diff --git a/changelog.md b/changelog.md index 733312c949..f1e570e6bf 100644 --- a/changelog.md +++ b/changelog.md @@ -4,7 +4,7 @@ ### Features -- [#3707](https://github.com/ignite/cli/pull/3707) Add collections support. +- [#3707](https://github.com/ignite/cli/pull/3707) and [#4094](https://github.com/ignite/cli/pull/4094) Add collections support. - [#3977](https://github.com/ignite/cli/pull/3977) Add `chain lint` command to lint the chain's codebase using `golangci-lint` - [#3770](https://github.com/ignite/cli/pull/3770) Add `scaffold configs` and `scaffold params` commands - [#4001](https://github.com/ignite/cli/pull/4001) Improve `xgenny` dry run @@ -21,6 +21,7 @@ ### Changes +- [#4094](https://github.com/ignite/cli/pull/4094) Scaffolding a multi-index map using `ignite s map foo bar baz --index foobar,foobaz` is no longer supported. Use one index instead of use `collections.IndexedMap`. - [#4058](https://github.com/ignite/cli/pull/4058) Simplify scaffolded modules by including `ValidateBasic()` logic in message handler. - [#4058](https://github.com/ignite/cli/pull/4058) Use `address.Codec` instead of `AccAddressFromBech32`. - [#3993](https://github.com/ignite/cli/pull/3993) Oracle scaffolding was deprecated and has been removed diff --git a/ignite/cmd/scaffold_map.go b/ignite/cmd/scaffold_map.go index 28fb34ebe4..8d5356bc08 100644 --- a/ignite/cmd/scaffold_map.go +++ b/ignite/cmd/scaffold_map.go @@ -6,9 +6,7 @@ import ( "github.com/ignite/cli/v29/ignite/services/scaffolder" ) -const ( - FlagIndexes = "index" -) +const FlagIndexName = "index" // NewScaffoldMap returns a new command to scaffold a map. func NewScaffoldMap() *cobra.Command { @@ -42,14 +40,7 @@ for the "hello" key. blogd q blog show-post hello -To customize the index, use the "--index" flag. Multiple indices can be -provided, which simplifies querying values. For example: - - ignite scaffold map product price desc --index category,guid - -With this command, you would get a "Product" value indexed by both a category -and a GUID (globally unique ID). This will let you programmatically fetch -product values that have the same category but are using different GUIDs. +By default, the index is called "index", to customize the index, use the "--index" flag. Since the behavior of "list" and "map" scaffolding is very similar, you can use the "--no-message", "--module", "--signer" flags as well as the colon syntax for @@ -67,12 +58,12 @@ For detailed type information use ignite scaffold type --help c.Flags().AddFlagSet(flagSetYes()) c.Flags().AddFlagSet(flagSetScaffoldType()) - c.Flags().StringSlice(FlagIndexes, []string{"index"}, "fields that index the value") + c.Flags().String(FlagIndexName, "index", "field that index the value") return c } func scaffoldMapHandler(cmd *cobra.Command, args []string) error { - indexes, _ := cmd.Flags().GetStringSlice(FlagIndexes) - return scaffoldType(cmd, args, scaffolder.MapType(indexes...)) + index, _ := cmd.Flags().GetString(FlagIndexName) + return scaffoldType(cmd, args, scaffolder.MapType(index)) } diff --git a/ignite/config/plugins/config.go b/ignite/config/plugins/config.go index 3a29f28c49..3a2adf0e96 100644 --- a/ignite/config/plugins/config.go +++ b/ignite/config/plugins/config.go @@ -2,9 +2,9 @@ package plugins import ( "os" + "slices" "strings" - "golang.org/x/exp/slices" "gopkg.in/yaml.v3" "github.com/ignite/cli/v29/ignite/pkg/errors" diff --git a/ignite/pkg/xstrings/xstrings.go b/ignite/pkg/xstrings/xstrings.go index 7924443e33..843be0644d 100644 --- a/ignite/pkg/xstrings/xstrings.go +++ b/ignite/pkg/xstrings/xstrings.go @@ -1,10 +1,10 @@ package xstrings import ( + "slices" "strings" "unicode" - "golang.org/x/exp/slices" // TODO: replace with slices.Contains when it will be available in stdlib (1.21) "golang.org/x/text/cases" "golang.org/x/text/language" ) diff --git a/ignite/services/scaffolder/type.go b/ignite/services/scaffolder/type.go index 6f8f50cb33..b649c4607c 100644 --- a/ignite/services/scaffolder/type.go +++ b/ignite/services/scaffolder/type.go @@ -33,7 +33,7 @@ type addTypeOptions struct { isMap bool isSingleton bool - indexes []string + index string withoutMessage bool withoutSimulation bool @@ -55,12 +55,11 @@ func ListType() AddTypeKind { } } -// MapType makes the type stored in a key-value convention in the storage with a custom -// index option. -func MapType(indexes ...string) AddTypeKind { +// MapType makes the type stored in a key-value convention in the storage with an index option. +func MapType(index string) AddTypeKind { return func(o *addTypeOptions) { o.isMap = true - o.indexes = indexes + o.index = index } } @@ -199,7 +198,7 @@ func (s Scaffolder) AddType( case o.isList: g, err = list.NewGenerator(s.Tracer(), opts) case o.isMap: - g, err = mapGenerator(s.Tracer(), opts, o.indexes) + g, err = mapGenerator(s.Tracer(), opts, o.index) case o.isSingleton: g, err = singleton.NewGenerator(s.Tracer(), opts) default: @@ -259,24 +258,31 @@ func parseTypeFields(opts addTypeOptions) (field.Fields, error) { } // mapGenerator returns the template generator for a map. -func mapGenerator(replacer placeholder.Replacer, opts *typed.Options, indexes []string) (*genny.Generator, error) { +func mapGenerator(replacer placeholder.Replacer, opts *typed.Options, index string) (*genny.Generator, error) { // Parse indexes with the associated type - parsedIndexes, err := field.ParseFields(indexes, checkForbiddenTypeIndex) + if strings.Contains(index, ",") { + return nil, errors.Errorf("multi-index map isn't supported") + } + + parsedIndexes, err := field.ParseFields([]string{index}, checkForbiddenTypeIndex) if err != nil { return nil, err } + if len(parsedIndexes) == 0 { + return nil, errors.Errorf("no index found, a valid map index must be provided") + } + // Indexes and type fields must be disjoint exists := make(map[string]struct{}) for _, name := range opts.Fields { exists[name.Name.LowerCamel] = struct{}{} } - for _, index := range parsedIndexes { - if _, ok := exists[index.Name.LowerCamel]; ok { - return nil, errors.Errorf("%s cannot simultaneously be an index and a field", index.Name.Original) - } + + if _, ok := exists[parsedIndexes[0].Name.LowerCamel]; ok { + return nil, errors.Errorf("%s cannot simultaneously be an index and a field", parsedIndexes[0].Name.Original) } - opts.Indexes = parsedIndexes + opts.Index = parsedIndexes[0] return maptype.NewGenerator(replacer, opts) } diff --git a/ignite/services/scaffolder/type_test.go b/ignite/services/scaffolder/type_test.go index 01a824a6f9..3c999a2077 100644 --- a/ignite/services/scaffolder/type_test.go +++ b/ignite/services/scaffolder/type_test.go @@ -82,13 +82,13 @@ func TestParseTypeFields(t *testing.T) { }, { name: "map type without simulation", - addKind: MapType("foo", "bar"), + addKind: MapType("foo"), addOptions: []AddTypeOption{ TypeWithoutSimulation(), }, expectedOptions: addTypeOptions{ moduleName: testModuleName, - indexes: []string{"foo", "bar"}, + index: "foo", isMap: true, withoutSimulation: true, signer: testSigner, diff --git a/ignite/templates/field/plushhelpers/plushhelpers.go b/ignite/templates/field/plushhelpers/plushhelpers.go index ab1be75135..1a9826e5b9 100644 --- a/ignite/templates/field/plushhelpers/plushhelpers.go +++ b/ignite/templates/field/plushhelpers/plushhelpers.go @@ -15,15 +15,20 @@ func ExtendPlushContext(ctx *plush.Context) { ctx.Set("mergeGoImports", mergeGoImports) ctx.Set("mergeProtoImports", mergeProtoImports) ctx.Set("mergeCustomImports", mergeCustomImports) + ctx.Set("appendFieldsAndMergeCustomImports", appendFieldsAndMergeCustomImports) ctx.Set("title", xstrings.Title) ctx.Set("toLower", strings.ToLower) } +func appendFieldsAndMergeCustomImports(f field.Field, fields ...field.Fields) []string { + return mergeCustomImports(append(fields, field.Fields{f})...) +} + func mergeCustomImports(fields ...field.Fields) []string { allImports := make([]string, 0) exist := make(map[string]struct{}) - for _, fields := range fields { - for _, customImport := range fields.Custom() { + for _, field := range fields { + for _, customImport := range field.Custom() { if _, ok := exist[customImport]; ok { continue } diff --git a/ignite/templates/typed/map/files/component/x/{{moduleName}}/keeper/query_{{typeName}}.go.plush b/ignite/templates/typed/map/files/component/x/{{moduleName}}/keeper/query_{{typeName}}.go.plush index 437bf3a53c..996f62b77d 100644 --- a/ignite/templates/typed/map/files/component/x/{{moduleName}}/keeper/query_{{typeName}}.go.plush +++ b/ignite/templates/typed/map/files/component/x/{{moduleName}}/keeper/query_{{typeName}}.go.plush @@ -3,34 +3,26 @@ package keeper import ( "context" - "cosmossdk.io/store/prefix" - "github.com/cosmos/cosmos-sdk/runtime" + "cosmossdk.io/collections" "github.com/cosmos/cosmos-sdk/types/query" "<%= ModulePath %>/x/<%= ModuleName %>/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) -func (s queryServer) List<%= TypeName.UpperCamel %>(ctx context.Context, req *types.QueryAll<%= TypeName.UpperCamel %>Request) (*types.QueryAll<%= TypeName.UpperCamel %>Response, error) { +func (q queryServer) List<%= TypeName.UpperCamel %>(ctx context.Context, req *types.QueryAll<%= TypeName.UpperCamel %>Request) (*types.QueryAll<%= TypeName.UpperCamel %>Response, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } - var <%= TypeName.LowerCamel %>s []types.<%= TypeName.UpperCamel %> - - store := runtime.KVStoreAdapter(s.k.storeService.OpenKVStore(ctx)) - <%= TypeName.LowerCamel %>Store := prefix.NewStore(store, types.KeyPrefix(types.<%= TypeName.UpperCamel %>KeyPrefix)) - - pageRes, err := query.Paginate(<%= TypeName.LowerCamel %>Store, req.Pagination, func(key []byte, value []byte) error { - var <%= TypeName.LowerCamel %> types.<%= TypeName.UpperCamel %> - if err := s.k.cdc.Unmarshal(value, &<%= TypeName.LowerCamel %>); err != nil { - return err - } - - <%= TypeName.LowerCamel %>s = append(<%= TypeName.LowerCamel %>s, <%= TypeName.LowerCamel %>) - return nil - }) - + <%= TypeName.LowerCamel %>s, pageRes, err := query.CollectionPaginate( + ctx, + q.k.<%= TypeName.UpperCamel %>, + req.Pagination, + func(_ <%= Index.DataType() %>, value types.<%= TypeName.UpperCamel %>) (types.<%= TypeName.UpperCamel %>, error){ + return value, nil + }, + ) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } @@ -38,17 +30,18 @@ func (s queryServer) List<%= TypeName.UpperCamel %>(ctx context.Context, req *ty return &types.QueryAll<%= TypeName.UpperCamel %>Response{<%= TypeName.UpperCamel %>: <%= TypeName.LowerCamel %>s, Pagination: pageRes}, nil } -func (s queryServer) Get<%= TypeName.UpperCamel %>(ctx context.Context, req *types.QueryGet<%= TypeName.UpperCamel %>Request) (*types.QueryGet<%= TypeName.UpperCamel %>Response, error) { +func (q queryServer) Get<%= TypeName.UpperCamel %>(ctx context.Context, req *types.QueryGet<%= TypeName.UpperCamel %>Request) (*types.QueryGet<%= TypeName.UpperCamel %>Response, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } - val, found := s.k.Get<%= TypeName.UpperCamel %>( - ctx, - <%= for (i, index) in Indexes { %>req.<%= index.Name.UpperCamel %>, - <% } %>) - if !found { - return nil, status.Error(codes.NotFound, "not found") + val, err := q.k.<%= TypeName.UpperCamel %>.Get(ctx, req.<%= Index.Name.UpperCamel %>) + if err != nil { + if errors.Is(err, collections.ErrNotFound) { + return nil, status.Error(codes.NotFound, "not found") + } + + return nil, status.Error(codes.Internal, "internal error") } return &types.QueryGet<%= TypeName.UpperCamel %>Response{<%= TypeName.UpperCamel %>: val}, nil diff --git a/ignite/templates/typed/map/files/component/x/{{moduleName}}/keeper/{{typeName}}.go.plush b/ignite/templates/typed/map/files/component/x/{{moduleName}}/keeper/{{typeName}}.go.plush deleted file mode 100644 index a0c681ce6a..0000000000 --- a/ignite/templates/typed/map/files/component/x/{{moduleName}}/keeper/{{typeName}}.go.plush +++ /dev/null @@ -1,70 +0,0 @@ -package keeper - -import ( - "context" - - "cosmossdk.io/store/prefix" - storetypes "cosmossdk.io/store/types" - "github.com/cosmos/cosmos-sdk/runtime" - "<%= ModulePath %>/x/<%= ModuleName %>/types" -) - -// Set<%= TypeName.UpperCamel %> set a specific <%= TypeName.LowerCamel %> in the store from its index -func (k Keeper) Set<%= TypeName.UpperCamel %>(ctx context.Context, <%= TypeName.LowerCamel %> types.<%= TypeName.UpperCamel %>) { - storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store := prefix.NewStore(storeAdapter, types.KeyPrefix(types.<%= TypeName.UpperCamel %>KeyPrefix)) - b := k.cdc.MustMarshal(&<%= TypeName.LowerCamel %>) - store.Set(types.<%= TypeName.UpperCamel %>Key( - <%= for (i, index) in Indexes { %><%= TypeName.LowerCamel %>.<%= index.Name.UpperCamel %>, - <% } %>), b) -} - -// Get<%= TypeName.UpperCamel %> returns a <%= TypeName.LowerCamel %> from its index -func (k Keeper) Get<%= TypeName.UpperCamel %>( - ctx context.Context, - <%= for (i, index) in Indexes { %><%= index.Name.LowerCamel %> <%= index.DataType() %>, - <% } %> -) (val types.<%= TypeName.UpperCamel %>, found bool) { - storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store := prefix.NewStore(storeAdapter, types.KeyPrefix(types.<%= TypeName.UpperCamel %>KeyPrefix)) - - b := store.Get(types.<%= TypeName.UpperCamel %>Key( - <%= for (i, index) in Indexes { %><%= index.Name.LowerCamel %>, - <% } %>)) - if b == nil { - return val, false - } - - k.cdc.MustUnmarshal(b, &val) - return val, true -} - -// Remove<%= TypeName.UpperCamel %> removes a <%= TypeName.LowerCamel %> from the store -func (k Keeper) Remove<%= TypeName.UpperCamel %>( - ctx context.Context, - <%= for (i, index) in Indexes { %><%= index.Name.LowerCamel %> <%= index.DataType() %>, - <% } %> -) { - storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store := prefix.NewStore(storeAdapter, types.KeyPrefix(types.<%= TypeName.UpperCamel %>KeyPrefix)) - store.Delete(types.<%= TypeName.UpperCamel %>Key( - <%= for (i, index) in Indexes { %><%= index.Name.LowerCamel %>, - <% } %>)) -} - -// GetAll<%= TypeName.UpperCamel %> returns all <%= TypeName.LowerCamel %> -func (k Keeper) GetAll<%= TypeName.UpperCamel %>(ctx context.Context) (list []types.<%= TypeName.UpperCamel %>) { - storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - store := prefix.NewStore(storeAdapter, types.KeyPrefix(types.<%= TypeName.UpperCamel %>KeyPrefix)) - iterator := storetypes.KVStorePrefixIterator(store, []byte{}) - - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - var val types.<%= TypeName.UpperCamel %> - k.cdc.MustUnmarshal(iterator.Value(), &val) - list = append(list, val) - } - - return -} diff --git a/ignite/templates/typed/map/files/component/x/{{moduleName}}/types/key_{{typeName}}.go.plush b/ignite/templates/typed/map/files/component/x/{{moduleName}}/types/key_{{typeName}}.go.plush index 36e0b5b619..16e1143755 100644 --- a/ignite/templates/typed/map/files/component/x/{{moduleName}}/types/key_{{typeName}}.go.plush +++ b/ignite/templates/typed/map/files/component/x/{{moduleName}}/types/key_{{typeName}}.go.plush @@ -1,23 +1,6 @@ package types -import "encoding/binary" +import "cosmossdk.io/collections" -var _ binary.ByteOrder - -const ( - // <%= TypeName.UpperCamel %>KeyPrefix is the prefix to retrieve all <%= TypeName.UpperCamel %> - <%= TypeName.UpperCamel %>KeyPrefix = "<%= TypeName.UpperCamel %>/value/" -) - -// <%= TypeName.UpperCamel %>Key returns the store key to retrieve a <%= TypeName.UpperCamel %> from the index fields -func <%= TypeName.UpperCamel %>Key( -<%= for (i, index) in Indexes { %><%= index.Name.LowerCamel %> <%= index.DataType() %>, -<% } %>) []byte { - var key []byte - <%= for (i, index) in Indexes { %> - <%= index.ToBytes(index.Name.LowerCamel) %> - key = append(key, <%= index.Name.LowerCamel %>Bytes...) - key = append(key, []byte("/")...) - <% } %> - return key -} \ No newline at end of file +// <%= TypeName.UpperCamel %>Key is the prefix to retrieve all <%= TypeName.UpperCamel %> +var <%= TypeName.UpperCamel %>Key = collections.NewPrefix("<%= TypeName.UpperCamel %>/value/") \ No newline at end of file diff --git a/ignite/templates/typed/map/files/component/{{protoDir}}/{{appName}}/{{moduleName}}/{{typeName}}.proto.plush b/ignite/templates/typed/map/files/component/{{protoDir}}/{{appName}}/{{moduleName}}/{{typeName}}.proto.plush index de089fbbe5..191bf7b201 100644 --- a/ignite/templates/typed/map/files/component/{{protoDir}}/{{appName}}/{{moduleName}}/{{typeName}}.proto.plush +++ b/ignite/templates/typed/map/files/component/{{protoDir}}/{{appName}}/{{moduleName}}/{{typeName}}.proto.plush @@ -1,13 +1,13 @@ syntax = "proto3"; package <%= protoPkgName %>; -option go_package = "<%= ModulePath %>/x/<%= ModuleName %>/types";<%= for (importName) in mergeCustomImports(Fields, Indexes) { %> +option go_package = "<%= ModulePath %>/x/<%= ModuleName %>/types";<%= for (importName) in appendFieldsAndMergeCustomImports(Index, Fields) { %> import "<%= AppName %>/<%= ModuleName %>/<%= importName %>.proto"; <% } %><%= for (importName) in mergeProtoImports(Fields) { %> import "<%= importName %>"; <% } %> -message <%= TypeName.UpperCamel %> {<%= for (i, index) in Indexes { %> - <%= index.ProtoType(i+1) %>; <% } %><%= for (i, field) in Fields { %> - <%= field.ProtoType(i+1+len(Indexes)) %>; <% } %> - <%= if (!NoMessage) { %>string <%= MsgSigner.LowerCamel %> = <%= len(Fields)+len(Indexes)+1 %>;<% } %> +message <%= TypeName.UpperCamel %> { + <%= Index.ProtoType(1) %>; <%= for (i, field) in Fields { %> + <%= field.ProtoType(i+2) %>; <% } %> + <%= if (!NoMessage) { %>string <%= MsgSigner.LowerCamel %> = <%= len(Fields)+2 %>;<% } %> } diff --git a/ignite/templates/typed/map/files/messages/x/{{moduleName}}/keeper/msg_server_{{typeName}}.go.plush b/ignite/templates/typed/map/files/messages/x/{{moduleName}}/keeper/msg_server_{{typeName}}.go.plush index db68eab1f9..e227bd9387 100644 --- a/ignite/templates/typed/map/files/messages/x/{{moduleName}}/keeper/msg_server_{{typeName}}.go.plush +++ b/ignite/templates/typed/map/files/messages/x/{{moduleName}}/keeper/msg_server_{{typeName}}.go.plush @@ -5,8 +5,9 @@ import ( "context" "<%= ModulePath %>/x/<%= ModuleName %>/types" - errorsmod "cosmossdk.io/errors" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "cosmossdk.io/collections" + errorsmod "cosmossdk.io/errors" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -16,26 +17,25 @@ func (k msgServer) Create<%= TypeName.UpperCamel %>(ctx context.Context, msg *t } // Check if the value already exists - _, isFound := k.Get<%= TypeName.UpperCamel %>( - ctx, - <%= for (i, index) in Indexes { %>msg.<%= index.Name.UpperCamel %>, - <% } %>) - if isFound { + ok, err := k.<%= TypeName.UpperCamel %>.Has(ctx, msg.<%= Index.Name.UpperCamel %>) + if err != nil { + return nil, errorsmod.Wrap(sdkerrors.ErrLogic, err.Error()) + } else if ok { return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "index already set") } var <%= TypeName.LowerCamel %> = types.<%= TypeName.UpperCamel %>{ <%= MsgSigner.UpperCamel %>: msg.<%= MsgSigner.UpperCamel %>, - <%= for (i, index) in Indexes { %><%= index.Name.UpperCamel %>: msg.<%= index.Name.UpperCamel %>, - <% } %><%= for (field) in Fields { %><%= field.Name.UpperCamel %>: msg.<%= field.Name.UpperCamel %>, + <%= Index.Name.UpperCamel %>: msg.<%= Index.Name.UpperCamel %>, + <%= for (field) in Fields { %><%= field.Name.UpperCamel %>: msg.<%= field.Name.UpperCamel %>, <% } %> } - k.Set<%= TypeName.UpperCamel %>( - ctx, - <%= TypeName.LowerCamel %>, - ) - return &types.MsgCreate<%= TypeName.UpperCamel %>Response{}, nil + if err := k.<%= TypeName.UpperCamel %>.Set(ctx, <%= TypeName.LowerCamel %>.<%= Index.Name.UpperCamel %>, <%= TypeName.LowerCamel %>); err != nil { + return nil, errorsmod.Wrap(sdkerrors.ErrLogic, err.Error()) + } + + return &types.MsgCreate<%= TypeName.UpperCamel %>Response{}, nil } func (k msgServer) Update<%= TypeName.UpperCamel %>(ctx context.Context, msg *types.MsgUpdate<%= TypeName.UpperCamel %>) (*types.MsgUpdate<%= TypeName.UpperCamel %>Response, error) { @@ -44,27 +44,30 @@ func (k msgServer) Update<%= TypeName.UpperCamel %>(ctx context.Context, msg *t } // Check if the value exists - valFound, isFound := k.Get<%= TypeName.UpperCamel %>( - ctx, - <%= for (i, index) in Indexes { %>msg.<%= index.Name.UpperCamel %>, - <% } %>) - if !isFound { - return nil, errorsmod.Wrap(sdkerrors.ErrKeyNotFound, "index not set") + val, err := k.<%= TypeName.UpperCamel %>.Get(ctx, msg.<%= Index.Name.UpperCamel %>) + if err != nil { + if errors.Is(err, collections.ErrNotFound) { + return nil, errorsmod.Wrap(sdkerrors.ErrKeyNotFound, "index not set") + } + + return nil, errorsmod.Wrap(sdkerrors.ErrLogic, err.Error()) } // Checks if the msg <%= MsgSigner.LowerCamel %> is the same as the current owner - if msg.<%= MsgSigner.UpperCamel %> != valFound.<%= MsgSigner.UpperCamel %> { + if msg.<%= MsgSigner.UpperCamel %> != val.<%= MsgSigner.UpperCamel %> { return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "incorrect owner") } var <%= TypeName.LowerCamel %> = types.<%= TypeName.UpperCamel %>{ <%= MsgSigner.UpperCamel %>: msg.<%= MsgSigner.UpperCamel %>, - <%= for (i, index) in Indexes { %><%= index.Name.UpperCamel %>: msg.<%= index.Name.UpperCamel %>, - <% } %><%= for (field) in Fields { %><%= field.Name.UpperCamel %>: msg.<%= field.Name.UpperCamel %>, + <%= Index.Name.UpperCamel %>: msg.<%= Index.Name.UpperCamel %>, + <%= for (field) in Fields { %><%= field.Name.UpperCamel %>: msg.<%= field.Name.UpperCamel %>, <% } %> } - k.Set<%= TypeName.UpperCamel %>(ctx, <%= TypeName.LowerCamel %>) + if err := k.<%= TypeName.UpperCamel %>.Set(ctx, <%= TypeName.LowerCamel %>.<%= Index.Name.UpperCamel %>, <%= TypeName.LowerCamel %>); err != nil { + return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "failed to update <%= TypeName.LowerCamel %>") + } return &types.MsgUpdate<%= TypeName.UpperCamel %>Response{}, nil } @@ -75,23 +78,23 @@ func (k msgServer) Delete<%= TypeName.UpperCamel %>(ctx context.Context, msg *t } // Check if the value exists - valFound, isFound := k.Get<%= TypeName.UpperCamel %>( - ctx, - <%= for (i, index) in Indexes { %>msg.<%= index.Name.UpperCamel %>, - <% } %>) - if !isFound { - return nil, errorsmod.Wrap(sdkerrors.ErrKeyNotFound, "index not set") + val, err := k.<%= TypeName.UpperCamel %>.Get(ctx, msg.<%= Index.Name.UpperCamel %>) + if err != nil { + if errors.Is(err, collections.ErrNotFound) { + return nil, errorsmod.Wrap(sdkerrors.ErrKeyNotFound, "index not set") + } + + return nil, errorsmod.Wrap(sdkerrors.ErrLogic, err.Error()) } // Checks if the msg <%= MsgSigner.LowerCamel %> is the same as the current owner - if msg.<%= MsgSigner.UpperCamel %> != valFound.<%= MsgSigner.UpperCamel %> { + if msg.<%= MsgSigner.UpperCamel %> != val.<%= MsgSigner.UpperCamel %> { return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "incorrect owner") } - k.Remove<%= TypeName.UpperCamel %>( - ctx, - <%= for (i, index) in Indexes { %>msg.<%= index.Name.UpperCamel %>, - <% } %>) + if err := k.<%= TypeName.UpperCamel %>.Remove(ctx, msg.<%= Index.Name.UpperCamel %>); err != nil { + return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "failed to remove <%= TypeName.LowerCamel %>") + } return &types.MsgDelete<%= TypeName.UpperCamel %>Response{}, nil } diff --git a/ignite/templates/typed/map/files/messages/x/{{moduleName}}/types/messages_{{typeName}}.go.plush b/ignite/templates/typed/map/files/messages/x/{{moduleName}}/types/messages_{{typeName}}.go.plush index 3348d22847..a6ffc57d10 100644 --- a/ignite/templates/typed/map/files/messages/x/{{moduleName}}/types/messages_{{typeName}}.go.plush +++ b/ignite/templates/typed/map/files/messages/x/{{moduleName}}/types/messages_{{typeName}}.go.plush @@ -2,40 +2,39 @@ package types func NewMsgCreate<%= TypeName.UpperCamel %>( <%= MsgSigner.LowerCamel %> string, - <%= for (i, index) in Indexes { %><%= index.Name.LowerCamel %> <%= index.DataType() %>, - <% } %><%= for (field) in Fields { %><%= field.Name.LowerCamel %> <%= field.DataType() %>, + <%= Index.Name.LowerCamel %> <%= Index.DataType() %>, + <%= for (field) in Fields { %><%= field.Name.LowerCamel %> <%= field.DataType() %>, <% } %> ) *MsgCreate<%= TypeName.UpperCamel %> { return &MsgCreate<%= TypeName.UpperCamel %>{ <%= MsgSigner.UpperCamel %> : <%= MsgSigner.LowerCamel %>, - <%= for (index) in Indexes { %><%= index.Name.UpperCamel %>: <%= index.Name.LowerCamel %>, - <% } %><%= for (field) in Fields { %><%= field.Name.UpperCamel %>: <%= field.Name.LowerCamel %>, + <%= Index.Name.UpperCamel %>: <%= Index.Name.LowerCamel %>, + <%= for (field) in Fields { %><%= field.Name.UpperCamel %>: <%= field.Name.LowerCamel %>, <% } %> } } func NewMsgUpdate<%= TypeName.UpperCamel %>( <%= MsgSigner.LowerCamel %> string, - <%= for (i, index) in Indexes { %><%= index.Name.LowerCamel %> <%= index.DataType() %>, - <% } %><%= for (field) in Fields { %><%= field.Name.LowerCamel %> <%= field.DataType() %>, + <%= Index.Name.LowerCamel %> <%= Index.DataType() %>, + <%= for (field) in Fields { %><%= field.Name.LowerCamel %> <%= field.DataType() %>, <% } %> ) *MsgUpdate<%= TypeName.UpperCamel %> { return &MsgUpdate<%= TypeName.UpperCamel %>{ <%= MsgSigner.UpperCamel %>: <%= MsgSigner.LowerCamel %>, - <%= for (index) in Indexes { %><%= index.Name.UpperCamel %>: <%= index.Name.LowerCamel %>, - <% } %><%= for (field) in Fields { %><%= field.Name.UpperCamel %>: <%= field.Name.LowerCamel %>, + <%= Index.Name.UpperCamel %>: <%= Index.Name.LowerCamel %>, + <%= for (field) in Fields { %><%= field.Name.UpperCamel %>: <%= field.Name.LowerCamel %>, <% } %> } } func NewMsgDelete<%= TypeName.UpperCamel %>( <%= MsgSigner.LowerCamel %> string, - <%= for (i, index) in Indexes { %><%= index.Name.LowerCamel %> <%= index.DataType() %>, + <%= Index.Name.LowerCamel %> <%= Index.DataType() %>, <% } %> ) *MsgDelete<%= TypeName.UpperCamel %> { return &MsgDelete<%= TypeName.UpperCamel %>{ <%= MsgSigner.UpperCamel %>: <%= MsgSigner.LowerCamel %>, - <%= for (index) in Indexes { %><%= index.Name.UpperCamel %>: <%= index.Name.LowerCamel %>, - <% } %> + <%= Index.Name.UpperCamel %>: <%= Index.Name.LowerCamel %>, } } \ No newline at end of file diff --git a/ignite/templates/typed/map/files/simapp/x/{{moduleName}}/simulation/{{typeName}}.go.plush b/ignite/templates/typed/map/files/simapp/x/{{moduleName}}/simulation/{{typeName}}.go.plush index fb2392f0d4..4b6429fca8 100644 --- a/ignite/templates/typed/map/files/simapp/x/{{moduleName}}/simulation/{{typeName}}.go.plush +++ b/ignite/templates/typed/map/files/simapp/x/{{moduleName}}/simulation/{{typeName}}.go.plush @@ -27,12 +27,12 @@ func SimulateMsgCreate<%= TypeName.UpperCamel %>( i := r.Int() msg := &types.MsgCreate<%= TypeName.UpperCamel %>{ - <%= MsgSigner.UpperCamel %>: simAccount.Address.String(),<%= for (i, index) in Indexes { %> - <%= index.Name.UpperCamel %>: <%= index.ValueLoop() %>,<% } %> + <%= MsgSigner.UpperCamel %>: simAccount.Address.String(), + <%= Index.Name.UpperCamel %>: <%= Index.ValueLoop() %>, } - _, found := k.Get<%= TypeName.UpperCamel %>(ctx <%= for (index) in Indexes { %>, msg.<%= index.Name.UpperCamel %><% } %>) - if found { + found, err := k.<%= TypeName.UpperCamel %>.Has(ctx, msg.<%= Index.Name.UpperCamel %>) + if err == nil && found { return simtypes.NoOpMsg(types.ModuleName, sdk.MsgTypeURL(msg), "<%= TypeName.UpperCamel %> already exist"), nil, nil } @@ -64,9 +64,18 @@ func SimulateMsgUpdate<%= TypeName.UpperCamel %>( simAccount = simtypes.Account{} <%= TypeName.LowerCamel %> = types.<%= TypeName.UpperCamel %>{} msg = &types.MsgUpdate<%= TypeName.UpperCamel %>{} - all<%= TypeName.UpperCamel %> = k.GetAll<%= TypeName.UpperCamel %>(ctx) found = false ) + + var all<%= TypeName.UpperCamel %> []types.<%= TypeName.UpperCamel %> + err := k.<%= TypeName.UpperCamel %>.Walk(ctx, nil, func(key <%= Index.DataType() %>, value types.<%= TypeName.UpperCamel %>) (stop bool, err error) { + all<%= TypeName.UpperCamel %> = append(all<%= TypeName.UpperCamel %>, value) + return false, nil + }) + if err != nil { + panic(err) + } + for _, obj := range all<%= TypeName.UpperCamel %> { simAccount, found = FindAccount(accs, obj.<%= MsgSigner.UpperCamel %>) if found { @@ -78,8 +87,7 @@ func SimulateMsgUpdate<%= TypeName.UpperCamel %>( return simtypes.NoOpMsg(types.ModuleName, sdk.MsgTypeURL(msg), "<%= TypeName.LowerCamel %> <%= MsgSigner.LowerCamel %> not found"), nil, nil } msg.<%= MsgSigner.UpperCamel %> = simAccount.Address.String() - <%= for (i, index) in Indexes { %> - msg.<%= index.Name.UpperCamel %> = <%= TypeName.LowerCamel %>.<%= index.Name.UpperCamel %><% } %> + msg.<%= Index.Name.UpperCamel %> = <%= TypeName.LowerCamel %>.<%= Index.Name.UpperCamel %> txCtx := simulation.OperationInput{ R: r, @@ -109,9 +117,18 @@ func SimulateMsgDelete<%= TypeName.UpperCamel %>( simAccount = simtypes.Account{} <%= TypeName.LowerCamel %> = types.<%= TypeName.UpperCamel %>{} msg = &types.MsgUpdate<%= TypeName.UpperCamel %>{} - all<%= TypeName.UpperCamel %> = k.GetAll<%= TypeName.UpperCamel %>(ctx) found = false ) + + var all<%= TypeName.UpperCamel %> []types.<%= TypeName.UpperCamel %> + err := k.<%= TypeName.UpperCamel %>.Walk(ctx, nil, func(key <%= Index.DataType() %>, value types.<%= TypeName.UpperCamel %>) (stop bool, err error) { + all<%= TypeName.UpperCamel %> = append(all<%= TypeName.UpperCamel %>, value) + return false, nil + }) + if err != nil { + panic(err) + } + for _, obj := range all<%= TypeName.UpperCamel %> { simAccount, found = FindAccount(accs, obj.<%= MsgSigner.UpperCamel %>) if found { @@ -123,8 +140,7 @@ func SimulateMsgDelete<%= TypeName.UpperCamel %>( return simtypes.NoOpMsg(types.ModuleName, sdk.MsgTypeURL(msg), "<%= TypeName.LowerCamel %> <%= MsgSigner.LowerCamel %> not found"), nil, nil } msg.<%= MsgSigner.UpperCamel %> = simAccount.Address.String() - <%= for (i, index) in Indexes { %> - msg.<%= index.Name.UpperCamel %> = <%= TypeName.LowerCamel %>.<%= index.Name.UpperCamel %><% } %> + msg.<%= Index.Name.UpperCamel %> = <%= TypeName.LowerCamel %>.<%= Index.Name.UpperCamel %> txCtx := simulation.OperationInput{ R: r, diff --git a/ignite/templates/typed/map/files/tests/component/x/{{moduleName}}/keeper/query_{{typeName}}_test.go.plush b/ignite/templates/typed/map/files/tests/component/x/{{moduleName}}/keeper/query_{{typeName}}_test.go.plush index 5860d4a3f1..6750c3c02c 100644 --- a/ignite/templates/typed/map/files/tests/component/x/{{moduleName}}/keeper/query_{{typeName}}_test.go.plush +++ b/ignite/templates/typed/map/files/tests/component/x/{{moduleName}}/keeper/query_{{typeName}}_test.go.plush @@ -1,7 +1,7 @@ package keeper_test import ( - "strconv" + "strconv" "testing" "github.com/cosmos/cosmos-sdk/types/query" @@ -18,6 +18,16 @@ import ( // Prevent strconv unused error var _ = strconv.IntSize +func createN<%= TypeName.UpperCamel %>(keeper keeper.Keeper, ctx context.Context, n int) []types.<%= TypeName.UpperCamel %> { + items := make([]types.<%= TypeName.UpperCamel %>, n) + for i := range items { + items[i].<%= Index.Name.UpperCamel %> = <%= Index.ValueLoop() %> + + _ = keeper.<%= TypeName.UpperCamel %>.Set(ctx, items[i].<%= Index.Name.UpperCamel %>, items[i]) + } + return items +} + func Test<%= TypeName.UpperCamel %>QuerySingle(t *testing.T) { k, ctx, _ := keepertest.<%= title(ModuleName) %>Keeper(t) qs := keeper.NewQueryServerImpl(k) @@ -31,24 +41,21 @@ func Test<%= TypeName.UpperCamel %>QuerySingle(t *testing.T) { { desc: "First", request: &types.QueryGet<%= TypeName.UpperCamel %>Request{ - <%= for (i, index) in Indexes { %><%= index.Name.UpperCamel %>: msgs[0].<%= index.Name.UpperCamel %>, - <% } %> + <%= Index.Name.UpperCamel %>: msgs[0].<%= Index.Name.UpperCamel %>, }, response: &types.QueryGet<%= TypeName.UpperCamel %>Response{<%= TypeName.UpperCamel %>: msgs[0]}, }, { desc: "Second", request: &types.QueryGet<%= TypeName.UpperCamel %>Request{ - <%= for (i, index) in Indexes { %><%= index.Name.UpperCamel %>: msgs[1].<%= index.Name.UpperCamel %>, - <% } %> + <%= Index.Name.UpperCamel %>: msgs[1].<%= Index.Name.UpperCamel %>, }, response: &types.QueryGet<%= TypeName.UpperCamel %>Response{<%= TypeName.UpperCamel %>: msgs[1]}, }, { desc: "KeyNotFound", request: &types.QueryGet<%= TypeName.UpperCamel %>Request{ - <%= for (i, index) in Indexes { %><%= index.Name.UpperCamel %>:<%= index.ValueInvalidIndex() %>, - <% } %> + <%= Index.Name.UpperCamel %>: <%= Index.ValueInvalidIndex() %>, }, err: status.Error(codes.NotFound, "not found"), }, diff --git a/ignite/templates/typed/map/files/tests/component/x/{{moduleName}}/keeper/{{typeName}}_test.go.plush b/ignite/templates/typed/map/files/tests/component/x/{{moduleName}}/keeper/{{typeName}}_test.go.plush deleted file mode 100644 index 1952fe6519..0000000000 --- a/ignite/templates/typed/map/files/tests/component/x/{{moduleName}}/keeper/{{typeName}}_test.go.plush +++ /dev/null @@ -1,66 +0,0 @@ -package keeper_test - -import ( - "context" - "strconv" - "testing" - - "<%= ModulePath %>/x/<%= ModuleName %>/keeper" - "<%= ModulePath %>/x/<%= ModuleName %>/types" - keepertest "<%= ModulePath %>/testutil/keeper" - "<%= ModulePath %>/testutil/nullify" - "github.com/stretchr/testify/require" -) - -// Prevent strconv unused error -var _ = strconv.IntSize - -func createN<%= TypeName.UpperCamel %>(keeper keeper.Keeper, ctx context.Context, n int) []types.<%= TypeName.UpperCamel %> { - items := make([]types.<%= TypeName.UpperCamel %>, n) - for i := range items { - <%= for (i, index) in Indexes { %>items[i].<%= index.Name.UpperCamel %> = <%= index.ValueLoop() %> - <% } %> - keeper.Set<%= TypeName.UpperCamel %>(ctx, items[i]) - } - return items -} - -func Test<%= TypeName.UpperCamel %>Get(t *testing.T) { - keeper, ctx, _ := keepertest.<%= title(ModuleName) %>Keeper(t) - items := createN<%= TypeName.UpperCamel %>(keeper, ctx, 10) - for _, item := range items { - rst, found := keeper.Get<%= TypeName.UpperCamel %>(ctx, - <%= for (i, index) in Indexes { %>item.<%= index.Name.UpperCamel %>, - <% } %> - ) - require.True(t, found) - require.Equal(t, - nullify.Fill(&item), - nullify.Fill(&rst), - ) - } -} -func Test<%= TypeName.UpperCamel %>Remove(t *testing.T) { - keeper, ctx, _ := keepertest.<%= title(ModuleName) %>Keeper(t) - items := createN<%= TypeName.UpperCamel %>(keeper, ctx, 10) - for _, item := range items { - keeper.Remove<%= TypeName.UpperCamel %>(ctx, - <%= for (i, index) in Indexes { %>item.<%= index.Name.UpperCamel %>, - <% } %> - ) - _, found := keeper.Get<%= TypeName.UpperCamel %>(ctx, - <%= for (i, index) in Indexes { %>item.<%= index.Name.UpperCamel %>, - <% } %> - ) - require.False(t, found) - } -} - -func Test<%= TypeName.UpperCamel %>GetAll(t *testing.T) { - keeper, ctx, _ := keepertest.<%= title(ModuleName) %>Keeper(t) - items := createN<%= TypeName.UpperCamel %>(keeper, ctx, 10) - require.ElementsMatch(t, - nullify.Fill(items), - nullify.Fill(keeper.GetAll<%= TypeName.UpperCamel %>(ctx)), - ) -} diff --git a/ignite/templates/typed/map/files/tests/messages/x/{{moduleName}}/keeper/msg_server_{{typeName}}_test.go.plush b/ignite/templates/typed/map/files/tests/messages/x/{{moduleName}}/keeper/msg_server_{{typeName}}_test.go.plush index 3cef7ce4bb..4a2358211d 100644 --- a/ignite/templates/typed/map/files/tests/messages/x/{{moduleName}}/keeper/msg_server_{{typeName}}_test.go.plush +++ b/ignite/templates/typed/map/files/tests/messages/x/{{moduleName}}/keeper/msg_server_{{typeName}}_test.go.plush @@ -23,16 +23,12 @@ func Test<%= TypeName.UpperCamel %>MsgServerCreate(t *testing.T) { for i := 0; i < 5; i++ { expected := &types.MsgCreate<%= TypeName.UpperCamel %>{<%= MsgSigner.UpperCamel %>: <%= MsgSigner.LowerCamel %>, - <%= for (i, index) in Indexes { %><%= index.Name.UpperCamel %>: <%= index.ValueLoop() %>, - <% } %> + <%= Index.Name.UpperCamel %>: <%= Index.ValueLoop() %>, } _, err := srv.Create<%= TypeName.UpperCamel %>(ctx, expected) require.NoError(t, err) - rst, found := k.Get<%= TypeName.UpperCamel %>(ctx, - <%= for (i, index) in Indexes { %>expected.<%= index.Name.UpperCamel %>, - <% } %> - ) - require.True(t, found) + rst, err := k.<%= TypeName.UpperCamel %>.Get(ctx, expected.<%= Index.Name.UpperCamel %>) + require.NoError(t, err) require.Equal(t, expected.<%= MsgSigner.UpperCamel %>, rst.<%= MsgSigner.UpperCamel %>) } } @@ -47,8 +43,7 @@ func Test<%= TypeName.UpperCamel %>MsgServerUpdate(t *testing.T) { srv := keeper.NewMsgServerImpl(k) expected := &types.MsgCreate<%= TypeName.UpperCamel %>{<%= MsgSigner.UpperCamel %>: <%= MsgSigner.LowerCamel %>, - <%= for (i, index) in Indexes { %><%= index.Name.UpperCamel %>: <%= index.ValueIndex() %>, - <% } %> + <%= Index.Name.UpperCamel %>: <%= Index.ValueIndex() %>, } _, err = srv.Create<%= TypeName.UpperCamel %>(ctx, expected) require.NoError(t, err) @@ -61,32 +56,28 @@ func Test<%= TypeName.UpperCamel %>MsgServerUpdate(t *testing.T) { { desc: "invalid address", request: &types.MsgUpdate<%= TypeName.UpperCamel %>{<%= MsgSigner.UpperCamel %>: "invalid", - <%= for (i, index) in Indexes { %><%= index.Name.UpperCamel %>: <%= index.ValueIndex() %>, - <% } %> + <%= Index.Name.UpperCamel %>: <%= Index.ValueIndex() %>, }, err: sdkerrors.ErrInvalidAddress, }, { desc: "unauthorized", request: &types.MsgUpdate<%= TypeName.UpperCamel %>{<%= MsgSigner.UpperCamel %>: unauthorizedAddr, - <%= for (i, index) in Indexes { %><%= index.Name.UpperCamel %>: <%= index.ValueIndex() %>, - <% } %> + <%= Index.Name.UpperCamel %>: <%= Index.ValueIndex() %>, }, err: sdkerrors.ErrUnauthorized, }, { desc: "key not found", request: &types.MsgUpdate<%= TypeName.UpperCamel %>{<%= MsgSigner.UpperCamel %>: <%= MsgSigner.LowerCamel %>, - <%= for (i, index) in Indexes { %><%= index.Name.UpperCamel %>: <%= index.ValueInvalidIndex() %>, - <% } %> + <%= Index.Name.UpperCamel %>: <%= Index.ValueInvalidIndex() %>, }, err: sdkerrors.ErrKeyNotFound, }, { desc: "completed", request: &types.MsgUpdate<%= TypeName.UpperCamel %>{<%= MsgSigner.UpperCamel %>: <%= MsgSigner.LowerCamel %>, - <%= for (i, index) in Indexes { %><%= index.Name.UpperCamel %>: <%= index.ValueIndex() %>, - <% } %> + <%= Index.Name.UpperCamel %>: <%= Index.ValueIndex() %>, }, }, } @@ -97,11 +88,8 @@ func Test<%= TypeName.UpperCamel %>MsgServerUpdate(t *testing.T) { require.ErrorIs(t, err, tc.err) } else { require.NoError(t, err) - rst, found := k.Get<%= TypeName.UpperCamel %>(ctx, - <%= for (i, index) in Indexes { %>expected.<%= index.Name.UpperCamel %>, - <% } %> - ) - require.True(t, found) + rst, err := k.<%= TypeName.UpperCamel %>.Get(ctx, expected.<%= Index.Name.UpperCamel %>) + require.NoError(t, err) require.Equal(t, expected.<%= MsgSigner.UpperCamel %>, rst.<%= MsgSigner.UpperCamel %>) } }) @@ -118,8 +106,7 @@ func Test<%= TypeName.UpperCamel %>MsgServerDelete(t *testing.T) { srv := keeper.NewMsgServerImpl(k) _, err = srv.Create<%= TypeName.UpperCamel %>(ctx, &types.MsgCreate<%= TypeName.UpperCamel %>{<%= MsgSigner.UpperCamel %>: <%= MsgSigner.LowerCamel %>, - <%= for (i, index) in Indexes { %><%= index.Name.UpperCamel %>: <%= index.ValueIndex() %>, - <% } %> + <%= Index.Name.UpperCamel %>: <%= Index.ValueIndex() %>, }) require.NoError(t, err) @@ -131,32 +118,28 @@ func Test<%= TypeName.UpperCamel %>MsgServerDelete(t *testing.T) { { desc: "invalid address", request: &types.MsgDelete<%= TypeName.UpperCamel %>{<%= MsgSigner.UpperCamel %>: "invalid", - <%= for (i, index) in Indexes { %><%= index.Name.UpperCamel %>: <%= index.ValueIndex() %>, - <% } %> + <%= Index.Name.UpperCamel %>: <%= Index.ValueIndex() %>, }, err: sdkerrors.ErrInvalidAddress, }, { desc: "unauthorized", request: &types.MsgDelete<%= TypeName.UpperCamel %>{<%= MsgSigner.UpperCamel %>: unauthorizedAddr, - <%= for (i, index) in Indexes { %><%= index.Name.UpperCamel %>: <%= index.ValueIndex() %>, - <% } %> + <%= Index.Name.UpperCamel %>: <%= Index.ValueIndex() %>, }, err: sdkerrors.ErrUnauthorized, }, { desc: "key not found", request: &types.MsgDelete<%= TypeName.UpperCamel %>{<%= MsgSigner.UpperCamel %>: <%= MsgSigner.LowerCamel %>, - <%= for (i, index) in Indexes { %><%= index.Name.UpperCamel %>: <%= index.ValueInvalidIndex() %>, - <% } %> + <%= Index.Name.UpperCamel %>: <%= Index.ValueInvalidIndex() %>, }, err: sdkerrors.ErrKeyNotFound, }, { desc: "completed", request: &types.MsgDelete<%= TypeName.UpperCamel %>{<%= MsgSigner.UpperCamel %>: <%= MsgSigner.LowerCamel %>, - <%= for (i, index) in Indexes { %><%= index.Name.UpperCamel %>: <%= index.ValueIndex() %>, - <% } %> + <%= Index.Name.UpperCamel %>: <%= Index.ValueIndex() %>, }, }, } @@ -167,10 +150,8 @@ func Test<%= TypeName.UpperCamel %>MsgServerDelete(t *testing.T) { require.ErrorIs(t, err, tc.err) } else { require.NoError(t, err) - _, found := k.Get<%= TypeName.UpperCamel %>(ctx, - <%= for (i, index) in Indexes { %>tc.request.<%= index.Name.UpperCamel %>, - <% } %> - ) + found, err := k.<%= TypeName.UpperCamel %>.Has(ctx, tc.request.<%= Index.Name.UpperCamel %>) + require.NoError(t, err) require.False(t, found) } }) diff --git a/ignite/templates/typed/map/map.go b/ignite/templates/typed/map/map.go index 76629c2ea1..cf50de9389 100644 --- a/ignite/templates/typed/map/map.go +++ b/ignite/templates/typed/map/map.go @@ -15,6 +15,7 @@ import ( "github.com/ignite/cli/v29/ignite/pkg/protoanalysis/protoutil" "github.com/ignite/cli/v29/ignite/pkg/xast" "github.com/ignite/cli/v29/ignite/pkg/xgenny" + "github.com/ignite/cli/v29/ignite/templates/field" "github.com/ignite/cli/v29/ignite/templates/field/datatype" "github.com/ignite/cli/v29/ignite/templates/module" "github.com/ignite/cli/v29/ignite/templates/typed" @@ -42,10 +43,8 @@ func NewGenerator(replacer placeholder.Replacer, opts *typed.Options) (*genny.Ge // Tests are not generated for map with a custom index that contains only booleans // because we can't generate reliable tests for this type var generateTest bool - for _, index := range opts.Indexes { - if index.DatatypeName != datatype.Bool { - generateTest = true - } + if opts.Index.DatatypeName != datatype.Bool { + generateTest = true } var ( @@ -79,6 +78,7 @@ func NewGenerator(replacer placeholder.Replacer, opts *typed.Options) (*genny.Ge ) g.RunFn(protoRPCModify(opts)) + g.RunFn(keeperModify(replacer, opts)) g.RunFn(clientCliQueryModify(replacer, opts)) g.RunFn(genesisProtoModify(opts)) g.RunFn(genesisTypesModify(replacer, opts)) @@ -117,6 +117,41 @@ func NewGenerator(replacer placeholder.Replacer, opts *typed.Options) (*genny.Ge return g, typed.Box(componentTemplate, opts, g) } +// keeperModify modifies the keeper to add a new collections map type +func keeperModify(replacer placeholder.Replacer, opts *typed.Options) genny.RunFn { + return func(r *genny.Runner) error { + path := filepath.Join(opts.AppPath, "x", opts.ModuleName, "keeper/keeper.go") + f, err := r.Disk.Find(path) + if err != nil { + return err + } + + templateKeeperType := `%[2]v collections.Map[%[3]v, types.%[2]v] + %[1]v` + replacementModuleType := fmt.Sprintf( + templateKeeperType, + typed.PlaceholderCollectionType, + opts.TypeName.UpperCamel, + opts.Index.DataType(), + ) + content := replacer.Replace(f.String(), typed.PlaceholderCollectionType, replacementModuleType) + + templateKeeperInstantiate := `%[2]v: collections.NewMap(sb, types.%[2]vKey, "%[3]v", %[4]v, codec.CollValue[types.%[2]v](cdc)), + %[1]v` + replacementInstantiate := fmt.Sprintf( + templateKeeperInstantiate, + typed.PlaceholderCollectionInstantiate, + opts.TypeName.UpperCamel, + opts.TypeName.LowerCamel, + dataTypeToCollectionKeyValue(opts.Index), + ) + content = replacer.Replace(content, typed.PlaceholderCollectionInstantiate, replacementInstantiate) + + newFile := genny.NewFileS(path, content) + return r.File(newFile) + } +} + // Modifies query.proto to add the required RPCs and Messages. // // What it depends on: @@ -139,11 +174,7 @@ func protoRPCModify(opts *typed.Options) genny.RunFn { return errors.Errorf("failed while adding imports in %s: %w", path, err) } - var protoIndexes []string - for _, index := range opts.Indexes { - protoIndexes = append(protoIndexes, fmt.Sprintf("{%s}", index.ProtoFieldName())) - } - indexPath := strings.Join(protoIndexes, "/") + protoIndex := fmt.Sprintf("{%s}", opts.Index.ProtoFieldName()) appModulePath := gomodulepath.ExtractAppPath(opts.ModulePath) serviceQuery, err := protoutil.GetServiceByName(protoFile, "Query") if err != nil { @@ -159,7 +190,7 @@ func protoRPCModify(opts *typed.Options) genny.RunFn { "google.api.http", fmt.Sprintf( "/%s/%s/%s/%s", - appModulePath, opts.ModuleName, typenameSnake, indexPath, + appModulePath, opts.ModuleName, typenameSnake, protoIndex, ), protoutil.Custom(), protoutil.SetField("get"), @@ -203,14 +234,10 @@ func protoRPCModify(opts *typed.Options) genny.RunFn { } // Add the messages. - var queryIndexFields []*proto.NormalField - for i, index := range opts.Indexes { - queryIndexFields = append(queryIndexFields, index.ToProtoField(i+1)) - } paginationType, paginationName := "cosmos.base.query.v1beta1.Page", "pagination" queryGetRequest := protoutil.NewMessage( fmt.Sprintf("QueryGet%sRequest", typenameUpper), - protoutil.WithFields(queryIndexFields...), + protoutil.WithFields(opts.Index.ToProtoField(1)), ) gogoOption := protoutil.NewOption("gogoproto.nullable", "false", protoutil.Custom()) queryGetResponse := protoutil.NewMessage( @@ -249,11 +276,6 @@ func clientCliQueryModify(replacer placeholder.Replacer, opts *typed.Options) ge return err } - var positionalArgs string - for _, field := range opts.Indexes { - positionalArgs += fmt.Sprintf(`{ProtoField: "%s"}, `, field.ProtoFieldName()) - } - template := `{ RpcMethod: "List%[2]v", Use: "list-%[3]v", @@ -264,7 +286,7 @@ func clientCliQueryModify(replacer placeholder.Replacer, opts *typed.Options) ge Use: "get-%[3]v [id]", Short: "Gets a %[4]v", Alias: []string{"show-%[3]v"}, - PositionalArgs: []*autocliv1.PositionalArgDescriptor{%[5]s}, + PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField:"%[5]s"}}, }, %[1]v` replacement := fmt.Sprintf( @@ -273,7 +295,7 @@ func clientCliQueryModify(replacer placeholder.Replacer, opts *typed.Options) ge opts.TypeName.UpperCamel, opts.TypeName.Kebab, opts.TypeName.Original, - strings.TrimSpace(positionalArgs), + opts.Index.ProtoFieldName(), ) content := replacer.Replace(f.String(), typed.PlaceholderAutoCLIQuery, replacement) newFile := genny.NewFileS(path, content) @@ -344,11 +366,7 @@ func genesisTypesModify(replacer placeholder.Replacer, opts *typed.Options) genn content = replacer.Replace(content, typed.PlaceholderGenesisTypesDefault, replacementTypesDefault) // lines of code to call the key function with the indexes of the element - var indexArgs []string - for _, index := range opts.Indexes { - indexArgs = append(indexArgs, "elem."+index.Name.UpperCamel) - } - keyCall := fmt.Sprintf("%sKey(%s)", opts.TypeName.UpperCamel, strings.Join(indexArgs, ",")) + keyCall := fmt.Sprintf("string(elem.%s)", opts.Index.Name.UpperCamel) templateTypesValidate := `// Check for duplicated index in %[2]v %[2]vIndexMap := make(map[string]struct{}) @@ -366,7 +384,7 @@ for _, elem := range gs.%[3]vList { typed.PlaceholderGenesisTypesValidate, opts.TypeName.LowerCamel, opts.TypeName.UpperCamel, - fmt.Sprintf("string(%s)", keyCall), + keyCall, ) content = replacer.Replace(content, typed.PlaceholderGenesisTypesValidate, replacementTypesValidate) @@ -385,7 +403,9 @@ func genesisModuleModify(replacer placeholder.Replacer, opts *typed.Options) gen templateModuleInit := `// Set all the %[2]v for _, elem := range genState.%[3]vList { - k.Set%[3]v(ctx, elem) + if err := k.%[3]v.Set(ctx, elem.%[4]v, elem); err != nil { + panic(err) + } } %[1]v` replacementModuleInit := fmt.Sprintf( @@ -393,16 +413,22 @@ for _, elem := range genState.%[3]vList { typed.PlaceholderGenesisModuleInit, opts.TypeName.LowerCamel, opts.TypeName.UpperCamel, + opts.Index.Name.UpperCamel, ) content := replacer.Replace(f.String(), typed.PlaceholderGenesisModuleInit, replacementModuleInit) - templateModuleExport := `genesis.%[3]vList = k.GetAll%[3]v(ctx) + templateModuleExport := `if err := k.%[2]v.Walk(ctx, nil, func(_ %[3]v, val types.%[2]v) (stop bool, err error) { + genesis.%[2]vList = append(genesis.%[2]vList, val) + return false, nil + }); err != nil { + panic(err) + } %[1]v` replacementModuleExport := fmt.Sprintf( templateModuleExport, typed.PlaceholderGenesisModuleExport, - opts.TypeName.LowerCamel, opts.TypeName.UpperCamel, + opts.Index.DataType(), ) content = replacer.Replace(content, typed.PlaceholderGenesisModuleExport, replacementModuleExport) @@ -422,9 +448,7 @@ func genesisTestsModify(replacer placeholder.Replacer, opts *typed.Options) genn // Create a list of two different indexes to use as sample sampleIndexes := make([]string, 2) for i := 0; i < 2; i++ { - for _, index := range opts.Indexes { - sampleIndexes[i] += index.GenesisArgs(i) - } + sampleIndexes[i] = opts.Index.GenesisArgs(i) } templateState := `%[2]vList: []types.%[2]v{ @@ -468,9 +492,7 @@ func genesisTypesTestsModify(replacer placeholder.Replacer, opts *typed.Options) // Create a list of two different indexes to use as sample sampleIndexes := make([]string, 2) for i := 0; i < 2; i++ { - for _, index := range opts.Indexes { - sampleIndexes[i] += index.GenesisArgs(i) - } + sampleIndexes[i] = opts.Index.GenesisArgs(i) } templateValid := `%[2]vList: []types.%[2]v{ @@ -563,19 +585,15 @@ func protoTxModify(opts *typed.Options) genny.RunFn { ) // Messages - var indexes []*proto.NormalField - for i, index := range opts.Indexes { - indexes = append(indexes, index.ToProtoField(i+2)) - } - + index := opts.Index.ToProtoField(2) var fields []*proto.NormalField for i, f := range opts.Fields { - fields = append(fields, f.ToProtoField(i+2+len(opts.Indexes))) + fields = append(fields, f.ToProtoField(i+3)) // +3 because of the index } // Ensure custom types are imported var protoImports []*proto.Import - for _, imp := range append(opts.Fields.ProtoImports(), opts.Indexes.ProtoImports()...) { + for _, imp := range append(opts.Fields.ProtoImports(), opts.Index.ProtoImports()...) { protoImports = append(protoImports, protoutil.NewImport(imp)) } for _, f := range opts.Fields.Custom() { @@ -590,7 +608,7 @@ func protoTxModify(opts *typed.Options) genny.RunFn { creator := protoutil.NewField(opts.MsgSigner.LowerCamel, "string", 1) creatorOpt := protoutil.NewOption(typed.MsgSignerOption, opts.MsgSigner.LowerCamel) commonFields := []*proto.NormalField{creator} - commonFields = append(commonFields, indexes...) + commonFields = append(commonFields, index) msgCreate := protoutil.NewMessage( "MsgCreate"+typenameUpper, @@ -629,18 +647,16 @@ func clientCliTxModify(replacer placeholder.Replacer, opts *typed.Options) genny return err } + index := fmt.Sprintf(`{ProtoField: "%s"}, `, opts.Index.ProtoFieldName()) + indexStr := fmt.Sprintf("[%s] ", opts.Index.ProtoFieldName()) var positionalArgs, positionalArgsStr string - var indexes, indexesStr string for _, field := range opts.Fields { positionalArgs += fmt.Sprintf(`{ProtoField: "%s"}, `, field.ProtoFieldName()) positionalArgsStr += fmt.Sprintf("[%s] ", field.ProtoFieldName()) } - for _, field := range opts.Indexes { - indexes += fmt.Sprintf(`{ProtoField: "%s"}, `, field.ProtoFieldName()) - indexesStr += fmt.Sprintf("[%s] ", field.ProtoFieldName()) - } - positionalArgs = indexes + positionalArgs - positionalArgsStr = indexesStr + positionalArgsStr + + positionalArgs = index + positionalArgs + positionalArgsStr = indexStr + positionalArgsStr template := `{ RpcMethod: "Create%[2]v", @@ -670,8 +686,8 @@ func clientCliTxModify(replacer placeholder.Replacer, opts *typed.Options) genny opts.TypeName.Original, strings.TrimSpace(positionalArgs), strings.TrimSpace(positionalArgsStr), - strings.TrimSpace(indexes), - strings.TrimSpace(indexesStr), + strings.TrimSpace(index), + strings.TrimSpace(indexStr), ) content := replacer.Replace(f.String(), typed.PlaceholderAutoCLITx, replacement) @@ -712,3 +728,28 @@ func typesCodecModify(replacer placeholder.Replacer, opts *typed.Options) genny. return r.File(newFile) } } + +// TODO(@julienrbrt): extend support of dataTypeToCollectionKeyValue +func dataTypeToCollectionKeyValue(f field.Field) string { + var collectionKeyValue string + switch f.DataType() { + case "string": + collectionKeyValue = "collections.StringKey" + case "int32": + collectionKeyValue = "collections.Int32Key" + case "int64": + collectionKeyValue = "collections.Int64Key" + case "uint32": + collectionKeyValue = "collections.Uint32Key" + case "uint64": + collectionKeyValue = "collections.Uint64Key" + case "byte": + collectionKeyValue = "collections.BytesKey" + case "bool": + collectionKeyValue = "collections.BoolKey" + default: + collectionKeyValue = "/* Add collection key value */" + } + + return collectionKeyValue +} diff --git a/ignite/templates/typed/map/simulation.go b/ignite/templates/typed/map/simulation.go index 3d8ce63f4b..0b342e66e9 100644 --- a/ignite/templates/typed/map/simulation.go +++ b/ignite/templates/typed/map/simulation.go @@ -18,13 +18,11 @@ func moduleSimulationModify(replacer placeholder.Replacer, opts *typed.Options) return err } - // Create a list of two different indexes and fields to use as sample + // Create a list of two different index/fields to use as sample sampleIndexes := make([]string, 2) for i := 0; i < 2; i++ { sampleIndexes[i] = fmt.Sprintf("%s: sample.AccAddress(),\n", opts.MsgSigner.UpperCamel) - for _, index := range opts.Indexes { - sampleIndexes[i] += index.GenesisArgs(i) - } + sampleIndexes[i] += opts.Index.GenesisArgs(i) } // simulation genesis state diff --git a/ignite/templates/typed/options.go b/ignite/templates/typed/options.go index 8c9877dcde..6163337c46 100644 --- a/ignite/templates/typed/options.go +++ b/ignite/templates/typed/options.go @@ -21,7 +21,7 @@ type Options struct { TypeName multiformatname.Name MsgSigner multiformatname.Name Fields field.Fields - Indexes field.Fields + Index field.Field NoMessage bool NoSimulation bool IsIBC bool diff --git a/ignite/templates/typed/typed.go b/ignite/templates/typed/typed.go index 51022e2b30..5507872cc7 100644 --- a/ignite/templates/typed/typed.go +++ b/ignite/templates/typed/typed.go @@ -27,7 +27,7 @@ func Box(box packd.Walker, opts *Options, g *genny.Generator) error { ctx.Set("ModulePath", opts.ModulePath) ctx.Set("MsgSigner", opts.MsgSigner) ctx.Set("Fields", opts.Fields) - ctx.Set("Indexes", opts.Indexes) + ctx.Set("Index", opts.Index) ctx.Set("NoMessage", opts.NoMessage) ctx.Set("protoPkgName", module.ProtoPackageName(appModulePath, opts.ModuleName)) ctx.Set("strconv", func() bool { diff --git a/integration/map/cmd_map_test.go b/integration/map/cmd_map_test.go index b029a5b106..ade036b5aa 100644 --- a/integration/map/cmd_map_test.go +++ b/integration/map/cmd_map_test.go @@ -120,7 +120,7 @@ func TestCreateMap(t *testing.T) { "email", "emailIds:ints", "--index", - "foo:string,bar:int,foobar:uint,barFoo:bool", + "bar:int", "--module", "example", ), @@ -128,7 +128,7 @@ func TestCreateMap(t *testing.T) { )), )) - env.Must(env.Exec("create a map with invalid index", + env.Must(env.Exec("create a map with invalid index (multi-index)", step.NewSteps(step.New( step.Exec( envtest.IgniteApp, @@ -138,7 +138,7 @@ func TestCreateMap(t *testing.T) { "map_with_invalid_index", "email", "--index", - "foo:strings,bar:ints", + "foo:strings,bar:int", "--module", "example", ), @@ -147,20 +147,31 @@ func TestCreateMap(t *testing.T) { envtest.ExecShouldError(), )) - env.Must(env.Exec("create a message and a map with no-message flag to check conflicts", + env.Must(env.Exec("create a map with invalid index (invalid type)", step.NewSteps(step.New( - step.Exec(envtest.IgniteApp, "s", "message", "--yes", "create-scavenge", "description"), - step.Exec(envtest.IgniteApp, "s", "map", "--yes", "scavenge", "description", "--no-message"), + step.Exec( + envtest.IgniteApp, + "s", + "map", + "--yes", + "map_with_invalid_index", + "email", + "--index", + "foo:unknown", + "--module", + "example", + ), step.Workdir(app.SourcePath()), )), + envtest.ExecShouldError(), )) - env.Must(env.Exec("should prevent creating a map with duplicated indexes", + env.Must(env.Exec("create a message and a map with no-message flag to check conflicts", step.NewSteps(step.New( - step.Exec(envtest.IgniteApp, "s", "map", "--yes", "map_with_duplicated_index", "email", "--index", "foo,foo"), + step.Exec(envtest.IgniteApp, "s", "message", "--yes", "create-scavenge", "description"), + step.Exec(envtest.IgniteApp, "s", "map", "--yes", "scavenge", "description", "--no-message"), step.Workdir(app.SourcePath()), )), - envtest.ExecShouldError(), )) env.Must(env.Exec("should prevent creating a map with an index present in fields",