From f25ee1703a692e649cf0f965cc37acc00a88e5e3 Mon Sep 17 00:00:00 2001 From: Nathan Haim Date: Wed, 11 Dec 2024 12:29:31 +0100 Subject: [PATCH 1/3] feat: add optional file flags for cli view add command --- cli/view_add.go | 64 ++++++++++++++++++++++++++-------- cli/view_add_test.go | 83 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 14 deletions(-) create mode 100644 cli/view_add_test.go diff --git a/cli/view_add.go b/cli/view_add.go index 9c7d42b723..e75fcac2de 100644 --- a/cli/view_add.go +++ b/cli/view_add.go @@ -22,8 +22,10 @@ import ( ) func MakeViewAddCommand() *cobra.Command { + var queryFile string + var sdlFile string var lensFile string - var cmd = &cobra.Command{ + cmd := &cobra.Command{ Use: "add [query] [sdl] [transform]", Short: "Add new view", Long: `Add new database view. @@ -36,25 +38,26 @@ Learn more about the DefraDB GraphQL Schema Language on https://docs.source.netw RunE: func(cmd *cobra.Command, args []string) error { store := mustGetContextStore(cmd) - query := args[0] - sdl := args[1] + fileOrArg := newFileOrArgData(args, os.ReadFile) + query, err := fileOrArg.next(queryFile) + if err != nil { + return err + } + sdl, err := fileOrArg.next(sdlFile) + if err != nil { + return err + } + lensCfgJson, err := fileOrArg.next(lensFile) + if err != nil { + return err + } - var lensCfgJson string - switch { - case lensFile != "": - data, err := os.ReadFile(lensFile) - if err != nil { - return err - } - lensCfgJson = string(data) - case len(args) == 3 && args[2] == "-": + if lensCfgJson == "-" { data, err := io.ReadAll(cmd.InOrStdin()) if err != nil { return err } lensCfgJson = string(data) - case len(args) == 3: - lensCfgJson = args[2] } var transform immutable.Option[model.Lens] @@ -77,5 +80,38 @@ Learn more about the DefraDB GraphQL Schema Language on https://docs.source.netw }, } cmd.Flags().StringVarP(&lensFile, "file", "f", "", "Lens configuration file") + cmd.Flags().StringVarP(&queryFile, "query-file", "", "", "Query file") + cmd.Flags().StringVarP(&sdlFile, "sdl-file", "", "", "SDL file") return cmd } + +type readFileFn func(string) ([]byte, error) + +// FileOrArgData tracks a serie of args. +type FileOrArgData struct { + args []string + currentIndex int + readFile readFileFn +} + +func newFileOrArgData(args []string, readFile readFileFn) FileOrArgData { + return FileOrArgData{ + args: args, + currentIndex: 0, + readFile: readFile, + } +} + +// next gets the data primarily from a file when filePath is set, or from expected arg index. +func (x *FileOrArgData) next(filePath string) (string, error) { + if filePath == "" { + data := x.args[x.currentIndex] + x.currentIndex += 1 + return data, nil + } + data, err := x.readFile(filePath) + if err != nil { + return "", err + } + return string(data), nil +} diff --git a/cli/view_add_test.go b/cli/view_add_test.go new file mode 100644 index 0000000000..fd7c565b44 --- /dev/null +++ b/cli/view_add_test.go @@ -0,0 +1,83 @@ +// Copyright 2023 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package cli + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestFileOrArgData(t *testing.T) { + tests := []struct { + name string + args []string + filePaths []string + expectedRes []string + readFile readFileFn + }{ + { + name: "NoFile", + args: []string{"arg0", "arg1", "arg2"}, + filePaths: []string{"", "", ""}, + expectedRes: []string{"arg0", "arg1", "arg2"}, + }, + { + name: "FileFirst", + args: []string{"arg1", "arg2"}, + filePaths: []string{"file0", "", ""}, + expectedRes: []string{"file0", "arg1", "arg2"}, + }, + { + name: "FileMiddle", + args: []string{"arg0", "arg2"}, + filePaths: []string{"", "file0", ""}, + expectedRes: []string{"arg0", "file0", "arg2"}, + }, + { + name: "FileLast", + args: []string{"arg0", "arg1"}, + filePaths: []string{"", "", "file0"}, + expectedRes: []string{"arg0", "arg1", "file0"}, + }, + { + name: "FileFirstLast", + args: []string{"arg1"}, + filePaths: []string{"file0", "", "file1"}, + expectedRes: []string{"file0", "arg1", "file1"}, + }, + } + + for _, test := range tests { + fileReader := newMockReadFile() + getData := newFileOrArgData(test.args, fileReader.Read) + for i := range test.filePaths { + res, err := getData.next(test.filePaths[i]) + require.NoError(t, err) + require.Equal(t, test.expectedRes[i], res) + } + } +} + +type mockReadFile struct { + index int +} + +func newMockReadFile() mockReadFile { + return mockReadFile{} +} + +func (f *mockReadFile) Read(string) ([]byte, error) { + data := []byte(fmt.Sprintf("file%d", f.index)) + f.index += 1 + return data, nil +} From 018f72939dc8aa86e19fe8ad4a8c0a40f849a747 Mon Sep 17 00:00:00 2001 From: Nathan Haim Date: Thu, 12 Dec 2024 06:54:14 +0100 Subject: [PATCH 2/3] feat: cli (client view add) switch mix arg/flag to flag usage --- cli/view_add.go | 62 ++++++++++++++------------------- cli/view_add_test.go | 83 -------------------------------------------- 2 files changed, 26 insertions(+), 119 deletions(-) delete mode 100644 cli/view_add_test.go diff --git a/cli/view_add.go b/cli/view_add.go index e75fcac2de..74f13fd2d5 100644 --- a/cli/view_add.go +++ b/cli/view_add.go @@ -22,32 +22,34 @@ import ( ) func MakeViewAddCommand() *cobra.Command { - var queryFile string - var sdlFile string - var lensFile string + var query, sdl, lens string + var queryFile, sdlFile, lensFile string cmd := &cobra.Command{ - Use: "add [query] [sdl] [transform]", + Use: "add", Short: "Add new view", Long: `Add new database view. -Example: add from an argument string: - defradb client view add 'Foo { name, ...}' 'type Foo { ... }' '{"lenses": [...' +Example: add from string flags: + defradb client view add --query 'Foo { name, ...}' --sdl 'type Foo { ... }' --lens '{"lenses": [...' +Example: add from file flags: + defradb client view add --query-file /path/to/query --sdl-file /path/to/sdl --lens-file /path/to/lens + +Flag pairs /-file are mutually exclusive. Learn more about the DefraDB GraphQL Schema Language on https://docs.source.network.`, - Args: cobra.RangeArgs(2, 4), + Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { store := mustGetContextStore(cmd) - fileOrArg := newFileOrArgData(args, os.ReadFile) - query, err := fileOrArg.next(queryFile) + query, err := pickDataOrReadFile(query, queryFile) if err != nil { return err } - sdl, err := fileOrArg.next(sdlFile) + sdl, err := pickDataOrReadFile(sdl, sdlFile) if err != nil { return err } - lensCfgJson, err := fileOrArg.next(lensFile) + lensCfgJson, err := pickDataOrReadFile(lens, lensFile) if err != nil { return err } @@ -79,39 +81,27 @@ Learn more about the DefraDB GraphQL Schema Language on https://docs.source.netw return writeJSON(cmd, defs) }, } - cmd.Flags().StringVarP(&lensFile, "file", "f", "", "Lens configuration file") + cmd.Flags().StringVarP(&query, "query", "", "", "Query") cmd.Flags().StringVarP(&queryFile, "query-file", "", "", "Query file") + cmd.Flags().StringVarP(&sdl, "sdl", "", "", "SDL") cmd.Flags().StringVarP(&sdlFile, "sdl-file", "", "", "SDL file") - return cmd -} - -type readFileFn func(string) ([]byte, error) + cmd.Flags().StringVarP(&lens, "lens", "", "", "Lens configuration") + cmd.Flags().StringVarP(&lensFile, "lens-file", "", "", "Lens configuration file") -// FileOrArgData tracks a serie of args. -type FileOrArgData struct { - args []string - currentIndex int - readFile readFileFn -} - -func newFileOrArgData(args []string, readFile readFileFn) FileOrArgData { - return FileOrArgData{ - args: args, - currentIndex: 0, - readFile: readFile, - } + cmd.MarkFlagsMutuallyExclusive("query", "query-file") + cmd.MarkFlagsMutuallyExclusive("sdl", "sdl-file") + cmd.MarkFlagsMutuallyExclusive("lens", "lens-file") + return cmd } -// next gets the data primarily from a file when filePath is set, or from expected arg index. -func (x *FileOrArgData) next(filePath string) (string, error) { - if filePath == "" { - data := x.args[x.currentIndex] - x.currentIndex += 1 +// pickDataOrReadFile gets the result from file path when provided, or from data. +func pickDataOrReadFile(data string, dataPath string) (string, error) { + if dataPath == "" { return data, nil } - data, err := x.readFile(filePath) + b, err := os.ReadFile(dataPath) if err != nil { return "", err } - return string(data), nil + return string(b), nil } diff --git a/cli/view_add_test.go b/cli/view_add_test.go deleted file mode 100644 index fd7c565b44..0000000000 --- a/cli/view_add_test.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2023 Democratized Data Foundation -// -// Use of this software is governed by the Business Source License -// included in the file licenses/BSL.txt. -// -// As of the Change Date specified in that file, in accordance with -// the Business Source License, use of this software will be governed -// by the Apache License, Version 2.0, included in the file -// licenses/APL.txt. - -package cli - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestFileOrArgData(t *testing.T) { - tests := []struct { - name string - args []string - filePaths []string - expectedRes []string - readFile readFileFn - }{ - { - name: "NoFile", - args: []string{"arg0", "arg1", "arg2"}, - filePaths: []string{"", "", ""}, - expectedRes: []string{"arg0", "arg1", "arg2"}, - }, - { - name: "FileFirst", - args: []string{"arg1", "arg2"}, - filePaths: []string{"file0", "", ""}, - expectedRes: []string{"file0", "arg1", "arg2"}, - }, - { - name: "FileMiddle", - args: []string{"arg0", "arg2"}, - filePaths: []string{"", "file0", ""}, - expectedRes: []string{"arg0", "file0", "arg2"}, - }, - { - name: "FileLast", - args: []string{"arg0", "arg1"}, - filePaths: []string{"", "", "file0"}, - expectedRes: []string{"arg0", "arg1", "file0"}, - }, - { - name: "FileFirstLast", - args: []string{"arg1"}, - filePaths: []string{"file0", "", "file1"}, - expectedRes: []string{"file0", "arg1", "file1"}, - }, - } - - for _, test := range tests { - fileReader := newMockReadFile() - getData := newFileOrArgData(test.args, fileReader.Read) - for i := range test.filePaths { - res, err := getData.next(test.filePaths[i]) - require.NoError(t, err) - require.Equal(t, test.expectedRes[i], res) - } - } -} - -type mockReadFile struct { - index int -} - -func newMockReadFile() mockReadFile { - return mockReadFile{} -} - -func (f *mockReadFile) Read(string) ([]byte, error) { - data := []byte(fmt.Sprintf("file%d", f.index)) - f.index += 1 - return data, nil -} From 01b3e88a9c1aa08c2242f467568e9539baf511a9 Mon Sep 17 00:00:00 2001 From: Nathan Haim Date: Thu, 12 Dec 2024 06:55:39 +0100 Subject: [PATCH 3/3] docs: update cli (client view add) --- .../references/cli/defradb_client_view_add.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/docs/website/references/cli/defradb_client_view_add.md b/docs/website/references/cli/defradb_client_view_add.md index c5073d709b..fb20b343cf 100644 --- a/docs/website/references/cli/defradb_client_view_add.md +++ b/docs/website/references/cli/defradb_client_view_add.md @@ -6,20 +6,29 @@ Add new view Add new database view. -Example: add from an argument string: - defradb client view add 'Foo { name, ...}' 'type Foo { ... }' '{"lenses": [...' +Example: add from string flags: + defradb client view add --query 'Foo { name, ...}' --sdl 'type Foo { ... }' --lens '{"lenses": [...' +Example: add from file flags: + defradb client view add --query-file /path/to/query --sdl-file /path/to/sdl --lens-file /path/to/lens + +Flag pairs /-file are mutually exclusive. Learn more about the DefraDB GraphQL Schema Language on https://docs.source.network. ``` -defradb client view add [query] [sdl] [transform] [flags] +defradb client view add [flags] ``` ### Options ``` - -f, --file string Lens configuration file - -h, --help help for add + --lens string Lens configuration + --lens-file string Lens configuration file + --query string Query + --query-file string Query file + --sdl string SDL + --sdl-file string SDL file + -h, --help help for add ``` ### Options inherited from parent commands