@fragno-dev/db 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +137 -13
- package/.turbo/turbo-test.log +36 -0
- package/CHANGELOG.md +7 -0
- package/dist/adapters/adapters.d.ts +18 -0
- package/dist/adapters/adapters.d.ts.map +1 -0
- package/dist/adapters/drizzle/drizzle-adapter.d.ts +21 -0
- package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -0
- package/dist/adapters/drizzle/drizzle-adapter.js +62 -0
- package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -0
- package/dist/adapters/drizzle/drizzle-query.d.ts +17 -0
- package/dist/adapters/drizzle/drizzle-query.d.ts.map +1 -0
- package/dist/adapters/drizzle/drizzle-query.js +139 -0
- package/dist/adapters/drizzle/drizzle-query.js.map +1 -0
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts +9 -0
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts.map +1 -0
- package/dist/adapters/drizzle/drizzle-uow-compiler.js +300 -0
- package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +1 -0
- package/dist/adapters/drizzle/drizzle-uow-decoder.js +82 -0
- package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +1 -0
- package/dist/adapters/drizzle/drizzle-uow-executor.js +125 -0
- package/dist/adapters/drizzle/drizzle-uow-executor.js.map +1 -0
- package/dist/adapters/drizzle/generate.js +273 -0
- package/dist/adapters/drizzle/generate.js.map +1 -0
- package/dist/adapters/drizzle/join-column-utils.js +28 -0
- package/dist/adapters/drizzle/join-column-utils.js.map +1 -0
- package/dist/adapters/drizzle/shared.js +11 -0
- package/dist/adapters/drizzle/shared.js.map +1 -0
- package/dist/adapters/kysely/kysely-adapter.d.ts +23 -0
- package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -0
- package/dist/adapters/kysely/kysely-adapter.js +119 -0
- package/dist/adapters/kysely/kysely-adapter.js.map +1 -0
- package/dist/adapters/kysely/kysely-query-builder.js +306 -0
- package/dist/adapters/kysely/kysely-query-builder.js.map +1 -0
- package/dist/adapters/kysely/kysely-query-compiler.js +67 -0
- package/dist/adapters/kysely/kysely-query-compiler.js.map +1 -0
- package/dist/adapters/kysely/kysely-query.js +158 -0
- package/dist/adapters/kysely/kysely-query.js.map +1 -0
- package/dist/adapters/kysely/kysely-uow-compiler.js +139 -0
- package/dist/adapters/kysely/kysely-uow-compiler.js.map +1 -0
- package/dist/adapters/kysely/kysely-uow-executor.js +89 -0
- package/dist/adapters/kysely/kysely-uow-executor.js.map +1 -0
- package/dist/adapters/kysely/migration/execute.js +176 -0
- package/dist/adapters/kysely/migration/execute.js.map +1 -0
- package/dist/fragment.d.ts +54 -0
- package/dist/fragment.d.ts.map +1 -0
- package/dist/fragment.js +92 -0
- package/dist/fragment.js.map +1 -0
- package/dist/id.d.ts +2 -0
- package/dist/migration-engine/auto-from-schema.js +116 -0
- package/dist/migration-engine/auto-from-schema.js.map +1 -0
- package/dist/migration-engine/create.d.ts +41 -0
- package/dist/migration-engine/create.d.ts.map +1 -0
- package/dist/migration-engine/create.js +58 -0
- package/dist/migration-engine/create.js.map +1 -0
- package/dist/migration-engine/shared.d.ts +90 -0
- package/dist/migration-engine/shared.d.ts.map +1 -0
- package/dist/migration-engine/shared.js +8 -0
- package/dist/migration-engine/shared.js.map +1 -0
- package/dist/mod.d.ts +55 -2
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +111 -2
- package/dist/mod.js.map +1 -1
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/column-builder.js +108 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/column-builder.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/column.js +55 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/column.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/entity.js +18 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/entity.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/columns/common.js +183 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/columns/common.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/columns/enum.js +58 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/columns/enum.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/foreign-keys.js +68 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/foreign-keys.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/unique-constraint.js +56 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/unique-constraint.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/utils/array.js +65 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/pg-core/utils/array.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/expressions/conditions.js +81 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/expressions/conditions.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/expressions/select.js +13 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/expressions/select.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/functions/aggregate.js +10 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/functions/aggregate.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/sql.js +372 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/sql/sql.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/subquery.js +23 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/subquery.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/table.js +62 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/table.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/table.utils.js +6 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/table.utils.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/tracing-utils.js +8 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/tracing-utils.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/tracing.js +8 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/tracing.js.map +1 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/view-common.js +6 -0
- package/dist/node_modules/.bun/drizzle-orm@0.44.6_4fae081eecb963e2/node_modules/drizzle-orm/view-common.js.map +1 -0
- package/dist/query/condition-builder.d.ts +41 -0
- package/dist/query/condition-builder.d.ts.map +1 -0
- package/dist/query/condition-builder.js +93 -0
- package/dist/query/condition-builder.js.map +1 -0
- package/dist/query/cursor.d.ts +88 -0
- package/dist/query/cursor.d.ts.map +1 -0
- package/dist/query/cursor.js +103 -0
- package/dist/query/cursor.js.map +1 -0
- package/dist/query/orm/orm.d.ts +18 -0
- package/dist/query/orm/orm.d.ts.map +1 -0
- package/dist/query/orm/orm.js +48 -0
- package/dist/query/orm/orm.js.map +1 -0
- package/dist/query/query.d.ts +79 -0
- package/dist/query/query.d.ts.map +1 -0
- package/dist/query/query.js +1 -0
- package/dist/query/result-transform.js +155 -0
- package/dist/query/result-transform.js.map +1 -0
- package/dist/query/unit-of-work.d.ts +435 -0
- package/dist/query/unit-of-work.d.ts.map +1 -0
- package/dist/query/unit-of-work.js +549 -0
- package/dist/query/unit-of-work.js.map +1 -0
- package/dist/schema/create.d.ts +273 -116
- package/dist/schema/create.d.ts.map +1 -1
- package/dist/schema/create.js +410 -222
- package/dist/schema/create.js.map +1 -1
- package/dist/schema/serialize.js +101 -0
- package/dist/schema/serialize.js.map +1 -0
- package/dist/schema-generator/schema-generator.d.ts +15 -0
- package/dist/schema-generator/schema-generator.d.ts.map +1 -0
- package/dist/shared/providers.d.ts +6 -0
- package/dist/shared/providers.d.ts.map +1 -0
- package/dist/util/import-generator.js +26 -0
- package/dist/util/import-generator.js.map +1 -0
- package/dist/util/parse.js +15 -0
- package/dist/util/parse.js.map +1 -0
- package/dist/util/types.d.ts +8 -0
- package/dist/util/types.d.ts.map +1 -0
- package/package.json +63 -2
- package/src/adapters/adapters.ts +22 -0
- package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +433 -0
- package/src/adapters/drizzle/drizzle-adapter.test.ts +122 -0
- package/src/adapters/drizzle/drizzle-adapter.ts +118 -0
- package/src/adapters/drizzle/drizzle-query.ts +234 -0
- package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +1084 -0
- package/src/adapters/drizzle/drizzle-uow-compiler.ts +546 -0
- package/src/adapters/drizzle/drizzle-uow-decoder.ts +165 -0
- package/src/adapters/drizzle/drizzle-uow-executor.ts +213 -0
- package/src/adapters/drizzle/generate.test.ts +643 -0
- package/src/adapters/drizzle/generate.ts +481 -0
- package/src/adapters/drizzle/join-column-utils.test.ts +79 -0
- package/src/adapters/drizzle/join-column-utils.ts +39 -0
- package/src/adapters/drizzle/migrate-drizzle.test.ts +226 -0
- package/src/adapters/drizzle/shared.ts +22 -0
- package/src/adapters/drizzle/test-utils.ts +56 -0
- package/src/adapters/kysely/kysely-adapter-pglite.test.ts +789 -0
- package/src/adapters/kysely/kysely-adapter.ts +196 -0
- package/src/adapters/kysely/kysely-query-builder.test.ts +1344 -0
- package/src/adapters/kysely/kysely-query-builder.ts +611 -0
- package/src/adapters/kysely/kysely-query-compiler.ts +124 -0
- package/src/adapters/kysely/kysely-query.ts +254 -0
- package/src/adapters/kysely/kysely-uow-compiler.test.ts +916 -0
- package/src/adapters/kysely/kysely-uow-compiler.ts +271 -0
- package/src/adapters/kysely/kysely-uow-executor.ts +149 -0
- package/src/adapters/kysely/kysely-uow-joins.test.ts +811 -0
- package/src/adapters/kysely/migration/execute-mysql.test.ts +1173 -0
- package/src/adapters/kysely/migration/execute-postgres.test.ts +2657 -0
- package/src/adapters/kysely/migration/execute.ts +382 -0
- package/src/adapters/kysely/migration/kysely-migrator.test.ts +197 -0
- package/src/fragment.test.ts +287 -0
- package/src/fragment.ts +198 -0
- package/src/migration-engine/auto-from-schema.test.ts +118 -58
- package/src/migration-engine/auto-from-schema.ts +103 -32
- package/src/migration-engine/create.test.ts +34 -46
- package/src/migration-engine/create.ts +41 -26
- package/src/migration-engine/shared.ts +26 -6
- package/src/mod.ts +197 -1
- package/src/query/condition-builder.test.ts +379 -0
- package/src/query/condition-builder.ts +294 -0
- package/src/query/cursor.test.ts +296 -0
- package/src/query/cursor.ts +147 -0
- package/src/query/orm/orm.ts +92 -0
- package/src/query/query-type.test.ts +429 -0
- package/src/query/query.ts +200 -0
- package/src/query/result-transform.test.ts +795 -0
- package/src/query/result-transform.ts +247 -0
- package/src/query/unit-of-work-types.test.ts +192 -0
- package/src/query/unit-of-work.test.ts +947 -0
- package/src/query/unit-of-work.ts +1199 -0
- package/src/schema/create.test.ts +653 -110
- package/src/schema/create.ts +708 -337
- package/src/schema/serialize.test.ts +559 -0
- package/src/schema/serialize.ts +359 -0
- package/src/schema-generator/schema-generator.ts +12 -0
- package/src/shared/config.ts +0 -8
- package/src/util/import-generator.ts +28 -0
- package/src/util/parse.ts +16 -0
- package/src/util/types.ts +4 -0
- package/tsconfig.json +1 -1
- package/tsdown.config.ts +11 -1
- package/vitest.config.ts +3 -0
- /package/dist/{cuid.js → id.js} +0 -0
- /package/src/{cuid.ts → id.ts} +0 -0
|
@@ -1,29 +1,43 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import {
|
|
1
|
+
import { describe, expect, expectTypeOf, it } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
column,
|
|
4
|
+
FragnoId,
|
|
5
|
+
FragnoReference,
|
|
6
|
+
idColumn,
|
|
7
|
+
referenceColumn,
|
|
8
|
+
schema,
|
|
9
|
+
SchemaBuilder,
|
|
10
|
+
} from "./create";
|
|
11
|
+
import type { RawColumnValues, TableToColumnValues, TableToInsertValues } from "../query/query";
|
|
3
12
|
|
|
4
13
|
describe("create", () => {
|
|
5
14
|
it("should create a table with columns using callback pattern", () => {
|
|
6
|
-
const
|
|
7
|
-
return t
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
15
|
+
const userSchema = schema((s) => {
|
|
16
|
+
return s.addTable("users", (t) => {
|
|
17
|
+
return t
|
|
18
|
+
.addColumn("id", idColumn())
|
|
19
|
+
.addColumn("name", column("string"))
|
|
20
|
+
.addColumn("email", column("string"))
|
|
21
|
+
.createIndex("unique_email", ["email"], { unique: true })
|
|
22
|
+
.addColumn("age", column("integer").nullable());
|
|
23
|
+
});
|
|
13
24
|
});
|
|
14
25
|
|
|
26
|
+
const userTable = userSchema.tables.users;
|
|
15
27
|
expect(userTable.columns.id).toBeDefined();
|
|
16
28
|
expect(userTable.columns.name).toBeDefined();
|
|
17
29
|
expect(userTable.columns.email).toBeDefined();
|
|
18
30
|
expect(userTable.columns.age).toBeDefined();
|
|
19
31
|
expect(userTable.columns.age.isNullable).toBe(true);
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
]);
|
|
32
|
+
|
|
33
|
+
// Verify the index was stored as a sub-operation
|
|
34
|
+
const addTableOps = userSchema.operations.filter((op) => op.type === "add-table");
|
|
35
|
+
expect(addTableOps).toHaveLength(1);
|
|
36
|
+
const indexOps = addTableOps[0].operations.filter((op) => op.type === "add-index");
|
|
37
|
+
expect(indexOps).toHaveLength(1);
|
|
38
|
+
expect(indexOps[0].name).toBe("unique_email");
|
|
39
|
+
expect(indexOps[0].columns).toEqual(["email"]);
|
|
40
|
+
expect(indexOps[0].unique).toBe(true);
|
|
27
41
|
});
|
|
28
42
|
|
|
29
43
|
it("should create a schema with multiple tables using callback pattern", () => {
|
|
@@ -48,13 +62,16 @@ describe("create", () => {
|
|
|
48
62
|
});
|
|
49
63
|
|
|
50
64
|
it("should generate default values for columns", () => {
|
|
51
|
-
const
|
|
52
|
-
return t
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
65
|
+
const testSchema = schema((s) => {
|
|
66
|
+
return s.addTable("test", (t) => {
|
|
67
|
+
return t
|
|
68
|
+
.addColumn("id", idColumn())
|
|
69
|
+
.addColumn("createdAt", column("timestamp").defaultTo$("now"))
|
|
70
|
+
.addColumn("status", column("string").defaultTo("active"));
|
|
71
|
+
});
|
|
56
72
|
});
|
|
57
73
|
|
|
74
|
+
const testTable = testSchema.tables.test;
|
|
58
75
|
const idValue = testTable.columns.id.generateDefaultValue();
|
|
59
76
|
expect(typeof idValue).toBe("string");
|
|
60
77
|
expect(idValue?.length).toBeGreaterThan(0);
|
|
@@ -66,7 +83,7 @@ describe("create", () => {
|
|
|
66
83
|
expect(statusValue).toBe("active");
|
|
67
84
|
});
|
|
68
85
|
|
|
69
|
-
it("should increment version on each
|
|
86
|
+
it("should increment schema version on each schema-level operation", () => {
|
|
70
87
|
const userSchema = schema((s) => {
|
|
71
88
|
return s
|
|
72
89
|
.addTable("users", (t) => {
|
|
@@ -84,41 +101,53 @@ describe("create", () => {
|
|
|
84
101
|
});
|
|
85
102
|
|
|
86
103
|
it("should support unique constraints on tables via unique method", () => {
|
|
87
|
-
const
|
|
88
|
-
return t
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
104
|
+
const userSchema = schema((s) => {
|
|
105
|
+
return s.addTable("users", (t) => {
|
|
106
|
+
return t
|
|
107
|
+
.addColumn("id", idColumn())
|
|
108
|
+
.addColumn("email", column("string"))
|
|
109
|
+
.addColumn("username", column("string"))
|
|
110
|
+
.createIndex("unique_email_username", ["email", "username"], { unique: true });
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Verify the unique index was stored as a sub-operation
|
|
115
|
+
const addTableOps = userSchema.operations.filter((op) => op.type === "add-table");
|
|
116
|
+
expect(addTableOps).toHaveLength(1);
|
|
117
|
+
const indexOps = addTableOps[0].operations.filter((op) => op.type === "add-index");
|
|
118
|
+
expect(indexOps).toHaveLength(1);
|
|
119
|
+
expect(indexOps[0].name).toBe("unique_email_username");
|
|
120
|
+
expect(indexOps[0].columns).toEqual(["email", "username"]);
|
|
121
|
+
expect(indexOps[0].unique).toBe(true);
|
|
99
122
|
});
|
|
100
123
|
|
|
101
124
|
it("should support creating indexes on tables", () => {
|
|
102
|
-
const
|
|
103
|
-
return t
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
expect(userTable.indexes).toHaveLength(2);
|
|
112
|
-
expect(userTable.indexes[0]).toEqual({
|
|
113
|
-
name: "idx_email",
|
|
114
|
-
columns: [userTable.columns.email],
|
|
115
|
-
unique: false,
|
|
116
|
-
});
|
|
117
|
-
expect(userTable.indexes[1]).toEqual({
|
|
118
|
-
name: "idx_username_unique",
|
|
119
|
-
columns: [userTable.columns.username],
|
|
120
|
-
unique: true,
|
|
125
|
+
const userSchema = schema((s) => {
|
|
126
|
+
return s.addTable("users", (t) => {
|
|
127
|
+
return t
|
|
128
|
+
.addColumn("id", idColumn())
|
|
129
|
+
.addColumn("email", column("string"))
|
|
130
|
+
.addColumn("username", column("string"))
|
|
131
|
+
.createIndex("idx_email", ["email"])
|
|
132
|
+
.createIndex("idx_username_unique", ["username"], { unique: true });
|
|
133
|
+
});
|
|
121
134
|
});
|
|
135
|
+
|
|
136
|
+
// Verify both indexes were stored as sub-operations
|
|
137
|
+
const addTableOps = userSchema.operations.filter((op) => op.type === "add-table");
|
|
138
|
+
expect(addTableOps).toHaveLength(1);
|
|
139
|
+
const indexOps = addTableOps[0].operations.filter((op) => op.type === "add-index");
|
|
140
|
+
expect(indexOps).toHaveLength(2);
|
|
141
|
+
|
|
142
|
+
const emailIndex = indexOps.find((op) => op.name === "idx_email");
|
|
143
|
+
expect(emailIndex).toBeDefined();
|
|
144
|
+
expect(emailIndex!.columns).toEqual(["email"]);
|
|
145
|
+
expect(emailIndex!.unique).toBe(false);
|
|
146
|
+
|
|
147
|
+
const usernameIndex = indexOps.find((op) => op.name === "idx_username_unique");
|
|
148
|
+
expect(usernameIndex).toBeDefined();
|
|
149
|
+
expect(usernameIndex!.columns).toEqual(["username"]);
|
|
150
|
+
expect(usernameIndex!.unique).toBe(true);
|
|
122
151
|
});
|
|
123
152
|
|
|
124
153
|
it("should demonstrate manual many-to-many relation setup", () => {
|
|
@@ -137,15 +166,15 @@ describe("create", () => {
|
|
|
137
166
|
.addColumn("userId", referenceColumn())
|
|
138
167
|
.addColumn("tagId", referenceColumn());
|
|
139
168
|
})
|
|
140
|
-
.addReference("
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
169
|
+
.addReference("user", {
|
|
170
|
+
type: "one",
|
|
171
|
+
from: { table: "user_tags", column: "userId" },
|
|
172
|
+
to: { table: "users", column: "id" },
|
|
144
173
|
})
|
|
145
|
-
.addReference("
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
174
|
+
.addReference("tag", {
|
|
175
|
+
type: "one",
|
|
176
|
+
from: { table: "user_tags", column: "tagId" },
|
|
177
|
+
to: { table: "tags", column: "id" },
|
|
149
178
|
});
|
|
150
179
|
});
|
|
151
180
|
|
|
@@ -155,10 +184,23 @@ describe("create", () => {
|
|
|
155
184
|
expect(junctionTable.relations["user"]).toBeDefined();
|
|
156
185
|
expect(junctionTable.relations["tag"]).toBeDefined();
|
|
157
186
|
|
|
158
|
-
// Verify both foreign keys were created
|
|
159
|
-
|
|
160
|
-
expect(
|
|
161
|
-
|
|
187
|
+
// Verify both foreign keys were created as operations
|
|
188
|
+
const addReferenceOps = userSchema.operations.filter((op) => op.type === "add-reference");
|
|
189
|
+
expect(addReferenceOps).toHaveLength(2);
|
|
190
|
+
|
|
191
|
+
const userRef = addReferenceOps.find((op) => op.referenceName === "user");
|
|
192
|
+
expect(userRef).toBeDefined();
|
|
193
|
+
expect(userRef!.tableName).toBe("user_tags");
|
|
194
|
+
expect(userRef!.config.type).toBe("one");
|
|
195
|
+
expect(userRef!.config.from).toEqual({ table: "user_tags", column: "userId" });
|
|
196
|
+
expect(userRef!.config.to).toEqual({ table: "users", column: "_internalId" });
|
|
197
|
+
|
|
198
|
+
const tagRef = addReferenceOps.find((op) => op.referenceName === "tag");
|
|
199
|
+
expect(tagRef).toBeDefined();
|
|
200
|
+
expect(tagRef!.tableName).toBe("user_tags");
|
|
201
|
+
expect(tagRef!.config.type).toBe("one");
|
|
202
|
+
expect(tagRef!.config.from).toEqual({ table: "user_tags", column: "tagId" });
|
|
203
|
+
expect(tagRef!.config.to).toEqual({ table: "tags", column: "_internalId" });
|
|
162
204
|
});
|
|
163
205
|
|
|
164
206
|
it("should create a foreign key reference using addReference", () => {
|
|
@@ -173,17 +215,17 @@ describe("create", () => {
|
|
|
173
215
|
.addColumn("title", column("string"))
|
|
174
216
|
.addColumn("authorId", referenceColumn());
|
|
175
217
|
})
|
|
176
|
-
.addReference("
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
218
|
+
.addReference("author", {
|
|
219
|
+
type: "one",
|
|
220
|
+
from: { table: "posts", column: "authorId" },
|
|
221
|
+
to: { table: "users", column: "id" },
|
|
180
222
|
});
|
|
181
223
|
});
|
|
182
224
|
|
|
183
225
|
const postsTable = userSchema.tables.posts;
|
|
184
226
|
|
|
185
227
|
// Verify the authorId column is marked as a reference
|
|
186
|
-
expect(postsTable.columns.authorId.
|
|
228
|
+
expect(postsTable.columns.authorId.role).toBe("reference");
|
|
187
229
|
|
|
188
230
|
// Verify the relation exists
|
|
189
231
|
const authorRelation = postsTable.relations["author"];
|
|
@@ -192,23 +234,14 @@ describe("create", () => {
|
|
|
192
234
|
expect(authorRelation.table).toBe(userSchema.tables.users);
|
|
193
235
|
expect(authorRelation.on).toEqual([["authorId", "id"]]);
|
|
194
236
|
|
|
195
|
-
// Verify the foreign key was created
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
expect(
|
|
199
|
-
expect(
|
|
200
|
-
expect(
|
|
201
|
-
expect(
|
|
202
|
-
|
|
203
|
-
// Verify the compiled foreign key format
|
|
204
|
-
const compiledFk = compileForeignKey(fk);
|
|
205
|
-
expect(compiledFk).toEqual({
|
|
206
|
-
name: "posts_users_author_fk",
|
|
207
|
-
table: "posts",
|
|
208
|
-
referencedTable: "users",
|
|
209
|
-
columns: ["authorId"],
|
|
210
|
-
referencedColumns: ["id"],
|
|
211
|
-
});
|
|
237
|
+
// Verify the foreign key was created as an operation
|
|
238
|
+
const addReferenceOps = userSchema.operations.filter((op) => op.type === "add-reference");
|
|
239
|
+
expect(addReferenceOps).toHaveLength(1);
|
|
240
|
+
expect(addReferenceOps[0].tableName).toBe("posts");
|
|
241
|
+
expect(addReferenceOps[0].referenceName).toBe("author");
|
|
242
|
+
expect(addReferenceOps[0].config.type).toBe("one");
|
|
243
|
+
expect(addReferenceOps[0].config.from).toEqual({ table: "posts", column: "authorId" });
|
|
244
|
+
expect(addReferenceOps[0].config.to).toEqual({ table: "users", column: "_internalId" });
|
|
212
245
|
});
|
|
213
246
|
|
|
214
247
|
it("should support multiple references by calling addReference multiple times", () => {
|
|
@@ -227,15 +260,15 @@ describe("create", () => {
|
|
|
227
260
|
.addColumn("authorId", referenceColumn())
|
|
228
261
|
.addColumn("categoryId", referenceColumn());
|
|
229
262
|
})
|
|
230
|
-
.addReference("
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
263
|
+
.addReference("author", {
|
|
264
|
+
type: "one",
|
|
265
|
+
from: { table: "posts", column: "authorId" },
|
|
266
|
+
to: { table: "users", column: "id" },
|
|
234
267
|
})
|
|
235
|
-
.addReference("
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
268
|
+
.addReference("category", {
|
|
269
|
+
type: "one",
|
|
270
|
+
from: { table: "posts", column: "categoryId" },
|
|
271
|
+
to: { table: "categories", column: "id" },
|
|
239
272
|
});
|
|
240
273
|
});
|
|
241
274
|
|
|
@@ -245,10 +278,23 @@ describe("create", () => {
|
|
|
245
278
|
expect(postsTable.relations["author"]).toBeDefined();
|
|
246
279
|
expect(postsTable.relations["category"]).toBeDefined();
|
|
247
280
|
|
|
248
|
-
// Verify both foreign keys were created
|
|
249
|
-
|
|
250
|
-
expect(
|
|
251
|
-
|
|
281
|
+
// Verify both foreign keys were created as operations
|
|
282
|
+
const addReferenceOps = userSchema.operations.filter((op) => op.type === "add-reference");
|
|
283
|
+
expect(addReferenceOps).toHaveLength(2);
|
|
284
|
+
|
|
285
|
+
const authorRef = addReferenceOps.find((op) => op.referenceName === "author");
|
|
286
|
+
expect(authorRef).toBeDefined();
|
|
287
|
+
expect(authorRef!.tableName).toBe("posts");
|
|
288
|
+
expect(authorRef!.config.type).toBe("one");
|
|
289
|
+
expect(authorRef!.config.from).toEqual({ table: "posts", column: "authorId" });
|
|
290
|
+
expect(authorRef!.config.to).toEqual({ table: "users", column: "_internalId" });
|
|
291
|
+
|
|
292
|
+
const categoryRef = addReferenceOps.find((op) => op.referenceName === "category");
|
|
293
|
+
expect(categoryRef).toBeDefined();
|
|
294
|
+
expect(categoryRef!.tableName).toBe("posts");
|
|
295
|
+
expect(categoryRef!.config.type).toBe("one");
|
|
296
|
+
expect(categoryRef!.config.from).toEqual({ table: "posts", column: "categoryId" });
|
|
297
|
+
expect(categoryRef!.config.to).toEqual({ table: "categories", column: "_internalId" });
|
|
252
298
|
});
|
|
253
299
|
|
|
254
300
|
it("should support self-referencing foreign keys", () => {
|
|
@@ -260,10 +306,10 @@ describe("create", () => {
|
|
|
260
306
|
.addColumn("name", column("string"))
|
|
261
307
|
.addColumn("invitedBy", referenceColumn().nullable());
|
|
262
308
|
})
|
|
263
|
-
.addReference("
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
309
|
+
.addReference("inviter", {
|
|
310
|
+
type: "one",
|
|
311
|
+
from: { table: "users", column: "invitedBy" },
|
|
312
|
+
to: { table: "users", column: "id" },
|
|
267
313
|
});
|
|
268
314
|
});
|
|
269
315
|
|
|
@@ -276,12 +322,509 @@ describe("create", () => {
|
|
|
276
322
|
expect(inviterRelation.table).toBe(usersTable);
|
|
277
323
|
expect(inviterRelation.on).toEqual([["invitedBy", "id"]]);
|
|
278
324
|
|
|
279
|
-
// Verify the foreign key was created
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
expect(
|
|
283
|
-
expect(
|
|
284
|
-
expect(
|
|
285
|
-
expect(
|
|
325
|
+
// Verify the foreign key was created as an operation
|
|
326
|
+
const addReferenceOps = userSchema.operations.filter((op) => op.type === "add-reference");
|
|
327
|
+
expect(addReferenceOps).toHaveLength(1);
|
|
328
|
+
expect(addReferenceOps[0].tableName).toBe("users");
|
|
329
|
+
expect(addReferenceOps[0].referenceName).toBe("inviter");
|
|
330
|
+
expect(addReferenceOps[0].config.type).toBe("one");
|
|
331
|
+
expect(addReferenceOps[0].config.from).toEqual({ table: "users", column: "invitedBy" });
|
|
332
|
+
expect(addReferenceOps[0].config.to).toEqual({ table: "users", column: "_internalId" });
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it("should allow altering an existing table to add columns", () => {
|
|
336
|
+
const userSchema = schema((s) => {
|
|
337
|
+
return s
|
|
338
|
+
.addTable("users", (t) => {
|
|
339
|
+
return t.addColumn("id", idColumn()).addColumn("name", column("string"));
|
|
340
|
+
})
|
|
341
|
+
.alterTable("users", (t) => {
|
|
342
|
+
return t
|
|
343
|
+
.addColumn("email", column("string"))
|
|
344
|
+
.addColumn("age", column("integer").nullable());
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
const usersTable = userSchema.tables.users;
|
|
349
|
+
|
|
350
|
+
// Verify the original columns exist
|
|
351
|
+
expect(usersTable.columns.id).toBeDefined();
|
|
352
|
+
expect(usersTable.columns.name).toBeDefined();
|
|
353
|
+
|
|
354
|
+
// Verify the new columns were added
|
|
355
|
+
expect(usersTable.columns.email).toBeDefined();
|
|
356
|
+
expect(usersTable.columns.age).toBeDefined();
|
|
357
|
+
expect(usersTable.columns.age.isNullable).toBe(true);
|
|
358
|
+
|
|
359
|
+
// Verify the operations were recorded
|
|
360
|
+
const alterTableOps = userSchema.operations.filter((op) => op.type === "alter-table");
|
|
361
|
+
expect(alterTableOps).toHaveLength(1);
|
|
362
|
+
expect(alterTableOps[0].operations).toHaveLength(2);
|
|
363
|
+
expect(alterTableOps[0].operations[0].type).toBe("add-column");
|
|
364
|
+
expect(alterTableOps[0].operations[1].type).toBe("add-column");
|
|
365
|
+
if (alterTableOps[0].operations[0].type === "add-column") {
|
|
366
|
+
expect(alterTableOps[0].operations[0].columnName).toBe("email");
|
|
367
|
+
}
|
|
368
|
+
if (alterTableOps[0].operations[1].type === "add-column") {
|
|
369
|
+
expect(alterTableOps[0].operations[1].columnName).toBe("age");
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Version should be: 1 (addTable) + 1 (alter-table with 2 columns)
|
|
373
|
+
expect(userSchema.version).toBe(2);
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
it("should allow altering an existing table to add indexes", () => {
|
|
377
|
+
const userSchema = schema((s) => {
|
|
378
|
+
return s
|
|
379
|
+
.addTable("users", (t) => {
|
|
380
|
+
return t
|
|
381
|
+
.addColumn("id", idColumn())
|
|
382
|
+
.addColumn("name", column("string"))
|
|
383
|
+
.addColumn("email", column("string"));
|
|
384
|
+
})
|
|
385
|
+
.alterTable("users", (t) => {
|
|
386
|
+
return t
|
|
387
|
+
.createIndex("idx_email", ["email"])
|
|
388
|
+
.createIndex("idx_name_unique", ["name"], { unique: true });
|
|
389
|
+
});
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
const alterTableOps = userSchema.operations.filter((op) => op.type === "alter-table");
|
|
393
|
+
expect(alterTableOps).toHaveLength(1);
|
|
394
|
+
const indexOps = alterTableOps[0].operations.filter((op) => op.type === "add-index");
|
|
395
|
+
expect(indexOps).toHaveLength(2);
|
|
396
|
+
|
|
397
|
+
// Version should be: 1 (addTable) + 1 (alter-table with indexes as sub-operations)
|
|
398
|
+
expect(userSchema.version).toBe(2);
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
it("should allow multiple alterTable calls on the same table", () => {
|
|
402
|
+
const userSchema = schema((s) => {
|
|
403
|
+
return s
|
|
404
|
+
.addTable("users", (t) => {
|
|
405
|
+
return t.addColumn("id", idColumn()).addColumn("name", column("string"));
|
|
406
|
+
})
|
|
407
|
+
.alterTable("users", (t) => {
|
|
408
|
+
return t.addColumn("email", column("string"));
|
|
409
|
+
})
|
|
410
|
+
.alterTable("users", (t) => {
|
|
411
|
+
return t.addColumn("age", column("integer").nullable());
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
const usersTable = userSchema.tables.users;
|
|
416
|
+
const columns = usersTable.columns;
|
|
417
|
+
|
|
418
|
+
expectTypeOf(columns.id.$in).toExtend<string | FragnoId | null>();
|
|
419
|
+
expectTypeOf(columns.id.$out).toEqualTypeOf<FragnoId>();
|
|
420
|
+
|
|
421
|
+
expectTypeOf(columns.name.$in).toBeString();
|
|
422
|
+
expectTypeOf(columns.name.$out).toBeString();
|
|
423
|
+
|
|
424
|
+
expectTypeOf(columns.email.$in).toBeString();
|
|
425
|
+
expectTypeOf(columns.email.$out).toBeString();
|
|
426
|
+
|
|
427
|
+
expectTypeOf(columns.age.$in).toExtend<number | null>();
|
|
428
|
+
expectTypeOf(columns.age.$out).toExtend<number | null>();
|
|
429
|
+
|
|
430
|
+
// Verify all columns exist
|
|
431
|
+
expect(usersTable.columns.id).toBeDefined();
|
|
432
|
+
expect(usersTable.columns.name).toBeDefined();
|
|
433
|
+
expect(usersTable.columns.email).toBeDefined();
|
|
434
|
+
expect(usersTable.columns.age).toBeDefined();
|
|
435
|
+
|
|
436
|
+
// Version should be: 1 (addTable) + 1 (first alter) + 1 (second alter)
|
|
437
|
+
expect(userSchema.version).toBe(3);
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
it("should preserve indexes when altering a table", () => {
|
|
441
|
+
const userSchema = schema((s) => {
|
|
442
|
+
return s
|
|
443
|
+
.addTable("users", (t) => {
|
|
444
|
+
return t
|
|
445
|
+
.addColumn("id", idColumn())
|
|
446
|
+
.addColumn("name", column("string"))
|
|
447
|
+
.addColumn("email", column("string"))
|
|
448
|
+
.createIndex("idx_email", ["email"])
|
|
449
|
+
.createIndex("idx_name_unique", ["name"], { unique: true });
|
|
450
|
+
})
|
|
451
|
+
.alterTable("users", (t) => {
|
|
452
|
+
return t.addColumn("age", column("integer").nullable());
|
|
453
|
+
});
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
const usersTable = userSchema.tables.users;
|
|
457
|
+
|
|
458
|
+
// Verify the new column was added
|
|
459
|
+
expect(usersTable.columns.age).toBeDefined();
|
|
460
|
+
|
|
461
|
+
// Verify the original indexes are still present in the table
|
|
462
|
+
expect(usersTable.indexes["idx_email"]).toBeDefined();
|
|
463
|
+
expect(usersTable.indexes["idx_email"].columnNames).toEqual(["email"]);
|
|
464
|
+
expect(usersTable.indexes["idx_email"].unique).toBe(false);
|
|
465
|
+
|
|
466
|
+
expect(usersTable.indexes["idx_name_unique"]).toBeDefined();
|
|
467
|
+
expect(usersTable.indexes["idx_name_unique"].columnNames).toEqual(["name"]);
|
|
468
|
+
expect(usersTable.indexes["idx_name_unique"].unique).toBe(true);
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
it("should not duplicate existing indexes when altering a table", () => {
|
|
472
|
+
const userSchema = schema((s) => {
|
|
473
|
+
return s
|
|
474
|
+
.addTable("users", (t) => {
|
|
475
|
+
return t
|
|
476
|
+
.addColumn("id", idColumn())
|
|
477
|
+
.addColumn("name", column("string"))
|
|
478
|
+
.addColumn("email", column("string"))
|
|
479
|
+
.createIndex("idx_email", ["email"])
|
|
480
|
+
.createIndex("idx_name_unique", ["name"], { unique: true });
|
|
481
|
+
})
|
|
482
|
+
.alterTable("users", (t) => {
|
|
483
|
+
return t.addColumn("age", column("integer").nullable());
|
|
484
|
+
});
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
// Verify the add-table operation contains both indexes
|
|
488
|
+
const addTableOps = userSchema.operations.filter((op) => op.type === "add-table");
|
|
489
|
+
expect(addTableOps).toHaveLength(1);
|
|
490
|
+
const addTableIndexOps = addTableOps[0].operations.filter((op) => op.type === "add-index");
|
|
491
|
+
expect(addTableIndexOps).toHaveLength(2);
|
|
492
|
+
|
|
493
|
+
// Verify the alter-table operation does NOT contain the existing indexes
|
|
494
|
+
const alterTableOps = userSchema.operations.filter((op) => op.type === "alter-table");
|
|
495
|
+
expect(alterTableOps).toHaveLength(1);
|
|
496
|
+
const alterTableIndexOps = alterTableOps[0].operations.filter((op) => op.type === "add-index");
|
|
497
|
+
expect(alterTableIndexOps).toHaveLength(0); // Should be 0, not 2
|
|
498
|
+
|
|
499
|
+
// The alter-table should only have the new column
|
|
500
|
+
const alterTableColumnOps = alterTableOps[0].operations.filter(
|
|
501
|
+
(op) => op.type === "add-column",
|
|
502
|
+
);
|
|
503
|
+
expect(alterTableColumnOps).toHaveLength(1);
|
|
504
|
+
if (alterTableColumnOps[0].type === "add-column") {
|
|
505
|
+
expect(alterTableColumnOps[0].columnName).toBe("age");
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
it("should only add new indexes when altering a table with additional indexes", () => {
|
|
510
|
+
const userSchema = schema((s) => {
|
|
511
|
+
return s
|
|
512
|
+
.addTable("users", (t) => {
|
|
513
|
+
return t
|
|
514
|
+
.addColumn("id", idColumn())
|
|
515
|
+
.addColumn("name", column("string"))
|
|
516
|
+
.addColumn("email", column("string"))
|
|
517
|
+
.createIndex("idx_email", ["email"]);
|
|
518
|
+
})
|
|
519
|
+
.alterTable("users", (t) => {
|
|
520
|
+
return t
|
|
521
|
+
.addColumn("age", column("integer").nullable())
|
|
522
|
+
.createIndex("idx_name", ["name"]) // New index
|
|
523
|
+
.createIndex("idx_age", ["age"]); // New index on new column
|
|
524
|
+
});
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
// Verify the add-table operation contains only the original index
|
|
528
|
+
const addTableOps = userSchema.operations.filter((op) => op.type === "add-table");
|
|
529
|
+
expect(addTableOps).toHaveLength(1);
|
|
530
|
+
const addTableIndexOps = addTableOps[0].operations.filter((op) => op.type === "add-index");
|
|
531
|
+
expect(addTableIndexOps).toHaveLength(1);
|
|
532
|
+
expect(addTableIndexOps[0].name).toBe("idx_email");
|
|
533
|
+
|
|
534
|
+
// Verify the alter-table operation contains only the NEW indexes
|
|
535
|
+
const alterTableOps = userSchema.operations.filter((op) => op.type === "alter-table");
|
|
536
|
+
expect(alterTableOps).toHaveLength(1);
|
|
537
|
+
const alterTableIndexOps = alterTableOps[0].operations.filter((op) => op.type === "add-index");
|
|
538
|
+
expect(alterTableIndexOps).toHaveLength(2); // Only the two new indexes
|
|
539
|
+
|
|
540
|
+
const indexNames = alterTableIndexOps.map((op) => op.name);
|
|
541
|
+
expect(indexNames).toContain("idx_name");
|
|
542
|
+
expect(indexNames).toContain("idx_age");
|
|
543
|
+
expect(indexNames).not.toContain("idx_email"); // Should not duplicate the original index
|
|
544
|
+
|
|
545
|
+
// Verify all three indexes are present in the final table structure
|
|
546
|
+
const usersTable = userSchema.tables.users;
|
|
547
|
+
expect(Object.keys(usersTable.indexes)).toHaveLength(3);
|
|
548
|
+
expect(usersTable.indexes["idx_email"]).toBeDefined();
|
|
549
|
+
expect(usersTable.indexes["idx_name"]).toBeDefined();
|
|
550
|
+
expect(usersTable.indexes["idx_age"]).toBeDefined();
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
it("Simple user table types", () => {
|
|
554
|
+
const _userSchema = schema((s) => {
|
|
555
|
+
return s.addTable("users", (t) => {
|
|
556
|
+
return t.addColumn("id", idColumn()).addColumn("name", column("string"));
|
|
557
|
+
});
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
type _UserInsert = TableToInsertValues<typeof _userSchema.tables.users>;
|
|
561
|
+
expectTypeOf<_UserInsert>().toExtend<{
|
|
562
|
+
[x: string]: unknown;
|
|
563
|
+
id?: string | FragnoId | null;
|
|
564
|
+
name: string;
|
|
565
|
+
}>();
|
|
566
|
+
|
|
567
|
+
type _UserResult = TableToColumnValues<typeof _userSchema.tables.users>;
|
|
568
|
+
expectTypeOf<_UserResult>().toExtend<{
|
|
569
|
+
id: FragnoId;
|
|
570
|
+
name: string;
|
|
571
|
+
}>();
|
|
572
|
+
|
|
573
|
+
type _RawUser = RawColumnValues<typeof _userSchema.tables.users>;
|
|
574
|
+
expectTypeOf<_RawUser>().toEqualTypeOf<{
|
|
575
|
+
id: FragnoId;
|
|
576
|
+
name: string;
|
|
577
|
+
}>();
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
it("Simple user table types after alter table statements", () => {
|
|
581
|
+
const _userSchema = schema((s) => {
|
|
582
|
+
return s
|
|
583
|
+
.addTable("users", (t) => {
|
|
584
|
+
return t.addColumn("id", idColumn()).addColumn("name", column("string"));
|
|
585
|
+
})
|
|
586
|
+
.addTable("emails", (t) => {
|
|
587
|
+
return t.addColumn("id", idColumn()).addColumn("email", column("string"));
|
|
588
|
+
})
|
|
589
|
+
.alterTable("emails", (t) => {
|
|
590
|
+
return t.addColumn("is_primary", column("bool").defaultTo(false));
|
|
591
|
+
});
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
type _UserInsert = TableToInsertValues<typeof _userSchema.tables.users>;
|
|
595
|
+
expectTypeOf<_UserInsert>().toEqualTypeOf<{
|
|
596
|
+
id?: string | FragnoId | null | undefined;
|
|
597
|
+
name: string;
|
|
598
|
+
}>();
|
|
599
|
+
|
|
600
|
+
type _UserResult = TableToColumnValues<typeof _userSchema.tables.users>;
|
|
601
|
+
expectTypeOf<_UserResult>().toEqualTypeOf<{
|
|
602
|
+
id: FragnoId;
|
|
603
|
+
name: string;
|
|
604
|
+
}>();
|
|
605
|
+
});
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
describe("idColumn", () => {
|
|
609
|
+
it("should create a table with an id column", () => {
|
|
610
|
+
const idCol = idColumn();
|
|
611
|
+
type _In = typeof idCol.$in;
|
|
612
|
+
type _Out = typeof idCol.$out;
|
|
613
|
+
expectTypeOf<_In>().toEqualTypeOf<string | FragnoId | null>();
|
|
614
|
+
expectTypeOf<_Out>().toEqualTypeOf<FragnoId>();
|
|
615
|
+
|
|
616
|
+
expect(idCol.generateDefaultValue()).toBeDefined();
|
|
617
|
+
});
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
describe("referenceColumn", () => {
|
|
621
|
+
it("should create a table with a reference column", () => {
|
|
622
|
+
const _referenceCol = referenceColumn();
|
|
623
|
+
type _In = typeof _referenceCol.$in;
|
|
624
|
+
type _Out = typeof _referenceCol.$out;
|
|
625
|
+
expectTypeOf<_In>().toEqualTypeOf<string | bigint | FragnoId | FragnoReference>();
|
|
626
|
+
expectTypeOf<_Out>().toEqualTypeOf<FragnoReference>();
|
|
627
|
+
});
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
describe("SchemaBuilder with existing schema", () => {
|
|
631
|
+
it("should initialize with an existing schema", () => {
|
|
632
|
+
const existingSchema = schema((s) => {
|
|
633
|
+
return s.addTable("users", (t) => {
|
|
634
|
+
return t.addColumn("id", idColumn()).addColumn("name", column("string"));
|
|
635
|
+
});
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
const extendedSchema = new SchemaBuilder(existingSchema)
|
|
639
|
+
.addTable("posts", (t) => {
|
|
640
|
+
return t.addColumn("id", idColumn()).addColumn("title", column("string"));
|
|
641
|
+
})
|
|
642
|
+
.build();
|
|
643
|
+
|
|
644
|
+
expect(extendedSchema.tables.users).toBeDefined();
|
|
645
|
+
expect(extendedSchema.tables.posts).toBeDefined();
|
|
646
|
+
expect(extendedSchema.version).toBe(2); // 1 from original + 1 from new table
|
|
647
|
+
expect(extendedSchema.operations).toHaveLength(2);
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
it("should preserve operations from existing schema", () => {
|
|
651
|
+
const existingSchema = schema((s) => {
|
|
652
|
+
return s
|
|
653
|
+
.addTable("users", (t) => {
|
|
654
|
+
return t.addColumn("id", idColumn()).addColumn("name", column("string"));
|
|
655
|
+
})
|
|
656
|
+
.addTable("posts", (t) => {
|
|
657
|
+
return t.addColumn("id", idColumn()).addColumn("title", column("string"));
|
|
658
|
+
});
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
const extendedSchema = new SchemaBuilder(existingSchema)
|
|
662
|
+
.addTable("comments", (t) => {
|
|
663
|
+
return t.addColumn("id", idColumn()).addColumn("text", column("string"));
|
|
664
|
+
})
|
|
665
|
+
.build();
|
|
666
|
+
|
|
667
|
+
expect(extendedSchema.operations).toHaveLength(3);
|
|
668
|
+
expect(extendedSchema.operations[0].type).toBe("add-table");
|
|
669
|
+
expect(extendedSchema.operations[0].tableName).toBe("users");
|
|
670
|
+
expect(extendedSchema.operations[1].type).toBe("add-table");
|
|
671
|
+
expect(extendedSchema.operations[1].tableName).toBe("posts");
|
|
672
|
+
expect(extendedSchema.operations[2].type).toBe("add-table");
|
|
673
|
+
expect(extendedSchema.operations[2].tableName).toBe("comments");
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
it("should merge multiple schemas using mergeWithExistingSchema", () => {
|
|
677
|
+
const schema1 = schema((s) => {
|
|
678
|
+
return s.addTable("users", (t) => {
|
|
679
|
+
return t.addColumn("id", idColumn()).addColumn("name", column("string"));
|
|
680
|
+
});
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
const schema2 = schema((s) => {
|
|
684
|
+
return s.addTable("posts", (t) => {
|
|
685
|
+
return t.addColumn("id", idColumn()).addColumn("title", column("string"));
|
|
686
|
+
});
|
|
687
|
+
});
|
|
688
|
+
|
|
689
|
+
const mergedSchema = new SchemaBuilder()
|
|
690
|
+
.mergeWithExistingSchema(schema1)
|
|
691
|
+
.mergeWithExistingSchema(schema2)
|
|
692
|
+
.build();
|
|
693
|
+
|
|
694
|
+
expect(mergedSchema.tables.users).toBeDefined();
|
|
695
|
+
expect(mergedSchema.tables.posts).toBeDefined();
|
|
696
|
+
expect(mergedSchema.version).toBe(2); // 1 from schema1 + 1 from schema2
|
|
697
|
+
expect(mergedSchema.operations).toHaveLength(2);
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
it("should extend merged schema with new tables", () => {
|
|
701
|
+
const schema1 = schema((s) => {
|
|
702
|
+
return s.addTable("users", (t) => {
|
|
703
|
+
return t.addColumn("id", idColumn()).addColumn("name", column("string"));
|
|
704
|
+
});
|
|
705
|
+
});
|
|
706
|
+
|
|
707
|
+
const schema2 = schema((s) => {
|
|
708
|
+
return s.addTable("posts", (t) => {
|
|
709
|
+
return t.addColumn("id", idColumn()).addColumn("title", column("string"));
|
|
710
|
+
});
|
|
711
|
+
});
|
|
712
|
+
|
|
713
|
+
const extended = new SchemaBuilder()
|
|
714
|
+
.mergeWithExistingSchema(schema1)
|
|
715
|
+
.mergeWithExistingSchema(schema2)
|
|
716
|
+
.addTable("comments", (t) => {
|
|
717
|
+
return t.addColumn("id", idColumn()).addColumn("text", column("string"));
|
|
718
|
+
})
|
|
719
|
+
.build();
|
|
720
|
+
|
|
721
|
+
expect(extended.tables.users).toBeDefined();
|
|
722
|
+
expect(extended.tables.posts).toBeDefined();
|
|
723
|
+
expect(extended.tables.comments).toBeDefined();
|
|
724
|
+
expect(extended.version).toBe(3); // 2 from merged + 1 from new table
|
|
725
|
+
expect(extended.operations).toHaveLength(3);
|
|
726
|
+
});
|
|
727
|
+
|
|
728
|
+
it("should use mergeWithExistingSchema method to merge schemas", () => {
|
|
729
|
+
const schema1 = schema((s) => {
|
|
730
|
+
return s.addTable("users", (t) => {
|
|
731
|
+
return t.addColumn("id", idColumn()).addColumn("name", column("string"));
|
|
732
|
+
});
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
const schema2 = schema((s) => {
|
|
736
|
+
return s.addTable("posts", (t) => {
|
|
737
|
+
return t.addColumn("id", idColumn()).addColumn("title", column("string"));
|
|
738
|
+
});
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
const combined = new SchemaBuilder()
|
|
742
|
+
.mergeWithExistingSchema(schema1)
|
|
743
|
+
.mergeWithExistingSchema(schema2)
|
|
744
|
+
.addTable("comments", (t) => {
|
|
745
|
+
return t.addColumn("id", idColumn()).addColumn("text", column("string"));
|
|
746
|
+
})
|
|
747
|
+
.build();
|
|
748
|
+
|
|
749
|
+
expect(combined.tables.users).toBeDefined();
|
|
750
|
+
expect(combined.tables.posts).toBeDefined();
|
|
751
|
+
expect(combined.tables.comments).toBeDefined();
|
|
752
|
+
expect(combined.version).toBe(3); // 1 + 1 + 1
|
|
753
|
+
expect(combined.operations).toHaveLength(3);
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
it("should merge operations from multiple schemas in order", () => {
|
|
757
|
+
const schema1 = schema((s) => {
|
|
758
|
+
return s.addTable("users", (t) => {
|
|
759
|
+
return t.addColumn("id", idColumn()).addColumn("name", column("string"));
|
|
760
|
+
});
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
const schema2 = schema((s) => {
|
|
764
|
+
return s
|
|
765
|
+
.addTable("posts", (t) => {
|
|
766
|
+
return t.addColumn("id", idColumn()).addColumn("title", column("string"));
|
|
767
|
+
})
|
|
768
|
+
.addTable("categories", (t) => {
|
|
769
|
+
return t.addColumn("id", idColumn()).addColumn("name", column("string"));
|
|
770
|
+
});
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
const mergedSchema = new SchemaBuilder()
|
|
774
|
+
.mergeWithExistingSchema(schema1)
|
|
775
|
+
.mergeWithExistingSchema(schema2)
|
|
776
|
+
.build();
|
|
777
|
+
|
|
778
|
+
expect(mergedSchema.operations).toHaveLength(3);
|
|
779
|
+
expect(mergedSchema.operations[0].tableName).toBe("users");
|
|
780
|
+
expect(mergedSchema.operations[1].tableName).toBe("posts");
|
|
781
|
+
expect(mergedSchema.operations[2].tableName).toBe("categories");
|
|
782
|
+
expect(mergedSchema.version).toBe(3); // 1 from schema1 + 2 from schema2
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
it("should merge three or more schemas", () => {
|
|
786
|
+
const schema1 = schema((s) => {
|
|
787
|
+
return s.addTable("users", (t) => {
|
|
788
|
+
return t.addColumn("id", idColumn()).addColumn("name", column("string"));
|
|
789
|
+
});
|
|
790
|
+
});
|
|
791
|
+
|
|
792
|
+
const schema2 = schema((s) => {
|
|
793
|
+
return s.addTable("posts", (t) => {
|
|
794
|
+
return t.addColumn("id", idColumn()).addColumn("title", column("string"));
|
|
795
|
+
});
|
|
796
|
+
});
|
|
797
|
+
|
|
798
|
+
const schema3 = schema((s) => {
|
|
799
|
+
return s.addTable("comments", (t) => {
|
|
800
|
+
return t.addColumn("id", idColumn()).addColumn("text", column("string"));
|
|
801
|
+
});
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
const mergedSchema = new SchemaBuilder()
|
|
805
|
+
.mergeWithExistingSchema(schema1)
|
|
806
|
+
.mergeWithExistingSchema(schema2)
|
|
807
|
+
.mergeWithExistingSchema(schema3)
|
|
808
|
+
.build();
|
|
809
|
+
|
|
810
|
+
expect(mergedSchema.tables.users).toBeDefined();
|
|
811
|
+
expect(mergedSchema.tables.posts).toBeDefined();
|
|
812
|
+
expect(mergedSchema.tables.comments).toBeDefined();
|
|
813
|
+
expect(mergedSchema.version).toBe(3);
|
|
814
|
+
expect(mergedSchema.operations).toHaveLength(3);
|
|
815
|
+
});
|
|
816
|
+
|
|
817
|
+
it("should handle single schema merge", () => {
|
|
818
|
+
const schema1 = schema((s) => {
|
|
819
|
+
return s.addTable("users", (t) => {
|
|
820
|
+
return t.addColumn("id", idColumn()).addColumn("name", column("string"));
|
|
821
|
+
});
|
|
822
|
+
});
|
|
823
|
+
|
|
824
|
+
const mergedSchema = new SchemaBuilder().mergeWithExistingSchema(schema1).build();
|
|
825
|
+
|
|
826
|
+
expect(mergedSchema.tables.users).toBeDefined();
|
|
827
|
+
expect(mergedSchema.version).toBe(1);
|
|
828
|
+
expect(mergedSchema.operations).toHaveLength(1);
|
|
286
829
|
});
|
|
287
830
|
});
|