feat(orm): gRPC codes for save errors (#11386)

## Description

Ref: #11088. First PR of several to add gRPC error codes and make sure that errors are a well-defined part of the API.

Also introduces Cucumber-style BDD acceptance tests into the SDK via https://github.com/regen-network/gocuke.



---

### 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)
This commit is contained in:
Aaron Craelius 2022-03-17 14:57:55 -04:00 committed by GitHub
parent c701e8b66a
commit 872d9247b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 1050 additions and 102 deletions

View File

@ -0,0 +1,49 @@
Feature: inserting, updating and 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"

View File

@ -5,12 +5,14 @@ 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
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,6 @@ 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
)

View File

@ -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=
@ -27,11 +33,16 @@ 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=
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=

View File

@ -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 (

View File

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

View File

@ -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<string, uint32> map = 18;
ExampleMessage msg = 19;
oneof sum {
uint32 oneof = 20;
}
// Invalid key fields:
repeated uint32 repeated = 17;
map<string, uint32> 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;
}

View File

@ -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,
},

View File

@ -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))

View File

@ -0,0 +1,68 @@
package ormtable_test
import (
"context"
"fmt"
"github.com/cosmos/cosmos-sdk/orm/model/ormtable"
"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/saving.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.ErrorContains(s, s.err, a)
}
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))
}

View File

@ -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

View File

@ -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 {

View File

@ -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)

View File

@ -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")
)