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:
parent
5126ec3c79
commit
63a248ef03
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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{}
|
||||
|
|
|
@ -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{}
|
||||
|
|
|
@ -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{}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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{}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue