From ddd18ff2eba062345a453304f04174c4b8fb0614 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Thu, 9 Mar 2023 15:56:09 +0100 Subject: [PATCH] feat(orm): add sequence getter for auto increment tables (#15320) Co-authored-by: Aaron Craelius --- orm/CHANGELOG.md | 8 ++++++-- orm/internal/codegen/table.go | 6 ++++++ orm/internal/testpb/bank.pb.go | 2 +- orm/internal/testpb/bank_query.pb.go | 6 +++++- orm/internal/testpb/test_schema.cosmos_orm.go | 15 +++++++++++++++ orm/internal/testpb/test_schema.pb.go | 3 ++- orm/internal/testpb/test_schema_query.pb.go | 12 +++++++++++- orm/model/ormtable/auto_increment.go | 9 +++++++++ orm/model/ormtable/auto_increment_test.go | 9 +++++++++ orm/model/ormtable/build.go | 9 +++------ orm/model/ormtable/table.go | 5 +++++ orm/model/ormtable/testdata/test_auto_inc.golden | 4 ++++ 12 files changed, 76 insertions(+), 12 deletions(-) diff --git a/orm/CHANGELOG.md b/orm/CHANGELOG.md index e7abd1f389..b8bb40c78d 100644 --- a/orm/CHANGELOG.md +++ b/orm/CHANGELOG.md @@ -36,10 +36,14 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +### Feature + +* [#15320](https://github.com/cosmos/cosmos-sdk/pull/15320) Add current sequence getter (`LastInsertedSequence`) for auto increment tables. + ### API Breaking Changes -- [14822](https://github.com/cosmos/cosmos-sdk/pull/14822) Migrate to cosmossdk.io/core genesis API +* [#14822](https://github.com/cosmos/cosmos-sdk/pull/14822) Migrate to cosmossdk.io/core genesis API ### State-machine Breaking Changes -- [12273](https://github.com/cosmos/cosmos-sdk/pull/12273) The timestamp key encoding was reworked to properly handle nil values. Existing users will need to manually migrate their data to the new encoding before upgrading. +* [#12273](https://github.com/cosmos/cosmos-sdk/pull/12273) The timestamp key encoding was reworked to properly handle nil values. Existing users will need to manually migrate their data to the new encoding before upgrading. diff --git a/orm/internal/codegen/table.go b/orm/internal/codegen/table.go index b1f21cecec..d629b0c298 100644 --- a/orm/internal/codegen/table.go +++ b/orm/internal/codegen/table.go @@ -62,6 +62,7 @@ func (t tableGen) getTableInterface() { t.P("Insert(ctx ", contextPkg.Ident("Context"), ", ", t.param(t.msg.GoIdent.GoName), " *", t.QualifiedGoIdent(t.msg.GoIdent), ") error") if t.table.PrimaryKey.AutoIncrement { t.P("InsertReturning", fieldsToCamelCase(t.table.PrimaryKey.Fields), "(ctx ", contextPkg.Ident("Context"), ", ", t.param(t.msg.GoIdent.GoName), " *", t.QualifiedGoIdent(t.msg.GoIdent), ") (uint64, error)") + t.P("LastInsertedSequence(ctx ", contextPkg.Ident("Context"), ") (uint64, error)") } t.P("Update(ctx ", contextPkg.Ident("Context"), ", ", t.param(t.msg.GoIdent.GoName), " *", t.QualifiedGoIdent(t.msg.GoIdent), ") error") t.P("Save(ctx ", contextPkg.Ident("Context"), ", ", t.param(t.msg.GoIdent.GoName), " *", t.QualifiedGoIdent(t.msg.GoIdent), ") error") @@ -184,6 +185,11 @@ func (t tableGen) genTableImpl() { t.P("return ", receiverVar, ".table.InsertReturningPKey(ctx, ", varName, ")") t.P("}") t.P() + + t.P(receiver, "LastInsertedSequence(ctx ", contextPkg.Ident("Context"), ") (uint64, error) {") + t.P("return ", receiverVar, ".table.LastInsertedSequence(ctx)") + t.P("}") + t.P() } // Has diff --git a/orm/internal/testpb/bank.pb.go b/orm/internal/testpb/bank.pb.go index 83c50055fd..8366c79dc5 100644 --- a/orm/internal/testpb/bank.pb.go +++ b/orm/internal/testpb/bank.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.27.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: testpb/bank.proto diff --git a/orm/internal/testpb/bank_query.pb.go b/orm/internal/testpb/bank_query.pb.go index f0a2e21f02..487235337c 100644 --- a/orm/internal/testpb/bank_query.pb.go +++ b/orm/internal/testpb/bank_query.pb.go @@ -2,7 +2,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.27.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: testpb/bank_query.proto @@ -139,6 +139,7 @@ type ListBalanceRequest struct { // query specifies the type of query - either a prefix or range query. // // Types that are assignable to Query: + // // *ListBalanceRequest_PrefixQuery // *ListBalanceRequest_RangeQuery_ Query isListBalanceRequest_Query `protobuf_oneof:"query"` @@ -389,6 +390,7 @@ type ListSupplyRequest struct { // query specifies the type of query - either a prefix or range query. // // Types that are assignable to Query: + // // *ListSupplyRequest_PrefixQuery // *ListSupplyRequest_RangeQuery_ Query isListSupplyRequest_Query `protobuf_oneof:"query"` @@ -541,6 +543,7 @@ type ListBalanceRequest_IndexKey struct { // key specifies the index key value. // // Types that are assignable to Key: + // // *ListBalanceRequest_IndexKey_AddressDenom_ // *ListBalanceRequest_IndexKey_Denom_ Key isListBalanceRequest_IndexKey_Key `protobuf_oneof:"key"` @@ -795,6 +798,7 @@ type ListSupplyRequest_IndexKey struct { // key specifies the index key value. // // Types that are assignable to Key: + // // *ListSupplyRequest_IndexKey_Denom_ Key isListSupplyRequest_IndexKey_Key `protobuf_oneof:"key"` } diff --git a/orm/internal/testpb/test_schema.cosmos_orm.go b/orm/internal/testpb/test_schema.cosmos_orm.go index a5cf2a6fbd..93ce0cda02 100644 --- a/orm/internal/testpb/test_schema.cosmos_orm.go +++ b/orm/internal/testpb/test_schema.cosmos_orm.go @@ -216,6 +216,7 @@ func NewExampleTableTable(db ormtable.Schema) (ExampleTableTable, error) { type ExampleAutoIncrementTableTable interface { Insert(ctx context.Context, exampleAutoIncrementTable *ExampleAutoIncrementTable) error InsertReturningId(ctx context.Context, exampleAutoIncrementTable *ExampleAutoIncrementTable) (uint64, error) + LastInsertedSequence(ctx context.Context) (uint64, error) Update(ctx context.Context, exampleAutoIncrementTable *ExampleAutoIncrementTable) error Save(ctx context.Context, exampleAutoIncrementTable *ExampleAutoIncrementTable) error Delete(ctx context.Context, exampleAutoIncrementTable *ExampleAutoIncrementTable) error @@ -302,6 +303,10 @@ func (this exampleAutoIncrementTableTable) InsertReturningId(ctx context.Context return this.table.InsertReturningPKey(ctx, exampleAutoIncrementTable) } +func (this exampleAutoIncrementTableTable) LastInsertedSequence(ctx context.Context) (uint64, error) { + return this.table.LastInsertedSequence(ctx) +} + func (this exampleAutoIncrementTableTable) Has(ctx context.Context, id uint64) (found bool, err error) { return this.table.PrimaryKey().Has(ctx, id) } @@ -401,6 +406,7 @@ func NewExampleSingletonTable(db ormtable.Schema) (ExampleSingletonTable, error) type ExampleTimestampTable interface { Insert(ctx context.Context, exampleTimestamp *ExampleTimestamp) error InsertReturningId(ctx context.Context, exampleTimestamp *ExampleTimestamp) (uint64, error) + LastInsertedSequence(ctx context.Context) (uint64, error) Update(ctx context.Context, exampleTimestamp *ExampleTimestamp) error Save(ctx context.Context, exampleTimestamp *ExampleTimestamp) error Delete(ctx context.Context, exampleTimestamp *ExampleTimestamp) error @@ -484,6 +490,10 @@ func (this exampleTimestampTable) InsertReturningId(ctx context.Context, example return this.table.InsertReturningPKey(ctx, exampleTimestamp) } +func (this exampleTimestampTable) LastInsertedSequence(ctx context.Context) (uint64, error) { + return this.table.LastInsertedSequence(ctx) +} + func (this exampleTimestampTable) Has(ctx context.Context, id uint64) (found bool, err error) { return this.table.PrimaryKey().Has(ctx, id) } @@ -683,6 +693,7 @@ func NewSimpleExampleTable(db ormtable.Schema) (SimpleExampleTable, error) { type ExampleAutoIncFieldNameTable interface { Insert(ctx context.Context, exampleAutoIncFieldName *ExampleAutoIncFieldName) error InsertReturningFoo(ctx context.Context, exampleAutoIncFieldName *ExampleAutoIncFieldName) (uint64, error) + LastInsertedSequence(ctx context.Context) (uint64, error) Update(ctx context.Context, exampleAutoIncFieldName *ExampleAutoIncFieldName) error Save(ctx context.Context, exampleAutoIncFieldName *ExampleAutoIncFieldName) error Delete(ctx context.Context, exampleAutoIncFieldName *ExampleAutoIncFieldName) error @@ -753,6 +764,10 @@ func (this exampleAutoIncFieldNameTable) InsertReturningFoo(ctx context.Context, return this.table.InsertReturningPKey(ctx, exampleAutoIncFieldName) } +func (this exampleAutoIncFieldNameTable) LastInsertedSequence(ctx context.Context) (uint64, error) { + return this.table.LastInsertedSequence(ctx) +} + func (this exampleAutoIncFieldNameTable) Has(ctx context.Context, foo uint64) (found bool, err error) { return this.table.PrimaryKey().Has(ctx, foo) } diff --git a/orm/internal/testpb/test_schema.pb.go b/orm/internal/testpb/test_schema.pb.go index 4f98d3208c..8dc30bfc36 100644 --- a/orm/internal/testpb/test_schema.pb.go +++ b/orm/internal/testpb/test_schema.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.27.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: testpb/test_schema.proto @@ -105,6 +105,7 @@ type ExampleTable struct { Map map[string]uint32 `protobuf:"bytes,18,rep,name=map,proto3" json:"map,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` Msg *ExampleTable_ExampleMessage `protobuf:"bytes,19,opt,name=msg,proto3" json:"msg,omitempty"` // Types that are assignable to Sum: + // // *ExampleTable_Oneof Sum isExampleTable_Sum `protobuf_oneof:"sum"` } diff --git a/orm/internal/testpb/test_schema_query.pb.go b/orm/internal/testpb/test_schema_query.pb.go index b72ddd3449..484624eb64 100644 --- a/orm/internal/testpb/test_schema_query.pb.go +++ b/orm/internal/testpb/test_schema_query.pb.go @@ -2,7 +2,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.27.1 +// protoc-gen-go v1.28.1 // protoc (unknown) // source: testpb/test_schema_query.proto @@ -253,6 +253,7 @@ type ListExampleTableRequest struct { // query specifies the type of query - either a prefix or range query. // // Types that are assignable to Query: + // // *ListExampleTableRequest_PrefixQuery // *ListExampleTableRequest_RangeQuery_ Query isListExampleTableRequest_Query `protobuf_oneof:"query"` @@ -599,6 +600,7 @@ type ListExampleAutoIncrementTableRequest struct { // query specifies the type of query - either a prefix or range query. // // Types that are assignable to Query: + // // *ListExampleAutoIncrementTableRequest_PrefixQuery // *ListExampleAutoIncrementTableRequest_RangeQuery_ Query isListExampleAutoIncrementTableRequest_Query `protobuf_oneof:"query"` @@ -938,6 +940,7 @@ type ListExampleTimestampRequest struct { // query specifies the type of query - either a prefix or range query. // // Types that are assignable to Query: + // // *ListExampleTimestampRequest_PrefixQuery // *ListExampleTimestampRequest_RangeQuery_ Query isListExampleTimestampRequest_Query `protobuf_oneof:"query"` @@ -1284,6 +1287,7 @@ type ListSimpleExampleRequest struct { // query specifies the type of query - either a prefix or range query. // // Types that are assignable to Query: + // // *ListSimpleExampleRequest_PrefixQuery // *ListSimpleExampleRequest_RangeQuery_ Query isListSimpleExampleRequest_Query `protobuf_oneof:"query"` @@ -1534,6 +1538,7 @@ type ListExampleAutoIncFieldNameRequest struct { // query specifies the type of query - either a prefix or range query. // // Types that are assignable to Query: + // // *ListExampleAutoIncFieldNameRequest_PrefixQuery // *ListExampleAutoIncFieldNameRequest_RangeQuery_ Query isListExampleAutoIncFieldNameRequest_Query `protobuf_oneof:"query"` @@ -1686,6 +1691,7 @@ type ListExampleTableRequest_IndexKey struct { // key specifies the index key value. // // Types that are assignable to Key: + // // *ListExampleTableRequest_IndexKey_U_32I_64Str // *ListExampleTableRequest_IndexKey_U_64Str // *ListExampleTableRequest_IndexKey_StrU_32 @@ -2108,6 +2114,7 @@ type ListExampleAutoIncrementTableRequest_IndexKey struct { // key specifies the index key value. // // Types that are assignable to Key: + // // *ListExampleAutoIncrementTableRequest_IndexKey_Id_ // *ListExampleAutoIncrementTableRequest_IndexKey_X_ Key isListExampleAutoIncrementTableRequest_IndexKey_Key `protobuf_oneof:"key"` @@ -2354,6 +2361,7 @@ type ListExampleTimestampRequest_IndexKey struct { // key specifies the index key value. // // Types that are assignable to Key: + // // *ListExampleTimestampRequest_IndexKey_Id_ // *ListExampleTimestampRequest_IndexKey_Ts_ Key isListExampleTimestampRequest_IndexKey_Key `protobuf_oneof:"key"` @@ -2598,6 +2606,7 @@ type ListSimpleExampleRequest_IndexKey struct { // key specifies the index key value. // // Types that are assignable to Key: + // // *ListSimpleExampleRequest_IndexKey_Name_ // *ListSimpleExampleRequest_IndexKey_Unique_ Key isListSimpleExampleRequest_IndexKey_Key `protobuf_oneof:"key"` @@ -2842,6 +2851,7 @@ type ListExampleAutoIncFieldNameRequest_IndexKey struct { // key specifies the index key value. // // Types that are assignable to Key: + // // *ListExampleAutoIncFieldNameRequest_IndexKey_Foo_ Key isListExampleAutoIncFieldNameRequest_IndexKey_Key `protobuf_oneof:"key"` } diff --git a/orm/model/ormtable/auto_increment.go b/orm/model/ormtable/auto_increment.go index 2a0eed6f94..982ce79872 100644 --- a/orm/model/ormtable/auto_increment.go +++ b/orm/model/ormtable/auto_increment.go @@ -61,6 +61,15 @@ func (t autoIncrementTable) Update(ctx context.Context, message proto.Message) e return err } +func (t autoIncrementTable) LastInsertedSequence(ctx context.Context) (uint64, error) { + backend, err := t.getBackend(ctx) + if err != nil { + return 0, err + } + + return t.curSeqValue(backend.IndexStoreReader()) +} + func (t *autoIncrementTable) save(ctx context.Context, backend Backend, message proto.Message, mode saveMode) (newPK uint64, err error) { messageRef := message.ProtoReflect() val := messageRef.Get(t.autoIncField).Uint() diff --git a/orm/model/ormtable/auto_increment_test.go b/orm/model/ormtable/auto_increment_test.go index c3180000dc..5ba1fa4ed0 100644 --- a/orm/model/ormtable/auto_increment_test.go +++ b/orm/model/ormtable/auto_increment_test.go @@ -52,12 +52,18 @@ func runAutoIncrementScenario(t *testing.T, table ormtable.AutoIncrementTable, c ex1 := &testpb.ExampleAutoIncrementTable{X: "foo", Y: 5} assert.NilError(t, store.Save(ctx, ex1)) assert.Equal(t, uint64(1), ex1.Id) + curSeq, err := table.LastInsertedSequence(ctx) + assert.NilError(t, err) + assert.Equal(t, curSeq, uint64(1)) ex2 := &testpb.ExampleAutoIncrementTable{X: "bar", Y: 10} newId, err := table.InsertReturningPKey(ctx, ex2) assert.NilError(t, err) assert.Equal(t, uint64(2), ex2.Id) assert.Equal(t, newId, ex2.Id) + curSeq, err = table.LastInsertedSequence(ctx) + assert.NilError(t, err) + assert.Equal(t, curSeq, uint64(2)) buf := &bytes.Buffer{} assert.NilError(t, table.ExportJSON(ctx, buf)) @@ -78,6 +84,9 @@ func runAutoIncrementScenario(t *testing.T, table ormtable.AutoIncrementTable, c ex1.Id = 0 assert.NilError(t, table.Insert(store3, ex1)) assert.Equal(t, uint64(3), ex1.Id) // should equal 3 because the sequence number 2 should have been imported from JSON + curSeq, err = table.LastInsertedSequence(store3) + assert.NilError(t, err) + assert.Equal(t, curSeq, uint64(3)) } func TestBadJSON(t *testing.T) { diff --git a/orm/model/ormtable/build.go b/orm/model/ormtable/build.go index 4b9dae4f8a..3e9137665d 100644 --- a/orm/model/ormtable/build.go +++ b/orm/model/ormtable/build.go @@ -3,18 +3,15 @@ package ormtable import ( "fmt" - "github.com/cosmos/cosmos-sdk/orm/internal/fieldnames" - - "github.com/cosmos/cosmos-sdk/orm/encoding/encodeutil" - - "google.golang.org/protobuf/reflect/protoregistry" - "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/reflect/protoregistry" ormv1 "cosmossdk.io/api/cosmos/orm/v1" + "github.com/cosmos/cosmos-sdk/orm/encoding/encodeutil" "github.com/cosmos/cosmos-sdk/orm/encoding/ormkv" + "github.com/cosmos/cosmos-sdk/orm/internal/fieldnames" "github.com/cosmos/cosmos-sdk/orm/types/ormerrors" ) diff --git a/orm/model/ormtable/table.go b/orm/model/ormtable/table.go index b66520ac8e..2217574636 100644 --- a/orm/model/ormtable/table.go +++ b/orm/model/ormtable/table.go @@ -143,6 +143,7 @@ type Table interface { // Schema is an interface for things that contain tables and can encode and // decode kv-store pairs. + type Schema interface { ormkv.EntryCodec @@ -156,4 +157,8 @@ type AutoIncrementTable interface { // InsertReturningPKey inserts the provided entry in the store and returns the newly // generated primary key for the message or an error. InsertReturningPKey(ctx context.Context, message proto.Message) (newPK uint64, err error) + + // LastInsertedSequence retrieves the sequence number of the last entry inserted into the table. + // The LastInsertedSequence is 0 if no entries have been inserted into the table. + LastInsertedSequence(ctx context.Context) (uint64, error) } diff --git a/orm/model/ormtable/testdata/test_auto_inc.golden b/orm/model/ormtable/testdata/test_auto_inc.golden index 07a1fc4663..432c3a371c 100644 --- a/orm/model/ormtable/testdata/test_auto_inc.golden +++ b/orm/model/ormtable/testdata/test_auto_inc.golden @@ -14,6 +14,8 @@ SET 03808002 01 SET 0301666f6f 0001 UNIQ testpb.ExampleAutoIncrementTable x : foo -> 1 ORM AFTER INSERT testpb.ExampleAutoIncrementTable {"id":1,"x":"foo","y":5} +GET 03808002 01 + SEQ testpb.ExampleAutoIncrementTable 1 GET 03808002 01 SEQ testpb.ExampleAutoIncrementTable 1 GET 03000002 @@ -28,6 +30,8 @@ SET 03808002 02 SET 0301626172 0002 UNIQ testpb.ExampleAutoIncrementTable x : bar -> 2 ORM AFTER INSERT testpb.ExampleAutoIncrementTable {"id":2,"x":"bar","y":10} +GET 03808002 02 + SEQ testpb.ExampleAutoIncrementTable 2 GET 03808002 02 SEQ testpb.ExampleAutoIncrementTable 2 ITERATOR 0300 -> 0301