From 6ea204994443edc7841df4f0dc86ee5b4edc8377 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 21 Jan 2022 22:13:43 -0500 Subject: [PATCH] feat(orm): add module db (#10991) ## Description This PR adds a `ModuleDB` interface which can be used directly by Cosmos SDK modules. A simplified bank example with Mint/Send/Burn functionality against Balance and Supply tables is included in the tests. This PR also: * adds simplified `Get` and `Has` methods to `Table` which use the primary key values in the message instead of `...interface{}` * adds a stable deterministic proto JSON marshaler and updates the `Entry.String` methods to use it because the golden tests are not deterministic without this. This code is currently internal but can be extracted to a public `codec` or `cosmos-proto` package eventually. --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [ ] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable) --- orm/encoding/ormkv/entry.go | 25 +- orm/encoding/ormkv/entry_test.go | 10 +- orm/go.mod | 10 +- orm/go.sum | 11 +- orm/internal/stablejson/encode.go | 93 ++ orm/internal/stablejson/encode_test.go | 37 + orm/internal/testkv/debug.go | 30 +- orm/internal/testpb/bank.proto | 31 + orm/internal/testpb/bank.pulsar.go | 1228 +++++++++++++++++ orm/model/ormdb/file.go | 125 ++ orm/model/ormdb/module.go | 162 +++ orm/model/ormdb/module_test.go | 220 +++ orm/model/ormdb/testdata/bank_scenario.golden | 58 + orm/model/ormtable/primary_key.go | 30 +- orm/model/ormtable/singleton_test.go | 4 +- orm/model/ormtable/table.go | 22 +- orm/model/ormtable/table_impl.go | 23 + orm/model/ormtable/table_test.go | 9 +- .../ormtable/testdata/test_auto_inc.golden | 16 +- .../ormtable/testdata/test_scenario.golden | 522 +++---- orm/types/ormerrors/errors.go | 3 +- 21 files changed, 2346 insertions(+), 323 deletions(-) create mode 100644 orm/internal/stablejson/encode.go create mode 100644 orm/internal/stablejson/encode_test.go create mode 100644 orm/internal/testpb/bank.proto create mode 100644 orm/internal/testpb/bank.pulsar.go create mode 100644 orm/model/ormdb/file.go create mode 100644 orm/model/ormdb/module.go create mode 100644 orm/model/ormdb/module_test.go create mode 100644 orm/model/ormdb/testdata/bank_scenario.golden diff --git a/orm/encoding/ormkv/entry.go b/orm/encoding/ormkv/entry.go index ac6016ee915..869eb9fbef3 100644 --- a/orm/encoding/ormkv/entry.go +++ b/orm/encoding/ormkv/entry.go @@ -4,10 +4,10 @@ import ( "fmt" "strings" - "google.golang.org/protobuf/encoding/protojson" + "github.com/cosmos/cosmos-sdk/orm/internal/stablejson" + "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/types/known/structpb" ) // Entry defines a logical representation of a kv-store entry for ORM instances. @@ -45,7 +45,12 @@ func (p *PrimaryKeyEntry) String() string { if p.Value == nil { return fmt.Sprintf("PK %s %s -> _", p.TableName, fmtValues(p.Key)) } else { - return fmt.Sprintf("PK %s %s -> %s", p.TableName, fmtValues(p.Key), p.Value) + valBz, err := stablejson.Marshal(p.Value) + valStr := string(valBz) + if err != nil { + valStr = fmt.Sprintf("ERR %v", err) + } + return fmt.Sprintf("PK %s %s -> %s", p.TableName, fmtValues(p.Key), valStr) } } @@ -56,19 +61,7 @@ func fmtValues(values []protoreflect.Value) string { parts := make([]string, len(values)) for i, v := range values { - val, err := structpb.NewValue(v.Interface()) - if err != nil { - parts[i] = "ERR" - continue - } - - bz, err := protojson.Marshal(val) - if err != nil { - parts[i] = "ERR" - continue - } - - parts[i] = string(bz) + parts[i] = fmt.Sprintf("%v", v.Interface()) } return strings.Join(parts, "/") diff --git a/orm/encoding/ormkv/entry_test.go b/orm/encoding/ormkv/entry_test.go index 1b060cea33d..9a78d60825a 100644 --- a/orm/encoding/ormkv/entry_test.go +++ b/orm/encoding/ormkv/entry_test.go @@ -19,7 +19,7 @@ func TestPrimaryKeyEntry(t *testing.T) { Key: encodeutil.ValuesOf(uint32(1), "abc"), Value: &testpb.ExampleTable{I32: -1}, } - assert.Equal(t, `PK testpb.ExampleTable 1/"abc" -> i32:-1`, entry.String()) + assert.Equal(t, `PK testpb.ExampleTable 1/abc -> {"i32":-1}`, entry.String()) assert.Equal(t, aFullName, entry.GetTableName()) // prefix key @@ -28,7 +28,7 @@ func TestPrimaryKeyEntry(t *testing.T) { Key: encodeutil.ValuesOf(uint32(1), "abc"), Value: nil, } - assert.Equal(t, `PK testpb.ExampleTable 1/"abc" -> _`, entry.String()) + assert.Equal(t, `PK testpb.ExampleTable 1/abc -> _`, entry.String()) assert.Equal(t, aFullName, entry.GetTableName()) } @@ -40,7 +40,7 @@ func TestIndexKeyEntry(t *testing.T) { IndexValues: encodeutil.ValuesOf(uint32(10), int32(-1), "abc"), PrimaryKey: encodeutil.ValuesOf("abc", int32(-1)), } - assert.Equal(t, `IDX testpb.ExampleTable u32/i32/str : 10/-1/"abc" -> "abc"/-1`, entry.String()) + assert.Equal(t, `IDX testpb.ExampleTable u32/i32/str : 10/-1/abc -> abc/-1`, entry.String()) assert.Equal(t, aFullName, entry.GetTableName()) entry = &ormkv.IndexKeyEntry{ @@ -50,7 +50,7 @@ func TestIndexKeyEntry(t *testing.T) { IndexValues: encodeutil.ValuesOf(uint32(10)), PrimaryKey: encodeutil.ValuesOf("abc", int32(-1)), } - assert.Equal(t, `UNIQ testpb.ExampleTable u32 : 10 -> "abc"/-1`, entry.String()) + assert.Equal(t, `UNIQ testpb.ExampleTable u32 : 10 -> abc/-1`, entry.String()) assert.Equal(t, aFullName, entry.GetTableName()) // prefix key @@ -70,6 +70,6 @@ func TestIndexKeyEntry(t *testing.T) { IsUnique: true, IndexValues: encodeutil.ValuesOf("abc", int32(1)), } - assert.Equal(t, `UNIQ testpb.ExampleTable str/i32 : "abc"/1 -> _`, entry.String()) + assert.Equal(t, `UNIQ testpb.ExampleTable str/i32 : abc/1 -> _`, entry.String()) assert.Equal(t, aFullName, entry.GetTableName()) } diff --git a/orm/go.mod b/orm/go.mod index fc36d4ff04a..7fb1fde89e0 100644 --- a/orm/go.mod +++ b/orm/go.mod @@ -4,8 +4,9 @@ go 1.17 require ( github.com/cosmos/cosmos-proto v1.0.0-alpha6 - github.com/cosmos/cosmos-sdk/api v0.1.0-alpha2 + github.com/cosmos/cosmos-sdk/api v0.1.0-alpha3 github.com/cosmos/cosmos-sdk/errors v1.0.0-beta.2 + github.com/stretchr/testify v1.7.0 github.com/tendermint/tm-db v0.6.6 google.golang.org/protobuf v1.27.1 gotest.tools/v3 v3.1.0 @@ -15,6 +16,7 @@ require ( require ( github.com/DataDog/zstd v1.4.5 // indirect github.com/cespare/xxhash v1.1.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgraph-io/badger/v2 v2.2007.2 // indirect github.com/dgraph-io/ristretto v0.0.3 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect @@ -22,19 +24,25 @@ require ( github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 // indirect github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect + github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3 // indirect github.com/google/btree v1.0.0 // indirect github.com/google/go-cmp v0.5.5 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca // indirect github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect go.etcd.io/bbolt v1.3.6 // indirect golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f // indirect golang.org/x/sys v0.0.0-20210903071746-97244b99971b // indirect + golang.org/x/text v0.3.6 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb // indirect + google.golang.org/grpc v1.43.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect ) replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 diff --git a/orm/go.sum b/orm/go.sum index 42a482eaaa9..eb28ed354e7 100644 --- a/orm/go.sum +++ b/orm/go.sum @@ -23,11 +23,10 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/cosmos/cosmos-proto v1.0.0-alpha4/go.mod h1:msdDWOvfStHLG+Z2y2SJ0dcqimZ2vc8M1MPnZ4jOF7U= github.com/cosmos/cosmos-proto v1.0.0-alpha6 h1:N2BvV2AyzGAXCJnvlw1pMzEQ+76tj5FDBrkYQYIDCdU= github.com/cosmos/cosmos-proto v1.0.0-alpha6/go.mod h1:msdDWOvfStHLG+Z2y2SJ0dcqimZ2vc8M1MPnZ4jOF7U= -github.com/cosmos/cosmos-sdk/api v0.1.0-alpha2 h1:47aK2mZ8oh3wyr5Q4OiZxyrMkQZRW67Ah/HfC8dW8hs= -github.com/cosmos/cosmos-sdk/api v0.1.0-alpha2/go.mod h1:xWm3hne2f6upv80eIS+fJnnUaed/R2EJno1It4Zb9aw= +github.com/cosmos/cosmos-sdk/api v0.1.0-alpha3 h1:tqpedvX/1UgQyX3W2hlW6Xg801FyojYT/NOHbW0oG+s= +github.com/cosmos/cosmos-sdk/api v0.1.0-alpha3/go.mod h1:Ht15guGn9F8b0lv8NkjXE9/asAvVUOt2n4gvQ4q5MyU= github.com/cosmos/cosmos-sdk/errors v1.0.0-beta.2 h1:bBglNlra8ZHb4dmbEE8V85ihLA+DkriSm7tcx6x/JWo= github.com/cosmos/cosmos-sdk/errors v1.0.0-beta.2/go.mod h1:Gi7pzVRnvZ1N16JAXpLADzng0ePoE7YeEHaULSFB2Ts= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= @@ -100,8 +99,10 @@ github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -122,6 +123,7 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4= github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -237,6 +239,7 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20200324203455-a04cca1dde73/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb h1:ZrsicilzPCS/Xr8qtBZZLpy4P9TYXAfl49ctG1/5tgw= google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= @@ -247,6 +250,7 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.43.0 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM= google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -263,6 +267,7 @@ google.golang.org/protobuf v1.27.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= diff --git a/orm/internal/stablejson/encode.go b/orm/internal/stablejson/encode.go new file mode 100644 index 00000000000..e9dd143773d --- /dev/null +++ b/orm/internal/stablejson/encode.go @@ -0,0 +1,93 @@ +package stablejson + +import ( + "bytes" + "fmt" + + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protopath" + "google.golang.org/protobuf/reflect/protorange" + "google.golang.org/protobuf/reflect/protoreflect" +) + +// Marshal marshals the provided message to JSON with a stable ordering based +// on ascending field numbers. +func Marshal(message proto.Message) ([]byte, error) { + buf := &bytes.Buffer{} + firstStack := []bool{true} + err := protorange.Options{ + Stable: true, + }.Range(message.ProtoReflect(), + func(p protopath.Values) error { + // Starting printing the value. + if !firstStack[len(firstStack)-1] { + _, _ = fmt.Fprintf(buf, ",") + } + firstStack[len(firstStack)-1] = false + + // Print the key. + var fd protoreflect.FieldDescriptor + last := p.Index(-1) + beforeLast := p.Index(-2) + switch last.Step.Kind() { + case protopath.FieldAccessStep: + fd = last.Step.FieldDescriptor() + _, _ = fmt.Fprintf(buf, "%q:", fd.Name()) + case protopath.ListIndexStep: + fd = beforeLast.Step.FieldDescriptor() // lists always appear in the context of a repeated field + case protopath.MapIndexStep: + fd = beforeLast.Step.FieldDescriptor() // maps always appear in the context of a repeated field + _, _ = fmt.Fprintf(buf, "%v:", last.Step.MapIndex().Interface()) + case protopath.AnyExpandStep: + _, _ = fmt.Fprintf(buf, `"@type":%q`, last.Value.Message().Descriptor().FullName()) + return nil + case protopath.UnknownAccessStep: + _, _ = fmt.Fprintf(buf, "?: ") + } + + switch v := last.Value.Interface().(type) { + case protoreflect.Message: + _, _ = fmt.Fprintf(buf, "{") + firstStack = append(firstStack, true) + case protoreflect.List: + _, _ = fmt.Fprintf(buf, "[") + firstStack = append(firstStack, true) + case protoreflect.Map: + _, _ = fmt.Fprintf(buf, "{") + firstStack = append(firstStack, true) + case protoreflect.EnumNumber: + var ev protoreflect.EnumValueDescriptor + if fd != nil { + ev = fd.Enum().Values().ByNumber(v) + } + if ev != nil { + _, _ = fmt.Fprintf(buf, "%v", ev.Name()) + } else { + _, _ = fmt.Fprintf(buf, "%v", v) + } + case string, []byte: + _, _ = fmt.Fprintf(buf, "%q", v) + default: + _, _ = fmt.Fprintf(buf, "%v", v) + } + return nil + }, + func(p protopath.Values) error { + last := p.Index(-1) + switch last.Value.Interface().(type) { + case protoreflect.Message: + if last.Step.Kind() != protopath.AnyExpandStep { + _, _ = fmt.Fprintf(buf, "}") + } + case protoreflect.List: + _, _ = fmt.Fprintf(buf, "]") + firstStack = firstStack[:len(firstStack)-1] + case protoreflect.Map: + _, _ = fmt.Fprintf(buf, "}") + firstStack = firstStack[:len(firstStack)-1] + } + return nil + }, + ) + return buf.Bytes(), err +} diff --git a/orm/internal/stablejson/encode_test.go b/orm/internal/stablejson/encode_test.go new file mode 100644 index 00000000000..fe192a578a4 --- /dev/null +++ b/orm/internal/stablejson/encode_test.go @@ -0,0 +1,37 @@ +package stablejson_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "google.golang.org/protobuf/types/known/anypb" + + bankv1beta1 "github.com/cosmos/cosmos-sdk/api/cosmos/bank/v1beta1" + basev1beta1 "github.com/cosmos/cosmos-sdk/api/cosmos/base/v1beta1" + txv1beta1 "github.com/cosmos/cosmos-sdk/api/cosmos/tx/v1beta1" + "github.com/cosmos/cosmos-sdk/orm/internal/stablejson" +) + +func TestStableJSON(t *testing.T) { + msg, err := anypb.New(&bankv1beta1.MsgSend{ + FromAddress: "foo213325", + ToAddress: "foo32t5sdfh", + Amount: []*basev1beta1.Coin{ + { + Denom: "bar", + Amount: "1234", + }, + { + Denom: "baz", + Amount: "321", + }, + }, + }) + require.NoError(t, err) + bz, err := stablejson.Marshal(&txv1beta1.TxBody{Messages: []*anypb.Any{msg}}) + require.NoError(t, err) + require.Equal(t, + `{"messages":[{"@type":"cosmos.bank.v1beta1.MsgSend","from_address":"foo213325","to_address":"foo32t5sdfh","amount":[{"denom":"bar","amount":"1234"},{"denom":"baz","amount":"321"}]}]}`, + string(bz)) +} diff --git a/orm/internal/testkv/debug.go b/orm/internal/testkv/debug.go index eda657c6d20..1ea97fb14d3 100644 --- a/orm/internal/testkv/debug.go +++ b/orm/internal/testkv/debug.go @@ -3,6 +3,8 @@ package testkv import ( "fmt" + "github.com/cosmos/cosmos-sdk/orm/internal/stablejson" + "google.golang.org/protobuf/proto" "github.com/cosmos/cosmos-sdk/orm/encoding/ormkv" @@ -210,10 +212,15 @@ type debugHooks struct { } func (d debugHooks) OnInsert(message proto.Message) error { + jsonBz, err := stablejson.Marshal(message) + if err != nil { + return err + } + d.debugger.Log(fmt.Sprintf( "ORM INSERT %s %s", message.ProtoReflect().Descriptor().FullName(), - message, + jsonBz, )) if d.hooks != nil { return d.hooks.OnInsert(message) @@ -222,11 +229,21 @@ func (d debugHooks) OnInsert(message proto.Message) error { } func (d debugHooks) OnUpdate(existing, new proto.Message) error { + existingJson, err := stablejson.Marshal(existing) + if err != nil { + return err + } + + newJson, err := stablejson.Marshal(new) + if err != nil { + return err + } + d.debugger.Log(fmt.Sprintf( "ORM UPDATE %s %s -> %s", existing.ProtoReflect().Descriptor().FullName(), - existing, - new, + existingJson, + newJson, )) if d.hooks != nil { return d.hooks.OnUpdate(existing, new) @@ -235,10 +252,15 @@ func (d debugHooks) OnUpdate(existing, new proto.Message) error { } func (d debugHooks) OnDelete(message proto.Message) error { + jsonBz, err := stablejson.Marshal(message) + if err != nil { + return err + } + d.debugger.Log(fmt.Sprintf( "ORM DELETE %s %s", message.ProtoReflect().Descriptor().FullName(), - message, + jsonBz, )) if d.hooks != nil { return d.hooks.OnDelete(message) diff --git a/orm/internal/testpb/bank.proto b/orm/internal/testpb/bank.proto new file mode 100644 index 00000000000..b1cb3c21aef --- /dev/null +++ b/orm/internal/testpb/bank.proto @@ -0,0 +1,31 @@ +syntax = "proto3"; + +package testpb; + +import "cosmos/orm/v1alpha1/orm.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/orm/internal/testpb"; + +// This is a simulated bank schema used for testing. + +message Balance { + option (cosmos.orm.v1alpha1.table) = { + id: 1; + primary_key:{fields: "address,denom"} + index: {id: 1 fields: "denom"} + }; + + string address = 1; + string denom = 2; + uint64 amount = 3; +} + +message Supply { + option (cosmos.orm.v1alpha1.table) = { + id: 2; + primary_key:{fields: "denom"} + }; + + string denom = 1; + uint64 amount = 2; +} diff --git a/orm/internal/testpb/bank.pulsar.go b/orm/internal/testpb/bank.pulsar.go new file mode 100644 index 00000000000..524ccf76abb --- /dev/null +++ b/orm/internal/testpb/bank.pulsar.go @@ -0,0 +1,1228 @@ +package testpb + +import ( + fmt "fmt" + io "io" + reflect "reflect" + sync "sync" + + runtime "github.com/cosmos/cosmos-proto/runtime" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoiface "google.golang.org/protobuf/runtime/protoiface" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + + _ "github.com/cosmos/cosmos-sdk/api/cosmos/orm/v1alpha1" +) + +var ( + md_Balance protoreflect.MessageDescriptor + fd_Balance_address protoreflect.FieldDescriptor + fd_Balance_denom protoreflect.FieldDescriptor + fd_Balance_amount protoreflect.FieldDescriptor +) + +func init() { + file_testpb_bank_proto_init() + md_Balance = File_testpb_bank_proto.Messages().ByName("Balance") + fd_Balance_address = md_Balance.Fields().ByName("address") + fd_Balance_denom = md_Balance.Fields().ByName("denom") + fd_Balance_amount = md_Balance.Fields().ByName("amount") +} + +var _ protoreflect.Message = (*fastReflection_Balance)(nil) + +type fastReflection_Balance Balance + +func (x *Balance) ProtoReflect() protoreflect.Message { + return (*fastReflection_Balance)(x) +} + +func (x *Balance) slowProtoReflect() protoreflect.Message { + mi := &file_testpb_bank_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_Balance_messageType fastReflection_Balance_messageType +var _ protoreflect.MessageType = fastReflection_Balance_messageType{} + +type fastReflection_Balance_messageType struct{} + +func (x fastReflection_Balance_messageType) Zero() protoreflect.Message { + return (*fastReflection_Balance)(nil) +} +func (x fastReflection_Balance_messageType) New() protoreflect.Message { + return new(fastReflection_Balance) +} +func (x fastReflection_Balance_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_Balance +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_Balance) Descriptor() protoreflect.MessageDescriptor { + return md_Balance +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_Balance) Type() protoreflect.MessageType { + return _fastReflection_Balance_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_Balance) New() protoreflect.Message { + return new(fastReflection_Balance) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_Balance) Interface() protoreflect.ProtoMessage { + return (*Balance)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_Balance) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Address != "" { + value := protoreflect.ValueOfString(x.Address) + if !f(fd_Balance_address, value) { + return + } + } + if x.Denom != "" { + value := protoreflect.ValueOfString(x.Denom) + if !f(fd_Balance_denom, value) { + return + } + } + if x.Amount != uint64(0) { + value := protoreflect.ValueOfUint64(x.Amount) + if !f(fd_Balance_amount, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_Balance) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "testpb.Balance.address": + return x.Address != "" + case "testpb.Balance.denom": + return x.Denom != "" + case "testpb.Balance.amount": + return x.Amount != uint64(0) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.Balance")) + } + panic(fmt.Errorf("message testpb.Balance does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Balance) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "testpb.Balance.address": + x.Address = "" + case "testpb.Balance.denom": + x.Denom = "" + case "testpb.Balance.amount": + x.Amount = uint64(0) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.Balance")) + } + panic(fmt.Errorf("message testpb.Balance does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_Balance) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "testpb.Balance.address": + value := x.Address + return protoreflect.ValueOfString(value) + case "testpb.Balance.denom": + value := x.Denom + return protoreflect.ValueOfString(value) + case "testpb.Balance.amount": + value := x.Amount + return protoreflect.ValueOfUint64(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.Balance")) + } + panic(fmt.Errorf("message testpb.Balance does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Balance) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "testpb.Balance.address": + x.Address = value.Interface().(string) + case "testpb.Balance.denom": + x.Denom = value.Interface().(string) + case "testpb.Balance.amount": + x.Amount = value.Uint() + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.Balance")) + } + panic(fmt.Errorf("message testpb.Balance does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Balance) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "testpb.Balance.address": + panic(fmt.Errorf("field address of message testpb.Balance is not mutable")) + case "testpb.Balance.denom": + panic(fmt.Errorf("field denom of message testpb.Balance is not mutable")) + case "testpb.Balance.amount": + panic(fmt.Errorf("field amount of message testpb.Balance is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.Balance")) + } + panic(fmt.Errorf("message testpb.Balance does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_Balance) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "testpb.Balance.address": + return protoreflect.ValueOfString("") + case "testpb.Balance.denom": + return protoreflect.ValueOfString("") + case "testpb.Balance.amount": + return protoreflect.ValueOfUint64(uint64(0)) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.Balance")) + } + panic(fmt.Errorf("message testpb.Balance does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_Balance) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in testpb.Balance", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_Balance) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Balance) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_Balance) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_Balance) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*Balance) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.Address) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.Denom) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.Amount != 0 { + n += 1 + runtime.Sov(uint64(x.Amount)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*Balance) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if x.Amount != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.Amount)) + i-- + dAtA[i] = 0x18 + } + if len(x.Denom) > 0 { + i -= len(x.Denom) + copy(dAtA[i:], x.Denom) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Denom))) + i-- + dAtA[i] = 0x12 + } + if len(x.Address) > 0 { + i -= len(x.Address) + copy(dAtA[i:], x.Address) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Address))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*Balance) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: Balance: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: Balance: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + x.Amount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.Amount |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_Supply protoreflect.MessageDescriptor + fd_Supply_denom protoreflect.FieldDescriptor + fd_Supply_amount protoreflect.FieldDescriptor +) + +func init() { + file_testpb_bank_proto_init() + md_Supply = File_testpb_bank_proto.Messages().ByName("Supply") + fd_Supply_denom = md_Supply.Fields().ByName("denom") + fd_Supply_amount = md_Supply.Fields().ByName("amount") +} + +var _ protoreflect.Message = (*fastReflection_Supply)(nil) + +type fastReflection_Supply Supply + +func (x *Supply) ProtoReflect() protoreflect.Message { + return (*fastReflection_Supply)(x) +} + +func (x *Supply) slowProtoReflect() protoreflect.Message { + mi := &file_testpb_bank_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_Supply_messageType fastReflection_Supply_messageType +var _ protoreflect.MessageType = fastReflection_Supply_messageType{} + +type fastReflection_Supply_messageType struct{} + +func (x fastReflection_Supply_messageType) Zero() protoreflect.Message { + return (*fastReflection_Supply)(nil) +} +func (x fastReflection_Supply_messageType) New() protoreflect.Message { + return new(fastReflection_Supply) +} +func (x fastReflection_Supply_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_Supply +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_Supply) Descriptor() protoreflect.MessageDescriptor { + return md_Supply +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_Supply) Type() protoreflect.MessageType { + return _fastReflection_Supply_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_Supply) New() protoreflect.Message { + return new(fastReflection_Supply) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_Supply) Interface() protoreflect.ProtoMessage { + return (*Supply)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_Supply) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Denom != "" { + value := protoreflect.ValueOfString(x.Denom) + if !f(fd_Supply_denom, value) { + return + } + } + if x.Amount != uint64(0) { + value := protoreflect.ValueOfUint64(x.Amount) + if !f(fd_Supply_amount, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_Supply) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "testpb.Supply.denom": + return x.Denom != "" + case "testpb.Supply.amount": + return x.Amount != uint64(0) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.Supply")) + } + panic(fmt.Errorf("message testpb.Supply does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Supply) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "testpb.Supply.denom": + x.Denom = "" + case "testpb.Supply.amount": + x.Amount = uint64(0) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.Supply")) + } + panic(fmt.Errorf("message testpb.Supply does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_Supply) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "testpb.Supply.denom": + value := x.Denom + return protoreflect.ValueOfString(value) + case "testpb.Supply.amount": + value := x.Amount + return protoreflect.ValueOfUint64(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.Supply")) + } + panic(fmt.Errorf("message testpb.Supply does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Supply) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "testpb.Supply.denom": + x.Denom = value.Interface().(string) + case "testpb.Supply.amount": + x.Amount = value.Uint() + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.Supply")) + } + panic(fmt.Errorf("message testpb.Supply does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Supply) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "testpb.Supply.denom": + panic(fmt.Errorf("field denom of message testpb.Supply is not mutable")) + case "testpb.Supply.amount": + panic(fmt.Errorf("field amount of message testpb.Supply is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.Supply")) + } + panic(fmt.Errorf("message testpb.Supply does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_Supply) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "testpb.Supply.denom": + return protoreflect.ValueOfString("") + case "testpb.Supply.amount": + return protoreflect.ValueOfUint64(uint64(0)) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.Supply")) + } + panic(fmt.Errorf("message testpb.Supply does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_Supply) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in testpb.Supply", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_Supply) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Supply) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_Supply) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_Supply) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*Supply) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.Denom) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.Amount != 0 { + n += 1 + runtime.Sov(uint64(x.Amount)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*Supply) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if x.Amount != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.Amount)) + i-- + dAtA[i] = 0x10 + } + if len(x.Denom) > 0 { + i -= len(x.Denom) + copy(dAtA[i:], x.Denom) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Denom))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*Supply) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: Supply: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: Supply: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + x.Amount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + x.Amount |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.0 +// protoc (unknown) +// source: testpb/bank.proto + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Balance struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Denom string `protobuf:"bytes,2,opt,name=denom,proto3" json:"denom,omitempty"` + Amount uint64 `protobuf:"varint,3,opt,name=amount,proto3" json:"amount,omitempty"` +} + +func (x *Balance) Reset() { + *x = Balance{} + if protoimpl.UnsafeEnabled { + mi := &file_testpb_bank_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Balance) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Balance) ProtoMessage() {} + +// Deprecated: Use Balance.ProtoReflect.Descriptor instead. +func (*Balance) Descriptor() ([]byte, []int) { + return file_testpb_bank_proto_rawDescGZIP(), []int{0} +} + +func (x *Balance) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +func (x *Balance) GetDenom() string { + if x != nil { + return x.Denom + } + return "" +} + +func (x *Balance) GetAmount() uint64 { + if x != nil { + return x.Amount + } + return 0 +} + +type Supply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` + Amount uint64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"` +} + +func (x *Supply) Reset() { + *x = Supply{} + if protoimpl.UnsafeEnabled { + mi := &file_testpb_bank_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Supply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Supply) ProtoMessage() {} + +// Deprecated: Use Supply.ProtoReflect.Descriptor instead. +func (*Supply) Descriptor() ([]byte, []int) { + return file_testpb_bank_proto_rawDescGZIP(), []int{1} +} + +func (x *Supply) GetDenom() string { + if x != nil { + return x.Denom + } + return "" +} + +func (x *Supply) GetAmount() uint64 { + if x != nil { + return x.Amount + } + return 0 +} + +var File_testpb_bank_proto protoreflect.FileDescriptor + +var file_testpb_bank_proto_rawDesc = []byte{ + 0x0a, 0x11, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2f, 0x62, 0x61, 0x6e, 0x6b, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x1a, 0x1d, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2f, 0x6f, 0x72, 0x6d, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, + 0x2f, 0x6f, 0x72, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x77, 0x0a, 0x07, 0x42, 0x61, + 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x14, 0x0a, 0x05, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x3a, 0x24, 0xf2, + 0x9e, 0xd3, 0x8e, 0x03, 0x1e, 0x0a, 0x0f, 0x0a, 0x0d, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x2c, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x12, 0x09, 0x0a, 0x05, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x10, + 0x01, 0x18, 0x01, 0x22, 0x49, 0x0a, 0x06, 0x53, 0x75, 0x70, 0x70, 0x6c, 0x79, 0x12, 0x14, 0x0a, + 0x05, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x64, 0x65, + 0x6e, 0x6f, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x3a, 0x11, 0xf2, 0x9e, 0xd3, + 0x8e, 0x03, 0x0b, 0x0a, 0x07, 0x0a, 0x05, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x18, 0x02, 0x42, 0x81, + 0x01, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x42, 0x09, 0x42, + 0x61, 0x6e, 0x6b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x63, 0x6f, + 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x6f, 0x72, 0x6d, 0x2f, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0xa2, 0x02, 0x03, 0x54, + 0x58, 0x58, 0xaa, 0x02, 0x06, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0xca, 0x02, 0x06, 0x54, 0x65, + 0x73, 0x74, 0x70, 0x62, 0xe2, 0x02, 0x12, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0x5c, 0x47, 0x50, + 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x06, 0x54, 0x65, 0x73, 0x74, + 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_testpb_bank_proto_rawDescOnce sync.Once + file_testpb_bank_proto_rawDescData = file_testpb_bank_proto_rawDesc +) + +func file_testpb_bank_proto_rawDescGZIP() []byte { + file_testpb_bank_proto_rawDescOnce.Do(func() { + file_testpb_bank_proto_rawDescData = protoimpl.X.CompressGZIP(file_testpb_bank_proto_rawDescData) + }) + return file_testpb_bank_proto_rawDescData +} + +var file_testpb_bank_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_testpb_bank_proto_goTypes = []interface{}{ + (*Balance)(nil), // 0: testpb.Balance + (*Supply)(nil), // 1: testpb.Supply +} +var file_testpb_bank_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_testpb_bank_proto_init() } +func file_testpb_bank_proto_init() { + if File_testpb_bank_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_testpb_bank_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Balance); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_testpb_bank_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Supply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_testpb_bank_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_testpb_bank_proto_goTypes, + DependencyIndexes: file_testpb_bank_proto_depIdxs, + MessageInfos: file_testpb_bank_proto_msgTypes, + }.Build() + File_testpb_bank_proto = out.File + file_testpb_bank_proto_rawDesc = nil + file_testpb_bank_proto_goTypes = nil + file_testpb_bank_proto_depIdxs = nil +} diff --git a/orm/model/ormdb/file.go b/orm/model/ormdb/file.go new file mode 100644 index 00000000000..ea0bb073e83 --- /dev/null +++ b/orm/model/ormdb/file.go @@ -0,0 +1,125 @@ +package ormdb + +import ( + "bytes" + "context" + "encoding/binary" + "math" + + "google.golang.org/protobuf/reflect/protoregistry" + + "github.com/cosmos/cosmos-sdk/orm/encoding/encodeutil" + + "github.com/cosmos/cosmos-sdk/orm/encoding/ormkv" + "github.com/cosmos/cosmos-sdk/orm/types/ormerrors" + + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + + "github.com/cosmos/cosmos-sdk/orm/model/ormtable" +) + +type fileDescriptorDBOptions struct { + Prefix []byte + ID uint32 + TypeResolver ormtable.TypeResolver + JSONValidator func(proto.Message) error + GetBackend func(context.Context) (ormtable.Backend, error) + GetReadBackend func(context.Context) (ormtable.ReadBackend, error) +} + +type fileDescriptorDB struct { + id uint32 + prefix []byte + tablesById map[uint32]ormtable.Table + tablesByName map[protoreflect.FullName]ormtable.Table + fileDescriptor protoreflect.FileDescriptor +} + +func newFileDescriptorDB(fileDescriptor protoreflect.FileDescriptor, options fileDescriptorDBOptions) (*fileDescriptorDB, error) { + prefix := encodeutil.AppendVarUInt32(options.Prefix, options.ID) + + schema := &fileDescriptorDB{ + id: options.ID, + prefix: prefix, + tablesById: map[uint32]ormtable.Table{}, + tablesByName: map[protoreflect.FullName]ormtable.Table{}, + fileDescriptor: fileDescriptor, + } + + resolver := options.TypeResolver + if resolver == nil { + resolver = protoregistry.GlobalTypes + } + + messages := fileDescriptor.Messages() + n := messages.Len() + for i := 0; i < n; i++ { + messageDescriptor := messages.Get(i) + tableName := messageDescriptor.FullName() + messageType, err := resolver.FindMessageByName(tableName) + if err != nil { + return nil, err + } + + table, err := ormtable.Build(ormtable.Options{ + Prefix: prefix, + MessageType: messageType, + TypeResolver: resolver, + JSONValidator: options.JSONValidator, + GetReadBackend: options.GetReadBackend, + GetBackend: options.GetBackend, + }) + if err != nil { + return nil, err + } + + id := table.ID() + if _, ok := schema.tablesById[id]; ok { + return nil, ormerrors.InvalidTableId.Wrapf("duplicate ID %d for %s", id, tableName) + } + schema.tablesById[id] = table + + if _, ok := schema.tablesByName[tableName]; ok { + return nil, ormerrors.InvalidTableDefinition.Wrapf("duplicate table %s", tableName) + } + schema.tablesByName[tableName] = table + } + + return schema, nil +} + +func (f fileDescriptorDB) DecodeEntry(k, v []byte) (ormkv.Entry, error) { + r := bytes.NewReader(k) + err := encodeutil.SkipPrefix(r, f.prefix) + if err != nil { + return nil, err + } + + id, err := binary.ReadUvarint(r) + if err != nil { + return nil, err + } + + if id > math.MaxUint32 { + return nil, ormerrors.UnexpectedDecodePrefix.Wrapf("uint32 varint id out of range %d", id) + } + + table, ok := f.tablesById[uint32(id)] + if !ok { + return nil, ormerrors.UnexpectedDecodePrefix.Wrapf("can't find table with id %d", id) + } + + return table.DecodeEntry(k, v) +} + +func (f fileDescriptorDB) EncodeEntry(entry ormkv.Entry) (k, v []byte, err error) { + table, ok := f.tablesByName[entry.GetTableName()] + if !ok { + return nil, nil, ormerrors.BadDecodeEntry.Wrapf("can't find table %s", entry.GetTableName()) + } + + return table.EncodeEntry(entry) +} + +var _ ormkv.EntryCodec = fileDescriptorDB{} diff --git a/orm/model/ormdb/module.go b/orm/model/ormdb/module.go new file mode 100644 index 00000000000..5b99d2309fd --- /dev/null +++ b/orm/model/ormdb/module.go @@ -0,0 +1,162 @@ +package ormdb + +import ( + "bytes" + "context" + "encoding/binary" + "math" + + "google.golang.org/protobuf/reflect/protodesc" + + "github.com/cosmos/cosmos-sdk/orm/encoding/encodeutil" + + "google.golang.org/protobuf/proto" + + "google.golang.org/protobuf/reflect/protoreflect" + + "github.com/cosmos/cosmos-sdk/orm/encoding/ormkv" + "github.com/cosmos/cosmos-sdk/orm/model/ormtable" + "github.com/cosmos/cosmos-sdk/orm/types/ormerrors" +) + +// ModuleSchema describes the ORM schema for a module. +type ModuleSchema struct { + // FileDescriptors are the file descriptors that contain ORM tables to use in this schema. + // Each file descriptor must have an unique non-zero uint32 ID associated with it. + FileDescriptors map[uint32]protoreflect.FileDescriptor + + // Prefix is an optional prefix to prepend to all keys. It is recommended + // to leave it empty. + Prefix []byte +} + +// ModuleDB defines the ORM database type to be used by modules. +type ModuleDB interface { + ormkv.EntryCodec + + // GetTable returns the table for the provided message type or nil. + GetTable(message proto.Message) ormtable.Table +} + +type moduleDB struct { + prefix []byte + filesById map[uint32]*fileDescriptorDB + tablesByName map[protoreflect.FullName]ormtable.Table +} + +// ModuleDBOptions are options for constructing a ModuleDB. +type ModuleDBOptions struct { + + // TypeResolver is an optional type resolver to be used when unmarshaling + // protobuf messages. If it is nil, protoregistry.GlobalTypes will be used. + TypeResolver ormtable.TypeResolver + + // FileResolver is an optional file resolver that can be used to retrieve + // pinned file descriptors that may be different from those available at + // runtime. The file descriptor versions returned by this resolver will be + // used instead of the ones provided at runtime by the ModuleSchema. + FileResolver protodesc.Resolver + + // JSONValidator is an optional validator that can be used for validating + // messaging when using ValidateJSON. If it is nil, DefaultJSONValidator + // will be used + JSONValidator func(proto.Message) error + + // GetBackend is the function used to retrieve the table backend. + // See ormtable.Options.GetBackend for more details. + GetBackend func(context.Context) (ormtable.Backend, error) + + // GetReadBackend is the function used to retrieve a table read backend. + // See ormtable.Options.GetReadBackend for more details. + GetReadBackend func(context.Context) (ormtable.ReadBackend, error) +} + +// NewModuleDB constructs a ModuleDB instance from the provided schema and options. +func NewModuleDB(schema ModuleSchema, options ModuleDBOptions) (ModuleDB, error) { + prefix := schema.Prefix + db := &moduleDB{ + prefix: prefix, + filesById: map[uint32]*fileDescriptorDB{}, + tablesByName: map[protoreflect.FullName]ormtable.Table{}, + } + + for id, fileDescriptor := range schema.FileDescriptors { + if id == 0 { + return nil, ormerrors.InvalidFileDescriptorID.Wrapf("for %s", fileDescriptor.Path()) + } + + opts := fileDescriptorDBOptions{ + ID: id, + Prefix: prefix, + TypeResolver: options.TypeResolver, + JSONValidator: options.JSONValidator, + GetBackend: options.GetBackend, + GetReadBackend: options.GetReadBackend, + } + + if options.FileResolver != nil { + // if a FileResolver is provided, we use that to resolve the file + // and not the one provided as a different pinned file descriptor + // may have been provided + var err error + fileDescriptor, err = options.FileResolver.FindFileByPath(fileDescriptor.Path()) + if err != nil { + return nil, err + } + } + + fdSchema, err := newFileDescriptorDB(fileDescriptor, opts) + if err != nil { + return nil, err + } + + db.filesById[id] = fdSchema + for name, table := range fdSchema.tablesByName { + if _, ok := db.tablesByName[name]; ok { + return nil, ormerrors.UnexpectedError.Wrapf("duplicate table %s", name) + } + + db.tablesByName[name] = table + } + } + + return db, nil +} + +func (m moduleDB) DecodeEntry(k, v []byte) (ormkv.Entry, error) { + r := bytes.NewReader(k) + err := encodeutil.SkipPrefix(r, m.prefix) + if err != nil { + return nil, err + } + + id, err := binary.ReadUvarint(r) + if err != nil { + return nil, err + } + + if id > math.MaxUint32 { + return nil, ormerrors.UnexpectedDecodePrefix.Wrapf("uint32 varint id out of range %d", id) + } + + fileSchema, ok := m.filesById[uint32(id)] + if !ok { + return nil, ormerrors.UnexpectedDecodePrefix.Wrapf("can't find FileDescriptor schema with id %d", id) + } + + return fileSchema.DecodeEntry(k, v) +} + +func (m moduleDB) EncodeEntry(entry ormkv.Entry) (k, v []byte, err error) { + tableName := entry.GetTableName() + table, ok := m.tablesByName[tableName] + if !ok { + return nil, nil, ormerrors.BadDecodeEntry.Wrapf("can't find table %s", tableName) + } + + return table.EncodeEntry(entry) +} + +func (m moduleDB) GetTable(message proto.Message) ormtable.Table { + return m.tablesByName[message.ProtoReflect().Descriptor().FullName()] +} diff --git a/orm/model/ormdb/module_test.go b/orm/model/ormdb/module_test.go new file mode 100644 index 00000000000..cf689461806 --- /dev/null +++ b/orm/model/ormdb/module_test.go @@ -0,0 +1,220 @@ +package ormdb_test + +import ( + "bytes" + "context" + "fmt" + "strings" + "testing" + + "google.golang.org/protobuf/reflect/protoreflect" + "gotest.tools/v3/assert" + "gotest.tools/v3/golden" + + "github.com/cosmos/cosmos-sdk/orm/internal/testkv" + "github.com/cosmos/cosmos-sdk/orm/internal/testpb" + "github.com/cosmos/cosmos-sdk/orm/model/ormdb" + "github.com/cosmos/cosmos-sdk/orm/model/ormtable" +) + +// These tests use a simulated bank keeper. Addresses and balances use +// string and uint64 types respectively for simplicity. + +var TestBankSchema = ormdb.ModuleSchema{ + FileDescriptors: map[uint32]protoreflect.FileDescriptor{ + 1: testpb.File_testpb_bank_proto, + }, +} + +type keeper struct { + balanceTable ormtable.Table + balanceAddressDenomIndex ormtable.UniqueIndex + balanceDenomIndex ormtable.Index + + supplyTable ormtable.Table + supplyDenomIndex ormtable.UniqueIndex +} + +func (k keeper) Send(ctx context.Context, from, to, denom string, amount uint64) error { + err := k.safeSubBalance(ctx, from, denom, amount) + if err != nil { + return err + } + + return k.addBalance(ctx, to, denom, amount) +} + +func (k keeper) Mint(ctx context.Context, acct, denom string, amount uint64) error { + supply := &testpb.Supply{Denom: denom} + _, err := k.supplyTable.Get(ctx, supply) + if err != nil { + return err + } + + supply.Amount = supply.Amount + amount + err = k.supplyTable.Save(ctx, supply) + if err != nil { + return err + } + + return k.addBalance(ctx, acct, denom, amount) +} + +func (k keeper) Burn(ctx context.Context, acct, denom string, amount uint64) error { + supply := &testpb.Supply{Denom: denom} + found, err := k.supplyTable.Get(ctx, supply) + if err != nil { + return err + } + + if !found { + return fmt.Errorf("no supply for %s", denom) + } + + if amount > supply.Amount { + return fmt.Errorf("insufficient supply") + } + + supply.Amount = supply.Amount - amount + + if supply.Amount == 0 { + err = k.supplyTable.Delete(ctx, supply) + } else { + err = k.supplyTable.Save(ctx, supply) + } + if err != nil { + return err + } + + return k.safeSubBalance(ctx, acct, denom, amount) +} + +func (k keeper) Balance(ctx context.Context, acct, denom string) (uint64, error) { + balance := &testpb.Balance{Address: acct, Denom: denom} + _, err := k.balanceTable.Get(ctx, balance) + return balance.Amount, err +} + +func (k keeper) Supply(ctx context.Context, denom string) (uint64, error) { + supply := &testpb.Supply{Denom: denom} + _, err := k.supplyTable.Get(ctx, supply) + return supply.Amount, err +} + +func (k keeper) addBalance(ctx context.Context, acct, denom string, amount uint64) error { + balance := &testpb.Balance{Address: acct, Denom: denom} + _, err := k.balanceTable.Get(ctx, balance) + if err != nil { + return err + } + + balance.Amount = balance.Amount + amount + return k.balanceTable.Save(ctx, balance) +} + +func (k keeper) safeSubBalance(ctx context.Context, acct, denom string, amount uint64) error { + balance := &testpb.Balance{Address: acct, Denom: denom} + found, err := k.balanceTable.Get(ctx, balance) + if err != nil { + return err + } + + if !found { + return fmt.Errorf("acct %x has no balance for %s", acct, denom) + } + + if amount > balance.Amount { + return fmt.Errorf("insufficient funds") + } + + balance.Amount = balance.Amount - amount + + if balance.Amount == 0 { + return k.balanceTable.Delete(ctx, balance) + } else { + return k.balanceTable.Save(ctx, balance) + } +} + +func newKeeper(db ormdb.ModuleDB) keeper { + k := keeper{ + balanceTable: db.GetTable(&testpb.Balance{}), + supplyTable: db.GetTable(&testpb.Supply{}), + } + + k.balanceAddressDenomIndex = k.balanceTable.GetUniqueIndex("address,denom") + k.balanceDenomIndex = k.balanceTable.GetIndex("denom") + k.supplyDenomIndex = k.supplyTable.GetUniqueIndex("denom") + + return k +} + +func TestModuleDB(t *testing.T) { + // create db & debug context + db, err := ormdb.NewModuleDB(TestBankSchema, ormdb.ModuleDBOptions{}) + assert.NilError(t, err) + debugBuf := &strings.Builder{} + store := testkv.NewDebugBackend( + testkv.NewSharedMemBackend(), + &testkv.EntryCodecDebugger{ + EntryCodec: db, + Print: func(s string) { debugBuf.WriteString(s + "\n") }, + }, + ) + ctx := ormtable.WrapContextDefault(store) + + // create keeper + k := newKeeper(db) + assert.Assert(t, k.balanceTable != nil) + assert.Assert(t, k.balanceAddressDenomIndex != nil) + assert.Assert(t, k.balanceDenomIndex != nil) + assert.Assert(t, k.supplyTable != nil) + assert.Assert(t, k.supplyDenomIndex != nil) + + // mint coins + denom := "foo" + acct1 := "bob" + err = k.Mint(ctx, acct1, denom, 100) + assert.NilError(t, err) + bal, err := k.Balance(ctx, acct1, denom) + assert.NilError(t, err) + assert.Equal(t, uint64(100), bal) + supply, err := k.Supply(ctx, denom) + assert.NilError(t, err) + assert.Equal(t, uint64(100), supply) + + // send coins + acct2 := "sally" + err = k.Send(ctx, acct1, acct2, denom, 30) + bal, err = k.Balance(ctx, acct1, denom) + assert.NilError(t, err) + assert.Equal(t, uint64(70), bal) + bal, err = k.Balance(ctx, acct2, denom) + assert.NilError(t, err) + assert.Equal(t, uint64(30), bal) + + // burn coins + err = k.Burn(ctx, acct2, denom, 3) + bal, err = k.Balance(ctx, acct2, denom) + assert.NilError(t, err) + assert.Equal(t, uint64(27), bal) + supply, err = k.Supply(ctx, denom) + assert.NilError(t, err) + assert.Equal(t, uint64(97), supply) + + // check debug output + golden.Assert(t, debugBuf.String(), "bank_scenario.golden") + + // check decode & encode + it, err := store.CommitmentStore().Iterator(nil, nil) + assert.NilError(t, err) + for it.Valid() { + entry, err := db.DecodeEntry(it.Key(), it.Value()) + assert.NilError(t, err) + k, v, err := db.EncodeEntry(entry) + assert.NilError(t, err) + assert.Assert(t, bytes.Equal(k, it.Key())) + assert.Assert(t, bytes.Equal(v, it.Value())) + it.Next() + } +} diff --git a/orm/model/ormdb/testdata/bank_scenario.golden b/orm/model/ormdb/testdata/bank_scenario.golden new file mode 100644 index 00000000000..8bd51f49e48 --- /dev/null +++ b/orm/model/ormdb/testdata/bank_scenario.golden @@ -0,0 +1,58 @@ +GET 010200666f6f + PK testpb.Supply foo -> {"denom":"foo"} +GET 010200666f6f + PK testpb.Supply foo -> {"denom":"foo"} +ORM INSERT testpb.Supply {"denom":"foo","amount":100} +SET 010200666f6f 1064 + PK testpb.Supply foo -> {"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} +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 +GET 010100626f6200666f6f 1864 + PK testpb.Balance bob/foo -> {"address":"bob","denom":"foo","amount":100} +GET 010200666f6f 1064 + PK testpb.Supply foo -> {"denom":"foo","amount":100} +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} +SET 010100626f6200666f6f 1846 + PK testpb.Balance bob/foo -> {"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} +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 +GET 010100626f6200666f6f 1846 + PK testpb.Balance bob/foo -> {"address":"bob","denom":"foo","amount":70} +GET 01010073616c6c7900666f6f 181e + PK testpb.Balance sally/foo -> {"address":"sally","denom":"foo","amount":30} +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} +SET 010200666f6f 1061 + PK testpb.Supply foo -> {"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} +SET 01010073616c6c7900666f6f 181b + PK testpb.Balance sally/foo -> {"address":"sally","denom":"foo","amount":27} +GET 01010073616c6c7900666f6f 181b + PK testpb.Balance sally/foo -> {"address":"sally","denom":"foo","amount":27} +GET 010200666f6f 1061 + PK testpb.Supply foo -> {"denom":"foo","amount":97} diff --git a/orm/model/ormtable/primary_key.go b/orm/model/ormtable/primary_key.go index 2150f19e70d..63f19eacdd6 100644 --- a/orm/model/ormtable/primary_key.go +++ b/orm/model/ormtable/primary_key.go @@ -33,18 +33,22 @@ func (p primaryKeyIndex) Iterator(ctx context.Context, options ...ormlist.Option func (p primaryKeyIndex) doNotImplement() {} -func (p primaryKeyIndex) Has(context context.Context, key ...interface{}) (found bool, err error) { - ctx, err := p.getReadBackend(context) +func (p primaryKeyIndex) Has(ctx context.Context, key ...interface{}) (found bool, err error) { + backend, err := p.getReadBackend(ctx) if err != nil { return false, err } - keyBz, err := p.EncodeKey(encodeutil.ValuesOf(key...)) + return p.has(backend, encodeutil.ValuesOf(key...)) +} + +func (p primaryKeyIndex) has(backend ReadBackend, values []protoreflect.Value) (found bool, err error) { + keyBz, err := p.EncodeKey(values) if err != nil { return false, err } - return ctx.CommitmentStoreReader().Has(keyBz) + return backend.CommitmentStoreReader().Has(keyBz) } func (p primaryKeyIndex) Get(ctx context.Context, message proto.Message, values ...interface{}) (found bool, err error) { @@ -56,6 +60,15 @@ func (p primaryKeyIndex) Get(ctx context.Context, message proto.Message, values return p.get(backend, message, encodeutil.ValuesOf(values...)) } +func (p primaryKeyIndex) get(backend ReadBackend, message proto.Message, values []protoreflect.Value) (found bool, err error) { + key, err := p.EncodeKey(values) + if err != nil { + return false, err + } + + return p.getByKeyBytes(backend, key, values, message) +} + func (t primaryKeyIndex) DeleteByKey(ctx context.Context, primaryKeyValues ...interface{}) error { return t.doDeleteByKey(ctx, encodeutil.ValuesOf(primaryKeyValues...)) } @@ -109,15 +122,6 @@ func (t primaryKeyIndex) doDeleteByKey(ctx context.Context, primaryKeyValues []p return writer.Write() } -func (p primaryKeyIndex) get(backend ReadBackend, message proto.Message, values []protoreflect.Value) (found bool, err error) { - key, err := p.EncodeKey(values) - if err != nil { - return false, err - } - - return p.getByKeyBytes(backend, key, values, message) -} - func (p primaryKeyIndex) getByKeyBytes(store ReadBackend, key []byte, keyValues []protoreflect.Value, message proto.Message) (found bool, err error) { bz, err := store.CommitmentStoreReader().Get(key) if err != nil { diff --git a/orm/model/ormtable/singleton_test.go b/orm/model/ormtable/singleton_test.go index 3de20d729f3..83dc0143eeb 100644 --- a/orm/model/ormtable/singleton_test.go +++ b/orm/model/ormtable/singleton_test.go @@ -22,11 +22,11 @@ func TestSingleton(t *testing.T) { assert.NilError(t, err) store := ormtable.WrapContextDefault(testkv.NewSplitMemBackend()) - found, err := singleton.Has(store) + found, err := singleton.Has(store, val) assert.NilError(t, err) assert.Assert(t, !found) assert.NilError(t, singleton.Save(store, val)) - found, err = singleton.Has(store) + found, err = singleton.Has(store, val) assert.NilError(t, err) assert.Assert(t, found) diff --git a/orm/model/ormtable/table.go b/orm/model/ormtable/table.go index c48c7e18ca8..851c648b088 100644 --- a/orm/model/ormtable/table.go +++ b/orm/model/ormtable/table.go @@ -17,7 +17,17 @@ import ( // systems, for instance to enable backwards compatibility when a major // migration needs to be performed. type View interface { - UniqueIndex + Index + + // Has returns true if there is an entity in the table with the same + // primary key as message. Other fields besides the primary key fields will not + // be used for retrieval. + Has(ctx context.Context, message proto.Message) (found bool, err error) + + // Get retrieves the message if one exists for the primary key fields + // set on the message. Other fields besides the primary key fields will not + // be used for retrieval. + Get(ctx context.Context, message proto.Message) (found bool, err error) // GetIndex returns the index referenced by the provided fields if // one exists or nil. Note that some concrete indexes can be retrieved by @@ -54,14 +64,16 @@ type Table interface { // Insert inserts the provided entry in the store and fails if there is // an unique key violation. See Save for more details on behavior. - Insert(context context.Context, message proto.Message) error + Insert(ctx context.Context, message proto.Message) error // Update updates the provided entry in the store and fails if an entry // with a matching primary key does not exist. See Save for more details // on behavior. - Update(context context.Context, message proto.Message) error + Update(ctx context.Context, message proto.Message) error - // Delete deletes the entry with the provided primary key from the store. + // Delete deletes the entry with the with primary key fields set on message + // 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 // be called. @@ -69,7 +81,7 @@ type Table interface { // Delete attempts to be atomic with respect to the underlying store, // meaning that either the full save operation is written or the store is // left unchanged, unless there is an error with the underlying store. - Delete(context context.Context, message proto.Message) error + Delete(ctx context.Context, message proto.Message) error // DefaultJSON returns default JSON that can be used as a template for // genesis files. diff --git a/orm/model/ormtable/table_impl.go b/orm/model/ormtable/table_impl.go index 92c607a7caa..dbe8b43c43c 100644 --- a/orm/model/ormtable/table_impl.go +++ b/orm/model/ormtable/table_impl.go @@ -364,6 +364,29 @@ func (t tableImpl) ID() uint32 { return t.tableId } +func (t tableImpl) Has(ctx context.Context, message proto.Message) (found bool, err error) { + backend, err := t.getReadBackend(ctx) + if err != nil { + return false, err + } + + keyValues := t.primaryKeyIndex.PrimaryKeyCodec.GetKeyValues(message.ProtoReflect()) + return t.primaryKeyIndex.has(backend, keyValues) +} + +// Get retrieves the message if one exists for the primary key fields +// set on the message. Other fields besides the primary key fields will not +// be used for retrieval. +func (t tableImpl) Get(ctx context.Context, message proto.Message) (found bool, err error) { + backend, err := t.getReadBackend(ctx) + if err != nil { + return false, err + } + + keyValues := t.primaryKeyIndex.PrimaryKeyCodec.GetKeyValues(message.ProtoReflect()) + return t.primaryKeyIndex.get(backend, message, keyValues) +} + var _ Table = &tableImpl{} type saveMode int diff --git a/orm/model/ormtable/table_test.go b/orm/model/ormtable/table_test.go index 868fa67c330..abb18e7a00f 100644 --- a/orm/model/ormtable/table_test.go +++ b/orm/model/ormtable/table_test.go @@ -371,14 +371,15 @@ func runTestScenario(t *testing.T, table ormtable.Table, backend ormtable.Backen data = append(data, &testpb.ExampleTable{U32: 9}) err = table.Save(ctx, data[10]) assert.NilError(t, err) - found, err = table.Get(ctx, &a, uint32(9), int64(0), "") + pkIndex := table.GetUniqueIndex("u32,i64,str") + found, err = pkIndex.Get(ctx, &a, uint32(9), int64(0), "") assert.NilError(t, err) assert.Assert(t, found) assert.DeepEqual(t, data[10], &a, protocmp.Transform()) // and update it data[10].B = true assert.NilError(t, table.Save(ctx, data[10])) - found, err = table.Get(ctx, &a, uint32(9), int64(0), "") + found, err = pkIndex.Get(ctx, &a, uint32(9), int64(0), "") assert.NilError(t, err) assert.Assert(t, found) assert.DeepEqual(t, data[10], &a, protocmp.Transform()) @@ -401,10 +402,10 @@ func runTestScenario(t *testing.T, table ormtable.Table, backend ormtable.Backen // let's delete item 5 key5 := []interface{}{uint32(7), int64(-2), "abe"} - err = table.DeleteByKey(ctx, key5...) + err = pkIndex.DeleteByKey(ctx, key5...) assert.NilError(t, err) // it should be gone - found, err = table.Has(ctx, key5...) + found, err = pkIndex.Has(ctx, key5...) assert.NilError(t, err) assert.Assert(t, !found) // and missing from the iterator diff --git a/orm/model/ormtable/testdata/test_auto_inc.golden b/orm/model/ormtable/testdata/test_auto_inc.golden index 2224e148a49..3f59cb47873 100644 --- a/orm/model/ormtable/testdata/test_auto_inc.golden +++ b/orm/model/ormtable/testdata/test_auto_inc.golden @@ -1,31 +1,31 @@ GET 03000000000000000005 - PK testpb.ExampleAutoIncrementTable 5 -> id:5 + PK testpb.ExampleAutoIncrementTable 5 -> {"id":5} GET 03808002 SEQ testpb.ExampleAutoIncrementTable 0 GET 03000000000000000001 - PK testpb.ExampleAutoIncrementTable 1 -> id:1 -ORM INSERT testpb.ExampleAutoIncrementTable id:1 x:"foo" y:5 + PK testpb.ExampleAutoIncrementTable 1 -> {"id":1} +ORM INSERT testpb.ExampleAutoIncrementTable {"id":1,"x":"foo","y":5} HAS 0301666f6f ERR:EOF SET 03000000000000000001 1203666f6f1805 - PK testpb.ExampleAutoIncrementTable 1 -> id:1 x:"foo" y:5 + PK testpb.ExampleAutoIncrementTable 1 -> {"id":1,"x":"foo","y":5} SET 03808002 01 SEQ testpb.ExampleAutoIncrementTable 1 SET 0301666f6f 0000000000000001 - UNIQ testpb.ExampleAutoIncrementTable x : "foo" -> 1 + UNIQ testpb.ExampleAutoIncrementTable x : foo -> 1 GET 03808002 01 SEQ testpb.ExampleAutoIncrementTable 1 ITERATOR 0300 -> 0301 VALID true KEY 03000000000000000001 1203666f6f1805 - PK testpb.ExampleAutoIncrementTable 1 -> id:1 x:"foo" y:5 + PK testpb.ExampleAutoIncrementTable 1 -> {"id":1,"x":"foo","y":5} NEXT VALID false ITERATOR 0300 -> 0301 VALID true KEY 03000000000000000001 1203666f6f1805 - PK testpb.ExampleAutoIncrementTable 1 -> id:1 x:"foo" y:5 + PK testpb.ExampleAutoIncrementTable 1 -> {"id":1,"x":"foo","y":5} KEY 03000000000000000001 1203666f6f1805 - PK testpb.ExampleAutoIncrementTable 1 -> id:1 x:"foo" y:5 + PK testpb.ExampleAutoIncrementTable 1 -> {"id":1,"x":"foo","y":5} NEXT VALID false diff --git a/orm/model/ormtable/testdata/test_scenario.golden b/orm/model/ormtable/testdata/test_scenario.golden index a8ba54f3f8c..55ccb6f9b89 100644 --- a/orm/model/ormtable/testdata/test_scenario.golden +++ b/orm/model/ormtable/testdata/test_scenario.golden @@ -1,327 +1,327 @@ GET 0100000000047ffffffffffffffe616263 - PK testpb.ExampleTable 4/-2/"abc" -> u32:4 str:"abc" i64:-2 -ORM INSERT testpb.ExampleTable u32:4 u64:7 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} HAS 01010000000000000007616263 ERR:EOF SET 0100000000047ffffffffffffffe616263 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} SET 01010000000000000007616263 000000047ffffffffffffffe - UNIQ testpb.ExampleTable u64/str : 7/"abc" -> 4/-2/"abc" + UNIQ testpb.ExampleTable u64/str : 7/abc -> 4/-2/abc SET 010261626300000000047ffffffffffffffe - 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 01030061626300000000047ffffffffffffffe - 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 ITERATOR 0100 -> 0101 VALID true KEY 0100000000047ffffffffffffffe616263 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} NEXT VALID false GET 0100000000047ffffffffffffffe616264 - PK testpb.ExampleTable 4/-2/"abd" -> u32:4 str:"abd" i64:-2 -ORM INSERT testpb.ExampleTable u32:4 u64:7 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} HAS 01010000000000000007616264 ERR:EOF SET 0100000000047ffffffffffffffe616264 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} SET 01010000000000000007616264 000000047ffffffffffffffe - UNIQ testpb.ExampleTable u64/str : 7/"abd" -> 4/-2/"abd" + UNIQ testpb.ExampleTable u64/str : 7/abd -> 4/-2/abd SET 010261626400000000047ffffffffffffffe - 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 01030061626400000000047ffffffffffffffe - 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 ITERATOR 0100 -> 0101 VALID true KEY 0100000000047ffffffffffffffe616263 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} NEXT VALID true KEY 0100000000047ffffffffffffffe616264 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} NEXT VALID false GET 0100000000047fffffffffffffff616263 - PK testpb.ExampleTable 4/-1/"abc" -> u32:4 str:"abc" i64:-1 -ORM INSERT testpb.ExampleTable u32:4 u64:8 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} HAS 01010000000000000008616263 ERR:EOF SET 0100000000047fffffffffffffff616263 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} SET 01010000000000000008616263 000000047fffffffffffffff - UNIQ testpb.ExampleTable u64/str : 8/"abc" -> 4/-1/"abc" + UNIQ testpb.ExampleTable u64/str : 8/abc -> 4/-1/abc SET 010261626300000000047fffffffffffffff - 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 01030061626300000000047fffffffffffffff - 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 GET 0100000000057ffffffffffffffe616264 - PK testpb.ExampleTable 5/-2/"abd" -> u32:5 str:"abd" i64:-2 -ORM INSERT testpb.ExampleTable u32:5 u64:8 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} HAS 01010000000000000008616264 ERR:EOF SET 0100000000057ffffffffffffffe616264 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} SET 01010000000000000008616264 000000057ffffffffffffffe - UNIQ testpb.ExampleTable u64/str : 8/"abd" -> 5/-2/"abd" + UNIQ testpb.ExampleTable u64/str : 8/abd -> 5/-2/abd SET 010261626400000000057ffffffffffffffe - 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 01030061626400000000057ffffffffffffffe - 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 GET 0100000000057ffffffffffffffe616265 - PK testpb.ExampleTable 5/-2/"abe" -> u32:5 str:"abe" i64:-2 -ORM INSERT testpb.ExampleTable u32:5 u64:9 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} HAS 01010000000000000009616265 ERR:EOF SET 0100000000057ffffffffffffffe616265 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} SET 01010000000000000009616265 000000057ffffffffffffffe - UNIQ testpb.ExampleTable u64/str : 9/"abe" -> 5/-2/"abe" + UNIQ testpb.ExampleTable u64/str : 9/abe -> 5/-2/abe SET 010261626500000000057ffffffffffffffe - 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 01030061626500000000057ffffffffffffffe - 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 GET 0100000000077ffffffffffffffe616265 - PK testpb.ExampleTable 7/-2/"abe" -> u32:7 str:"abe" i64:-2 -ORM INSERT testpb.ExampleTable u32:7 u64:10 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} HAS 0101000000000000000a616265 ERR:EOF SET 0100000000077ffffffffffffffe616265 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} SET 0101000000000000000a616265 000000077ffffffffffffffe - UNIQ testpb.ExampleTable u64/str : 10/"abe" -> 7/-2/"abe" + UNIQ testpb.ExampleTable u64/str : 10/abe -> 7/-2/abe SET 010261626500000000077ffffffffffffffe - 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 01030061626500000000077ffffffffffffffe - 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 GET 0100000000077fffffffffffffff616265 - PK testpb.ExampleTable 7/-1/"abe" -> u32:7 str:"abe" i64:-1 -ORM INSERT testpb.ExampleTable u32:7 u64:11 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} HAS 0101000000000000000b616265 ERR:EOF SET 0100000000077fffffffffffffff616265 100b - PK testpb.ExampleTable 7/-1/"abe" -> u32:7 u64:11 str:"abe" i64:-1 + PK testpb.ExampleTable 7/-1/abe -> {"u32":7,"u64":11,"str":"abe","i64":-1} SET 0101000000000000000b616265 000000077fffffffffffffff - UNIQ testpb.ExampleTable u64/str : 11/"abe" -> 7/-1/"abe" + UNIQ testpb.ExampleTable u64/str : 11/abe -> 7/-1/abe SET 010261626500000000077fffffffffffffff - 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 01030061626500000000077fffffffffffffff - 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 GET 0100000000087ffffffffffffffc616263 - PK testpb.ExampleTable 8/-4/"abc" -> u32:8 str:"abc" i64:-4 -ORM INSERT testpb.ExampleTable u32:8 u64:11 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} HAS 0101000000000000000b616263 ERR:EOF SET 0100000000087ffffffffffffffc616263 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} SET 0101000000000000000b616263 000000087ffffffffffffffc - UNIQ testpb.ExampleTable u64/str : 11/"abc" -> 8/-4/"abc" + UNIQ testpb.ExampleTable u64/str : 11/abc -> 8/-4/abc SET 010261626300000000087ffffffffffffffc - 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 01030061626300000000087ffffffffffffffc - 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 GET 0100000000088000000000000001616263 - PK testpb.ExampleTable 8/1/"abc" -> u32:8 str:"abc" i64:1 -ORM INSERT testpb.ExampleTable u32:8 u64:12 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} HAS 0101000000000000000c616263 ERR:EOF SET 0100000000088000000000000001616263 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} SET 0101000000000000000c616263 000000088000000000000001 - UNIQ testpb.ExampleTable u64/str : 12/"abc" -> 8/1/"abc" + UNIQ testpb.ExampleTable u64/str : 12/abc -> 8/1/abc SET 010261626300000000088000000000000001 - 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 01030061626300000000088000000000000001 - 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 GET 0100000000088000000000000001616264 - PK testpb.ExampleTable 8/1/"abd" -> u32:8 str:"abd" i64:1 -ORM INSERT testpb.ExampleTable u32:8 u64:10 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} HAS 0101000000000000000a616264 ERR:EOF SET 0100000000088000000000000001616264 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} SET 0101000000000000000a616264 000000088000000000000001 - UNIQ testpb.ExampleTable u64/str : 10/"abd" -> 8/1/"abd" + UNIQ testpb.ExampleTable u64/str : 10/abd -> 8/1/abd SET 010261626400000000088000000000000001 - 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 01030061626400000000088000000000000001 - 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 ITERATOR 010000000008 -> 010000000009 VALID true KEY 0100000000087ffffffffffffffc616263 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} NEXT VALID true KEY 0100000000088000000000000001616263 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} NEXT VALID true KEY 0100000000088000000000000001616264 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} NEXT VALID false ITERATOR 010000000004 <- 010000000005 VALID true KEY 0100000000047fffffffffffffff616263 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} NEXT VALID true KEY 0100000000047ffffffffffffffe616264 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} NEXT VALID true KEY 0100000000047ffffffffffffffe616263 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} NEXT VALID false ITERATOR 0100000000047fffffffffffffff -> 010000000008 VALID true KEY 0100000000047fffffffffffffff616263 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} NEXT VALID true KEY 0100000000057ffffffffffffffe616264 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} NEXT VALID true KEY 0100000000057ffffffffffffffe616265 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} NEXT VALID true KEY 0100000000077ffffffffffffffe616265 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} NEXT VALID true KEY 0100000000077fffffffffffffff616265 100b - PK testpb.ExampleTable 7/-1/"abe" -> u32:7 u64:11 str:"abe" i64:-1 + PK testpb.ExampleTable 7/-1/abe -> {"u32":7,"u64":11,"str":"abe","i64":-1} NEXT VALID false ITERATOR 0100000000057ffffffffffffffd -> 010000000008800000000000000161626300 VALID true KEY 0100000000057ffffffffffffffe616264 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} NEXT VALID true KEY 0100000000057ffffffffffffffe616265 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} NEXT VALID true KEY 0100000000077ffffffffffffffe616265 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} NEXT VALID true KEY 0100000000077fffffffffffffff616265 100b - PK testpb.ExampleTable 7/-1/"abe" -> u32:7 u64:11 str:"abe" i64:-1 + PK testpb.ExampleTable 7/-1/abe -> {"u32":7,"u64":11,"str":"abe","i64":-1} NEXT VALID true KEY 0100000000087ffffffffffffffc616263 100b - PK testpb.ExampleTable 8/-4/"abc" -> u32:8 u64:11 str:"abc" i64:-4 + PK testpb.ExampleTable 8/-4/abc -> {"u32":8,"u64":11,"str":"abc","i64":-4} NEXT VALID true KEY 0100000000088000000000000001616263 100c - PK testpb.ExampleTable 8/1/"abc" -> u32:8 u64:12 str:"abc" i64:1 + PK testpb.ExampleTable 8/1/abc -> {"u32":8,"u64":12,"str":"abc","i64":1} NEXT VALID false ITERATOR 010261626300 <- 010261626401 VALID true KEY 010261626400000000088000000000000001 - 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 0100000000088000000000000001616264 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} NEXT VALID true KEY 010261626400000000057ffffffffffffffe - 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 0100000000057ffffffffffffffe616264 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} NEXT VALID true KEY 010261626400000000047ffffffffffffffe - 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 0100000000047ffffffffffffffe616264 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} NEXT VALID true KEY 010261626300000000088000000000000001 - 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 0100000000088000000000000001616263 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} NEXT VALID true KEY 010261626300000000087ffffffffffffffc - 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 0100000000087ffffffffffffffc616263 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} NEXT VALID true KEY 010261626300000000047fffffffffffffff - IDX testpb.ExampleTable str/u32/i64 : "abc"/4/-1 -> 4/-1/"abc" + IDX testpb.ExampleTable str/u32/i64 : abc/4/-1 -> 4/-1/abc GET 0100000000047fffffffffffffff616263 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} NEXT VALID true KEY 010261626300000000047ffffffffffffffe - IDX testpb.ExampleTable str/u32/i64 : "abc"/4/-2 -> 4/-2/"abc" + IDX testpb.ExampleTable str/u32/i64 : abc/4/-2 -> 4/-2/abc GET 0100000000047ffffffffffffffe616263 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} NEXT VALID false ITERATOR 01026162650000000007 -> 01026162650000000008 VALID true KEY 010261626500000000077ffffffffffffffe - IDX testpb.ExampleTable str/u32/i64 : "abe"/7/-2 -> 7/-2/"abe" + IDX testpb.ExampleTable str/u32/i64 : abe/7/-2 -> 7/-2/abe GET 0100000000077ffffffffffffffe616265 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} NEXT VALID true KEY 010261626500000000077fffffffffffffff - IDX testpb.ExampleTable str/u32/i64 : "abe"/7/-1 -> 7/-1/"abe" + IDX testpb.ExampleTable str/u32/i64 : abe/7/-1 -> 7/-1/abe GET 0100000000077fffffffffffffff616265 100b - PK testpb.ExampleTable 7/-1/"abe" -> u32:7 u64:11 str:"abe" i64:-1 + PK testpb.ExampleTable 7/-1/abe -> {"u32":7,"u64":11,"str":"abe","i64":-1} NEXT VALID false ITERATOR 01026162630000000004 <- 01026162630000000005 VALID true KEY 010261626300000000047fffffffffffffff - IDX testpb.ExampleTable str/u32/i64 : "abc"/4/-1 -> 4/-1/"abc" + IDX testpb.ExampleTable str/u32/i64 : abc/4/-1 -> 4/-1/abc GET 0100000000047fffffffffffffff616263 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} NEXT VALID true KEY 010261626300000000047ffffffffffffffe - IDX testpb.ExampleTable str/u32/i64 : "abc"/4/-2 -> 4/-2/"abc" + IDX testpb.ExampleTable str/u32/i64 : abc/4/-2 -> 4/-2/abc GET 0100000000047ffffffffffffffe616263 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} NEXT VALID false HAS 0101000000000000000c616263 ERR:EOF GET 0101000000000000000c616263 000000088000000000000001 - UNIQ testpb.ExampleTable u64/str : 12/"abc" -> 8/1/"abc" + UNIQ testpb.ExampleTable u64/str : 12/abc -> 8/1/abc GET 0100000000088000000000000001616263 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} ITERATOR 0100 -> 0101 VALID true KEY 0100000000047ffffffffffffffe616263 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} KEY 0100000000047ffffffffffffffe616263 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} NEXT VALID true KEY 0100000000047ffffffffffffffe616264 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} KEY 0100000000047ffffffffffffffe616264 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} NEXT VALID true KEY 0100000000047fffffffffffffff616263 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} KEY 0100000000047fffffffffffffff616263 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} NEXT VALID true KEY 0100000000057ffffffffffffffe616264 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} KEY 0100000000057ffffffffffffffe616264 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} NEXT VALID true NEXT @@ -340,57 +340,57 @@ ITERATOR 0100 -> 0101 ITERATOR 0100000000057ffffffffffffffe61626400 -> 0101 VALID true KEY 0100000000057ffffffffffffffe616265 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} KEY 0100000000057ffffffffffffffe616265 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} NEXT VALID true KEY 0100000000077ffffffffffffffe616265 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} KEY 0100000000077ffffffffffffffe616265 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} NEXT VALID true KEY 0100000000077fffffffffffffff616265 100b - PK testpb.ExampleTable 7/-1/"abe" -> u32:7 u64:11 str:"abe" i64:-1 + PK testpb.ExampleTable 7/-1/abe -> {"u32":7,"u64":11,"str":"abe","i64":-1} KEY 0100000000077fffffffffffffff616265 100b - PK testpb.ExampleTable 7/-1/"abe" -> u32:7 u64:11 str:"abe" i64:-1 + PK testpb.ExampleTable 7/-1/abe -> {"u32":7,"u64":11,"str":"abe","i64":-1} NEXT VALID true KEY 0100000000087ffffffffffffffc616263 100b - PK testpb.ExampleTable 8/-4/"abc" -> u32:8 u64:11 str:"abc" i64:-4 + PK testpb.ExampleTable 8/-4/abc -> {"u32":8,"u64":11,"str":"abc","i64":-4} KEY 0100000000087ffffffffffffffc616263 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} NEXT VALID true CLOSE ITERATOR 0100000000087ffffffffffffffc61626300 -> 0101 VALID true KEY 0100000000088000000000000001616263 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} KEY 0100000000088000000000000001616263 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} NEXT VALID true KEY 0100000000088000000000000001616264 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} KEY 0100000000088000000000000001616264 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} NEXT VALID false CLOSE ITERATOR 0100 <- 0101 VALID true KEY 0100000000088000000000000001616264 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} KEY 0100000000088000000000000001616264 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} NEXT VALID true KEY 0100000000088000000000000001616263 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} KEY 0100000000088000000000000001616263 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} NEXT VALID true NEXT @@ -413,42 +413,42 @@ ITERATOR 0100 <- 0101 ITERATOR 0100 <- 0100000000088000000000000001616263 VALID true KEY 0100000000087ffffffffffffffc616263 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} KEY 0100000000087ffffffffffffffc616263 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} NEXT VALID true KEY 0100000000077fffffffffffffff616265 100b - PK testpb.ExampleTable 7/-1/"abe" -> u32:7 u64:11 str:"abe" i64:-1 + PK testpb.ExampleTable 7/-1/abe -> {"u32":7,"u64":11,"str":"abe","i64":-1} KEY 0100000000077fffffffffffffff616265 100b - PK testpb.ExampleTable 7/-1/"abe" -> u32:7 u64:11 str:"abe" i64:-1 + PK testpb.ExampleTable 7/-1/abe -> {"u32":7,"u64":11,"str":"abe","i64":-1} NEXT VALID true CLOSE ITERATOR 0100000000047fffffffffffffff616263 -> 0100000000077ffffffffffffffe61626500 VALID true KEY 0100000000047fffffffffffffff616263 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} KEY 0100000000047fffffffffffffff616263 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} NEXT VALID true KEY 0100000000057ffffffffffffffe616264 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} KEY 0100000000057ffffffffffffffe616264 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} NEXT VALID true KEY 0100000000057ffffffffffffffe616265 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} KEY 0100000000057ffffffffffffffe616265 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} NEXT VALID true KEY 0100000000077ffffffffffffffe616265 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} KEY 0100000000077ffffffffffffffe616265 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} NEXT VALID false CLOSE @@ -461,15 +461,15 @@ ITERATOR 0100 -> 0101 NEXT VALID true KEY 0100000000057ffffffffffffffe616264 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} KEY 0100000000057ffffffffffffffe616264 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} NEXT VALID true KEY 0100000000057ffffffffffffffe616265 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} KEY 0100000000057ffffffffffffffe616265 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} NEXT VALID true NEXT @@ -496,21 +496,21 @@ ITERATOR 0100 <- 0101 NEXT VALID true KEY 0100000000057ffffffffffffffe616265 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} KEY 0100000000057ffffffffffffffe616265 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} NEXT VALID true KEY 0100000000057ffffffffffffffe616264 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} KEY 0100000000057ffffffffffffffe616264 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} NEXT VALID true KEY 0100000000047fffffffffffffff616263 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} KEY 0100000000047fffffffffffffff616263 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} NEXT VALID true NEXT @@ -565,357 +565,357 @@ ITERATOR 0100 -> 0101 VALID false CLOSE GET 0100000000047ffffffffffffffe616263 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 + 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} HAS 0101000000000000000e616263 ERR:EOF SET 0100000000047ffffffffffffffe616263 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} DEL 01010000000000000007616263 DEL ERR:EOF SET 0101000000000000000e616263 000000047ffffffffffffffe - UNIQ testpb.ExampleTable u64/str : 14/"abc" -> 4/-2/"abc" + UNIQ testpb.ExampleTable u64/str : 14/abc -> 4/-2/abc DEL 01030061626300000000047ffffffffffffffe -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 01030361626361626300000000047ffffffffffffffe - IDX testpb.ExampleTable bz/str/u32/i64 : "YWJj"/"abc"/4/-2 -> 4/-2/"abc" + IDX testpb.ExampleTable bz/str/u32/i64 : [97 98 99]/abc/4/-2 -> 4/-2/abc GET 0100000000047ffffffffffffffe616264 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 + 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} HAS 0101000000000000000e616264 ERR:EOF SET 0100000000047ffffffffffffffe616264 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} DEL 01010000000000000007616264 DEL ERR:EOF SET 0101000000000000000e616264 000000047ffffffffffffffe - UNIQ testpb.ExampleTable u64/str : 14/"abd" -> 4/-2/"abd" + UNIQ testpb.ExampleTable u64/str : 14/abd -> 4/-2/abd DEL 01030061626400000000047ffffffffffffffe -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 01030361626461626400000000047ffffffffffffffe - IDX testpb.ExampleTable bz/str/u32/i64 : "YWJk"/"abd"/4/-2 -> 4/-2/"abd" + IDX testpb.ExampleTable bz/str/u32/i64 : [97 98 100]/abd/4/-2 -> 4/-2/abd GET 0100000000047fffffffffffffff616263 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 + 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} HAS 01010000000000000010616263 ERR:EOF SET 0100000000047fffffffffffffff616263 10102203616263 - PK testpb.ExampleTable 4/-1/"abc" -> u32:4 u64:16 str:"abc" bz:"abc" i64:-1 + PK testpb.ExampleTable 4/-1/abc -> {"u32":4,"u64":16,"str":"abc","bz":"abc","i64":-1} DEL 01010000000000000008616263 DEL ERR:EOF SET 01010000000000000010616263 000000047fffffffffffffff - UNIQ testpb.ExampleTable u64/str : 16/"abc" -> 4/-1/"abc" + UNIQ testpb.ExampleTable u64/str : 16/abc -> 4/-1/abc DEL 01030061626300000000047fffffffffffffff -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 01030361626361626300000000047fffffffffffffff - IDX testpb.ExampleTable bz/str/u32/i64 : "YWJj"/"abc"/4/-1 -> 4/-1/"abc" + IDX testpb.ExampleTable bz/str/u32/i64 : [97 98 99]/abc/4/-1 -> 4/-1/abc GET 0100000000057ffffffffffffffe616264 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 + 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} HAS 01010000000000000010616264 ERR:EOF SET 0100000000057ffffffffffffffe616264 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} DEL 01010000000000000008616264 DEL ERR:EOF SET 01010000000000000010616264 000000057ffffffffffffffe - UNIQ testpb.ExampleTable u64/str : 16/"abd" -> 5/-2/"abd" + UNIQ testpb.ExampleTable u64/str : 16/abd -> 5/-2/abd DEL 01030061626400000000057ffffffffffffffe -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 01030361626461626400000000057ffffffffffffffe - IDX testpb.ExampleTable bz/str/u32/i64 : "YWJk"/"abd"/5/-2 -> 5/-2/"abd" + IDX testpb.ExampleTable bz/str/u32/i64 : [97 98 100]/abd/5/-2 -> 5/-2/abd GET 0100000000057ffffffffffffffe616265 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 + 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} HAS 01010000000000000012616265 ERR:EOF SET 0100000000057ffffffffffffffe616265 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} DEL 01010000000000000009616265 DEL ERR:EOF SET 01010000000000000012616265 000000057ffffffffffffffe - UNIQ testpb.ExampleTable u64/str : 18/"abe" -> 5/-2/"abe" + UNIQ testpb.ExampleTable u64/str : 18/abe -> 5/-2/abe DEL 01030061626500000000057ffffffffffffffe -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 01030361626561626500000000057ffffffffffffffe - IDX testpb.ExampleTable bz/str/u32/i64 : "YWJl"/"abe"/5/-2 -> 5/-2/"abe" + IDX testpb.ExampleTable bz/str/u32/i64 : [97 98 101]/abe/5/-2 -> 5/-2/abe ITERATOR 0100 -> 0101 VALID true KEY 0100000000047ffffffffffffffe616263 100e2203616263 - PK testpb.ExampleTable 4/-2/"abc" -> u32:4 u64:14 str:"abc" bz:"abc" i64:-2 + PK testpb.ExampleTable 4/-2/abc -> {"u32":4,"u64":14,"str":"abc","bz":"abc","i64":-2} NEXT VALID true KEY 0100000000047ffffffffffffffe616264 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} NEXT VALID true KEY 0100000000047fffffffffffffff616263 10102203616263 - PK testpb.ExampleTable 4/-1/"abc" -> u32:4 u64:16 str:"abc" bz:"abc" i64:-1 + PK testpb.ExampleTable 4/-1/abc -> {"u32":4,"u64":16,"str":"abc","bz":"abc","i64":-1} NEXT VALID true KEY 0100000000057ffffffffffffffe616264 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} NEXT VALID true KEY 0100000000057ffffffffffffffe616265 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} NEXT VALID true KEY 0100000000077ffffffffffffffe616265 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} NEXT VALID true KEY 0100000000077fffffffffffffff616265 100b - PK testpb.ExampleTable 7/-1/"abe" -> u32:7 u64:11 str:"abe" i64:-1 + PK testpb.ExampleTable 7/-1/abe -> {"u32":7,"u64":11,"str":"abe","i64":-1} NEXT VALID true KEY 0100000000087ffffffffffffffc616263 100b - PK testpb.ExampleTable 8/-4/"abc" -> u32:8 u64:11 str:"abc" i64:-4 + PK testpb.ExampleTable 8/-4/abc -> {"u32":8,"u64":11,"str":"abc","i64":-4} NEXT VALID true KEY 0100000000088000000000000001616263 100c - PK testpb.ExampleTable 8/1/"abc" -> u32:8 u64:12 str:"abc" i64:1 + PK testpb.ExampleTable 8/1/abc -> {"u32":8,"u64":12,"str":"abc","i64":1} NEXT VALID true KEY 0100000000088000000000000001616264 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} NEXT VALID false GET 0100000000098000000000000000 - PK testpb.ExampleTable 9/0/"" -> u32:9 -ORM INSERT testpb.ExampleTable u32:9 + PK testpb.ExampleTable 9/0/ -> {"u32":9} +ORM INSERT testpb.ExampleTable {"u32":9} HAS 01010000000000000000 ERR:EOF SET 0100000000098000000000000000 - PK testpb.ExampleTable 9/0/"" -> u32:9 + PK testpb.ExampleTable 9/0/ -> {"u32":9} SET 01010000000000000000 000000098000000000000000 - UNIQ testpb.ExampleTable u64/str : 0/"" -> 9/0/"" + UNIQ testpb.ExampleTable u64/str : 0/ -> 9/0/ SET 010200000000098000000000000000 - IDX testpb.ExampleTable str/u32/i64 : ""/9/0 -> 9/0/"" + IDX testpb.ExampleTable str/u32/i64 : /9/0 -> 9/0/ SET 01030000000000098000000000000000 - IDX testpb.ExampleTable bz/str/u32/i64 : ""/""/9/0 -> 9/0/"" + IDX testpb.ExampleTable bz/str/u32/i64 : []//9/0 -> 9/0/ GET 0100000000098000000000000000 - PK testpb.ExampleTable 9/0/"" -> u32:9 + PK testpb.ExampleTable 9/0/ -> {"u32":9} GET 0100000000098000000000000000 - PK testpb.ExampleTable 9/0/"" -> u32:9 -ORM UPDATE testpb.ExampleTable u32:9 -> u32:9 b:true + PK testpb.ExampleTable 9/0/ -> {"u32":9} +ORM UPDATE testpb.ExampleTable {"u32":9} -> {"u32":9,"b":true} SET 0100000000098000000000000000 7801 - PK testpb.ExampleTable 9/0/"" -> u32:9 b:true + PK testpb.ExampleTable 9/0/ -> {"u32":9,"b":true} GET 0100000000098000000000000000 7801 - PK testpb.ExampleTable 9/0/"" -> u32:9 b:true + PK testpb.ExampleTable 9/0/ -> {"u32":9,"b":true} ITERATOR 0100 -> 0101 VALID true KEY 0100000000047ffffffffffffffe616263 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} NEXT VALID true KEY 0100000000047ffffffffffffffe616264 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} NEXT VALID true KEY 0100000000047fffffffffffffff616263 10102203616263 - PK testpb.ExampleTable 4/-1/"abc" -> u32:4 u64:16 str:"abc" bz:"abc" i64:-1 + PK testpb.ExampleTable 4/-1/abc -> {"u32":4,"u64":16,"str":"abc","bz":"abc","i64":-1} NEXT VALID true KEY 0100000000057ffffffffffffffe616264 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} NEXT VALID true KEY 0100000000057ffffffffffffffe616265 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} NEXT VALID true KEY 0100000000077ffffffffffffffe616265 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} NEXT VALID true KEY 0100000000077fffffffffffffff616265 100b - PK testpb.ExampleTable 7/-1/"abe" -> u32:7 u64:11 str:"abe" i64:-1 + PK testpb.ExampleTable 7/-1/abe -> {"u32":7,"u64":11,"str":"abe","i64":-1} NEXT VALID true KEY 0100000000087ffffffffffffffc616263 100b - PK testpb.ExampleTable 8/-4/"abc" -> u32:8 u64:11 str:"abc" i64:-4 + PK testpb.ExampleTable 8/-4/abc -> {"u32":8,"u64":11,"str":"abc","i64":-4} NEXT VALID true KEY 0100000000088000000000000001616263 100c - PK testpb.ExampleTable 8/1/"abc" -> u32:8 u64:12 str:"abc" i64:1 + PK testpb.ExampleTable 8/1/abc -> {"u32":8,"u64":12,"str":"abc","i64":1} NEXT VALID true KEY 0100000000088000000000000001616264 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} NEXT VALID true KEY 0100000000098000000000000000 7801 - PK testpb.ExampleTable 9/0/"" -> u32:9 b:true + PK testpb.ExampleTable 9/0/ -> {"u32":9,"b":true} NEXT VALID false ITERATOR 0100 -> 0101 VALID true KEY 0100000000047ffffffffffffffe616263 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} NEXT VALID true KEY 0100000000047ffffffffffffffe616264 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} NEXT VALID true KEY 0100000000047fffffffffffffff616263 10102203616263 - PK testpb.ExampleTable 4/-1/"abc" -> u32:4 u64:16 str:"abc" bz:"abc" i64:-1 + PK testpb.ExampleTable 4/-1/abc -> {"u32":4,"u64":16,"str":"abc","bz":"abc","i64":-1} NEXT VALID true KEY 0100000000057ffffffffffffffe616264 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} NEXT VALID true KEY 0100000000057ffffffffffffffe616265 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} NEXT VALID true KEY 0100000000077ffffffffffffffe616265 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} NEXT VALID true KEY 0100000000077fffffffffffffff616265 100b - PK testpb.ExampleTable 7/-1/"abe" -> u32:7 u64:11 str:"abe" i64:-1 + PK testpb.ExampleTable 7/-1/abe -> {"u32":7,"u64":11,"str":"abe","i64":-1} NEXT VALID true KEY 0100000000087ffffffffffffffc616263 100b - PK testpb.ExampleTable 8/-4/"abc" -> u32:8 u64:11 str:"abc" i64:-4 + PK testpb.ExampleTable 8/-4/abc -> {"u32":8,"u64":11,"str":"abc","i64":-4} NEXT VALID true KEY 0100000000088000000000000001616263 100c - PK testpb.ExampleTable 8/1/"abc" -> u32:8 u64:12 str:"abc" i64:1 + PK testpb.ExampleTable 8/1/abc -> {"u32":8,"u64":12,"str":"abc","i64":1} NEXT VALID true KEY 0100000000088000000000000001616264 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} NEXT VALID true KEY 0100000000098000000000000000 7801 - PK testpb.ExampleTable 9/0/"" -> u32:9 b:true + PK testpb.ExampleTable 9/0/ -> {"u32":9,"b":true} NEXT VALID false ITERATOR 0100 -> 0101 VALID true KEY 0100000000047ffffffffffffffe616263 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} KEY 0100000000047ffffffffffffffe616263 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} NEXT VALID true KEY 0100000000047ffffffffffffffe616264 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} KEY 0100000000047ffffffffffffffe616264 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} NEXT VALID true KEY 0100000000047fffffffffffffff616263 10102203616263 - PK testpb.ExampleTable 4/-1/"abc" -> u32:4 u64:16 str:"abc" bz:"abc" i64:-1 + PK testpb.ExampleTable 4/-1/abc -> {"u32":4,"u64":16,"str":"abc","bz":"abc","i64":-1} KEY 0100000000047fffffffffffffff616263 10102203616263 - PK testpb.ExampleTable 4/-1/"abc" -> u32:4 u64:16 str:"abc" bz:"abc" i64:-1 + PK testpb.ExampleTable 4/-1/abc -> {"u32":4,"u64":16,"str":"abc","bz":"abc","i64":-1} NEXT VALID true KEY 0100000000057ffffffffffffffe616264 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} KEY 0100000000057ffffffffffffffe616264 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} NEXT VALID true KEY 0100000000057ffffffffffffffe616265 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} KEY 0100000000057ffffffffffffffe616265 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} NEXT VALID true KEY 0100000000077ffffffffffffffe616265 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} KEY 0100000000077ffffffffffffffe616265 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} NEXT VALID true KEY 0100000000077fffffffffffffff616265 100b - PK testpb.ExampleTable 7/-1/"abe" -> u32:7 u64:11 str:"abe" i64:-1 + PK testpb.ExampleTable 7/-1/abe -> {"u32":7,"u64":11,"str":"abe","i64":-1} KEY 0100000000077fffffffffffffff616265 100b - PK testpb.ExampleTable 7/-1/"abe" -> u32:7 u64:11 str:"abe" i64:-1 + PK testpb.ExampleTable 7/-1/abe -> {"u32":7,"u64":11,"str":"abe","i64":-1} NEXT VALID true KEY 0100000000087ffffffffffffffc616263 100b - PK testpb.ExampleTable 8/-4/"abc" -> u32:8 u64:11 str:"abc" i64:-4 + PK testpb.ExampleTable 8/-4/abc -> {"u32":8,"u64":11,"str":"abc","i64":-4} KEY 0100000000087ffffffffffffffc616263 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} NEXT VALID true KEY 0100000000088000000000000001616263 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} KEY 0100000000088000000000000001616263 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} NEXT VALID true KEY 0100000000088000000000000001616264 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} KEY 0100000000088000000000000001616264 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} NEXT VALID true KEY 0100000000098000000000000000 7801 - PK testpb.ExampleTable 9/0/"" -> u32:9 b:true + PK testpb.ExampleTable 9/0/ -> {"u32":9,"b":true} KEY 0100000000098000000000000000 7801 - PK testpb.ExampleTable 9/0/"" -> u32:9 b:true + PK testpb.ExampleTable 9/0/ -> {"u32":9,"b":true} NEXT VALID false GET 0100000000077ffffffffffffffe616265 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 + 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} DEL 0100000000077ffffffffffffffe616265 -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 0101000000000000000a616265 DEL ERR:EOF DEL 010261626500000000077ffffffffffffffe -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 01030061626500000000077ffffffffffffffe -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 HAS 0100000000077ffffffffffffffe616265 - 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 VALID true KEY 0100000000047ffffffffffffffe616263 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} NEXT VALID true KEY 0100000000047ffffffffffffffe616264 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} NEXT VALID true KEY 0100000000047fffffffffffffff616263 10102203616263 - PK testpb.ExampleTable 4/-1/"abc" -> u32:4 u64:16 str:"abc" bz:"abc" i64:-1 + PK testpb.ExampleTable 4/-1/abc -> {"u32":4,"u64":16,"str":"abc","bz":"abc","i64":-1} NEXT VALID true KEY 0100000000057ffffffffffffffe616264 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} NEXT VALID true KEY 0100000000057ffffffffffffffe616265 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} NEXT VALID true KEY 0100000000077fffffffffffffff616265 100b - PK testpb.ExampleTable 7/-1/"abe" -> u32:7 u64:11 str:"abe" i64:-1 + PK testpb.ExampleTable 7/-1/abe -> {"u32":7,"u64":11,"str":"abe","i64":-1} NEXT VALID true KEY 0100000000087ffffffffffffffc616263 100b - PK testpb.ExampleTable 8/-4/"abc" -> u32:8 u64:11 str:"abc" i64:-4 + PK testpb.ExampleTable 8/-4/abc -> {"u32":8,"u64":11,"str":"abc","i64":-4} NEXT VALID true KEY 0100000000088000000000000001616263 100c - PK testpb.ExampleTable 8/1/"abc" -> u32:8 u64:12 str:"abc" i64:1 + PK testpb.ExampleTable 8/1/abc -> {"u32":8,"u64":12,"str":"abc","i64":1} NEXT VALID true KEY 0100000000088000000000000001616264 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} NEXT VALID true KEY 0100000000098000000000000000 7801 - PK testpb.ExampleTable 9/0/"" -> u32:9 b:true + PK testpb.ExampleTable 9/0/ -> {"u32":9,"b":true} NEXT VALID false CLOSE diff --git a/orm/types/ormerrors/errors.go b/orm/types/ormerrors/errors.go index 755e6c78451..01e2e4ccd16 100644 --- a/orm/types/ormerrors/errors.go +++ b/orm/types/ormerrors/errors.go @@ -17,7 +17,7 @@ var ( NotFoundOnUpdate = errors.New(codespace, 10, "can't update object which doesn't exist") PrimaryKeyInvalidOnUpdate = errors.New(codespace, 11, "can't update object with missing or invalid primary key") AutoIncrementKeyAlreadySet = errors.New(codespace, 12, "can't create with auto-increment primary key already set") - CantFindIndexer = errors.New(codespace, 13, "can't find indexer") + CantFindIndex = errors.New(codespace, 13, "can't find index") UnexpectedDecodePrefix = errors.New(codespace, 14, "unexpected prefix while trying to decode an entry") BytesFieldTooLong = errors.New(codespace, 15, "bytes field is longer than 255 bytes") UnsupportedOperation = errors.New(codespace, 16, "unsupported operation") @@ -30,4 +30,5 @@ var ( JSONImportError = errors.New(codespace, 23, "json import error") UniqueKeyViolation = errors.New(codespace, 24, "unique key violation") InvalidTableDefinition = errors.New(codespace, 25, "invalid table definition") + InvalidFileDescriptorID = errors.New(codespace, 26, "invalid file descriptor ID") )