From d98da81a428b559ed5c45444a9ebd6416c5aa34b Mon Sep 17 00:00:00 2001 From: Georges Chaudy Date: Mon, 8 Jul 2024 11:49:05 +0200 Subject: [PATCH] move sqltemplate --- pkg/services/store/entity/sqlstash/create.go | 2 +- pkg/services/store/entity/sqlstash/delete.go | 2 +- .../store/entity/sqlstash/folder_support.go | 2 +- pkg/services/store/entity/sqlstash/queries.go | 2 +- .../store/entity/sqlstash/queries_test.go | 2 +- .../entity/sqlstash/sql_storage_server.go | 2 +- .../sqlstash/sql_storage_server_test.go | 2 +- .../store/entity/sqlstash/sqltemplate/args.go | 85 --- .../entity/sqlstash/sqltemplate/args_test.go | 101 --- .../entity/sqlstash/sqltemplate/dialect.go | 140 ---- .../sqlstash/sqltemplate/dialect_mysql.go | 21 - .../sqltemplate/dialect_postgresql.go | 37 - .../sqltemplate/dialect_postgresql_test.go | 38 - .../sqlstash/sqltemplate/dialect_sqlite.go | 18 - .../sqlstash/sqltemplate/dialect_test.go | 184 ----- .../sqlstash/sqltemplate/example_test.go | 156 ---- .../store/entity/sqlstash/sqltemplate/into.go | 41 - .../entity/sqlstash/sqltemplate/into_test.go | 51 -- .../sqltemplate/mocks/SQLTemplateIface.go | 664 ---------------- .../sqlstash/sqltemplate/mocks/WithResults.go | 719 ------------------ .../sqlstash/sqltemplate/sqltemplate.go | 141 ---- .../sqlstash/sqltemplate/sqltemplate_test.go | 91 --- pkg/services/store/entity/sqlstash/update.go | 2 +- pkg/services/store/entity/sqlstash/utils.go | 2 +- .../store/entity/sqlstash/utils_test.go | 4 +- pkg/storage/unified/resource/server.go | 3 +- pkg/storage/unified/sql/backend.go | 26 +- pkg/storage/unified/sql/backend_test.go | 2 +- .../sql/sqltemplate/mocks/SQLTemplateIface.go | 2 +- .../sql/sqltemplate/mocks/WithResults.go | 2 +- pkg/storage/unified/sqlnext/sql_resources.go | 2 +- 31 files changed, 35 insertions(+), 2511 deletions(-) delete mode 100644 pkg/services/store/entity/sqlstash/sqltemplate/args.go delete mode 100644 pkg/services/store/entity/sqlstash/sqltemplate/args_test.go delete mode 100644 pkg/services/store/entity/sqlstash/sqltemplate/dialect.go delete mode 100644 pkg/services/store/entity/sqlstash/sqltemplate/dialect_mysql.go delete mode 100644 pkg/services/store/entity/sqlstash/sqltemplate/dialect_postgresql.go delete mode 100644 pkg/services/store/entity/sqlstash/sqltemplate/dialect_postgresql_test.go delete mode 100644 pkg/services/store/entity/sqlstash/sqltemplate/dialect_sqlite.go delete mode 100644 pkg/services/store/entity/sqlstash/sqltemplate/dialect_test.go delete mode 100644 pkg/services/store/entity/sqlstash/sqltemplate/example_test.go delete mode 100644 pkg/services/store/entity/sqlstash/sqltemplate/into.go delete mode 100644 pkg/services/store/entity/sqlstash/sqltemplate/into_test.go delete mode 100644 pkg/services/store/entity/sqlstash/sqltemplate/mocks/SQLTemplateIface.go delete mode 100644 pkg/services/store/entity/sqlstash/sqltemplate/mocks/WithResults.go delete mode 100644 pkg/services/store/entity/sqlstash/sqltemplate/sqltemplate.go delete mode 100644 pkg/services/store/entity/sqlstash/sqltemplate/sqltemplate_test.go diff --git a/pkg/services/store/entity/sqlstash/create.go b/pkg/services/store/entity/sqlstash/create.go index 85195b263e8..24b69454f8e 100644 --- a/pkg/services/store/entity/sqlstash/create.go +++ b/pkg/services/store/entity/sqlstash/create.go @@ -11,7 +11,7 @@ import ( grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic" "github.com/grafana/grafana/pkg/services/store/entity" "github.com/grafana/grafana/pkg/services/store/entity/db" - "github.com/grafana/grafana/pkg/services/store/entity/sqlstash/sqltemplate" + "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" ) func (s *sqlEntityServer) Create(ctx context.Context, r *entity.CreateEntityRequest) (*entity.CreateEntityResponse, error) { diff --git a/pkg/services/store/entity/sqlstash/delete.go b/pkg/services/store/entity/sqlstash/delete.go index ac0b56f0a1f..74cd4b93a81 100644 --- a/pkg/services/store/entity/sqlstash/delete.go +++ b/pkg/services/store/entity/sqlstash/delete.go @@ -10,7 +10,7 @@ import ( grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic" "github.com/grafana/grafana/pkg/services/store/entity" "github.com/grafana/grafana/pkg/services/store/entity/db" - "github.com/grafana/grafana/pkg/services/store/entity/sqlstash/sqltemplate" + "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" ) func (s *sqlEntityServer) Delete(ctx context.Context, r *entity.DeleteEntityRequest) (*entity.DeleteEntityResponse, error) { diff --git a/pkg/services/store/entity/sqlstash/folder_support.go b/pkg/services/store/entity/sqlstash/folder_support.go index 2b264804819..e2a3c075c2c 100644 --- a/pkg/services/store/entity/sqlstash/folder_support.go +++ b/pkg/services/store/entity/sqlstash/folder_support.go @@ -8,7 +8,7 @@ import ( folder "github.com/grafana/grafana/pkg/apis/folder/v0alpha1" "github.com/grafana/grafana/pkg/services/store/entity/db" - "github.com/grafana/grafana/pkg/services/store/entity/sqlstash/sqltemplate" + "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" ) type folderInfo struct { diff --git a/pkg/services/store/entity/sqlstash/queries.go b/pkg/services/store/entity/sqlstash/queries.go index 5a91f56bc0e..f82e07a1cfb 100644 --- a/pkg/services/store/entity/sqlstash/queries.go +++ b/pkg/services/store/entity/sqlstash/queries.go @@ -16,7 +16,7 @@ import ( grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic" "github.com/grafana/grafana/pkg/services/store/entity" "github.com/grafana/grafana/pkg/services/store/entity/db" - "github.com/grafana/grafana/pkg/services/store/entity/sqlstash/sqltemplate" + "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" ) // Templates setup. diff --git a/pkg/services/store/entity/sqlstash/queries_test.go b/pkg/services/store/entity/sqlstash/queries_test.go index ca34342bc4d..61038fde0a9 100644 --- a/pkg/services/store/entity/sqlstash/queries_test.go +++ b/pkg/services/store/entity/sqlstash/queries_test.go @@ -16,7 +16,7 @@ import ( grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic" "github.com/grafana/grafana/pkg/services/store/entity" "github.com/grafana/grafana/pkg/services/store/entity/db" - "github.com/grafana/grafana/pkg/services/store/entity/sqlstash/sqltemplate" + "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" "github.com/grafana/grafana/pkg/util/testutil" ) diff --git a/pkg/services/store/entity/sqlstash/sql_storage_server.go b/pkg/services/store/entity/sqlstash/sql_storage_server.go index 723bf34c52d..219c454e9bf 100644 --- a/pkg/services/store/entity/sqlstash/sql_storage_server.go +++ b/pkg/services/store/entity/sqlstash/sql_storage_server.go @@ -25,8 +25,8 @@ import ( "github.com/grafana/grafana/pkg/services/sqlstore/session" "github.com/grafana/grafana/pkg/services/store/entity" "github.com/grafana/grafana/pkg/services/store/entity/db" - "github.com/grafana/grafana/pkg/services/store/entity/sqlstash/sqltemplate" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" ) const entityTable = "entity" diff --git a/pkg/services/store/entity/sqlstash/sql_storage_server_test.go b/pkg/services/store/entity/sqlstash/sql_storage_server_test.go index 938f7f85ed0..c5cb4b33354 100644 --- a/pkg/services/store/entity/sqlstash/sql_storage_server_test.go +++ b/pkg/services/store/entity/sqlstash/sql_storage_server_test.go @@ -10,7 +10,7 @@ import ( "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/sqlstore/session" "github.com/grafana/grafana/pkg/services/store/entity" - "github.com/grafana/grafana/pkg/services/store/entity/sqlstash/sqltemplate" + "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" "github.com/grafana/grafana/pkg/util/testutil" ) diff --git a/pkg/services/store/entity/sqlstash/sqltemplate/args.go b/pkg/services/store/entity/sqlstash/sqltemplate/args.go deleted file mode 100644 index eac4452ea37..00000000000 --- a/pkg/services/store/entity/sqlstash/sqltemplate/args.go +++ /dev/null @@ -1,85 +0,0 @@ -package sqltemplate - -import ( - "errors" - "reflect" - "strings" -) - -// Args errors. -var ( - ErrInvalidArgList = errors.New("invalid arglist") -) - -// Args keeps the data that needs to be passed to the engine for execution in -// the right order. Add it to your data types passed to SQLTemplate, either by -// embedding or with a named struct field if its Arg method would clash with -// another struct field. -type Args struct { - d interface{ ArgPlaceholder(argNum int) string } - values []any -} - -func NewArgs(d Dialect) *Args { - return &Args{ - d: d, - } -} - -// Arg can be called from within templates to pass arguments to the SQL driver -// to use in the execution of the query. -func (a *Args) Arg(x any) string { - a.values = append(a.values, x) - - return a.d.ArgPlaceholder(len(a.values)) -} - -// ArgList returns a comma separated list of `?` placeholders for each element -// in the provided slice argument, calling Arg for each of them. -// Example struct: -// -// type sqlMyRequest struct { -// *sqltemplate.SQLTemplate -// IDs []int64 -// } -// -// Example usage in a SQL template: -// -// DELETE FROM {{ .Ident "mytab" }} -// WHERE id IN ( {{ argList . .IDs }} ) -// ; -func (a *Args) ArgList(slice reflect.Value) (string, error) { - if !slice.IsValid() || slice.Kind() != reflect.Slice { - return "", ErrInvalidArgList - } - sliceLen := slice.Len() - if sliceLen == 0 { - return "", nil - } - - var b strings.Builder - b.Grow(3*sliceLen - 2) // the list will be ?, ?, ? - for i, l := 0, slice.Len(); i < l; i++ { - if i > 0 { - b.WriteString(", ") - } - b.WriteString(a.Arg(slice.Index(i).Interface())) - } - - return b.String(), nil -} - -func (a *Args) Reset() { - a.values = nil -} - -func (a *Args) GetArgs() []any { - return a.values -} - -type ArgsIface interface { - Arg(x any) string - ArgList(slice reflect.Value) (string, error) - GetArgs() []any - Reset() -} diff --git a/pkg/services/store/entity/sqlstash/sqltemplate/args_test.go b/pkg/services/store/entity/sqlstash/sqltemplate/args_test.go deleted file mode 100644 index 5399db21ae1..00000000000 --- a/pkg/services/store/entity/sqlstash/sqltemplate/args_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package sqltemplate - -import ( - "errors" - "reflect" - "testing" -) - -func TestArgs_Arg(t *testing.T) { - t.Parallel() - - shouldBeQuestionMark := func(t *testing.T, s string) { - t.Helper() - if s != "?" { - t.Fatalf("expecting question mark, got %q", s) - } - } - - a := NewArgs(MySQL) - - shouldBeQuestionMark(t, a.Arg(0)) - shouldBeQuestionMark(t, a.Arg(1)) - shouldBeQuestionMark(t, a.Arg(2)) - shouldBeQuestionMark(t, a.Arg(3)) - shouldBeQuestionMark(t, a.Arg(4)) - - for i, arg := range a.GetArgs() { - v, ok := arg.(int) - if !ok { - t.Fatalf("unexpected value: %T(%v)", arg, arg) - } - if v != i { - t.Fatalf("unexpected int value: %v", v) - } - } -} - -func TestArg_ArgList(t *testing.T) { - t.Parallel() - - testCases := []struct { - input reflect.Value - added []any - output string - err error - }{ - {err: ErrInvalidArgList}, - {input: reflect.ValueOf(1), err: ErrInvalidArgList}, - {input: reflect.ValueOf(nil), err: ErrInvalidArgList}, - {input: reflect.ValueOf(any(nil)), err: ErrInvalidArgList}, - {input: reflect.ValueOf("asd"), err: ErrInvalidArgList}, - {input: reflect.ValueOf([]any{})}, - - { - input: reflect.ValueOf([]any{true}), - added: []any{true}, - output: "?", - }, - - { - input: reflect.ValueOf([]any{1, true}), - added: []any{1, true}, - output: "?, ?", - }, - - { - input: reflect.ValueOf([]any{1, "asd", true}), - added: []any{1, "asd", true}, - output: "?, ?, ?", - }, - } - - var a Args - a.d = argFmtSQL92 - for i, tc := range testCases { - a.Reset() - - gotOutput, gotErr := a.ArgList(tc.input) - if !errors.Is(gotErr, tc.err) { - t.Fatalf("[test #%d] Unexpected error. Expected: %v, actual: %v", - i, gotErr, tc.err) - } - - if tc.output != gotOutput { - t.Fatalf("[test #%d] Unexpected output. Expected: %v, actual: %v", - i, gotOutput, tc.output) - } - - if len(tc.added) != len(a.values) { - t.Fatalf("[test #%d] Unexpected added items.\n\tExpected: %#v\n\t"+ - "Actual: %#v", i, tc.added, a.values) - } - - for j := range tc.added { - if !reflect.DeepEqual(tc.added[j], a.values[j]) { - t.Fatalf("[test #%d] Unexpected %d-eth item.\n\tExpected:"+ - " %#v\n\tActual: %#v", i, j, tc.added[j], a.values[j]) - } - } - } -} diff --git a/pkg/services/store/entity/sqlstash/sqltemplate/dialect.go b/pkg/services/store/entity/sqlstash/sqltemplate/dialect.go deleted file mode 100644 index 2824d783059..00000000000 --- a/pkg/services/store/entity/sqlstash/sqltemplate/dialect.go +++ /dev/null @@ -1,140 +0,0 @@ -package sqltemplate - -import ( - "errors" - "strconv" - "strings" -) - -// Dialect-agnostic errors. -var ( - ErrEmptyIdent = errors.New("empty identifier") - ErrInvalidRowLockingClause = errors.New("invalid row-locking clause") -) - -// Dialect should be added to the data types passed to SQL templates to -// provide methods that deal with SQL implementation-specific traits. It can be -// embedded for ease of use, or with a named struct field if any of its methods -// would clash with other struct field names. -type Dialect interface { - // Name identifies the Dialect. Note that a Dialect may be common to more - // than one DBMS (e.g. "postgres" is common to PostgreSQL and to - // CockroachDB), while we can maintain different Dialects for the same DBMS - // but different versions (e.g. "mysql5" and "mysql8"). - Name() string - - // Ident returns the given string quoted in a way that is suitable to be - // used as an identifier. Database names, schema names, table names, column - // names are all examples of identifiers. - Ident(string) (string, error) - - // ArgPlaceholder returns a safe argument suitable to be used in a SQL - // prepared statement for the argNum-eth argument passed in execution - // (starting at 1). The SQL92 Standard specifies the question mark ('?') - // should be used in all cases, but some implementations differ. - ArgPlaceholder(argNum int) string - - // SelectFor parses and returns the given row-locking clause for a SELECT - // statement. If the clause is invalid it returns an error. Implementations - // of this method should use ParseRowLockingClause. - // Example: - // - // SELECT * - // FROM mytab - // WHERE id = ? - // {{ .SelectFor "Update NoWait" }}; -- will be uppercased - SelectFor(...string) (string, error) -} - -// RowLockingClause represents a row-locking clause in a SELECT statement. -type RowLockingClause string - -// Valid returns whether the given option is valid. -func (o RowLockingClause) Valid() bool { - switch o { - case SelectForShare, SelectForShareNoWait, SelectForShareSkipLocked, - SelectForUpdate, SelectForUpdateNoWait, SelectForUpdateSkipLocked: - return true - } - return false -} - -// ParseRowLockingClause parses a RowLockingClause from the given strings. This -// should be used by implementations of Dialect to parse the input of the -// SelectFor method. -func ParseRowLockingClause(s ...string) (RowLockingClause, error) { - opt := RowLockingClause(strings.ToUpper(strings.Join(s, " "))) - if !opt.Valid() { - return "", ErrInvalidRowLockingClause - } - - return opt, nil -} - -// Row-locking clause options. -const ( - SelectForShare RowLockingClause = "SHARE" - SelectForShareNoWait RowLockingClause = "SHARE NOWAIT" - SelectForShareSkipLocked RowLockingClause = "SHARE SKIP LOCKED" - SelectForUpdate RowLockingClause = "UPDATE" - SelectForUpdateNoWait RowLockingClause = "UPDATE NOWAIT" - SelectForUpdateSkipLocked RowLockingClause = "UPDATE SKIP LOCKED" -) - -type rowLockingClauseMap map[RowLockingClause]RowLockingClause - -func (rlc rowLockingClauseMap) SelectFor(s ...string) (string, error) { - // all implementations should err on invalid input, otherwise we would just - // be hiding the error until we change the dialect - o, err := ParseRowLockingClause(s...) - if err != nil { - return "", err - } - - var ret string - if len(rlc) > 0 { - ret = "FOR " + string(rlc[o]) - } - - return ret, nil -} - -var rowLockingClauseAll = rowLockingClauseMap{ - SelectForShare: SelectForShare, - SelectForShareNoWait: SelectForShareNoWait, - SelectForShareSkipLocked: SelectForShareSkipLocked, - SelectForUpdate: SelectForUpdate, - SelectForUpdateNoWait: SelectForUpdateNoWait, - SelectForUpdateSkipLocked: SelectForUpdateSkipLocked, -} - -// standardIdent provides standard SQL escaping of identifiers. -type standardIdent struct{} - -func (standardIdent) Ident(s string) (string, error) { - if s == "" { - return "", ErrEmptyIdent - } - return `"` + strings.ReplaceAll(s, `"`, `""`) + `"`, nil -} - -type argPlaceholderFunc func(int) string - -func (f argPlaceholderFunc) ArgPlaceholder(argNum int) string { - return f(argNum) -} - -var ( - argFmtSQL92 = argPlaceholderFunc(func(int) string { - return "?" - }) - argFmtPositional = argPlaceholderFunc(func(argNum int) string { - return "$" + strconv.Itoa(argNum) - }) -) - -type name string - -func (n name) Name() string { - return string(n) -} diff --git a/pkg/services/store/entity/sqlstash/sqltemplate/dialect_mysql.go b/pkg/services/store/entity/sqlstash/sqltemplate/dialect_mysql.go deleted file mode 100644 index 705c8c9eca4..00000000000 --- a/pkg/services/store/entity/sqlstash/sqltemplate/dialect_mysql.go +++ /dev/null @@ -1,21 +0,0 @@ -package sqltemplate - -// MySQL is the default implementation of Dialect for the MySQL DMBS, currently -// supporting MySQL-8.x. It relies on having ANSI_QUOTES SQL Mode enabled. For -// more information about ANSI_QUOTES and SQL Modes see: -// -// https://dev.mysql.com/doc/refman/8.4/en/sql-mode.html#sqlmode_ansi_quotes -var MySQL = mysql{ - rowLockingClauseMap: rowLockingClauseAll, - argPlaceholderFunc: argFmtSQL92, - name: "mysql", -} - -var _ Dialect = MySQL - -type mysql struct { - standardIdent - rowLockingClauseMap - argPlaceholderFunc - name -} diff --git a/pkg/services/store/entity/sqlstash/sqltemplate/dialect_postgresql.go b/pkg/services/store/entity/sqlstash/sqltemplate/dialect_postgresql.go deleted file mode 100644 index 39e8603ae0b..00000000000 --- a/pkg/services/store/entity/sqlstash/sqltemplate/dialect_postgresql.go +++ /dev/null @@ -1,37 +0,0 @@ -package sqltemplate - -import ( - "errors" - "strings" -) - -// PostgreSQL is an implementation of Dialect for the PostgreSQL DMBS. -var PostgreSQL = postgresql{ - rowLockingClauseMap: rowLockingClauseAll, - argPlaceholderFunc: argFmtPositional, - name: "postgres", -} - -var _ Dialect = PostgreSQL - -// PostgreSQL-specific errors. -var ( - ErrPostgreSQLUnsupportedIdent = errors.New("identifiers in PostgreSQL cannot contain the character with code zero") -) - -type postgresql struct { - standardIdent - rowLockingClauseMap - argPlaceholderFunc - name -} - -func (p postgresql) Ident(s string) (string, error) { - // See: - // https://www.postgresql.org/docs/current/sql-syntax-lexical.html - if strings.IndexByte(s, 0) != -1 { - return "", ErrPostgreSQLUnsupportedIdent - } - - return p.standardIdent.Ident(s) -} diff --git a/pkg/services/store/entity/sqlstash/sqltemplate/dialect_postgresql_test.go b/pkg/services/store/entity/sqlstash/sqltemplate/dialect_postgresql_test.go deleted file mode 100644 index 11a7dcc2f41..00000000000 --- a/pkg/services/store/entity/sqlstash/sqltemplate/dialect_postgresql_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package sqltemplate - -import ( - "errors" - "testing" -) - -func TestPostgreSQL_Ident(t *testing.T) { - t.Parallel() - - testCases := []struct { - input string - output string - err error - }{ - {input: ``, err: ErrEmptyIdent}, - {input: `polite_example`, output: `"polite_example"`}, - {input: `Juan Carlos`, output: `"Juan Carlos"`}, - { - input: `unpolite_` + string([]byte{0}) + `example`, - err: ErrPostgreSQLUnsupportedIdent, - }, - { - input: `exaggerated " ' ` + "`" + ` example`, - output: `"exaggerated "" ' ` + "`" + ` example"`, - }, - } - - for i, tc := range testCases { - gotOutput, gotErr := PostgreSQL.Ident(tc.input) - if !errors.Is(gotErr, tc.err) { - t.Fatalf("unexpected error %v in test case %d", gotErr, i) - } - if gotOutput != tc.output { - t.Fatalf("unexpected error %v in test case %d", gotErr, i) - } - } -} diff --git a/pkg/services/store/entity/sqlstash/sqltemplate/dialect_sqlite.go b/pkg/services/store/entity/sqlstash/sqltemplate/dialect_sqlite.go deleted file mode 100644 index 8a41a8f2c4d..00000000000 --- a/pkg/services/store/entity/sqlstash/sqltemplate/dialect_sqlite.go +++ /dev/null @@ -1,18 +0,0 @@ -package sqltemplate - -// SQLite is an implementation of Dialect for the SQLite DMBS. -var SQLite = sqlite{ - argPlaceholderFunc: argFmtSQL92, - name: "sqlite", -} - -var _ Dialect = SQLite - -type sqlite struct { - // See: - // https://www.sqlite.org/lang_keywords.html - standardIdent - rowLockingClauseMap - argPlaceholderFunc - name -} diff --git a/pkg/services/store/entity/sqlstash/sqltemplate/dialect_test.go b/pkg/services/store/entity/sqlstash/sqltemplate/dialect_test.go deleted file mode 100644 index 987170fd6f3..00000000000 --- a/pkg/services/store/entity/sqlstash/sqltemplate/dialect_test.go +++ /dev/null @@ -1,184 +0,0 @@ -package sqltemplate - -import ( - "errors" - "strings" - "testing" -) - -func TestSelectForOption_Valid(t *testing.T) { - t.Parallel() - - testCases := []struct { - input RowLockingClause - expected bool - }{ - {input: "", expected: false}, - {input: "share", expected: false}, - {input: SelectForShare, expected: true}, - {input: SelectForShareNoWait, expected: true}, - {input: SelectForShareSkipLocked, expected: true}, - {input: SelectForUpdate, expected: true}, - {input: SelectForUpdateNoWait, expected: true}, - {input: SelectForUpdateSkipLocked, expected: true}, - } - - for i, tc := range testCases { - got := tc.input.Valid() - if got != tc.expected { - t.Fatalf("unexpected %v in test case %d", got, i) - } - } -} - -func TestParseRowLockingClause(t *testing.T) { - t.Parallel() - - splitSpace := func(s string) []string { - return strings.Split(s, " ") - } - - testCases := []struct { - input []string - output RowLockingClause - err error - }{ - {err: ErrInvalidRowLockingClause}, - { - input: []string{" " + string(SelectForShare)}, - err: ErrInvalidRowLockingClause, - }, - { - input: splitSpace(string(SelectForShareNoWait)), - output: SelectForShareNoWait, - }, - { - input: splitSpace(strings.ToLower(string(SelectForShareNoWait))), - output: SelectForShareNoWait, - }, - { - input: splitSpace(strings.ToTitle(string(SelectForShareNoWait))), - output: SelectForShareNoWait, - }, - } - - for i, tc := range testCases { - gotOutput, gotErr := ParseRowLockingClause(tc.input...) - if !errors.Is(gotErr, tc.err) { - t.Fatalf("unexpected error %v in test case %d", gotErr, i) - } - if gotOutput != (tc.output) { - t.Fatalf("unexpected output %q in test case %d", gotOutput, i) - } - } -} - -func TestRowLockingClauseMap_SelectFor(t *testing.T) { - t.Parallel() - - splitSpace := func(s string) []string { - return strings.Split(s, " ") - } - - testCases := []struct { - input []string - output RowLockingClause - err error - }{ - {err: ErrInvalidRowLockingClause}, - {input: []string{"invalid"}, err: ErrInvalidRowLockingClause}, - {input: []string{" share"}, err: ErrInvalidRowLockingClause}, - - { - input: splitSpace(string(SelectForShare)), - output: "FOR " + SelectForShare, - }, - } - - var nilRLC rowLockingClauseMap - for i, tc := range testCases { - gotOutput, gotErr := nilRLC.SelectFor(tc.input...) - if !errors.Is(gotErr, tc.err) { - t.Fatalf("[nil] unexpected error %v in test case %d", gotErr, i) - } - if gotOutput != "" { - t.Fatalf("[nil] unexpected output %v in test case %d", gotOutput, i) - } - - gotOutput, gotErr = rowLockingClauseAll.SelectFor(tc.input...) - if !errors.Is(gotErr, tc.err) { - t.Fatalf("[all] unexpected error %v in test case %d", gotErr, i) - } - if gotOutput != string(tc.output) { - t.Fatalf("[all] unexpected output %v in test case %d", gotOutput, i) - } - } -} - -func TestStandardIdent_Ident(t *testing.T) { - t.Parallel() - - testCases := []struct { - input string - output string - err error - }{ - {input: ``, err: ErrEmptyIdent}, - {input: `polite_example`, output: `"polite_example"`}, - {input: `Juan Carlos`, output: `"Juan Carlos"`}, - { - input: `exaggerated " ' ` + "`" + ` example`, - output: `"exaggerated "" ' ` + "`" + ` example"`, - }, - } - - for i, tc := range testCases { - gotOutput, gotErr := standardIdent{}.Ident(tc.input) - if !errors.Is(gotErr, tc.err) { - t.Fatalf("unexpected error %v in test case %d", gotErr, i) - } - if gotOutput != tc.output { - t.Fatalf("unexpected error %v in test case %d", gotErr, i) - } - } -} - -func TestArgPlaceholderFunc(t *testing.T) { - t.Parallel() - - testCases := []struct { - input int - valuePositional string - }{ - { - input: 1, - valuePositional: "$1", - }, - { - input: 16, - valuePositional: "$16", - }, - } - - for i, tc := range testCases { - got := argFmtSQL92(tc.input) - if got != "?" { - t.Fatalf("[argFmtSQL92] unexpected value %q in test case %d", got, i) - } - - got = argFmtPositional(tc.input) - if got != tc.valuePositional { - t.Fatalf("[argFmtPositional] unexpected value %q in test case %d", got, i) - } - } -} - -func TestName_Name(t *testing.T) { - t.Parallel() - - const v = "some dialect name" - n := name(v) - if n.Name() != v { - t.Fatalf("unexpected dialect name %q", n.Name()) - } -} diff --git a/pkg/services/store/entity/sqlstash/sqltemplate/example_test.go b/pkg/services/store/entity/sqlstash/sqltemplate/example_test.go deleted file mode 100644 index e8e8241f881..00000000000 --- a/pkg/services/store/entity/sqlstash/sqltemplate/example_test.go +++ /dev/null @@ -1,156 +0,0 @@ -package sqltemplate - -import ( - "fmt" - "regexp" - "strings" - "text/template" -) - -// This file contains runnable examples. They serve the purpose of providing -// idiomatic usage of the package as well as showing how it actually works, -// since the examples are actually run together with regular Go tests. Note that -// the "Output" comment section at the end of each function starting with -// "Example" is used by the standard Go test tool to check that the standard -// output of the function matches the commented text until the end of the -// function. If you change the function, you may need to adapt that comment -// section as it's possible that the output changes, causing it to fail tests. -// To learn more about Go's runnable tests, which are a core builtin feature of -// Go's standard testing library, see: -// https://pkg.go.dev/testing#hdr-Examples -// -// If you're unfamiliar with Go text templating language, please, consider -// reading that library's documentation first. - -// In this example we will use both Args and Dialect to dynamically and securely -// build SQL queries, while also keeping track of the arguments that need to be -// passed to the database methods to replace the placeholder "?" with the -// correct values. - -// We will start by assuming we receive a request to retrieve a user's -// information and that we need to provide a certain response. - -type GetUserRequest struct { - ID int -} - -type GetUserResponse struct { - ID int - Type string - Name string -} - -// Our template will take care for us of taking the request to build the query, -// and then sort the arguments for execution as well as preparing the values -// that need to be read for the response. We wil create a struct to pass the -// request and an empty response, as well as a *SQLTemplate that will provide -// the methods to achieve our purpose:: - -type GetUserQuery struct { - *SQLTemplate - Request *GetUserRequest - Response *GetUserResponse -} - -// And finally we will define our template, that is free to use all the power of -// the Go templating language, plus the methods we added with *SQLTemplate: -var getUserTmpl = template.Must(template.New("example").Parse(` - SELECT - {{ .Ident "id" | .Into .Response.ID }}, - {{ .Ident "type" | .Into .Response.Type }}, - {{ .Ident "name" | .Into .Response.Name }} - - FROM {{ .Ident "users" }} - WHERE - {{ .Ident "id" }} = {{ .Arg .Request.ID }}; -`)) - -// There are three interesting methods used in the above template: -// 1. Ident: safely escape a SQL identifier. Even though here the only -// identifier that may be problematic is "type" (because it is a reserved -// word in many dialects), it is a good practice to escape all identifiers -// just to make sure we're accounting for all variability in dialects, and -// also for consistency. -// 2. Into: this causes the selected field to be saved to the corresponding -// field of GetUserQuery. -// 3. Arg: this allows us to state that at this point will be a "?" that has to -// be populated with the value of the given field of GetUserQuery. - -func Example() { - // Let's pretend this example function is the handler of the GetUser method - // of our service to see how it all works together. - - queryData := &GetUserQuery{ - // The dialect (in this case we chose MySQL) should be set in your - // service at startup when you connect to your database - SQLTemplate: New(MySQL), - - // This is a synthetic request for our test - Request: &GetUserRequest{ - ID: 1, - }, - - // Create an empty response to be populated - Response: new(GetUserResponse), - } - - // The next step is to execute the query template for our queryData, and - // generate the arguments for the db.QueryRow and row.Scan methods later - query, err := Execute(getUserTmpl, queryData) - if err != nil { - panic(err) // terminate the runnable example on error - } - - // Assuming that we have a *sql.DB object named "db", we could now make our - // query with: - // row := db.QueryRowContext(ctx, query, queryData.GetArgs()...) - // // and check row.Err() here - - // As we're not actually running a database in this example, let's verify - // that we find our arguments populated as expected instead: - if len(queryData.GetArgs()) != 1 { - panic(fmt.Sprintf("unexpected number of args: %#v", queryData.Args)) - } - id, ok := queryData.GetArgs()[0].(int) - if !ok || id != queryData.Request.ID { - panic(fmt.Sprintf("unexpected args: %#v", queryData.Args)) - } - - // In your code you would now have "row" populated with the row data, - // assuming that the operation succeeded, so you would now scan the row data - // abd populate the values of our response: - // err := row.Scan(queryData.GetScanDest()...) - // // and check err here - - // Again, as we're not actually running a database in this example, we will - // instead run the code to assert that queryData.ScanDest was populated with - // the expected data, which should be pointers to each of the fields of - // Response so that the Scan method can write to them: - if len(queryData.GetScanDest()) != 3 { - panic(fmt.Sprintf("unexpected number of scan dest: %#v", queryData.ScanDest)) - } - idPtr, ok := queryData.GetScanDest()[0].(*int) - if !ok || idPtr != &queryData.Response.ID { - panic(fmt.Sprintf("unexpected response 'id' pointer: %#v", queryData.ScanDest)) - } - typePtr, ok := queryData.GetScanDest()[1].(*string) - if !ok || typePtr != &queryData.Response.Type { - panic(fmt.Sprintf("unexpected response 'type' pointer: %#v", queryData.ScanDest)) - } - namePtr, ok := queryData.GetScanDest()[2].(*string) - if !ok || namePtr != &queryData.Response.Name { - panic(fmt.Sprintf("unexpected response 'name' pointer: %#v", queryData.ScanDest)) - } - - // Remember the variable "query"? Well, we didn't check it. We will now make - // use of Go's runnable examples and print its contents to standard output - // so Go's tooling verify this example's output each time we run tests. - // By the way, to make the result more stable, we will remove some - // unnecessary white space from the query. - whiteSpaceRE := regexp.MustCompile(`\s+`) - query = strings.TrimSpace(whiteSpaceRE.ReplaceAllString(query, " ")) - fmt.Println(query) - - // Output: - // SELECT "id", "type", "name" FROM "users" WHERE "id" = ?; -} diff --git a/pkg/services/store/entity/sqlstash/sqltemplate/into.go b/pkg/services/store/entity/sqlstash/sqltemplate/into.go deleted file mode 100644 index 2896f89481c..00000000000 --- a/pkg/services/store/entity/sqlstash/sqltemplate/into.go +++ /dev/null @@ -1,41 +0,0 @@ -package sqltemplate - -import ( - "fmt" - "reflect" -) - -type ScanDest struct { - values []any - colNames []string -} - -func (i *ScanDest) Into(v reflect.Value, colName string) (string, error) { - if !v.IsValid() || !v.CanAddr() || !v.Addr().CanInterface() { - return "", fmt.Errorf("invalid or unaddressable value: %v", colName) - } - - i.values = append(i.values, v.Addr().Interface()) - i.colNames = append(i.colNames, colName) - - return colName, nil -} - -func (i *ScanDest) Reset() { - i.values = nil -} - -func (i *ScanDest) GetScanDest() []any { - return i.values -} - -func (i *ScanDest) GetColNames() []string { - return i.colNames -} - -type ScanDestIface interface { - Into(v reflect.Value, colName string) (string, error) - GetScanDest() []any - GetColNames() []string - Reset() -} diff --git a/pkg/services/store/entity/sqlstash/sqltemplate/into_test.go b/pkg/services/store/entity/sqlstash/sqltemplate/into_test.go deleted file mode 100644 index b4b06767f7c..00000000000 --- a/pkg/services/store/entity/sqlstash/sqltemplate/into_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package sqltemplate - -import ( - "reflect" - "slices" - "testing" -) - -func TestScanDest_Into(t *testing.T) { - t.Parallel() - - var d ScanDest - - colName, err := d.Into(reflect.Value{}, "some field") - if colName != "" || err == nil || len(d.GetScanDest()) != 0 { - t.Fatalf("unexpected outcome, got colname %q, err: %v, scan dest: %#v", - colName, err, d) - } - - data := struct { - X int - Y byte - }{} - dataVal := reflect.ValueOf(&data).Elem() - - expectedColNames := []string{"some int", "and a byte"} - - colName, err = d.Into(dataVal.FieldByName("X"), expectedColNames[0]) - v := d.GetScanDest() - if err != nil || colName != expectedColNames[0] || len(v) != 1 || v[0] != &data.X { - t.Fatalf("unexpected outcome, got colname %q, err: %v, scan dest: %#v", - colName, err, d) - } - - colName, err = d.Into(dataVal.FieldByName("Y"), expectedColNames[1]) - v = d.GetScanDest() - if err != nil || colName != expectedColNames[1] || len(v) != 2 || v[1] != &data.Y { - t.Fatalf("unexpected outcome, got colname %q, err: %v, scan dest: %#v", - colName, err, d) - } - - if gotColNames := d.GetColNames(); !slices.Equal(expectedColNames, gotColNames) { - t.Fatalf("unexpected column names: %v", gotColNames) - } - - d.Reset() - v = d.GetScanDest() - if len(v) != 0 { - t.Fatalf("unexpected values after reset: %v", v) - } -} diff --git a/pkg/services/store/entity/sqlstash/sqltemplate/mocks/SQLTemplateIface.go b/pkg/services/store/entity/sqlstash/sqltemplate/mocks/SQLTemplateIface.go deleted file mode 100644 index d41f66f97c3..00000000000 --- a/pkg/services/store/entity/sqlstash/sqltemplate/mocks/SQLTemplateIface.go +++ /dev/null @@ -1,664 +0,0 @@ -// Code generated by mockery v2.43.1. DO NOT EDIT. - -package mocks - -import ( - reflect "reflect" - - mock "github.com/stretchr/testify/mock" - - sqltemplate "github.com/grafana/grafana/pkg/services/store/entity/sqlstash/sqltemplate" -) - -// SQLTemplateIface is an autogenerated mock type for the SQLTemplateIface type -type SQLTemplateIface struct { - mock.Mock -} - -type SQLTemplateIface_Expecter struct { - mock *mock.Mock -} - -func (_m *SQLTemplateIface) EXPECT() *SQLTemplateIface_Expecter { - return &SQLTemplateIface_Expecter{mock: &_m.Mock} -} - -// Arg provides a mock function with given fields: x -func (_m *SQLTemplateIface) Arg(x interface{}) string { - ret := _m.Called(x) - - if len(ret) == 0 { - panic("no return value specified for Arg") - } - - var r0 string - if rf, ok := ret.Get(0).(func(interface{}) string); ok { - r0 = rf(x) - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// SQLTemplateIface_Arg_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Arg' -type SQLTemplateIface_Arg_Call struct { - *mock.Call -} - -// Arg is a helper method to define mock.On call -// - x interface{} -func (_e *SQLTemplateIface_Expecter) Arg(x interface{}) *SQLTemplateIface_Arg_Call { - return &SQLTemplateIface_Arg_Call{Call: _e.mock.On("Arg", x)} -} - -func (_c *SQLTemplateIface_Arg_Call) Run(run func(x interface{})) *SQLTemplateIface_Arg_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(interface{})) - }) - return _c -} - -func (_c *SQLTemplateIface_Arg_Call) Return(_a0 string) *SQLTemplateIface_Arg_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *SQLTemplateIface_Arg_Call) RunAndReturn(run func(interface{}) string) *SQLTemplateIface_Arg_Call { - _c.Call.Return(run) - return _c -} - -// ArgList provides a mock function with given fields: slice -func (_m *SQLTemplateIface) ArgList(slice reflect.Value) (string, error) { - ret := _m.Called(slice) - - if len(ret) == 0 { - panic("no return value specified for ArgList") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(reflect.Value) (string, error)); ok { - return rf(slice) - } - if rf, ok := ret.Get(0).(func(reflect.Value) string); ok { - r0 = rf(slice) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(reflect.Value) error); ok { - r1 = rf(slice) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SQLTemplateIface_ArgList_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ArgList' -type SQLTemplateIface_ArgList_Call struct { - *mock.Call -} - -// ArgList is a helper method to define mock.On call -// - slice reflect.Value -func (_e *SQLTemplateIface_Expecter) ArgList(slice interface{}) *SQLTemplateIface_ArgList_Call { - return &SQLTemplateIface_ArgList_Call{Call: _e.mock.On("ArgList", slice)} -} - -func (_c *SQLTemplateIface_ArgList_Call) Run(run func(slice reflect.Value)) *SQLTemplateIface_ArgList_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(reflect.Value)) - }) - return _c -} - -func (_c *SQLTemplateIface_ArgList_Call) Return(_a0 string, _a1 error) *SQLTemplateIface_ArgList_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *SQLTemplateIface_ArgList_Call) RunAndReturn(run func(reflect.Value) (string, error)) *SQLTemplateIface_ArgList_Call { - _c.Call.Return(run) - return _c -} - -// ArgPlaceholder provides a mock function with given fields: argNum -func (_m *SQLTemplateIface) ArgPlaceholder(argNum int) string { - ret := _m.Called(argNum) - - if len(ret) == 0 { - panic("no return value specified for ArgPlaceholder") - } - - var r0 string - if rf, ok := ret.Get(0).(func(int) string); ok { - r0 = rf(argNum) - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// SQLTemplateIface_ArgPlaceholder_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ArgPlaceholder' -type SQLTemplateIface_ArgPlaceholder_Call struct { - *mock.Call -} - -// ArgPlaceholder is a helper method to define mock.On call -// - argNum int -func (_e *SQLTemplateIface_Expecter) ArgPlaceholder(argNum interface{}) *SQLTemplateIface_ArgPlaceholder_Call { - return &SQLTemplateIface_ArgPlaceholder_Call{Call: _e.mock.On("ArgPlaceholder", argNum)} -} - -func (_c *SQLTemplateIface_ArgPlaceholder_Call) Run(run func(argNum int)) *SQLTemplateIface_ArgPlaceholder_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(int)) - }) - return _c -} - -func (_c *SQLTemplateIface_ArgPlaceholder_Call) Return(_a0 string) *SQLTemplateIface_ArgPlaceholder_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *SQLTemplateIface_ArgPlaceholder_Call) RunAndReturn(run func(int) string) *SQLTemplateIface_ArgPlaceholder_Call { - _c.Call.Return(run) - return _c -} - -// GetArgs provides a mock function with given fields: -func (_m *SQLTemplateIface) GetArgs() []interface{} { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetArgs") - } - - var r0 []interface{} - if rf, ok := ret.Get(0).(func() []interface{}); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]interface{}) - } - } - - return r0 -} - -// SQLTemplateIface_GetArgs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetArgs' -type SQLTemplateIface_GetArgs_Call struct { - *mock.Call -} - -// GetArgs is a helper method to define mock.On call -func (_e *SQLTemplateIface_Expecter) GetArgs() *SQLTemplateIface_GetArgs_Call { - return &SQLTemplateIface_GetArgs_Call{Call: _e.mock.On("GetArgs")} -} - -func (_c *SQLTemplateIface_GetArgs_Call) Run(run func()) *SQLTemplateIface_GetArgs_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *SQLTemplateIface_GetArgs_Call) Return(_a0 []interface{}) *SQLTemplateIface_GetArgs_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *SQLTemplateIface_GetArgs_Call) RunAndReturn(run func() []interface{}) *SQLTemplateIface_GetArgs_Call { - _c.Call.Return(run) - return _c -} - -// GetColNames provides a mock function with given fields: -func (_m *SQLTemplateIface) GetColNames() []string { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetColNames") - } - - var r0 []string - if rf, ok := ret.Get(0).(func() []string); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]string) - } - } - - return r0 -} - -// SQLTemplateIface_GetColNames_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetColNames' -type SQLTemplateIface_GetColNames_Call struct { - *mock.Call -} - -// GetColNames is a helper method to define mock.On call -func (_e *SQLTemplateIface_Expecter) GetColNames() *SQLTemplateIface_GetColNames_Call { - return &SQLTemplateIface_GetColNames_Call{Call: _e.mock.On("GetColNames")} -} - -func (_c *SQLTemplateIface_GetColNames_Call) Run(run func()) *SQLTemplateIface_GetColNames_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *SQLTemplateIface_GetColNames_Call) Return(_a0 []string) *SQLTemplateIface_GetColNames_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *SQLTemplateIface_GetColNames_Call) RunAndReturn(run func() []string) *SQLTemplateIface_GetColNames_Call { - _c.Call.Return(run) - return _c -} - -// GetScanDest provides a mock function with given fields: -func (_m *SQLTemplateIface) GetScanDest() []interface{} { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetScanDest") - } - - var r0 []interface{} - if rf, ok := ret.Get(0).(func() []interface{}); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]interface{}) - } - } - - return r0 -} - -// SQLTemplateIface_GetScanDest_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetScanDest' -type SQLTemplateIface_GetScanDest_Call struct { - *mock.Call -} - -// GetScanDest is a helper method to define mock.On call -func (_e *SQLTemplateIface_Expecter) GetScanDest() *SQLTemplateIface_GetScanDest_Call { - return &SQLTemplateIface_GetScanDest_Call{Call: _e.mock.On("GetScanDest")} -} - -func (_c *SQLTemplateIface_GetScanDest_Call) Run(run func()) *SQLTemplateIface_GetScanDest_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *SQLTemplateIface_GetScanDest_Call) Return(_a0 []interface{}) *SQLTemplateIface_GetScanDest_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *SQLTemplateIface_GetScanDest_Call) RunAndReturn(run func() []interface{}) *SQLTemplateIface_GetScanDest_Call { - _c.Call.Return(run) - return _c -} - -// Ident provides a mock function with given fields: _a0 -func (_m *SQLTemplateIface) Ident(_a0 string) (string, error) { - ret := _m.Called(_a0) - - if len(ret) == 0 { - panic("no return value specified for Ident") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(string) (string, error)); ok { - return rf(_a0) - } - if rf, ok := ret.Get(0).(func(string) string); ok { - r0 = rf(_a0) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(_a0) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SQLTemplateIface_Ident_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Ident' -type SQLTemplateIface_Ident_Call struct { - *mock.Call -} - -// Ident is a helper method to define mock.On call -// - _a0 string -func (_e *SQLTemplateIface_Expecter) Ident(_a0 interface{}) *SQLTemplateIface_Ident_Call { - return &SQLTemplateIface_Ident_Call{Call: _e.mock.On("Ident", _a0)} -} - -func (_c *SQLTemplateIface_Ident_Call) Run(run func(_a0 string)) *SQLTemplateIface_Ident_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *SQLTemplateIface_Ident_Call) Return(_a0 string, _a1 error) *SQLTemplateIface_Ident_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *SQLTemplateIface_Ident_Call) RunAndReturn(run func(string) (string, error)) *SQLTemplateIface_Ident_Call { - _c.Call.Return(run) - return _c -} - -// Into provides a mock function with given fields: v, colName -func (_m *SQLTemplateIface) Into(v reflect.Value, colName string) (string, error) { - ret := _m.Called(v, colName) - - if len(ret) == 0 { - panic("no return value specified for Into") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(reflect.Value, string) (string, error)); ok { - return rf(v, colName) - } - if rf, ok := ret.Get(0).(func(reflect.Value, string) string); ok { - r0 = rf(v, colName) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(reflect.Value, string) error); ok { - r1 = rf(v, colName) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SQLTemplateIface_Into_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Into' -type SQLTemplateIface_Into_Call struct { - *mock.Call -} - -// Into is a helper method to define mock.On call -// - v reflect.Value -// - colName string -func (_e *SQLTemplateIface_Expecter) Into(v interface{}, colName interface{}) *SQLTemplateIface_Into_Call { - return &SQLTemplateIface_Into_Call{Call: _e.mock.On("Into", v, colName)} -} - -func (_c *SQLTemplateIface_Into_Call) Run(run func(v reflect.Value, colName string)) *SQLTemplateIface_Into_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(reflect.Value), args[1].(string)) - }) - return _c -} - -func (_c *SQLTemplateIface_Into_Call) Return(_a0 string, _a1 error) *SQLTemplateIface_Into_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *SQLTemplateIface_Into_Call) RunAndReturn(run func(reflect.Value, string) (string, error)) *SQLTemplateIface_Into_Call { - _c.Call.Return(run) - return _c -} - -// Name provides a mock function with given fields: -func (_m *SQLTemplateIface) Name() string { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Name") - } - - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// SQLTemplateIface_Name_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Name' -type SQLTemplateIface_Name_Call struct { - *mock.Call -} - -// Name is a helper method to define mock.On call -func (_e *SQLTemplateIface_Expecter) Name() *SQLTemplateIface_Name_Call { - return &SQLTemplateIface_Name_Call{Call: _e.mock.On("Name")} -} - -func (_c *SQLTemplateIface_Name_Call) Run(run func()) *SQLTemplateIface_Name_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *SQLTemplateIface_Name_Call) Return(_a0 string) *SQLTemplateIface_Name_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *SQLTemplateIface_Name_Call) RunAndReturn(run func() string) *SQLTemplateIface_Name_Call { - _c.Call.Return(run) - return _c -} - -// Reset provides a mock function with given fields: -func (_m *SQLTemplateIface) Reset() { - _m.Called() -} - -// SQLTemplateIface_Reset_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Reset' -type SQLTemplateIface_Reset_Call struct { - *mock.Call -} - -// Reset is a helper method to define mock.On call -func (_e *SQLTemplateIface_Expecter) Reset() *SQLTemplateIface_Reset_Call { - return &SQLTemplateIface_Reset_Call{Call: _e.mock.On("Reset")} -} - -func (_c *SQLTemplateIface_Reset_Call) Run(run func()) *SQLTemplateIface_Reset_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *SQLTemplateIface_Reset_Call) Return() *SQLTemplateIface_Reset_Call { - _c.Call.Return() - return _c -} - -func (_c *SQLTemplateIface_Reset_Call) RunAndReturn(run func()) *SQLTemplateIface_Reset_Call { - _c.Call.Return(run) - return _c -} - -// SelectFor provides a mock function with given fields: _a0 -func (_m *SQLTemplateIface) SelectFor(_a0 ...string) (string, error) { - _va := make([]interface{}, len(_a0)) - for _i := range _a0 { - _va[_i] = _a0[_i] - } - var _ca []interface{} - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - if len(ret) == 0 { - panic("no return value specified for SelectFor") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(...string) (string, error)); ok { - return rf(_a0...) - } - if rf, ok := ret.Get(0).(func(...string) string); ok { - r0 = rf(_a0...) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(...string) error); ok { - r1 = rf(_a0...) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SQLTemplateIface_SelectFor_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SelectFor' -type SQLTemplateIface_SelectFor_Call struct { - *mock.Call -} - -// SelectFor is a helper method to define mock.On call -// - _a0 ...string -func (_e *SQLTemplateIface_Expecter) SelectFor(_a0 ...interface{}) *SQLTemplateIface_SelectFor_Call { - return &SQLTemplateIface_SelectFor_Call{Call: _e.mock.On("SelectFor", - append([]interface{}{}, _a0...)...)} -} - -func (_c *SQLTemplateIface_SelectFor_Call) Run(run func(_a0 ...string)) *SQLTemplateIface_SelectFor_Call { - _c.Call.Run(func(args mock.Arguments) { - variadicArgs := make([]string, len(args)-0) - for i, a := range args[0:] { - if a != nil { - variadicArgs[i] = a.(string) - } - } - run(variadicArgs...) - }) - return _c -} - -func (_c *SQLTemplateIface_SelectFor_Call) Return(_a0 string, _a1 error) *SQLTemplateIface_SelectFor_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *SQLTemplateIface_SelectFor_Call) RunAndReturn(run func(...string) (string, error)) *SQLTemplateIface_SelectFor_Call { - _c.Call.Return(run) - return _c -} - -// SetDialect provides a mock function with given fields: _a0 -func (_m *SQLTemplateIface) SetDialect(_a0 sqltemplate.Dialect) { - _m.Called(_a0) -} - -// SQLTemplateIface_SetDialect_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetDialect' -type SQLTemplateIface_SetDialect_Call struct { - *mock.Call -} - -// SetDialect is a helper method to define mock.On call -// - _a0 sqltemplate.Dialect -func (_e *SQLTemplateIface_Expecter) SetDialect(_a0 interface{}) *SQLTemplateIface_SetDialect_Call { - return &SQLTemplateIface_SetDialect_Call{Call: _e.mock.On("SetDialect", _a0)} -} - -func (_c *SQLTemplateIface_SetDialect_Call) Run(run func(_a0 sqltemplate.Dialect)) *SQLTemplateIface_SetDialect_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(sqltemplate.Dialect)) - }) - return _c -} - -func (_c *SQLTemplateIface_SetDialect_Call) Return() *SQLTemplateIface_SetDialect_Call { - _c.Call.Return() - return _c -} - -func (_c *SQLTemplateIface_SetDialect_Call) RunAndReturn(run func(sqltemplate.Dialect)) *SQLTemplateIface_SetDialect_Call { - _c.Call.Return(run) - return _c -} - -// Validate provides a mock function with given fields: -func (_m *SQLTemplateIface) Validate() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Validate") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// SQLTemplateIface_Validate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Validate' -type SQLTemplateIface_Validate_Call struct { - *mock.Call -} - -// Validate is a helper method to define mock.On call -func (_e *SQLTemplateIface_Expecter) Validate() *SQLTemplateIface_Validate_Call { - return &SQLTemplateIface_Validate_Call{Call: _e.mock.On("Validate")} -} - -func (_c *SQLTemplateIface_Validate_Call) Run(run func()) *SQLTemplateIface_Validate_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *SQLTemplateIface_Validate_Call) Return(_a0 error) *SQLTemplateIface_Validate_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *SQLTemplateIface_Validate_Call) RunAndReturn(run func() error) *SQLTemplateIface_Validate_Call { - _c.Call.Return(run) - return _c -} - -// NewSQLTemplateIface creates a new instance of SQLTemplateIface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewSQLTemplateIface(t interface { - mock.TestingT - Cleanup(func()) -}) *SQLTemplateIface { - mock := &SQLTemplateIface{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/pkg/services/store/entity/sqlstash/sqltemplate/mocks/WithResults.go b/pkg/services/store/entity/sqlstash/sqltemplate/mocks/WithResults.go deleted file mode 100644 index 7c98a0c3433..00000000000 --- a/pkg/services/store/entity/sqlstash/sqltemplate/mocks/WithResults.go +++ /dev/null @@ -1,719 +0,0 @@ -// Code generated by mockery v2.43.1. DO NOT EDIT. - -package mocks - -import ( - reflect "reflect" - - mock "github.com/stretchr/testify/mock" - - sqltemplate "github.com/grafana/grafana/pkg/services/store/entity/sqlstash/sqltemplate" -) - -// WithResults is an autogenerated mock type for the WithResults type -type WithResults[T interface{}] struct { - mock.Mock -} - -type WithResults_Expecter[T interface{}] struct { - mock *mock.Mock -} - -func (_m *WithResults[T]) EXPECT() *WithResults_Expecter[T] { - return &WithResults_Expecter[T]{mock: &_m.Mock} -} - -// Arg provides a mock function with given fields: x -func (_m *WithResults[T]) Arg(x interface{}) string { - ret := _m.Called(x) - - if len(ret) == 0 { - panic("no return value specified for Arg") - } - - var r0 string - if rf, ok := ret.Get(0).(func(interface{}) string); ok { - r0 = rf(x) - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// WithResults_Arg_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Arg' -type WithResults_Arg_Call[T interface{}] struct { - *mock.Call -} - -// Arg is a helper method to define mock.On call -// - x interface{} -func (_e *WithResults_Expecter[T]) Arg(x interface{}) *WithResults_Arg_Call[T] { - return &WithResults_Arg_Call[T]{Call: _e.mock.On("Arg", x)} -} - -func (_c *WithResults_Arg_Call[T]) Run(run func(x interface{})) *WithResults_Arg_Call[T] { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(interface{})) - }) - return _c -} - -func (_c *WithResults_Arg_Call[T]) Return(_a0 string) *WithResults_Arg_Call[T] { - _c.Call.Return(_a0) - return _c -} - -func (_c *WithResults_Arg_Call[T]) RunAndReturn(run func(interface{}) string) *WithResults_Arg_Call[T] { - _c.Call.Return(run) - return _c -} - -// ArgList provides a mock function with given fields: slice -func (_m *WithResults[T]) ArgList(slice reflect.Value) (string, error) { - ret := _m.Called(slice) - - if len(ret) == 0 { - panic("no return value specified for ArgList") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(reflect.Value) (string, error)); ok { - return rf(slice) - } - if rf, ok := ret.Get(0).(func(reflect.Value) string); ok { - r0 = rf(slice) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(reflect.Value) error); ok { - r1 = rf(slice) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WithResults_ArgList_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ArgList' -type WithResults_ArgList_Call[T interface{}] struct { - *mock.Call -} - -// ArgList is a helper method to define mock.On call -// - slice reflect.Value -func (_e *WithResults_Expecter[T]) ArgList(slice interface{}) *WithResults_ArgList_Call[T] { - return &WithResults_ArgList_Call[T]{Call: _e.mock.On("ArgList", slice)} -} - -func (_c *WithResults_ArgList_Call[T]) Run(run func(slice reflect.Value)) *WithResults_ArgList_Call[T] { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(reflect.Value)) - }) - return _c -} - -func (_c *WithResults_ArgList_Call[T]) Return(_a0 string, _a1 error) *WithResults_ArgList_Call[T] { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *WithResults_ArgList_Call[T]) RunAndReturn(run func(reflect.Value) (string, error)) *WithResults_ArgList_Call[T] { - _c.Call.Return(run) - return _c -} - -// ArgPlaceholder provides a mock function with given fields: argNum -func (_m *WithResults[T]) ArgPlaceholder(argNum int) string { - ret := _m.Called(argNum) - - if len(ret) == 0 { - panic("no return value specified for ArgPlaceholder") - } - - var r0 string - if rf, ok := ret.Get(0).(func(int) string); ok { - r0 = rf(argNum) - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// WithResults_ArgPlaceholder_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ArgPlaceholder' -type WithResults_ArgPlaceholder_Call[T interface{}] struct { - *mock.Call -} - -// ArgPlaceholder is a helper method to define mock.On call -// - argNum int -func (_e *WithResults_Expecter[T]) ArgPlaceholder(argNum interface{}) *WithResults_ArgPlaceholder_Call[T] { - return &WithResults_ArgPlaceholder_Call[T]{Call: _e.mock.On("ArgPlaceholder", argNum)} -} - -func (_c *WithResults_ArgPlaceholder_Call[T]) Run(run func(argNum int)) *WithResults_ArgPlaceholder_Call[T] { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(int)) - }) - return _c -} - -func (_c *WithResults_ArgPlaceholder_Call[T]) Return(_a0 string) *WithResults_ArgPlaceholder_Call[T] { - _c.Call.Return(_a0) - return _c -} - -func (_c *WithResults_ArgPlaceholder_Call[T]) RunAndReturn(run func(int) string) *WithResults_ArgPlaceholder_Call[T] { - _c.Call.Return(run) - return _c -} - -// GetArgs provides a mock function with given fields: -func (_m *WithResults[T]) GetArgs() []interface{} { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetArgs") - } - - var r0 []interface{} - if rf, ok := ret.Get(0).(func() []interface{}); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]interface{}) - } - } - - return r0 -} - -// WithResults_GetArgs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetArgs' -type WithResults_GetArgs_Call[T interface{}] struct { - *mock.Call -} - -// GetArgs is a helper method to define mock.On call -func (_e *WithResults_Expecter[T]) GetArgs() *WithResults_GetArgs_Call[T] { - return &WithResults_GetArgs_Call[T]{Call: _e.mock.On("GetArgs")} -} - -func (_c *WithResults_GetArgs_Call[T]) Run(run func()) *WithResults_GetArgs_Call[T] { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *WithResults_GetArgs_Call[T]) Return(_a0 []interface{}) *WithResults_GetArgs_Call[T] { - _c.Call.Return(_a0) - return _c -} - -func (_c *WithResults_GetArgs_Call[T]) RunAndReturn(run func() []interface{}) *WithResults_GetArgs_Call[T] { - _c.Call.Return(run) - return _c -} - -// GetColNames provides a mock function with given fields: -func (_m *WithResults[T]) GetColNames() []string { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetColNames") - } - - var r0 []string - if rf, ok := ret.Get(0).(func() []string); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]string) - } - } - - return r0 -} - -// WithResults_GetColNames_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetColNames' -type WithResults_GetColNames_Call[T interface{}] struct { - *mock.Call -} - -// GetColNames is a helper method to define mock.On call -func (_e *WithResults_Expecter[T]) GetColNames() *WithResults_GetColNames_Call[T] { - return &WithResults_GetColNames_Call[T]{Call: _e.mock.On("GetColNames")} -} - -func (_c *WithResults_GetColNames_Call[T]) Run(run func()) *WithResults_GetColNames_Call[T] { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *WithResults_GetColNames_Call[T]) Return(_a0 []string) *WithResults_GetColNames_Call[T] { - _c.Call.Return(_a0) - return _c -} - -func (_c *WithResults_GetColNames_Call[T]) RunAndReturn(run func() []string) *WithResults_GetColNames_Call[T] { - _c.Call.Return(run) - return _c -} - -// GetScanDest provides a mock function with given fields: -func (_m *WithResults[T]) GetScanDest() []interface{} { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetScanDest") - } - - var r0 []interface{} - if rf, ok := ret.Get(0).(func() []interface{}); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]interface{}) - } - } - - return r0 -} - -// WithResults_GetScanDest_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetScanDest' -type WithResults_GetScanDest_Call[T interface{}] struct { - *mock.Call -} - -// GetScanDest is a helper method to define mock.On call -func (_e *WithResults_Expecter[T]) GetScanDest() *WithResults_GetScanDest_Call[T] { - return &WithResults_GetScanDest_Call[T]{Call: _e.mock.On("GetScanDest")} -} - -func (_c *WithResults_GetScanDest_Call[T]) Run(run func()) *WithResults_GetScanDest_Call[T] { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *WithResults_GetScanDest_Call[T]) Return(_a0 []interface{}) *WithResults_GetScanDest_Call[T] { - _c.Call.Return(_a0) - return _c -} - -func (_c *WithResults_GetScanDest_Call[T]) RunAndReturn(run func() []interface{}) *WithResults_GetScanDest_Call[T] { - _c.Call.Return(run) - return _c -} - -// Ident provides a mock function with given fields: _a0 -func (_m *WithResults[T]) Ident(_a0 string) (string, error) { - ret := _m.Called(_a0) - - if len(ret) == 0 { - panic("no return value specified for Ident") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(string) (string, error)); ok { - return rf(_a0) - } - if rf, ok := ret.Get(0).(func(string) string); ok { - r0 = rf(_a0) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(_a0) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WithResults_Ident_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Ident' -type WithResults_Ident_Call[T interface{}] struct { - *mock.Call -} - -// Ident is a helper method to define mock.On call -// - _a0 string -func (_e *WithResults_Expecter[T]) Ident(_a0 interface{}) *WithResults_Ident_Call[T] { - return &WithResults_Ident_Call[T]{Call: _e.mock.On("Ident", _a0)} -} - -func (_c *WithResults_Ident_Call[T]) Run(run func(_a0 string)) *WithResults_Ident_Call[T] { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *WithResults_Ident_Call[T]) Return(_a0 string, _a1 error) *WithResults_Ident_Call[T] { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *WithResults_Ident_Call[T]) RunAndReturn(run func(string) (string, error)) *WithResults_Ident_Call[T] { - _c.Call.Return(run) - return _c -} - -// Into provides a mock function with given fields: v, colName -func (_m *WithResults[T]) Into(v reflect.Value, colName string) (string, error) { - ret := _m.Called(v, colName) - - if len(ret) == 0 { - panic("no return value specified for Into") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(reflect.Value, string) (string, error)); ok { - return rf(v, colName) - } - if rf, ok := ret.Get(0).(func(reflect.Value, string) string); ok { - r0 = rf(v, colName) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(reflect.Value, string) error); ok { - r1 = rf(v, colName) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WithResults_Into_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Into' -type WithResults_Into_Call[T interface{}] struct { - *mock.Call -} - -// Into is a helper method to define mock.On call -// - v reflect.Value -// - colName string -func (_e *WithResults_Expecter[T]) Into(v interface{}, colName interface{}) *WithResults_Into_Call[T] { - return &WithResults_Into_Call[T]{Call: _e.mock.On("Into", v, colName)} -} - -func (_c *WithResults_Into_Call[T]) Run(run func(v reflect.Value, colName string)) *WithResults_Into_Call[T] { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(reflect.Value), args[1].(string)) - }) - return _c -} - -func (_c *WithResults_Into_Call[T]) Return(_a0 string, _a1 error) *WithResults_Into_Call[T] { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *WithResults_Into_Call[T]) RunAndReturn(run func(reflect.Value, string) (string, error)) *WithResults_Into_Call[T] { - _c.Call.Return(run) - return _c -} - -// Name provides a mock function with given fields: -func (_m *WithResults[T]) Name() string { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Name") - } - - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// WithResults_Name_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Name' -type WithResults_Name_Call[T interface{}] struct { - *mock.Call -} - -// Name is a helper method to define mock.On call -func (_e *WithResults_Expecter[T]) Name() *WithResults_Name_Call[T] { - return &WithResults_Name_Call[T]{Call: _e.mock.On("Name")} -} - -func (_c *WithResults_Name_Call[T]) Run(run func()) *WithResults_Name_Call[T] { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *WithResults_Name_Call[T]) Return(_a0 string) *WithResults_Name_Call[T] { - _c.Call.Return(_a0) - return _c -} - -func (_c *WithResults_Name_Call[T]) RunAndReturn(run func() string) *WithResults_Name_Call[T] { - _c.Call.Return(run) - return _c -} - -// Reset provides a mock function with given fields: -func (_m *WithResults[T]) Reset() { - _m.Called() -} - -// WithResults_Reset_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Reset' -type WithResults_Reset_Call[T interface{}] struct { - *mock.Call -} - -// Reset is a helper method to define mock.On call -func (_e *WithResults_Expecter[T]) Reset() *WithResults_Reset_Call[T] { - return &WithResults_Reset_Call[T]{Call: _e.mock.On("Reset")} -} - -func (_c *WithResults_Reset_Call[T]) Run(run func()) *WithResults_Reset_Call[T] { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *WithResults_Reset_Call[T]) Return() *WithResults_Reset_Call[T] { - _c.Call.Return() - return _c -} - -func (_c *WithResults_Reset_Call[T]) RunAndReturn(run func()) *WithResults_Reset_Call[T] { - _c.Call.Return(run) - return _c -} - -// Results provides a mock function with given fields: -func (_m *WithResults[T]) Results() (T, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Results") - } - - var r0 T - var r1 error - if rf, ok := ret.Get(0).(func() (T, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() T); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(T) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WithResults_Results_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Results' -type WithResults_Results_Call[T interface{}] struct { - *mock.Call -} - -// Results is a helper method to define mock.On call -func (_e *WithResults_Expecter[T]) Results() *WithResults_Results_Call[T] { - return &WithResults_Results_Call[T]{Call: _e.mock.On("Results")} -} - -func (_c *WithResults_Results_Call[T]) Run(run func()) *WithResults_Results_Call[T] { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *WithResults_Results_Call[T]) Return(_a0 T, _a1 error) *WithResults_Results_Call[T] { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *WithResults_Results_Call[T]) RunAndReturn(run func() (T, error)) *WithResults_Results_Call[T] { - _c.Call.Return(run) - return _c -} - -// SelectFor provides a mock function with given fields: _a0 -func (_m *WithResults[T]) SelectFor(_a0 ...string) (string, error) { - _va := make([]interface{}, len(_a0)) - for _i := range _a0 { - _va[_i] = _a0[_i] - } - var _ca []interface{} - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - if len(ret) == 0 { - panic("no return value specified for SelectFor") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(...string) (string, error)); ok { - return rf(_a0...) - } - if rf, ok := ret.Get(0).(func(...string) string); ok { - r0 = rf(_a0...) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(...string) error); ok { - r1 = rf(_a0...) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// WithResults_SelectFor_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SelectFor' -type WithResults_SelectFor_Call[T interface{}] struct { - *mock.Call -} - -// SelectFor is a helper method to define mock.On call -// - _a0 ...string -func (_e *WithResults_Expecter[T]) SelectFor(_a0 ...interface{}) *WithResults_SelectFor_Call[T] { - return &WithResults_SelectFor_Call[T]{Call: _e.mock.On("SelectFor", - append([]interface{}{}, _a0...)...)} -} - -func (_c *WithResults_SelectFor_Call[T]) Run(run func(_a0 ...string)) *WithResults_SelectFor_Call[T] { - _c.Call.Run(func(args mock.Arguments) { - variadicArgs := make([]string, len(args)-0) - for i, a := range args[0:] { - if a != nil { - variadicArgs[i] = a.(string) - } - } - run(variadicArgs...) - }) - return _c -} - -func (_c *WithResults_SelectFor_Call[T]) Return(_a0 string, _a1 error) *WithResults_SelectFor_Call[T] { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *WithResults_SelectFor_Call[T]) RunAndReturn(run func(...string) (string, error)) *WithResults_SelectFor_Call[T] { - _c.Call.Return(run) - return _c -} - -// SetDialect provides a mock function with given fields: _a0 -func (_m *WithResults[T]) SetDialect(_a0 sqltemplate.Dialect) { - _m.Called(_a0) -} - -// WithResults_SetDialect_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetDialect' -type WithResults_SetDialect_Call[T interface{}] struct { - *mock.Call -} - -// SetDialect is a helper method to define mock.On call -// - _a0 sqltemplate.Dialect -func (_e *WithResults_Expecter[T]) SetDialect(_a0 interface{}) *WithResults_SetDialect_Call[T] { - return &WithResults_SetDialect_Call[T]{Call: _e.mock.On("SetDialect", _a0)} -} - -func (_c *WithResults_SetDialect_Call[T]) Run(run func(_a0 sqltemplate.Dialect)) *WithResults_SetDialect_Call[T] { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(sqltemplate.Dialect)) - }) - return _c -} - -func (_c *WithResults_SetDialect_Call[T]) Return() *WithResults_SetDialect_Call[T] { - _c.Call.Return() - return _c -} - -func (_c *WithResults_SetDialect_Call[T]) RunAndReturn(run func(sqltemplate.Dialect)) *WithResults_SetDialect_Call[T] { - _c.Call.Return(run) - return _c -} - -// Validate provides a mock function with given fields: -func (_m *WithResults[T]) Validate() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Validate") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// WithResults_Validate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Validate' -type WithResults_Validate_Call[T interface{}] struct { - *mock.Call -} - -// Validate is a helper method to define mock.On call -func (_e *WithResults_Expecter[T]) Validate() *WithResults_Validate_Call[T] { - return &WithResults_Validate_Call[T]{Call: _e.mock.On("Validate")} -} - -func (_c *WithResults_Validate_Call[T]) Run(run func()) *WithResults_Validate_Call[T] { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *WithResults_Validate_Call[T]) Return(_a0 error) *WithResults_Validate_Call[T] { - _c.Call.Return(_a0) - return _c -} - -func (_c *WithResults_Validate_Call[T]) RunAndReturn(run func() error) *WithResults_Validate_Call[T] { - _c.Call.Return(run) - return _c -} - -// NewWithResults creates a new instance of WithResults. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewWithResults[T interface{}](t interface { - mock.TestingT - Cleanup(func()) -}) *WithResults[T] { - mock := &WithResults[T]{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/pkg/services/store/entity/sqlstash/sqltemplate/sqltemplate.go b/pkg/services/store/entity/sqlstash/sqltemplate/sqltemplate.go deleted file mode 100644 index 551a23fca62..00000000000 --- a/pkg/services/store/entity/sqlstash/sqltemplate/sqltemplate.go +++ /dev/null @@ -1,141 +0,0 @@ -package sqltemplate - -import ( - "errors" - "regexp" - "strings" - "text/template" -) - -// Package-level errors. -var ( - ErrValidationNotImplemented = errors.New("validation not implemented") - ErrSQLTemplateNoSerialize = errors.New("SQLTemplate should not be serialized") -) - -// SQLTemplate provides comprehensive support for SQL templating, handling -// dialect traits, execution arguments and scanning arguments. -type SQLTemplate struct { - Dialect - Args - ScanDest -} - -// New returns a nee *SQLTemplate that will use the given dialect. -func New(d Dialect) *SQLTemplate { - ret := new(SQLTemplate) - ret.SetDialect(d) - - return ret -} - -func (t *SQLTemplate) Reset() { - t.Args.Reset() - t.ScanDest.Reset() -} - -func (t *SQLTemplate) SetDialect(d Dialect) { - t.Reset() - t.Dialect = d - t.Args.d = d -} - -func (t *SQLTemplate) Validate() error { - return ErrValidationNotImplemented -} - -func (t *SQLTemplate) MarshalJSON() ([]byte, error) { - return nil, ErrSQLTemplateNoSerialize -} - -func (t *SQLTemplate) UnmarshalJSON([]byte) error { - return ErrSQLTemplateNoSerialize -} - -//go:generate mockery --with-expecter --name SQLTemplateIface - -// SQLTemplateIface can be used as argument in general purpose utilities -// expecting a struct embedding *SQLTemplate. -type SQLTemplateIface interface { - Dialect - ArgsIface - ScanDestIface - // Reset calls the Reset method of ArgsIface and ScanDestIface. - Reset() - // SetDialect allows reusing the template components. It should first call - // Reset. - SetDialect(Dialect) - // Validate should be implemented to validate a request before executing the - // template. - Validate() error -} - -//go:generate mockery --with-expecter --name WithResults - -// WithResults has an additional method suited for structs embedding -// *SQLTemplate and returning a set of rows. -type WithResults[T any] interface { - SQLTemplateIface - - // Results returns the results of the query. If the query is expected to - // return a set of rows, then it should be a deep copy of the internal - // results, so that it can be called multiple times to get the different - // values. - Results() (T, error) -} - -// Execute is a trivial utility to execute and return the results of any -// text/template as a string and an error. -func Execute(t *template.Template, data any) (string, error) { - var b strings.Builder - if err := t.Execute(&b, data); err != nil { - return "", err - } - - return b.String(), nil -} - -// FormatSQL is an opinionated formatter for SQL template output. It can be used -// to reduce the final code length, for debugging, and testing. It is not a -// propoer and full-fledged SQL parser, so it makes the following assumptions, -// which are also good practices for writing your SQL templates: -// 1. There are no SQL comments. Consider adding your comments as template -// comments instead (i.e. "{{/* this is a template comment */}}"). -// 2. There are no multiline strings, and strings do not contain consecutive -// spaces. Code looking like this is already a smell. Avoid string literals, -// pass them as arguments so they can be appropriately escaped by the -// corresponding driver. And identifiers with white space should be avoided -// in all cases as well. -func FormatSQL(q string) string { - q = strings.TrimSpace(q) - for _, f := range formatREs { - q = f.re.ReplaceAllString(q, f.replacement) - } - q = strings.TrimSpace(q) - - return q -} - -type reFormatting struct { - re *regexp.Regexp - replacement string -} - -var formatREs = []reFormatting{ - {re: regexp.MustCompile(`\s+`), replacement: " "}, - {re: regexp.MustCompile(` ?([+-/*=<>%!~]+) ?`), replacement: " $1 "}, - {re: regexp.MustCompile(`([([{]) `), replacement: "$1"}, - {re: regexp.MustCompile(` ([)\]}])`), replacement: "$1"}, - {re: regexp.MustCompile(` ?, ?`), replacement: ", "}, - {re: regexp.MustCompile(` ?([;.:]) ?`), replacement: "$1"}, - - // Add newlines and a bit of visual aid - { - re: regexp.MustCompile(`((UNION|INTERSECT|EXCEPT)( (ALL|DISTINCT))? )?SELECT `), - replacement: "\n${1}SELECT ", - }, - { - re: regexp.MustCompile(` (FROM|WHERE|GROUP BY|HAVING|WINDOW|ORDER BY|LIMIT|OFFSET) `), - replacement: "\n $1 ", - }, -} diff --git a/pkg/services/store/entity/sqlstash/sqltemplate/sqltemplate_test.go b/pkg/services/store/entity/sqlstash/sqltemplate/sqltemplate_test.go deleted file mode 100644 index c46fc2d7cca..00000000000 --- a/pkg/services/store/entity/sqlstash/sqltemplate/sqltemplate_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package sqltemplate - -import ( - "encoding/json" - "errors" - "reflect" - "testing" - "text/template" -) - -func TestSQLTemplate(t *testing.T) { - t.Parallel() - - field := reflect.ValueOf(new(struct { - X int - })).Elem().FieldByName("X") - - tmpl := New(MySQL) - tmpl.Arg(1) - _, err := tmpl.Into(field, "colname") - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - tmpl.SetDialect(SQLite) - a := tmpl.GetArgs() - d := tmpl.GetScanDest() - if len(a) != 0 || len(d) != 0 { - t.Fatalf("unexpected values after SetDialect(). Args: %v, ScanDest: %v", - a, d) - } - - b, err := json.Marshal(tmpl) - if b != nil || !errors.Is(err, ErrSQLTemplateNoSerialize) { - t.Fatalf("should fail serialization with ErrSQLTemplateNoSerialize") - } - - err = json.Unmarshal([]byte(`{}`), &tmpl) - if !errors.Is(err, ErrSQLTemplateNoSerialize) { - t.Fatalf("should fail deserialization with ErrSQLTemplateNoSerialize") - } - - err = tmpl.Validate() - if !errors.Is(err, ErrValidationNotImplemented) { - t.Fatalf("should fail with ErrValidationNotImplemented") - } -} - -func TestExecute(t *testing.T) { - t.Parallel() - - tmpl := template.Must(template.New("test").Parse(`{{ .ID }}`)) - - data := struct { - ID int - }{ - ID: 1, - } - - txt, err := Execute(tmpl, data) - if txt != "1" || err != nil { - t.Fatalf("unexpected error, txt: %q, err: %v", txt, err) - } - - txt, err = Execute(tmpl, 1) - if txt != "" || err == nil { - t.Fatalf("unexpected result, txt: %q, err: %v", txt, err) - } -} - -func TestFormatSQL(t *testing.T) { - t.Parallel() - - // TODO: improve testing - - const ( - input = ` - SELECT * - FROM "mytab" AS t - WHERE "id">= 3 AND "str" = ? ; - ` - expected = `SELECT * - FROM "mytab" AS t - WHERE "id" >= 3 AND "str" = ?;` - ) - - got := FormatSQL(input) - if expected != got { - t.Fatalf("Unexpected output.\n\tExpected: %s\n\tActual: %s", expected, - got) - } -} diff --git a/pkg/services/store/entity/sqlstash/update.go b/pkg/services/store/entity/sqlstash/update.go index af059717a2a..0c03e80f9a5 100644 --- a/pkg/services/store/entity/sqlstash/update.go +++ b/pkg/services/store/entity/sqlstash/update.go @@ -11,7 +11,7 @@ import ( grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic" "github.com/grafana/grafana/pkg/services/store/entity" "github.com/grafana/grafana/pkg/services/store/entity/db" - "github.com/grafana/grafana/pkg/services/store/entity/sqlstash/sqltemplate" + "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" ) func (s *sqlEntityServer) Update(ctx context.Context, r *entity.UpdateEntityRequest) (*entity.UpdateEntityResponse, error) { diff --git a/pkg/services/store/entity/sqlstash/utils.go b/pkg/services/store/entity/sqlstash/utils.go index 3d4666b9649..3d140ea31c3 100644 --- a/pkg/services/store/entity/sqlstash/utils.go +++ b/pkg/services/store/entity/sqlstash/utils.go @@ -10,7 +10,7 @@ import ( "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/services/store/entity/db" - "github.com/grafana/grafana/pkg/services/store/entity/sqlstash/sqltemplate" + "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" ) func createETag(body []byte, meta []byte, status []byte) string { diff --git a/pkg/services/store/entity/sqlstash/utils_test.go b/pkg/services/store/entity/sqlstash/utils_test.go index 70d02263623..b3d4907c2ec 100644 --- a/pkg/services/store/entity/sqlstash/utils_test.go +++ b/pkg/services/store/entity/sqlstash/utils_test.go @@ -16,8 +16,8 @@ import ( "github.com/grafana/grafana/pkg/services/store/entity/db" "github.com/grafana/grafana/pkg/services/store/entity/db/dbimpl" - "github.com/grafana/grafana/pkg/services/store/entity/sqlstash/sqltemplate" - sqltemplateMocks "github.com/grafana/grafana/pkg/services/store/entity/sqlstash/sqltemplate/mocks" + "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" + sqltemplateMocks "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate/mocks" "github.com/grafana/grafana/pkg/util/testutil" ) diff --git a/pkg/storage/unified/resource/server.go b/pkg/storage/unified/resource/server.go index fcf807cb2e1..17f1fe1a6ce 100644 --- a/pkg/storage/unified/resource/server.go +++ b/pkg/storage/unified/resource/server.go @@ -490,6 +490,8 @@ func (s *server) Read(ctx context.Context, req *ReadRequest) (*ReadResponse, err return &ReadResponse{Status: status}, nil } + // TODO: shall we also check for the namespace and Name ? Or is that a backend concern? + rsp, err := s.backend.Read(ctx, req) if err != nil { if rsp == nil { @@ -504,7 +506,6 @@ func (s *server) List(ctx context.Context, req *ListRequest) (*ListResponse, err if err := s.Init(); err != nil { return nil, err } - // TODO: rsp, err := s.backend.PrepareList(ctx, req) // Status??? diff --git a/pkg/storage/unified/sql/backend.go b/pkg/storage/unified/sql/backend.go index ac8e9415101..b91f20a7a7f 100644 --- a/pkg/storage/unified/sql/backend.go +++ b/pkg/storage/unified/sql/backend.go @@ -391,15 +391,9 @@ func (b *backend) WatchWriteEvents(ctx context.Context) (<-chan *resource.Writte return nil, err } // Fetch the lastest RV - rows, err := b.sqlDB.QueryContext(ctx, `SELECT COALESCE(max("resource_version"), 0) FROM "resource";`) + since, err := fetchLatestRV(ctx, b.sqlDB) if err != nil { - return nil, fmt.Errorf("fetch latest rv: %w", err) - } - since := int64(0) - if rows.Next() { - if err := rows.Scan(&since); err != nil { - return nil, fmt.Errorf("scan since resource version: %w", err) - } + return nil, err } // Start the poller stream := make(chan *resource.WrittenEvent) @@ -429,6 +423,22 @@ func (b *backend) poller(ctx context.Context, since int64, stream chan<- *resour } } +// fetchLatestRV returns the current maxium RV in the resource table +func fetchLatestRV(ctx context.Context, db db.DB) (int64, error) { + // Fetch the lastest RV + rows, err := db.QueryContext(ctx, `SELECT COALESCE(max("resource_version"), 0) FROM "resource";`) + if err != nil { + return 0, fmt.Errorf("fetch latest rv: %w", err) + } + since := int64(0) + if rows.Next() { + if err := rows.Scan(&since); err != nil { + return 0, fmt.Errorf("scan since resource version: %w", err) + } + } + return since, nil +} + func (b *backend) poll(ctx context.Context, since int64, stream chan<- *resource.WrittenEvent) (int64, error) { ctx, span := b.tracer.Start(ctx, trace_prefix+"poll") defer span.End() diff --git a/pkg/storage/unified/sql/backend_test.go b/pkg/storage/unified/sql/backend_test.go index 0cfd95df550..6a829c3fe17 100644 --- a/pkg/storage/unified/sql/backend_test.go +++ b/pkg/storage/unified/sql/backend_test.go @@ -144,7 +144,7 @@ func TestBackendHappyPath(t *testing.T) { }) } -func TestBackendWatchWriteEventsFromHead(t *testing.T) { +func TestBackendWatchWriteEventsFromLastest(t *testing.T) { ctx := context.Background() dbstore := db.InitTestDB(t) diff --git a/pkg/storage/unified/sql/sqltemplate/mocks/SQLTemplateIface.go b/pkg/storage/unified/sql/sqltemplate/mocks/SQLTemplateIface.go index d41f66f97c3..4461b349a31 100644 --- a/pkg/storage/unified/sql/sqltemplate/mocks/SQLTemplateIface.go +++ b/pkg/storage/unified/sql/sqltemplate/mocks/SQLTemplateIface.go @@ -7,7 +7,7 @@ import ( mock "github.com/stretchr/testify/mock" - sqltemplate "github.com/grafana/grafana/pkg/services/store/entity/sqlstash/sqltemplate" + sqltemplate "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" ) // SQLTemplateIface is an autogenerated mock type for the SQLTemplateIface type diff --git a/pkg/storage/unified/sql/sqltemplate/mocks/WithResults.go b/pkg/storage/unified/sql/sqltemplate/mocks/WithResults.go index 7c98a0c3433..dea246cd777 100644 --- a/pkg/storage/unified/sql/sqltemplate/mocks/WithResults.go +++ b/pkg/storage/unified/sql/sqltemplate/mocks/WithResults.go @@ -7,7 +7,7 @@ import ( mock "github.com/stretchr/testify/mock" - sqltemplate "github.com/grafana/grafana/pkg/services/store/entity/sqlstash/sqltemplate" + sqltemplate "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" ) // WithResults is an autogenerated mock type for the WithResults type diff --git a/pkg/storage/unified/sqlnext/sql_resources.go b/pkg/storage/unified/sqlnext/sql_resources.go index 01f5f72c267..93484ed34d6 100644 --- a/pkg/storage/unified/sqlnext/sql_resources.go +++ b/pkg/storage/unified/sqlnext/sql_resources.go @@ -15,8 +15,8 @@ import ( "github.com/grafana/grafana/pkg/services/sqlstore/session" "github.com/grafana/grafana/pkg/services/store/entity/db" "github.com/grafana/grafana/pkg/services/store/entity/sqlstash" - "github.com/grafana/grafana/pkg/services/store/entity/sqlstash/sqltemplate" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" ) // Package-level errors.