From 2d7f0b69d726d50db00c431d366c982cc6dbfd66 Mon Sep 17 00:00:00 2001 From: Cool Developer Date: Wed, 30 Oct 2024 12:42:47 -0400 Subject: [PATCH 1/6] indexer postgres --- simapp/app_di.go | 3 +++ simapp/go.mod | 7 +++++++ simapp/go.sum | 8 ++++++++ 3 files changed, 18 insertions(+) diff --git a/simapp/app_di.go b/simapp/app_di.go index 0704cbdc38ca..93ad1d1a19e0 100644 --- a/simapp/app_di.go +++ b/simapp/app_di.go @@ -7,12 +7,15 @@ import ( "fmt" "io" + _ "github.com/jackc/pgx/v5/stdlib" // Import and register pgx driver + clienthelpers "cosmossdk.io/client/v2/helpers" "cosmossdk.io/core/address" "cosmossdk.io/core/appmodule" "cosmossdk.io/core/registry" corestore "cosmossdk.io/core/store" "cosmossdk.io/depinject" + _ "cosmossdk.io/indexer/postgres" // register the postgres indexer "cosmossdk.io/log" "cosmossdk.io/x/accounts" basedepinject "cosmossdk.io/x/accounts/defaults/base/depinject" diff --git a/simapp/go.mod b/simapp/go.mod index 96e451a955e7..2a1b541b2b4f 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -9,6 +9,7 @@ require ( cosmossdk.io/core v1.0.0-alpha.5 cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29 cosmossdk.io/depinject v1.0.0 + cosmossdk.io/indexer/postgres v0.1.0 cosmossdk.io/log v1.4.1 cosmossdk.io/math v1.3.0 cosmossdk.io/store v1.1.1 @@ -49,6 +50,8 @@ require ( google.golang.org/protobuf v1.35.1 ) +require github.com/jackc/pgx/v5 v5.7.1 + require ( buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.35.1-20240701160653-fedbb9acfd2f.1 // indirect buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.35.1-20240130113600-88ef6483f90f.1 // indirect @@ -147,6 +150,9 @@ require ( github.com/huandu/skiplist v1.2.1 // indirect github.com/iancoleman/strcase v0.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/klauspost/compress v1.17.9 // indirect @@ -240,6 +246,7 @@ replace ( cosmossdk.io/api => ../api cosmossdk.io/client/v2 => ../client/v2 cosmossdk.io/collections => ../collections + cosmossdk.io/indexer/postgres => ../indexer/postgres cosmossdk.io/store => ../store cosmossdk.io/tools/confix => ../tools/confix cosmossdk.io/x/accounts => ../x/accounts diff --git a/simapp/go.sum b/simapp/go.sum index 753a95f0dcf5..4054434cb98a 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -600,6 +600,14 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= +github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94= github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= From b6c6da76085a3558907faba4fdc68268b459ba7a Mon Sep 17 00:00:00 2001 From: Cool Developer Date: Thu, 31 Oct 2024 10:01:27 -0400 Subject: [PATCH 2/6] wip --- collections/indexes/reverse_pair.go | 4 ++-- collections/keyset.go | 14 ++++++++++++-- collections/map.go | 27 ++++++++++++++++++++++----- x/bank/keeper/view.go | 7 ------- x/bank/module.go | 8 ++++++++ 5 files changed, 44 insertions(+), 16 deletions(-) diff --git a/collections/indexes/reverse_pair.go b/collections/indexes/reverse_pair.go index 0e2cc301374e..0f8446a45886 100644 --- a/collections/indexes/reverse_pair.go +++ b/collections/indexes/reverse_pair.go @@ -55,12 +55,12 @@ func NewReversePair[Value, K1, K2 any]( } if o.uncheckedValue { return &ReversePair[K1, K2, Value]{ - refKeys: collections.NewKeySet(sb, prefix, name, collections.PairKeyCodec(pkc.KeyCodec2(), pkc.KeyCodec1()), collections.WithKeySetUncheckedValue()), + refKeys: collections.NewKeySet(sb, prefix, name, collections.PairKeyCodec(pkc.KeyCodec2(), pkc.KeyCodec1()), collections.WithKeySetUncheckedValue(), collections.WithKeySetSecondaryIndex()), } } mi := &ReversePair[K1, K2, Value]{ - refKeys: collections.NewKeySet(sb, prefix, name, collections.PairKeyCodec(pkc.KeyCodec2(), pkc.KeyCodec1())), + refKeys: collections.NewKeySet(sb, prefix, name, collections.PairKeyCodec(pkc.KeyCodec2(), pkc.KeyCodec1()), collections.WithKeySetSecondaryIndex()), } return mi diff --git a/collections/keyset.go b/collections/keyset.go index 37c3bd268e37..07e035f750f5 100644 --- a/collections/keyset.go +++ b/collections/keyset.go @@ -21,7 +21,17 @@ func WithKeySetUncheckedValue() func(opt *keySetOptions) { } } -type keySetOptions struct{ uncheckedValue bool } +// WithKeySetSecondaryIndex changes the behavior of the KeySet to be a secondary index. +func WithKeySetSecondaryIndex() func(opt *keySetOptions) { + return func(opt *keySetOptions) { + opt.isSecondaryIndex = true + } +} + +type keySetOptions struct { + uncheckedValue bool + isSecondaryIndex bool +} // KeySet builds on top of a Map and represents a collection retaining only a set // of keys and no value. It can be used, for example, in an allow list. @@ -44,7 +54,7 @@ func NewKeySet[K any]( if o.uncheckedValue { vc = codec.NewAltValueCodec(vc, func(_ []byte) (NoValue, error) { return NoValue{}, nil }) } - return (KeySet[K])(NewMap(schema, prefix, name, keyCodec, vc)) + return (KeySet[K])(NewMap(schema, prefix, name, keyCodec, vc, WithMapSecondaryIndex(o.isSecondaryIndex))) } // Set adds the key to the KeySet. Errors on encoding problems. diff --git a/collections/map.go b/collections/map.go index 360d96feafa3..78001dadd920 100644 --- a/collections/map.go +++ b/collections/map.go @@ -27,6 +27,17 @@ type Map[K, V any] struct { isSecondaryIndex bool } +// WithMapSecondaryIndex changes the behavior of the Map to be a secondary index. +func WithMapSecondaryIndex(isSecondaryIndex bool) func(opt *mapOptions) { + return func(opt *mapOptions) { + opt.isSecondaryIndex = isSecondaryIndex + } +} + +type mapOptions struct { + isSecondaryIndex bool +} + // NewMap returns a Map given a StoreKey, a Prefix, human-readable name and the relative value and key encoders. // Name and prefix must be unique within the schema and name must match the format specified by NameRegex, or // else this method will panic. @@ -36,13 +47,19 @@ func NewMap[K, V any]( name string, keyCodec codec.KeyCodec[K], valueCodec codec.ValueCodec[V], + options ...func(opt *mapOptions), ) Map[K, V] { + o := new(mapOptions) + for _, opt := range options { + opt(o) + } m := Map[K, V]{ - kc: keyCodec, - vc: valueCodec, - sa: schemaBuilder.schema.storeAccessor, - prefix: prefix.Bytes(), - name: name, + kc: keyCodec, + vc: valueCodec, + sa: schemaBuilder.schema.storeAccessor, + prefix: prefix.Bytes(), + name: name, + isSecondaryIndex: o.isSecondaryIndex, } schemaBuilder.addCollection(collectionImpl[K, V]{m}) return m diff --git a/x/bank/keeper/view.go b/x/bank/keeper/view.go index 08dc56300077..31620246518e 100644 --- a/x/bank/keeper/view.go +++ b/x/bank/keeper/view.go @@ -10,7 +10,6 @@ import ( "cosmossdk.io/core/appmodule" errorsmod "cosmossdk.io/errors" "cosmossdk.io/math" - "cosmossdk.io/schema" "cosmossdk.io/x/bank/types" "github.com/cosmos/cosmos-sdk/codec" @@ -257,9 +256,3 @@ func (k BaseViewKeeper) ValidateBalance(ctx context.Context, addr sdk.AccAddress return nil } - -// ModuleCodec implements `schema.HasModuleCodec` interface. -// It allows the indexer to decode the module's KVPairUpdate. -func (k BaseViewKeeper) ModuleCodec() (schema.ModuleCodec, error) { - return k.Schema.ModuleCodec(collections.IndexingOptions{}) -} diff --git a/x/bank/module.go b/x/bank/module.go index 49aa2981b918..f387903c5886 100644 --- a/x/bank/module.go +++ b/x/bank/module.go @@ -9,8 +9,10 @@ import ( "github.com/spf13/cobra" "google.golang.org/grpc" + "cosmossdk.io/collections" "cosmossdk.io/core/appmodule" "cosmossdk.io/core/registry" + "cosmossdk.io/schema" "cosmossdk.io/x/bank/client/cli" "cosmossdk.io/x/bank/keeper" "cosmossdk.io/x/bank/simulation" @@ -175,3 +177,9 @@ func (am AppModule) WeightedOperationsX(weights simsx.WeightSource, reg simsx.Re reg.Add(weights.Get("msg_send", 100), simulation.MsgSendFactory()) reg.Add(weights.Get("msg_multisend", 10), simulation.MsgMultiSendFactory()) } + +// ModuleCodec implements `schema.HasModuleCodec` interface. +// It allows the indexer to decode the module's KVPairUpdate. +func (am AppModule) ModuleCodec() (schema.ModuleCodec, error) { + return am.keeper.(keeper.BaseKeeper).Schema.ModuleCodec(collections.IndexingOptions{}) +} From b1ccaf9b8333b2031f30284e5471cd4a56a8cafc Mon Sep 17 00:00:00 2001 From: Cool Developer Date: Mon, 4 Nov 2024 08:44:42 -0500 Subject: [PATCH 3/6] postgres indexer fix --- collections/codec/indexing.go | 12 ++++++------ collections/indexing.go | 3 +++ collections/pair.go | 5 +++++ indexer/postgres/params.go | 8 ++++++++ 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/collections/codec/indexing.go b/collections/codec/indexing.go index 26ff651cc8e0..b0db41e6ef00 100644 --- a/collections/codec/indexing.go +++ b/collections/codec/indexing.go @@ -81,20 +81,20 @@ func FallbackSchemaCodec[T any]() SchemaCodec[T] { FromSchemaType: nil, } } else { - // we default to encoding everything to JSON + // we default to encoding everything to String return SchemaCodec[T]{ - Fields: []schema.Field{{Kind: schema.JSONKind}}, + Fields: []schema.Field{{Kind: schema.StringKind}}, ToSchemaType: func(t T) (any, error) { bz, err := json.Marshal(t) - return json.RawMessage(bz), err + return string(json.RawMessage(bz)), err }, FromSchemaType: func(a any) (T, error) { var t T - bz, ok := a.(json.RawMessage) + sz, ok := a.(string) if !ok { - return t, fmt.Errorf("expected json.RawMessage, got %T", a) + return t, fmt.Errorf("expected string, got %T", a) } - err := json.Unmarshal(bz, &t) + err := json.Unmarshal([]byte(sz), &t) return t, err }, } diff --git a/collections/indexing.go b/collections/indexing.go index 5939aed5fea3..bb039e7be256 100644 --- a/collections/indexing.go +++ b/collections/indexing.go @@ -133,6 +133,9 @@ func (c collectionImpl[K, V]) schemaCodec() (*collectionSchemaCodec, error) { if err != nil { return nil, err } + if keyDecoder.ToSchemaType == nil { + return x, nil + } return keyDecoder.ToSchemaType(x) } ensureFieldNames(c.m.kc, "key", res.objectType.KeyFields) diff --git a/collections/pair.go b/collections/pair.go index 97b678a8c154..7bc30a1c1c46 100644 --- a/collections/pair.go +++ b/collections/pair.go @@ -33,6 +33,11 @@ func (p Pair[K1, K2]) K2() (k2 K2) { return *p.key2 } +// Keys returns key1 and key2 as a slice. +func (p Pair[K1, K2]) Keys() []interface{} { + return []interface{}{p.K1(), p.K2()} +} + // Join creates a new Pair instance composed of the two provided keys, in order. func Join[K1, K2 any](key1 K1, key2 K2) Pair[K1, K2] { return Pair[K1, K2]{ diff --git a/indexer/postgres/params.go b/indexer/postgres/params.go index ea7a1d486ea8..ca595f05cf15 100644 --- a/indexer/postgres/params.go +++ b/indexer/postgres/params.go @@ -8,6 +8,11 @@ import ( "cosmossdk.io/schema" ) +type keyCollection interface { + // Keys returns the key fields for the collection. + Keys() []interface{} +} + // bindKeyParams binds the key to the key columns. func (tm *objectIndexer) bindKeyParams(key interface{}) ([]interface{}, []string, error) { n := len(tm.typ.KeyFields) @@ -17,6 +22,9 @@ func (tm *objectIndexer) bindKeyParams(key interface{}) ([]interface{}, []string } else if n == 1 { return tm.bindParams(tm.typ.KeyFields, []interface{}{key}) } else { + if kc, ok := key.(keyCollection); ok { + return tm.bindParams(tm.typ.KeyFields, kc.Keys()) + } key, ok := key.([]interface{}) if !ok { return nil, nil, errors.New("expected key to be a slice") From 7b1669c21cc6890c9d09147d5175be245c5007c8 Mon Sep 17 00:00:00 2001 From: Cool Developer Date: Mon, 4 Nov 2024 13:36:19 -0500 Subject: [PATCH 4/6] deal with overrided store keys --- runtime/builder.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/runtime/builder.go b/runtime/builder.go index 37be02fa769e..f3de4da2dcbf 100644 --- a/runtime/builder.go +++ b/runtime/builder.go @@ -99,7 +99,14 @@ func (a *AppBuilder) registerIndexer() error { if indexerOpts := a.appOptions.Get("indexer"); indexerOpts != nil { moduleSet := map[string]any{} for modName, mod := range a.app.ModuleManager.Modules { - moduleSet[modName] = mod + storeKey := modName + for _, cfg := range a.app.config.OverrideStoreKeys { + if cfg.ModuleName == modName { + storeKey = cfg.KvStoreKey + break + } + } + moduleSet[storeKey] = mod } return a.app.EnableIndexer(indexerOpts, a.kvStoreKeys(), moduleSet) From 3a92a77e9b9852995505b549d23edee0fda15646 Mon Sep 17 00:00:00 2001 From: Cool Developer Date: Tue, 5 Nov 2024 07:57:06 -0500 Subject: [PATCH 5/6] go mod tidy --- collections/codec/indexing.go | 2 +- collections/keyset.go | 2 +- collections/map.go | 4 ++-- collections/quad.go | 5 +++++ collections/triple.go | 5 +++++ simapp/go.sum | 1 + tests/go.mod | 6 ++++++ tests/go.sum | 9 +++++++++ 8 files changed, 30 insertions(+), 4 deletions(-) diff --git a/collections/codec/indexing.go b/collections/codec/indexing.go index b0db41e6ef00..0731ff073047 100644 --- a/collections/codec/indexing.go +++ b/collections/codec/indexing.go @@ -65,7 +65,7 @@ func ValueSchemaCodec[V any](cdc ValueCodec[V]) (SchemaCodec[V], error) { // FallbackSchemaCodec returns a fallback schema codec for T when one isn't explicitly // specified with HasSchemaCodec. It maps all simple types directly to schema kinds -// and converts everything else to JSON. +// and converts everything else to String. func FallbackSchemaCodec[T any]() SchemaCodec[T] { var t T kind := schema.KindForGoValue(t) diff --git a/collections/keyset.go b/collections/keyset.go index 07e035f750f5..ee8e5ba011bc 100644 --- a/collections/keyset.go +++ b/collections/keyset.go @@ -54,7 +54,7 @@ func NewKeySet[K any]( if o.uncheckedValue { vc = codec.NewAltValueCodec(vc, func(_ []byte) (NoValue, error) { return NoValue{}, nil }) } - return (KeySet[K])(NewMap(schema, prefix, name, keyCodec, vc, WithMapSecondaryIndex(o.isSecondaryIndex))) + return (KeySet[K])(NewMap(schema, prefix, name, keyCodec, vc, withMapSecondaryIndex(o.isSecondaryIndex))) } // Set adds the key to the KeySet. Errors on encoding problems. diff --git a/collections/map.go b/collections/map.go index 78001dadd920..3fda806df380 100644 --- a/collections/map.go +++ b/collections/map.go @@ -27,8 +27,8 @@ type Map[K, V any] struct { isSecondaryIndex bool } -// WithMapSecondaryIndex changes the behavior of the Map to be a secondary index. -func WithMapSecondaryIndex(isSecondaryIndex bool) func(opt *mapOptions) { +// withMapSecondaryIndex changes the behavior of the Map to be a secondary index. +func withMapSecondaryIndex(isSecondaryIndex bool) func(opt *mapOptions) { return func(opt *mapOptions) { opt.isSecondaryIndex = isSecondaryIndex } diff --git a/collections/quad.go b/collections/quad.go index cf17cc32eaba..e482b7af6ce7 100644 --- a/collections/quad.go +++ b/collections/quad.go @@ -54,6 +54,11 @@ func (t Quad[K1, K2, K3, K4]) K4() (x K4) { return x } +// Keys returns key1, key2, key3 and key4 as a slice. +func (t Quad[K1, K2, K3, K4]) Keys() []interface{} { + return []interface{}{t.K1(), t.K2(), t.K3(), t.K4()} +} + // QuadPrefix creates a new Quad instance composed only of the first part of the key. func QuadPrefix[K1, K2, K3, K4 any](k1 K1) Quad[K1, K2, K3, K4] { return Quad[K1, K2, K3, K4]{k1: &k1} diff --git a/collections/triple.go b/collections/triple.go index 17f519d54d6d..e0b0bdc1269a 100644 --- a/collections/triple.go +++ b/collections/triple.go @@ -45,6 +45,11 @@ func (t Triple[K1, K2, K3]) K3() (x K3) { return x } +// Keys returns key1, key2 and key3 as a slice. +func (t Triple[K1, K2, K3]) Keys() []interface{} { + return []interface{}{t.K1(), t.K2(), t.K3()} +} + // TriplePrefix creates a new Triple instance composed only of the first part of the key. func TriplePrefix[K1, K2, K3 any](k1 K1) Triple[K1, K2, K3] { return Triple[K1, K2, K3]{k1: &k1} diff --git a/simapp/go.sum b/simapp/go.sum index 4054434cb98a..c24356e4e46b 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -204,6 +204,7 @@ cosmossdk.io/log v1.4.1 h1:wKdjfDRbDyZRuWa8M+9nuvpVYxrEOwbD/CA8hvhU8QM= cosmossdk.io/log v1.4.1/go.mod h1:k08v0Pyq+gCP6phvdI6RCGhLf/r425UT6Rk/m+o74rU= cosmossdk.io/math v1.3.0 h1:RC+jryuKeytIiictDslBP9i1fhkVm6ZDmZEoNP316zE= cosmossdk.io/math v1.3.0/go.mod h1:vnRTxewy+M7BtXBNFybkuhSH4WfedVAAnERHgVFhp3k= +cosmossdk.io/schema v0.3.0/go.mod h1:RDAhxIeNB4bYqAlF4NBJwRrgtnciMcyyg0DOKnhNZQQ= cosmossdk.io/schema v0.3.1-0.20241010135032-192601639cac h1:3joNZZWZ3k7fMsrBDL1ktuQ2xQwYLZOaDhkruadDFmc= cosmossdk.io/schema v0.3.1-0.20241010135032-192601639cac/go.mod h1:RDAhxIeNB4bYqAlF4NBJwRrgtnciMcyyg0DOKnhNZQQ= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= diff --git a/tests/go.mod b/tests/go.mod index a98402d39de5..2846cc0748ba 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -65,6 +65,7 @@ require ( cloud.google.com/go/storage v1.43.0 // indirect cosmossdk.io/client/v2 v2.0.0-20230630094428-02b760776860 // indirect cosmossdk.io/errors v1.0.1 // indirect + cosmossdk.io/indexer/postgres v0.1.0 // indirect cosmossdk.io/schema v0.3.1-0.20241010135032-192601639cac // indirect cosmossdk.io/x/circuit v0.0.0-20230613133644-0a778132a60f // indirect cosmossdk.io/x/epochs v0.0.0-20240522060652-a1ae4c3e0337 // indirect @@ -151,6 +152,10 @@ require ( github.com/huandu/skiplist v1.2.1 // indirect github.com/iancoleman/strcase v0.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.7.1 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/klauspost/compress v1.17.9 // indirect @@ -237,6 +242,7 @@ replace ( cosmossdk.io/api => ../api cosmossdk.io/client/v2 => ../client/v2 cosmossdk.io/collections => ../collections + cosmossdk.io/indexer/postgres => ../indexer/postgres cosmossdk.io/store => ../store cosmossdk.io/x/accounts => ../x/accounts cosmossdk.io/x/accounts/defaults/base => ../x/accounts/defaults/base diff --git a/tests/go.sum b/tests/go.sum index 6e624911ccd2..74107b1d8d49 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -204,6 +204,7 @@ cosmossdk.io/log v1.4.1 h1:wKdjfDRbDyZRuWa8M+9nuvpVYxrEOwbD/CA8hvhU8QM= cosmossdk.io/log v1.4.1/go.mod h1:k08v0Pyq+gCP6phvdI6RCGhLf/r425UT6Rk/m+o74rU= cosmossdk.io/math v1.3.0 h1:RC+jryuKeytIiictDslBP9i1fhkVm6ZDmZEoNP316zE= cosmossdk.io/math v1.3.0/go.mod h1:vnRTxewy+M7BtXBNFybkuhSH4WfedVAAnERHgVFhp3k= +cosmossdk.io/schema v0.3.0/go.mod h1:RDAhxIeNB4bYqAlF4NBJwRrgtnciMcyyg0DOKnhNZQQ= cosmossdk.io/schema v0.3.1-0.20241010135032-192601639cac h1:3joNZZWZ3k7fMsrBDL1ktuQ2xQwYLZOaDhkruadDFmc= cosmossdk.io/schema v0.3.1-0.20241010135032-192601639cac/go.mod h1:RDAhxIeNB4bYqAlF4NBJwRrgtnciMcyyg0DOKnhNZQQ= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= @@ -595,6 +596,14 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= +github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94= github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= From 8a911e3e9a13a4d6c270c34ae36f618c962501f3 Mon Sep 17 00:00:00 2001 From: Cool Developer Date: Tue, 5 Nov 2024 13:50:15 -0500 Subject: [PATCH 6/6] fix pair codec --- collections/codec/indexing.go | 4 ++-- collections/indexes/multi.go | 17 +++++++++++++++-- collections/indexes/reverse_pair.go | 17 +++++++++++++++-- collections/pair.go | 15 ++++++++++----- collections/quad.go | 15 ++++++++++----- collections/triple.go | 15 ++++++++++----- indexer/postgres/params.go | 8 -------- 7 files changed, 62 insertions(+), 29 deletions(-) diff --git a/collections/codec/indexing.go b/collections/codec/indexing.go index 0731ff073047..01f3740bd588 100644 --- a/collections/codec/indexing.go +++ b/collections/codec/indexing.go @@ -65,7 +65,7 @@ func ValueSchemaCodec[V any](cdc ValueCodec[V]) (SchemaCodec[V], error) { // FallbackSchemaCodec returns a fallback schema codec for T when one isn't explicitly // specified with HasSchemaCodec. It maps all simple types directly to schema kinds -// and converts everything else to String. +// and converts everything else to JSON String. func FallbackSchemaCodec[T any]() SchemaCodec[T] { var t T kind := schema.KindForGoValue(t) @@ -81,7 +81,7 @@ func FallbackSchemaCodec[T any]() SchemaCodec[T] { FromSchemaType: nil, } } else { - // we default to encoding everything to String + // we default to encoding everything to JSON String return SchemaCodec[T]{ Fields: []schema.Field{{Kind: schema.StringKind}}, ToSchemaType: func(t T) (any, error) { diff --git a/collections/indexes/multi.go b/collections/indexes/multi.go index 49ad2fb6f378..3554346906cb 100644 --- a/collections/indexes/multi.go +++ b/collections/indexes/multi.go @@ -51,13 +51,26 @@ func NewMulti[ReferenceKey, PrimaryKey, Value any]( if o.uncheckedValue { return &Multi[ReferenceKey, PrimaryKey, Value]{ getRefKey: getRefKeyFunc, - refKeys: collections.NewKeySet(schema, prefix, name, collections.PairKeyCodec(refCodec, pkCodec), collections.WithKeySetUncheckedValue()), + refKeys: collections.NewKeySet( + schema, + prefix, + name, + collections.PairKeyCodec(refCodec, pkCodec), + collections.WithKeySetUncheckedValue(), + collections.WithKeySetSecondaryIndex(), + ), } } return &Multi[ReferenceKey, PrimaryKey, Value]{ getRefKey: getRefKeyFunc, - refKeys: collections.NewKeySet(schema, prefix, name, collections.PairKeyCodec(refCodec, pkCodec)), + refKeys: collections.NewKeySet( + schema, + prefix, + name, + collections.PairKeyCodec(refCodec, pkCodec), + collections.WithKeySetSecondaryIndex(), + ), } } diff --git a/collections/indexes/reverse_pair.go b/collections/indexes/reverse_pair.go index 0f8446a45886..4b85b62c6c97 100644 --- a/collections/indexes/reverse_pair.go +++ b/collections/indexes/reverse_pair.go @@ -55,12 +55,25 @@ func NewReversePair[Value, K1, K2 any]( } if o.uncheckedValue { return &ReversePair[K1, K2, Value]{ - refKeys: collections.NewKeySet(sb, prefix, name, collections.PairKeyCodec(pkc.KeyCodec2(), pkc.KeyCodec1()), collections.WithKeySetUncheckedValue(), collections.WithKeySetSecondaryIndex()), + refKeys: collections.NewKeySet( + sb, + prefix, + name, + collections.PairKeyCodec(pkc.KeyCodec2(), pkc.KeyCodec1()), + collections.WithKeySetUncheckedValue(), + collections.WithKeySetSecondaryIndex(), + ), } } mi := &ReversePair[K1, K2, Value]{ - refKeys: collections.NewKeySet(sb, prefix, name, collections.PairKeyCodec(pkc.KeyCodec2(), pkc.KeyCodec1()), collections.WithKeySetSecondaryIndex()), + refKeys: collections.NewKeySet( + sb, + prefix, + name, + collections.PairKeyCodec(pkc.KeyCodec2(), pkc.KeyCodec1()), + collections.WithKeySetSecondaryIndex(), + ), } return mi diff --git a/collections/pair.go b/collections/pair.go index 7bc30a1c1c46..955cfe3d22b7 100644 --- a/collections/pair.go +++ b/collections/pair.go @@ -33,11 +33,6 @@ func (p Pair[K1, K2]) K2() (k2 K2) { return *p.key2 } -// Keys returns key1 and key2 as a slice. -func (p Pair[K1, K2]) Keys() []interface{} { - return []interface{}{p.K1(), p.K2()} -} - // Join creates a new Pair instance composed of the two provided keys, in order. func Join[K1, K2 any](key1 K1, key2 K2) Pair[K1, K2] { return Pair[K1, K2]{ @@ -252,6 +247,16 @@ func (p pairKeyCodec[K1, K2]) SchemaCodec() (codec.SchemaCodec[Pair[K1, K2]], er return codec.SchemaCodec[Pair[K1, K2]]{ Fields: []schema.Field{field1, field2}, + ToSchemaType: func(pair Pair[K1, K2]) (any, error) { + return []interface{}{pair.K1(), pair.K2()}, nil + }, + FromSchemaType: func(a any) (Pair[K1, K2], error) { + aSlice, ok := a.([]interface{}) + if !ok || len(aSlice) != 2 { + return Pair[K1, K2]{}, fmt.Errorf("expected slice of length 2, got %T", a) + } + return Join(aSlice[0].(K1), aSlice[1].(K2)), nil + }, }, nil } diff --git a/collections/quad.go b/collections/quad.go index e482b7af6ce7..48b98a526538 100644 --- a/collections/quad.go +++ b/collections/quad.go @@ -54,11 +54,6 @@ func (t Quad[K1, K2, K3, K4]) K4() (x K4) { return x } -// Keys returns key1, key2, key3 and key4 as a slice. -func (t Quad[K1, K2, K3, K4]) Keys() []interface{} { - return []interface{}{t.K1(), t.K2(), t.K3(), t.K4()} -} - // QuadPrefix creates a new Quad instance composed only of the first part of the key. func QuadPrefix[K1, K2, K3, K4 any](k1 K1) Quad[K1, K2, K3, K4] { return Quad[K1, K2, K3, K4]{k1: &k1} @@ -387,6 +382,16 @@ func (t quadKeyCodec[K1, K2, K3, K4]) SchemaCodec() (codec.SchemaCodec[Quad[K1, return codec.SchemaCodec[Quad[K1, K2, K3, K4]]{ Fields: []schema.Field{field1, field2, field3, field4}, + ToSchemaType: func(q Quad[K1, K2, K3, K4]) (any, error) { + return []interface{}{q.K1(), q.K2(), q.K3(), q.K4()}, nil + }, + FromSchemaType: func(a any) (Quad[K1, K2, K3, K4], error) { + aSlice, ok := a.([]interface{}) + if !ok || len(aSlice) != 4 { + return Quad[K1, K2, K3, K4]{}, fmt.Errorf("expected slice of length 4, got %T", a) + } + return Join4(aSlice[0].(K1), aSlice[1].(K2), aSlice[2].(K3), aSlice[3].(K4)), nil + }, }, nil } diff --git a/collections/triple.go b/collections/triple.go index e0b0bdc1269a..d7dcb36056be 100644 --- a/collections/triple.go +++ b/collections/triple.go @@ -45,11 +45,6 @@ func (t Triple[K1, K2, K3]) K3() (x K3) { return x } -// Keys returns key1, key2 and key3 as a slice. -func (t Triple[K1, K2, K3]) Keys() []interface{} { - return []interface{}{t.K1(), t.K2(), t.K3()} -} - // TriplePrefix creates a new Triple instance composed only of the first part of the key. func TriplePrefix[K1, K2, K3 any](k1 K1) Triple[K1, K2, K3] { return Triple[K1, K2, K3]{k1: &k1} @@ -316,6 +311,16 @@ func (t tripleKeyCodec[K1, K2, K3]) SchemaCodec() (codec.SchemaCodec[Triple[K1, return codec.SchemaCodec[Triple[K1, K2, K3]]{ Fields: []schema.Field{field1, field2, field3}, + ToSchemaType: func(t Triple[K1, K2, K3]) (any, error) { + return []interface{}{t.K1(), t.K2(), t.K3()}, nil + }, + FromSchemaType: func(a any) (Triple[K1, K2, K3], error) { + aSlice, ok := a.([]interface{}) + if !ok || len(aSlice) != 3 { + return Triple[K1, K2, K3]{}, fmt.Errorf("expected slice of length 3, got %T", a) + } + return Join3(aSlice[0].(K1), aSlice[1].(K2), aSlice[2].(K3)), nil + }, }, nil } diff --git a/indexer/postgres/params.go b/indexer/postgres/params.go index ca595f05cf15..ea7a1d486ea8 100644 --- a/indexer/postgres/params.go +++ b/indexer/postgres/params.go @@ -8,11 +8,6 @@ import ( "cosmossdk.io/schema" ) -type keyCollection interface { - // Keys returns the key fields for the collection. - Keys() []interface{} -} - // bindKeyParams binds the key to the key columns. func (tm *objectIndexer) bindKeyParams(key interface{}) ([]interface{}, []string, error) { n := len(tm.typ.KeyFields) @@ -22,9 +17,6 @@ func (tm *objectIndexer) bindKeyParams(key interface{}) ([]interface{}, []string } else if n == 1 { return tm.bindParams(tm.typ.KeyFields, []interface{}{key}) } else { - if kc, ok := key.(keyCollection); ok { - return tm.bindParams(tm.typ.KeyFields, kc.Keys()) - } key, ok := key.([]interface{}) if !ok { return nil, nil, errors.New("expected key to be a slice")