From a4a16f6e7d4842531a5d2d11d69e20c78a4aab1f Mon Sep 17 00:00:00 2001 From: Kutluhan Metin Date: Tue, 29 Aug 2023 10:42:47 +0300 Subject: [PATCH] [CLC-19]: `\di` Command to List Indexes (#292) --- base/commands/map/map_set.go | 3 +- base/commands/object/object_list.go | 57 +------------- base/commands/script.go | 2 +- base/commands/shell.go | 1 + base/commands/shell_script_common.go | 15 +--- base/commands/sql/sql_it_test.go | 36 +++++++++ base/commands/sql/testdata/list_indexes.txt | 5 ++ base/commands/sql/testdata/sql_help.txt | 4 +- base/maps/maps.go | 74 +++++++++++++++++++ base/objects/objects.go | 61 +++++++++++++++ clc/shell/common.go | 68 +++++++++++++---- docs/modules/ROOT/pages/clc.adoc | 73 ++++++++++++++++++ .../proto/codec/bitmap_index_options_codec.go | 37 ++++++++++ internal/proto/codec/builtin.go | 20 +++++ internal/proto/codec/index_config_codec.go | 47 ++++++++++++ .../proto/codec/mc_get_map_config_codec.go | 73 ++++++++++++++++++ 16 files changed, 488 insertions(+), 88 deletions(-) create mode 100644 base/commands/sql/testdata/list_indexes.txt create mode 100644 base/maps/maps.go create mode 100644 base/objects/objects.go create mode 100644 internal/proto/codec/bitmap_index_options_codec.go create mode 100644 internal/proto/codec/index_config_codec.go create mode 100644 internal/proto/codec/mc_get_map_config_codec.go diff --git a/base/commands/map/map_set.go b/base/commands/map/map_set.go index 6f5c6798..c90402fe 100644 --- a/base/commands/map/map_set.go +++ b/base/commands/map/map_set.go @@ -6,12 +6,11 @@ import ( "context" "fmt" - "github.com/hazelcast/hazelcast-go-client" - "github.com/hazelcast/hazelcast-commandline-client/clc" . "github.com/hazelcast/hazelcast-commandline-client/internal/check" "github.com/hazelcast/hazelcast-commandline-client/internal/plug" "github.com/hazelcast/hazelcast-commandline-client/internal/proto/codec" + "github.com/hazelcast/hazelcast-go-client" ) type MapSetCommand struct{} diff --git a/base/commands/object/object_list.go b/base/commands/object/object_list.go index 7ae583a0..b38e571a 100644 --- a/base/commands/object/object_list.go +++ b/base/commands/object/object_list.go @@ -8,8 +8,7 @@ import ( "sort" "strings" - "github.com/hazelcast/hazelcast-go-client/types" - + "github.com/hazelcast/hazelcast-commandline-client/base/objects" "github.com/hazelcast/hazelcast-commandline-client/clc" . "github.com/hazelcast/hazelcast-commandline-client/internal/check" "github.com/hazelcast/hazelcast-commandline-client/internal/output" @@ -81,7 +80,7 @@ func (cm ObjectListCommand) Exec(ctx context.Context, ec plug.ExecContext) error typeFilter = ec.Args()[0] } showHidden := ec.Props().GetBool(flagShowHidden) - objs, err := getObjects(ctx, ec, typeFilter, showHidden) + objs, err := objects.GetAll(ctx, ec, typeFilter, showHidden) if err != nil { return err } @@ -100,7 +99,7 @@ func (cm ObjectListCommand) Exec(ctx context.Context, ec plug.ExecContext) error output.Column{ Name: "Service Name", Type: serialization.TypeString, - Value: shortType(o.ServiceName), + Value: objects.ShortType(o.ServiceName), }, valueCol, }) @@ -122,56 +121,6 @@ func objectFilterTypes() string { return sb.String() } -func getObjects(ctx context.Context, ec plug.ExecContext, typeFilter string, showHidden bool) ([]types.DistributedObjectInfo, error) { - ci, err := ec.ClientInternal(ctx) - if err != nil { - return nil, err - } - objs, stop, err := ec.ExecuteBlocking(ctx, func(ctx context.Context, sp clc.Spinner) (any, error) { - sp.SetText("Getting distributed objects") - return ci.Client().GetDistributedObjectsInfo(ctx) - }) - if err != nil { - return nil, err - } - stop() - var r []types.DistributedObjectInfo - typeFilter = strings.ToLower(typeFilter) - for _, o := range objs.([]types.DistributedObjectInfo) { - if !showHidden && (o.Name == "" || strings.HasPrefix(o.Name, "__")) { - continue - } - if o.Name == "" { - o.Name = "(no name)" - } - if typeFilter == "" { - r = append(r, o) - continue - } - if typeFilter == shortType(o.ServiceName) { - r = append(r, o) - } - } - sort.Slice(r, func(i, j int) bool { - // first sort by type, then name - ri := r[i] - rj := r[j] - if ri.ServiceName < rj.ServiceName { - return true - } - if ri.ServiceName > rj.ServiceName { - return false - } - return ri.Name < rj.Name - }) - return r, nil -} - -func shortType(svcName string) string { - s := strings.TrimSuffix(strings.TrimPrefix(svcName, "hz:impl:"), "Service") - return strings.ToLower(s) -} - func init() { // sort objectTypes so they look better in help sort.Slice(objTypes, func(i, j int) bool { diff --git a/base/commands/script.go b/base/commands/script.go index 0c1ac9c8..5c745196 100644 --- a/base/commands/script.go +++ b/base/commands/script.go @@ -72,7 +72,7 @@ func (cm ScriptCommand) Exec(ctx context.Context, ec plug.ExecContext) error { verbose := ec.Props().GetBool(clc.PropertyVerbose) ie := ec.Props().GetBool(flagIgnoreErrors) echo := ec.Props().GetBool(flagEcho) - textFn := makeTextFunc(m, ec, verbose, ie, echo, func(shortcut string) bool { + textFn := makeTextFunc(m, ec, verbose, false, false, func(shortcut string) bool { // shortcuts are not supported in the script mode return false }) diff --git a/base/commands/shell.go b/base/commands/shell.go index c92208ad..33acda46 100644 --- a/base/commands/shell.go +++ b/base/commands/shell.go @@ -43,6 +43,7 @@ func (cm *ShellCommand) Init(cc plug.InitContext) error { cc.Hide() cm.mu.Lock() cm.shortcuts = map[string]struct{}{ + `\di`: {}, `\dm`: {}, `\dm+`: {}, `\exit`: {}, diff --git a/base/commands/shell_script_common.go b/base/commands/shell_script_common.go index 29c9e1a0..d9e4f078 100644 --- a/base/commands/shell_script_common.go +++ b/base/commands/shell_script_common.go @@ -13,7 +13,6 @@ import ( "github.com/hazelcast/hazelcast-commandline-client/clc/cmd" "github.com/hazelcast/hazelcast-commandline-client/clc/shell" - "github.com/hazelcast/hazelcast-commandline-client/clc/sql" "github.com/hazelcast/hazelcast-commandline-client/internal/check" "github.com/hazelcast/hazelcast-commandline-client/internal/plug" ) @@ -65,7 +64,7 @@ func makeTextFunc(m *cmd.Main, ec plug.ExecContext, verbose, ignoreErrors, echo return m.Execute(ctx, args...) } } - text, err := shell.ConvertStatement(text) + f, err := shell.ConvertStatement(ctx, ec, text, verbose) if err != nil { if errors.Is(err, shell.ErrHelp) { check.I2(fmt.Fprintln(stdout, shell.InteractiveHelp())) @@ -73,18 +72,6 @@ func makeTextFunc(m *cmd.Main, ec plug.ExecContext, verbose, ignoreErrors, echo } return err } - f := func() error { - res, stop, err := sql.ExecSQL(ctx, ec, text) - if err != nil { - return err - } - defer stop() - // TODO: update sql.UpdateOutput to use stdout - if err := sql.UpdateOutput(ctx, ec, res, verbose); err != nil { - return err - } - return nil - } if w, ok := ec.(plug.ResultWrapper); ok { return w.WrapResult(f) } diff --git a/base/commands/sql/sql_it_test.go b/base/commands/sql/sql_it_test.go index 331ccf1c..dc9728af 100644 --- a/base/commands/sql/sql_it_test.go +++ b/base/commands/sql/sql_it_test.go @@ -10,6 +10,9 @@ import ( "time" "github.com/hazelcast/hazelcast-go-client" + hz "github.com/hazelcast/hazelcast-go-client" + "github.com/hazelcast/hazelcast-go-client/serialization" + "github.com/hazelcast/hazelcast-go-client/types" "github.com/stretchr/testify/require" _ "github.com/hazelcast/hazelcast-commandline-client/base/commands" @@ -165,10 +168,43 @@ $ | | %s | | | $-----------------------------------------------------------------------------------------------------------------------------$`, p1, p2, p1, p2) tcx.AssertStdoutDollar(target) }) + // di + tcx.WithReset(func() { + mm, err := tcx.Client.GetMap(ctx, "default") + check.Must(err) + check.Must(addIndex(mm)) + tcx.WriteStdinf("\\di\n") + tcx.AssertStdoutDollarWithPath("testdata/list_indexes.txt") + }) + // di NAME + tcx.WithReset(func() { + mm, err := tcx.Client.GetMap(ctx, "default") + check.Must(err) + check.Must(addIndex(mm)) + tcx.WriteStdinf("\\di default\n") + tcx.AssertStdoutDollarWithPath("testdata/list_indexes.txt") + }) }) }) } +func addIndex(m *hz.Map) error { + err := m.Set(context.Background(), "k1", serialization.JSON(`{"A": 10, "B": 40}`)) + if err != nil { + return err + } + indexConfig := types.IndexConfig{ + Name: "my-index", + Type: types.IndexTypeSorted, + Attributes: []string{"A"}, + BitmapIndexOptions: types.BitmapIndexOptions{UniqueKey: "B", UniqueKeyTransformation: types.UniqueKeyTransformationLong}, + } + if err = m.AddIndex(context.Background(), indexConfig); err != nil { + return err + } + return nil +} + func sqlSuggestion_Interactive(t *testing.T) { tcx := it.TestContext{T: t} tcx.Tester(func(tcx it.TestContext) { diff --git a/base/commands/sql/testdata/list_indexes.txt b/base/commands/sql/testdata/list_indexes.txt new file mode 100644 index 00000000..92a1c851 --- /dev/null +++ b/base/commands/sql/testdata/list_indexes.txt @@ -0,0 +1,5 @@ +$----------------------------------$ +$ Map Name | Name | Attributes $ +$----------------------------------$ +$ default | my-index | [A] $ +$----------------------------------$ \ No newline at end of file diff --git a/base/commands/sql/testdata/sql_help.txt b/base/commands/sql/testdata/sql_help.txt index 641d5073..15eb8645 100644 --- a/base/commands/sql/testdata/sql_help.txt +++ b/base/commands/sql/testdata/sql_help.txt @@ -1,6 +1,8 @@ $Shortcut Commands:$ +$\di List Indexes$ +$\di MAPPING List Indexes for a specific mapping$ $\dm List mappings$ $\dm MAPPING Display information about a mapping$ $\dm+ MAPPING Describe a mapping$ $\exit Exit the shell$ -$\help Display help for CLC commands$ +$\help Display help for CLC commands$ \ No newline at end of file diff --git a/base/maps/maps.go b/base/maps/maps.go new file mode 100644 index 00000000..e85aeba6 --- /dev/null +++ b/base/maps/maps.go @@ -0,0 +1,74 @@ +package maps + +import ( + "context" + "fmt" + + "github.com/hazelcast/hazelcast-commandline-client/base/commands/object" + "github.com/hazelcast/hazelcast-commandline-client/base/objects" + "github.com/hazelcast/hazelcast-commandline-client/clc" + "github.com/hazelcast/hazelcast-commandline-client/internal/output" + "github.com/hazelcast/hazelcast-commandline-client/internal/plug" + "github.com/hazelcast/hazelcast-commandline-client/internal/proto/codec" + "github.com/hazelcast/hazelcast-commandline-client/internal/serialization" + "github.com/hazelcast/hazelcast-go-client/types" +) + +func Indexes(ctx context.Context, ec plug.ExecContext, mapName string) error { + var mapNames []string + if mapName != "" { + mapNames = append(mapNames, mapName) + } else { + maps, err := objects.GetAll(ctx, ec, object.Map, false) + if err != nil { + return err + } + for _, mm := range maps { + mapNames = append(mapNames, mm.Name) + } + } + ci, err := ec.ClientInternal(ctx) + if err != nil { + return err + } + resp, stop, err := ec.ExecuteBlocking(ctx, func(ctx context.Context, sp clc.Spinner) (any, error) { + allIndexes := make(map[string][]types.IndexConfig) + for _, mn := range mapNames { + sp.SetText(fmt.Sprintf("Getting indexes of map %s", mn)) + req := codec.EncodeMCGetMapConfigRequest(mn) + // If member configurations are different, this may not work well, however it is nothing to do with CLC + resp, err := ci.InvokeOnRandomTarget(ctx, req, nil) + if err != nil { + return nil, err + } + _, _, _, _, _, _, _, _, _, _, globalIndexes := codec.DecodeMCGetMapConfigResponse(resp) + if err != nil { + return nil, err + } + allIndexes[mn] = globalIndexes + } + return allIndexes, nil + }) + stop() + var rows []output.Row + for mn, indexes := range resp.(map[string][]types.IndexConfig) { + for _, index := range indexes { + rows = append(rows, + output.Row{ + output.Column{ + Name: "Map Name", + Type: serialization.TypeString, + Value: mn, + }, output.Column{ + Name: "Name", + Type: serialization.TypeString, + Value: index.Name, + }, output.Column{ + Name: "Attributes", + Type: serialization.TypeStringArray, + Value: index.Attributes, + }}) + } + } + return ec.AddOutputRows(ctx, rows...) +} diff --git a/base/objects/objects.go b/base/objects/objects.go new file mode 100644 index 00000000..1228df59 --- /dev/null +++ b/base/objects/objects.go @@ -0,0 +1,61 @@ +package objects + +import ( + "context" + "sort" + "strings" + + "github.com/hazelcast/hazelcast-commandline-client/clc" + "github.com/hazelcast/hazelcast-commandline-client/internal/plug" + "github.com/hazelcast/hazelcast-go-client/types" +) + +func GetAll(ctx context.Context, ec plug.ExecContext, typeFilter string, showHidden bool) ([]types.DistributedObjectInfo, error) { + ci, err := ec.ClientInternal(ctx) + if err != nil { + return nil, err + } + objs, stop, err := ec.ExecuteBlocking(ctx, func(ctx context.Context, sp clc.Spinner) (any, error) { + sp.SetText("Getting distributed objects") + return ci.Client().GetDistributedObjectsInfo(ctx) + }) + if err != nil { + return nil, err + } + stop() + var r []types.DistributedObjectInfo + typeFilter = strings.ToLower(typeFilter) + for _, o := range objs.([]types.DistributedObjectInfo) { + if !showHidden && (o.Name == "" || strings.HasPrefix(o.Name, "__")) { + continue + } + if o.Name == "" { + o.Name = "(no name)" + } + if typeFilter == "" { + r = append(r, o) + continue + } + if typeFilter == ShortType(o.ServiceName) { + r = append(r, o) + } + } + sort.Slice(r, func(i, j int) bool { + // first sort by type, then name + ri := r[i] + rj := r[j] + if ri.ServiceName < rj.ServiceName { + return true + } + if ri.ServiceName > rj.ServiceName { + return false + } + return ri.Name < rj.Name + }) + return r, nil +} + +func ShortType(svcName string) string { + s := strings.TrimSuffix(strings.TrimPrefix(svcName, "hz:impl:"), "Service") + return strings.ToLower(s) +} diff --git a/clc/shell/common.go b/clc/shell/common.go index c293e478..8d66261a 100644 --- a/clc/shell/common.go +++ b/clc/shell/common.go @@ -1,62 +1,98 @@ package shell import ( + "context" "errors" "fmt" "strings" + + "github.com/hazelcast/hazelcast-commandline-client/base/maps" + "github.com/hazelcast/hazelcast-commandline-client/clc/sql" + "github.com/hazelcast/hazelcast-commandline-client/internal/plug" ) const CmdPrefix = `\` var ErrHelp = errors.New("interactive help") -func ConvertStatement(stmt string) (string, error) { +func ConvertStatement(ctx context.Context, ec plug.ExecContext, stmt string, verbose bool) (func() error, error) { + var query string stmt = strings.TrimSpace(stmt) if strings.HasPrefix(stmt, "help") { - return "", ErrHelp + return nil, ErrHelp } if strings.HasPrefix(stmt, CmdPrefix) { // this is a shell command stmt = strings.TrimPrefix(stmt, CmdPrefix) parts := strings.Fields(stmt) switch parts[0] { - case "dm": + case "di": if len(parts) == 1 { - return "show mappings;", nil + return func() error { + return maps.Indexes(ctx, ec, "") + }, nil } if len(parts) == 2 { + return func() error { + return maps.Indexes(ctx, ec, parts[1]) + }, nil + } else { + return nil, fmt.Errorf("Usage: %sdi [mapping]", CmdPrefix) + } + case "dm": + if len(parts) == 1 { + query = "show mappings;" + } else if len(parts) == 2 { // escape single quote mn := strings.Replace(parts[1], "'", "''", -1) - return fmt.Sprintf(` + query = fmt.Sprintf(` SELECT * FROM information_schema.mappings WHERE table_name = '%s'; - `, mn), nil + `, mn) + } else { + return nil, fmt.Errorf("Usage: %sdm [mapping]", CmdPrefix) } - return "", fmt.Errorf("Usage: %sdm [mapping]", CmdPrefix) case "dm+": if len(parts) == 1 { - return "show mappings;", nil - } - if len(parts) == 2 { + query = "show mappings;" + } else if len(parts) == 2 { // escape single quote mn := strings.Replace(parts[1], "'", "''", -1) - return fmt.Sprintf(` + query = fmt.Sprintf(` SELECT * FROM information_schema.columns WHERE table_name = '%s'; - `, mn), nil + `, mn) + } else { + return nil, fmt.Errorf("Usage: %sdm+ [mapping]", CmdPrefix) } - return "", fmt.Errorf("Usage: %sdm+ [mapping]", CmdPrefix) case "exit": - return "", ErrExit + return nil, ErrExit + default: + return nil, fmt.Errorf("Unknown shell command: %s", stmt) + } + } else { + query = stmt + } + f := func() error { + res, stop, err := sql.ExecSQL(ctx, ec, query) + if err != nil { + return err + } + defer stop() + // TODO: update sql.UpdateOutput to use stdout + if err := sql.UpdateOutput(ctx, ec, res, verbose); err != nil { + return err } - return "", fmt.Errorf("Unknown shell command: %s", stmt) + return nil } - return stmt, nil + return f, nil } func InteractiveHelp() string { return ` Shortcut Commands: + \di List Indexes + \di MAPPING List Indexes for a specific mapping \dm List mappings \dm MAPPING Display information about a mapping \dm+ MAPPING Describe a mapping diff --git a/docs/modules/ROOT/pages/clc.adoc b/docs/modules/ROOT/pages/clc.adoc index 9d1bf209..d48a14d0 100644 --- a/docs/modules/ROOT/pages/clc.adoc +++ b/docs/modules/ROOT/pages/clc.adoc @@ -52,3 +52,76 @@ You can enter multiline commands by ending all lines except the last line with a replicatedmap | __sql.catalog ------------------------------------------------- ---- + +== Shortcut Commands + +* <> +* <> +* <> +* <> + +== exit +Exits the shell. + +Usage: + +[source,bash] +---- +exit +---- + +== help +Display help for CLC commands + +Usage: + +[source,bash] +---- +help +---- + +== di +Lists indexes. If you provide a mapping, it lists indexes to that specific mapping, otherwise it lists all the indexes. + +Usage: + +[source,bash] +---- +di [MAPPING] +---- + +Parameters: + +[cols="1m,1a,2a,1a"] +|=== +|Parameter|Required|Description|Default + +|`MAPPING` +|Optional +|Name of the mapping. +| + +|=== + +== dm(+) +If you don't provide the `MAPPING` parameter, it lists mappings. If you add `+` postfix, it describes the given mapping, otherwise it displays information about it. + +Usage: + +[source,bash] +---- +dm(+) [MAPPING] +---- + +Parameters: + +[cols="1m,1a,2a,1a"] +|=== +|Parameter|Required|Description|Default + +|`MAPPING` +|Optional +|Name of the mapping. +| + +|==== \ No newline at end of file diff --git a/internal/proto/codec/bitmap_index_options_codec.go b/internal/proto/codec/bitmap_index_options_codec.go new file mode 100644 index 00000000..fe3fe8cd --- /dev/null +++ b/internal/proto/codec/bitmap_index_options_codec.go @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2008-2021, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package codec + +import ( + proto "github.com/hazelcast/hazelcast-go-client" + "github.com/hazelcast/hazelcast-go-client/types" +) + +const ( + BitmapIndexOptionsCodecUniqueKeyTransformationFieldOffset = 0 + BitmapIndexOptionsCodecUniqueKeyTransformationInitialFrameSize = BitmapIndexOptionsCodecUniqueKeyTransformationFieldOffset + proto.IntSizeInBytes +) + +func DecodeBitmapIndexOptions(frameIterator *proto.ForwardFrameIterator) types.BitmapIndexOptions { + // begin frame + frameIterator.Next() + initialFrame := frameIterator.Next() + uniqueKeyTransformation := DecodeInt(initialFrame.Content, BitmapIndexOptionsCodecUniqueKeyTransformationFieldOffset) + + uniqueKey := DecodeString(frameIterator) + FastForwardToEndFrame(frameIterator) + return types.BitmapIndexOptions{UniqueKey: uniqueKey, UniqueKeyTransformation: types.UniqueKeyTransformation(uniqueKeyTransformation)} +} diff --git a/internal/proto/codec/builtin.go b/internal/proto/codec/builtin.go index 9f012494..0482768c 100644 --- a/internal/proto/codec/builtin.go +++ b/internal/proto/codec/builtin.go @@ -266,3 +266,23 @@ func DecodeListMultiFrameForData(frameIterator *proto.ForwardFrameIterator) []*i frameIterator.Next() return result } + +func DecodeListMultiFrameForIndexConfig(frameIterator *proto.ForwardFrameIterator) []types.IndexConfig { + var result []types.IndexConfig + if frameIterator.HasNext() { + frameIterator.Next() + + for !NextFrameIsDataStructureEndFrame(frameIterator) { + result = append(result, DecodeIndexConfig(frameIterator)) + } + frameIterator.Next() + } + return result +} + +func DecodeNullableForBitmapIndexOptions(frameIterator *proto.ForwardFrameIterator) types.BitmapIndexOptions { + if NextFrameIsNullFrame(frameIterator) { + return types.BitmapIndexOptions{} + } + return DecodeBitmapIndexOptions(frameIterator) +} diff --git a/internal/proto/codec/index_config_codec.go b/internal/proto/codec/index_config_codec.go new file mode 100644 index 00000000..8be4dffe --- /dev/null +++ b/internal/proto/codec/index_config_codec.go @@ -0,0 +1,47 @@ +/* +* Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License") +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. + */ + +package codec + +import ( + proto "github.com/hazelcast/hazelcast-go-client" + "github.com/hazelcast/hazelcast-go-client/types" + pubtypes "github.com/hazelcast/hazelcast-go-client/types" +) + +const ( + IndexConfigCodecTypeFieldOffset = 0 + IndexConfigCodecTypeInitialFrameSize = IndexConfigCodecTypeFieldOffset + proto.IntSizeInBytes +) + +func DecodeIndexConfig(frameIterator *proto.ForwardFrameIterator) pubtypes.IndexConfig { + // begin frame + frameIterator.Next() + initialFrame := frameIterator.Next() + _type := DecodeInt(initialFrame.Content, IndexConfigCodecTypeFieldOffset) + + name := DecodeNullableForString(frameIterator) + attributes := DecodeListMultiFrameForString(frameIterator) + bitmapIndexOptions := DecodeNullableForBitmapIndexOptions(frameIterator) + FastForwardToEndFrame(frameIterator) + + return pubtypes.IndexConfig{ + Name: name, + Type: types.IndexType(_type), + Attributes: attributes, + BitmapIndexOptions: bitmapIndexOptions, + } +} diff --git a/internal/proto/codec/mc_get_map_config_codec.go b/internal/proto/codec/mc_get_map_config_codec.go new file mode 100644 index 00000000..b6571434 --- /dev/null +++ b/internal/proto/codec/mc_get_map_config_codec.go @@ -0,0 +1,73 @@ +/* +* Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License") +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. + */ + +package codec + +import ( + proto "github.com/hazelcast/hazelcast-go-client" + pubtypes "github.com/hazelcast/hazelcast-go-client/types" +) + +const ( + MCGetMapConfigCodecRequestMessageType = int32(0x200300) + MCGetMapConfigCodecResponseMessageType = int32(0x200301) + + MCGetMapConfigCodecRequestInitialFrameSize = proto.PartitionIDOffset + proto.IntSizeInBytes + + MCGetMapConfigResponseInMemoryFormatOffset = proto.ResponseBackupAcksOffset + proto.ByteSizeInBytes + MCGetMapConfigResponseBackupCountOffset = MCGetMapConfigResponseInMemoryFormatOffset + proto.IntSizeInBytes + MCGetMapConfigResponseAsyncBackupCountOffset = MCGetMapConfigResponseBackupCountOffset + proto.IntSizeInBytes + MCGetMapConfigResponseTimeToLiveSecondsOffset = MCGetMapConfigResponseAsyncBackupCountOffset + proto.IntSizeInBytes + MCGetMapConfigResponseMaxIdleSecondsOffset = MCGetMapConfigResponseTimeToLiveSecondsOffset + proto.IntSizeInBytes + MCGetMapConfigResponseMaxSizeOffset = MCGetMapConfigResponseMaxIdleSecondsOffset + proto.IntSizeInBytes + MCGetMapConfigResponseMaxSizePolicyOffset = MCGetMapConfigResponseMaxSizeOffset + proto.IntSizeInBytes + MCGetMapConfigResponseReadBackupDataOffset = MCGetMapConfigResponseMaxSizePolicyOffset + proto.IntSizeInBytes + MCGetMapConfigResponseEvictionPolicyOffset = MCGetMapConfigResponseReadBackupDataOffset + proto.BooleanSizeInBytes +) + +// Gets the config of a map on the member it's called on. + +func EncodeMCGetMapConfigRequest(mapName string) *proto.ClientMessage { + clientMessage := proto.NewClientMessageForEncode() + clientMessage.SetRetryable(true) + + initialFrame := proto.NewFrameWith(make([]byte, MCGetMapConfigCodecRequestInitialFrameSize), proto.UnfragmentedMessage) + clientMessage.AddFrame(initialFrame) + clientMessage.SetMessageType(MCGetMapConfigCodecRequestMessageType) + clientMessage.SetPartitionId(-1) + + EncodeString(clientMessage, mapName) + + return clientMessage +} + +func DecodeMCGetMapConfigResponse(clientMessage *proto.ClientMessage) (inMemoryFormat int32, backupCount int32, asyncBackupCount int32, timeToLiveSeconds int32, maxIdleSeconds int32, maxSize int32, maxSizePolicy int32, readBackupData bool, evictionPolicy int32, mergePolicy string, globalIndexes []pubtypes.IndexConfig) { + frameIterator := clientMessage.FrameIterator() + initialFrame := frameIterator.Next() + + inMemoryFormat = DecodeInt(initialFrame.Content, MCGetMapConfigResponseInMemoryFormatOffset) + backupCount = DecodeInt(initialFrame.Content, MCGetMapConfigResponseBackupCountOffset) + asyncBackupCount = DecodeInt(initialFrame.Content, MCGetMapConfigResponseAsyncBackupCountOffset) + timeToLiveSeconds = DecodeInt(initialFrame.Content, MCGetMapConfigResponseTimeToLiveSecondsOffset) + maxIdleSeconds = DecodeInt(initialFrame.Content, MCGetMapConfigResponseMaxIdleSecondsOffset) + maxSize = DecodeInt(initialFrame.Content, MCGetMapConfigResponseMaxSizeOffset) + maxSizePolicy = DecodeInt(initialFrame.Content, MCGetMapConfigResponseMaxSizePolicyOffset) + readBackupData = DecodeBoolean(initialFrame.Content, MCGetMapConfigResponseReadBackupDataOffset) + evictionPolicy = DecodeInt(initialFrame.Content, MCGetMapConfigResponseEvictionPolicyOffset) + mergePolicy = DecodeString(frameIterator) + globalIndexes = DecodeListMultiFrameForIndexConfig(frameIterator) + return inMemoryFormat, backupCount, asyncBackupCount, timeToLiveSeconds, maxIdleSeconds, maxSize, maxSizePolicy, readBackupData, evictionPolicy, mergePolicy, globalIndexes +}