mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
SQL: Add sql template test helper (#91953)
This commit is contained in:
parent
ac72098248
commit
d9cabe5e14
@ -29,7 +29,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type sqlQuery struct {
|
type sqlQuery struct {
|
||||||
*sqltemplate.SQLTemplate
|
sqltemplate.SQLTemplateIface
|
||||||
Query *DashboardQuery
|
Query *DashboardQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,167 +1,69 @@
|
|||||||
package legacy
|
package legacy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
"testing"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate/mocks"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed testdata/*
|
|
||||||
var testdataFS embed.FS
|
|
||||||
|
|
||||||
func testdata(t *testing.T, filename string) []byte {
|
|
||||||
t.Helper()
|
|
||||||
b, err := testdataFS.ReadFile(`testdata/` + filename)
|
|
||||||
if err != nil {
|
|
||||||
writeTestData(filename, "<empty>")
|
|
||||||
assert.Fail(t, "missing test file")
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeTestData(filename, value string) {
|
|
||||||
_ = os.WriteFile(filepath.Join("testdata", filename), []byte(value), 0777)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestQueries(t *testing.T) {
|
func TestQueries(t *testing.T) {
|
||||||
t.Parallel()
|
mocks.CheckQuerySnapshots(t, mocks.TemplateTestSetup{
|
||||||
|
RootDir: "testdata",
|
||||||
// Check each dialect
|
Templates: map[*template.Template][]mocks.TemplateTestCase{
|
||||||
dialects := []sqltemplate.Dialect{
|
sqlQueryDashboards: {
|
||||||
sqltemplate.MySQL,
|
{
|
||||||
sqltemplate.SQLite,
|
Name: "history_uid",
|
||||||
sqltemplate.PostgreSQL,
|
Data: &sqlQuery{
|
||||||
}
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
|
Query: &DashboardQuery{
|
||||||
// Each template has one or more test cases, each identified with a
|
OrgID: 2,
|
||||||
// descriptive name (e.g. "happy path", "error twiddling the frobb"). Each
|
UID: "UUU",
|
||||||
// of them will test that for the same input data they must produce a result
|
},
|
||||||
// that will depend on the Dialect. Expected queries should be defined in
|
|
||||||
// separate files in the testdata directory. This improves the testing
|
|
||||||
// experience by separating test data from test code, since mixing both
|
|
||||||
// tends to make it more difficult to reason about what is being done,
|
|
||||||
// especially as we want testing code to scale and make it easy to add
|
|
||||||
// tests.
|
|
||||||
type (
|
|
||||||
testCase = struct {
|
|
||||||
Name string
|
|
||||||
|
|
||||||
// Data should be the struct passed to the template.
|
|
||||||
Data sqltemplate.SQLTemplateIface
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Define tests cases. Most templates are trivial and testing that they
|
|
||||||
// generate correct code for a single Dialect is fine, since the one thing
|
|
||||||
// that always changes is how SQL placeholder arguments are passed (most
|
|
||||||
// Dialects use `?` while PostgreSQL uses `$1`, `$2`, etc.), and that is
|
|
||||||
// something that should be tested in the Dialect implementation instead of
|
|
||||||
// here. We will ask to have at least one test per SQL template, and we will
|
|
||||||
// lean to test MySQL. Templates containing branching (conditionals, loops,
|
|
||||||
// etc.) should be exercised at least once in each of their branches.
|
|
||||||
//
|
|
||||||
// NOTE: in the Data field, make sure to have pointers populated to simulate
|
|
||||||
// data is set as it would be in a real request. The data being correctly
|
|
||||||
// populated in each case should be tested in integration tests, where the
|
|
||||||
// data will actually flow to and from a real database. In this tests we
|
|
||||||
// only care about producing the correct SQL.
|
|
||||||
testCases := map[*template.Template][]*testCase{
|
|
||||||
sqlQueryDashboards: {
|
|
||||||
{
|
|
||||||
Name: "history_uid",
|
|
||||||
Data: &sqlQuery{
|
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
|
||||||
Query: &DashboardQuery{
|
|
||||||
OrgID: 2,
|
|
||||||
UID: "UUU",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
Name: "history_uid_at_version",
|
||||||
Name: "history_uid_at_version",
|
Data: &sqlQuery{
|
||||||
Data: &sqlQuery{
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
Query: &DashboardQuery{
|
||||||
Query: &DashboardQuery{
|
OrgID: 2,
|
||||||
OrgID: 2,
|
UID: "UUU",
|
||||||
UID: "UUU",
|
Version: 3,
|
||||||
Version: 3,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
Name: "history_uid_second_page",
|
||||||
Name: "history_uid_second_page",
|
Data: &sqlQuery{
|
||||||
Data: &sqlQuery{
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
Query: &DashboardQuery{
|
||||||
Query: &DashboardQuery{
|
OrgID: 2,
|
||||||
OrgID: 2,
|
UID: "UUU",
|
||||||
UID: "UUU",
|
LastID: 7,
|
||||||
LastID: 7,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
Name: "dashboard",
|
||||||
Name: "dashboard",
|
Data: &sqlQuery{
|
||||||
Data: &sqlQuery{
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
Query: &DashboardQuery{
|
||||||
Query: &DashboardQuery{
|
OrgID: 2,
|
||||||
OrgID: 2,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
Name: "dashboard_next_page",
|
||||||
Name: "dashboard_next_page",
|
Data: &sqlQuery{
|
||||||
Data: &sqlQuery{
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
Query: &DashboardQuery{
|
||||||
Query: &DashboardQuery{
|
OrgID: 2,
|
||||||
OrgID: 2,
|
LastID: 22,
|
||||||
LastID: 22,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
|
|
||||||
// Execute test cases
|
|
||||||
for tmpl, tcs := range testCases {
|
|
||||||
t.Run(tmpl.Name(), func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
for _, tc := range tcs {
|
|
||||||
t.Run(tc.Name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
for _, dialect := range dialects {
|
|
||||||
filename := dialect.DialectName() + "__" + tc.Name + ".sql"
|
|
||||||
t.Run(filename, func(t *testing.T) {
|
|
||||||
// not parallel because we're sharing tc.Data, not
|
|
||||||
// worth it deep cloning
|
|
||||||
|
|
||||||
expectedQuery := string(testdata(t, filename))
|
|
||||||
//expectedQuery := sqltemplate.FormatSQL(rawQuery)
|
|
||||||
|
|
||||||
tc.Data.SetDialect(dialect)
|
|
||||||
err := tc.Data.Validate()
|
|
||||||
require.NoError(t, err)
|
|
||||||
got, err := sqltemplate.Execute(tmpl, tc.Data)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
got = sqltemplate.RemoveEmptyLines(got)
|
|
||||||
if diff := cmp.Diff(expectedQuery, got); diff != "" {
|
|
||||||
writeTestData(filename, got)
|
|
||||||
t.Errorf("%s: %s", tc.Name, diff)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -92,8 +92,8 @@ func (a *dashboardSqlAccess) getRows(ctx context.Context, query *DashboardQuery)
|
|||||||
}
|
}
|
||||||
|
|
||||||
req := sqlQuery{
|
req := sqlQuery{
|
||||||
SQLTemplate: sqltemplate.New(a.dialect),
|
SQLTemplateIface: sqltemplate.New(a.dialect),
|
||||||
Query: query,
|
Query: query,
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpl := sqlQueryDashboards
|
tmpl := sqlQueryDashboards
|
||||||
|
@ -14,5 +14,5 @@ SELECT
|
|||||||
LEFT OUTER JOIN `user` AS created_user ON dashboard.created_by = created_user.id
|
LEFT OUTER JOIN `user` AS created_user ON dashboard.created_by = created_user.id
|
||||||
LEFT OUTER JOIN `user` AS updated_user ON dashboard.updated_by = updated_user.id
|
LEFT OUTER JOIN `user` AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
WHERE dashboard.is_folder = false
|
WHERE dashboard.is_folder = false
|
||||||
AND dashboard.org_id = ?
|
AND dashboard.org_id = 2
|
||||||
ORDER BY dashboard.id DESC
|
ORDER BY dashboard.id DESC
|
@ -14,7 +14,7 @@ SELECT
|
|||||||
LEFT OUTER JOIN `user` AS created_user ON dashboard.created_by = created_user.id
|
LEFT OUTER JOIN `user` AS created_user ON dashboard.created_by = created_user.id
|
||||||
LEFT OUTER JOIN `user` AS updated_user ON dashboard.updated_by = updated_user.id
|
LEFT OUTER JOIN `user` AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
WHERE dashboard.is_folder = false
|
WHERE dashboard.is_folder = false
|
||||||
AND dashboard.org_id = ?
|
AND dashboard.org_id = 2
|
||||||
AND dashboard.id > ?
|
AND dashboard.id > 22
|
||||||
AND dashboard.deleted IS NULL
|
AND dashboard.deleted IS NULL
|
||||||
ORDER BY dashboard.id DESC
|
ORDER BY dashboard.id DESC
|
19
pkg/registry/apis/dashboard/legacy/testdata/mysql--query_dashboards-history_uid.sql
vendored
Executable file
19
pkg/registry/apis/dashboard/legacy/testdata/mysql--query_dashboards-history_uid.sql
vendored
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
SELECT
|
||||||
|
dashboard.org_id, dashboard.id,
|
||||||
|
dashboard.uid, dashboard.folder_uid,
|
||||||
|
dashboard.deleted, plugin_id,
|
||||||
|
dashboard_provisioning.name as origin_name,
|
||||||
|
dashboard_provisioning.external_id as origin_path,
|
||||||
|
dashboard_provisioning.check_sum as origin_key,
|
||||||
|
dashboard_provisioning.updated as origin_ts,
|
||||||
|
dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id,
|
||||||
|
dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id,
|
||||||
|
dashboard.version, '' as message, dashboard.data
|
||||||
|
FROM dashboard
|
||||||
|
LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id
|
||||||
|
LEFT OUTER JOIN `user` AS created_user ON dashboard.created_by = created_user.id
|
||||||
|
LEFT OUTER JOIN `user` AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
|
WHERE dashboard.is_folder = false
|
||||||
|
AND dashboard.org_id = 2
|
||||||
|
AND dashboard.uid = 'UUU'
|
||||||
|
ORDER BY dashboard.id DESC
|
@ -15,6 +15,6 @@ SELECT
|
|||||||
LEFT OUTER JOIN `user` AS created_user ON dashboard.created_by = created_user.id
|
LEFT OUTER JOIN `user` AS created_user ON dashboard.created_by = created_user.id
|
||||||
LEFT OUTER JOIN `user` AS updated_user ON dashboard.updated_by = updated_user.id
|
LEFT OUTER JOIN `user` AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
WHERE dashboard.is_folder = false
|
WHERE dashboard.is_folder = false
|
||||||
AND dashboard.org_id = ?
|
AND dashboard.org_id = 2
|
||||||
AND dashboard_version.version = ?
|
AND dashboard_version.version = 3
|
||||||
ORDER BY dashboard_version.version DESC
|
ORDER BY dashboard_version.version DESC
|
20
pkg/registry/apis/dashboard/legacy/testdata/mysql--query_dashboards-history_uid_second_page.sql
vendored
Executable file
20
pkg/registry/apis/dashboard/legacy/testdata/mysql--query_dashboards-history_uid_second_page.sql
vendored
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
SELECT
|
||||||
|
dashboard.org_id, dashboard.id,
|
||||||
|
dashboard.uid, dashboard.folder_uid,
|
||||||
|
dashboard.deleted, plugin_id,
|
||||||
|
dashboard_provisioning.name as origin_name,
|
||||||
|
dashboard_provisioning.external_id as origin_path,
|
||||||
|
dashboard_provisioning.check_sum as origin_key,
|
||||||
|
dashboard_provisioning.updated as origin_ts,
|
||||||
|
dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id,
|
||||||
|
dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id,
|
||||||
|
dashboard.version, '' as message, dashboard.data
|
||||||
|
FROM dashboard
|
||||||
|
LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id
|
||||||
|
LEFT OUTER JOIN `user` AS created_user ON dashboard.created_by = created_user.id
|
||||||
|
LEFT OUTER JOIN `user` AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
|
WHERE dashboard.is_folder = false
|
||||||
|
AND dashboard.org_id = 2
|
||||||
|
AND dashboard.uid = 'UUU'
|
||||||
|
AND dashboard.deleted IS NULL
|
||||||
|
ORDER BY dashboard.id DESC
|
@ -14,6 +14,5 @@ SELECT
|
|||||||
LEFT OUTER JOIN `user` AS created_user ON dashboard.created_by = created_user.id
|
LEFT OUTER JOIN `user` AS created_user ON dashboard.created_by = created_user.id
|
||||||
LEFT OUTER JOIN `user` AS updated_user ON dashboard.updated_by = updated_user.id
|
LEFT OUTER JOIN `user` AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
WHERE dashboard.is_folder = false
|
WHERE dashboard.is_folder = false
|
||||||
AND dashboard.org_id = ?
|
AND dashboard.org_id = 2
|
||||||
AND dashboard.uid = ?
|
|
||||||
ORDER BY dashboard.id DESC
|
ORDER BY dashboard.id DESC
|
@ -14,7 +14,7 @@ SELECT
|
|||||||
LEFT OUTER JOIN `user` AS created_user ON dashboard.created_by = created_user.id
|
LEFT OUTER JOIN `user` AS created_user ON dashboard.created_by = created_user.id
|
||||||
LEFT OUTER JOIN `user` AS updated_user ON dashboard.updated_by = updated_user.id
|
LEFT OUTER JOIN `user` AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
WHERE dashboard.is_folder = false
|
WHERE dashboard.is_folder = false
|
||||||
AND dashboard.org_id = ?
|
AND dashboard.org_id = 2
|
||||||
AND dashboard.uid = ?
|
AND dashboard.id > 22
|
||||||
AND dashboard.deleted IS NULL
|
AND dashboard.deleted IS NULL
|
||||||
ORDER BY dashboard.id DESC
|
ORDER BY dashboard.id DESC
|
19
pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-history_uid.sql
vendored
Executable file
19
pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-history_uid.sql
vendored
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
SELECT
|
||||||
|
dashboard.org_id, dashboard.id,
|
||||||
|
dashboard.uid, dashboard.folder_uid,
|
||||||
|
dashboard.deleted, plugin_id,
|
||||||
|
dashboard_provisioning.name as origin_name,
|
||||||
|
dashboard_provisioning.external_id as origin_path,
|
||||||
|
dashboard_provisioning.check_sum as origin_key,
|
||||||
|
dashboard_provisioning.updated as origin_ts,
|
||||||
|
dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id,
|
||||||
|
dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id,
|
||||||
|
dashboard.version, '' as message, dashboard.data
|
||||||
|
FROM dashboard
|
||||||
|
LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id
|
||||||
|
LEFT OUTER JOIN `user` AS created_user ON dashboard.created_by = created_user.id
|
||||||
|
LEFT OUTER JOIN `user` AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
|
WHERE dashboard.is_folder = false
|
||||||
|
AND dashboard.org_id = 2
|
||||||
|
AND dashboard.uid = 'UUU'
|
||||||
|
ORDER BY dashboard.id DESC
|
20
pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-history_uid_at_version.sql
vendored
Executable file
20
pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-history_uid_at_version.sql
vendored
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
SELECT
|
||||||
|
dashboard.org_id, dashboard.id,
|
||||||
|
dashboard.uid, dashboard.folder_uid,
|
||||||
|
dashboard.deleted, plugin_id,
|
||||||
|
dashboard_provisioning.name as origin_name,
|
||||||
|
dashboard_provisioning.external_id as origin_path,
|
||||||
|
dashboard_provisioning.check_sum as origin_key,
|
||||||
|
dashboard_provisioning.updated as origin_ts,
|
||||||
|
dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id,
|
||||||
|
dashboard_version.created, updated_user.uid as updated_by,updated_user.id as created_by_id,
|
||||||
|
dashboard_version.version, dashboard_version.message, dashboard_version.data
|
||||||
|
FROM dashboard
|
||||||
|
LEFT OUTER JOIN dashboard_version ON dashboard.id = dashboard_version.dashboard_id
|
||||||
|
LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id
|
||||||
|
LEFT OUTER JOIN `user` AS created_user ON dashboard.created_by = created_user.id
|
||||||
|
LEFT OUTER JOIN `user` AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
|
WHERE dashboard.is_folder = false
|
||||||
|
AND dashboard.org_id = 2
|
||||||
|
AND dashboard_version.version = 3
|
||||||
|
ORDER BY dashboard_version.version DESC
|
20
pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-history_uid_second_page.sql
vendored
Executable file
20
pkg/registry/apis/dashboard/legacy/testdata/mysql-query_dashboards-history_uid_second_page.sql
vendored
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
SELECT
|
||||||
|
dashboard.org_id, dashboard.id,
|
||||||
|
dashboard.uid, dashboard.folder_uid,
|
||||||
|
dashboard.deleted, plugin_id,
|
||||||
|
dashboard_provisioning.name as origin_name,
|
||||||
|
dashboard_provisioning.external_id as origin_path,
|
||||||
|
dashboard_provisioning.check_sum as origin_key,
|
||||||
|
dashboard_provisioning.updated as origin_ts,
|
||||||
|
dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id,
|
||||||
|
dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id,
|
||||||
|
dashboard.version, '' as message, dashboard.data
|
||||||
|
FROM dashboard
|
||||||
|
LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id
|
||||||
|
LEFT OUTER JOIN `user` AS created_user ON dashboard.created_by = created_user.id
|
||||||
|
LEFT OUTER JOIN `user` AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
|
WHERE dashboard.is_folder = false
|
||||||
|
AND dashboard.org_id = 2
|
||||||
|
AND dashboard.uid = 'UUU'
|
||||||
|
AND dashboard.deleted IS NULL
|
||||||
|
ORDER BY dashboard.id DESC
|
@ -14,5 +14,5 @@ SELECT
|
|||||||
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
||||||
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
WHERE dashboard.is_folder = false
|
WHERE dashboard.is_folder = false
|
||||||
AND dashboard.org_id = ?
|
AND dashboard.org_id = 2
|
||||||
ORDER BY dashboard.id DESC
|
ORDER BY dashboard.id DESC
|
@ -14,7 +14,7 @@ SELECT
|
|||||||
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
||||||
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
WHERE dashboard.is_folder = false
|
WHERE dashboard.is_folder = false
|
||||||
AND dashboard.org_id = ?
|
AND dashboard.org_id = 2
|
||||||
AND dashboard.id > ?
|
AND dashboard.id > 22
|
||||||
AND dashboard.deleted IS NULL
|
AND dashboard.deleted IS NULL
|
||||||
ORDER BY dashboard.id DESC
|
ORDER BY dashboard.id DESC
|
19
pkg/registry/apis/dashboard/legacy/testdata/postgres--query_dashboards-history_uid.sql
vendored
Executable file
19
pkg/registry/apis/dashboard/legacy/testdata/postgres--query_dashboards-history_uid.sql
vendored
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
SELECT
|
||||||
|
dashboard.org_id, dashboard.id,
|
||||||
|
dashboard.uid, dashboard.folder_uid,
|
||||||
|
dashboard.deleted, plugin_id,
|
||||||
|
dashboard_provisioning.name as origin_name,
|
||||||
|
dashboard_provisioning.external_id as origin_path,
|
||||||
|
dashboard_provisioning.check_sum as origin_key,
|
||||||
|
dashboard_provisioning.updated as origin_ts,
|
||||||
|
dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id,
|
||||||
|
dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id,
|
||||||
|
dashboard.version, '' as message, dashboard.data
|
||||||
|
FROM dashboard
|
||||||
|
LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id
|
||||||
|
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
||||||
|
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
|
WHERE dashboard.is_folder = false
|
||||||
|
AND dashboard.org_id = 2
|
||||||
|
AND dashboard.uid = 'UUU'
|
||||||
|
ORDER BY dashboard.id DESC
|
@ -15,6 +15,6 @@ SELECT
|
|||||||
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
||||||
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
WHERE dashboard.is_folder = false
|
WHERE dashboard.is_folder = false
|
||||||
AND dashboard.org_id = ?
|
AND dashboard.org_id = 2
|
||||||
AND dashboard_version.version = ?
|
AND dashboard_version.version = 3
|
||||||
ORDER BY dashboard_version.version DESC
|
ORDER BY dashboard_version.version DESC
|
20
pkg/registry/apis/dashboard/legacy/testdata/postgres--query_dashboards-history_uid_second_page.sql
vendored
Executable file
20
pkg/registry/apis/dashboard/legacy/testdata/postgres--query_dashboards-history_uid_second_page.sql
vendored
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
SELECT
|
||||||
|
dashboard.org_id, dashboard.id,
|
||||||
|
dashboard.uid, dashboard.folder_uid,
|
||||||
|
dashboard.deleted, plugin_id,
|
||||||
|
dashboard_provisioning.name as origin_name,
|
||||||
|
dashboard_provisioning.external_id as origin_path,
|
||||||
|
dashboard_provisioning.check_sum as origin_key,
|
||||||
|
dashboard_provisioning.updated as origin_ts,
|
||||||
|
dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id,
|
||||||
|
dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id,
|
||||||
|
dashboard.version, '' as message, dashboard.data
|
||||||
|
FROM dashboard
|
||||||
|
LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id
|
||||||
|
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
||||||
|
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
|
WHERE dashboard.is_folder = false
|
||||||
|
AND dashboard.org_id = 2
|
||||||
|
AND dashboard.uid = 'UUU'
|
||||||
|
AND dashboard.deleted IS NULL
|
||||||
|
ORDER BY dashboard.id DESC
|
@ -14,5 +14,5 @@ SELECT
|
|||||||
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
||||||
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
WHERE dashboard.is_folder = false
|
WHERE dashboard.is_folder = false
|
||||||
AND dashboard.org_id = $1
|
AND dashboard.org_id = 2
|
||||||
ORDER BY dashboard.id DESC
|
ORDER BY dashboard.id DESC
|
@ -14,7 +14,7 @@ SELECT
|
|||||||
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
||||||
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
WHERE dashboard.is_folder = false
|
WHERE dashboard.is_folder = false
|
||||||
AND dashboard.org_id = ?
|
AND dashboard.org_id = 2
|
||||||
AND dashboard.uid = ?
|
AND dashboard.id > 22
|
||||||
AND dashboard.deleted IS NULL
|
AND dashboard.deleted IS NULL
|
||||||
ORDER BY dashboard.id DESC
|
ORDER BY dashboard.id DESC
|
19
pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-history_uid.sql
vendored
Executable file
19
pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-history_uid.sql
vendored
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
SELECT
|
||||||
|
dashboard.org_id, dashboard.id,
|
||||||
|
dashboard.uid, dashboard.folder_uid,
|
||||||
|
dashboard.deleted, plugin_id,
|
||||||
|
dashboard_provisioning.name as origin_name,
|
||||||
|
dashboard_provisioning.external_id as origin_path,
|
||||||
|
dashboard_provisioning.check_sum as origin_key,
|
||||||
|
dashboard_provisioning.updated as origin_ts,
|
||||||
|
dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id,
|
||||||
|
dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id,
|
||||||
|
dashboard.version, '' as message, dashboard.data
|
||||||
|
FROM dashboard
|
||||||
|
LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id
|
||||||
|
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
||||||
|
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
|
WHERE dashboard.is_folder = false
|
||||||
|
AND dashboard.org_id = 2
|
||||||
|
AND dashboard.uid = 'UUU'
|
||||||
|
ORDER BY dashboard.id DESC
|
@ -15,6 +15,6 @@ SELECT
|
|||||||
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
||||||
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
WHERE dashboard.is_folder = false
|
WHERE dashboard.is_folder = false
|
||||||
AND dashboard.org_id = $1
|
AND dashboard.org_id = 2
|
||||||
AND dashboard_version.version = $2
|
AND dashboard_version.version = 3
|
||||||
ORDER BY dashboard_version.version DESC
|
ORDER BY dashboard_version.version DESC
|
20
pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-history_uid_second_page.sql
vendored
Executable file
20
pkg/registry/apis/dashboard/legacy/testdata/postgres-query_dashboards-history_uid_second_page.sql
vendored
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
SELECT
|
||||||
|
dashboard.org_id, dashboard.id,
|
||||||
|
dashboard.uid, dashboard.folder_uid,
|
||||||
|
dashboard.deleted, plugin_id,
|
||||||
|
dashboard_provisioning.name as origin_name,
|
||||||
|
dashboard_provisioning.external_id as origin_path,
|
||||||
|
dashboard_provisioning.check_sum as origin_key,
|
||||||
|
dashboard_provisioning.updated as origin_ts,
|
||||||
|
dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id,
|
||||||
|
dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id,
|
||||||
|
dashboard.version, '' as message, dashboard.data
|
||||||
|
FROM dashboard
|
||||||
|
LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id
|
||||||
|
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
||||||
|
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
|
WHERE dashboard.is_folder = false
|
||||||
|
AND dashboard.org_id = 2
|
||||||
|
AND dashboard.uid = 'UUU'
|
||||||
|
AND dashboard.deleted IS NULL
|
||||||
|
ORDER BY dashboard.id DESC
|
@ -14,6 +14,5 @@ SELECT
|
|||||||
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
||||||
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
WHERE dashboard.is_folder = false
|
WHERE dashboard.is_folder = false
|
||||||
AND dashboard.org_id = ?
|
AND dashboard.org_id = 2
|
||||||
AND dashboard.uid = ?
|
|
||||||
ORDER BY dashboard.id DESC
|
ORDER BY dashboard.id DESC
|
@ -14,7 +14,7 @@ SELECT
|
|||||||
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
||||||
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
WHERE dashboard.is_folder = false
|
WHERE dashboard.is_folder = false
|
||||||
AND dashboard.org_id = $1
|
AND dashboard.org_id = 2
|
||||||
AND dashboard.id > $2
|
AND dashboard.id > 22
|
||||||
AND dashboard.deleted IS NULL
|
AND dashboard.deleted IS NULL
|
||||||
ORDER BY dashboard.id DESC
|
ORDER BY dashboard.id DESC
|
19
pkg/registry/apis/dashboard/legacy/testdata/sqlite--query_dashboards-history_uid.sql
vendored
Executable file
19
pkg/registry/apis/dashboard/legacy/testdata/sqlite--query_dashboards-history_uid.sql
vendored
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
SELECT
|
||||||
|
dashboard.org_id, dashboard.id,
|
||||||
|
dashboard.uid, dashboard.folder_uid,
|
||||||
|
dashboard.deleted, plugin_id,
|
||||||
|
dashboard_provisioning.name as origin_name,
|
||||||
|
dashboard_provisioning.external_id as origin_path,
|
||||||
|
dashboard_provisioning.check_sum as origin_key,
|
||||||
|
dashboard_provisioning.updated as origin_ts,
|
||||||
|
dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id,
|
||||||
|
dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id,
|
||||||
|
dashboard.version, '' as message, dashboard.data
|
||||||
|
FROM dashboard
|
||||||
|
LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id
|
||||||
|
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
||||||
|
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
|
WHERE dashboard.is_folder = false
|
||||||
|
AND dashboard.org_id = 2
|
||||||
|
AND dashboard.uid = 'UUU'
|
||||||
|
ORDER BY dashboard.id DESC
|
20
pkg/registry/apis/dashboard/legacy/testdata/sqlite--query_dashboards-history_uid_at_version.sql
vendored
Executable file
20
pkg/registry/apis/dashboard/legacy/testdata/sqlite--query_dashboards-history_uid_at_version.sql
vendored
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
SELECT
|
||||||
|
dashboard.org_id, dashboard.id,
|
||||||
|
dashboard.uid, dashboard.folder_uid,
|
||||||
|
dashboard.deleted, plugin_id,
|
||||||
|
dashboard_provisioning.name as origin_name,
|
||||||
|
dashboard_provisioning.external_id as origin_path,
|
||||||
|
dashboard_provisioning.check_sum as origin_key,
|
||||||
|
dashboard_provisioning.updated as origin_ts,
|
||||||
|
dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id,
|
||||||
|
dashboard_version.created, updated_user.uid as updated_by,updated_user.id as created_by_id,
|
||||||
|
dashboard_version.version, dashboard_version.message, dashboard_version.data
|
||||||
|
FROM dashboard
|
||||||
|
LEFT OUTER JOIN dashboard_version ON dashboard.id = dashboard_version.dashboard_id
|
||||||
|
LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id
|
||||||
|
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
||||||
|
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
|
WHERE dashboard.is_folder = false
|
||||||
|
AND dashboard.org_id = 2
|
||||||
|
AND dashboard_version.version = 3
|
||||||
|
ORDER BY dashboard_version.version DESC
|
20
pkg/registry/apis/dashboard/legacy/testdata/sqlite--query_dashboards-history_uid_second_page.sql
vendored
Executable file
20
pkg/registry/apis/dashboard/legacy/testdata/sqlite--query_dashboards-history_uid_second_page.sql
vendored
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
SELECT
|
||||||
|
dashboard.org_id, dashboard.id,
|
||||||
|
dashboard.uid, dashboard.folder_uid,
|
||||||
|
dashboard.deleted, plugin_id,
|
||||||
|
dashboard_provisioning.name as origin_name,
|
||||||
|
dashboard_provisioning.external_id as origin_path,
|
||||||
|
dashboard_provisioning.check_sum as origin_key,
|
||||||
|
dashboard_provisioning.updated as origin_ts,
|
||||||
|
dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id,
|
||||||
|
dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id,
|
||||||
|
dashboard.version, '' as message, dashboard.data
|
||||||
|
FROM dashboard
|
||||||
|
LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id
|
||||||
|
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
||||||
|
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
|
WHERE dashboard.is_folder = false
|
||||||
|
AND dashboard.org_id = 2
|
||||||
|
AND dashboard.uid = 'UUU'
|
||||||
|
AND dashboard.deleted IS NULL
|
||||||
|
ORDER BY dashboard.id DESC
|
@ -14,6 +14,5 @@ SELECT
|
|||||||
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
||||||
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
WHERE dashboard.is_folder = false
|
WHERE dashboard.is_folder = false
|
||||||
AND dashboard.org_id = $1
|
AND dashboard.org_id = 2
|
||||||
AND dashboard.uid = $2
|
|
||||||
ORDER BY dashboard.id DESC
|
ORDER BY dashboard.id DESC
|
@ -14,7 +14,7 @@ SELECT
|
|||||||
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
||||||
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
WHERE dashboard.is_folder = false
|
WHERE dashboard.is_folder = false
|
||||||
AND dashboard.org_id = $1
|
AND dashboard.org_id = 2
|
||||||
AND dashboard.uid = $2
|
AND dashboard.id > 22
|
||||||
AND dashboard.deleted IS NULL
|
AND dashboard.deleted IS NULL
|
||||||
ORDER BY dashboard.id DESC
|
ORDER BY dashboard.id DESC
|
19
pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-history_uid.sql
vendored
Executable file
19
pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-history_uid.sql
vendored
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
SELECT
|
||||||
|
dashboard.org_id, dashboard.id,
|
||||||
|
dashboard.uid, dashboard.folder_uid,
|
||||||
|
dashboard.deleted, plugin_id,
|
||||||
|
dashboard_provisioning.name as origin_name,
|
||||||
|
dashboard_provisioning.external_id as origin_path,
|
||||||
|
dashboard_provisioning.check_sum as origin_key,
|
||||||
|
dashboard_provisioning.updated as origin_ts,
|
||||||
|
dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id,
|
||||||
|
dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id,
|
||||||
|
dashboard.version, '' as message, dashboard.data
|
||||||
|
FROM dashboard
|
||||||
|
LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id
|
||||||
|
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
||||||
|
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
|
WHERE dashboard.is_folder = false
|
||||||
|
AND dashboard.org_id = 2
|
||||||
|
AND dashboard.uid = 'UUU'
|
||||||
|
ORDER BY dashboard.id DESC
|
20
pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-history_uid_at_version.sql
vendored
Executable file
20
pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-history_uid_at_version.sql
vendored
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
SELECT
|
||||||
|
dashboard.org_id, dashboard.id,
|
||||||
|
dashboard.uid, dashboard.folder_uid,
|
||||||
|
dashboard.deleted, plugin_id,
|
||||||
|
dashboard_provisioning.name as origin_name,
|
||||||
|
dashboard_provisioning.external_id as origin_path,
|
||||||
|
dashboard_provisioning.check_sum as origin_key,
|
||||||
|
dashboard_provisioning.updated as origin_ts,
|
||||||
|
dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id,
|
||||||
|
dashboard_version.created, updated_user.uid as updated_by,updated_user.id as created_by_id,
|
||||||
|
dashboard_version.version, dashboard_version.message, dashboard_version.data
|
||||||
|
FROM dashboard
|
||||||
|
LEFT OUTER JOIN dashboard_version ON dashboard.id = dashboard_version.dashboard_id
|
||||||
|
LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id
|
||||||
|
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
||||||
|
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
|
WHERE dashboard.is_folder = false
|
||||||
|
AND dashboard.org_id = 2
|
||||||
|
AND dashboard_version.version = 3
|
||||||
|
ORDER BY dashboard_version.version DESC
|
20
pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-history_uid_second_page.sql
vendored
Executable file
20
pkg/registry/apis/dashboard/legacy/testdata/sqlite-query_dashboards-history_uid_second_page.sql
vendored
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
SELECT
|
||||||
|
dashboard.org_id, dashboard.id,
|
||||||
|
dashboard.uid, dashboard.folder_uid,
|
||||||
|
dashboard.deleted, plugin_id,
|
||||||
|
dashboard_provisioning.name as origin_name,
|
||||||
|
dashboard_provisioning.external_id as origin_path,
|
||||||
|
dashboard_provisioning.check_sum as origin_key,
|
||||||
|
dashboard_provisioning.updated as origin_ts,
|
||||||
|
dashboard.created, created_user.uid as created_by, dashboard.created_by as created_by_id,
|
||||||
|
dashboard.updated, updated_user.uid as updated_by, dashboard.updated_by as updated_by_id,
|
||||||
|
dashboard.version, '' as message, dashboard.data
|
||||||
|
FROM dashboard
|
||||||
|
LEFT OUTER JOIN dashboard_provisioning ON dashboard.id = dashboard_provisioning.dashboard_id
|
||||||
|
LEFT OUTER JOIN "user" AS created_user ON dashboard.created_by = created_user.id
|
||||||
|
LEFT OUTER JOIN "user" AS updated_user ON dashboard.updated_by = updated_user.id
|
||||||
|
WHERE dashboard.is_folder = false
|
||||||
|
AND dashboard.org_id = 2
|
||||||
|
AND dashboard.uid = 'UUU'
|
||||||
|
AND dashboard.deleted IS NULL
|
||||||
|
ORDER BY dashboard.id DESC
|
@ -55,8 +55,8 @@ func (s *legacySQLStore) ListTeams(ctx context.Context, ns claims.NamespaceInfo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
req := sqlQueryListTeams{
|
req := sqlQueryListTeams{
|
||||||
SQLTemplate: sqltemplate.New(s.dialect),
|
SQLTemplateIface: sqltemplate.New(s.dialect),
|
||||||
Query: &query,
|
Query: &query,
|
||||||
}
|
}
|
||||||
|
|
||||||
rawQuery, err := sqltemplate.Execute(sqlQueryTeams, req)
|
rawQuery, err := sqltemplate.Execute(sqlQueryTeams, req)
|
||||||
@ -117,8 +117,8 @@ func (s *legacySQLStore) ListUsers(ctx context.Context, ns claims.NamespaceInfo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
return s.queryUsers(ctx, sqlQueryUsers, sqlQueryListUsers{
|
return s.queryUsers(ctx, sqlQueryUsers, sqlQueryListUsers{
|
||||||
SQLTemplate: sqltemplate.New(s.dialect),
|
SQLTemplateIface: sqltemplate.New(s.dialect),
|
||||||
Query: &query,
|
Query: &query,
|
||||||
}, limit, query.UID != "")
|
}, limit, query.UID != "")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,7 +180,7 @@ func (s *legacySQLStore) GetDisplay(ctx context.Context, ns claims.NamespaceInfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
return s.queryUsers(ctx, sqlQueryDisplay, sqlQueryGetDisplay{
|
return s.queryUsers(ctx, sqlQueryDisplay, sqlQueryGetDisplay{
|
||||||
SQLTemplate: sqltemplate.New(s.dialect),
|
SQLTemplateIface: sqltemplate.New(s.dialect),
|
||||||
Query: &query,
|
Query: &query,
|
||||||
}, 10000, false)
|
}, 10000, false)
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type sqlQueryListUsers struct {
|
type sqlQueryListUsers struct {
|
||||||
*sqltemplate.SQLTemplate
|
sqltemplate.SQLTemplateIface
|
||||||
Query *ListUserQuery
|
Query *ListUserQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ func (r sqlQueryListUsers) Validate() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type sqlQueryListTeams struct {
|
type sqlQueryListTeams struct {
|
||||||
*sqltemplate.SQLTemplate
|
sqltemplate.SQLTemplateIface
|
||||||
Query *ListTeamQuery
|
Query *ListTeamQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ func (r sqlQueryListTeams) Validate() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type sqlQueryGetDisplay struct {
|
type sqlQueryGetDisplay struct {
|
||||||
*sqltemplate.SQLTemplate
|
sqltemplate.SQLTemplateIface
|
||||||
Query *GetUserDisplayQuery
|
Query *GetUserDisplayQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,207 +1,109 @@
|
|||||||
package legacy
|
package legacy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
"testing"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate/mocks"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed testdata/*
|
|
||||||
var testdataFS embed.FS
|
|
||||||
|
|
||||||
func testdata(t *testing.T, filename string) []byte {
|
|
||||||
t.Helper()
|
|
||||||
b, err := testdataFS.ReadFile(`testdata/` + filename)
|
|
||||||
if err != nil {
|
|
||||||
writeTestData(filename, "<empty>")
|
|
||||||
assert.Fail(t, "missing test file")
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeTestData(filename, value string) {
|
|
||||||
_ = os.WriteFile(filepath.Join("testdata", filename), []byte(value), 0777)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestQueries(t *testing.T) {
|
func TestQueries(t *testing.T) {
|
||||||
t.Parallel()
|
mocks.CheckQuerySnapshots(t, mocks.TemplateTestSetup{
|
||||||
|
RootDir: "testdata",
|
||||||
// Check each dialect
|
Templates: map[*template.Template][]mocks.TemplateTestCase{
|
||||||
dialects := []sqltemplate.Dialect{
|
sqlQueryTeams: {
|
||||||
sqltemplate.MySQL,
|
{
|
||||||
sqltemplate.SQLite,
|
Name: "teams_uid",
|
||||||
sqltemplate.PostgreSQL,
|
Data: &sqlQueryListTeams{
|
||||||
}
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
|
Query: &ListTeamQuery{
|
||||||
// Each template has one or more test cases, each identified with a
|
UID: "abc",
|
||||||
// descriptive name (e.g. "happy path", "error twiddling the frobb"). Each
|
},
|
||||||
// of them will test that for the same input data they must produce a result
|
},
|
||||||
// that will depend on the Dialect. Expected queries should be defined in
|
},
|
||||||
// separate files in the testdata directory. This improves the testing
|
{
|
||||||
// experience by separating test data from test code, since mixing both
|
Name: "teams_page_1",
|
||||||
// tends to make it more difficult to reason about what is being done,
|
Data: &sqlQueryListTeams{
|
||||||
// especially as we want testing code to scale and make it easy to add
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
// tests.
|
Query: &ListTeamQuery{
|
||||||
type (
|
Limit: 5,
|
||||||
testCase = struct {
|
},
|
||||||
Name string
|
},
|
||||||
|
},
|
||||||
// Data should be the struct passed to the template.
|
{
|
||||||
Data sqltemplate.SQLTemplateIface
|
Name: "teams_page_2",
|
||||||
}
|
Data: &sqlQueryListTeams{
|
||||||
)
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
|
Query: &ListTeamQuery{
|
||||||
// Define tests cases. Most templates are trivial and testing that they
|
ContinueID: 1,
|
||||||
// generate correct code for a single Dialect is fine, since the one thing
|
Limit: 2,
|
||||||
// that always changes is how SQL placeholder arguments are passed (most
|
},
|
||||||
// Dialects use `?` while PostgreSQL uses `$1`, `$2`, etc.), and that is
|
|
||||||
// something that should be tested in the Dialect implementation instead of
|
|
||||||
// here. We will ask to have at least one test per SQL template, and we will
|
|
||||||
// lean to test MySQL. Templates containing branching (conditionals, loops,
|
|
||||||
// etc.) should be exercised at least once in each of their branches.
|
|
||||||
//
|
|
||||||
// NOTE: in the Data field, make sure to have pointers populated to simulate
|
|
||||||
// data is set as it would be in a real request. The data being correctly
|
|
||||||
// populated in each case should be tested in integration tests, where the
|
|
||||||
// data will actually flow to and from a real database. In this tests we
|
|
||||||
// only care about producing the correct SQL.
|
|
||||||
testCases := map[*template.Template][]*testCase{
|
|
||||||
sqlQueryTeams: {
|
|
||||||
{
|
|
||||||
Name: "teams_uid",
|
|
||||||
Data: &sqlQueryListTeams{
|
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
|
||||||
Query: &ListTeamQuery{
|
|
||||||
UID: "abc",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
sqlQueryUsers: {
|
||||||
Name: "teams_page_1",
|
{
|
||||||
Data: &sqlQueryListTeams{
|
Name: "users_uid",
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
Data: &sqlQueryListUsers{
|
||||||
Query: &ListTeamQuery{
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
Limit: 5,
|
Query: &ListUserQuery{
|
||||||
|
UID: "abc",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "users_page_1",
|
||||||
|
Data: &sqlQueryListUsers{
|
||||||
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
|
Query: &ListUserQuery{
|
||||||
|
Limit: 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "users_page_2",
|
||||||
|
Data: &sqlQueryListUsers{
|
||||||
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
|
Query: &ListUserQuery{
|
||||||
|
ContinueID: 1,
|
||||||
|
Limit: 2,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
sqlQueryDisplay: {
|
||||||
Name: "teams_page_2",
|
{
|
||||||
Data: &sqlQueryListTeams{
|
Name: "display_uids",
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
Data: &sqlQueryGetDisplay{
|
||||||
Query: &ListTeamQuery{
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
ContinueID: 1,
|
Query: &GetUserDisplayQuery{
|
||||||
Limit: 2,
|
OrgID: 2,
|
||||||
|
UIDs: []string{"a", "b"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "display_ids",
|
||||||
|
Data: &sqlQueryGetDisplay{
|
||||||
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
|
Query: &GetUserDisplayQuery{
|
||||||
|
OrgID: 2,
|
||||||
|
IDs: []int64{1, 2},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "display_ids_uids",
|
||||||
|
Data: &sqlQueryGetDisplay{
|
||||||
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
|
Query: &GetUserDisplayQuery{
|
||||||
|
OrgID: 2,
|
||||||
|
UIDs: []string{"a", "b"},
|
||||||
|
IDs: []int64{1, 2},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
sqlQueryUsers: {
|
})
|
||||||
{
|
|
||||||
Name: "users_uid",
|
|
||||||
Data: &sqlQueryListUsers{
|
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
|
||||||
Query: &ListUserQuery{
|
|
||||||
UID: "abc",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "users_page_1",
|
|
||||||
Data: &sqlQueryListUsers{
|
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
|
||||||
Query: &ListUserQuery{
|
|
||||||
Limit: 5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "users_page_2",
|
|
||||||
Data: &sqlQueryListUsers{
|
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
|
||||||
Query: &ListUserQuery{
|
|
||||||
ContinueID: 1,
|
|
||||||
Limit: 2,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
sqlQueryDisplay: {
|
|
||||||
{
|
|
||||||
Name: "display_uids",
|
|
||||||
Data: &sqlQueryGetDisplay{
|
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
|
||||||
Query: &GetUserDisplayQuery{
|
|
||||||
OrgID: 2,
|
|
||||||
UIDs: []string{"a", "b"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "display_ids",
|
|
||||||
Data: &sqlQueryGetDisplay{
|
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
|
||||||
Query: &GetUserDisplayQuery{
|
|
||||||
OrgID: 2,
|
|
||||||
IDs: []int64{1, 2},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "display_ids_uids",
|
|
||||||
Data: &sqlQueryGetDisplay{
|
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
|
||||||
Query: &GetUserDisplayQuery{
|
|
||||||
OrgID: 2,
|
|
||||||
UIDs: []string{"a", "b"},
|
|
||||||
IDs: []int64{1, 2},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute test cases
|
|
||||||
for tmpl, tcs := range testCases {
|
|
||||||
t.Run(tmpl.Name(), func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
for _, tc := range tcs {
|
|
||||||
t.Run(tc.Name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
for _, dialect := range dialects {
|
|
||||||
filename := dialect.DialectName() + "__" + tc.Name + ".sql"
|
|
||||||
t.Run(filename, func(t *testing.T) {
|
|
||||||
// not parallel because we're sharing tc.Data, not
|
|
||||||
// worth it deep cloning
|
|
||||||
|
|
||||||
expectedQuery := string(testdata(t, filename))
|
|
||||||
//expectedQuery := sqltemplate.FormatSQL(rawQuery)
|
|
||||||
|
|
||||||
tc.Data.SetDialect(dialect)
|
|
||||||
err := tc.Data.Validate()
|
|
||||||
require.NoError(t, err)
|
|
||||||
got, err := sqltemplate.Execute(tmpl, tc.Data)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
got = sqltemplate.RemoveEmptyLines(got)
|
|
||||||
if diff := cmp.Diff(expectedQuery, got); diff != "" {
|
|
||||||
writeTestData(filename, got)
|
|
||||||
t.Errorf("%s: %s", tc.Name, diff)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
||||||
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
||||||
FROM `user` as u JOIN org_user ON u.id = org_user.user_id
|
FROM `user` as u JOIN org_user ON u.id = org_user.user_id
|
||||||
WHERE org_user.org_id = ? AND ( 1=2
|
WHERE org_user.org_id = 2 AND ( 1=2
|
||||||
OR u.id IN (?, ?)
|
OR u.id IN (1, 2)
|
||||||
)
|
)
|
||||||
ORDER BY u.id asc
|
ORDER BY u.id asc
|
||||||
LIMIT 500
|
LIMIT 500
|
@ -1,9 +1,9 @@
|
|||||||
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
||||||
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
||||||
FROM `user` as u JOIN org_user ON u.id = org_user.user_id
|
FROM `user` as u JOIN org_user ON u.id = org_user.user_id
|
||||||
WHERE org_user.org_id = ? AND ( 1=2
|
WHERE org_user.org_id = 2 AND ( 1=2
|
||||||
OR uid IN (?, ?)
|
OR uid IN ('a', 'b')
|
||||||
OR u.id IN (?, ?)
|
OR u.id IN (1, 2)
|
||||||
)
|
)
|
||||||
ORDER BY u.id asc
|
ORDER BY u.id asc
|
||||||
LIMIT 500
|
LIMIT 500
|
@ -1,8 +1,8 @@
|
|||||||
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
||||||
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
||||||
FROM `user` as u JOIN org_user ON u.id = org_user.user_id
|
FROM `user` as u JOIN org_user ON u.id = org_user.user_id
|
||||||
WHERE org_user.org_id = ? AND ( 1=2
|
WHERE org_user.org_id = 2 AND ( 1=2
|
||||||
OR uid IN (?, ?)
|
OR uid IN ('a', 'b')
|
||||||
)
|
)
|
||||||
ORDER BY u.id asc
|
ORDER BY u.id asc
|
||||||
LIMIT 500
|
LIMIT 500
|
@ -1,5 +1,5 @@
|
|||||||
SELECT id, uid, name, email, created, updated
|
SELECT id, uid, name, email, created, updated
|
||||||
FROM "team"
|
FROM "team"
|
||||||
WHERE org_id = ?
|
WHERE org_id = 0
|
||||||
ORDER BY id asc
|
ORDER BY id asc
|
||||||
LIMIT ?
|
LIMIT 5
|
@ -1,6 +1,6 @@
|
|||||||
SELECT id, uid, name, email, created, updated
|
SELECT id, uid, name, email, created, updated
|
||||||
FROM "team"
|
FROM "team"
|
||||||
WHERE org_id = ?
|
WHERE org_id = 0
|
||||||
AND id > ?
|
AND id > 1
|
||||||
ORDER BY id asc
|
ORDER BY id asc
|
||||||
LIMIT ?
|
LIMIT 2
|
@ -1,6 +1,6 @@
|
|||||||
SELECT id, uid, name, email, created, updated
|
SELECT id, uid, name, email, created, updated
|
||||||
FROM "team"
|
FROM "team"
|
||||||
WHERE org_id = ?
|
WHERE org_id = 0
|
||||||
AND uid = ?
|
AND uid = 'abc'
|
||||||
ORDER BY id asc
|
ORDER BY id asc
|
||||||
LIMIT ?
|
LIMIT 0
|
@ -1,7 +1,7 @@
|
|||||||
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
||||||
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
||||||
FROM `user` as u JOIN org_user ON u.id = org_user.user_id
|
FROM `user` as u JOIN org_user ON u.id = org_user.user_id
|
||||||
WHERE org_user.org_id = ?
|
WHERE org_user.org_id = 0
|
||||||
AND u.is_service_account = ?
|
AND u.is_service_account = FALSE
|
||||||
ORDER BY u.id asc
|
ORDER BY u.id asc
|
||||||
LIMIT ?
|
LIMIT 5
|
@ -1,8 +1,8 @@
|
|||||||
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
||||||
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
||||||
FROM `user` as u JOIN org_user ON u.id = org_user.user_id
|
FROM `user` as u JOIN org_user ON u.id = org_user.user_id
|
||||||
WHERE org_user.org_id = ?
|
WHERE org_user.org_id = 0
|
||||||
AND u.is_service_account = ?
|
AND u.is_service_account = FALSE
|
||||||
AND id > ?
|
AND id > 1
|
||||||
ORDER BY u.id asc
|
ORDER BY u.id asc
|
||||||
LIMIT ?
|
LIMIT 2
|
8
pkg/registry/apis/identity/legacy/testdata/mysql--query_users-users_uid.sql
vendored
Executable file
8
pkg/registry/apis/identity/legacy/testdata/mysql--query_users-users_uid.sql
vendored
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
||||||
|
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
||||||
|
FROM `user` as u JOIN org_user ON u.id = org_user.user_id
|
||||||
|
WHERE org_user.org_id = 0
|
||||||
|
AND u.is_service_account = FALSE
|
||||||
|
AND uid = 'abc'
|
||||||
|
ORDER BY u.id asc
|
||||||
|
LIMIT 0
|
@ -1,8 +0,0 @@
|
|||||||
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
|
||||||
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
|
||||||
FROM `user` as u JOIN org_user ON u.id = org_user.user_id
|
|
||||||
WHERE org_user.org_id = ?
|
|
||||||
AND u.is_service_account = ?
|
|
||||||
AND uid = ?
|
|
||||||
ORDER BY u.id asc
|
|
||||||
LIMIT ?
|
|
@ -1,8 +1,8 @@
|
|||||||
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
||||||
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
||||||
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
||||||
WHERE org_user.org_id = ? AND ( 1=2
|
WHERE org_user.org_id = 2 AND ( 1=2
|
||||||
OR u.id IN (?, ?)
|
OR u.id IN (1, 2)
|
||||||
)
|
)
|
||||||
ORDER BY u.id asc
|
ORDER BY u.id asc
|
||||||
LIMIT 500
|
LIMIT 500
|
@ -1,9 +1,9 @@
|
|||||||
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
||||||
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
||||||
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
||||||
WHERE org_user.org_id = ? AND ( 1=2
|
WHERE org_user.org_id = 2 AND ( 1=2
|
||||||
OR uid IN (?, ?)
|
OR uid IN ('a', 'b')
|
||||||
OR u.id IN (?, ?)
|
OR u.id IN (1, 2)
|
||||||
)
|
)
|
||||||
ORDER BY u.id asc
|
ORDER BY u.id asc
|
||||||
LIMIT 500
|
LIMIT 500
|
@ -1,8 +1,8 @@
|
|||||||
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
||||||
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
||||||
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
||||||
WHERE org_user.org_id = $1 AND ( 1=2
|
WHERE org_user.org_id = 2 AND ( 1=2
|
||||||
OR uid IN ($2, $3)
|
OR uid IN ('a', 'b')
|
||||||
)
|
)
|
||||||
ORDER BY u.id asc
|
ORDER BY u.id asc
|
||||||
LIMIT 500
|
LIMIT 500
|
@ -1,5 +1,5 @@
|
|||||||
SELECT id, uid, name, email, created, updated
|
SELECT id, uid, name, email, created, updated
|
||||||
FROM "team"
|
FROM "team"
|
||||||
WHERE org_id = ?
|
WHERE org_id = 0
|
||||||
ORDER BY id asc
|
ORDER BY id asc
|
||||||
LIMIT ?
|
LIMIT 5
|
6
pkg/registry/apis/identity/legacy/testdata/postgres--query_teams-teams_page_2.sql
vendored
Executable file
6
pkg/registry/apis/identity/legacy/testdata/postgres--query_teams-teams_page_2.sql
vendored
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
SELECT id, uid, name, email, created, updated
|
||||||
|
FROM "team"
|
||||||
|
WHERE org_id = 0
|
||||||
|
AND id > 1
|
||||||
|
ORDER BY id asc
|
||||||
|
LIMIT 2
|
6
pkg/registry/apis/identity/legacy/testdata/postgres--query_teams-teams_uid.sql
vendored
Executable file
6
pkg/registry/apis/identity/legacy/testdata/postgres--query_teams-teams_uid.sql
vendored
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
SELECT id, uid, name, email, created, updated
|
||||||
|
FROM "team"
|
||||||
|
WHERE org_id = 0
|
||||||
|
AND uid = 'abc'
|
||||||
|
ORDER BY id asc
|
||||||
|
LIMIT 0
|
@ -1,7 +1,7 @@
|
|||||||
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
||||||
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
||||||
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
||||||
WHERE org_user.org_id = ?
|
WHERE org_user.org_id = 0
|
||||||
AND u.is_service_account = ?
|
AND u.is_service_account = FALSE
|
||||||
ORDER BY u.id asc
|
ORDER BY u.id asc
|
||||||
LIMIT ?
|
LIMIT 5
|
@ -1,8 +1,8 @@
|
|||||||
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
||||||
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
||||||
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
||||||
WHERE org_user.org_id = $1
|
WHERE org_user.org_id = 0
|
||||||
AND u.is_service_account = $2
|
AND u.is_service_account = FALSE
|
||||||
AND id > $3
|
AND id > 1
|
||||||
ORDER BY u.id asc
|
ORDER BY u.id asc
|
||||||
LIMIT $4
|
LIMIT 2
|
8
pkg/registry/apis/identity/legacy/testdata/postgres--query_users-users_uid.sql
vendored
Executable file
8
pkg/registry/apis/identity/legacy/testdata/postgres--query_users-users_uid.sql
vendored
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
||||||
|
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
||||||
|
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
||||||
|
WHERE org_user.org_id = 0
|
||||||
|
AND u.is_service_account = FALSE
|
||||||
|
AND uid = 'abc'
|
||||||
|
ORDER BY u.id asc
|
||||||
|
LIMIT 0
|
@ -1,9 +0,0 @@
|
|||||||
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
|
||||||
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
|
||||||
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
|
||||||
WHERE org_user.org_id = $1 AND ( 1=2
|
|
||||||
OR uid IN ($2, $3)
|
|
||||||
OR u.id IN ($4, $5)
|
|
||||||
)
|
|
||||||
ORDER BY u.id asc
|
|
||||||
LIMIT 500
|
|
@ -1,6 +0,0 @@
|
|||||||
SELECT id, uid, name, email, created, updated
|
|
||||||
FROM "team"
|
|
||||||
WHERE org_id = $1
|
|
||||||
AND id > $2
|
|
||||||
ORDER BY id asc
|
|
||||||
LIMIT $3
|
|
@ -1,6 +0,0 @@
|
|||||||
SELECT id, uid, name, email, created, updated
|
|
||||||
FROM "team"
|
|
||||||
WHERE org_id = $1
|
|
||||||
AND uid = $2
|
|
||||||
ORDER BY id asc
|
|
||||||
LIMIT $3
|
|
@ -1,8 +0,0 @@
|
|||||||
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
|
||||||
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
|
||||||
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
|
||||||
WHERE org_user.org_id = $1
|
|
||||||
AND u.is_service_account = $2
|
|
||||||
AND uid = $3
|
|
||||||
ORDER BY u.id asc
|
|
||||||
LIMIT $4
|
|
@ -1,8 +1,8 @@
|
|||||||
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
||||||
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
||||||
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
||||||
WHERE org_user.org_id = ? AND ( 1=2
|
WHERE org_user.org_id = 2 AND ( 1=2
|
||||||
OR uid IN (?, ?)
|
OR u.id IN (1, 2)
|
||||||
)
|
)
|
||||||
ORDER BY u.id asc
|
ORDER BY u.id asc
|
||||||
LIMIT 500
|
LIMIT 500
|
9
pkg/registry/apis/identity/legacy/testdata/sqlite--query_display-display_ids_uids.sql
vendored
Executable file
9
pkg/registry/apis/identity/legacy/testdata/sqlite--query_display-display_ids_uids.sql
vendored
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
||||||
|
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
||||||
|
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
||||||
|
WHERE org_user.org_id = 2 AND ( 1=2
|
||||||
|
OR uid IN ('a', 'b')
|
||||||
|
OR u.id IN (1, 2)
|
||||||
|
)
|
||||||
|
ORDER BY u.id asc
|
||||||
|
LIMIT 500
|
@ -1,8 +1,8 @@
|
|||||||
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
||||||
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
||||||
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
||||||
WHERE org_user.org_id = $1 AND ( 1=2
|
WHERE org_user.org_id = 2 AND ( 1=2
|
||||||
OR u.id IN ($2, $3)
|
OR uid IN ('a', 'b')
|
||||||
)
|
)
|
||||||
ORDER BY u.id asc
|
ORDER BY u.id asc
|
||||||
LIMIT 500
|
LIMIT 500
|
@ -1,5 +1,5 @@
|
|||||||
SELECT id, uid, name, email, created, updated
|
SELECT id, uid, name, email, created, updated
|
||||||
FROM "team"
|
FROM "team"
|
||||||
WHERE org_id = $1
|
WHERE org_id = 0
|
||||||
ORDER BY id asc
|
ORDER BY id asc
|
||||||
LIMIT $2
|
LIMIT 5
|
6
pkg/registry/apis/identity/legacy/testdata/sqlite--query_teams-teams_page_2.sql
vendored
Executable file
6
pkg/registry/apis/identity/legacy/testdata/sqlite--query_teams-teams_page_2.sql
vendored
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
SELECT id, uid, name, email, created, updated
|
||||||
|
FROM "team"
|
||||||
|
WHERE org_id = 0
|
||||||
|
AND id > 1
|
||||||
|
ORDER BY id asc
|
||||||
|
LIMIT 2
|
6
pkg/registry/apis/identity/legacy/testdata/sqlite--query_teams-teams_uid.sql
vendored
Executable file
6
pkg/registry/apis/identity/legacy/testdata/sqlite--query_teams-teams_uid.sql
vendored
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
SELECT id, uid, name, email, created, updated
|
||||||
|
FROM "team"
|
||||||
|
WHERE org_id = 0
|
||||||
|
AND uid = 'abc'
|
||||||
|
ORDER BY id asc
|
||||||
|
LIMIT 0
|
@ -1,7 +1,7 @@
|
|||||||
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
||||||
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
||||||
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
||||||
WHERE org_user.org_id = $1
|
WHERE org_user.org_id = 0
|
||||||
AND u.is_service_account = $2
|
AND u.is_service_account = FALSE
|
||||||
ORDER BY u.id asc
|
ORDER BY u.id asc
|
||||||
LIMIT $3
|
LIMIT 5
|
8
pkg/registry/apis/identity/legacy/testdata/sqlite--query_users-users_page_2.sql
vendored
Executable file
8
pkg/registry/apis/identity/legacy/testdata/sqlite--query_users-users_page_2.sql
vendored
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
||||||
|
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
||||||
|
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
||||||
|
WHERE org_user.org_id = 0
|
||||||
|
AND u.is_service_account = FALSE
|
||||||
|
AND id > 1
|
||||||
|
ORDER BY u.id asc
|
||||||
|
LIMIT 2
|
8
pkg/registry/apis/identity/legacy/testdata/sqlite--query_users-users_uid.sql
vendored
Executable file
8
pkg/registry/apis/identity/legacy/testdata/sqlite--query_users-users_uid.sql
vendored
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
||||||
|
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
||||||
|
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
||||||
|
WHERE org_user.org_id = 0
|
||||||
|
AND u.is_service_account = FALSE
|
||||||
|
AND uid = 'abc'
|
||||||
|
ORDER BY u.id asc
|
||||||
|
LIMIT 0
|
@ -1,6 +0,0 @@
|
|||||||
SELECT id, uid, name, email, created, updated
|
|
||||||
FROM "team"
|
|
||||||
WHERE org_id = ?
|
|
||||||
AND id > ?
|
|
||||||
ORDER BY id asc
|
|
||||||
LIMIT ?
|
|
@ -1,6 +0,0 @@
|
|||||||
SELECT id, uid, name, email, created, updated
|
|
||||||
FROM "team"
|
|
||||||
WHERE org_id = ?
|
|
||||||
AND uid = ?
|
|
||||||
ORDER BY id asc
|
|
||||||
LIMIT ?
|
|
@ -1,8 +0,0 @@
|
|||||||
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
|
||||||
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
|
||||||
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
|
||||||
WHERE org_user.org_id = ?
|
|
||||||
AND u.is_service_account = ?
|
|
||||||
AND id > ?
|
|
||||||
ORDER BY u.id asc
|
|
||||||
LIMIT ?
|
|
@ -1,8 +0,0 @@
|
|||||||
SELECT org_user.org_id, u.id, u.uid, u.login, u.email, u.name,
|
|
||||||
u.created, u.updated, u.is_service_account, u.is_disabled, u.is_admin
|
|
||||||
FROM "user" as u JOIN org_user ON u.id = org_user.user_id
|
|
||||||
WHERE org_user.org_id = ?
|
|
||||||
AND u.is_service_account = ?
|
|
||||||
AND uid = ?
|
|
||||||
ORDER BY u.id asc
|
|
||||||
LIMIT ?
|
|
@ -136,18 +136,18 @@ func (b *backend) create(ctx context.Context, event resource.WriteEvent) (int64,
|
|||||||
|
|
||||||
// 1. Insert into resource
|
// 1. Insert into resource
|
||||||
if _, err := dbutil.Exec(ctx, tx, sqlResourceInsert, sqlResourceRequest{
|
if _, err := dbutil.Exec(ctx, tx, sqlResourceInsert, sqlResourceRequest{
|
||||||
SQLTemplate: sqltemplate.New(b.dialect),
|
SQLTemplateIface: sqltemplate.New(b.dialect),
|
||||||
WriteEvent: event,
|
WriteEvent: event,
|
||||||
GUID: guid,
|
GUID: guid,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("insert into resource: %w", err)
|
return fmt.Errorf("insert into resource: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Insert into resource history
|
// 2. Insert into resource history
|
||||||
if _, err := dbutil.Exec(ctx, tx, sqlResourceHistoryInsert, sqlResourceRequest{
|
if _, err := dbutil.Exec(ctx, tx, sqlResourceHistoryInsert, sqlResourceRequest{
|
||||||
SQLTemplate: sqltemplate.New(b.dialect),
|
SQLTemplateIface: sqltemplate.New(b.dialect),
|
||||||
WriteEvent: event,
|
WriteEvent: event,
|
||||||
GUID: guid,
|
GUID: guid,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("insert into resource history: %w", err)
|
return fmt.Errorf("insert into resource history: %w", err)
|
||||||
}
|
}
|
||||||
@ -162,17 +162,17 @@ func (b *backend) create(ctx context.Context, event resource.WriteEvent) (int64,
|
|||||||
|
|
||||||
// 5. Update the RV in both resource and resource_history
|
// 5. Update the RV in both resource and resource_history
|
||||||
if _, err = dbutil.Exec(ctx, tx, sqlResourceHistoryUpdateRV, sqlResourceUpdateRVRequest{
|
if _, err = dbutil.Exec(ctx, tx, sqlResourceHistoryUpdateRV, sqlResourceUpdateRVRequest{
|
||||||
SQLTemplate: sqltemplate.New(b.dialect),
|
SQLTemplateIface: sqltemplate.New(b.dialect),
|
||||||
GUID: guid,
|
GUID: guid,
|
||||||
ResourceVersion: rv,
|
ResourceVersion: rv,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("update resource_history rv: %w", err)
|
return fmt.Errorf("update resource_history rv: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = dbutil.Exec(ctx, tx, sqlResourceUpdateRV, sqlResourceUpdateRVRequest{
|
if _, err = dbutil.Exec(ctx, tx, sqlResourceUpdateRV, sqlResourceUpdateRVRequest{
|
||||||
SQLTemplate: sqltemplate.New(b.dialect),
|
SQLTemplateIface: sqltemplate.New(b.dialect),
|
||||||
GUID: guid,
|
GUID: guid,
|
||||||
ResourceVersion: rv,
|
ResourceVersion: rv,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("update resource rv: %w", err)
|
return fmt.Errorf("update resource rv: %w", err)
|
||||||
}
|
}
|
||||||
@ -194,9 +194,9 @@ func (b *backend) update(ctx context.Context, event resource.WriteEvent) (int64,
|
|||||||
|
|
||||||
// 1. Update resource
|
// 1. Update resource
|
||||||
_, err := dbutil.Exec(ctx, tx, sqlResourceUpdate, sqlResourceRequest{
|
_, err := dbutil.Exec(ctx, tx, sqlResourceUpdate, sqlResourceRequest{
|
||||||
SQLTemplate: sqltemplate.New(b.dialect),
|
SQLTemplateIface: sqltemplate.New(b.dialect),
|
||||||
WriteEvent: event,
|
WriteEvent: event,
|
||||||
GUID: guid,
|
GUID: guid,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("initial resource update: %w", err)
|
return fmt.Errorf("initial resource update: %w", err)
|
||||||
@ -204,9 +204,9 @@ func (b *backend) update(ctx context.Context, event resource.WriteEvent) (int64,
|
|||||||
|
|
||||||
// 2. Insert into resource history
|
// 2. Insert into resource history
|
||||||
if _, err := dbutil.Exec(ctx, tx, sqlResourceHistoryInsert, sqlResourceRequest{
|
if _, err := dbutil.Exec(ctx, tx, sqlResourceHistoryInsert, sqlResourceRequest{
|
||||||
SQLTemplate: sqltemplate.New(b.dialect),
|
SQLTemplateIface: sqltemplate.New(b.dialect),
|
||||||
WriteEvent: event,
|
WriteEvent: event,
|
||||||
GUID: guid,
|
GUID: guid,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("insert into resource history: %w", err)
|
return fmt.Errorf("insert into resource history: %w", err)
|
||||||
}
|
}
|
||||||
@ -221,17 +221,17 @@ func (b *backend) update(ctx context.Context, event resource.WriteEvent) (int64,
|
|||||||
|
|
||||||
// 5. Update the RV in both resource and resource_history
|
// 5. Update the RV in both resource and resource_history
|
||||||
if _, err = dbutil.Exec(ctx, tx, sqlResourceHistoryUpdateRV, sqlResourceUpdateRVRequest{
|
if _, err = dbutil.Exec(ctx, tx, sqlResourceHistoryUpdateRV, sqlResourceUpdateRVRequest{
|
||||||
SQLTemplate: sqltemplate.New(b.dialect),
|
SQLTemplateIface: sqltemplate.New(b.dialect),
|
||||||
GUID: guid,
|
GUID: guid,
|
||||||
ResourceVersion: rv,
|
ResourceVersion: rv,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("update history rv: %w", err)
|
return fmt.Errorf("update history rv: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = dbutil.Exec(ctx, tx, sqlResourceUpdateRV, sqlResourceUpdateRVRequest{
|
if _, err = dbutil.Exec(ctx, tx, sqlResourceUpdateRV, sqlResourceUpdateRVRequest{
|
||||||
SQLTemplate: sqltemplate.New(b.dialect),
|
SQLTemplateIface: sqltemplate.New(b.dialect),
|
||||||
GUID: guid,
|
GUID: guid,
|
||||||
ResourceVersion: rv,
|
ResourceVersion: rv,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("update resource rv: %w", err)
|
return fmt.Errorf("update resource rv: %w", err)
|
||||||
}
|
}
|
||||||
@ -254,9 +254,9 @@ func (b *backend) delete(ctx context.Context, event resource.WriteEvent) (int64,
|
|||||||
|
|
||||||
// 1. delete from resource
|
// 1. delete from resource
|
||||||
_, err := dbutil.Exec(ctx, tx, sqlResourceDelete, sqlResourceRequest{
|
_, err := dbutil.Exec(ctx, tx, sqlResourceDelete, sqlResourceRequest{
|
||||||
SQLTemplate: sqltemplate.New(b.dialect),
|
SQLTemplateIface: sqltemplate.New(b.dialect),
|
||||||
WriteEvent: event,
|
WriteEvent: event,
|
||||||
GUID: guid,
|
GUID: guid,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("delete resource: %w", err)
|
return fmt.Errorf("delete resource: %w", err)
|
||||||
@ -264,9 +264,9 @@ func (b *backend) delete(ctx context.Context, event resource.WriteEvent) (int64,
|
|||||||
|
|
||||||
// 2. Add event to resource history
|
// 2. Add event to resource history
|
||||||
if _, err := dbutil.Exec(ctx, tx, sqlResourceHistoryInsert, sqlResourceRequest{
|
if _, err := dbutil.Exec(ctx, tx, sqlResourceHistoryInsert, sqlResourceRequest{
|
||||||
SQLTemplate: sqltemplate.New(b.dialect),
|
SQLTemplateIface: sqltemplate.New(b.dialect),
|
||||||
WriteEvent: event,
|
WriteEvent: event,
|
||||||
GUID: guid,
|
GUID: guid,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("insert into resource history: %w", err)
|
return fmt.Errorf("insert into resource history: %w", err)
|
||||||
}
|
}
|
||||||
@ -281,9 +281,9 @@ func (b *backend) delete(ctx context.Context, event resource.WriteEvent) (int64,
|
|||||||
|
|
||||||
// 5. Update the RV in resource_history
|
// 5. Update the RV in resource_history
|
||||||
if _, err = dbutil.Exec(ctx, tx, sqlResourceHistoryUpdateRV, sqlResourceUpdateRVRequest{
|
if _, err = dbutil.Exec(ctx, tx, sqlResourceHistoryUpdateRV, sqlResourceUpdateRVRequest{
|
||||||
SQLTemplate: sqltemplate.New(b.dialect),
|
SQLTemplateIface: sqltemplate.New(b.dialect),
|
||||||
GUID: guid,
|
GUID: guid,
|
||||||
ResourceVersion: rv,
|
ResourceVersion: rv,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("update history rv: %w", err)
|
return fmt.Errorf("update history rv: %w", err)
|
||||||
}
|
}
|
||||||
@ -302,9 +302,9 @@ func (b *backend) ReadResource(ctx context.Context, req *resource.ReadRequest) *
|
|||||||
// TODO: validate key ?
|
// TODO: validate key ?
|
||||||
|
|
||||||
readReq := sqlResourceReadRequest{
|
readReq := sqlResourceReadRequest{
|
||||||
SQLTemplate: sqltemplate.New(b.dialect),
|
SQLTemplateIface: sqltemplate.New(b.dialect),
|
||||||
Request: req,
|
Request: req,
|
||||||
readResponse: new(readResponse),
|
readResponse: new(readResponse),
|
||||||
}
|
}
|
||||||
|
|
||||||
sr := sqlResourceRead
|
sr := sqlResourceRead
|
||||||
@ -418,8 +418,8 @@ func (b *backend) listLatest(ctx context.Context, req *resource.ListRequest, cb
|
|||||||
}
|
}
|
||||||
|
|
||||||
listReq := sqlResourceListRequest{
|
listReq := sqlResourceListRequest{
|
||||||
SQLTemplate: sqltemplate.New(b.dialect),
|
SQLTemplateIface: sqltemplate.New(b.dialect),
|
||||||
Request: new(resource.ListRequest),
|
Request: new(resource.ListRequest),
|
||||||
}
|
}
|
||||||
listReq.Request = proto.Clone(req).(*resource.ListRequest)
|
listReq.Request = proto.Clone(req).(*resource.ListRequest)
|
||||||
|
|
||||||
@ -467,7 +467,7 @@ func (b *backend) listAtRevision(ctx context.Context, req *resource.ListRequest,
|
|||||||
limit = math.MaxInt64 // a limit is required for offset
|
limit = math.MaxInt64 // a limit is required for offset
|
||||||
}
|
}
|
||||||
listReq := sqlResourceHistoryListRequest{
|
listReq := sqlResourceHistoryListRequest{
|
||||||
SQLTemplate: sqltemplate.New(b.dialect),
|
SQLTemplateIface: sqltemplate.New(b.dialect),
|
||||||
Request: &historyListRequest{
|
Request: &historyListRequest{
|
||||||
ResourceVersion: iter.listRV,
|
ResourceVersion: iter.listRV,
|
||||||
Limit: limit,
|
Limit: limit,
|
||||||
@ -554,7 +554,7 @@ func (b *backend) poller(ctx context.Context, since groupResourceRV, stream chan
|
|||||||
func (b *backend) listLatestRVs(ctx context.Context) (groupResourceRV, error) {
|
func (b *backend) listLatestRVs(ctx context.Context) (groupResourceRV, error) {
|
||||||
since := groupResourceRV{}
|
since := groupResourceRV{}
|
||||||
reqRVs := sqlResourceVersionListRequest{
|
reqRVs := sqlResourceVersionListRequest{
|
||||||
SQLTemplate: sqltemplate.New(b.dialect),
|
SQLTemplateIface: sqltemplate.New(b.dialect),
|
||||||
groupResourceVersion: new(groupResourceVersion),
|
groupResourceVersion: new(groupResourceVersion),
|
||||||
}
|
}
|
||||||
query, err := sqltemplate.Execute(sqlResourceVersionList, reqRVs)
|
query, err := sqltemplate.Execute(sqlResourceVersionList, reqRVs)
|
||||||
@ -585,11 +585,11 @@ func (b *backend) listLatestRVs(ctx context.Context) (groupResourceRV, error) {
|
|||||||
// fetchLatestRV returns the current maximum RV in the resource table
|
// fetchLatestRV returns the current maximum RV in the resource table
|
||||||
func fetchLatestRV(ctx context.Context, x db.ContextExecer, d sqltemplate.Dialect, group, resource string) (int64, error) {
|
func fetchLatestRV(ctx context.Context, x db.ContextExecer, d sqltemplate.Dialect, group, resource string) (int64, error) {
|
||||||
res, err := dbutil.QueryRow(ctx, x, sqlResourceVersionGet, sqlResourceVersionRequest{
|
res, err := dbutil.QueryRow(ctx, x, sqlResourceVersionGet, sqlResourceVersionRequest{
|
||||||
SQLTemplate: sqltemplate.New(d),
|
SQLTemplateIface: sqltemplate.New(d),
|
||||||
Group: group,
|
Group: group,
|
||||||
Resource: resource,
|
Resource: resource,
|
||||||
ReadOnly: true,
|
ReadOnly: true,
|
||||||
resourceVersion: new(resourceVersion),
|
resourceVersion: new(resourceVersion),
|
||||||
})
|
})
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
return 1, nil
|
return 1, nil
|
||||||
@ -604,7 +604,7 @@ func (b *backend) poll(ctx context.Context, grp string, res string, since int64,
|
|||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
pollReq := sqlResourceHistoryPollRequest{
|
pollReq := sqlResourceHistoryPollRequest{
|
||||||
SQLTemplate: sqltemplate.New(b.dialect),
|
SQLTemplateIface: sqltemplate.New(b.dialect),
|
||||||
Resource: res,
|
Resource: res,
|
||||||
Group: grp,
|
Group: grp,
|
||||||
SinceResourceVersion: since,
|
SinceResourceVersion: since,
|
||||||
@ -661,19 +661,19 @@ func resourceVersionAtomicInc(ctx context.Context, x db.ContextExecer, d sqltemp
|
|||||||
// TODO: refactor this code to run in a multi-statement transaction in order to minimize the number of round trips.
|
// TODO: refactor this code to run in a multi-statement transaction in order to minimize the number of round trips.
|
||||||
// 1 Lock the row for update
|
// 1 Lock the row for update
|
||||||
rv, err := dbutil.QueryRow(ctx, x, sqlResourceVersionGet, sqlResourceVersionRequest{
|
rv, err := dbutil.QueryRow(ctx, x, sqlResourceVersionGet, sqlResourceVersionRequest{
|
||||||
SQLTemplate: sqltemplate.New(d),
|
SQLTemplateIface: sqltemplate.New(d),
|
||||||
Group: key.Group,
|
Group: key.Group,
|
||||||
Resource: key.Resource,
|
Resource: key.Resource,
|
||||||
resourceVersion: new(resourceVersion),
|
resourceVersion: new(resourceVersion),
|
||||||
})
|
})
|
||||||
|
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
// if there wasn't a row associated with the given resource, we create one with
|
// if there wasn't a row associated with the given resource, we create one with
|
||||||
// version 1
|
// version 1
|
||||||
if _, err = dbutil.Exec(ctx, x, sqlResourceVersionInsert, sqlResourceVersionRequest{
|
if _, err = dbutil.Exec(ctx, x, sqlResourceVersionInsert, sqlResourceVersionRequest{
|
||||||
SQLTemplate: sqltemplate.New(d),
|
SQLTemplateIface: sqltemplate.New(d),
|
||||||
Group: key.Group,
|
Group: key.Group,
|
||||||
Resource: key.Resource,
|
Resource: key.Resource,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return 0, fmt.Errorf("insert into resource_version: %w", err)
|
return 0, fmt.Errorf("insert into resource_version: %w", err)
|
||||||
}
|
}
|
||||||
@ -687,9 +687,9 @@ func resourceVersionAtomicInc(ctx context.Context, x db.ContextExecer, d sqltemp
|
|||||||
|
|
||||||
// 2. Increment the resource version
|
// 2. Increment the resource version
|
||||||
_, err = dbutil.Exec(ctx, x, sqlResourceVersionInc, sqlResourceVersionRequest{
|
_, err = dbutil.Exec(ctx, x, sqlResourceVersionInc, sqlResourceVersionRequest{
|
||||||
SQLTemplate: sqltemplate.New(d),
|
SQLTemplateIface: sqltemplate.New(d),
|
||||||
Group: key.Group,
|
Group: key.Group,
|
||||||
Resource: key.Resource,
|
Resource: key.Resource,
|
||||||
resourceVersion: &resourceVersion{
|
resourceVersion: &resourceVersion{
|
||||||
ResourceVersion: nextRV,
|
ResourceVersion: nextRV,
|
||||||
},
|
},
|
||||||
|
@ -58,7 +58,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type sqlResourceRequest struct {
|
type sqlResourceRequest struct {
|
||||||
*sqltemplate.SQLTemplate
|
sqltemplate.SQLTemplateIface
|
||||||
GUID string
|
GUID string
|
||||||
WriteEvent resource.WriteEvent
|
WriteEvent resource.WriteEvent
|
||||||
}
|
}
|
||||||
@ -80,7 +80,7 @@ func (r *historyPollResponse) Results() (*historyPollResponse, error) {
|
|||||||
|
|
||||||
type groupResourceRV map[string]map[string]int64
|
type groupResourceRV map[string]map[string]int64
|
||||||
type sqlResourceHistoryPollRequest struct {
|
type sqlResourceHistoryPollRequest struct {
|
||||||
*sqltemplate.SQLTemplate
|
sqltemplate.SQLTemplateIface
|
||||||
Resource string
|
Resource string
|
||||||
Group string
|
Group string
|
||||||
SinceResourceVersion int64
|
SinceResourceVersion int64
|
||||||
@ -102,7 +102,7 @@ func (r *readResponse) Results() (*readResponse, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type sqlResourceReadRequest struct {
|
type sqlResourceReadRequest struct {
|
||||||
*sqltemplate.SQLTemplate
|
sqltemplate.SQLTemplateIface
|
||||||
Request *resource.ReadRequest
|
Request *resource.ReadRequest
|
||||||
*readResponse
|
*readResponse
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ func (r sqlResourceReadRequest) Validate() error {
|
|||||||
|
|
||||||
// List
|
// List
|
||||||
type sqlResourceListRequest struct {
|
type sqlResourceListRequest struct {
|
||||||
*sqltemplate.SQLTemplate
|
sqltemplate.SQLTemplateIface
|
||||||
Request *resource.ListRequest
|
Request *resource.ListRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ type historyListRequest struct {
|
|||||||
Options *resource.ListOptions
|
Options *resource.ListOptions
|
||||||
}
|
}
|
||||||
type sqlResourceHistoryListRequest struct {
|
type sqlResourceHistoryListRequest struct {
|
||||||
*sqltemplate.SQLTemplate
|
sqltemplate.SQLTemplateIface
|
||||||
Request *historyListRequest
|
Request *historyListRequest
|
||||||
Response *resource.ResourceWrapper
|
Response *resource.ResourceWrapper
|
||||||
}
|
}
|
||||||
@ -150,7 +150,7 @@ func (r sqlResourceHistoryListRequest) Results() (*resource.ResourceWrapper, err
|
|||||||
// update RV
|
// update RV
|
||||||
|
|
||||||
type sqlResourceUpdateRVRequest struct {
|
type sqlResourceUpdateRVRequest struct {
|
||||||
*sqltemplate.SQLTemplate
|
sqltemplate.SQLTemplateIface
|
||||||
GUID string
|
GUID string
|
||||||
ResourceVersion int64
|
ResourceVersion int64
|
||||||
}
|
}
|
||||||
@ -174,7 +174,7 @@ func (r *resourceVersion) Results() (*resourceVersion, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type sqlResourceVersionRequest struct {
|
type sqlResourceVersionRequest struct {
|
||||||
*sqltemplate.SQLTemplate
|
sqltemplate.SQLTemplateIface
|
||||||
Group, Resource string
|
Group, Resource string
|
||||||
ReadOnly bool
|
ReadOnly bool
|
||||||
*resourceVersion
|
*resourceVersion
|
||||||
@ -185,7 +185,7 @@ func (r sqlResourceVersionRequest) Validate() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type sqlResourceVersionListRequest struct {
|
type sqlResourceVersionListRequest struct {
|
||||||
*sqltemplate.SQLTemplate
|
sqltemplate.SQLTemplateIface
|
||||||
*groupResourceVersion
|
*groupResourceVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,353 +1,184 @@
|
|||||||
package sql
|
package sql
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
|
||||||
"testing"
|
"testing"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
||||||
"github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate"
|
"github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate/mocks"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed testdata/*
|
|
||||||
var testdataFS embed.FS
|
|
||||||
|
|
||||||
func testdata(t *testing.T, filename string) []byte {
|
|
||||||
t.Helper()
|
|
||||||
b, err := testdataFS.ReadFile(`testdata/` + filename)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestQueries(t *testing.T) {
|
func TestQueries(t *testing.T) {
|
||||||
t.Parallel()
|
mocks.CheckQuerySnapshots(t, mocks.TemplateTestSetup{
|
||||||
|
RootDir: "testdata",
|
||||||
// Each template has one or more test cases, each identified with a
|
Templates: map[*template.Template][]mocks.TemplateTestCase{
|
||||||
// descriptive name (e.g. "happy path", "error twiddling the frobb"). Each
|
sqlResourceDelete: {
|
||||||
// of them will test that for the same input data they must produce a result
|
{
|
||||||
// that will depend on the Dialect. Expected queries should be defined in
|
Name: "simple",
|
||||||
// separate files in the testdata directory. This improves the testing
|
Data: &sqlResourceRequest{
|
||||||
// experience by separating test data from test code, since mixing both
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
// tends to make it more difficult to reason about what is being done,
|
WriteEvent: resource.WriteEvent{
|
||||||
// especially as we want testing code to scale and make it easy to add
|
|
||||||
// tests.
|
|
||||||
type (
|
|
||||||
// type aliases to make code more semantic and self-documenting
|
|
||||||
resultSQLFilename = string
|
|
||||||
dialects = []sqltemplate.Dialect
|
|
||||||
expected map[resultSQLFilename]dialects
|
|
||||||
|
|
||||||
testCase = struct {
|
|
||||||
Name string
|
|
||||||
|
|
||||||
// Data should be the struct passed to the template.
|
|
||||||
Data sqltemplate.SQLTemplateIface
|
|
||||||
|
|
||||||
// Expected maps the filename containing the expected result query
|
|
||||||
// to the list of dialects that would produce it. For simple
|
|
||||||
// queries, it is possible that more than one dialect produce the
|
|
||||||
// same output. The filename is expected to be in the `testdata`
|
|
||||||
// directory.
|
|
||||||
Expected expected
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Define tests cases. Most templates are trivial and testing that they
|
|
||||||
// generate correct code for a single Dialect is fine, since the one thing
|
|
||||||
// that always changes is how SQL placeholder arguments are passed (most
|
|
||||||
// Dialects use `?` while PostgreSQL uses `$1`, `$2`, etc.), and that is
|
|
||||||
// something that should be tested in the Dialect implementation instead of
|
|
||||||
// here. We will ask to have at least one test per SQL template, and we will
|
|
||||||
// lean to test MySQL. Templates containing branching (conditionals, loops,
|
|
||||||
// etc.) should be exercised at least once in each of their branches.
|
|
||||||
//
|
|
||||||
// NOTE: in the Data field, make sure to have pointers populated to simulate
|
|
||||||
// data is set as it would be in a real request. The data being correctly
|
|
||||||
// populated in each case should be tested in integration tests, where the
|
|
||||||
// data will actually flow to and from a real database. In this tests we
|
|
||||||
// only care about producing the correct SQL.
|
|
||||||
testCases := map[*template.Template][]*testCase{
|
|
||||||
sqlResourceDelete: {
|
|
||||||
{
|
|
||||||
Name: "single path",
|
|
||||||
Data: &sqlResourceRequest{
|
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
|
||||||
WriteEvent: resource.WriteEvent{
|
|
||||||
Key: &resource.ResourceKey{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Expected: expected{
|
|
||||||
"resource_delete_mysql_sqlite.sql": dialects{
|
|
||||||
sqltemplate.MySQL,
|
|
||||||
sqltemplate.SQLite,
|
|
||||||
},
|
|
||||||
"resource_delete_postgres.sql": dialects{
|
|
||||||
sqltemplate.PostgreSQL,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
sqlResourceInsert: {
|
|
||||||
{
|
|
||||||
Name: "insert into resource",
|
|
||||||
Data: &sqlResourceRequest{
|
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
|
||||||
WriteEvent: resource.WriteEvent{
|
|
||||||
Key: &resource.ResourceKey{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Expected: expected{
|
|
||||||
"resource_insert_mysql_sqlite.sql": dialects{
|
|
||||||
sqltemplate.MySQL,
|
|
||||||
sqltemplate.SQLite,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
sqlResourceUpdate: {
|
|
||||||
{
|
|
||||||
Name: "single path",
|
|
||||||
Data: &sqlResourceRequest{
|
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
|
||||||
WriteEvent: resource.WriteEvent{
|
|
||||||
Key: &resource.ResourceKey{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Expected: expected{
|
|
||||||
"resource_update_mysql_sqlite.sql": dialects{
|
|
||||||
sqltemplate.MySQL,
|
|
||||||
sqltemplate.SQLite,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
sqlResourceRead: {
|
|
||||||
{
|
|
||||||
Name: "without resource version",
|
|
||||||
Data: &sqlResourceReadRequest{
|
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
|
||||||
Request: &resource.ReadRequest{
|
|
||||||
Key: &resource.ResourceKey{},
|
|
||||||
},
|
|
||||||
readResponse: new(readResponse),
|
|
||||||
},
|
|
||||||
Expected: expected{
|
|
||||||
"resource_read_mysql_sqlite.sql": dialects{
|
|
||||||
sqltemplate.MySQL,
|
|
||||||
sqltemplate.SQLite,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
sqlResourceList: {
|
|
||||||
{
|
|
||||||
Name: "filter on namespace",
|
|
||||||
Data: &sqlResourceListRequest{
|
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
|
||||||
Request: &resource.ListRequest{
|
|
||||||
Limit: 10,
|
|
||||||
Options: &resource.ListOptions{
|
|
||||||
Key: &resource.ResourceKey{
|
Key: &resource.ResourceKey{
|
||||||
Namespace: "ns",
|
Namespace: "nn",
|
||||||
|
Group: "gg",
|
||||||
|
Resource: "rr",
|
||||||
|
Name: "name",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Expected: expected{
|
},
|
||||||
"resource_list_mysql_sqlite.sql": dialects{
|
sqlResourceInsert: {
|
||||||
sqltemplate.MySQL,
|
{
|
||||||
sqltemplate.SQLite,
|
Name: "simple",
|
||||||
|
Data: &sqlResourceRequest{
|
||||||
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
|
WriteEvent: resource.WriteEvent{
|
||||||
|
Key: &resource.ResourceKey{
|
||||||
|
Namespace: "nn",
|
||||||
|
Group: "gg",
|
||||||
|
Resource: "rr",
|
||||||
|
Name: "name",
|
||||||
|
},
|
||||||
|
Type: resource.WatchEvent_ADDED,
|
||||||
|
PreviousRV: 123,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
sqlResourceUpdate: {
|
||||||
|
{
|
||||||
|
Name: "single path",
|
||||||
|
Data: &sqlResourceRequest{
|
||||||
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
|
WriteEvent: resource.WriteEvent{
|
||||||
|
Key: &resource.ResourceKey{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
sqlResourceRead: {
|
||||||
|
{
|
||||||
|
Name: "without_resource_version",
|
||||||
|
Data: &sqlResourceReadRequest{
|
||||||
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
|
Request: &resource.ReadRequest{
|
||||||
|
Key: &resource.ResourceKey{},
|
||||||
|
},
|
||||||
|
readResponse: new(readResponse),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
|
|
||||||
sqlResourceHistoryList: {
|
sqlResourceList: {
|
||||||
{
|
{
|
||||||
Name: "single path",
|
Name: "filter_on_namespace",
|
||||||
Data: &sqlResourceHistoryListRequest{
|
Data: &sqlResourceListRequest{
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
Request: &historyListRequest{
|
Request: &resource.ListRequest{
|
||||||
Limit: 10,
|
Limit: 10,
|
||||||
Options: &resource.ListOptions{
|
Options: &resource.ListOptions{
|
||||||
Key: &resource.ResourceKey{
|
Key: &resource.ResourceKey{
|
||||||
Namespace: "ns",
|
Namespace: "ns",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Response: new(resource.ResourceWrapper),
|
|
||||||
},
|
},
|
||||||
Expected: expected{
|
},
|
||||||
"resource_history_list_mysql_sqlite.sql": dialects{
|
|
||||||
sqltemplate.MySQL,
|
sqlResourceHistoryList: {
|
||||||
sqltemplate.SQLite,
|
{
|
||||||
|
Name: "single path",
|
||||||
|
Data: &sqlResourceHistoryListRequest{
|
||||||
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
|
Request: &historyListRequest{
|
||||||
|
Limit: 10,
|
||||||
|
Options: &resource.ListOptions{
|
||||||
|
Key: &resource.ResourceKey{
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Response: new(resource.ResourceWrapper),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
|
|
||||||
sqlResourceUpdateRV: {
|
sqlResourceUpdateRV: {
|
||||||
{
|
{
|
||||||
Name: "single path",
|
Name: "single path",
|
||||||
Data: &sqlResourceUpdateRVRequest{
|
Data: &sqlResourceUpdateRVRequest{
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
},
|
|
||||||
Expected: expected{
|
|
||||||
"resource_update_rv_mysql_sqlite.sql": dialects{
|
|
||||||
sqltemplate.MySQL,
|
|
||||||
sqltemplate.SQLite,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
|
|
||||||
sqlResourceHistoryRead: {
|
sqlResourceHistoryRead: {
|
||||||
{
|
{
|
||||||
Name: "single path",
|
Name: "single path",
|
||||||
Data: &sqlResourceReadRequest{
|
Data: &sqlResourceReadRequest{
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
Request: &resource.ReadRequest{
|
Request: &resource.ReadRequest{
|
||||||
ResourceVersion: 123,
|
ResourceVersion: 123,
|
||||||
Key: &resource.ResourceKey{},
|
Key: &resource.ResourceKey{},
|
||||||
},
|
},
|
||||||
readResponse: new(readResponse),
|
readResponse: new(readResponse),
|
||||||
},
|
|
||||||
Expected: expected{
|
|
||||||
"resource_history_read_mysql_sqlite.sql": dialects{
|
|
||||||
sqltemplate.MySQL,
|
|
||||||
sqltemplate.SQLite,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
|
|
||||||
sqlResourceHistoryUpdateRV: {
|
sqlResourceHistoryUpdateRV: {
|
||||||
{
|
{
|
||||||
Name: "single path",
|
Name: "single path",
|
||||||
Data: &sqlResourceUpdateRVRequest{
|
Data: &sqlResourceUpdateRVRequest{
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
},
|
|
||||||
Expected: expected{
|
|
||||||
"resource_history_update_rv_mysql_sqlite.sql": dialects{
|
|
||||||
sqltemplate.MySQL,
|
|
||||||
sqltemplate.SQLite,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
|
|
||||||
sqlResourceHistoryInsert: {
|
sqlResourceHistoryInsert: {
|
||||||
{
|
{
|
||||||
Name: "insert into resource_history",
|
Name: "insert into resource_history",
|
||||||
Data: &sqlResourceRequest{
|
Data: &sqlResourceRequest{
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
WriteEvent: resource.WriteEvent{
|
WriteEvent: resource.WriteEvent{
|
||||||
Key: &resource.ResourceKey{},
|
Key: &resource.ResourceKey{},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
Expected: expected{
|
|
||||||
"resource_history_insert_mysql_sqlite.sql": dialects{
|
|
||||||
sqltemplate.MySQL,
|
|
||||||
sqltemplate.SQLite,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
|
|
||||||
sqlResourceVersionGet: {
|
sqlResourceVersionGet: {
|
||||||
{
|
{
|
||||||
Name: "single path",
|
Name: "single path",
|
||||||
Data: &sqlResourceVersionRequest{
|
Data: &sqlResourceVersionRequest{
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
resourceVersion: new(resourceVersion),
|
resourceVersion: new(resourceVersion),
|
||||||
ReadOnly: false,
|
ReadOnly: false,
|
||||||
},
|
|
||||||
Expected: expected{
|
|
||||||
"resource_version_get_mysql.sql": dialects{
|
|
||||||
sqltemplate.MySQL,
|
|
||||||
},
|
|
||||||
"resource_version_get_sqlite.sql": dialects{
|
|
||||||
sqltemplate.SQLite,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
|
|
||||||
sqlResourceVersionInc: {
|
sqlResourceVersionInc: {
|
||||||
{
|
{
|
||||||
Name: "increment resource version",
|
Name: "increment resource version",
|
||||||
Data: &sqlResourceVersionRequest{
|
Data: &sqlResourceVersionRequest{
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
resourceVersion: &resourceVersion{
|
resourceVersion: &resourceVersion{
|
||||||
ResourceVersion: 123,
|
ResourceVersion: 123,
|
||||||
},
|
},
|
||||||
},
|
|
||||||
Expected: expected{
|
|
||||||
"resource_version_inc_mysql_sqlite.sql": dialects{
|
|
||||||
sqltemplate.MySQL,
|
|
||||||
sqltemplate.SQLite,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
|
|
||||||
sqlResourceVersionInsert: {
|
sqlResourceVersionInsert: {
|
||||||
{
|
{
|
||||||
Name: "single path",
|
Name: "single path",
|
||||||
Data: &sqlResourceVersionRequest{
|
Data: &sqlResourceVersionRequest{
|
||||||
SQLTemplate: new(sqltemplate.SQLTemplate),
|
SQLTemplateIface: mocks.NewTestingSQLTemplate(),
|
||||||
},
|
|
||||||
Expected: expected{
|
|
||||||
"resource_version_insert_mysql_sqlite.sql": dialects{
|
|
||||||
sqltemplate.MySQL,
|
|
||||||
sqltemplate.SQLite,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}})
|
||||||
}
|
|
||||||
|
|
||||||
// Execute test cases
|
|
||||||
for tmpl, tcs := range testCases {
|
|
||||||
t.Run(tmpl.Name(), func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
for _, tc := range tcs {
|
|
||||||
t.Run(tc.Name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
for filename, ds := range tc.Expected {
|
|
||||||
t.Run(filename, func(t *testing.T) {
|
|
||||||
// not parallel because we're sharing tc.Data, not
|
|
||||||
// worth it deep cloning
|
|
||||||
|
|
||||||
rawQuery := string(testdata(t, filename))
|
|
||||||
expectedQuery := sqltemplate.FormatSQL(rawQuery)
|
|
||||||
|
|
||||||
for _, d := range ds {
|
|
||||||
t.Run(d.DialectName(), func(t *testing.T) {
|
|
||||||
// not parallel for the same reason
|
|
||||||
|
|
||||||
tc.Data.SetDialect(d)
|
|
||||||
err := tc.Data.Validate()
|
|
||||||
require.NoError(t, err)
|
|
||||||
got, err := sqltemplate.Execute(tmpl, tc.Data)
|
|
||||||
require.NoError(t, err)
|
|
||||||
got = sqltemplate.FormatSQL(got)
|
|
||||||
require.Equal(t, expectedQuery, got)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
147
pkg/storage/unified/sql/sqltemplate/mocks/test_snapshots.go
Normal file
147
pkg/storage/unified/sql/sqltemplate/mocks/test_snapshots.go
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
package mocks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
reflect "reflect"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
sqltemplate "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewTestingSQLTemplate() sqltemplate.SQLTemplateIface {
|
||||||
|
standard := sqltemplate.New(sqltemplate.MySQL) // dialect gets replaced at each iteration
|
||||||
|
return &testingSQLTemplate{standard}
|
||||||
|
}
|
||||||
|
|
||||||
|
type testingSQLTemplate struct {
|
||||||
|
*sqltemplate.SQLTemplate
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *testingSQLTemplate) Arg(x any) string {
|
||||||
|
_ = t.SQLTemplate.Arg(x) // discard the output
|
||||||
|
|
||||||
|
switch v := reflect.ValueOf(x); {
|
||||||
|
case v.Kind() == reflect.Bool:
|
||||||
|
if v.Bool() {
|
||||||
|
return "TRUE"
|
||||||
|
}
|
||||||
|
return "FALSE"
|
||||||
|
|
||||||
|
case v.CanInt(), v.CanUint(), v.CanFloat():
|
||||||
|
_, ok := x.(fmt.Stringer)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Sprintf("%v", x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("'%v'", x) // single quotes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *testingSQLTemplate) ArgList(slice reflect.Value) (string, error) {
|
||||||
|
// Copied from upstream Arg
|
||||||
|
if !slice.IsValid() || slice.Kind() != reflect.Slice {
|
||||||
|
return "", sqltemplate.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(t.Arg(slice.Index(i).Interface()))
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type TemplateTestCase struct {
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Data should be the struct passed to the template.
|
||||||
|
Data sqltemplate.SQLTemplateIface
|
||||||
|
}
|
||||||
|
|
||||||
|
type TemplateTestSetup struct {
|
||||||
|
// Where the snapshots can be found
|
||||||
|
RootDir string
|
||||||
|
|
||||||
|
// The template will be run through each dialect
|
||||||
|
Dialects []sqltemplate.Dialect
|
||||||
|
|
||||||
|
// Check a set of templates against example inputs
|
||||||
|
Templates map[*template.Template][]TemplateTestCase
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckQuerySnapshots(t *testing.T, setup TemplateTestSetup) {
|
||||||
|
t.Helper()
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
if len(setup.Dialects) < 1 {
|
||||||
|
setup.Dialects = []sqltemplate.Dialect{
|
||||||
|
sqltemplate.MySQL,
|
||||||
|
sqltemplate.SQLite,
|
||||||
|
sqltemplate.PostgreSQL,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for tmpl, cases := range setup.Templates {
|
||||||
|
t.Run(tmpl.Name(), func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tname := strings.TrimSuffix(tmpl.Name(), ".sql")
|
||||||
|
for _, input := range cases {
|
||||||
|
t.Run(input.Name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
require.NotPanics(t, func() {
|
||||||
|
for _, dialect := range setup.Dialects {
|
||||||
|
t.Run(dialect.DialectName(), func(t *testing.T) {
|
||||||
|
// not parallel because we're sharing tc.Data,
|
||||||
|
// but also not worth deep cloning
|
||||||
|
input.Data.SetDialect(dialect)
|
||||||
|
err := input.Data.Validate()
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
got, err := sqltemplate.Execute(tmpl, input.Data)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
clean := sqltemplate.RemoveEmptyLines(got)
|
||||||
|
|
||||||
|
update := false
|
||||||
|
fname := fmt.Sprintf("%s--%s-%s.sql", dialect.DialectName(), tname, input.Name)
|
||||||
|
fpath := filepath.Join(setup.RootDir, fname)
|
||||||
|
|
||||||
|
// We can ignore the gosec G304 because this is only for tests
|
||||||
|
// nolint:gosec
|
||||||
|
expect, err := os.ReadFile(fpath)
|
||||||
|
if err != nil || len(expect) < 1 {
|
||||||
|
update = true
|
||||||
|
t.Errorf("missing " + fpath)
|
||||||
|
} else {
|
||||||
|
if diff := cmp.Diff(string(expect), clean); diff != "" {
|
||||||
|
t.Errorf("%s: %s", fname, diff)
|
||||||
|
update = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if update {
|
||||||
|
_ = os.WriteFile(fpath, []byte(clean), 0777)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -11,21 +11,25 @@ import (
|
|||||||
var (
|
var (
|
||||||
ErrValidationNotImplemented = errors.New("validation not implemented")
|
ErrValidationNotImplemented = errors.New("validation not implemented")
|
||||||
ErrSQLTemplateNoSerialize = errors.New("SQLTemplate should not be serialized")
|
ErrSQLTemplateNoSerialize = errors.New("SQLTemplate should not be serialized")
|
||||||
|
|
||||||
|
// Make sure SQLTemplate implements the interface
|
||||||
|
_ SQLTemplateIface = (*SQLTemplate)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// SQLTemplate provides comprehensive support for SQL templating, handling
|
// SQLTemplate provides comprehensive support for SQL templating, handling
|
||||||
// dialect traits, execution arguments and scanning arguments.
|
// dialect traits, execution arguments and scanning arguments.
|
||||||
type SQLTemplate struct {
|
type SQLTemplate struct {
|
||||||
Dialect
|
Dialect
|
||||||
Args
|
*Args
|
||||||
ScanDest
|
*ScanDest
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a nee *SQLTemplate that will use the given dialect.
|
// New returns a nee *SQLTemplate that will use the given dialect.
|
||||||
func New(d Dialect) *SQLTemplate {
|
func New(d Dialect) *SQLTemplate {
|
||||||
ret := new(SQLTemplate)
|
ret := new(SQLTemplate)
|
||||||
|
ret.ScanDest = new(ScanDest)
|
||||||
|
ret.Args = NewArgs(d)
|
||||||
ret.SetDialect(d)
|
ret.SetDialect(d)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
7
pkg/storage/unified/sql/testdata/mysql--resource_delete-simple.sql
vendored
Executable file
7
pkg/storage/unified/sql/testdata/mysql--resource_delete-simple.sql
vendored
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
DELETE FROM "resource"
|
||||||
|
WHERE 1 = 1
|
||||||
|
AND "namespace" = 'nn'
|
||||||
|
AND "group" = 'gg'
|
||||||
|
AND "resource" = 'rr'
|
||||||
|
AND "name" = 'name'
|
||||||
|
;
|
20
pkg/storage/unified/sql/testdata/mysql--resource_history_insert-insert into resource_history.sql
vendored
Executable file
20
pkg/storage/unified/sql/testdata/mysql--resource_history_insert-insert into resource_history.sql
vendored
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
INSERT INTO "resource_history"
|
||||||
|
(
|
||||||
|
"guid",
|
||||||
|
"group",
|
||||||
|
"resource",
|
||||||
|
"namespace",
|
||||||
|
"name",
|
||||||
|
"value",
|
||||||
|
"action"
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'[]',
|
||||||
|
'UNKNOWN'
|
||||||
|
)
|
||||||
|
;
|
25
pkg/storage/unified/sql/testdata/mysql--resource_history_list-single path.sql
vendored
Executable file
25
pkg/storage/unified/sql/testdata/mysql--resource_history_list-single path.sql
vendored
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
SELECT
|
||||||
|
kv."resource_version",
|
||||||
|
kv."namespace",
|
||||||
|
kv."name",
|
||||||
|
kv."value"
|
||||||
|
FROM "resource_history" as kv
|
||||||
|
INNER JOIN (
|
||||||
|
SELECT "namespace", "group", "resource", "name", max("resource_version") AS "resource_version"
|
||||||
|
FROM "resource_history" AS mkv
|
||||||
|
WHERE 1 = 1
|
||||||
|
AND "resource_version" <= 0
|
||||||
|
AND "namespace" = 'ns'
|
||||||
|
GROUP BY mkv."namespace", mkv."group", mkv."resource", mkv."name"
|
||||||
|
) AS maxkv
|
||||||
|
ON
|
||||||
|
maxkv."resource_version" = kv."resource_version"
|
||||||
|
AND maxkv."namespace" = kv."namespace"
|
||||||
|
AND maxkv."group" = kv."group"
|
||||||
|
AND maxkv."resource" = kv."resource"
|
||||||
|
AND maxkv."name" = kv."name"
|
||||||
|
WHERE kv."action" != 3
|
||||||
|
AND kv."namespace" = 'ns'
|
||||||
|
ORDER BY kv."namespace" ASC, kv."name" ASC
|
||||||
|
LIMIT 10 OFFSET 0
|
||||||
|
;
|
13
pkg/storage/unified/sql/testdata/mysql--resource_history_read-single path.sql
vendored
Executable file
13
pkg/storage/unified/sql/testdata/mysql--resource_history_read-single path.sql
vendored
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
SELECT
|
||||||
|
"resource_version",
|
||||||
|
"value"
|
||||||
|
FROM "resource_history"
|
||||||
|
WHERE 1 = 1
|
||||||
|
AND "namespace" = ''
|
||||||
|
AND "group" = ''
|
||||||
|
AND "resource" = ''
|
||||||
|
AND "name" = ''
|
||||||
|
AND "resource_version" <= 123
|
||||||
|
ORDER BY "resource_version" DESC
|
||||||
|
LIMIT 1
|
||||||
|
;
|
4
pkg/storage/unified/sql/testdata/mysql--resource_history_update_rv-single path.sql
vendored
Executable file
4
pkg/storage/unified/sql/testdata/mysql--resource_history_update_rv-single path.sql
vendored
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
UPDATE "resource_history"
|
||||||
|
SET "resource_version" = 0
|
||||||
|
WHERE "guid" = ''
|
||||||
|
;
|
20
pkg/storage/unified/sql/testdata/mysql--resource_insert-simple.sql
vendored
Executable file
20
pkg/storage/unified/sql/testdata/mysql--resource_insert-simple.sql
vendored
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
INSERT INTO "resource"
|
||||||
|
(
|
||||||
|
"guid",
|
||||||
|
"group",
|
||||||
|
"resource",
|
||||||
|
"namespace",
|
||||||
|
"name",
|
||||||
|
"value",
|
||||||
|
"action"
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
'',
|
||||||
|
'gg',
|
||||||
|
'rr',
|
||||||
|
'nn',
|
||||||
|
'name',
|
||||||
|
'[]',
|
||||||
|
'ADDED'
|
||||||
|
)
|
||||||
|
;
|
10
pkg/storage/unified/sql/testdata/mysql--resource_list-filter_on_namespace.sql
vendored
Executable file
10
pkg/storage/unified/sql/testdata/mysql--resource_list-filter_on_namespace.sql
vendored
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
SELECT
|
||||||
|
"resource_version",
|
||||||
|
"namespace",
|
||||||
|
"name",
|
||||||
|
"value"
|
||||||
|
FROM "resource"
|
||||||
|
WHERE 1 = 1
|
||||||
|
AND "namespace" = 'ns'
|
||||||
|
ORDER BY "namespace" ASC, "name" ASC
|
||||||
|
;
|
10
pkg/storage/unified/sql/testdata/mysql--resource_read-without_resource_version.sql
vendored
Executable file
10
pkg/storage/unified/sql/testdata/mysql--resource_read-without_resource_version.sql
vendored
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
SELECT
|
||||||
|
"resource_version",
|
||||||
|
"value"
|
||||||
|
FROM "resource"
|
||||||
|
WHERE 1 = 1
|
||||||
|
AND "namespace" = ''
|
||||||
|
AND "group" = ''
|
||||||
|
AND "resource" = ''
|
||||||
|
AND "name" = ''
|
||||||
|
;
|
11
pkg/storage/unified/sql/testdata/mysql--resource_update-single path.sql
vendored
Executable file
11
pkg/storage/unified/sql/testdata/mysql--resource_update-single path.sql
vendored
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
UPDATE "resource"
|
||||||
|
SET
|
||||||
|
"guid" = '',
|
||||||
|
"value" = '[]',
|
||||||
|
"action" = 'UNKNOWN'
|
||||||
|
WHERE 1 = 1
|
||||||
|
AND "group" = ''
|
||||||
|
AND "resource" = ''
|
||||||
|
AND "namespace" = ''
|
||||||
|
AND "name" = ''
|
||||||
|
;
|
4
pkg/storage/unified/sql/testdata/mysql--resource_update_rv-single path.sql
vendored
Executable file
4
pkg/storage/unified/sql/testdata/mysql--resource_update_rv-single path.sql
vendored
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
UPDATE "resource"
|
||||||
|
SET "resource_version" = 0
|
||||||
|
WHERE "guid" = ''
|
||||||
|
;
|
8
pkg/storage/unified/sql/testdata/mysql--resource_version_get-single path.sql
vendored
Executable file
8
pkg/storage/unified/sql/testdata/mysql--resource_version_get-single path.sql
vendored
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
SELECT
|
||||||
|
"resource_version"
|
||||||
|
FROM "resource_version"
|
||||||
|
WHERE 1 = 1
|
||||||
|
AND "group" = ''
|
||||||
|
AND "resource" = ''
|
||||||
|
FOR UPDATE
|
||||||
|
;
|
7
pkg/storage/unified/sql/testdata/mysql--resource_version_inc-increment resource version.sql
vendored
Executable file
7
pkg/storage/unified/sql/testdata/mysql--resource_version_inc-increment resource version.sql
vendored
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
UPDATE "resource_version"
|
||||||
|
SET
|
||||||
|
"resource_version" = 123
|
||||||
|
WHERE 1 = 1
|
||||||
|
AND "group" = ''
|
||||||
|
AND "resource" = ''
|
||||||
|
;
|
12
pkg/storage/unified/sql/testdata/mysql--resource_version_insert-single path.sql
vendored
Executable file
12
pkg/storage/unified/sql/testdata/mysql--resource_version_insert-single path.sql
vendored
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
INSERT INTO "resource_version"
|
||||||
|
(
|
||||||
|
"group",
|
||||||
|
"resource",
|
||||||
|
"resource_version"
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
1
|
||||||
|
)
|
||||||
|
;
|
7
pkg/storage/unified/sql/testdata/postgres--resource_delete-simple.sql
vendored
Executable file
7
pkg/storage/unified/sql/testdata/postgres--resource_delete-simple.sql
vendored
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
DELETE FROM "resource"
|
||||||
|
WHERE 1 = 1
|
||||||
|
AND "namespace" = 'nn'
|
||||||
|
AND "group" = 'gg'
|
||||||
|
AND "resource" = 'rr'
|
||||||
|
AND "name" = 'name'
|
||||||
|
;
|
20
pkg/storage/unified/sql/testdata/postgres--resource_history_insert-insert into resource_history.sql
vendored
Executable file
20
pkg/storage/unified/sql/testdata/postgres--resource_history_insert-insert into resource_history.sql
vendored
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
INSERT INTO "resource_history"
|
||||||
|
(
|
||||||
|
"guid",
|
||||||
|
"group",
|
||||||
|
"resource",
|
||||||
|
"namespace",
|
||||||
|
"name",
|
||||||
|
"value",
|
||||||
|
"action"
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'[]',
|
||||||
|
'UNKNOWN'
|
||||||
|
)
|
||||||
|
;
|
25
pkg/storage/unified/sql/testdata/postgres--resource_history_list-single path.sql
vendored
Executable file
25
pkg/storage/unified/sql/testdata/postgres--resource_history_list-single path.sql
vendored
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
SELECT
|
||||||
|
kv."resource_version",
|
||||||
|
kv."namespace",
|
||||||
|
kv."name",
|
||||||
|
kv."value"
|
||||||
|
FROM "resource_history" as kv
|
||||||
|
INNER JOIN (
|
||||||
|
SELECT "namespace", "group", "resource", "name", max("resource_version") AS "resource_version"
|
||||||
|
FROM "resource_history" AS mkv
|
||||||
|
WHERE 1 = 1
|
||||||
|
AND "resource_version" <= 0
|
||||||
|
AND "namespace" = 'ns'
|
||||||
|
GROUP BY mkv."namespace", mkv."group", mkv."resource", mkv."name"
|
||||||
|
) AS maxkv
|
||||||
|
ON
|
||||||
|
maxkv."resource_version" = kv."resource_version"
|
||||||
|
AND maxkv."namespace" = kv."namespace"
|
||||||
|
AND maxkv."group" = kv."group"
|
||||||
|
AND maxkv."resource" = kv."resource"
|
||||||
|
AND maxkv."name" = kv."name"
|
||||||
|
WHERE kv."action" != 3
|
||||||
|
AND kv."namespace" = 'ns'
|
||||||
|
ORDER BY kv."namespace" ASC, kv."name" ASC
|
||||||
|
LIMIT 10 OFFSET 0
|
||||||
|
;
|
13
pkg/storage/unified/sql/testdata/postgres--resource_history_read-single path.sql
vendored
Executable file
13
pkg/storage/unified/sql/testdata/postgres--resource_history_read-single path.sql
vendored
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
SELECT
|
||||||
|
"resource_version",
|
||||||
|
"value"
|
||||||
|
FROM "resource_history"
|
||||||
|
WHERE 1 = 1
|
||||||
|
AND "namespace" = ''
|
||||||
|
AND "group" = ''
|
||||||
|
AND "resource" = ''
|
||||||
|
AND "name" = ''
|
||||||
|
AND "resource_version" <= 123
|
||||||
|
ORDER BY "resource_version" DESC
|
||||||
|
LIMIT 1
|
||||||
|
;
|
4
pkg/storage/unified/sql/testdata/postgres--resource_history_update_rv-single path.sql
vendored
Executable file
4
pkg/storage/unified/sql/testdata/postgres--resource_history_update_rv-single path.sql
vendored
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
UPDATE "resource_history"
|
||||||
|
SET "resource_version" = 0
|
||||||
|
WHERE "guid" = ''
|
||||||
|
;
|
20
pkg/storage/unified/sql/testdata/postgres--resource_insert-simple.sql
vendored
Executable file
20
pkg/storage/unified/sql/testdata/postgres--resource_insert-simple.sql
vendored
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
INSERT INTO "resource"
|
||||||
|
(
|
||||||
|
"guid",
|
||||||
|
"group",
|
||||||
|
"resource",
|
||||||
|
"namespace",
|
||||||
|
"name",
|
||||||
|
"value",
|
||||||
|
"action"
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
'',
|
||||||
|
'gg',
|
||||||
|
'rr',
|
||||||
|
'nn',
|
||||||
|
'name',
|
||||||
|
'[]',
|
||||||
|
'ADDED'
|
||||||
|
)
|
||||||
|
;
|
10
pkg/storage/unified/sql/testdata/postgres--resource_list-filter_on_namespace.sql
vendored
Executable file
10
pkg/storage/unified/sql/testdata/postgres--resource_list-filter_on_namespace.sql
vendored
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
SELECT
|
||||||
|
"resource_version",
|
||||||
|
"namespace",
|
||||||
|
"name",
|
||||||
|
"value"
|
||||||
|
FROM "resource"
|
||||||
|
WHERE 1 = 1
|
||||||
|
AND "namespace" = 'ns'
|
||||||
|
ORDER BY "namespace" ASC, "name" ASC
|
||||||
|
;
|
10
pkg/storage/unified/sql/testdata/postgres--resource_read-without_resource_version.sql
vendored
Executable file
10
pkg/storage/unified/sql/testdata/postgres--resource_read-without_resource_version.sql
vendored
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
SELECT
|
||||||
|
"resource_version",
|
||||||
|
"value"
|
||||||
|
FROM "resource"
|
||||||
|
WHERE 1 = 1
|
||||||
|
AND "namespace" = ''
|
||||||
|
AND "group" = ''
|
||||||
|
AND "resource" = ''
|
||||||
|
AND "name" = ''
|
||||||
|
;
|
11
pkg/storage/unified/sql/testdata/postgres--resource_update-single path.sql
vendored
Executable file
11
pkg/storage/unified/sql/testdata/postgres--resource_update-single path.sql
vendored
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
UPDATE "resource"
|
||||||
|
SET
|
||||||
|
"guid" = '',
|
||||||
|
"value" = '[]',
|
||||||
|
"action" = 'UNKNOWN'
|
||||||
|
WHERE 1 = 1
|
||||||
|
AND "group" = ''
|
||||||
|
AND "resource" = ''
|
||||||
|
AND "namespace" = ''
|
||||||
|
AND "name" = ''
|
||||||
|
;
|
4
pkg/storage/unified/sql/testdata/postgres--resource_update_rv-single path.sql
vendored
Executable file
4
pkg/storage/unified/sql/testdata/postgres--resource_update_rv-single path.sql
vendored
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
UPDATE "resource"
|
||||||
|
SET "resource_version" = 0
|
||||||
|
WHERE "guid" = ''
|
||||||
|
;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user