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 package testkv
import ( import (
"context"
"fmt" "fmt"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
@ -23,10 +24,16 @@ type Debugger interface {
// NewDebugBackend wraps both stores from a Backend with a debugger. // NewDebugBackend wraps both stores from a Backend with a debugger.
func NewDebugBackend(backend ormtable.Backend, debugger Debugger) ormtable.Backend { func NewDebugBackend(backend ormtable.Backend, debugger Debugger) ormtable.Backend {
hooks := debugHooks{
debugger: debugger,
validateHooks: backend.ValidateHooks(),
writeHooks: backend.WriteHooks(),
}
return ormtable.NewBackend(ormtable.BackendOptions{ return ormtable.NewBackend(ormtable.BackendOptions{
CommitmentStore: NewDebugStore(backend.CommitmentStore(), debugger, "commit"), CommitmentStore: NewDebugStore(backend.CommitmentStore(), debugger, "commit"),
IndexStore: NewDebugStore(backend.IndexStore(), debugger, "index"), 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 { type debugHooks struct {
debugger Debugger debugger Debugger
hooks ormtable.Hooks 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) jsonBz, err := stablejson.Marshal(message)
if err != nil { if err != nil {
return err return err
} }
d.debugger.Log(fmt.Sprintf( d.debugger.Log(fmt.Sprintf(
"ORM INSERT %s %s", "ORM BEFORE INSERT %s %s",
message.ProtoReflect().Descriptor().FullName(), message.ProtoReflect().Descriptor().FullName(),
jsonBz, jsonBz,
)) ))
if d.hooks != nil { if d.validateHooks != nil {
return d.hooks.OnInsert(message) return d.validateHooks.ValidateInsert(context, message)
} }
return nil 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) existingJson, err := stablejson.Marshal(existing)
if err != nil { if err != nil {
return err return err
@ -239,30 +247,84 @@ func (d debugHooks) OnUpdate(existing, new proto.Message) error {
} }
d.debugger.Log(fmt.Sprintf( d.debugger.Log(fmt.Sprintf(
"ORM UPDATE %s %s -> %s", "ORM BEFORE UPDATE %s %s -> %s",
existing.ProtoReflect().Descriptor().FullName(), existing.ProtoReflect().Descriptor().FullName(),
existingJson, existingJson,
newJson, newJson,
)) ))
if d.hooks != nil { if d.validateHooks != nil {
return d.hooks.OnUpdate(existing, new) return d.validateHooks.ValidateUpdate(ctx, existing, new)
} }
return nil 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) jsonBz, err := stablejson.Marshal(message)
if err != nil { if err != nil {
return err return err
} }
d.debugger.Log(fmt.Sprintf( d.debugger.Log(fmt.Sprintf(
"ORM DELETE %s %s", "ORM BEFORE DELETE %s %s",
message.ProtoReflect().Descriptor().FullName(), message.ProtoReflect().Descriptor().FullName(),
jsonBz, jsonBz,
)) ))
if d.hooks != nil { if d.validateHooks != nil {
return d.hooks.OnDelete(message) return d.validateHooks.ValidateDelete(ctx, message)
} }
return nil 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) ctrl := gomock.NewController(t)
db, err := ormdb.NewModuleDB(TestBankSchema, ormdb.ModuleDBOptions{}) db, err := ormdb.NewModuleDB(TestBankSchema, ormdb.ModuleDBOptions{})
assert.NilError(t, err) assert.NilError(t, err)
hooks := ormmocks.NewMockHooks(ctrl) validateHooks := ormmocks.NewMockValidateHooks(ctrl)
ctx := ormtable.WrapContextDefault(ormtest.NewMemoryBackend().WithHooks(hooks)) writeHooks := ormmocks.NewMockWriteHooks(ctrl)
ctx := ormtable.WrapContextDefault(ormtest.NewMemoryBackend().
WithValidateHooks(validateHooks).
WithWriteHooks(writeHooks))
k, err := NewKeeper(db) k, err := NewKeeper(db)
assert.NilError(t, err) assert.NilError(t, err)
@ -284,24 +287,48 @@ func TestHooks(t *testing.T) {
acct1 := "bob" acct1 := "bob"
acct2 := "sally" acct2 := "sally"
hooks.EXPECT().OnInsert(ormmocks.Eq(&testpb.Balance{Address: acct1, Denom: denom, Amount: 10})) validateHooks.EXPECT().ValidateInsert(gomock.Any(), 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.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)) 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: 10}),
ormmocks.Eq(&testpb.Balance{Address: acct1, Denom: denom, Amount: 5}), 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}), ormmocks.Eq(&testpb.Balance{Address: acct2, Denom: denom, Amount: 5}),
) )
assert.NilError(t, k.Send(ctx, acct1, acct2, denom, 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: 10}),
ormmocks.Eq(&testpb.Supply{Denom: denom, Amount: 5}), 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}), ormmocks.Eq(&testpb.Balance{Address: acct1, Denom: denom, Amount: 5}),
) )
assert.NilError(t, k.Burn(ctx, acct1, denom, 5)) assert.NilError(t, k.Burn(ctx, acct1, denom, 5))

