feat(orm): range/prefix deletion support (#11103)

## Description

This adds `DeleteBy...` methods to the ORM codegen for the primary key + every unique index.



---

### Author Checklist

*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*

I have...

- [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] added `!` to the type prefix if API or client breaking change
- [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting))
- [ ] provided a link to the relevant issue or specification
- [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules)
- [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing)
- [ ] added a changelog entry to `CHANGELOG.md`
- [ ] included comments for [documenting Go code](https://blog.golang.org/godoc)
- [ ] updated the relevant documentation or specification
- [ ] reviewed "Files changed" and left comments if necessary
- [ ] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*

I have...

- [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed 
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)
This commit is contained in:
Aaron Craelius 2022-02-03 05:04:02 -05:00 committed by GitHub
parent 5126ec3c79
commit 63a248ef03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 398 additions and 54 deletions

View File

@ -65,11 +65,14 @@ func (t tableGen) genStoreInterface() {
t.P("Delete(ctx ", contextPkg.Ident("Context"), ", ", t.param(t.msg.GoIdent.GoName), " *", t.QualifiedGoIdent(t.msg.GoIdent), ") error")
t.P("Has(ctx ", contextPkg.Ident("Context"), ", ", t.fieldsArgs(t.primaryKeyFields.Names()), ") (found bool, err error)")
t.P("Get(ctx ", contextPkg.Ident("Context"), ", ", t.fieldsArgs(t.primaryKeyFields.Names()), ") (*", t.QualifiedGoIdent(t.msg.GoIdent), ", error)")
for _, idx := range t.uniqueIndexes {
t.genUniqueIndexSig(idx)
}
t.P("List(ctx ", contextPkg.Ident("Context"), ", prefixKey ", t.indexKeyInterfaceName(), ", opts ...", ormListPkg.Ident("Option"), ") ", "(", t.iteratorName(), ", error)")
t.P("ListRange(ctx ", contextPkg.Ident("Context"), ", from, to ", t.indexKeyInterfaceName(), ", opts ...", ormListPkg.Ident("Option"), ") ", "(", t.iteratorName(), ", error)")
t.P("DeleteBy(ctx ", contextPkg.Ident("Context"), ", prefixKey ", t.indexKeyInterfaceName(), ") error")
t.P("DeleteRange(ctx ", contextPkg.Ident("Context"), ", from, to ", t.indexKeyInterfaceName(), ") error")
t.P()
t.P("doNotImplement()")
t.P("}")
@ -77,9 +80,9 @@ func (t tableGen) genStoreInterface() {
}
// returns the has and get (in that order) function signature for unique indexes.
func (t tableGen) uniqueIndexSig(idx *ormv1alpha1.SecondaryIndexDescriptor) (string, string) {
fieldsSlc := strings.Split(idx.Fields, ",")
camelFields := t.fieldsToCamelCase(idx.Fields)
func (t tableGen) uniqueIndexSig(idxFields string) (string, string) {
fieldsSlc := strings.Split(idxFields, ",")
camelFields := t.fieldsToCamelCase(idxFields)
hasFuncName := "HasBy" + camelFields
getFuncName := "GetBy" + camelFields
@ -91,7 +94,7 @@ func (t tableGen) uniqueIndexSig(idx *ormv1alpha1.SecondaryIndexDescriptor) (str
}
func (t tableGen) genUniqueIndexSig(idx *ormv1alpha1.SecondaryIndexDescriptor) {
hasSig, getSig := t.uniqueIndexSig(idx)
hasSig, getSig := t.uniqueIndexSig(idx.Fields)
t.P(hasSig)
t.P(getSig)
}
@ -197,7 +200,7 @@ func (t tableGen) genStoreImpl() {
for _, idx := range t.uniqueIndexes {
fields := strings.Split(idx.Fields, ",")
hasName, getName := t.uniqueIndexSig(idx)
hasName, getName := t.uniqueIndexSig(idx.Fields)
// has
t.P("func (", receiverVar, " ", t.messageStoreReceiverName(t.msg), ") ", hasName, "{")
@ -243,6 +246,20 @@ func (t tableGen) genStoreImpl() {
t.P("}")
t.P()
// DeleteBy
t.P(receiver, "DeleteBy(ctx ", contextPkg.Ident("Context"), ", prefixKey ", t.indexKeyInterfaceName(), ") error {")
t.P("return ", receiverVar, ".table.GetIndexByID(prefixKey.id()).DeleteBy(ctx, prefixKey.values()...)")
t.P("}")
t.P()
t.P()
// DeleteRange
t.P(receiver, "DeleteRange(ctx ", contextPkg.Ident("Context"), ", from, to ", t.indexKeyInterfaceName(), ") error {")
t.P("return ", receiverVar, ".table.GetIndexByID(from.id()).DeleteRange(ctx, from.values(), to.values())")
t.P("}")
t.P()
t.P()
t.P(receiver, "doNotImplement() {}")
t.P()
}

View File

@ -20,6 +20,8 @@ type BalanceStore interface {
Get(ctx context.Context, address string, denom string) (*Balance, error)
List(ctx context.Context, prefixKey BalanceIndexKey, opts ...ormlist.Option) (BalanceIterator, error)
ListRange(ctx context.Context, from, to BalanceIndexKey, opts ...ormlist.Option) (BalanceIterator, error)
DeleteBy(ctx context.Context, prefixKey BalanceIndexKey) error
DeleteRange(ctx context.Context, from, to BalanceIndexKey) error
doNotImplement()
}
@ -117,6 +119,14 @@ func (this balanceStore) ListRange(ctx context.Context, from, to BalanceIndexKey
return BalanceIterator{it}, err
}
func (this balanceStore) DeleteBy(ctx context.Context, prefixKey BalanceIndexKey) error {
return this.table.GetIndexByID(prefixKey.id()).DeleteBy(ctx, prefixKey.values()...)
}
func (this balanceStore) DeleteRange(ctx context.Context, from, to BalanceIndexKey) error {
return this.table.GetIndexByID(from.id()).DeleteRange(ctx, from.values(), to.values())
}
func (this balanceStore) doNotImplement() {}
var _ BalanceStore = balanceStore{}
@ -138,6 +148,8 @@ type SupplyStore interface {
Get(ctx context.Context, denom string) (*Supply, error)
List(ctx context.Context, prefixKey SupplyIndexKey, opts ...ormlist.Option) (SupplyIterator, error)
ListRange(ctx context.Context, from, to SupplyIndexKey, opts ...ormlist.Option) (SupplyIterator, error)
DeleteBy(ctx context.Context, prefixKey SupplyIndexKey) error
DeleteRange(ctx context.Context, from, to SupplyIndexKey) error
doNotImplement()
}
@ -217,6 +229,14 @@ func (this supplyStore) ListRange(ctx context.Context, from, to SupplyIndexKey,
return SupplyIterator{it}, err
}
func (this supplyStore) DeleteBy(ctx context.Context, prefixKey SupplyIndexKey) error {
return this.table.GetIndexByID(prefixKey.id()).DeleteBy(ctx, prefixKey.values()...)
}
func (this supplyStore) DeleteRange(ctx context.Context, from, to SupplyIndexKey) error {
return this.table.GetIndexByID(from.id()).DeleteRange(ctx, from.values(), to.values())
}
func (this supplyStore) doNotImplement() {}
var _ SupplyStore = supplyStore{}

View File

@ -22,6 +22,8 @@ type ExampleTableStore interface {
GetByU64Str(ctx context.Context, u64 uint64, str string) (*ExampleTable, error)
List(ctx context.Context, prefixKey ExampleTableIndexKey, opts ...ormlist.Option) (ExampleTableIterator, error)
ListRange(ctx context.Context, from, to ExampleTableIndexKey, opts ...ormlist.Option) (ExampleTableIterator, error)
DeleteBy(ctx context.Context, prefixKey ExampleTableIndexKey) error
DeleteRange(ctx context.Context, from, to ExampleTableIndexKey) error
doNotImplement()
}
@ -184,6 +186,14 @@ func (this exampleTableStore) ListRange(ctx context.Context, from, to ExampleTab
return ExampleTableIterator{it}, err
}
func (this exampleTableStore) DeleteBy(ctx context.Context, prefixKey ExampleTableIndexKey) error {
return this.table.GetIndexByID(prefixKey.id()).DeleteBy(ctx, prefixKey.values()...)
}
func (this exampleTableStore) DeleteRange(ctx context.Context, from, to ExampleTableIndexKey) error {
return this.table.GetIndexByID(from.id()).DeleteRange(ctx, from.values(), to.values())
}
func (this exampleTableStore) doNotImplement() {}
var _ ExampleTableStore = exampleTableStore{}
@ -208,6 +218,8 @@ type ExampleAutoIncrementTableStore interface {
GetByX(ctx context.Context, x string) (*ExampleAutoIncrementTable, error)
List(ctx context.Context, prefixKey ExampleAutoIncrementTableIndexKey, opts ...ormlist.Option) (ExampleAutoIncrementTableIterator, error)
ListRange(ctx context.Context, from, to ExampleAutoIncrementTableIndexKey, opts ...ormlist.Option) (ExampleAutoIncrementTableIterator, error)
DeleteBy(ctx context.Context, prefixKey ExampleAutoIncrementTableIndexKey) error
DeleteRange(ctx context.Context, from, to ExampleAutoIncrementTableIndexKey) error
doNotImplement()
}
@ -321,6 +333,14 @@ func (this exampleAutoIncrementTableStore) ListRange(ctx context.Context, from,
return ExampleAutoIncrementTableIterator{it}, err
}
func (this exampleAutoIncrementTableStore) DeleteBy(ctx context.Context, prefixKey ExampleAutoIncrementTableIndexKey) error {
return this.table.GetIndexByID(prefixKey.id()).DeleteBy(ctx, prefixKey.values()...)
}
func (this exampleAutoIncrementTableStore) DeleteRange(ctx context.Context, from, to ExampleAutoIncrementTableIndexKey) error {
return this.table.GetIndexByID(from.id()).DeleteRange(ctx, from.values(), to.values())
}
func (this exampleAutoIncrementTableStore) doNotImplement() {}
var _ ExampleAutoIncrementTableStore = exampleAutoIncrementTableStore{}

View File

@ -11,14 +11,13 @@ type batchIndexCommitmentWriter struct {
func newBatchIndexCommitmentWriter(store Backend) *batchIndexCommitmentWriter {
return &batchIndexCommitmentWriter{
Backend: store,
// optimal array capacities are estimated here:
commitmentWriter: &batchStoreWriter{
ReadonlyStore: store.CommitmentStoreReader(),
writes: make([]batchWriterEntry, 0, 2),
curBuf: make([]*batchWriterEntry, 0, capacity),
},
indexWriter: &batchStoreWriter{
ReadonlyStore: store.IndexStoreReader(),
writes: make([]batchWriterEntry, 0, 16),
curBuf: make([]*batchWriterEntry, 0, capacity),
},
}
}
@ -33,12 +32,12 @@ func (w *batchIndexCommitmentWriter) IndexStore() kv.Store {
// Write flushes any pending writes.
func (w *batchIndexCommitmentWriter) Write() error {
err := flushWrites(w.Backend.CommitmentStore(), w.commitmentWriter.writes)
err := flushWrites(w.Backend.CommitmentStore(), w.commitmentWriter)
if err != nil {
return err
}
err = flushWrites(w.Backend.IndexStore(), w.indexWriter.writes)
err = flushWrites(w.Backend.IndexStore(), w.indexWriter)
if err != nil {
return err
}
@ -49,15 +48,25 @@ func (w *batchIndexCommitmentWriter) Write() error {
return err
}
func flushWrites(writer kv.Store, writes []batchWriterEntry) error {
func flushWrites(store kv.Store, writer *batchStoreWriter) error {
for _, buf := range writer.prevBufs {
err := flushBuf(store, buf)
if err != nil {
return err
}
}
return flushBuf(store, writer.curBuf)
}
func flushBuf(store kv.Store, writes []*batchWriterEntry) error {
for _, write := range writes {
if !write.delete {
err := writer.Set(write.key, write.value)
err := store.Set(write.key, write.value)
if err != nil {
return err
}
} else {
err := writer.Delete(write.key)
err := store.Delete(write.key)
if err != nil {
return err
}
@ -69,8 +78,10 @@ func flushWrites(writer kv.Store, writes []batchWriterEntry) error {
// Close discards any pending writes and should generally be called using
// a defer statement.
func (w *batchIndexCommitmentWriter) Close() {
w.commitmentWriter.writes = nil
w.indexWriter.writes = nil
w.commitmentWriter.prevBufs = nil
w.commitmentWriter.curBuf = nil
w.indexWriter.prevBufs = nil
w.indexWriter.curBuf = nil
}
type batchWriterEntry struct {
@ -80,17 +91,29 @@ type batchWriterEntry struct {
type batchStoreWriter struct {
kv.ReadonlyStore
writes []batchWriterEntry
prevBufs [][]*batchWriterEntry
curBuf []*batchWriterEntry
}
const capacity = 16
func (b *batchStoreWriter) Set(key, value []byte) error {
b.writes = append(b.writes, batchWriterEntry{key: key, value: value})
b.append(&batchWriterEntry{key: key, value: value})
return nil
}
func (b *batchStoreWriter) Delete(key []byte) error {
b.writes = append(b.writes, batchWriterEntry{key: key, delete: true})
b.append(&batchWriterEntry{key: key, delete: true})
return nil
}
func (b *batchStoreWriter) append(entry *batchWriterEntry) {
if len(b.curBuf) == capacity {
b.prevBufs = append(b.prevBufs, b.curBuf)
b.curBuf = make([]*batchWriterEntry, 0, capacity)
}
b.curBuf = append(b.curBuf, entry)
}
var _ Backend = &batchIndexCommitmentWriter{}

View File

@ -38,6 +38,12 @@ type Index interface {
// Range iteration is inclusive at both ends.
ListRange(ctx context.Context, from, to []interface{}, options ...ormlist.Option) (Iterator, error)
// DeleteBy deletes any entries which match the provided prefix key.
DeleteBy(context context.Context, prefixKey ...interface{}) error
// DeleteRange deletes any entries between the provided range keys.
DeleteRange(context context.Context, from, to []interface{}) error
// MessageType returns the protobuf message type of the index.
MessageType() protoreflect.MessageType
@ -64,9 +70,6 @@ type UniqueIndex interface {
// Get retrieves the message if one exists for the provided key values.
Get(context context.Context, message proto.Message, keyValues ...interface{}) (found bool, err error)
// DeleteByKey deletes the message if one exists in for the provided key values.
DeleteByKey(context context.Context, keyValues ...interface{}) error
}
type indexer interface {

View File

@ -24,6 +24,24 @@ type indexKeyIndex struct {
getReadBackend func(context.Context) (ReadBackend, error)
}
func (i indexKeyIndex) DeleteBy(ctx context.Context, keyValues ...interface{}) error {
it, err := i.List(ctx, keyValues)
if err != nil {
return err
}
return i.primaryKey.deleteByIterator(ctx, it)
}
func (i indexKeyIndex) DeleteRange(ctx context.Context, from, to []interface{}) error {
it, err := i.ListRange(ctx, from, to)
if err != nil {
return err
}
return i.primaryKey.deleteByIterator(ctx, it)
}
func (i indexKeyIndex) List(ctx context.Context, prefixKey []interface{}, options ...ormlist.Option) (Iterator, error) {
backend, err := i.getReadBackend(ctx)
if err != nil {

View File

@ -15,6 +15,10 @@ import (
)
// Iterator defines the interface for iterating over indexes.
//
// WARNING: it is generally unsafe to mutate a table while iterating over it.
// Instead you should do reads and writes separately, or use a helper
// function like DeleteBy which does this efficiently.
type Iterator interface {
// Next advances the iterator and returns true if a valid entry is found.
@ -213,6 +217,7 @@ func (i *indexIterator) Next() bool {
i.started = true
} else {
i.iterator.Next()
i.indexValues = nil
}
return i.iterator.Valid()

View File

@ -80,16 +80,38 @@ func (p primaryKeyIndex) get(backend ReadBackend, message proto.Message, values
return p.getByKeyBytes(backend, key, values, message)
}
func (p primaryKeyIndex) DeleteByKey(ctx context.Context, primaryKeyValues ...interface{}) error {
return p.doDeleteByKey(ctx, encodeutil.ValuesOf(primaryKeyValues...))
func (p primaryKeyIndex) DeleteBy(ctx context.Context, primaryKeyValues ...interface{}) error {
if len(primaryKeyValues) == len(p.GetFieldNames()) {
return p.doDelete(ctx, encodeutil.ValuesOf(primaryKeyValues...))
}
it, err := p.List(ctx, primaryKeyValues)
if err != nil {
return err
}
return p.deleteByIterator(ctx, it)
}
func (p primaryKeyIndex) doDeleteByKey(ctx context.Context, primaryKeyValues []protoreflect.Value) error {
func (p primaryKeyIndex) DeleteRange(ctx context.Context, from, to []interface{}) error {
it, err := p.ListRange(ctx, from, to)
if err != nil {
return err
}
return p.deleteByIterator(ctx, it)
}
func (p primaryKeyIndex) doDelete(ctx context.Context, primaryKeyValues []protoreflect.Value) error {
backend, err := p.getBackend(ctx)
if err != nil {
return err
}
// delete object
writer := newBatchIndexCommitmentWriter(backend)
defer writer.Close()
pk, err := p.EncodeKey(primaryKeyValues)
if err != nil {
return err
@ -105,23 +127,30 @@ func (p primaryKeyIndex) doDeleteByKey(ctx context.Context, primaryKeyValues []p
return nil
}
err = p.doDeleteWithWriteBatch(backend, writer, pk, msg)
if err != nil {
return err
}
return writer.Write()
}
func (p primaryKeyIndex) doDeleteWithWriteBatch(backend Backend, writer *batchIndexCommitmentWriter, primaryKeyBz []byte, message proto.Message) error {
if hooks := backend.Hooks(); hooks != nil {
err = hooks.OnDelete(msg)
err := hooks.OnDelete(message)
if err != nil {
return err
}
}
// delete object
writer := newBatchIndexCommitmentWriter(backend)
defer writer.Close()
err = writer.CommitmentStore().Delete(pk)
err := writer.CommitmentStore().Delete(primaryKeyBz)
if err != nil {
return err
}
// clear indexes
mref := msg.ProtoReflect()
mref := message.ProtoReflect()
indexStoreWriter := writer.IndexStore()
for _, idx := range p.indexers {
err := idx.onDelete(indexStoreWriter, mref)
@ -130,7 +159,7 @@ func (p primaryKeyIndex) doDeleteByKey(ctx context.Context, primaryKeyValues []p
}
}
return writer.Write()
return nil
}
func (p primaryKeyIndex) getByKeyBytes(store ReadBackend, key []byte, keyValues []protoreflect.Value, message proto.Message) (found bool, err error) {
@ -154,4 +183,42 @@ func (p primaryKeyIndex) Fields() string {
return p.fields.String()
}
func (p primaryKeyIndex) deleteByIterator(ctx context.Context, it Iterator) error {
backend, err := p.getBackend(ctx)
if err != nil {
return err
}
// we batch writes while the iterator is still open
writer := newBatchIndexCommitmentWriter(backend)
defer writer.Close()
for it.Next() {
_, pk, err := it.Keys()
if err != nil {
return err
}
msg, err := it.GetMessage()
if err != nil {
return err
}
pkBz, err := p.EncodeKey(pk)
if err != nil {
return err
}
err = p.doDeleteWithWriteBatch(backend, writer, pkBz, msg)
if err != nil {
return err
}
}
// close iterator
it.Close()
// then write batch
return writer.Write()
}
var _ UniqueIndex = &primaryKeyIndex{}

View File

@ -155,7 +155,7 @@ func (t tableImpl) doSave(writer *batchIndexCommitmentWriter, message proto.Mess
func (t tableImpl) Delete(context context.Context, message proto.Message) error {
pk := t.PrimaryKeyCodec.GetKeyValues(message.ProtoReflect())
return t.DeleteByKey(context, pk)
return t.DeleteBy(context, pk)
}
func (t tableImpl) GetIndex(fields string) Index {

View File

@ -336,7 +336,6 @@ func runTestScenario(t *testing.T, table ormtable.Table, backend ormtable.Backen
data = append(data, &testpb.ExampleTable{U32: 9})
err = store.Save(ctx, data[10])
assert.NilError(t, err)
pkIndex := table.GetUniqueIndex("u32,i64,str")
a, err = store.Get(ctx, 9, 0, "")
assert.NilError(t, err)
assert.Assert(t, a != nil)
@ -366,17 +365,36 @@ func runTestScenario(t *testing.T, table ormtable.Table, backend ormtable.Backen
assertTablesEqual(t, table, ctx, store2)
// let's delete item 5
key5 := []interface{}{uint32(7), int64(-2), "abe"}
err = pkIndex.DeleteByKey(ctx, key5...)
err = store.DeleteBy(ctx, testpb.ExampleTableU32I64StrIndexKey{}.WithU32I64Str(7, -2, "abe"))
assert.NilError(t, err)
// it should be gone
found, err = pkIndex.Has(ctx, key5...)
found, err = store.Has(ctx, 7, -2, "abe")
assert.NilError(t, err)
assert.Assert(t, !found)
// and missing from the iterator
it, err = store.List(ctx, testpb.ExampleTablePrimaryKey{})
assert.NilError(t, err)
assertIteratorItems(it, 0, 1, 2, 3, 4, 6, 7, 8, 9, 10)
// let's do a batch delete
// first iterate over the items we'll delete to check that iterator
it, err = store.List(ctx, testpb.ExampleTableStrU32IndexKey{}.WithStr("abd"))
assert.NilError(t, err)
assertIteratorItems(it, 1, 3, 9)
// now delete them
assert.NilError(t, store.DeleteBy(ctx, testpb.ExampleTableStrU32IndexKey{}.WithStr("abd")))
it, err = store.List(ctx, testpb.ExampleTablePrimaryKey{})
assert.NilError(t, err)
assertIteratorItems(it, 0, 2, 4, 6, 7, 8, 10)
// Let's do a range delete
assert.NilError(t, store.DeleteRange(ctx,
testpb.ExampleTableStrU32IndexKey{}.WithStrU32("abc", 8),
testpb.ExampleTableStrU32IndexKey{}.WithStrU32("abe", 5),
))
it, err = store.List(ctx, testpb.ExampleTablePrimaryKey{})
assert.NilError(t, err)
assertIteratorItems(it, 0, 2, 6, 10)
}
func TestRandomTableData(t *testing.T) {

View File

@ -934,6 +934,170 @@ ITERATOR 0100 -> 0101
PK testpb.ExampleTable 9/0/ -> {"u32":9,"b":true}
NEXT
VALID false
ITERATOR 010261626400 -> 010261626401
VALID true
KEY 010261626400000000047ffffffffffffffe
IDX testpb.ExampleTable str/u32/i64 : abd/4/-2 -> 4/-2/abd
GET 0100000000047ffffffffffffffe616264 100e2203616264
PK testpb.ExampleTable 4/-2/abd -> {"u32":4,"u64":14,"str":"abd","bz":"abd","i64":-2}
NEXT
VALID true
KEY 010261626400000000057ffffffffffffffe
IDX testpb.ExampleTable str/u32/i64 : abd/5/-2 -> 5/-2/abd
GET 0100000000057ffffffffffffffe616264 10102203616264
PK testpb.ExampleTable 5/-2/abd -> {"u32":5,"u64":16,"str":"abd","bz":"abd","i64":-2}
NEXT
VALID true
KEY 010261626400000000088000000000000001
IDX testpb.ExampleTable str/u32/i64 : abd/8/1 -> 8/1/abd
GET 0100000000088000000000000001616264 100a
PK testpb.ExampleTable 8/1/abd -> {"u32":8,"u64":10,"str":"abd","i64":1}
NEXT
VALID false
ITERATOR 010261626400 -> 010261626401
VALID true
KEY 010261626400000000047ffffffffffffffe
IDX testpb.ExampleTable str/u32/i64 : abd/4/-2 -> 4/-2/abd
GET 0100000000047ffffffffffffffe616264 100e2203616264
PK testpb.ExampleTable 4/-2/abd -> {"u32":4,"u64":14,"str":"abd","bz":"abd","i64":-2}
ORM DELETE testpb.ExampleTable {"u32":4,"u64":14,"str":"abd","bz":"abd","i64":-2}
NEXT
VALID true
KEY 010261626400000000057ffffffffffffffe
IDX testpb.ExampleTable str/u32/i64 : abd/5/-2 -> 5/-2/abd
GET 0100000000057ffffffffffffffe616264 10102203616264
PK testpb.ExampleTable 5/-2/abd -> {"u32":5,"u64":16,"str":"abd","bz":"abd","i64":-2}
ORM DELETE testpb.ExampleTable {"u32":5,"u64":16,"str":"abd","bz":"abd","i64":-2}
NEXT
VALID true
KEY 010261626400000000088000000000000001
IDX testpb.ExampleTable str/u32/i64 : abd/8/1 -> 8/1/abd
GET 0100000000088000000000000001616264 100a
PK testpb.ExampleTable 8/1/abd -> {"u32":8,"u64":10,"str":"abd","i64":1}
ORM DELETE testpb.ExampleTable {"u32":8,"u64":10,"str":"abd","i64":1}
NEXT
VALID false
CLOSE
DEL 0100000000047ffffffffffffffe616264
DEL PK testpb.ExampleTable 4/-2/abd -> {"u32":4,"str":"abd","i64":-2}
DEL 0100000000057ffffffffffffffe616264
DEL PK testpb.ExampleTable 5/-2/abd -> {"u32":5,"str":"abd","i64":-2}
DEL 0100000000088000000000000001616264
DEL PK testpb.ExampleTable 8/1/abd -> {"u32":8,"str":"abd","i64":1}
DEL 0101000000000000000e616264
DEL ERR:EOF
DEL 010261626400000000047ffffffffffffffe
DEL IDX testpb.ExampleTable str/u32/i64 : abd/4/-2 -> 4/-2/abd
DEL 01030361626461626400000000047ffffffffffffffe
DEL IDX testpb.ExampleTable bz/str/u32/i64 : [97 98 100]/abd/4/-2 -> 4/-2/abd
DEL 01010000000000000010616264
DEL ERR:EOF
DEL 010261626400000000057ffffffffffffffe
DEL IDX testpb.ExampleTable str/u32/i64 : abd/5/-2 -> 5/-2/abd
DEL 01030361626461626400000000057ffffffffffffffe
DEL IDX testpb.ExampleTable bz/str/u32/i64 : [97 98 100]/abd/5/-2 -> 5/-2/abd
DEL 0101000000000000000a616264
DEL ERR:EOF
DEL 010261626400000000088000000000000001
DEL IDX testpb.ExampleTable str/u32/i64 : abd/8/1 -> 8/1/abd
DEL 01030061626400000000088000000000000001
DEL IDX testpb.ExampleTable bz/str/u32/i64 : []/abd/8/1 -> 8/1/abd
ITERATOR 0100 -> 0101
VALID true
KEY 0100000000047ffffffffffffffe616263 100e2203616263
PK testpb.ExampleTable 4/-2/abc -> {"u32":4,"u64":14,"str":"abc","bz":"abc","i64":-2}
NEXT
VALID true
KEY 0100000000047fffffffffffffff616263 10102203616263
PK testpb.ExampleTable 4/-1/abc -> {"u32":4,"u64":16,"str":"abc","bz":"abc","i64":-1}
NEXT
VALID true
KEY 0100000000057ffffffffffffffe616265 10122203616265
PK testpb.ExampleTable 5/-2/abe -> {"u32":5,"u64":18,"str":"abe","bz":"abe","i64":-2}
NEXT
VALID true
KEY 0100000000077fffffffffffffff616265 100b
PK testpb.ExampleTable 7/-1/abe -> {"u32":7,"u64":11,"str":"abe","i64":-1}
NEXT
VALID true
KEY 0100000000087ffffffffffffffc616263 100b
PK testpb.ExampleTable 8/-4/abc -> {"u32":8,"u64":11,"str":"abc","i64":-4}
NEXT
VALID true
KEY 0100000000088000000000000001616263 100c
PK testpb.ExampleTable 8/1/abc -> {"u32":8,"u64":12,"str":"abc","i64":1}
NEXT
VALID true
KEY 0100000000098000000000000000 7801
PK testpb.ExampleTable 9/0/ -> {"u32":9,"b":true}
NEXT
VALID false
ITERATOR 01026162630000000008 -> 01026162650000000006
VALID true
KEY 010261626300000000087ffffffffffffffc
IDX testpb.ExampleTable str/u32/i64 : abc/8/-4 -> 8/-4/abc
GET 0100000000087ffffffffffffffc616263 100b
PK testpb.ExampleTable 8/-4/abc -> {"u32":8,"u64":11,"str":"abc","i64":-4}
ORM DELETE testpb.ExampleTable {"u32":8,"u64":11,"str":"abc","i64":-4}
NEXT
VALID true
KEY 010261626300000000088000000000000001
IDX testpb.ExampleTable str/u32/i64 : abc/8/1 -> 8/1/abc
GET 0100000000088000000000000001616263 100c
PK testpb.ExampleTable 8/1/abc -> {"u32":8,"u64":12,"str":"abc","i64":1}
ORM DELETE testpb.ExampleTable {"u32":8,"u64":12,"str":"abc","i64":1}
NEXT
VALID true
KEY 010261626500000000057ffffffffffffffe
IDX testpb.ExampleTable str/u32/i64 : abe/5/-2 -> 5/-2/abe
GET 0100000000057ffffffffffffffe616265 10122203616265
PK testpb.ExampleTable 5/-2/abe -> {"u32":5,"u64":18,"str":"abe","bz":"abe","i64":-2}
ORM DELETE testpb.ExampleTable {"u32":5,"u64":18,"str":"abe","bz":"abe","i64":-2}
NEXT
VALID false
CLOSE
DEL 0100000000087ffffffffffffffc616263
DEL PK testpb.ExampleTable 8/-4/abc -> {"u32":8,"str":"abc","i64":-4}
DEL 0100000000088000000000000001616263
DEL PK testpb.ExampleTable 8/1/abc -> {"u32":8,"str":"abc","i64":1}
DEL 0100000000057ffffffffffffffe616265
DEL PK testpb.ExampleTable 5/-2/abe -> {"u32":5,"str":"abe","i64":-2}
DEL 0101000000000000000b616263
DEL ERR:EOF
DEL 010261626300000000087ffffffffffffffc
DEL IDX testpb.ExampleTable str/u32/i64 : abc/8/-4 -> 8/-4/abc
DEL 01030061626300000000087ffffffffffffffc
DEL IDX testpb.ExampleTable bz/str/u32/i64 : []/abc/8/-4 -> 8/-4/abc
DEL 0101000000000000000c616263
DEL ERR:EOF
DEL 010261626300000000088000000000000001
DEL IDX testpb.ExampleTable str/u32/i64 : abc/8/1 -> 8/1/abc
DEL 01030061626300000000088000000000000001
DEL IDX testpb.ExampleTable bz/str/u32/i64 : []/abc/8/1 -> 8/1/abc
DEL 01010000000000000012616265
DEL ERR:EOF
DEL 010261626500000000057ffffffffffffffe
DEL IDX testpb.ExampleTable str/u32/i64 : abe/5/-2 -> 5/-2/abe
DEL 01030361626561626500000000057ffffffffffffffe
DEL IDX testpb.ExampleTable bz/str/u32/i64 : [97 98 101]/abe/5/-2 -> 5/-2/abe
ITERATOR 0100 -> 0101
VALID true
KEY 0100000000047ffffffffffffffe616263 100e2203616263
PK testpb.ExampleTable 4/-2/abc -> {"u32":4,"u64":14,"str":"abc","bz":"abc","i64":-2}
NEXT
VALID true
KEY 0100000000047fffffffffffffff616263 10102203616263
PK testpb.ExampleTable 4/-1/abc -> {"u32":4,"u64":16,"str":"abc","bz":"abc","i64":-1}
NEXT
VALID true
KEY 0100000000077fffffffffffffff616265 100b
PK testpb.ExampleTable 7/-1/abe -> {"u32":7,"u64":11,"str":"abe","i64":-1}
NEXT
VALID true
KEY 0100000000098000000000000000 7801
PK testpb.ExampleTable 9/0/ -> {"u32":9,"b":true}
NEXT
VALID false
CLOSE
CLOSE
CLOSE

View File

@ -87,33 +87,22 @@ func (u uniqueKeyIndex) Get(ctx context.Context, message proto.Message, keyValue
return u.primaryKey.get(backend, message, pk)
}
func (u uniqueKeyIndex) DeleteByKey(ctx context.Context, keyValues ...interface{}) error {
backend, err := u.getReadBackend(ctx)
func (u uniqueKeyIndex) DeleteBy(ctx context.Context, keyValues ...interface{}) error {
it, err := u.List(ctx, keyValues)
if err != nil {
return err
}
key, err := u.GetKeyCodec().EncodeKey(encodeutil.ValuesOf(keyValues...))
return u.primaryKey.deleteByIterator(ctx, it)
}
func (u uniqueKeyIndex) DeleteRange(ctx context.Context, from, to []interface{}) error {
it, err := u.ListRange(ctx, from, to)
if err != nil {
return err
}
value, err := backend.IndexStoreReader().Get(key)
if err != nil {
return err
}
// for unique keys, value can be empty and the entry still exists
if value == nil {
return nil
}
_, pk, err := u.DecodeIndexKey(key, value)
if err != nil {
return err
}
return u.primaryKey.doDeleteByKey(ctx, pk)
return u.primaryKey.deleteByIterator(ctx, it)
}
func (u uniqueKeyIndex) onInsert(store kv.Store, message protoreflect.Message) error {