Skip to content

Commit

Permalink
refactor(orm)!: refactor hooks into validate and write hooks (#11185)
Browse files Browse the repository at this point in the history
* refactor(orm)!: refactor hooks into validate and write hooks

* impl and tests

* docs

* update mock hooks and tests

Co-authored-by: Marko <[email protected]>
  • Loading branch information
aaronc and tac0turtle authored Feb 25, 2022
1 parent c686634 commit 57b4613
Show file tree
Hide file tree
Showing 15 changed files with 395 additions and 149 deletions.
92 changes: 77 additions & 15 deletions orm/internal/testkv/debug.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package testkv

import (
"context"
"fmt"

"google.golang.org/protobuf/proto"
Expand All @@ -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,
})
}

Expand Down Expand Up @@ -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
Expand All @@ -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)
}
}
43 changes: 35 additions & 8 deletions orm/model/ormdb/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,33 +275,60 @@ 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)

denom := "foo"
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}),
)
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}),
)
hooks.EXPECT().OnDelete(
writeHooks.EXPECT().OnDelete(
gomock.Any(),
ormmocks.Eq(&testpb.Balance{Address: acct1, Denom: denom, Amount: 5}),
)
assert.NilError(t, k.Burn(ctx, acct1, denom, 5))
Expand Down
18 changes: 12 additions & 6 deletions orm/model/ormdb/testdata/bank_scenario.golden
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
16 changes: 8 additions & 8 deletions orm/model/ormtable/auto_increment.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
}

Expand All @@ -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
}

Expand All @@ -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)
Expand All @@ -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) {
Expand Down Expand Up @@ -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 {
Expand All @@ -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)
}
})
}
Expand Down
Loading

0 comments on commit 57b4613

Please sign in to comment.