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 +}