refactor(orm)!: refactor hooks into validate and write hooks (#11185)

* refactor(orm)!: refactor hooks into validate and write hooks

* impl and tests

* docs

* update mock hooks and tests

Co-authored-by: Marko <marbar3778@yahoo.com>
This commit is contained in:
Aaron Craelius 2022-02-25 08:54:44 -05:00 committed by GitHub
parent c686634819
commit 57b46134a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 393 additions and 147 deletions

View File

@ -1,6 +1,7 @@
package testkv
import (
"context"
"fmt"
"google.golang.org/protobuf/proto"
@ -23,10 +24,16 @@ type Debugger interface {
// NewDebugBackend wraps both stores from a Backend with a debugger.
func NewDebugBackend(backend ormtable.Backend, debugger Debugger) ormtable.Backend {
hooks := debugHooks{
debugger: debugger,
validateHooks: backend.ValidateHooks(),
writeHooks: backend.WriteHooks(),
}
return ormtable.NewBackend(ormtable.BackendOptions{
CommitmentStore: NewDebugStore(backend.CommitmentStore(), debugger, "commit"),
IndexStore: NewDebugStore(backend.IndexStore(), debugger, "index"),
Hooks: debugHooks{debugger: debugger, hooks: backend.Hooks()},
ValidateHooks: hooks,
WriteHooks: hooks,
})
}
@ -206,28 +213,29 @@ func (d *EntryCodecDebugger) Decode(key, value []byte) string {
}
type debugHooks struct {
debugger Debugger
hooks ormtable.Hooks
debugger Debugger
validateHooks ormtable.ValidateHooks
writeHooks ormtable.WriteHooks
}
func (d debugHooks) OnInsert(message proto.Message) error {
func (d debugHooks) ValidateInsert(context context.Context, message proto.Message) error {
jsonBz, err := stablejson.Marshal(message)
if err != nil {
return err
}
d.debugger.Log(fmt.Sprintf(
"ORM INSERT %s %s",
"ORM BEFORE INSERT %s %s",
message.ProtoReflect().Descriptor().FullName(),
jsonBz,
))
if d.hooks != nil {
return d.hooks.OnInsert(message)
if d.validateHooks != nil {
return d.validateHooks.ValidateInsert(context, message)
}
return nil
}
func (d debugHooks) OnUpdate(existing, new proto.Message) error {
func (d debugHooks) ValidateUpdate(ctx context.Context, existing, new proto.Message) error {
existingJson, err := stablejson.Marshal(existing)
if err != nil {
return err
@ -239,30 +247,84 @@ func (d debugHooks) OnUpdate(existing, new proto.Message) error {
}
d.debugger.Log(fmt.Sprintf(
"ORM UPDATE %s %s -> %s",
"ORM BEFORE UPDATE %s %s -> %s",
existing.ProtoReflect().Descriptor().FullName(),
existingJson,
newJson,
))
if d.hooks != nil {
return d.hooks.OnUpdate(existing, new)
if d.validateHooks != nil {
return d.validateHooks.ValidateUpdate(ctx, existing, new)
}
return nil
}
func (d debugHooks) OnDelete(message proto.Message) error {
func (d debugHooks) ValidateDelete(ctx context.Context, message proto.Message) error {
jsonBz, err := stablejson.Marshal(message)
if err != nil {
return err
}
d.debugger.Log(fmt.Sprintf(
"ORM DELETE %s %s",
"ORM BEFORE DELETE %s %s",
message.ProtoReflect().Descriptor().FullName(),
jsonBz,
))
if d.hooks != nil {
return d.hooks.OnDelete(message)
if d.validateHooks != nil {
return d.validateHooks.ValidateDelete(ctx, message)
}
return nil
}
func (d debugHooks) OnInsert(ctx context.Context, message proto.Message) {
jsonBz, err := stablejson.Marshal(message)
if err != nil {
panic(err)
}
d.debugger.Log(fmt.Sprintf(
"ORM AFTER INSERT %s %s",
message.ProtoReflect().Descriptor().FullName(),
jsonBz,
))
if d.writeHooks != nil {
d.writeHooks.OnInsert(ctx, message)
}
}
func (d debugHooks) OnUpdate(ctx context.Context, existing, new proto.Message) {
existingJson, err := stablejson.Marshal(existing)
if err != nil {
panic(err)
}
newJson, err := stablejson.Marshal(new)
if err != nil {
panic(err)
}
d.debugger.Log(fmt.Sprintf(
"ORM AFTER UPDATE %s %s -> %s",
existing.ProtoReflect().Descriptor().FullName(),
existingJson,
newJson,
))
if d.writeHooks != nil {
d.writeHooks.OnUpdate(ctx, existing, new)
}
}
func (d debugHooks) OnDelete(ctx context.Context, message proto.Message) {
jsonBz, err := stablejson.Marshal(message)
if err != nil {
panic(err)
}
d.debugger.Log(fmt.Sprintf(
"ORM AFTER DELETE %s %s",
message.ProtoReflect().Descriptor().FullName(),
jsonBz,
))
if d.writeHooks != nil {
d.writeHooks.OnDelete(ctx, message)
}
}

View File

@ -275,8 +275,11 @@ func TestHooks(t *testing.T) {
ctrl := gomock.NewController(t)
db, err := ormdb.NewModuleDB(TestBankSchema, ormdb.ModuleDBOptions{})
assert.NilError(t, err)
hooks := ormmocks.NewMockHooks(ctrl)
ctx := ormtable.WrapContextDefault(ormtest.NewMemoryBackend().WithHooks(hooks))
validateHooks := ormmocks.NewMockValidateHooks(ctrl)
writeHooks := ormmocks.NewMockWriteHooks(ctrl)
ctx := ormtable.WrapContextDefault(ormtest.NewMemoryBackend().
WithValidateHooks(validateHooks).
WithWriteHooks(writeHooks))
k, err := NewKeeper(db)
assert.NilError(t, err)
@ -284,24 +287,48 @@ func TestHooks(t *testing.T) {
acct1 := "bob"
acct2 := "sally"
hooks.EXPECT().OnInsert(ormmocks.Eq(&testpb.Balance{Address: acct1, Denom: denom, Amount: 10}))
hooks.EXPECT().OnInsert(ormmocks.Eq(&testpb.Supply{Denom: denom, Amount: 10}))
validateHooks.EXPECT().ValidateInsert(gomock.Any(), ormmocks.Eq(&testpb.Balance{Address: acct1, Denom: denom, Amount: 10}))
validateHooks.EXPECT().ValidateInsert(gomock.Any(), ormmocks.Eq(&testpb.Supply{Denom: denom, Amount: 10}))
writeHooks.EXPECT().OnInsert(gomock.Any(), ormmocks.Eq(&testpb.Balance{Address: acct1, Denom: denom, Amount: 10}))
writeHooks.EXPECT().OnInsert(gomock.Any(), ormmocks.Eq(&testpb.Supply{Denom: denom, Amount: 10}))
assert.NilError(t, k.Mint(ctx, acct1, denom, 10))
hooks.EXPECT().OnUpdate(
validateHooks.EXPECT().ValidateUpdate(
gomock.Any(),
ormmocks.Eq(&testpb.Balance{Address: acct1, Denom: denom, Amount: 10}),
ormmocks.Eq(&testpb.Balance{Address: acct1, Denom: denom, Amount: 5}),
)
hooks.EXPECT().OnInsert(
validateHooks.EXPECT().ValidateInsert(
gomock.Any(),
ormmocks.Eq(&testpb.Balance{Address: acct2, Denom: denom, Amount: 5}),
)
writeHooks.EXPECT().OnUpdate(
gomock.Any(),
ormmocks.Eq(&testpb.Balance{Address: acct1, Denom: denom, Amount: 10}),
ormmocks.Eq(&testpb.Balance{Address: acct1, Denom: denom, Amount: 5}),
)
writeHooks.EXPECT().OnInsert(
gomock.Any(),
ormmocks.Eq(&testpb.Balance{Address: acct2, Denom: denom, Amount: 5}),
)
assert.NilError(t, k.Send(ctx, acct1, acct2, denom, 5))
hooks.EXPECT().OnUpdate(
validateHooks.EXPECT().ValidateUpdate(
gomock.Any(),
ormmocks.Eq(&testpb.Supply{Denom: denom, Amount: 10}),
ormmocks.Eq(&testpb.Supply{Denom: denom, Amount: 5}),
)
hooks.EXPECT().OnDelete(
validateHooks.EXPECT().ValidateDelete(
gomock.Any(),
ormmocks.Eq(&testpb.Balance{Address: acct1, Denom: denom, Amount: 5}),
)
writeHooks.EXPECT().OnUpdate(
gomock.Any(),
ormmocks.Eq(&testpb.Supply{Denom: denom, Amount: 10}),
ormmocks.Eq(&testpb.Supply{Denom: denom, Amount: 5}),
)
writeHooks.EXPECT().OnDelete(
gomock.Any(),
ormmocks.Eq(&testpb.Balance{Address: acct1, Denom: denom, Amount: 5}),
)
assert.NilError(t, k.Burn(ctx, acct1, denom, 5))

View File

@ -2,18 +2,20 @@ GET 010200666f6f
PK testpb.Supply foo -> {"denom":"foo"}
GET 010200666f6f
PK testpb.Supply foo -> {"denom":"foo"}
ORM INSERT testpb.Supply {"denom":"foo","amount":100}
ORM BEFORE INSERT testpb.Supply {"denom":"foo","amount":100}
SET 010200666f6f 1064
PK testpb.Supply foo -> {"denom":"foo","amount":100}
ORM AFTER INSERT testpb.Supply {"denom":"foo","amount":100}
GET 010100626f6200666f6f
PK testpb.Balance bob/foo -> {"address":"bob","denom":"foo"}
GET 010100626f6200666f6f
PK testpb.Balance bob/foo -> {"address":"bob","denom":"foo"}
ORM INSERT testpb.Balance {"address":"bob","denom":"foo","amount":100}
ORM BEFORE INSERT testpb.Balance {"address":"bob","denom":"foo","amount":100}
SET 010100626f6200666f6f 1864
PK testpb.Balance bob/foo -> {"address":"bob","denom":"foo","amount":100}
SET 010101666f6f00626f62
IDX testpb.Balance denom/address : foo/bob -> bob/foo
ORM AFTER INSERT testpb.Balance {"address":"bob","denom":"foo","amount":100}
GET 010100626f6200666f6f 1864
PK testpb.Balance bob/foo -> {"address":"bob","denom":"foo","amount":100}
GET 010200666f6f 1064
@ -22,18 +24,20 @@ GET 010100626f6200666f6f 1864
PK testpb.Balance bob/foo -> {"address":"bob","denom":"foo","amount":100}
GET 010100626f6200666f6f 1864
PK testpb.Balance bob/foo -> {"address":"bob","denom":"foo","amount":100}
ORM UPDATE testpb.Balance {"address":"bob","denom":"foo","amount":100} -> {"address":"bob","denom":"foo","amount":70}
ORM BEFORE UPDATE testpb.Balance {"address":"bob","denom":"foo","amount":100} -> {"address":"bob","denom":"foo","amount":70}
SET 010100626f6200666f6f 1846
PK testpb.Balance bob/foo -> {"address":"bob","denom":"foo","amount":70}
ORM AFTER UPDATE testpb.Balance {"address":"bob","denom":"foo","amount":100} -> {"address":"bob","denom":"foo","amount":70}
GET 01010073616c6c7900666f6f
PK testpb.Balance sally/foo -> {"address":"sally","denom":"foo"}
GET 01010073616c6c7900666f6f
PK testpb.Balance sally/foo -> {"address":"sally","denom":"foo"}
ORM INSERT testpb.Balance {"address":"sally","denom":"foo","amount":30}
ORM BEFORE INSERT testpb.Balance {"address":"sally","denom":"foo","amount":30}
SET 01010073616c6c7900666f6f 181e
PK testpb.Balance sally/foo -> {"address":"sally","denom":"foo","amount":30}
SET 010101666f6f0073616c6c79
IDX testpb.Balance denom/address : foo/sally -> sally/foo
ORM AFTER INSERT testpb.Balance {"address":"sally","denom":"foo","amount":30}
GET 010100626f6200666f6f 1846
PK testpb.Balance bob/foo -> {"address":"bob","denom":"foo","amount":70}
GET 01010073616c6c7900666f6f 181e
@ -42,16 +46,18 @@ GET 010200666f6f 1064
PK testpb.Supply foo -> {"denom":"foo","amount":100}
GET 010200666f6f 1064
PK testpb.Supply foo -> {"denom":"foo","amount":100}
ORM UPDATE testpb.Supply {"denom":"foo","amount":100} -> {"denom":"foo","amount":97}
ORM BEFORE UPDATE testpb.Supply {"denom":"foo","amount":100} -> {"denom":"foo","amount":97}
SET 010200666f6f 1061
PK testpb.Supply foo -> {"denom":"foo","amount":97}
ORM AFTER UPDATE testpb.Supply {"denom":"foo","amount":100} -> {"denom":"foo","amount":97}
GET 01010073616c6c7900666f6f 181e
PK testpb.Balance sally/foo -> {"address":"sally","denom":"foo","amount":30}
GET 01010073616c6c7900666f6f 181e
PK testpb.Balance sally/foo -> {"address":"sally","denom":"foo","amount":30}
ORM UPDATE testpb.Balance {"address":"sally","denom":"foo","amount":30} -> {"address":"sally","denom":"foo","amount":27}
ORM BEFORE UPDATE testpb.Balance {"address":"sally","denom":"foo","amount":30} -> {"address":"sally","denom":"foo","amount":27}
SET 01010073616c6c7900666f6f 181b
PK testpb.Balance sally/foo -> {"address":"sally","denom":"foo","amount":27}
ORM AFTER UPDATE testpb.Balance {"address":"sally","denom":"foo","amount":30} -> {"address":"sally","denom":"foo","amount":27}
GET 01010073616c6c7900666f6f 181b
PK testpb.Balance sally/foo -> {"address":"sally","denom":"foo","amount":27}
GET 010200666f6f 1061

View File

@ -28,7 +28,7 @@ func (t autoIncrementTable) InsertReturningID(ctx context.Context, message proto
return 0, err
}
return t.save(backend, message, saveModeInsert)
return t.save(ctx, backend, message, saveModeInsert)
}
func (t autoIncrementTable) Save(ctx context.Context, message proto.Message) error {
@ -37,7 +37,7 @@ func (t autoIncrementTable) Save(ctx context.Context, message proto.Message) err
return err
}
_, err = t.save(backend, message, saveModeDefault)
_, err = t.save(ctx, backend, message, saveModeDefault)
return err
}
@ -47,7 +47,7 @@ func (t autoIncrementTable) Insert(ctx context.Context, message proto.Message) e
return err
}
_, err = t.save(backend, message, saveModeInsert)
_, err = t.save(ctx, backend, message, saveModeInsert)
return err
}
@ -57,11 +57,11 @@ func (t autoIncrementTable) Update(ctx context.Context, message proto.Message) e
return err
}
_, err = t.save(backend, message, saveModeUpdate)
_, err = t.save(ctx, backend, message, saveModeUpdate)
return err
}
func (t *autoIncrementTable) save(backend Backend, message proto.Message, mode saveMode) (newId uint64, err error) {
func (t *autoIncrementTable) save(ctx context.Context, backend Backend, message proto.Message, mode saveMode) (newId uint64, err error) {
messageRef := message.ProtoReflect()
val := messageRef.Get(t.autoIncField).Uint()
writer := newBatchIndexCommitmentWriter(backend)
@ -87,7 +87,7 @@ func (t *autoIncrementTable) save(backend Backend, message proto.Message, mode s
mode = saveModeUpdate
}
return newId, t.tableImpl.doSave(writer, message, mode)
return newId, t.tableImpl.doSave(ctx, writer, message, mode)
}
func (t *autoIncrementTable) curSeqValue(kv kv.ReadonlyStore) (uint64, error) {
@ -148,7 +148,7 @@ func (t autoIncrementTable) ImportJSON(ctx context.Context, reader io.Reader) er
if id == 0 {
// we don't have an ID in the JSON, so we call Save to insert and
// generate one
_, err = t.save(backend, message, saveModeInsert)
_, err = t.save(ctx, backend, message, saveModeInsert)
return err
} else {
if id > maxID {
@ -158,7 +158,7 @@ func (t autoIncrementTable) ImportJSON(ctx context.Context, reader io.Reader) er
// either no ID or SAVE_MODE_UPDATE. So instead we drop one level
// down and insert using tableImpl which doesn't know about
// auto-incrementing IDs
return t.tableImpl.save(backend, message, saveModeInsert)
return t.tableImpl.save(ctx, backend, message, saveModeInsert)
}
})
}

View File

@ -30,11 +30,15 @@ type Backend interface {
// otherwise it the commitment store.
IndexStore() kv.Store
// Hooks returns a Hooks instance or nil.
Hooks() Hooks
// ValidateHooks returns a ValidateHooks instance or nil.
ValidateHooks() ValidateHooks
// WithHooks returns a copy of this backend with the provided hooks.
WithHooks(Hooks) Backend
// WithValidateHooks returns a copy of this backend with the provided hooks.
WithValidateHooks(ValidateHooks) Backend
WriteHooks() WriteHooks
WithWriteHooks(WriteHooks) Backend
}
// ReadBackendOptions defines options for creating a ReadBackend.
@ -82,11 +86,25 @@ func NewReadBackend(options ReadBackendOptions) ReadBackend {
type backend struct {
commitmentStore kv.Store
indexStore kv.Store
hooks Hooks
validateHooks ValidateHooks
writeHooks WriteHooks
}
func (c backend) WithHooks(hooks Hooks) Backend {
c.hooks = hooks
func (c backend) ValidateHooks() ValidateHooks {
return c.validateHooks
}
func (c backend) WithValidateHooks(hooks ValidateHooks) Backend {
c.validateHooks = hooks
return c
}
func (c backend) WriteHooks() WriteHooks {
return c.writeHooks
}
func (c backend) WithWriteHooks(hooks WriteHooks) Backend {
c.writeHooks = hooks
return c
}
@ -108,10 +126,6 @@ func (c backend) IndexStore() kv.Store {
return c.indexStore
}
func (c backend) Hooks() Hooks {
return c.hooks
}
// BackendOptions defines options for creating a Backend.
// Context can optionally define two stores - a commitment store
// that is backed by a merkle tree and an index store that isn't.
@ -126,8 +140,10 @@ type BackendOptions struct {
// If it is nil the CommitmentStore will be used.
IndexStore kv.Store
// Hooks are optional hooks into ORM insert, update and delete operations.
Hooks Hooks
// ValidateHooks are optional hooks into ORM insert, update and delete operations.
ValidateHooks ValidateHooks
WriteHooks WriteHooks
}
// NewBackend creates a new Backend.
@ -139,7 +155,8 @@ func NewBackend(options BackendOptions) Backend {
return &backend{
commitmentStore: options.CommitmentStore,
indexStore: indexStore,
hooks: options.Hooks,
validateHooks: options.ValidateHooks,
writeHooks: options.WriteHooks,
}
}

View File

@ -62,7 +62,9 @@ func flushWrites(store kv.Store, writer *batchStoreWriter) error {
func flushBuf(store kv.Store, writes []*batchWriterEntry) error {
for _, write := range writes {
if !write.delete {
if write.hookCall != nil {
write.hookCall()
} else if !write.delete {
err := store.Set(write.key, write.value)
if err != nil {
return err
@ -73,6 +75,7 @@ func flushBuf(store kv.Store, writes []*batchWriterEntry) error {
return err
}
}
}
return nil
}
@ -89,6 +92,7 @@ func (w *batchIndexCommitmentWriter) Close() {
type batchWriterEntry struct {
key, value []byte
delete bool
hookCall func()
}
type batchStoreWriter struct {
@ -109,6 +113,10 @@ func (b *batchStoreWriter) Delete(key []byte) error {
return nil
}
func (w *batchIndexCommitmentWriter) enqueueHook(f func()) {
w.indexWriter.append(&batchWriterEntry{hookCall: f})
}
func (b *batchStoreWriter) append(entry *batchWriterEntry) {
if len(b.curBuf) == capacity {
b.prevBufs = append(b.prevBufs, b.curBuf)

View File

@ -1,21 +1,42 @@
package ormtable
import "google.golang.org/protobuf/proto"
import (
"context"
// Hooks defines an interface for a table hooks which can intercept
// insert, update and delete operations. Table.Save and Table.Delete methods will
// do a type assertion on kvstore.IndexCommitmentStore and if the Hooks
// interface is defined call the appropriate hooks.
type Hooks interface {
// OnInsert is called before the message is inserted.
// If error is not nil the operation will fail.
OnInsert(proto.Message) error
"google.golang.org/protobuf/proto"
)
// OnUpdate is called before the existing message is updated with the new one.
// If error is not nil the operation will fail.
OnUpdate(existing, new proto.Message) error
// ValidateHooks defines an interface for a table hooks which can intercept
// insert, update and delete operations and possibly return an error.
type ValidateHooks interface {
// OnDelete is called before the message is deleted.
// If error is not nil the operation will fail.
OnDelete(proto.Message) error
// ValidateInsert is called before the message is inserted.
// If error is not nil the insertion will fail.
ValidateInsert(context.Context, proto.Message) error
// ValidateUpdate is called before the existing message is updated with the new one.
// If error is not nil the update will fail.
ValidateUpdate(ctx context.Context, existing, new proto.Message) error
// ValidateDelete is called before the message is deleted.
// If error is not nil the deletion will fail.
ValidateDelete(context.Context, proto.Message) error
}
// WriteHooks defines an interface for listening to insertions, updates and
// deletes after they are written to the store. This can be used for indexing
// state in another database. Indexers should make sure they coordinate with
// transactions at live at the next level above the ORM as they write hooks
// may be called but the enclosing transaction may still fail. The context
// is provided in each method to help coordinate this.
type WriteHooks interface {
// OnInsert is called after an message is inserted into the store.
OnInsert(context.Context, proto.Message)
// OnUpdate is called after the entity is updated in the store.
OnUpdate(ctx context.Context, existing, new proto.Message)
// OnDelete is called after the entity is deleted from the store.
OnDelete(context.Context, proto.Message)
}

View File

@ -127,7 +127,7 @@ func (p primaryKeyIndex) doDelete(ctx context.Context, primaryKeyValues []protor
return nil
}
err = p.doDeleteWithWriteBatch(backend, writer, pk, msg)
err = p.doDeleteWithWriteBatch(ctx, backend, writer, pk, msg)
if err != nil {
return err
}
@ -135,9 +135,9 @@ func (p primaryKeyIndex) doDelete(ctx context.Context, primaryKeyValues []protor
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(message)
func (p primaryKeyIndex) doDeleteWithWriteBatch(ctx context.Context, backend Backend, writer *batchIndexCommitmentWriter, primaryKeyBz []byte, message proto.Message) error {
if hooks := backend.ValidateHooks(); hooks != nil {
err := hooks.ValidateDelete(ctx, message)
if err != nil {
return err
}
@ -159,6 +159,12 @@ func (p primaryKeyIndex) doDeleteWithWriteBatch(backend Backend, writer *batchIn
}
}
if writeHooks := backend.WriteHooks(); writeHooks != nil {
writer.enqueueHook(func() {
writeHooks.OnDelete(ctx, message)
})
}
return nil
}
@ -209,7 +215,7 @@ func (p primaryKeyIndex) deleteByIterator(ctx context.Context, it Iterator) erro
return err
}
err = p.doDeleteWithWriteBatch(backend, writer, pkBz, msg)
err = p.doDeleteWithWriteBatch(ctx, backend, writer, pkBz, msg)
if err != nil {
return err
}

View File

@ -60,7 +60,7 @@ func (t singleton) ImportJSON(ctx context.Context, reader io.Reader) error {
return err
}
return t.save(backend, msg, saveModeDefault)
return t.save(ctx, backend, msg, saveModeDefault)
}
func (t singleton) ExportJSON(ctx context.Context, writer io.Writer) error {

View File

@ -60,8 +60,8 @@ type Table interface {
// Save saves the provided entry in the store either inserting it or
// updating it if needed.
//
// If store implement the Hooks interface, the appropriate OnInsert or
// OnUpdate hook method will be called.
// If store implement the ValidateHooks interface, the appropriate ValidateInsert or
// ValidateUpdate hook method will be called.
//
// Save attempts to be atomic with respect to the underlying store,
// meaning that either the full save operation is written or the store is
@ -81,7 +81,7 @@ type Table interface {
// if one exists. Other fields besides the primary key fields will not
// be used for retrieval.
//
// If store implement the Hooks interface, the OnDelete hook method will
// If store implement the ValidateHooks interface, the ValidateDelete hook method will
// be called.
//
// Delete attempts to be atomic with respect to the underlying store,

View File

@ -53,7 +53,7 @@ func (t tableImpl) Save(ctx context.Context, message proto.Message) error {
return err
}
return t.save(backend, message, saveModeDefault)
return t.save(ctx, backend, message, saveModeDefault)
}
func (t tableImpl) Insert(ctx context.Context, message proto.Message) error {
@ -62,7 +62,7 @@ func (t tableImpl) Insert(ctx context.Context, message proto.Message) error {
return err
}
return t.save(backend, message, saveModeInsert)
return t.save(ctx, backend, message, saveModeInsert)
}
func (t tableImpl) Update(ctx context.Context, message proto.Message) error {
@ -71,16 +71,16 @@ func (t tableImpl) Update(ctx context.Context, message proto.Message) error {
return err
}
return t.save(backend, message, saveModeUpdate)
return t.save(ctx, backend, message, saveModeUpdate)
}
func (t tableImpl) save(backend Backend, message proto.Message, mode saveMode) error {
func (t tableImpl) save(ctx context.Context, backend Backend, message proto.Message, mode saveMode) error {
writer := newBatchIndexCommitmentWriter(backend)
defer writer.Close()
return t.doSave(writer, message, mode)
return t.doSave(ctx, writer, message, mode)
}
func (t tableImpl) doSave(writer *batchIndexCommitmentWriter, message proto.Message, mode saveMode) error {
func (t tableImpl) doSave(ctx context.Context, writer *batchIndexCommitmentWriter, message proto.Message, mode saveMode) error {
mref := message.ProtoReflect()
pkValues, pk, err := t.EncodeKeyFromMessage(mref)
if err != nil {
@ -98,8 +98,8 @@ func (t tableImpl) doSave(writer *batchIndexCommitmentWriter, message proto.Mess
return ormerrors.PrimaryKeyConstraintViolation.Wrapf("%q:%+v", mref.Descriptor().FullName(), pkValues)
}
if hooks := writer.Hooks(); hooks != nil {
err = hooks.OnUpdate(existing, message)
if validateHooks := writer.ValidateHooks(); validateHooks != nil {
err = validateHooks.ValidateUpdate(ctx, existing, message)
if err != nil {
return err
}
@ -109,8 +109,8 @@ func (t tableImpl) doSave(writer *batchIndexCommitmentWriter, message proto.Mess
return ormerrors.NotFoundOnUpdate.Wrapf("%q", mref.Descriptor().FullName())
}
if hooks := writer.Hooks(); hooks != nil {
err = hooks.OnInsert(message)
if validateHooks := writer.ValidateHooks(); validateHooks != nil {
err = validateHooks.ValidateInsert(ctx, message)
if err != nil {
return err
}
@ -140,6 +140,11 @@ func (t tableImpl) doSave(writer *batchIndexCommitmentWriter, message proto.Mess
}
}
if writeHooks := writer.WriteHooks(); writeHooks != nil {
writer.enqueueHook(func() {
writeHooks.OnInsert(ctx, message)
})
}
} else {
existingMref := existing.ProtoReflect()
for _, idx := range t.indexers {
@ -148,6 +153,11 @@ func (t tableImpl) doSave(writer *batchIndexCommitmentWriter, message proto.Mess
return err
}
}
if writeHooks := writer.WriteHooks(); writeHooks != nil {
writer.enqueueHook(func() {
writeHooks.OnUpdate(ctx, existing, message)
})
}
}
return writer.Write()
@ -283,7 +293,7 @@ func (t tableImpl) ImportJSON(ctx context.Context, reader io.Reader) error {
}
return t.decodeJson(reader, func(message proto.Message) error {
return t.save(backend, message, saveModeDefault)
return t.save(ctx, backend, message, saveModeDefault)
})
}

View File

@ -4,7 +4,7 @@ GET 03808002
SEQ testpb.ExampleAutoIncrementTable 0
GET 03000001
PK testpb.ExampleAutoIncrementTable 1 -> {"id":1}
ORM INSERT testpb.ExampleAutoIncrementTable {"id":1,"x":"foo","y":5}
ORM BEFORE INSERT testpb.ExampleAutoIncrementTable {"id":1,"x":"foo","y":5}
HAS 0301666f6f
ERR:EOF
SET 03000001 1203666f6f1805
@ -13,11 +13,12 @@ SET 03808002 01
SEQ testpb.ExampleAutoIncrementTable 1
SET 0301666f6f 0001
UNIQ testpb.ExampleAutoIncrementTable x : foo -> 1
ORM AFTER INSERT testpb.ExampleAutoIncrementTable {"id":1,"x":"foo","y":5}
GET 03808002 01
SEQ testpb.ExampleAutoIncrementTable 1
GET 03000002
PK testpb.ExampleAutoIncrementTable 2 -> {"id":2}
ORM INSERT testpb.ExampleAutoIncrementTable {"id":2,"x":"bar","y":10}
ORM BEFORE INSERT testpb.ExampleAutoIncrementTable {"id":2,"x":"bar","y":10}
HAS 0301626172
ERR:EOF
SET 03000002 1203626172180a
@ -26,6 +27,7 @@ SET 03808002 02
SEQ testpb.ExampleAutoIncrementTable 2
SET 0301626172 0002
UNIQ testpb.ExampleAutoIncrementTable x : bar -> 2
ORM AFTER INSERT testpb.ExampleAutoIncrementTable {"id":2,"x":"bar","y":10}
GET 03808002 02
SEQ testpb.ExampleAutoIncrementTable 2
ITERATOR 0300 -> 0301
@ -54,18 +56,20 @@ ITERATOR 0300 -> 0301
VALID false
GET 03000001 1203666f6f1805
PK testpb.ExampleAutoIncrementTable 1 -> {"id":1,"x":"foo","y":5}
ORM DELETE testpb.ExampleAutoIncrementTable {"id":1,"x":"foo","y":5}
ORM BEFORE DELETE testpb.ExampleAutoIncrementTable {"id":1,"x":"foo","y":5}
DEL 03000001
DEL PK testpb.ExampleAutoIncrementTable 1 -> {"id":1}
DEL 0301666f6f
DEL ERR:EOF
ORM AFTER DELETE testpb.ExampleAutoIncrementTable {"id":1,"x":"foo","y":5}
GET 03000002 1203626172180a
PK testpb.ExampleAutoIncrementTable 2 -> {"id":2,"x":"bar","y":10}
ORM DELETE testpb.ExampleAutoIncrementTable {"id":2,"x":"bar","y":10}
ORM BEFORE DELETE testpb.ExampleAutoIncrementTable {"id":2,"x":"bar","y":10}
DEL 03000002
DEL PK testpb.ExampleAutoIncrementTable 2 -> {"id":2}
DEL 0301626172
DEL ERR:EOF
ORM AFTER DELETE testpb.ExampleAutoIncrementTable {"id":2,"x":"bar","y":10}
GET 03808002 02
SEQ testpb.ExampleAutoIncrementTable 2
ITERATOR 0300 -> 0301

View File

@ -1,6 +1,6 @@
GET 010000047ffffffffffffffe616263
PK testpb.ExampleTable 4/-2/abc -> {"u32":4,"str":"abc","i64":-2}
ORM INSERT testpb.ExampleTable {"u32":4,"u64":7,"str":"abc","i64":-2}
ORM BEFORE INSERT testpb.ExampleTable {"u32":4,"u64":7,"str":"abc","i64":-2}
HAS 01010007616263
ERR:EOF
SET 010000047ffffffffffffffe616263 1007
@ -11,6 +11,7 @@ SET 01026162630000047ffffffffffffffe
IDX testpb.ExampleTable str/u32/i64 : abc/4/-2 -> 4/-2/abc
SET 0103006162630000047ffffffffffffffe
IDX testpb.ExampleTable bz/str/u32/i64 : []/abc/4/-2 -> 4/-2/abc
ORM AFTER INSERT testpb.ExampleTable {"u32":4,"u64":7,"str":"abc","i64":-2}
ITERATOR 0100 -> 0101
VALID true
KEY 010000047ffffffffffffffe616263 1007
@ -19,7 +20,7 @@ ITERATOR 0100 -> 0101
VALID false
GET 010000047ffffffffffffffe616264
PK testpb.ExampleTable 4/-2/abd -> {"u32":4,"str":"abd","i64":-2}
ORM INSERT testpb.ExampleTable {"u32":4,"u64":7,"str":"abd","i64":-2}
ORM BEFORE INSERT testpb.ExampleTable {"u32":4,"u64":7,"str":"abd","i64":-2}
HAS 01010007616264
ERR:EOF
SET 010000047ffffffffffffffe616264 1007
@ -30,6 +31,7 @@ SET 01026162640000047ffffffffffffffe
IDX testpb.ExampleTable str/u32/i64 : abd/4/-2 -> 4/-2/abd
SET 0103006162640000047ffffffffffffffe
IDX testpb.ExampleTable bz/str/u32/i64 : []/abd/4/-2 -> 4/-2/abd
ORM AFTER INSERT testpb.ExampleTable {"u32":4,"u64":7,"str":"abd","i64":-2}
ITERATOR 0100 -> 0101
VALID true
KEY 010000047ffffffffffffffe616263 1007
@ -42,7 +44,7 @@ ITERATOR 0100 -> 0101
VALID false
GET 010000047fffffffffffffff616263
PK testpb.ExampleTable 4/-1/abc -> {"u32":4,"str":"abc","i64":-1}
ORM INSERT testpb.ExampleTable {"u32":4,"u64":8,"str":"abc","i64":-1}
ORM BEFORE INSERT testpb.ExampleTable {"u32":4,"u64":8,"str":"abc","i64":-1}
HAS 01010008616263
ERR:EOF
SET 010000047fffffffffffffff616263 1008
@ -53,9 +55,10 @@ SET 01026162630000047fffffffffffffff
IDX testpb.ExampleTable str/u32/i64 : abc/4/-1 -> 4/-1/abc
SET 0103006162630000047fffffffffffffff
IDX testpb.ExampleTable bz/str/u32/i64 : []/abc/4/-1 -> 4/-1/abc
ORM AFTER INSERT testpb.ExampleTable {"u32":4,"u64":8,"str":"abc","i64":-1}
GET 010000057ffffffffffffffe616264
PK testpb.ExampleTable 5/-2/abd -> {"u32":5,"str":"abd","i64":-2}
ORM INSERT testpb.ExampleTable {"u32":5,"u64":8,"str":"abd","i64":-2}
ORM BEFORE INSERT testpb.ExampleTable {"u32":5,"u64":8,"str":"abd","i64":-2}
HAS 01010008616264
ERR:EOF
SET 010000057ffffffffffffffe616264 1008
@ -66,9 +69,10 @@ SET 01026162640000057ffffffffffffffe
IDX testpb.ExampleTable str/u32/i64 : abd/5/-2 -> 5/-2/abd
SET 0103006162640000057ffffffffffffffe
IDX testpb.ExampleTable bz/str/u32/i64 : []/abd/5/-2 -> 5/-2/abd
ORM AFTER INSERT testpb.ExampleTable {"u32":5,"u64":8,"str":"abd","i64":-2}
GET 010000057ffffffffffffffe616265
PK testpb.ExampleTable 5/-2/abe -> {"u32":5,"str":"abe","i64":-2}
ORM INSERT testpb.ExampleTable {"u32":5,"u64":9,"str":"abe","i64":-2}
ORM BEFORE INSERT testpb.ExampleTable {"u32":5,"u64":9,"str":"abe","i64":-2}
HAS 01010009616265
ERR:EOF
SET 010000057ffffffffffffffe616265 1009
@ -79,9 +83,10 @@ SET 01026162650000057ffffffffffffffe
IDX testpb.ExampleTable str/u32/i64 : abe/5/-2 -> 5/-2/abe
SET 0103006162650000057ffffffffffffffe
IDX testpb.ExampleTable bz/str/u32/i64 : []/abe/5/-2 -> 5/-2/abe
ORM AFTER INSERT testpb.ExampleTable {"u32":5,"u64":9,"str":"abe","i64":-2}
GET 010000077ffffffffffffffe616265
PK testpb.ExampleTable 7/-2/abe -> {"u32":7,"str":"abe","i64":-2}
ORM INSERT testpb.ExampleTable {"u32":7,"u64":10,"str":"abe","i64":-2}
ORM BEFORE INSERT testpb.ExampleTable {"u32":7,"u64":10,"str":"abe","i64":-2}
HAS 0101000a616265
ERR:EOF
SET 010000077ffffffffffffffe616265 100a
@ -92,9 +97,10 @@ SET 01026162650000077ffffffffffffffe
IDX testpb.ExampleTable str/u32/i64 : abe/7/-2 -> 7/-2/abe
SET 0103006162650000077ffffffffffffffe
IDX testpb.ExampleTable bz/str/u32/i64 : []/abe/7/-2 -> 7/-2/abe
ORM AFTER INSERT testpb.ExampleTable {"u32":7,"u64":10,"str":"abe","i64":-2}
GET 010000077fffffffffffffff616265
PK testpb.ExampleTable 7/-1/abe -> {"u32":7,"str":"abe","i64":-1}
ORM INSERT testpb.ExampleTable {"u32":7,"u64":11,"str":"abe","i64":-1}
ORM BEFORE INSERT testpb.ExampleTable {"u32":7,"u64":11,"str":"abe","i64":-1}
HAS 0101000b616265
ERR:EOF
SET 010000077fffffffffffffff616265 100b
@ -105,9 +111,10 @@ SET 01026162650000077fffffffffffffff
IDX testpb.ExampleTable str/u32/i64 : abe/7/-1 -> 7/-1/abe
SET 0103006162650000077fffffffffffffff
IDX testpb.ExampleTable bz/str/u32/i64 : []/abe/7/-1 -> 7/-1/abe
ORM AFTER INSERT testpb.ExampleTable {"u32":7,"u64":11,"str":"abe","i64":-1}
GET 010000087ffffffffffffffc616263
PK testpb.ExampleTable 8/-4/abc -> {"u32":8,"str":"abc","i64":-4}
ORM INSERT testpb.ExampleTable {"u32":8,"u64":11,"str":"abc","i64":-4}
ORM BEFORE INSERT testpb.ExampleTable {"u32":8,"u64":11,"str":"abc","i64":-4}
HAS 0101000b616263
ERR:EOF
SET 010000087ffffffffffffffc616263 100b
@ -118,9 +125,10 @@ SET 01026162630000087ffffffffffffffc
IDX testpb.ExampleTable str/u32/i64 : abc/8/-4 -> 8/-4/abc
SET 0103006162630000087ffffffffffffffc
IDX testpb.ExampleTable bz/str/u32/i64 : []/abc/8/-4 -> 8/-4/abc
ORM AFTER INSERT testpb.ExampleTable {"u32":8,"u64":11,"str":"abc","i64":-4}
GET 010000088000000000000001616263
PK testpb.ExampleTable 8/1/abc -> {"u32":8,"str":"abc","i64":1}
ORM INSERT testpb.ExampleTable {"u32":8,"u64":12,"str":"abc","i64":1}
ORM BEFORE INSERT testpb.ExampleTable {"u32":8,"u64":12,"str":"abc","i64":1}
HAS 0101000c616263
ERR:EOF
SET 010000088000000000000001616263 100c
@ -131,9 +139,10 @@ SET 01026162630000088000000000000001
IDX testpb.ExampleTable str/u32/i64 : abc/8/1 -> 8/1/abc
SET 0103006162630000088000000000000001
IDX testpb.ExampleTable bz/str/u32/i64 : []/abc/8/1 -> 8/1/abc
ORM AFTER INSERT testpb.ExampleTable {"u32":8,"u64":12,"str":"abc","i64":1}
GET 010000088000000000000001616264
PK testpb.ExampleTable 8/1/abd -> {"u32":8,"str":"abd","i64":1}
ORM INSERT testpb.ExampleTable {"u32":8,"u64":10,"str":"abd","i64":1}
ORM BEFORE INSERT testpb.ExampleTable {"u32":8,"u64":10,"str":"abd","i64":1}
HAS 0101000a616264
ERR:EOF
SET 010000088000000000000001616264 100a
@ -144,6 +153,7 @@ SET 01026162640000088000000000000001
IDX testpb.ExampleTable str/u32/i64 : abd/8/1 -> 8/1/abd
SET 0103006162640000088000000000000001
IDX testpb.ExampleTable bz/str/u32/i64 : []/abd/8/1 -> 8/1/abd
ORM AFTER INSERT testpb.ExampleTable {"u32":8,"u64":10,"str":"abd","i64":1}
ITERATOR 01000008 -> 01000009
VALID true
KEY 010000087ffffffffffffffc616263 100b
@ -614,7 +624,7 @@ ITERATOR 0100 -> 0101
VALID false
GET 010000047ffffffffffffffe616263 1007
PK testpb.ExampleTable 4/-2/abc -> {"u32":4,"u64":7,"str":"abc","i64":-2}
ORM UPDATE testpb.ExampleTable {"u32":4,"u64":7,"str":"abc","i64":-2} -> {"u32":4,"u64":14,"str":"abc","bz":"abc","i64":-2}
ORM BEFORE UPDATE testpb.ExampleTable {"u32":4,"u64":7,"str":"abc","i64":-2} -> {"u32":4,"u64":14,"str":"abc","bz":"abc","i64":-2}
HAS 0101000e616263
ERR:EOF
SET 010000047ffffffffffffffe616263 100e2203616263
@ -627,9 +637,10 @@ DEL 0103006162630000047ffffffffffffffe
DEL IDX testpb.ExampleTable bz/str/u32/i64 : []/abc/4/-2 -> 4/-2/abc
SET 0103036162636162630000047ffffffffffffffe
IDX testpb.ExampleTable bz/str/u32/i64 : [97 98 99]/abc/4/-2 -> 4/-2/abc
ORM AFTER UPDATE testpb.ExampleTable {"u32":4,"u64":7,"str":"abc","i64":-2} -> {"u32":4,"u64":14,"str":"abc","bz":"abc","i64":-2}
GET 010000047ffffffffffffffe616264 1007
PK testpb.ExampleTable 4/-2/abd -> {"u32":4,"u64":7,"str":"abd","i64":-2}
ORM UPDATE testpb.ExampleTable {"u32":4,"u64":7,"str":"abd","i64":-2} -> {"u32":4,"u64":14,"str":"abd","bz":"abd","i64":-2}
ORM BEFORE UPDATE testpb.ExampleTable {"u32":4,"u64":7,"str":"abd","i64":-2} -> {"u32":4,"u64":14,"str":"abd","bz":"abd","i64":-2}
HAS 0101000e616264
ERR:EOF
SET 010000047ffffffffffffffe616264 100e2203616264
@ -642,9 +653,10 @@ DEL 0103006162640000047ffffffffffffffe
DEL IDX testpb.ExampleTable bz/str/u32/i64 : []/abd/4/-2 -> 4/-2/abd
SET 0103036162646162640000047ffffffffffffffe
IDX testpb.ExampleTable bz/str/u32/i64 : [97 98 100]/abd/4/-2 -> 4/-2/abd
ORM AFTER UPDATE testpb.ExampleTable {"u32":4,"u64":7,"str":"abd","i64":-2} -> {"u32":4,"u64":14,"str":"abd","bz":"abd","i64":-2}
GET 010000047fffffffffffffff616263 1008
PK testpb.ExampleTable 4/-1/abc -> {"u32":4,"u64":8,"str":"abc","i64":-1}
ORM UPDATE testpb.ExampleTable {"u32":4,"u64":8,"str":"abc","i64":-1} -> {"u32":4,"u64":16,"str":"abc","bz":"abc","i64":-1}
ORM BEFORE UPDATE testpb.ExampleTable {"u32":4,"u64":8,"str":"abc","i64":-1} -> {"u32":4,"u64":16,"str":"abc","bz":"abc","i64":-1}
HAS 01010010616263
ERR:EOF
SET 010000047fffffffffffffff616263 10102203616263
@ -657,9 +669,10 @@ DEL 0103006162630000047fffffffffffffff
DEL IDX testpb.ExampleTable bz/str/u32/i64 : []/abc/4/-1 -> 4/-1/abc
SET 0103036162636162630000047fffffffffffffff
IDX testpb.ExampleTable bz/str/u32/i64 : [97 98 99]/abc/4/-1 -> 4/-1/abc
ORM AFTER UPDATE testpb.ExampleTable {"u32":4,"u64":8,"str":"abc","i64":-1} -> {"u32":4,"u64":16,"str":"abc","bz":"abc","i64":-1}
GET 010000057ffffffffffffffe616264 1008
PK testpb.ExampleTable 5/-2/abd -> {"u32":5,"u64":8,"str":"abd","i64":-2}
ORM UPDATE testpb.ExampleTable {"u32":5,"u64":8,"str":"abd","i64":-2} -> {"u32":5,"u64":16,"str":"abd","bz":"abd","i64":-2}
ORM BEFORE UPDATE testpb.ExampleTable {"u32":5,"u64":8,"str":"abd","i64":-2} -> {"u32":5,"u64":16,"str":"abd","bz":"abd","i64":-2}
HAS 01010010616264
ERR:EOF
SET 010000057ffffffffffffffe616264 10102203616264
@ -672,9 +685,10 @@ DEL 0103006162640000057ffffffffffffffe
DEL IDX testpb.ExampleTable bz/str/u32/i64 : []/abd/5/-2 -> 5/-2/abd
SET 0103036162646162640000057ffffffffffffffe
IDX testpb.ExampleTable bz/str/u32/i64 : [97 98 100]/abd/5/-2 -> 5/-2/abd
ORM AFTER UPDATE testpb.ExampleTable {"u32":5,"u64":8,"str":"abd","i64":-2} -> {"u32":5,"u64":16,"str":"abd","bz":"abd","i64":-2}
GET 010000057ffffffffffffffe616265 1009
PK testpb.ExampleTable 5/-2/abe -> {"u32":5,"u64":9,"str":"abe","i64":-2}
ORM UPDATE testpb.ExampleTable {"u32":5,"u64":9,"str":"abe","i64":-2} -> {"u32":5,"u64":18,"str":"abe","bz":"abe","i64":-2}
ORM BEFORE UPDATE testpb.ExampleTable {"u32":5,"u64":9,"str":"abe","i64":-2} -> {"u32":5,"u64":18,"str":"abe","bz":"abe","i64":-2}
HAS 01010012616265
ERR:EOF
SET 010000057ffffffffffffffe616265 10122203616265
@ -687,6 +701,7 @@ DEL 0103006162650000057ffffffffffffffe
DEL IDX testpb.ExampleTable bz/str/u32/i64 : []/abe/5/-2 -> 5/-2/abe
SET 0103036162656162650000057ffffffffffffffe
IDX testpb.ExampleTable bz/str/u32/i64 : [97 98 101]/abe/5/-2 -> 5/-2/abe
ORM AFTER UPDATE testpb.ExampleTable {"u32":5,"u64":9,"str":"abe","i64":-2} -> {"u32":5,"u64":18,"str":"abe","bz":"abe","i64":-2}
ITERATOR 0100 -> 0101
VALID true
KEY 010000047ffffffffffffffe616263 100e2203616263
@ -731,7 +746,7 @@ ITERATOR 0100 -> 0101
VALID false
GET 010000098000000000000000
PK testpb.ExampleTable 9/0/ -> {"u32":9}
ORM INSERT testpb.ExampleTable {"u32":9}
ORM BEFORE INSERT testpb.ExampleTable {"u32":9}
HAS 01010000
ERR:EOF
SET 010000098000000000000000
@ -742,13 +757,15 @@ SET 01020000098000000000000000
IDX testpb.ExampleTable str/u32/i64 : /9/0 -> 9/0/
SET 0103000000098000000000000000
IDX testpb.ExampleTable bz/str/u32/i64 : []//9/0 -> 9/0/
ORM AFTER INSERT testpb.ExampleTable {"u32":9}
GET 010000098000000000000000
PK testpb.ExampleTable 9/0/ -> {"u32":9}
GET 010000098000000000000000
PK testpb.ExampleTable 9/0/ -> {"u32":9}
ORM UPDATE testpb.ExampleTable {"u32":9} -> {"u32":9,"b":true}
ORM BEFORE UPDATE testpb.ExampleTable {"u32":9} -> {"u32":9,"b":true}
SET 010000098000000000000000 7801
PK testpb.ExampleTable 9/0/ -> {"u32":9,"b":true}
ORM AFTER UPDATE testpb.ExampleTable {"u32":9} -> {"u32":9,"b":true}
GET 010000098000000000000000 7801
PK testpb.ExampleTable 9/0/ -> {"u32":9,"b":true}
ITERATOR 0100 -> 0101
@ -913,7 +930,7 @@ ITERATOR 0100 -> 0101
VALID false
GET 010000077ffffffffffffffe616265 100a
PK testpb.ExampleTable 7/-2/abe -> {"u32":7,"u64":10,"str":"abe","i64":-2}
ORM DELETE testpb.ExampleTable {"u32":7,"u64":10,"str":"abe","i64":-2}
ORM BEFORE DELETE testpb.ExampleTable {"u32":7,"u64":10,"str":"abe","i64":-2}
DEL 010000077ffffffffffffffe616265
DEL PK testpb.ExampleTable 7/-2/abe -> {"u32":7,"str":"abe","i64":-2}
DEL 0101000a616265
@ -922,6 +939,7 @@ DEL 01026162650000077ffffffffffffffe
DEL IDX testpb.ExampleTable str/u32/i64 : abe/7/-2 -> 7/-2/abe
DEL 0103006162650000077ffffffffffffffe
DEL IDX testpb.ExampleTable bz/str/u32/i64 : []/abe/7/-2 -> 7/-2/abe
ORM AFTER DELETE testpb.ExampleTable {"u32":7,"u64":10,"str":"abe","i64":-2}
HAS 010000077ffffffffffffffe616265
PK testpb.ExampleTable 7/-2/abe -> {"u32":7,"str":"abe","i64":-2}
ITERATOR 0100 -> 0101
@ -992,21 +1010,21 @@ ITERATOR 010261626400 -> 010261626401
IDX testpb.ExampleTable str/u32/i64 : abd/4/-2 -> 4/-2/abd
GET 010000047ffffffffffffffe616264 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}
ORM BEFORE DELETE testpb.ExampleTable {"u32":4,"u64":14,"str":"abd","bz":"abd","i64":-2}
NEXT
VALID true
KEY 01026162640000057ffffffffffffffe
IDX testpb.ExampleTable str/u32/i64 : abd/5/-2 -> 5/-2/abd
GET 010000057ffffffffffffffe616264 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}
ORM BEFORE DELETE testpb.ExampleTable {"u32":5,"u64":16,"str":"abd","bz":"abd","i64":-2}
NEXT
VALID true
KEY 01026162640000088000000000000001
IDX testpb.ExampleTable str/u32/i64 : abd/8/1 -> 8/1/abd
GET 010000088000000000000001616264 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}
ORM BEFORE DELETE testpb.ExampleTable {"u32":8,"u64":10,"str":"abd","i64":1}
NEXT
VALID false
CLOSE
@ -1022,18 +1040,21 @@ DEL 01026162640000047ffffffffffffffe
DEL IDX testpb.ExampleTable str/u32/i64 : abd/4/-2 -> 4/-2/abd
DEL 0103036162646162640000047ffffffffffffffe
DEL IDX testpb.ExampleTable bz/str/u32/i64 : [97 98 100]/abd/4/-2 -> 4/-2/abd
ORM AFTER DELETE testpb.ExampleTable {"u32":4,"u64":14,"str":"abd","bz":"abd","i64":-2}
DEL 01010010616264
DEL ERR:EOF
DEL 01026162640000057ffffffffffffffe
DEL IDX testpb.ExampleTable str/u32/i64 : abd/5/-2 -> 5/-2/abd
DEL 0103036162646162640000057ffffffffffffffe
DEL IDX testpb.ExampleTable bz/str/u32/i64 : [97 98 100]/abd/5/-2 -> 5/-2/abd
ORM AFTER DELETE testpb.ExampleTable {"u32":5,"u64":16,"str":"abd","bz":"abd","i64":-2}
DEL 0101000a616264
DEL ERR:EOF
DEL 01026162640000088000000000000001
DEL IDX testpb.ExampleTable str/u32/i64 : abd/8/1 -> 8/1/abd
DEL 0103006162640000088000000000000001
DEL IDX testpb.ExampleTable bz/str/u32/i64 : []/abd/8/1 -> 8/1/abd
ORM AFTER DELETE testpb.ExampleTable {"u32":8,"u64":10,"str":"abd","i64":1}
ITERATOR 0100 -> 0101
VALID true
KEY 010000047ffffffffffffffe616263 100e2203616263
@ -1070,21 +1091,21 @@ ITERATOR 0102616263000008 -> 0102616265000006
IDX testpb.ExampleTable str/u32/i64 : abc/8/-4 -> 8/-4/abc
GET 010000087ffffffffffffffc616263 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}
ORM BEFORE DELETE testpb.ExampleTable {"u32":8,"u64":11,"str":"abc","i64":-4}
NEXT
VALID true
KEY 01026162630000088000000000000001
IDX testpb.ExampleTable str/u32/i64 : abc/8/1 -> 8/1/abc
GET 010000088000000000000001616263 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}
ORM BEFORE DELETE testpb.ExampleTable {"u32":8,"u64":12,"str":"abc","i64":1}
NEXT
VALID true
KEY 01026162650000057ffffffffffffffe
IDX testpb.ExampleTable str/u32/i64 : abe/5/-2 -> 5/-2/abe
GET 010000057ffffffffffffffe616265 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}
ORM BEFORE DELETE testpb.ExampleTable {"u32":5,"u64":18,"str":"abe","bz":"abe","i64":-2}
NEXT
VALID false
CLOSE
@ -1100,18 +1121,21 @@ DEL 01026162630000087ffffffffffffffc
DEL IDX testpb.ExampleTable str/u32/i64 : abc/8/-4 -> 8/-4/abc
DEL 0103006162630000087ffffffffffffffc
DEL IDX testpb.ExampleTable bz/str/u32/i64 : []/abc/8/-4 -> 8/-4/abc
ORM AFTER DELETE testpb.ExampleTable {"u32":8,"u64":11,"str":"abc","i64":-4}
DEL 0101000c616263
DEL ERR:EOF
DEL 01026162630000088000000000000001
DEL IDX testpb.ExampleTable str/u32/i64 : abc/8/1 -> 8/1/abc
DEL 0103006162630000088000000000000001
DEL IDX testpb.ExampleTable bz/str/u32/i64 : []/abc/8/1 -> 8/1/abc
ORM AFTER DELETE testpb.ExampleTable {"u32":8,"u64":12,"str":"abc","i64":1}
DEL 01010012616265
DEL ERR:EOF
DEL 01026162650000057ffffffffffffffe
DEL IDX testpb.ExampleTable str/u32/i64 : abe/5/-2 -> 5/-2/abe
DEL 0103036162656162650000057ffffffffffffffe
DEL IDX testpb.ExampleTable bz/str/u32/i64 : [97 98 101]/abe/5/-2 -> 5/-2/abe
ORM AFTER DELETE testpb.ExampleTable {"u32":5,"u64":18,"str":"abe","bz":"abe","i64":-2}
ITERATOR 0100 -> 0101
VALID true
KEY 010000047ffffffffffffffe616263 100e2203616263
@ -1132,7 +1156,7 @@ ITERATOR 0100 -> 0101
VALID false
GET 010000047ffffffffffffffe616263 100e2203616263
PK testpb.ExampleTable 4/-2/abc -> {"u32":4,"u64":14,"str":"abc","bz":"abc","i64":-2}
ORM DELETE testpb.ExampleTable {"u32":4,"u64":14,"str":"abc","bz":"abc","i64":-2}
ORM BEFORE DELETE testpb.ExampleTable {"u32":4,"u64":14,"str":"abc","bz":"abc","i64":-2}
DEL 010000047ffffffffffffffe616263
DEL PK testpb.ExampleTable 4/-2/abc -> {"u32":4,"str":"abc","i64":-2}
DEL 0101000e616263
@ -1141,6 +1165,7 @@ DEL 01026162630000047ffffffffffffffe
DEL IDX testpb.ExampleTable str/u32/i64 : abc/4/-2 -> 4/-2/abc
DEL 0103036162636162630000047ffffffffffffffe
DEL IDX testpb.ExampleTable bz/str/u32/i64 : [97 98 99]/abc/4/-2 -> 4/-2/abc
ORM AFTER DELETE testpb.ExampleTable {"u32":4,"u64":14,"str":"abc","bz":"abc","i64":-2}
ITERATOR 0100 -> 0101
VALID true
KEY 010000047fffffffffffffff616263 10102203616263

View File

@ -1,5 +1,5 @@
// Package ormmocks contains generated mocks for orm types that can be used
// in testing. Right now, this package only contains a mock for ormtable.Hooks
// in testing. Right now, this package only contains a mock for ormtable.ValidateHooks
// as this useful way for unit testing using an in-memory database. Rather
// than attempting to mock a whole table or database instance, instead
// a mock Hook instance can be passed in to verify that the expected
@ -9,5 +9,5 @@
// be used in gomock EXPECT functions.
//
// See TestHooks in ormdb/module_test.go for examples of how to use
// mock Hooks in a real-world scenario.
// mock ValidateHooks in a real-world scenario.
package ormmocks

View File

@ -5,73 +5,133 @@
package ormmocks
import (
context "context"
reflect "reflect"
gomock "github.com/golang/mock/gomock"
proto "google.golang.org/protobuf/proto"
)
// MockHooks is a mock of Hooks interface.
type MockHooks struct {
// MockValidateHooks is a mock of ValidateHooks interface.
type MockValidateHooks struct {
ctrl *gomock.Controller
recorder *MockHooksMockRecorder
recorder *MockValidateHooksMockRecorder
}
// MockHooksMockRecorder is the mock recorder for MockHooks.
type MockHooksMockRecorder struct {
mock *MockHooks
// MockValidateHooksMockRecorder is the mock recorder for MockValidateHooks.
type MockValidateHooksMockRecorder struct {
mock *MockValidateHooks
}
// NewMockHooks creates a new mock instance.
func NewMockHooks(ctrl *gomock.Controller) *MockHooks {
mock := &MockHooks{ctrl: ctrl}
mock.recorder = &MockHooksMockRecorder{mock}
// NewMockValidateHooks creates a new mock instance.
func NewMockValidateHooks(ctrl *gomock.Controller) *MockValidateHooks {
mock := &MockValidateHooks{ctrl: ctrl}
mock.recorder = &MockValidateHooksMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockHooks) EXPECT() *MockHooksMockRecorder {
func (m *MockValidateHooks) EXPECT() *MockValidateHooksMockRecorder {
return m.recorder
}
// ValidateDelete mocks base method.
func (m *MockValidateHooks) ValidateDelete(arg0 context.Context, arg1 proto.Message) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ValidateDelete", arg0, arg1)
ret0, _ := ret[0].(error)
return ret0
}
// ValidateDelete indicates an expected call of ValidateDelete.
func (mr *MockValidateHooksMockRecorder) ValidateDelete(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateDelete", reflect.TypeOf((*MockValidateHooks)(nil).ValidateDelete), arg0, arg1)
}
// ValidateInsert mocks base method.
func (m *MockValidateHooks) ValidateInsert(arg0 context.Context, arg1 proto.Message) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ValidateInsert", arg0, arg1)
ret0, _ := ret[0].(error)
return ret0
}
// ValidateInsert indicates an expected call of ValidateInsert.
func (mr *MockValidateHooksMockRecorder) ValidateInsert(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateInsert", reflect.TypeOf((*MockValidateHooks)(nil).ValidateInsert), arg0, arg1)
}
// ValidateUpdate mocks base method.
func (m *MockValidateHooks) ValidateUpdate(ctx context.Context, existing, new proto.Message) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ValidateUpdate", ctx, existing, new)
ret0, _ := ret[0].(error)
return ret0
}
// ValidateUpdate indicates an expected call of ValidateUpdate.
func (mr *MockValidateHooksMockRecorder) ValidateUpdate(ctx, existing, new interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateUpdate", reflect.TypeOf((*MockValidateHooks)(nil).ValidateUpdate), ctx, existing, new)
}
// MockWriteHooks is a mock of WriteHooks interface.
type MockWriteHooks struct {
ctrl *gomock.Controller
recorder *MockWriteHooksMockRecorder
}
// MockWriteHooksMockRecorder is the mock recorder for MockWriteHooks.
type MockWriteHooksMockRecorder struct {
mock *MockWriteHooks
}
// NewMockWriteHooks creates a new mock instance.
func NewMockWriteHooks(ctrl *gomock.Controller) *MockWriteHooks {
mock := &MockWriteHooks{ctrl: ctrl}
mock.recorder = &MockWriteHooksMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockWriteHooks) EXPECT() *MockWriteHooksMockRecorder {
return m.recorder
}
// OnDelete mocks base method.
func (m *MockHooks) OnDelete(arg0 proto.Message) error {
func (m *MockWriteHooks) OnDelete(arg0 context.Context, arg1 proto.Message) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "OnDelete", arg0)
ret0, _ := ret[0].(error)
return ret0
m.ctrl.Call(m, "OnDelete", arg0, arg1)
}
// OnDelete indicates an expected call of OnDelete.
func (mr *MockHooksMockRecorder) OnDelete(arg0 interface{}) *gomock.Call {
func (mr *MockWriteHooksMockRecorder) OnDelete(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnDelete", reflect.TypeOf((*MockHooks)(nil).OnDelete), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnDelete", reflect.TypeOf((*MockWriteHooks)(nil).OnDelete), arg0, arg1)
}
// OnInsert mocks base method.
func (m *MockHooks) OnInsert(arg0 proto.Message) error {
func (m *MockWriteHooks) OnInsert(arg0 context.Context, arg1 proto.Message) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "OnInsert", arg0)
ret0, _ := ret[0].(error)
return ret0
m.ctrl.Call(m, "OnInsert", arg0, arg1)
}
// OnInsert indicates an expected call of OnInsert.
func (mr *MockHooksMockRecorder) OnInsert(arg0 interface{}) *gomock.Call {
func (mr *MockWriteHooksMockRecorder) OnInsert(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnInsert", reflect.TypeOf((*MockHooks)(nil).OnInsert), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnInsert", reflect.TypeOf((*MockWriteHooks)(nil).OnInsert), arg0, arg1)
}
// OnUpdate mocks base method.
func (m *MockHooks) OnUpdate(existing, new proto.Message) error {
func (m *MockWriteHooks) OnUpdate(ctx context.Context, existing, new proto.Message) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "OnUpdate", existing, new)
ret0, _ := ret[0].(error)
return ret0
m.ctrl.Call(m, "OnUpdate", ctx, existing, new)
}
// OnUpdate indicates an expected call of OnUpdate.
func (mr *MockHooksMockRecorder) OnUpdate(existing, new interface{}) *gomock.Call {
func (mr *MockWriteHooksMockRecorder) OnUpdate(ctx, existing, new interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnUpdate", reflect.TypeOf((*MockHooks)(nil).OnUpdate), existing, new)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnUpdate", reflect.TypeOf((*MockWriteHooks)(nil).OnUpdate), ctx, existing, new)
}