8a4029058b
Add demo dashboard settings table and CRUD API * Add demo dashboard settings table and CRUD API - Migration 00000000000123: create demoDashboardSettings table (id, guid, key, value JSONB, isDeleted, timestamps) - SQLC queries and repository for create, list, listByGuid, get, update, soft delete - OpenAPI paths and schemas in queryAPI.yaml; regenerate api.gen.go (embedded spec) - Handlers in api/queryAPI/demodashboardsettings.go; ConfigProvider GetDBQueries for repo access - Unit tests for demo dashboard settings CRUD * Fix sqlc-generated demo dashboard setting types Align demo dashboard settings handlers with sqlc output (DemoDashboardSetting model + pointer slices) so CI codegen/build succeeds. * Fix CI gosec and gofmt issues - Suppress gosec G115 for TotalCount len->int32 cast (consistent with other list endpoints) - gofmt mock GetDBQueries() in test helpers * gofmt query API demo settings * Tighten demo dashboard settings OpenAPI constraints * Regenerate query API embedded spec * refactor: generic UI settings (table, API, service) and three-layer architecture - Replace demo-dashboard-settings with generic UI settings: - Table uiSettings with namespace (was guid), key, value JSONB; UNIQUE(namespace, key) - Migration 123: create_ui_settings (single migration, no rename) - OpenAPI: /ui-settings, UISettingsService, UISetting schemas with namespace - API types and handlers: CreateUISetting, ListUISettings, GetUISetting, UpdateUISetting, DeleteUISetting - Add service layer (architecture fix): - internal/uisettings: Service with Create, List, ListByNamespace, Get, Update, SoftDelete - Controllers call s.svc.UISettings only; remove GetDBQueries from queryAPI ConfigProvider - Wire UISettings in Services, main.go, and testutils - Repository: uisettings.sql + uisettings.sql.go, UISetting model; remove demodashboardsettings - Controller: uisettings.go (replaces demodashboardsettings.go), ErrNotFound from uisettings package - Tests: uisettings_test.go with namespace-based list/cre… * Add UISetting model and generated queries for uiSettings table - models.go: add UISetting struct (sqlc 1.30.0) - uisettings.sql.go: generated CRUD for ui_settings feature Made-with: Cursor * Use repository.UiSetting to match sqlc-generated type - service and API use repository.UiSetting (sqlc struct name for uiSettings table) - uisettings.sql.go: keep CreateUISetting/GetUISetting etc. from query names, return *UiSetting - Fixes Docker/CI build undefined repository.UISetting * Fix import formatting for golangci-lint * Lint fix * uisettings list test * tests fixes * Merge main: resolve api.gen.go conflicts (UI settings + DeleteDocument) * Doc updates and elimination of index redundancy Approved-by: Jay Brown
183 lines
4.3 KiB
Go
183 lines
4.3 KiB
Go
package uisettings_test
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
"queryorchestration/internal/serviceconfig"
|
|
"queryorchestration/internal/test"
|
|
"queryorchestration/internal/uisettings"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
type testConfig struct {
|
|
serviceconfig.BaseConfig
|
|
}
|
|
|
|
func TestCreate(t *testing.T) {
|
|
ctx := t.Context()
|
|
cfg := &testConfig{}
|
|
test.CreateDB(t, cfg)
|
|
svc := uisettings.New(cfg)
|
|
|
|
row, err := svc.Create(ctx, "ns1", "key1", []byte(`{"a":1}`))
|
|
require.NoError(t, err)
|
|
require.NotNil(t, row)
|
|
assert.Equal(t, "ns1", row.Namespace)
|
|
assert.Equal(t, "key1", row.Key)
|
|
var val map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(row.Value, &val))
|
|
assert.Equal(t, float64(1), val["a"])
|
|
assert.False(t, row.IsDeleted)
|
|
assert.NotEqual(t, uuid.Nil, row.ID)
|
|
}
|
|
|
|
func TestList(t *testing.T) {
|
|
ctx := t.Context()
|
|
cfg := &testConfig{}
|
|
test.CreateDB(t, cfg)
|
|
svc := uisettings.New(cfg)
|
|
|
|
_, err := svc.Create(ctx, "ns-a", "k1", []byte(`{}`))
|
|
require.NoError(t, err)
|
|
_, err = svc.Create(ctx, "ns-b", "k2", []byte(`{"b":2}`))
|
|
require.NoError(t, err)
|
|
|
|
rows, err := svc.List(ctx)
|
|
require.NoError(t, err)
|
|
require.Len(t, rows, 2)
|
|
namespaces := map[string]bool{rows[0].Namespace: true, rows[1].Namespace: true}
|
|
assert.True(t, namespaces["ns-a"])
|
|
assert.True(t, namespaces["ns-b"])
|
|
}
|
|
|
|
func TestListByNamespace(t *testing.T) {
|
|
ctx := t.Context()
|
|
cfg := &testConfig{}
|
|
test.CreateDB(t, cfg)
|
|
svc := uisettings.New(cfg)
|
|
|
|
_, err := svc.Create(ctx, "scoped", "k1", []byte(`{"x":1}`))
|
|
require.NoError(t, err)
|
|
_, err = svc.Create(ctx, "other", "k2", []byte(`{"y":2}`))
|
|
require.NoError(t, err)
|
|
_, err = svc.Create(ctx, "scoped", "k3", []byte(`{"z":3}`))
|
|
require.NoError(t, err)
|
|
|
|
rows, err := svc.ListByNamespace(ctx, "scoped")
|
|
require.NoError(t, err)
|
|
require.Len(t, rows, 2)
|
|
for _, r := range rows {
|
|
assert.Equal(t, "scoped", r.Namespace)
|
|
}
|
|
}
|
|
|
|
func TestGet(t *testing.T) {
|
|
ctx := t.Context()
|
|
cfg := &testConfig{}
|
|
test.CreateDB(t, cfg)
|
|
svc := uisettings.New(cfg)
|
|
|
|
created, err := svc.Create(ctx, "get-ns", "key", []byte(`{"v":1}`))
|
|
require.NoError(t, err)
|
|
|
|
row, err := svc.Get(ctx, created.ID)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, row)
|
|
assert.Equal(t, created.ID, row.ID)
|
|
assert.Equal(t, "get-ns", row.Namespace)
|
|
assert.Equal(t, "key", row.Key)
|
|
}
|
|
|
|
func TestGet_NotFound(t *testing.T) {
|
|
ctx := t.Context()
|
|
cfg := &testConfig{}
|
|
test.CreateDB(t, cfg)
|
|
svc := uisettings.New(cfg)
|
|
|
|
_, err := svc.Get(ctx, uuid.New())
|
|
assert.ErrorIs(t, err, uisettings.ErrNotFound)
|
|
}
|
|
|
|
func TestGet_AfterSoftDeleteReturnsNotFound(t *testing.T) {
|
|
ctx := t.Context()
|
|
cfg := &testConfig{}
|
|
test.CreateDB(t, cfg)
|
|
svc := uisettings.New(cfg)
|
|
|
|
created, err := svc.Create(ctx, "del-ns", "key", []byte(`{}`))
|
|
require.NoError(t, err)
|
|
|
|
err = svc.SoftDelete(ctx, created.ID)
|
|
require.NoError(t, err)
|
|
|
|
_, err = svc.Get(ctx, created.ID)
|
|
assert.ErrorIs(t, err, uisettings.ErrNotFound)
|
|
}
|
|
|
|
func TestUpdate(t *testing.T) {
|
|
ctx := t.Context()
|
|
cfg := &testConfig{}
|
|
test.CreateDB(t, cfg)
|
|
svc := uisettings.New(cfg)
|
|
|
|
created, err := svc.Create(ctx, "upd-ns", "k", []byte(`{"old":true}`))
|
|
require.NoError(t, err)
|
|
|
|
err = svc.Update(ctx, created.ID, []byte(`{"new":true}`))
|
|
require.NoError(t, err)
|
|
|
|
row, err := svc.Get(ctx, created.ID)
|
|
require.NoError(t, err)
|
|
var val map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(row.Value, &val))
|
|
assert.Equal(t, true, val["new"])
|
|
}
|
|
|
|
func TestSoftDelete(t *testing.T) {
|
|
ctx := t.Context()
|
|
cfg := &testConfig{}
|
|
test.CreateDB(t, cfg)
|
|
svc := uisettings.New(cfg)
|
|
|
|
created, err := svc.Create(ctx, "softdel-ns", "k", []byte(`{}`))
|
|
require.NoError(t, err)
|
|
|
|
err = svc.SoftDelete(ctx, created.ID)
|
|
require.NoError(t, err)
|
|
|
|
rows, err := svc.List(ctx)
|
|
require.NoError(t, err)
|
|
for _, r := range rows {
|
|
assert.NotEqual(t, created.ID, r.ID)
|
|
}
|
|
}
|
|
|
|
func TestList_emptyDB(t *testing.T) {
|
|
ctx := t.Context()
|
|
cfg := &testConfig{}
|
|
test.CreateDB(t, cfg)
|
|
svc := uisettings.New(cfg)
|
|
|
|
rows, err := svc.List(ctx)
|
|
require.NoError(t, err)
|
|
assert.Empty(t, rows)
|
|
}
|
|
|
|
func TestListByNamespace_emptyResult(t *testing.T) {
|
|
ctx := t.Context()
|
|
cfg := &testConfig{}
|
|
test.CreateDB(t, cfg)
|
|
svc := uisettings.New(cfg)
|
|
|
|
_, err := svc.Create(ctx, "only-ns", "k", []byte(`{}`))
|
|
require.NoError(t, err)
|
|
|
|
rows, err := svc.ListByNamespace(ctx, "other-namespace")
|
|
require.NoError(t, err)
|
|
assert.Empty(t, rows)
|
|
}
|