Skip to content

Commit

Permalink
feat(templates): use collections for map and remove multi index suppo…
Browse files Browse the repository at this point in the history
…rt (#4094)
  • Loading branch information
julienrbrt authored May 8, 2024
1 parent 53573da commit 1610734
Show file tree
Hide file tree
Showing 22 changed files with 287 additions and 388 deletions.
3 changes: 2 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
19 changes: 5 additions & 14 deletions ignite/cmd/scaffold_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand All @@ -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))
}
2 changes: 1 addition & 1 deletion ignite/config/plugins/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion ignite/pkg/xstrings/xstrings.go
Original file line number Diff line number Diff line change
@@ -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"
)
Expand Down
32 changes: 19 additions & 13 deletions ignite/services/scaffolder/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type addTypeOptions struct {
isMap bool
isSingleton bool

indexes []string
index string

withoutMessage bool
withoutSimulation bool
Expand All @@ -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
}
}

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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)
}
4 changes: 2 additions & 2 deletions ignite/services/scaffolder/type_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
9 changes: 7 additions & 2 deletions ignite/templates/field/plushhelpers/plushhelpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,52 +3,45 @@ 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())
}

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
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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
}
// <%= TypeName.UpperCamel %>Key is the prefix to retrieve all <%= TypeName.UpperCamel %>
var <%= TypeName.UpperCamel %>Key = collections.NewPrefix("<%= TypeName.UpperCamel %>/value/")
Original file line number Diff line number Diff line change
@@ -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 %>;<% } %>
}

Loading

0 comments on commit 1610734

Please sign in to comment.