View File

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

View File

@ -28,7 +28,7 @@ func (t autoIncrementTable) InsertReturningID(ctx context.Context, message proto
return 0, err 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 { 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 return err
} }
_, err = t.save(backend, message, saveModeDefault) _, err = t.save(ctx, backend, message, saveModeDefault)
return err return err
} }
@ -47,7 +47,7 @@ func (t autoIncrementTable) Insert(ctx context.Context, message proto.Message) e
return err return err
} }
_, err = t.save(backend, message, saveModeInsert) _, err = t.save(ctx, backend, message, saveModeInsert)
return err return err
} }
@ -57,11 +57,11 @@ func (t autoIncrementTable) Update(ctx context.Context, message proto.Message) e
return err return err
} }
_, err = t.save(backend, message, saveModeUpdate) _, err = t.save(ctx, backend, message, saveModeUpdate)
return err 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() messageRef := message.ProtoReflect()
val := messageRef.Get(t.autoIncField).Uint() val := messageRef.Get(t.autoIncField).Uint()
writer := newBatchIndexCommitmentWriter(backend) writer := newBatchIndexCommitmentWriter(backend)
@ -87,7 +87,7 @@ func (t *autoIncrementTable) save(backend Backend, message proto.Message, mode s
mode = saveModeUpdate 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) { 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 { if id == 0 {
// we don't have an ID in the JSON, so we call Save to insert and // we don't have an ID in the JSON, so we call Save to insert and
// generate one // generate one
_, err = t.save(backend, message, saveModeInsert) _, err = t.save(ctx, backend, message, saveModeInsert)
return err return err
} else { } else {
if id > maxID { 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 // either no ID or SAVE_MODE_UPDATE. So instead we drop one level
// down and insert using tableImpl which doesn't know about // down and insert using tableImpl which doesn't know about
// auto-incrementing IDs // 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. // otherwise it the commitment store.
IndexStore() kv.Store IndexStore() kv.Store
// Hooks returns a Hooks instance or nil. // ValidateHooks returns a ValidateHooks instance or nil.
Hooks() Hooks ValidateHooks() ValidateHooks
// WithHooks returns a copy of this backend with the provided hooks. // WithValidateHooks returns a copy of this backend with the provided hooks.
WithHooks(Hooks) Backend WithValidateHooks(ValidateHooks) Backend
WriteHooks() WriteHooks
WithWriteHooks(WriteHooks) Backend
} }
// ReadBackendOptions defines options for creating a ReadBackend. // ReadBackendOptions defines options for creating a ReadBackend.
@ -82,11 +86,25 @@ func NewReadBackend(options ReadBackendOptions) ReadBackend {
type backend struct { type backend struct {
commitmentStore kv.Store commitmentStore kv.Store
indexStore kv.Store indexStore kv.Store
hooks Hooks validateHooks ValidateHooks
writeHooks WriteHooks
} }
func (c backend) WithHooks(hooks Hooks) Backend { func (c backend) ValidateHooks() ValidateHooks {
c.hooks = hooks 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 return c
} }
@ -108,10 +126,6 @@ func (c backend) IndexStore() kv.Store {
return c.indexStore return c.indexStore
} }
func (c backend) Hooks() Hooks {
return c.hooks
}
// BackendOptions defines options for creating a Backend. // BackendOptions defines options for creating a Backend.
// Context can optionally define two stores - a commitment store // Context can optionally define two stores - a commitment store
// that is backed by a merkle tree and an index store that isn't. // 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. // If it is nil the CommitmentStore will be used.
IndexStore kv.Store IndexStore kv.Store
// Hooks are optional hooks into ORM insert, update and delete operations. // ValidateHooks are optional hooks into ORM insert, update and delete operations.
Hooks Hooks ValidateHooks ValidateHooks
WriteHooks WriteHooks
} }
// NewBackend creates a new Backend. // NewBackend creates a new Backend.
@ -139,7 +155,8 @@ func NewBackend(options BackendOptions) Backend {
return &backend{ return &backend{
commitmentStore: options.CommitmentStore, commitmentStore: options.CommitmentStore,
indexStore: indexStore, 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 { func flushBuf(store kv.Store, writes []*batchWriterEntry) error {
for _, write := range writes { for _, write := range writes {
if !write.delete { if write.hookCall != nil {
write.hookCall()
} else if !write.delete {
err := store.Set(write.key, write.value) err := store.Set(write.key, write.value)
if err != nil { if err != nil {
return err return err
@ -73,6 +75,7 @@ func flushBuf(store kv.Store, writes []*batchWriterEntry) error {
return err return err
} }
} }
} }
return nil return nil
} }
@ -89,6 +92,7 @@ func (w *batchIndexCommitmentWriter) Close() {
type batchWriterEntry struct { type batchWriterEntry struct {
key, value []byte key, value []byte
delete bool delete bool
hookCall func()
} }
type batchStoreWriter struct { type batchStoreWriter struct {
@ -109,6 +113,10 @@ func (b *batchStoreWriter) Delete(key []byte) error {
return nil return nil
} }
func (w *batchIndexCommitmentWriter) enqueueHook(f func()) {
w.indexWriter.append(&batchWriterEntry{hookCall: f})
}
func (b *batchStoreWriter) append(entry *batchWriterEntry) { func (b *batchStoreWriter) append(entry *batchWriterEntry) {
if len(b.curBuf) == capacity { if len(b.curBuf) == capacity {
b.prevBufs = append(b.prevBufs, b.curBuf) b.prevBufs = append(b.prevBufs, b.curBuf)

View File

@ -1,21 +1,42 @@
package ormtable package ormtable
import "google.golang.org/protobuf/proto" import (
"context"
// Hooks defines an interface for a table hooks which can intercept "google.golang.org/protobuf/proto"
// 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
// OnUpdate is called before the existing message is updated with the new one. // ValidateHooks defines an interface for a table hooks which can intercept
// If error is not nil the operation will fail. // insert, update and delete operations and possibly return an error.
OnUpdate(existing, new proto.Message) error type ValidateHooks interface {
// OnDelete is called before the message is deleted. // ValidateInsert is called before the message is inserted.
// If error is not nil the operation will fail. // If error is not nil the insertion will fail.
OnDelete(proto.Message) error 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 return nil
} }
err = p.doDeleteWithWriteBatch(backend, writer, pk, msg) err = p.doDeleteWithWriteBatch(ctx, backend, writer, pk, msg)
if err != nil { if err != nil {
return err return err
} }
@ -135,9 +135,9 @@ func (p primaryKeyIndex) doDelete(ctx context.Context, primaryKeyValues []protor
return writer.Write() return writer.Write()
} }
func (p primaryKeyIndex) doDeleteWithWriteBatch(backend Backend, writer *batchIndexCommitmentWriter, primaryKeyBz []byte, message proto.Message) error { func (p primaryKeyIndex) doDeleteWithWriteBatch(ctx context.Context, backend Backend, writer *batchIndexCommitmentWriter, primaryKeyBz []byte, message proto.Message) error {
if hooks := backend.Hooks(); hooks != nil { if hooks := backend.ValidateHooks(); hooks != nil {
err := hooks.OnDelete(message) err := hooks.ValidateDelete(ctx, message)
if err != nil { if err != nil {
return err 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 return nil
} }
@ -209,7 +215,7 @@ func (p primaryKeyIndex) deleteByIterator(ctx context.Context, it Iterator) erro
return err return err
} }
err = p.doDeleteWithWriteBatch(backend, writer, pkBz, msg) err = p.doDeleteWithWriteBatch(ctx, backend, writer, pkBz, msg)
if err != nil { if err != nil {
return err return err
} }

View File

@ -60,7 +60,7 @@ func (t singleton) ImportJSON(ctx context.Context, reader io.Reader) error {
return err 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 { 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 // Save saves the provided entry in the store either inserting it or
// updating it if needed. // updating it if needed.
// //
// If store implement the Hooks interface, the appropriate OnInsert or // If store implement the ValidateHooks interface, the appropriate ValidateInsert or
// OnUpdate hook method will be called. // ValidateUpdate hook method will be called.
// //
// Save attempts to be atomic with respect to the underlying store, // Save attempts to be atomic with respect to the underlying store,
// meaning that either the full save operation is written or the store is // 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 // if one exists. Other fields besides the primary key fields will not
// be used for retrieval. // 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. // be called.
// //
// Delete attempts to be atomic with respect to the underlying store, // 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 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 { 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 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 { 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 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) writer := newBatchIndexCommitmentWriter(backend)
defer writer.Close() 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() mref := message.ProtoReflect()
pkValues, pk, err := t.EncodeKeyFromMessage(mref) pkValues, pk, err := t.EncodeKeyFromMessage(mref)
if err != nil { 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) return ormerrors.PrimaryKeyConstraintViolation.Wrapf("%q:%+v", mref.Descriptor().FullName(), pkValues)
} }
if hooks := writer.Hooks(); hooks != nil { if validateHooks := writer.ValidateHooks(); validateHooks != nil {
err = hooks.OnUpdate(existing, message) err = validateHooks.ValidateUpdate(ctx, existing, message)
if err != nil { if err != nil {
return err return err
} }
@ -109,8 +109,8 @@ func (t tableImpl) doSave(writer *batchIndexCommitmentWriter, message proto.Mess
return ormerrors.NotFoundOnUpdate.Wrapf("%q", mref.Descriptor().FullName()) return ormerrors.NotFoundOnUpdate.Wrapf("%q", mref.Descriptor().FullName())
} }
if hooks := writer.Hooks(); hooks != nil { if validateHooks := writer.ValidateHooks(); validateHooks != nil {
err = hooks.OnInsert(message) err = validateHooks.ValidateInsert(ctx, message)
if err != nil { if err != nil {
return err 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 { } else {
existingMref := existing.ProtoReflect() existingMref := existing.ProtoReflect()
for _, idx := range t.indexers { for _, idx := range t.indexers {
@ -148,6 +153,11 @@ func (t tableImpl) doSave(writer *batchIndexCommitmentWriter, message proto.Mess
return err return err
} }
} }
if writeHooks := writer.WriteHooks(); writeHooks != nil {
writer.enqueueHook(func() {
writeHooks.OnUpdate(ctx, existing, message)
})
}
} }
return writer.Write() 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.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 SEQ testpb.ExampleAutoIncrementTable 0
GET 03000001 GET 03000001
PK testpb.ExampleAutoIncrementTable 1 -> {"id":1} 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 HAS 0301666f6f
ERR:EOF ERR:EOF
SET 03000001 1203666f6f1805 SET 03000001 1203666f6f1805
@ -13,11 +13,12 @@ SET 03808002 01
SEQ testpb.ExampleAutoIncrementTable 1 SEQ testpb.ExampleAutoIncrementTable 1
SET 0301666f6f 0001 SET 0301666f6f 0001
UNIQ testpb.ExampleAutoIncrementTable x : foo -> 1 UNIQ testpb.ExampleAutoIncrementTable x : foo -> 1
ORM AFTER INSERT testpb.ExampleAutoIncrementTable {"id":1,"x":"foo","y":5}
GET 03808002 01 GET 03808002 01
SEQ testpb.ExampleAutoIncrementTable 1 SEQ testpb.ExampleAutoIncrementTable 1
GET 03000002 GET 03000002
PK testpb.ExampleAutoIncrementTable 2 -> {"id":2} 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 HAS 0301626172
ERR:EOF ERR:EOF
SET 03000002 1203626172180a SET 03000002 1203626172180a
@ -26,6 +27,7 @@ SET 03808002 02
SEQ testpb.ExampleAutoIncrementTable 2 SEQ testpb.ExampleAutoIncrementTable 2
SET 0301626172 0002 SET 0301626172 0002
UNIQ testpb.ExampleAutoIncrementTable x : bar -> 2 UNIQ testpb.ExampleAutoIncrementTable x : bar -> 2
ORM AFTER INSERT testpb.ExampleAutoIncrementTable {"id":2,"x":"bar","y":10}
GET 03808002 02 GET 03808002 02
SEQ testpb.ExampleAutoIncrementTable 2 SEQ testpb.ExampleAutoIncrementTable 2
ITERATOR 0300 -> 0301 ITERATOR 0300 -> 0301
@ -54,18 +56,20 @@ ITERATOR 0300 -> 0301
VALID false VALID false
GET 03000001 1203666f6f1805 GET 03000001 1203666f6f1805
PK testpb.ExampleAutoIncrementTable 1 -> {"id":1,"x":"foo","y":5} 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 03000001
DEL PK testpb.ExampleAutoIncrementTable 1 -> {"id":1} DEL PK testpb.ExampleAutoIncrementTable 1 -> {"id":1}
DEL 0301666f6f DEL 0301666f6f
DEL ERR:EOF DEL ERR:EOF
ORM AFTER DELETE testpb.ExampleAutoIncrementTable {"id":1,"x":"foo","y":5}
GET 03000002 1203626172180a GET 03000002 1203626172180a
PK testpb.ExampleAutoIncrementTable 2 -> {"id":2,"x":"bar","y":10} 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 03000002
DEL PK testpb.ExampleAutoIncrementTable 2 -> {"id":2} DEL PK testpb.ExampleAutoIncrementTable 2 -> {"id":2}
DEL 0301626172 DEL 0301626172
DEL ERR:EOF DEL ERR:EOF
ORM AFTER DELETE testpb.ExampleAutoIncrementTable {"id":2,"x":"bar","y":10}
GET 03808002 02 GET 03808002 02
SEQ testpb.ExampleAutoIncrementTable 2 SEQ testpb.ExampleAutoIncrementTable 2
ITERATOR 0300 -> 0301 ITERATOR 0300 -> 0301

View File

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

View File

@ -1,5 +1,5 @@
// Package ormmocks contains generated mocks for orm types that can be used // 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 // as this useful way for unit testing using an in-memory database. Rather
// than attempting to mock a whole table or database instance, instead // than attempting to mock a whole table or database instance, instead
// a mock Hook instance can be passed in to verify that the expected // a mock Hook instance can be passed in to verify that the expected
@ -9,5 +9,5 @@
// be used in gomock EXPECT functions. // be used in gomock EXPECT functions.
// //
// See TestHooks in ormdb/module_test.go for examples of how to use // 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 package ormmocks

View File

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