@fragno-dev/db 0.1.1 → 0.1.2
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 +61 -53
- package/CHANGELOG.md +12 -0
- package/dist/adapters/adapters.d.ts +11 -1
- package/dist/adapters/adapters.d.ts.map +1 -1
- package/dist/adapters/drizzle/drizzle-adapter.d.ts +9 -2
- package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -1
- package/dist/adapters/drizzle/drizzle-adapter.js +21 -39
- package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-query.d.ts.map +1 -1
- package/dist/adapters/drizzle/drizzle-query.js +3 -2
- package/dist/adapters/drizzle/drizzle-query.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.js +8 -6
- package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-executor.js.map +1 -1
- package/dist/adapters/drizzle/generate.js +107 -34
- package/dist/adapters/drizzle/generate.js.map +1 -1
- package/dist/adapters/drizzle/shared.js +14 -1
- package/dist/adapters/drizzle/shared.js.map +1 -1
- package/dist/adapters/kysely/kysely-adapter.d.ts +2 -1
- package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -1
- package/dist/adapters/kysely/kysely-adapter.js +25 -30
- package/dist/adapters/kysely/kysely-adapter.js.map +1 -1
- package/dist/adapters/kysely/kysely-query-builder.js +48 -44
- package/dist/adapters/kysely/kysely-query-builder.js.map +1 -1
- package/dist/adapters/kysely/kysely-query-compiler.js +2 -2
- package/dist/adapters/kysely/kysely-query-compiler.js.map +1 -1
- package/dist/adapters/kysely/kysely-query.js +3 -2
- package/dist/adapters/kysely/kysely-query.js.map +1 -1
- package/dist/adapters/kysely/kysely-shared.js +18 -0
- package/dist/adapters/kysely/kysely-shared.js.map +1 -0
- package/dist/adapters/kysely/kysely-uow-compiler.js +4 -3
- package/dist/adapters/kysely/kysely-uow-compiler.js.map +1 -1
- package/dist/adapters/kysely/migration/execute.js +15 -12
- package/dist/adapters/kysely/migration/execute.js.map +1 -1
- package/dist/migration-engine/auto-from-schema.js +2 -8
- package/dist/migration-engine/auto-from-schema.js.map +1 -1
- package/dist/migration-engine/create.d.ts +1 -5
- package/dist/migration-engine/create.js +1 -1
- package/dist/migration-engine/create.js.map +1 -1
- package/dist/migration-engine/generation-engine.d.ts +51 -0
- package/dist/migration-engine/generation-engine.d.ts.map +1 -0
- package/dist/migration-engine/generation-engine.js +165 -0
- package/dist/migration-engine/generation-engine.js.map +1 -0
- package/dist/migration-engine/shared.d.ts +5 -2
- package/dist/migration-engine/shared.d.ts.map +1 -1
- package/dist/migration-engine/shared.js.map +1 -1
- package/dist/mod.d.ts +0 -8
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +0 -32
- package/dist/mod.js.map +1 -1
- package/dist/query/condition-builder.js.map +1 -1
- package/dist/query/result-transform.js +2 -1
- package/dist/query/result-transform.js.map +1 -1
- package/dist/schema/create.d.ts +74 -16
- package/dist/schema/create.d.ts.map +1 -1
- package/dist/schema/create.js +76 -11
- package/dist/schema/create.js.map +1 -1
- package/dist/schema/serialize.js.map +1 -1
- package/dist/shared/settings-schema.js +36 -0
- package/dist/shared/settings-schema.js.map +1 -0
- package/dist/util/import-generator.js.map +1 -1
- package/dist/util/parse.js.map +1 -1
- package/package.json +8 -2
- package/src/adapters/adapters.ts +10 -3
- package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +11 -7
- package/src/adapters/drizzle/drizzle-adapter.test.ts +77 -29
- package/src/adapters/drizzle/drizzle-adapter.ts +31 -78
- package/src/adapters/drizzle/drizzle-query.ts +4 -7
- package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +9 -3
- package/src/adapters/drizzle/drizzle-uow-compiler.ts +12 -6
- package/src/adapters/drizzle/drizzle-uow-decoder.ts +1 -1
- package/src/adapters/drizzle/drizzle-uow-executor.ts +1 -1
- package/src/adapters/drizzle/generate.test.ts +573 -150
- package/src/adapters/drizzle/generate.ts +187 -36
- package/src/adapters/drizzle/migrate-drizzle.test.ts +30 -6
- package/src/adapters/drizzle/shared.ts +31 -1
- package/src/adapters/drizzle/test-utils.ts +3 -1
- package/src/adapters/kysely/kysely-adapter-pglite.test.ts +25 -27
- package/src/adapters/kysely/kysely-adapter.ts +35 -58
- package/src/adapters/kysely/kysely-query-builder.ts +75 -44
- package/src/adapters/kysely/kysely-query-compiler.ts +3 -1
- package/src/adapters/kysely/kysely-query.ts +8 -2
- package/src/adapters/kysely/kysely-shared.ts +23 -0
- package/src/adapters/kysely/kysely-uow-compiler.ts +5 -2
- package/src/adapters/kysely/migration/execute-mysql.test.ts +2 -2
- package/src/adapters/kysely/migration/execute-postgres.test.ts +19 -19
- package/src/adapters/kysely/migration/execute.ts +48 -17
- package/src/adapters/kysely/migration/kysely-migrator.test.ts +19 -37
- package/src/fragment.test.ts +1 -0
- package/src/migration-engine/auto-from-schema.ts +14 -18
- package/src/migration-engine/create.ts +1 -6
- package/src/migration-engine/generation-engine.test.ts +597 -0
- package/src/migration-engine/generation-engine.ts +356 -0
- package/src/migration-engine/shared.ts +1 -4
- package/src/mod.ts +0 -66
- package/src/query/condition-builder.ts +24 -8
- package/src/query/result-transform.ts +7 -1
- package/src/schema/create.test.ts +4 -1
- package/src/schema/create.ts +132 -24
- package/src/schema/serialize.ts +21 -7
- package/src/shared/settings-schema.ts +61 -0
- package/src/util/deep-equal.ts +21 -7
- package/src/util/import-generator.ts +3 -1
- package/src/util/parse.ts +3 -1
- package/tsdown.config.ts +1 -0
- package/.turbo/turbo-test.log +0 -37
- package/.turbo/turbo-types$colon$check.log +0 -1
|
@@ -80,6 +80,7 @@ describe("DrizzleAdapter PGLite", () => {
|
|
|
80
80
|
"drizzle-adapter-pglite",
|
|
81
81
|
testSchema,
|
|
82
82
|
"postgresql",
|
|
83
|
+
"namespace",
|
|
83
84
|
);
|
|
84
85
|
|
|
85
86
|
// Create Drizzle instance with PGLite (in-memory Postgres)
|
|
@@ -103,13 +104,16 @@ describe("DrizzleAdapter PGLite", () => {
|
|
|
103
104
|
provider: "postgresql",
|
|
104
105
|
});
|
|
105
106
|
|
|
107
|
+
expect(await adapter.isConnectionHealthy()).toBe(true);
|
|
108
|
+
|
|
106
109
|
return async () => {
|
|
107
110
|
await cleanup();
|
|
108
111
|
};
|
|
109
112
|
}, 12000);
|
|
110
113
|
|
|
111
114
|
it("should execute Unit of Work with version checking", async () => {
|
|
112
|
-
|
|
115
|
+
// Pass namespace to ensure mapper translates logical table names to physical (prefixed) names
|
|
116
|
+
const queryEngine = adapter.createQueryEngine(testSchema, "namespace");
|
|
113
117
|
|
|
114
118
|
// Create initial user using UOW
|
|
115
119
|
const createUow = queryEngine.createUnitOfWork("create-user").create("users", {
|
|
@@ -194,7 +198,7 @@ describe("DrizzleAdapter PGLite", () => {
|
|
|
194
198
|
});
|
|
195
199
|
|
|
196
200
|
it("should support count operations", async () => {
|
|
197
|
-
const queryEngine = adapter.createQueryEngine(testSchema, "
|
|
201
|
+
const queryEngine = adapter.createQueryEngine(testSchema, "namespace");
|
|
198
202
|
|
|
199
203
|
// Create some users
|
|
200
204
|
await queryEngine
|
|
@@ -215,7 +219,7 @@ describe("DrizzleAdapter PGLite", () => {
|
|
|
215
219
|
});
|
|
216
220
|
|
|
217
221
|
it("should support cursor-based pagination", async () => {
|
|
218
|
-
const queryEngine = adapter.createQueryEngine(testSchema, "
|
|
222
|
+
const queryEngine = adapter.createQueryEngine(testSchema, "namespace");
|
|
219
223
|
|
|
220
224
|
const createUow = queryEngine
|
|
221
225
|
.createUnitOfWork("create-users")
|
|
@@ -262,7 +266,7 @@ describe("DrizzleAdapter PGLite", () => {
|
|
|
262
266
|
});
|
|
263
267
|
|
|
264
268
|
it("should support joins", async () => {
|
|
265
|
-
const queryEngine = adapter.createQueryEngine(testSchema, "
|
|
269
|
+
const queryEngine = adapter.createQueryEngine(testSchema, "namespace");
|
|
266
270
|
const queries: DrizzleCompiledQuery[] = [];
|
|
267
271
|
|
|
268
272
|
const createUow = queryEngine
|
|
@@ -298,7 +302,7 @@ describe("DrizzleAdapter PGLite", () => {
|
|
|
298
302
|
|
|
299
303
|
const [query] = queries;
|
|
300
304
|
expect(query.sql).toMatchInlineSnapshot(
|
|
301
|
-
`"select "
|
|
305
|
+
`"select "emails_namespace"."id", "emails_namespace"."user_id", "emails_namespace"."email", "emails_namespace"."is_primary", "emails_namespace"."_internalId", "emails_namespace"."_version", "emails_namespace_user"."data" as "user" from "emails_namespace" "emails_namespace" left join lateral (select json_build_array("emails_namespace_user"."name", "emails_namespace_user"."id", "emails_namespace_user"."age", "emails_namespace_user"."_internalId", "emails_namespace_user"."_version") as "data" from (select * from "users_namespace" "emails_namespace_user" where "emails_namespace_user"."_internalId" = "emails_namespace"."user_id" limit $1) "emails_namespace_user") "emails_namespace_user" on true"`,
|
|
302
306
|
);
|
|
303
307
|
|
|
304
308
|
expect(email).toMatchObject({
|
|
@@ -323,7 +327,7 @@ describe("DrizzleAdapter PGLite", () => {
|
|
|
323
327
|
});
|
|
324
328
|
|
|
325
329
|
it("should support complex nested joins (comments -> post -> author)", async () => {
|
|
326
|
-
const queryEngine = adapter.createQueryEngine(testSchema, "
|
|
330
|
+
const queryEngine = adapter.createQueryEngine(testSchema, "namespace");
|
|
327
331
|
const queries: DrizzleCompiledQuery[] = [];
|
|
328
332
|
|
|
329
333
|
// Create a user (author)
|
|
@@ -427,7 +431,7 @@ describe("DrizzleAdapter PGLite", () => {
|
|
|
427
431
|
|
|
428
432
|
const [query] = queries;
|
|
429
433
|
expect(query.sql).toMatchInlineSnapshot(
|
|
430
|
-
`"select "
|
|
434
|
+
`"select "comments_namespace"."id", "comments_namespace"."post_id", "comments_namespace"."user_id", "comments_namespace"."text", "comments_namespace"."_internalId", "comments_namespace"."_version", "comments_namespace_post"."data" as "post", "comments_namespace_commenter"."data" as "commenter" from "comments_namespace" "comments_namespace" left join lateral (select json_build_array("comments_namespace_post"."id", "comments_namespace_post"."title", "comments_namespace_post"."content", "comments_namespace_post"."_internalId", "comments_namespace_post"."_version", "comments_namespace_post_author"."data") as "data" from (select * from "posts_namespace" "comments_namespace_post" where "comments_namespace_post"."_internalId" = "comments_namespace"."post_id" order by "comments_namespace_post"."id" desc limit $1) "comments_namespace_post" left join lateral (select json_build_array("comments_namespace_post_author"."id", "comments_namespace_post_author"."name", "comments_namespace_post_author"."age", "comments_namespace_post_author"."_internalId", "comments_namespace_post_author"."_version") as "data" from (select * from "users_namespace" "comments_namespace_post_author" where "comments_namespace_post_author"."_internalId" = "comments_namespace_post"."user_id" order by "comments_namespace_post_author"."name" asc limit $2) "comments_namespace_post_author") "comments_namespace_post_author" on true) "comments_namespace_post" on true left join lateral (select json_build_array("comments_namespace_commenter"."id", "comments_namespace_commenter"."name", "comments_namespace_commenter"."_internalId", "comments_namespace_commenter"."_version") as "data" from (select * from "users_namespace" "comments_namespace_commenter" where "comments_namespace_commenter"."_internalId" = "comments_namespace"."user_id" limit $3) "comments_namespace_commenter") "comments_namespace_commenter" on true"`,
|
|
431
435
|
);
|
|
432
436
|
});
|
|
433
437
|
});
|
|
@@ -15,7 +15,7 @@ describe("DrizzleAdapter", () => {
|
|
|
15
15
|
provider: "postgresql",
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
const generator = adapter.createSchemaGenerator(testSchema, "test");
|
|
18
|
+
const generator = adapter.createSchemaGenerator([{ schema: testSchema, namespace: "test" }]);
|
|
19
19
|
const result = generator.generateSchema({ path: "schema.ts" });
|
|
20
20
|
|
|
21
21
|
expect(result.path).toBe("schema.ts");
|
|
@@ -23,22 +23,38 @@ describe("DrizzleAdapter", () => {
|
|
|
23
23
|
"import { pgTable, varchar, text, bigserial, integer, uniqueIndex } from "drizzle-orm/pg-core"
|
|
24
24
|
import { createId } from "@fragno-dev/db/id"
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
_internalId: bigserial("_internalId", { mode: "number" }).primaryKey().notNull(),
|
|
30
|
-
_version: integer("_version").notNull().default(0)
|
|
31
|
-
})
|
|
26
|
+
// ============================================================================
|
|
27
|
+
// Settings Table (shared across all fragments)
|
|
28
|
+
// ============================================================================
|
|
32
29
|
|
|
33
30
|
export const fragno_db_settings = pgTable("fragno_db_settings", {
|
|
34
31
|
id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
|
|
35
32
|
key: text("key").notNull(),
|
|
36
|
-
value: text("value").notNull()
|
|
33
|
+
value: text("value").notNull(),
|
|
37
34
|
_internalId: bigserial("_internalId", { mode: "number" }).primaryKey().notNull(),
|
|
38
35
|
_version: integer("_version").notNull().default(0)
|
|
39
36
|
}, (table) => [
|
|
40
37
|
uniqueIndex("unique_key").on(table.key)
|
|
41
|
-
])
|
|
38
|
+
])
|
|
39
|
+
|
|
40
|
+
export const fragnoDbSettingSchemaVersion = 1;
|
|
41
|
+
|
|
42
|
+
// ============================================================================
|
|
43
|
+
// Fragment: test
|
|
44
|
+
// ============================================================================
|
|
45
|
+
|
|
46
|
+
export const users_test = pgTable("users_test", {
|
|
47
|
+
id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
|
|
48
|
+
name: text("name").notNull(),
|
|
49
|
+
_internalId: bigserial("_internalId", { mode: "number" }).primaryKey().notNull(),
|
|
50
|
+
_version: integer("_version").notNull().default(0)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
export const test_schema = {
|
|
54
|
+
"users_test": users_test,
|
|
55
|
+
users: users_test,
|
|
56
|
+
schemaVersion: 1
|
|
57
|
+
}"
|
|
42
58
|
`);
|
|
43
59
|
});
|
|
44
60
|
|
|
@@ -48,7 +64,7 @@ describe("DrizzleAdapter", () => {
|
|
|
48
64
|
provider: "sqlite",
|
|
49
65
|
});
|
|
50
66
|
|
|
51
|
-
const generator = adapter.createSchemaGenerator(testSchema, "test");
|
|
67
|
+
const generator = adapter.createSchemaGenerator([{ schema: testSchema, namespace: "test" }]);
|
|
52
68
|
const result = generator.generateSchema({ path: "schema.ts" });
|
|
53
69
|
|
|
54
70
|
expect(result.path).toBe("schema.ts");
|
|
@@ -56,22 +72,38 @@ describe("DrizzleAdapter", () => {
|
|
|
56
72
|
"import { sqliteTable, text, integer, uniqueIndex } from "drizzle-orm/sqlite-core"
|
|
57
73
|
import { createId } from "@fragno-dev/db/id"
|
|
58
74
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
_internalId: integer("_internalId").primaryKey().autoincrement().notNull(),
|
|
63
|
-
_version: integer("_version").notNull().default(0)
|
|
64
|
-
})
|
|
75
|
+
// ============================================================================
|
|
76
|
+
// Settings Table (shared across all fragments)
|
|
77
|
+
// ============================================================================
|
|
65
78
|
|
|
66
79
|
export const fragno_db_settings = sqliteTable("fragno_db_settings", {
|
|
67
80
|
id: text("id").notNull().$defaultFn(() => createId()),
|
|
68
81
|
key: text("key").notNull(),
|
|
69
|
-
value: text("value").notNull()
|
|
82
|
+
value: text("value").notNull(),
|
|
70
83
|
_internalId: integer("_internalId").primaryKey().autoincrement().notNull(),
|
|
71
84
|
_version: integer("_version").notNull().default(0)
|
|
72
85
|
}, (table) => [
|
|
73
86
|
uniqueIndex("unique_key").on(table.key)
|
|
74
|
-
])
|
|
87
|
+
])
|
|
88
|
+
|
|
89
|
+
export const fragnoDbSettingSchemaVersion = 1;
|
|
90
|
+
|
|
91
|
+
// ============================================================================
|
|
92
|
+
// Fragment: test
|
|
93
|
+
// ============================================================================
|
|
94
|
+
|
|
95
|
+
export const users_test = sqliteTable("users_test", {
|
|
96
|
+
id: text("id").notNull().$defaultFn(() => createId()),
|
|
97
|
+
name: text("name").notNull(),
|
|
98
|
+
_internalId: integer("_internalId").primaryKey().autoincrement().notNull(),
|
|
99
|
+
_version: integer("_version").notNull().default(0)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
export const test_schema = {
|
|
103
|
+
"users_test": users_test,
|
|
104
|
+
users: users_test,
|
|
105
|
+
schemaVersion: 1
|
|
106
|
+
}"
|
|
75
107
|
`);
|
|
76
108
|
});
|
|
77
109
|
|
|
@@ -81,10 +113,10 @@ describe("DrizzleAdapter", () => {
|
|
|
81
113
|
provider: "postgresql",
|
|
82
114
|
});
|
|
83
115
|
|
|
84
|
-
const generator = adapter.createSchemaGenerator(testSchema, "myapp");
|
|
116
|
+
const generator = adapter.createSchemaGenerator([{ schema: testSchema, namespace: "myapp" }]);
|
|
85
117
|
const result = generator.generateSchema();
|
|
86
118
|
|
|
87
|
-
expect(result.path).toBe("
|
|
119
|
+
expect(result.path).toBe("fragno-schema.ts");
|
|
88
120
|
});
|
|
89
121
|
|
|
90
122
|
it("should preserve original schema tables", () => {
|
|
@@ -93,7 +125,7 @@ describe("DrizzleAdapter", () => {
|
|
|
93
125
|
provider: "postgresql",
|
|
94
126
|
});
|
|
95
127
|
|
|
96
|
-
const generator = adapter.createSchemaGenerator(testSchema, "test");
|
|
128
|
+
const generator = adapter.createSchemaGenerator([{ schema: testSchema, namespace: "test" }]);
|
|
97
129
|
const result = generator.generateSchema();
|
|
98
130
|
|
|
99
131
|
// Original table should still be there
|
|
@@ -101,22 +133,38 @@ describe("DrizzleAdapter", () => {
|
|
|
101
133
|
"import { pgTable, varchar, text, bigserial, integer, uniqueIndex } from "drizzle-orm/pg-core"
|
|
102
134
|
import { createId } from "@fragno-dev/db/id"
|
|
103
135
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
_internalId: bigserial("_internalId", { mode: "number" }).primaryKey().notNull(),
|
|
108
|
-
_version: integer("_version").notNull().default(0)
|
|
109
|
-
})
|
|
136
|
+
// ============================================================================
|
|
137
|
+
// Settings Table (shared across all fragments)
|
|
138
|
+
// ============================================================================
|
|
110
139
|
|
|
111
140
|
export const fragno_db_settings = pgTable("fragno_db_settings", {
|
|
112
141
|
id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
|
|
113
142
|
key: text("key").notNull(),
|
|
114
|
-
value: text("value").notNull()
|
|
143
|
+
value: text("value").notNull(),
|
|
115
144
|
_internalId: bigserial("_internalId", { mode: "number" }).primaryKey().notNull(),
|
|
116
145
|
_version: integer("_version").notNull().default(0)
|
|
117
146
|
}, (table) => [
|
|
118
147
|
uniqueIndex("unique_key").on(table.key)
|
|
119
|
-
])
|
|
148
|
+
])
|
|
149
|
+
|
|
150
|
+
export const fragnoDbSettingSchemaVersion = 1;
|
|
151
|
+
|
|
152
|
+
// ============================================================================
|
|
153
|
+
// Fragment: test
|
|
154
|
+
// ============================================================================
|
|
155
|
+
|
|
156
|
+
export const users_test = pgTable("users_test", {
|
|
157
|
+
id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
|
|
158
|
+
name: text("name").notNull(),
|
|
159
|
+
_internalId: bigserial("_internalId", { mode: "number" }).primaryKey().notNull(),
|
|
160
|
+
_version: integer("_version").notNull().default(0)
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
export const test_schema = {
|
|
164
|
+
"users_test": users_test,
|
|
165
|
+
users: users_test,
|
|
166
|
+
schemaVersion: 1
|
|
167
|
+
}"
|
|
120
168
|
`);
|
|
121
169
|
});
|
|
122
170
|
});
|
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
import type { DatabaseAdapter } from "../adapters";
|
|
2
|
-
import {
|
|
3
|
-
column,
|
|
4
|
-
idColumn,
|
|
5
|
-
schema,
|
|
6
|
-
SchemaBuilder,
|
|
7
|
-
type AnySchema,
|
|
8
|
-
type FragnoId,
|
|
9
|
-
} from "../../schema/create";
|
|
2
|
+
import { type AnySchema } from "../../schema/create";
|
|
10
3
|
import type { AbstractQuery } from "../../query/query";
|
|
11
4
|
import type { SchemaGenerator } from "../../schema-generator/schema-generator";
|
|
12
5
|
import { generateSchema } from "./generate";
|
|
13
6
|
import { fromDrizzle, type DrizzleUOWConfig } from "./drizzle-query";
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
import { createTableNameMapper, type DBType, type DrizzleResult } from "./shared";
|
|
8
|
+
import { createSettingsManager, settingsSchema } from "../../shared/settings-schema";
|
|
9
|
+
import { sql } from "drizzle-orm";
|
|
17
10
|
|
|
18
11
|
export interface DrizzleConfig {
|
|
19
12
|
db: unknown;
|
|
@@ -27,92 +20,52 @@ export class DrizzleAdapter implements DatabaseAdapter<DrizzleUOWConfig> {
|
|
|
27
20
|
this.#drizzleConfig = config;
|
|
28
21
|
}
|
|
29
22
|
|
|
30
|
-
|
|
31
|
-
return
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
23
|
+
get provider(): "sqlite" | "mysql" | "postgresql" {
|
|
24
|
+
return this.#drizzleConfig.provider;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async isConnectionHealthy(): Promise<boolean> {
|
|
28
|
+
try {
|
|
29
|
+
const result = (await (this.#drizzleConfig.db as DBType).execute(
|
|
30
|
+
sql`SELECT 1 as healthy`,
|
|
31
|
+
)) as DrizzleResult;
|
|
32
|
+
return result.rows[0]["healthy"] === 1;
|
|
33
|
+
} catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
async getSchemaVersion(namespace: string): Promise<string | undefined> {
|
|
38
|
-
const queryEngine = this.createQueryEngine(
|
|
39
|
+
const queryEngine = this.createQueryEngine(settingsSchema, namespace);
|
|
39
40
|
const manager = createSettingsManager(queryEngine, namespace);
|
|
40
|
-
const randomId = createId();
|
|
41
|
-
|
|
42
|
-
const result = await manager.createKeyWithDefault(randomId);
|
|
43
|
-
if (result) {
|
|
44
|
-
await manager.delete(result.id);
|
|
45
|
-
}
|
|
46
41
|
|
|
42
|
+
// Try to read the version key directly
|
|
43
|
+
const result = await manager.get("version");
|
|
47
44
|
return result?.value;
|
|
48
45
|
}
|
|
49
46
|
|
|
50
47
|
createQueryEngine<TSchema extends AnySchema>(
|
|
51
48
|
schema: TSchema,
|
|
52
|
-
|
|
49
|
+
namespace: string,
|
|
53
50
|
): AbstractQuery<TSchema, DrizzleUOWConfig> {
|
|
54
|
-
|
|
51
|
+
// Only create mapper if namespace is non-empty
|
|
52
|
+
const mapper = namespace ? createTableNameMapper(namespace) : undefined;
|
|
53
|
+
return fromDrizzle(schema, this.#drizzleConfig, mapper);
|
|
55
54
|
}
|
|
56
55
|
|
|
57
|
-
createSchemaGenerator(
|
|
56
|
+
createSchemaGenerator(
|
|
57
|
+
fragments: { schema: AnySchema; namespace: string }[],
|
|
58
|
+
options?: { path?: string },
|
|
59
|
+
): SchemaGenerator {
|
|
58
60
|
return {
|
|
59
|
-
generateSchema: (
|
|
60
|
-
const path = options?.path ??
|
|
61
|
-
|
|
62
|
-
const schemaWithSettingsTable = this.#createFullSchema(schema);
|
|
61
|
+
generateSchema: (genOptions) => {
|
|
62
|
+
const path = genOptions?.path ?? options?.path ?? "fragno-schema.ts";
|
|
63
63
|
|
|
64
64
|
return {
|
|
65
|
-
schema: generateSchema(
|
|
65
|
+
schema: generateSchema(fragments, this.#drizzleConfig.provider),
|
|
66
66
|
path,
|
|
67
67
|
};
|
|
68
68
|
},
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
-
|
|
73
|
-
function createSettingsSchema(version: number) {
|
|
74
|
-
return schema((s) => {
|
|
75
|
-
return s.addTable(SETTINGS_TABLE_NAME, (t) => {
|
|
76
|
-
return t
|
|
77
|
-
.addColumn("id", idColumn())
|
|
78
|
-
.addColumn("key", column("string"))
|
|
79
|
-
.addColumn("value", column("string").defaultTo(String(version)))
|
|
80
|
-
.createIndex("unique_key", ["key"], { unique: true });
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function createSettingsManager(
|
|
86
|
-
queryEngine: AbstractQuery<ReturnType<typeof createSettingsSchema>, DrizzleUOWConfig>,
|
|
87
|
-
namespace: string,
|
|
88
|
-
) {
|
|
89
|
-
return {
|
|
90
|
-
async createKeyWithDefault(key: string) {
|
|
91
|
-
const writeUow = queryEngine
|
|
92
|
-
.createUnitOfWork("createKeyWithDefault")
|
|
93
|
-
.create(SETTINGS_TABLE_NAME, {
|
|
94
|
-
key: `${namespace}.${key}`,
|
|
95
|
-
});
|
|
96
|
-
const { success } = await writeUow.executeMutations();
|
|
97
|
-
if (!success) {
|
|
98
|
-
throw new Error("Failed to create key with default");
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return this.get(key);
|
|
102
|
-
},
|
|
103
|
-
|
|
104
|
-
async get(key: string): Promise<{ id: FragnoId; key: string; value: string } | undefined> {
|
|
105
|
-
const uow = queryEngine
|
|
106
|
-
.createUnitOfWork()
|
|
107
|
-
.find(SETTINGS_TABLE_NAME, (b) =>
|
|
108
|
-
b.whereIndex("unique_key", (eb) => eb("key", "=", `${namespace}.${key}`)),
|
|
109
|
-
);
|
|
110
|
-
const [[result]] = await uow.executeRetrieve();
|
|
111
|
-
return result; // FIXME: result should be maybe undefined
|
|
112
|
-
},
|
|
113
|
-
|
|
114
|
-
async delete(id: FragnoId) {
|
|
115
|
-
await queryEngine.delete(SETTINGS_TABLE_NAME, id);
|
|
116
|
-
},
|
|
117
|
-
};
|
|
118
|
-
}
|
|
@@ -5,14 +5,9 @@ import type { CompiledMutation, UOWExecutor } from "../../query/unit-of-work";
|
|
|
5
5
|
import { createDrizzleUOWCompiler, type DrizzleCompiledQuery } from "./drizzle-uow-compiler";
|
|
6
6
|
import { executeDrizzleRetrievalPhase, executeDrizzleMutationPhase } from "./drizzle-uow-executor";
|
|
7
7
|
import { UnitOfWork } from "../../query/unit-of-work";
|
|
8
|
-
import { parseDrizzle } from "./shared";
|
|
8
|
+
import { parseDrizzle, type DrizzleResult, type TableNameMapper } from "./shared";
|
|
9
9
|
import { createDrizzleUOWDecoder } from "./drizzle-uow-decoder";
|
|
10
10
|
|
|
11
|
-
export interface DrizzleResult {
|
|
12
|
-
rows: Record<string, unknown>[];
|
|
13
|
-
affectedRows: number;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
11
|
/**
|
|
17
12
|
* Configuration options for creating a Drizzle Unit of Work
|
|
18
13
|
*/
|
|
@@ -33,6 +28,7 @@ export interface DrizzleUOWConfig {
|
|
|
33
28
|
*
|
|
34
29
|
* @param schema - The database schema definition
|
|
35
30
|
* @param config - Drizzle configuration containing the database instance and provider
|
|
31
|
+
* @param mapper - Optional table name mapper for namespace prefixing
|
|
36
32
|
* @returns An AbstractQuery instance for performing database operations
|
|
37
33
|
*
|
|
38
34
|
* @example
|
|
@@ -48,12 +44,13 @@ export interface DrizzleUOWConfig {
|
|
|
48
44
|
export function fromDrizzle<T extends AnySchema>(
|
|
49
45
|
schema: T,
|
|
50
46
|
config: DrizzleConfig,
|
|
47
|
+
mapper?: TableNameMapper,
|
|
51
48
|
): AbstractQuery<T, DrizzleUOWConfig> {
|
|
52
49
|
const [db] = parseDrizzle(config.db);
|
|
53
50
|
const { provider } = config;
|
|
54
51
|
|
|
55
52
|
function createUOW(name?: string, uowConfig?: DrizzleUOWConfig) {
|
|
56
|
-
const uowCompiler = createDrizzleUOWCompiler(schema, config, uowConfig?.onQuery);
|
|
53
|
+
const uowCompiler = createDrizzleUOWCompiler(schema, config, mapper, uowConfig?.onQuery);
|
|
57
54
|
|
|
58
55
|
const executor: UOWExecutor<DrizzleCompiledQuery, DrizzleResult> = {
|
|
59
56
|
executeRetrievalPhase: (retrievalBatch: DrizzleCompiledQuery[]) =>
|
|
@@ -755,9 +755,15 @@ describe("drizzle-uow-compiler", () => {
|
|
|
755
755
|
return t
|
|
756
756
|
.addColumn("id", idColumn())
|
|
757
757
|
.addColumn("message", column("string"))
|
|
758
|
-
.addColumn(
|
|
759
|
-
|
|
760
|
-
|
|
758
|
+
.addColumn(
|
|
759
|
+
"sessionId",
|
|
760
|
+
column("string").defaultTo$((b) => b.cuid()),
|
|
761
|
+
) // runtime cuid
|
|
762
|
+
.addColumn(
|
|
763
|
+
"timestamp",
|
|
764
|
+
column("timestamp").defaultTo$((b) => b.now()),
|
|
765
|
+
) // runtime now
|
|
766
|
+
.addColumn("counter", column("integer").defaultTo$(42)) // runtime function
|
|
761
767
|
.addColumn("status", column("string").defaultTo("pending")) // static default
|
|
762
768
|
.createIndex("idx_session", ["sessionId"]);
|
|
763
769
|
});
|
|
@@ -9,7 +9,7 @@ import type {
|
|
|
9
9
|
} from "../../query/unit-of-work";
|
|
10
10
|
import { buildCondition, type Condition } from "../../query/condition-builder";
|
|
11
11
|
import type { DrizzleConfig } from "./drizzle-adapter";
|
|
12
|
-
import { type ColumnType, type TableType, parseDrizzle } from "./shared";
|
|
12
|
+
import { type ColumnType, type TableType, type TableNameMapper, parseDrizzle } from "./shared";
|
|
13
13
|
import { encodeValues, ReferenceSubquery } from "../../query/result-transform";
|
|
14
14
|
import { serialize } from "../../schema/serialize";
|
|
15
15
|
import { decodeCursor, serializeCursorValues } from "../../query/cursor";
|
|
@@ -29,12 +29,14 @@ export type DrizzleCompiledQuery = {
|
|
|
29
29
|
*
|
|
30
30
|
* @param schema - The database schema
|
|
31
31
|
* @param config - Drizzle configuration
|
|
32
|
+
* @param mapper - Optional table name mapper for namespace prefixing
|
|
32
33
|
* @param onQuery - Optional callback to receive compiled queries for logging/debugging
|
|
33
34
|
* @returns A UOWCompiler instance for Drizzle
|
|
34
35
|
*/
|
|
35
36
|
export function createDrizzleUOWCompiler<TSchema extends AnySchema>(
|
|
36
37
|
schema: TSchema,
|
|
37
38
|
config: DrizzleConfig,
|
|
39
|
+
mapper?: TableNameMapper,
|
|
38
40
|
onQuery?: (query: DrizzleCompiledQuery) => void,
|
|
39
41
|
): UOWCompiler<TSchema, DrizzleCompiledQuery> {
|
|
40
42
|
const [db, drizzleTables] = parseDrizzle(config.db);
|
|
@@ -45,14 +47,15 @@ export function createDrizzleUOWCompiler<TSchema extends AnySchema>(
|
|
|
45
47
|
* @throws Error if table is not found in Drizzle schema
|
|
46
48
|
*/
|
|
47
49
|
function toDrizzleTable(table: AnyTable): TableType {
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
+
// Map logical table name to physical table name using the mapper
|
|
51
|
+
const physicalTableName = mapper ? mapper.toPhysical(table.ormName) : table.ormName;
|
|
52
|
+
const out = drizzleTables[physicalTableName];
|
|
50
53
|
if (out) {
|
|
51
54
|
return out;
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
throw new Error(
|
|
55
|
-
`[Drizzle] Unknown table name ${
|
|
58
|
+
`[Drizzle] Unknown table name ${physicalTableName} (logical: ${table.ormName}), is it included in your Drizzle schema?`,
|
|
56
59
|
);
|
|
57
60
|
}
|
|
58
61
|
|
|
@@ -150,7 +153,9 @@ export function createDrizzleUOWCompiler<TSchema extends AnySchema>(
|
|
|
150
153
|
|
|
151
154
|
if (condition.type === "not") {
|
|
152
155
|
const result = buildWhere(condition.item);
|
|
153
|
-
if (!result)
|
|
156
|
+
if (!result) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
154
159
|
|
|
155
160
|
return Drizzle.not(result);
|
|
156
161
|
}
|
|
@@ -435,7 +440,8 @@ export function createDrizzleUOWCompiler<TSchema extends AnySchema>(
|
|
|
435
440
|
queryConfig.with = processJoins(joins);
|
|
436
441
|
}
|
|
437
442
|
|
|
438
|
-
const
|
|
443
|
+
const physicalTableName = mapper ? mapper.toPhysical(op.table.ormName) : op.table.ormName;
|
|
444
|
+
const compiledQuery = db.query[physicalTableName].findMany(queryConfig).toSQL();
|
|
439
445
|
onQuery?.(compiledQuery);
|
|
440
446
|
return compiledQuery;
|
|
441
447
|
}
|
|
@@ -2,8 +2,8 @@ import type { AnySchema, AnyTable } from "../../schema/create";
|
|
|
2
2
|
import type { SQLProvider } from "../../shared/providers";
|
|
3
3
|
import type { RetrievalOperation, UOWDecoder } from "../../query/unit-of-work";
|
|
4
4
|
import { decodeResult } from "../../query/result-transform";
|
|
5
|
-
import type { DrizzleResult } from "./drizzle-query";
|
|
6
5
|
import { getOrderedJoinColumns } from "./join-column-utils";
|
|
6
|
+
import type { DrizzleResult } from "./shared";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Join information with nested join support
|
|
@@ -2,7 +2,7 @@ import { SQL, StringChunk, sql, type SQLChunk } from "drizzle-orm";
|
|
|
2
2
|
import type { CompiledMutation, MutationResult } from "../../query/unit-of-work";
|
|
3
3
|
import type { DBType } from "./shared";
|
|
4
4
|
import type { DrizzleCompiledQuery } from "./drizzle-uow-compiler";
|
|
5
|
-
import type { DrizzleResult } from "./
|
|
5
|
+
import type { DrizzleResult } from "./shared";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Convert a DrizzleCompiledQuery (SQL string + params) to a Drizzle SQL object
|