From 47f077197c06789c7e78cdee2c95a6e06fedad6d Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 15 Mar 2022 18:53:57 -0400 Subject: [PATCH 1/6] feat(orm): gRPC codes for save errors --- errors/errors.go | 19 + errors/errors_test.go | 7 +- orm/features/table/save.feature | 49 ++ orm/go.mod | 10 +- orm/go.sum | 18 + orm/internal/testpb/bank.pulsar.go | 2 +- orm/internal/testpb/test_schema.cosmos_orm.go | 162 +++++ orm/internal/testpb/test_schema.proto | 126 ++-- orm/internal/testpb/test_schema.pulsar.go | 682 +++++++++++++++++- orm/model/ormtable/save_test.go | 85 +++ orm/model/ormtable/table_impl.go | 4 +- orm/model/ormtable/unique.go | 4 +- orm/types/ormerrors/errors.go | 12 +- 13 files changed, 1080 insertions(+), 100 deletions(-) create mode 100644 orm/features/table/save.feature create mode 100644 orm/model/ormtable/save_test.go diff --git a/errors/errors.go b/errors/errors.go index 5d54bedfc95b..342d4bd80291 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -244,6 +244,25 @@ func (e *wrappedError) Unwrap() error { return e.parent } +func (e *wrappedError) GRPCStatus() *grpcstatus.Status { + w := e.Cause() + for { + if hasStatus, ok := w.(interface { + GRPCStatus() *grpcstatus.Status + }); ok { + return hasStatus.GRPCStatus() + } + + x, ok := w.(causer) + if ok { + w = x.Cause() + } + if x == nil { + return grpcstatus.New(grpccodes.Unknown, e.msg) + } + } +} + // Recover captures a panic and stop its propagation. If panic happens it is // transformed into a ErrPanic instance and assigned to given error. Call this // function using defer in order to work as expected. diff --git a/errors/errors_test.go b/errors/errors_test.go index 07868eb76f43..acc00fb12977 100644 --- a/errors/errors_test.go +++ b/errors/errors_test.go @@ -213,11 +213,14 @@ func (s *errorsTestSuite) TestABCIError() { func (s *errorsTestSuite) TestGRPCStatus() { s.Require().Equal(codes.Unknown, grpcstatus.Code(errInternal)) s.Require().Equal(codes.NotFound, grpcstatus.Code(ErrNotFound)) - s.Require().Equal(codes.Unimplemented, grpcstatus.Code(ErrNotSupported)) - s.Require().Equal(codes.FailedPrecondition, grpcstatus.Code(ErrConflict)) + status, ok := grpcstatus.FromError(ErrNotFound) s.Require().True(ok) s.Require().Equal("codespace testtesttest code 38: not found", status.Message()) + + // test wrapping + s.Require().Equal(codes.Unimplemented, grpcstatus.Code(ErrNotSupported.Wrap("test"))) + s.Require().Equal(codes.FailedPrecondition, grpcstatus.Code(ErrConflict.Wrapf("test %s", "foo"))) } func ExampleWrap() { diff --git a/orm/features/table/save.feature b/orm/features/table/save.feature new file mode 100644 index 000000000000..931c953f8cbb --- /dev/null +++ b/orm/features/table/save.feature @@ -0,0 +1,49 @@ +Feature: saving entities + + Scenario: can't insert an entity with a duplicate primary key + Given an existing entity + """ + {"name": "foo", "not_unique": "bar"} + """ + When I insert + """ + {"name": "foo", "not_unique": "baz"} + """ + Then expect a "already exists" error + And expect grpc error code "ALREADY_EXISTS" + + Scenario: can't update entity that doesn't exist + When I update + """ + {"name":"foo"} + """ + Then expect a "not found" error + And expect grpc error code "NOT_FOUND" +# + Scenario: can't violate unique constraint on insert + Given an existing entity + """ + {"name": "foo", "unique": "bar"} + """ + When I insert + """ + {"name": "baz", "unique": "bar"} + """ + Then expect a "unique key violation" error + And expect grpc error code "FAILED_PRECONDITION" + + Scenario: can't violate unique constraint on update + Given an existing entity + """ + {"name": "foo", "unique": "bar"} + """ + And an existing entity + """ + {"name": "baz", "unique": "bam"} + """ + When I update + """ + {"name": "baz", "unique": "bar"} + """ + Then expect a "unique key violation" error + And expect grpc error code "FAILED_PRECONDITION" diff --git a/orm/go.mod b/orm/go.mod index 24050e7f6cb4..0ae24776151a 100644 --- a/orm/go.mod +++ b/orm/go.mod @@ -9,8 +9,10 @@ require ( github.com/golang/mock v1.6.0 github.com/google/go-cmp v0.5.7 github.com/iancoleman/strcase v0.2.0 + github.com/regen-network/gocuke v0.6.1 github.com/stretchr/testify v1.7.0 github.com/tendermint/tm-db v0.6.7 + google.golang.org/grpc v1.44.0 google.golang.org/protobuf v1.27.1 gotest.tools/v3 v3.1.0 pgregory.net/rapid v0.4.7 @@ -18,13 +20,18 @@ require ( require ( github.com/DataDog/zstd v1.4.5 // indirect + github.com/alecthomas/participle/v2 v2.0.0-alpha7 // indirect github.com/cespare/xxhash v1.1.0 // indirect + github.com/cockroachdb/apd/v3 v3.1.0 // indirect github.com/cosmos/gorocksdb v1.2.0 // indirect + github.com/cucumber/gherkin-go/v19 v19.0.3 // indirect + github.com/cucumber/messages-go/v16 v16.0.1 // 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 github.com/dustin/go-humanize v1.0.0 // indirect + github.com/gofrs/uuid v4.0.0+incompatible // 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 @@ -39,7 +46,8 @@ require ( 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-20220222213610-43724f9ea8cf // indirect - google.golang.org/grpc v1.44.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect ) + +replace github.com/cosmos/cosmos-sdk/errors => ../errors \ No newline at end of file diff --git a/orm/go.sum b/orm/go.sum index 6e9c0f4d9255..06f4fa8a794c 100644 --- a/orm/go.sum +++ b/orm/go.sum @@ -6,6 +6,10 @@ github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/alecthomas/participle/v2 v2.0.0-alpha7 h1:cK4vjj0VSgb3lN1nuKA5F7dw+1s1pWBe5bx7nNCnN+c= +github.com/alecthomas/participle/v2 v2.0.0-alpha7/go.mod h1:NumScqsC42o9x+dGj8/YqsIfhrIQjFEOFovxotbBirA= +github.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1 h1:GDQdwm/gAcJcLAKQQZGOJ4knlw+7rfEQQcmwTbt4p5E= +github.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -20,6 +24,8 @@ github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/apd/v3 v3.1.0 h1:MK3Ow7LH0W8zkd5GMKA1PvS9qG3bWFI95WaVNfyZJ/w= +github.com/cockroachdb/apd/v3 v3.1.0/go.mod h1:6qgPBMXjATAdD/VefbRP9NoSLKjbB4LCoA7gN4LpHs4= 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= @@ -32,6 +38,11 @@ github.com/cosmos/cosmos-sdk/errors v1.0.0-beta.3/go.mod h1:HFea93YKmoMJ/mNKtkSe github.com/cosmos/gorocksdb v1.2.0 h1:d0l3jJG8M4hBouIZq0mDUHZ+zjOx044J3nGRskwTb4Y= github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cucumber/gherkin-go/v19 v19.0.3 h1:mMSKu1077ffLbTJULUfM5HPokgeBcIGboyeNUof1MdE= +github.com/cucumber/gherkin-go/v19 v19.0.3/go.mod h1:jY/NP6jUtRSArQQJ5h1FXOUgk5fZK24qtE7vKi776Vw= +github.com/cucumber/messages-go/v16 v16.0.0/go.mod h1:EJcyR5Mm5ZuDsKJnT2N9KRnBK30BGjtYotDKpwQ0v6g= +github.com/cucumber/messages-go/v16 v16.0.1 h1:fvkpwsLgnIm0qugftrw2YwNlio+ABe2Iu94Ap8GMYIY= +github.com/cucumber/messages-go/v16 v16.0.1/go.mod h1:EJcyR5Mm5ZuDsKJnT2N9KRnBK30BGjtYotDKpwQ0v6g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -62,6 +73,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -113,6 +126,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN 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/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= +github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -126,12 +141,15 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/gocuke v0.6.1 h1:SEsXbZDg7/DXpy/hPsLbVvfdObpK13PsJ8Pq3ko+S4s= +github.com/regen-network/gocuke v0.6.1/go.mod h1:+i/R+pDBMLx1M7rL3fV7FC18gzyVTdGu3rNLUSOzHIo= 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= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= diff --git a/orm/internal/testpb/bank.pulsar.go b/orm/internal/testpb/bank.pulsar.go index b66d2cf34bf4..1a347bf5575e 100644 --- a/orm/internal/testpb/bank.pulsar.go +++ b/orm/internal/testpb/bank.pulsar.go @@ -1016,7 +1016,7 @@ func (x *fastReflection_Supply) ProtoMethods() *protoiface.Methods { // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.27.0 -// protoc v3.19.1 +// protoc (unknown) // source: testpb/bank.proto const ( diff --git a/orm/internal/testpb/test_schema.cosmos_orm.go b/orm/internal/testpb/test_schema.cosmos_orm.go index 4ad28f452ab6..5f62658a0778 100644 --- a/orm/internal/testpb/test_schema.cosmos_orm.go +++ b/orm/internal/testpb/test_schema.cosmos_orm.go @@ -530,11 +530,162 @@ func NewExampleTimestampTable(db ormtable.Schema) (ExampleTimestampTable, error) return exampleTimestampTable{table.(ormtable.AutoIncrementTable)}, nil } +type SimpleExampleTable interface { + Insert(ctx context.Context, simpleExample *SimpleExample) error + Update(ctx context.Context, simpleExample *SimpleExample) error + Save(ctx context.Context, simpleExample *SimpleExample) error + Delete(ctx context.Context, simpleExample *SimpleExample) error + Has(ctx context.Context, name string) (found bool, err error) + // Get returns nil and an error which responds true to ormerrors.IsNotFound() if the record was not found. + Get(ctx context.Context, name string) (*SimpleExample, error) + HasByUnique(ctx context.Context, unique string) (found bool, err error) + // GetByUnique returns nil and an error which responds true to ormerrors.IsNotFound() if the record was not found. + GetByUnique(ctx context.Context, unique string) (*SimpleExample, error) + List(ctx context.Context, prefixKey SimpleExampleIndexKey, opts ...ormlist.Option) (SimpleExampleIterator, error) + ListRange(ctx context.Context, from, to SimpleExampleIndexKey, opts ...ormlist.Option) (SimpleExampleIterator, error) + DeleteBy(ctx context.Context, prefixKey SimpleExampleIndexKey) error + DeleteRange(ctx context.Context, from, to SimpleExampleIndexKey) error + + doNotImplement() +} + +type SimpleExampleIterator struct { + ormtable.Iterator +} + +func (i SimpleExampleIterator) Value() (*SimpleExample, error) { + var simpleExample SimpleExample + err := i.UnmarshalMessage(&simpleExample) + return &simpleExample, err +} + +type SimpleExampleIndexKey interface { + id() uint32 + values() []interface{} + simpleExampleIndexKey() +} + +// primary key starting index.. +type SimpleExamplePrimaryKey = SimpleExampleNameIndexKey + +type SimpleExampleNameIndexKey struct { + vs []interface{} +} + +func (x SimpleExampleNameIndexKey) id() uint32 { return 0 } +func (x SimpleExampleNameIndexKey) values() []interface{} { return x.vs } +func (x SimpleExampleNameIndexKey) simpleExampleIndexKey() {} + +func (this SimpleExampleNameIndexKey) WithName(name string) SimpleExampleNameIndexKey { + this.vs = []interface{}{name} + return this +} + +type SimpleExampleUniqueIndexKey struct { + vs []interface{} +} + +func (x SimpleExampleUniqueIndexKey) id() uint32 { return 1 } +func (x SimpleExampleUniqueIndexKey) values() []interface{} { return x.vs } +func (x SimpleExampleUniqueIndexKey) simpleExampleIndexKey() {} + +func (this SimpleExampleUniqueIndexKey) WithUnique(unique string) SimpleExampleUniqueIndexKey { + this.vs = []interface{}{unique} + return this +} + +type simpleExampleTable struct { + table ormtable.Table +} + +func (this simpleExampleTable) Insert(ctx context.Context, simpleExample *SimpleExample) error { + return this.table.Insert(ctx, simpleExample) +} + +func (this simpleExampleTable) Update(ctx context.Context, simpleExample *SimpleExample) error { + return this.table.Update(ctx, simpleExample) +} + +func (this simpleExampleTable) Save(ctx context.Context, simpleExample *SimpleExample) error { + return this.table.Save(ctx, simpleExample) +} + +func (this simpleExampleTable) Delete(ctx context.Context, simpleExample *SimpleExample) error { + return this.table.Delete(ctx, simpleExample) +} + +func (this simpleExampleTable) Has(ctx context.Context, name string) (found bool, err error) { + return this.table.PrimaryKey().Has(ctx, name) +} + +func (this simpleExampleTable) Get(ctx context.Context, name string) (*SimpleExample, error) { + var simpleExample SimpleExample + found, err := this.table.PrimaryKey().Get(ctx, &simpleExample, name) + if err != nil { + return nil, err + } + if !found { + return nil, ormerrors.NotFound + } + return &simpleExample, nil +} + +func (this simpleExampleTable) HasByUnique(ctx context.Context, unique string) (found bool, err error) { + return this.table.GetIndexByID(1).(ormtable.UniqueIndex).Has(ctx, + unique, + ) +} + +func (this simpleExampleTable) GetByUnique(ctx context.Context, unique string) (*SimpleExample, error) { + var simpleExample SimpleExample + found, err := this.table.GetIndexByID(1).(ormtable.UniqueIndex).Get(ctx, &simpleExample, + unique, + ) + if err != nil { + return nil, err + } + if !found { + return nil, ormerrors.NotFound + } + return &simpleExample, nil +} + +func (this simpleExampleTable) List(ctx context.Context, prefixKey SimpleExampleIndexKey, opts ...ormlist.Option) (SimpleExampleIterator, error) { + it, err := this.table.GetIndexByID(prefixKey.id()).List(ctx, prefixKey.values(), opts...) + return SimpleExampleIterator{it}, err +} + +func (this simpleExampleTable) ListRange(ctx context.Context, from, to SimpleExampleIndexKey, opts ...ormlist.Option) (SimpleExampleIterator, error) { + it, err := this.table.GetIndexByID(from.id()).ListRange(ctx, from.values(), to.values(), opts...) + return SimpleExampleIterator{it}, err +} + +func (this simpleExampleTable) DeleteBy(ctx context.Context, prefixKey SimpleExampleIndexKey) error { + return this.table.GetIndexByID(prefixKey.id()).DeleteBy(ctx, prefixKey.values()...) +} + +func (this simpleExampleTable) DeleteRange(ctx context.Context, from, to SimpleExampleIndexKey) error { + return this.table.GetIndexByID(from.id()).DeleteRange(ctx, from.values(), to.values()) +} + +func (this simpleExampleTable) doNotImplement() {} + +var _ SimpleExampleTable = simpleExampleTable{} + +func NewSimpleExampleTable(db ormtable.Schema) (SimpleExampleTable, error) { + table := db.GetTable(&SimpleExample{}) + if table == nil { + return nil, ormerrors.TableNotFound.Wrap(string((&SimpleExample{}).ProtoReflect().Descriptor().FullName())) + } + return simpleExampleTable{table}, nil +} + type TestSchemaStore interface { ExampleTableTable() ExampleTableTable ExampleAutoIncrementTableTable() ExampleAutoIncrementTableTable ExampleSingletonTable() ExampleSingletonTable ExampleTimestampTable() ExampleTimestampTable + SimpleExampleTable() SimpleExampleTable doNotImplement() } @@ -544,6 +695,7 @@ type testSchemaStore struct { exampleAutoIncrementTable ExampleAutoIncrementTableTable exampleSingleton ExampleSingletonTable exampleTimestamp ExampleTimestampTable + simpleExample SimpleExampleTable } func (x testSchemaStore) ExampleTableTable() ExampleTableTable { @@ -562,6 +714,10 @@ func (x testSchemaStore) ExampleTimestampTable() ExampleTimestampTable { return x.exampleTimestamp } +func (x testSchemaStore) SimpleExampleTable() SimpleExampleTable { + return x.simpleExample +} + func (testSchemaStore) doNotImplement() {} var _ TestSchemaStore = testSchemaStore{} @@ -587,10 +743,16 @@ func NewTestSchemaStore(db ormtable.Schema) (TestSchemaStore, error) { return nil, err } + simpleExampleTable, err := NewSimpleExampleTable(db) + if err != nil { + return nil, err + } + return testSchemaStore{ exampleTableTable, exampleAutoIncrementTableTable, exampleSingletonTable, exampleTimestampTable, + simpleExampleTable, }, nil } diff --git a/orm/internal/testpb/test_schema.proto b/orm/internal/testpb/test_schema.proto index 47792619b608..522e801f994e 100644 --- a/orm/internal/testpb/test_schema.proto +++ b/orm/internal/testpb/test_schema.proto @@ -9,68 +9,68 @@ import "cosmos/orm/v1alpha1/orm.proto"; message ExampleTable { option (cosmos.orm.v1alpha1.table) = { id: 1; -primary_key: { -fields: - "u32,i64,str" -} -index: { -id: - 1; -fields: - "u64,str" unique: true -} -index: { -id: - 2; -fields: - "str,u32" -} -index: { -id: - 3; -fields: - "bz,str" -} -}; + primary_key: { + fields: + "u32,i64,str" + } + index: { + id: + 1; + fields: + "u64,str" unique: true + } + index: { + id: + 2; + fields: + "str,u32" + } + index: { + id: + 3; + fields: + "bz,str" + } + }; -// Valid key fields: -uint32 u32 = 1; -uint64 u64 = 2; -string str = 3; -bytes bz = 4; -google.protobuf.Timestamp ts = 5; -google.protobuf.Duration dur = 6; -int32 i32 = 7; -sint32 s32 = 8; -sfixed32 sf32 = 9; -int64 i64 = 10; -sint64 s64 = 11; -sfixed64 sf64 = 12; -fixed32 f32 = 13; -fixed64 f64 = 14; -bool b = 15; -Enum e = 16; + // Valid key fields: + uint32 u32 = 1; + uint64 u64 = 2; + string str = 3; + bytes bz = 4; + google.protobuf.Timestamp ts = 5; + google.protobuf.Duration dur = 6; + int32 i32 = 7; + sint32 s32 = 8; + sfixed32 sf32 = 9; + int64 i64 = 10; + sint64 s64 = 11; + sfixed64 sf64 = 12; + fixed32 f32 = 13; + fixed64 f64 = 14; + bool b = 15; + Enum e = 16; -// Invalid key fields: -repeated uint32 repeated = 17; -map map = 18; -ExampleMessage msg = 19; -oneof sum { - uint32 oneof = 20; -} + // Invalid key fields: + repeated uint32 repeated = 17; + map map = 18; + ExampleMessage msg = 19; + oneof sum { + uint32 oneof = 20; + } -message ExampleMessage { - string foo = 1; - int32 bar = 2; -} + message ExampleMessage { + string foo = 1; + int32 bar = 2; + } } enum Enum { ENUM_UNSPECIFIED = 0; - ENUM_ONE = 1; - ENUM_TWO = 2; - ENUM_FIVE = 5; - ENUM_NEG_THREE = -3; + ENUM_ONE = 1; + ENUM_TWO = 2; + ENUM_FIVE = 5; + ENUM_NEG_THREE = -3; } message ExampleAutoIncrementTable { @@ -81,8 +81,8 @@ message ExampleAutoIncrementTable { }; uint64 id = 1; - string x = 2; - int32 y = 3; + string x = 2; + int32 y = 3; } message ExampleSingleton { @@ -104,3 +104,15 @@ message ExampleTimestamp { string name = 2; google.protobuf.Timestamp ts = 3; } + +message SimpleExample { + option (cosmos.orm.v1alpha1.table) = { + id: 5 + primary_key: {fields: "name"} + index: {id: 1, fields: "unique", unique: true} + }; + + string name = 1; + string unique = 2; + string not_unique = 3; +} \ No newline at end of file diff --git a/orm/internal/testpb/test_schema.pulsar.go b/orm/internal/testpb/test_schema.pulsar.go index 7fb309825a5e..6cb4e98cb9a2 100644 --- a/orm/internal/testpb/test_schema.pulsar.go +++ b/orm/internal/testpb/test_schema.pulsar.go @@ -1872,7 +1872,7 @@ func (x *ExampleTable_ExampleMessage) ProtoReflect() protoreflect.Message { } func (x *ExampleTable_ExampleMessage) slowProtoReflect() protoreflect.Message { - mi := &file_testpb_test_schema_proto_msgTypes[5] + mi := &file_testpb_test_schema_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3849,10 +3849,558 @@ func (x *fastReflection_ExampleTimestamp) ProtoMethods() *protoiface.Methods { } } +var ( + md_SimpleExample protoreflect.MessageDescriptor + fd_SimpleExample_name protoreflect.FieldDescriptor + fd_SimpleExample_unique protoreflect.FieldDescriptor + fd_SimpleExample_not_unique protoreflect.FieldDescriptor +) + +func init() { + file_testpb_test_schema_proto_init() + md_SimpleExample = File_testpb_test_schema_proto.Messages().ByName("SimpleExample") + fd_SimpleExample_name = md_SimpleExample.Fields().ByName("name") + fd_SimpleExample_unique = md_SimpleExample.Fields().ByName("unique") + fd_SimpleExample_not_unique = md_SimpleExample.Fields().ByName("not_unique") +} + +var _ protoreflect.Message = (*fastReflection_SimpleExample)(nil) + +type fastReflection_SimpleExample SimpleExample + +func (x *SimpleExample) ProtoReflect() protoreflect.Message { + return (*fastReflection_SimpleExample)(x) +} + +func (x *SimpleExample) slowProtoReflect() protoreflect.Message { + mi := &file_testpb_test_schema_proto_msgTypes[4] + 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_SimpleExample_messageType fastReflection_SimpleExample_messageType +var _ protoreflect.MessageType = fastReflection_SimpleExample_messageType{} + +type fastReflection_SimpleExample_messageType struct{} + +func (x fastReflection_SimpleExample_messageType) Zero() protoreflect.Message { + return (*fastReflection_SimpleExample)(nil) +} +func (x fastReflection_SimpleExample_messageType) New() protoreflect.Message { + return new(fastReflection_SimpleExample) +} +func (x fastReflection_SimpleExample_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_SimpleExample +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_SimpleExample) Descriptor() protoreflect.MessageDescriptor { + return md_SimpleExample +} + +// 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_SimpleExample) Type() protoreflect.MessageType { + return _fastReflection_SimpleExample_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_SimpleExample) New() protoreflect.Message { + return new(fastReflection_SimpleExample) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_SimpleExample) Interface() protoreflect.ProtoMessage { + return (*SimpleExample)(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_SimpleExample) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Name != "" { + value := protoreflect.ValueOfString(x.Name) + if !f(fd_SimpleExample_name, value) { + return + } + } + if x.Unique != "" { + value := protoreflect.ValueOfString(x.Unique) + if !f(fd_SimpleExample_unique, value) { + return + } + } + if x.NotUnique != "" { + value := protoreflect.ValueOfString(x.NotUnique) + if !f(fd_SimpleExample_not_unique, 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_SimpleExample) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "testpb.SimpleExample.name": + return x.Name != "" + case "testpb.SimpleExample.unique": + return x.Unique != "" + case "testpb.SimpleExample.not_unique": + return x.NotUnique != "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.SimpleExample")) + } + panic(fmt.Errorf("message testpb.SimpleExample 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_SimpleExample) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "testpb.SimpleExample.name": + x.Name = "" + case "testpb.SimpleExample.unique": + x.Unique = "" + case "testpb.SimpleExample.not_unique": + x.NotUnique = "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.SimpleExample")) + } + panic(fmt.Errorf("message testpb.SimpleExample 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_SimpleExample) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "testpb.SimpleExample.name": + value := x.Name + return protoreflect.ValueOfString(value) + case "testpb.SimpleExample.unique": + value := x.Unique + return protoreflect.ValueOfString(value) + case "testpb.SimpleExample.not_unique": + value := x.NotUnique + return protoreflect.ValueOfString(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.SimpleExample")) + } + panic(fmt.Errorf("message testpb.SimpleExample 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_SimpleExample) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "testpb.SimpleExample.name": + x.Name = value.Interface().(string) + case "testpb.SimpleExample.unique": + x.Unique = value.Interface().(string) + case "testpb.SimpleExample.not_unique": + x.NotUnique = value.Interface().(string) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.SimpleExample")) + } + panic(fmt.Errorf("message testpb.SimpleExample 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_SimpleExample) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "testpb.SimpleExample.name": + panic(fmt.Errorf("field name of message testpb.SimpleExample is not mutable")) + case "testpb.SimpleExample.unique": + panic(fmt.Errorf("field unique of message testpb.SimpleExample is not mutable")) + case "testpb.SimpleExample.not_unique": + panic(fmt.Errorf("field not_unique of message testpb.SimpleExample is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.SimpleExample")) + } + panic(fmt.Errorf("message testpb.SimpleExample 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_SimpleExample) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "testpb.SimpleExample.name": + return protoreflect.ValueOfString("") + case "testpb.SimpleExample.unique": + return protoreflect.ValueOfString("") + case "testpb.SimpleExample.not_unique": + return protoreflect.ValueOfString("") + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: testpb.SimpleExample")) + } + panic(fmt.Errorf("message testpb.SimpleExample 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_SimpleExample) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in testpb.SimpleExample", 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_SimpleExample) 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_SimpleExample) 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_SimpleExample) 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_SimpleExample) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*SimpleExample) + 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.Name) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.Unique) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.NotUnique) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + 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().(*SimpleExample) + 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 len(x.NotUnique) > 0 { + i -= len(x.NotUnique) + copy(dAtA[i:], x.NotUnique) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.NotUnique))) + i-- + dAtA[i] = 0x1a + } + if len(x.Unique) > 0 { + i -= len(x.Unique) + copy(dAtA[i:], x.Unique) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Unique))) + i-- + dAtA[i] = 0x12 + } + if len(x.Name) > 0 { + i -= len(x.Name) + copy(dAtA[i:], x.Name) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Name))) + 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().(*SimpleExample) + 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: SimpleExample: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: SimpleExample: 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 Name", 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.Name = 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 Unique", 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.Unique = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field NotUnique", 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.NotUnique = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + 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 v3.19.1 +// protoc (unknown) // source: testpb/test_schema.proto const ( @@ -4270,6 +4818,57 @@ func (x *ExampleTimestamp) GetTs() *timestamppb.Timestamp { return nil } +type SimpleExample struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Unique string `protobuf:"bytes,2,opt,name=unique,proto3" json:"unique,omitempty"` + NotUnique string `protobuf:"bytes,3,opt,name=not_unique,json=notUnique,proto3" json:"not_unique,omitempty"` +} + +func (x *SimpleExample) Reset() { + *x = SimpleExample{} + if protoimpl.UnsafeEnabled { + mi := &file_testpb_test_schema_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SimpleExample) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SimpleExample) ProtoMessage() {} + +// Deprecated: Use SimpleExample.ProtoReflect.Descriptor instead. +func (*SimpleExample) Descriptor() ([]byte, []int) { + return file_testpb_test_schema_proto_rawDescGZIP(), []int{4} +} + +func (x *SimpleExample) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *SimpleExample) GetUnique() string { + if x != nil { + return x.Unique + } + return "" +} + +func (x *SimpleExample) GetNotUnique() string { + if x != nil { + return x.NotUnique + } + return "" +} + type ExampleTable_ExampleMessage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -4282,7 +4881,7 @@ type ExampleTable_ExampleMessage struct { func (x *ExampleTable_ExampleMessage) Reset() { *x = ExampleTable_ExampleMessage{} if protoimpl.UnsafeEnabled { - mi := &file_testpb_test_schema_proto_msgTypes[5] + mi := &file_testpb_test_schema_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4386,22 +4985,30 @@ var file_testpb_test_schema_proto_rawDesc = []byte{ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x02, 0x74, 0x73, 0x3a, 0x18, 0xf2, 0x9e, 0xd3, 0x8e, 0x03, 0x12, 0x0a, 0x06, 0x0a, 0x02, 0x69, 0x64, 0x10, 0x01, 0x12, 0x06, 0x0a, 0x02, - 0x74, 0x73, 0x10, 0x01, 0x18, 0x04, 0x2a, 0x64, 0x0a, 0x04, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x14, - 0x0a, 0x10, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, - 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x4f, 0x4e, 0x45, - 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x54, 0x57, 0x4f, 0x10, 0x02, - 0x12, 0x0d, 0x0a, 0x09, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x46, 0x49, 0x56, 0x45, 0x10, 0x05, 0x12, - 0x1b, 0x0a, 0x0e, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x4e, 0x45, 0x47, 0x5f, 0x54, 0x48, 0x52, 0x45, - 0x45, 0x10, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x42, 0x87, 0x01, 0x0a, - 0x0a, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x42, 0x0f, 0x54, 0x65, 0x73, - 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 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, + 0x74, 0x73, 0x10, 0x01, 0x18, 0x04, 0x22, 0x7a, 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, + 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x75, + 0x6e, 0x69, 0x71, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x6e, 0x69, + 0x71, 0x75, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x6f, 0x74, 0x5f, 0x75, 0x6e, 0x69, 0x71, 0x75, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x6f, 0x74, 0x55, 0x6e, 0x69, 0x71, + 0x75, 0x65, 0x3a, 0x1e, 0xf2, 0x9e, 0xd3, 0x8e, 0x03, 0x18, 0x0a, 0x06, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x0c, 0x0a, 0x06, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x10, 0x01, 0x18, 0x01, + 0x18, 0x05, 0x2a, 0x64, 0x0a, 0x04, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x10, 0x45, 0x4e, + 0x55, 0x4d, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x0c, 0x0a, 0x08, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x4f, 0x4e, 0x45, 0x10, 0x01, 0x12, 0x0c, + 0x0a, 0x08, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x54, 0x57, 0x4f, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, + 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x46, 0x49, 0x56, 0x45, 0x10, 0x05, 0x12, 0x1b, 0x0a, 0x0e, 0x45, + 0x4e, 0x55, 0x4d, 0x5f, 0x4e, 0x45, 0x47, 0x5f, 0x54, 0x48, 0x52, 0x45, 0x45, 0x10, 0xfd, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x42, 0x87, 0x01, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, + 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0x42, 0x0f, 0x54, 0x65, 0x73, 0x74, 0x53, 0x63, 0x68, + 0x65, 0x6d, 0x61, 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 ( @@ -4417,25 +5024,26 @@ func file_testpb_test_schema_proto_rawDescGZIP() []byte { } var file_testpb_test_schema_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_testpb_test_schema_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_testpb_test_schema_proto_msgTypes = make([]protoimpl.MessageInfo, 7) var file_testpb_test_schema_proto_goTypes = []interface{}{ (Enum)(0), // 0: testpb.Enum (*ExampleTable)(nil), // 1: testpb.ExampleTable (*ExampleAutoIncrementTable)(nil), // 2: testpb.ExampleAutoIncrementTable (*ExampleSingleton)(nil), // 3: testpb.ExampleSingleton (*ExampleTimestamp)(nil), // 4: testpb.ExampleTimestamp - nil, // 5: testpb.ExampleTable.MapEntry - (*ExampleTable_ExampleMessage)(nil), // 6: testpb.ExampleTable.ExampleMessage - (*timestamppb.Timestamp)(nil), // 7: google.protobuf.Timestamp - (*durationpb.Duration)(nil), // 8: google.protobuf.Duration + (*SimpleExample)(nil), // 5: testpb.SimpleExample + nil, // 6: testpb.ExampleTable.MapEntry + (*ExampleTable_ExampleMessage)(nil), // 7: testpb.ExampleTable.ExampleMessage + (*timestamppb.Timestamp)(nil), // 8: google.protobuf.Timestamp + (*durationpb.Duration)(nil), // 9: google.protobuf.Duration } var file_testpb_test_schema_proto_depIdxs = []int32{ - 7, // 0: testpb.ExampleTable.ts:type_name -> google.protobuf.Timestamp - 8, // 1: testpb.ExampleTable.dur:type_name -> google.protobuf.Duration + 8, // 0: testpb.ExampleTable.ts:type_name -> google.protobuf.Timestamp + 9, // 1: testpb.ExampleTable.dur:type_name -> google.protobuf.Duration 0, // 2: testpb.ExampleTable.e:type_name -> testpb.Enum - 5, // 3: testpb.ExampleTable.map:type_name -> testpb.ExampleTable.MapEntry - 6, // 4: testpb.ExampleTable.msg:type_name -> testpb.ExampleTable.ExampleMessage - 7, // 5: testpb.ExampleTimestamp.ts:type_name -> google.protobuf.Timestamp + 6, // 3: testpb.ExampleTable.map:type_name -> testpb.ExampleTable.MapEntry + 7, // 4: testpb.ExampleTable.msg:type_name -> testpb.ExampleTable.ExampleMessage + 8, // 5: testpb.ExampleTimestamp.ts:type_name -> google.protobuf.Timestamp 6, // [6:6] is the sub-list for method output_type 6, // [6:6] is the sub-list for method input_type 6, // [6:6] is the sub-list for extension type_name @@ -4497,7 +5105,19 @@ func file_testpb_test_schema_proto_init() { return nil } } - file_testpb_test_schema_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_testpb_test_schema_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SimpleExample); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_testpb_test_schema_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExampleTable_ExampleMessage); i { case 0: return &v.state @@ -4519,7 +5139,7 @@ func file_testpb_test_schema_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_testpb_test_schema_proto_rawDesc, NumEnums: 1, - NumMessages: 6, + NumMessages: 7, NumExtensions: 0, NumServices: 0, }, diff --git a/orm/model/ormtable/save_test.go b/orm/model/ormtable/save_test.go new file mode 100644 index 000000000000..b79dd53537d1 --- /dev/null +++ b/orm/model/ormtable/save_test.go @@ -0,0 +1,85 @@ +package ormtable_test + +import ( + "context" + "fmt" + "github.com/cosmos/cosmos-sdk/orm/model/ormtable" + "github.com/cosmos/cosmos-sdk/orm/types/ormerrors" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/encoding/protojson" + "testing" + + "github.com/regen-network/gocuke" + "gotest.tools/v3/assert" + + "github.com/cosmos/cosmos-sdk/orm/internal/testpb" + "github.com/cosmos/cosmos-sdk/orm/testing/ormtest" +) + +func TestSave(t *testing.T) { + gocuke.NewRunner(t, &suite{}).Path("../../features/table/save.feature").Run() +} + +type suite struct { + gocuke.TestingT + table ormtable.Table + ctx context.Context + err error +} + +func (s *suite) Before() { + var err error + s.table, err = ormtable.Build(ormtable.Options{ + MessageType: (&testpb.SimpleExample{}).ProtoReflect().Type(), + }) + assert.NilError(s, err) + s.ctx = ormtable.WrapContextDefault(ormtest.NewMemoryBackend()) +} + +func (s *suite) AnExistingEntity(docString gocuke.DocString) { + existing := s.simpleExampleFromDocString(docString) + assert.NilError(s, s.table.Insert(s.ctx, existing)) +} + +func (s suite) simpleExampleFromDocString(docString gocuke.DocString) *testpb.SimpleExample { + ex := &testpb.SimpleExample{} + assert.NilError(s, protojson.Unmarshal([]byte(docString.Content), ex)) + return ex +} + +func (s *suite) IInsert(a gocuke.DocString) { + ex := s.simpleExampleFromDocString(a) + s.err = s.table.Insert(s.ctx, ex) +} + +func (s *suite) IUpdate(a gocuke.DocString) { + ex := s.simpleExampleFromDocString(a) + s.err = s.table.Update(s.ctx, ex) +} + +func (s *suite) ExpectAError(a string) { + assert.ErrorIs(s, s.err, s.toError(a), s.err.Error()) +} + +func (s *suite) toError(str string) error { + switch str { + case "already exists": + return ormerrors.AlreadyExists + case "not found": + return ormerrors.NotFound + case "constraint violation": + return ormerrors.ConstraintViolation + case "unique key violation": + return ormerrors.UniqueKeyViolation + default: + s.Fatalf("missing case for error %s", str) + return nil + } +} + +func (s *suite) ExpectGrpcErrorCode(a string) { + var code codes.Code + assert.NilError(s, code.UnmarshalJSON([]byte(fmt.Sprintf("%q", a)))) + assert.Equal(s, code, status.Code(s.err)) +} diff --git a/orm/model/ormtable/table_impl.go b/orm/model/ormtable/table_impl.go index 34d75aa74649..b598161b6cf6 100644 --- a/orm/model/ormtable/table_impl.go +++ b/orm/model/ormtable/table_impl.go @@ -95,7 +95,7 @@ func (t tableImpl) doSave(ctx context.Context, writer *batchIndexCommitmentWrite if haveExisting { if mode == saveModeInsert { - return ormerrors.PrimaryKeyConstraintViolation.Wrapf("%q:%+v", mref.Descriptor().FullName(), pkValues) + return ormerrors.AlreadyExists.Wrapf("%q:%+v", mref.Descriptor().FullName(), pkValues) } if validateHooks := writer.ValidateHooks(); validateHooks != nil { @@ -106,7 +106,7 @@ func (t tableImpl) doSave(ctx context.Context, writer *batchIndexCommitmentWrite } } else { if mode == saveModeUpdate { - return ormerrors.NotFoundOnUpdate.Wrapf("%q", mref.Descriptor().FullName()) + return ormerrors.NotFound.Wrapf("%q", mref.Descriptor().FullName()) } if validateHooks := writer.ValidateHooks(); validateHooks != nil { diff --git a/orm/model/ormtable/unique.go b/orm/model/ormtable/unique.go index d61a9150b8cc..63386942ae09 100644 --- a/orm/model/ormtable/unique.go +++ b/orm/model/ormtable/unique.go @@ -118,7 +118,7 @@ func (u uniqueKeyIndex) onInsert(store kv.Store, message protoreflect.Message) e } if has { - return ormerrors.UniqueKeyViolation + return ormerrors.UniqueKeyViolation.Wrapf("%q", u.fields) } return store.Set(k, v) @@ -143,7 +143,7 @@ func (u uniqueKeyIndex) onUpdate(store kv.Store, new, existing protoreflect.Mess } if has { - return ormerrors.UniqueKeyViolation + return ormerrors.UniqueKeyViolation.Wrapf("%q", u.fields) } existingKey, err := keyCodec.EncodeKey(existingValues) diff --git a/orm/types/ormerrors/errors.go b/orm/types/ormerrors/errors.go index fb2d597d3c66..bcb432a7410c 100644 --- a/orm/types/ormerrors/errors.go +++ b/orm/types/ormerrors/errors.go @@ -1,6 +1,9 @@ package ormerrors -import "github.com/cosmos/cosmos-sdk/errors" +import ( + "github.com/cosmos/cosmos-sdk/errors" + "google.golang.org/grpc/codes" +) var codespace = "orm" @@ -19,7 +22,6 @@ var ( InvalidIndexId = errors.New(codespace, 7, "invalid or missing index id, need a value >= 0 and < 32768") DuplicateIndexId = errors.New(codespace, 8, "duplicate index id") PrimaryKeyConstraintViolation = errors.New(codespace, 9, "object with primary key already exists") - 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") CantFindIndex = errors.New(codespace, 13, "can't find index") @@ -33,11 +35,13 @@ var ( UnexpectedError = errors.New(codespace, 21, "unexpected error") InvalidRangeIterationKeys = errors.New(codespace, 22, "invalid range iteration keys") JSONImportError = errors.New(codespace, 23, "json import error") - UniqueKeyViolation = errors.New(codespace, 24, "unique key violation") + UniqueKeyViolation = errors.RegisterWithGRPCCode(codespace, 24, codes.FailedPrecondition, "unique key violation") InvalidTableDefinition = errors.New(codespace, 25, "invalid table definition") InvalidFileDescriptorID = errors.New(codespace, 26, "invalid file descriptor ID") TableNotFound = errors.New(codespace, 27, "table not found") JSONValidationError = errors.New(codespace, 28, "invalid JSON") - NotFound = errors.New(codespace, 29, "not found") + NotFound = errors.RegisterWithGRPCCode(codespace, 29, codes.NotFound, "not found") ReadOnly = errors.New(codespace, 30, "database is read-only") + AlreadyExists = errors.RegisterWithGRPCCode(codespace, 31, codes.AlreadyExists, "already exists") + ConstraintViolation = errors.RegisterWithGRPCCode(codespace, 32, codes.FailedPrecondition, "failed precondition") ) From 77d58b78aae4ab93320495a192192750dc42841c Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 15 Mar 2022 18:56:22 -0400 Subject: [PATCH 2/6] simplify --- orm/model/ormtable/save_test.go | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/orm/model/ormtable/save_test.go b/orm/model/ormtable/save_test.go index b79dd53537d1..c8e6ff0268f1 100644 --- a/orm/model/ormtable/save_test.go +++ b/orm/model/ormtable/save_test.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "github.com/cosmos/cosmos-sdk/orm/model/ormtable" - "github.com/cosmos/cosmos-sdk/orm/types/ormerrors" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/encoding/protojson" @@ -59,23 +58,7 @@ func (s *suite) IUpdate(a gocuke.DocString) { } func (s *suite) ExpectAError(a string) { - assert.ErrorIs(s, s.err, s.toError(a), s.err.Error()) -} - -func (s *suite) toError(str string) error { - switch str { - case "already exists": - return ormerrors.AlreadyExists - case "not found": - return ormerrors.NotFound - case "constraint violation": - return ormerrors.ConstraintViolation - case "unique key violation": - return ormerrors.UniqueKeyViolation - default: - s.Fatalf("missing case for error %s", str) - return nil - } + assert.ErrorContains(s, s.err, a) } func (s *suite) ExpectGrpcErrorCode(a string) { From 95e1845340297dbb52f44474907e07ff35a133a4 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 16 Mar 2022 13:11:52 -0400 Subject: [PATCH 3/6] update go.mod --- orm/go.mod | 4 +--- orm/go.sum | 4 ++-- orm/model/ormtable/auto_increment_test.go | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/orm/go.mod b/orm/go.mod index 0ae24776151a..2930d41da72b 100644 --- a/orm/go.mod +++ b/orm/go.mod @@ -5,7 +5,7 @@ go 1.17 require ( github.com/cosmos/cosmos-proto v1.0.0-alpha7 github.com/cosmos/cosmos-sdk/api v0.1.0-alpha5 - github.com/cosmos/cosmos-sdk/errors v1.0.0-beta.3 + github.com/cosmos/cosmos-sdk/errors v1.0.0-beta.4 github.com/golang/mock v1.6.0 github.com/google/go-cmp v0.5.7 github.com/iancoleman/strcase v0.2.0 @@ -49,5 +49,3 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect ) - -replace github.com/cosmos/cosmos-sdk/errors => ../errors \ No newline at end of file diff --git a/orm/go.sum b/orm/go.sum index 06f4fa8a794c..68f77c74561d 100644 --- a/orm/go.sum +++ b/orm/go.sum @@ -33,8 +33,8 @@ github.com/cosmos/cosmos-proto v1.0.0-alpha7 h1:yqYUOHF2jopwZh4dVQp3xgqwftE5/2hk github.com/cosmos/cosmos-proto v1.0.0-alpha7/go.mod h1:dosO4pSAbJF8zWCzCoTWP7nNsjcvSUBQmniFxDg5daw= github.com/cosmos/cosmos-sdk/api v0.1.0-alpha5 h1:UlK7NOHGlEbvbDTCM0cN7BJN6hhqeXZIuLv6KapFYTc= github.com/cosmos/cosmos-sdk/api v0.1.0-alpha5/go.mod h1:gZu6sOu2vl4Fd7I+BjDSx2bxndwPgFLGfOegek3SQQo= -github.com/cosmos/cosmos-sdk/errors v1.0.0-beta.3 h1:Ep7FHNViVwwGnwLFEPewZYsyN2CJNVMmMvFmtNQtbnw= -github.com/cosmos/cosmos-sdk/errors v1.0.0-beta.3/go.mod h1:HFea93YKmoMJ/mNKtkSeJZDtyJ4inxBsUK928KONcqo= +github.com/cosmos/cosmos-sdk/errors v1.0.0-beta.4 h1:Kjv3QD2Y3C7TvxDh1+Yg9cXefwFbTOUypUtB1tMJRco= +github.com/cosmos/cosmos-sdk/errors v1.0.0-beta.4/go.mod h1:HFea93YKmoMJ/mNKtkSeJZDtyJ4inxBsUK928KONcqo= github.com/cosmos/gorocksdb v1.2.0 h1:d0l3jJG8M4hBouIZq0mDUHZ+zjOx044J3nGRskwTb4Y= github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= diff --git a/orm/model/ormtable/auto_increment_test.go b/orm/model/ormtable/auto_increment_test.go index c18280892b2f..4f1556f4f1a3 100644 --- a/orm/model/ormtable/auto_increment_test.go +++ b/orm/model/ormtable/auto_increment_test.go @@ -47,7 +47,7 @@ func runAutoIncrementScenario(t *testing.T, table ormtable.AutoIncrementTable, c assert.NilError(t, err) err = store.Save(ctx, &testpb.ExampleAutoIncrementTable{Id: 5}) - assert.ErrorContains(t, err, "update") + assert.ErrorContains(t, err, "not found") ex1 := &testpb.ExampleAutoIncrementTable{X: "foo", Y: 5} assert.NilError(t, store.Save(ctx, ex1)) From 87ba6d7366cea317bd696da48eb512d1a88823b4 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 16 Mar 2022 13:12:48 -0400 Subject: [PATCH 4/6] revert --- codec/legacy/amino_msg_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/codec/legacy/amino_msg_test.go b/codec/legacy/amino_msg_test.go index ac13f5a1b8c9..c38317020e76 100644 --- a/codec/legacy/amino_msg_test.go +++ b/codec/legacy/amino_msg_test.go @@ -4,11 +4,10 @@ import ( "strings" "testing" - "github.com/stretchr/testify/require" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/legacy" "github.com/cosmos/cosmos-sdk/testutil/testdata" + "github.com/stretchr/testify/require" ) func TestRegisterAminoMsg(t *testing.T) { From d8ef8b87eeb9d59b224bb1809177a1d92de39776 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 16 Mar 2022 13:20:47 -0400 Subject: [PATCH 5/6] docs --- orm/model/ormtable/table.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/orm/model/ormtable/table.go b/orm/model/ormtable/table.go index 4c9910d6445b..7594fcadbbf6 100644 --- a/orm/model/ormtable/table.go +++ b/orm/model/ormtable/table.go @@ -66,15 +66,24 @@ type Table interface { // Save 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. + // + // If a unique key constraint is violated, ormerrors.UniqueKeyViolation + // (or an error wrapping it) will be returned. Save(context context.Context, message proto.Message) error // Insert inserts the provided entry in the store and fails if there is // an unique key violation. See Save for more details on behavior. + // + // If an entity with the same primary key exists, an error wrapping + // ormerrors.AlreadyExists will be returned. 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. + // + // If an entity with the same primary key does not exist, ormerrors.NotFound + // (or an error wrapping it) will be returned. Update(ctx context.Context, message proto.Message) error // Delete deletes the entry with the with primary key fields set on message From 4ea80b30a56437261aa85fdc9ad8f2438f8c6bc4 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 16 Mar 2022 16:05:30 -0400 Subject: [PATCH 6/6] update feature name --- orm/features/table/{save.feature => saving.feature} | 2 +- orm/model/ormtable/save_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename orm/features/table/{save.feature => saving.feature} (96%) diff --git a/orm/features/table/save.feature b/orm/features/table/saving.feature similarity index 96% rename from orm/features/table/save.feature rename to orm/features/table/saving.feature index 931c953f8cbb..59c6151971b9 100644 --- a/orm/features/table/save.feature +++ b/orm/features/table/saving.feature @@ -1,4 +1,4 @@ -Feature: saving entities +Feature: inserting, updating and saving entities Scenario: can't insert an entity with a duplicate primary key Given an existing entity diff --git a/orm/model/ormtable/save_test.go b/orm/model/ormtable/save_test.go index c8e6ff0268f1..dc3a24edd0ca 100644 --- a/orm/model/ormtable/save_test.go +++ b/orm/model/ormtable/save_test.go @@ -17,7 +17,7 @@ import ( ) func TestSave(t *testing.T) { - gocuke.NewRunner(t, &suite{}).Path("../../features/table/save.feature").Run() + gocuke.NewRunner(t, &suite{}).Path("../../features/table/saving.feature").Run() } type suite struct {