chore: initial commit of ai site platform
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
126
platform/internal/meta/postgres_test.go
Normal file
126
platform/internal/meta/postgres_test.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package meta_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"aijianzhan/platform/internal/blueprint"
|
||||
"aijianzhan/platform/internal/meta"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
func testDSN(t *testing.T) string {
|
||||
t.Helper()
|
||||
dsn := os.Getenv("PLATFORM_TEST_DSN")
|
||||
if dsn == "" {
|
||||
dsn = "postgres://platform:platform@127.0.0.1:5432/platform?sslmode=disable"
|
||||
}
|
||||
return dsn
|
||||
}
|
||||
|
||||
func TestPostgresMetaPersist(t *testing.T) {
|
||||
db, err := sql.Open("postgres", testDSN(t))
|
||||
if err != nil {
|
||||
t.Skip(err)
|
||||
}
|
||||
if err := db.Ping(); err != nil {
|
||||
t.Skip(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
if err := meta.EnsureSchema(ctx, db); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
store := meta.NewPostgresStore(db)
|
||||
slug := "meta_persist_demo"
|
||||
tenantID := int64(99001)
|
||||
_, _ = db.ExecContext(ctx, `DELETE FROM platform_meta.tenant_apps WHERE tenant_id=$1 AND slug=$2`, tenantID, slug)
|
||||
|
||||
n := false
|
||||
bp := &blueprint.Blueprint{
|
||||
Version: "1.0",
|
||||
Meta: blueprint.Meta{Name: "持久化测试", Slug: slug, Locale: "zh-CN"},
|
||||
Storage: blueprint.Storage{Mode: "schema_per_app", Engine: "postgres", SchemaName: "app_t99001_meta_persist_demo"},
|
||||
Entities: []blueprint.Entity{{
|
||||
Name: "item", Table: "item", Label: "Item", PrimaryKey: "id",
|
||||
Fields: []blueprint.Field{
|
||||
{Name: "id", Type: "bigint", Label: "ID", Nullable: &n},
|
||||
{Name: "title", Type: "string", Label: "标题", Nullable: &n, MaxLength: 64},
|
||||
},
|
||||
}},
|
||||
Apis: blueprint.Apis{
|
||||
BasePath: "/api/v1/apps/" + slug,
|
||||
Resources: []blueprint.APIResource{{
|
||||
Entity: "item", Path: "/items",
|
||||
Operations: []string{"list", "get", "create"},
|
||||
}},
|
||||
},
|
||||
Pages: []blueprint.Page{{
|
||||
ID: "list", Title: "列表", Route: "/items", Type: "list", Entity: "item",
|
||||
}},
|
||||
Security: blueprint.Security{
|
||||
Visibility: "private",
|
||||
Roles: []blueprint.Role{{
|
||||
Name: "管理员", Permissions: []string{"读取模块", "写入模块", "发布模块", "新增数据", "查询数据"},
|
||||
}},
|
||||
RowPolicies: []blueprint.RowPolicy{{Entity: "item", Rule: "tenant_isolated"}},
|
||||
},
|
||||
}
|
||||
|
||||
rec := &meta.AppRecord{
|
||||
AppID: "11111111-1111-1111-1111-111111111111",
|
||||
TenantID: tenantID,
|
||||
Slug: slug,
|
||||
Name: bp.Meta.Name,
|
||||
SchemaName: bp.Storage.SchemaName,
|
||||
Engine: "postgres",
|
||||
Status: meta.StatusPublished,
|
||||
Blueprint: bp,
|
||||
DDL: []string{"SELECT 1"},
|
||||
Endpoints: []string{"GET /api/v1/apps/" + slug + "/items"},
|
||||
CreatedAt: time.Now().UTC(),
|
||||
UpdatedAt: time.Now().UTC(),
|
||||
}
|
||||
if err := store.Save(ctx, rec); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
got, err := store.GetBySlug(ctx, tenantID, slug)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got.Status != meta.StatusPublished || got.Blueprint == nil || got.Blueprint.Meta.Name != "持久化测试" {
|
||||
t.Fatalf("unexpected record: %+v", got)
|
||||
}
|
||||
|
||||
ref, err := store.ResolveResource(ctx, tenantID, slug, "items")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ref.Entity.Name != "item" {
|
||||
t.Fatalf("entity=%s", ref.Entity.Name)
|
||||
}
|
||||
|
||||
// 二次 Save 应保留 app_id
|
||||
rec.Name = "持久化测试-更新"
|
||||
rec.AppID = "22222222-2222-2222-2222-222222222222"
|
||||
if err := store.Save(ctx, rec); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got2, err := store.GetBySlug(ctx, tenantID, slug)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got2.AppID != "11111111-1111-1111-1111-111111111111" {
|
||||
t.Fatalf("app_id should be preserved, got %s", got2.AppID)
|
||||
}
|
||||
if got2.Name != "持久化测试-更新" {
|
||||
t.Fatalf("name not updated: %s", got2.Name)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user