@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.
Files changed (108) hide show
  1. package/.turbo/turbo-build.log +61 -53
  2. package/CHANGELOG.md +12 -0
  3. package/dist/adapters/adapters.d.ts +11 -1
  4. package/dist/adapters/adapters.d.ts.map +1 -1
  5. package/dist/adapters/drizzle/drizzle-adapter.d.ts +9 -2
  6. package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -1
  7. package/dist/adapters/drizzle/drizzle-adapter.js +21 -39
  8. package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -1
  9. package/dist/adapters/drizzle/drizzle-query.d.ts.map +1 -1
  10. package/dist/adapters/drizzle/drizzle-query.js +3 -2
  11. package/dist/adapters/drizzle/drizzle-query.js.map +1 -1
  12. package/dist/adapters/drizzle/drizzle-uow-compiler.js +8 -6
  13. package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +1 -1
  14. package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +1 -1
  15. package/dist/adapters/drizzle/drizzle-uow-executor.js.map +1 -1
  16. package/dist/adapters/drizzle/generate.js +107 -34
  17. package/dist/adapters/drizzle/generate.js.map +1 -1
  18. package/dist/adapters/drizzle/shared.js +14 -1
  19. package/dist/adapters/drizzle/shared.js.map +1 -1
  20. package/dist/adapters/kysely/kysely-adapter.d.ts +2 -1
  21. package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -1
  22. package/dist/adapters/kysely/kysely-adapter.js +25 -30
  23. package/dist/adapters/kysely/kysely-adapter.js.map +1 -1
  24. package/dist/adapters/kysely/kysely-query-builder.js +48 -44
  25. package/dist/adapters/kysely/kysely-query-builder.js.map +1 -1
  26. package/dist/adapters/kysely/kysely-query-compiler.js +2 -2
  27. package/dist/adapters/kysely/kysely-query-compiler.js.map +1 -1
  28. package/dist/adapters/kysely/kysely-query.js +3 -2
  29. package/dist/adapters/kysely/kysely-query.js.map +1 -1
  30. package/dist/adapters/kysely/kysely-shared.js +18 -0
  31. package/dist/adapters/kysely/kysely-shared.js.map +1 -0
  32. package/dist/adapters/kysely/kysely-uow-compiler.js +4 -3
  33. package/dist/adapters/kysely/kysely-uow-compiler.js.map +1 -1
  34. package/dist/adapters/kysely/migration/execute.js +15 -12
  35. package/dist/adapters/kysely/migration/execute.js.map +1 -1
  36. package/dist/migration-engine/auto-from-schema.js +2 -8
  37. package/dist/migration-engine/auto-from-schema.js.map +1 -1
  38. package/dist/migration-engine/create.d.ts +1 -5
  39. package/dist/migration-engine/create.js +1 -1
  40. package/dist/migration-engine/create.js.map +1 -1
  41. package/dist/migration-engine/generation-engine.d.ts +51 -0
  42. package/dist/migration-engine/generation-engine.d.ts.map +1 -0
  43. package/dist/migration-engine/generation-engine.js +165 -0
  44. package/dist/migration-engine/generation-engine.js.map +1 -0
  45. package/dist/migration-engine/shared.d.ts +5 -2
  46. package/dist/migration-engine/shared.d.ts.map +1 -1
  47. package/dist/migration-engine/shared.js.map +1 -1
  48. package/dist/mod.d.ts +0 -8
  49. package/dist/mod.d.ts.map +1 -1
  50. package/dist/mod.js +0 -32
  51. package/dist/mod.js.map +1 -1
  52. package/dist/query/condition-builder.js.map +1 -1
  53. package/dist/query/result-transform.js +2 -1
  54. package/dist/query/result-transform.js.map +1 -1
  55. package/dist/schema/create.d.ts +74 -16
  56. package/dist/schema/create.d.ts.map +1 -1
  57. package/dist/schema/create.js +76 -11
  58. package/dist/schema/create.js.map +1 -1
  59. package/dist/schema/serialize.js.map +1 -1
  60. package/dist/shared/settings-schema.js +36 -0
  61. package/dist/shared/settings-schema.js.map +1 -0
  62. package/dist/util/import-generator.js.map +1 -1
  63. package/dist/util/parse.js.map +1 -1
  64. package/package.json +8 -2
  65. package/src/adapters/adapters.ts +10 -3
  66. package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +11 -7
  67. package/src/adapters/drizzle/drizzle-adapter.test.ts +77 -29
  68. package/src/adapters/drizzle/drizzle-adapter.ts +31 -78
  69. package/src/adapters/drizzle/drizzle-query.ts +4 -7
  70. package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +9 -3
  71. package/src/adapters/drizzle/drizzle-uow-compiler.ts +12 -6
  72. package/src/adapters/drizzle/drizzle-uow-decoder.ts +1 -1
  73. package/src/adapters/drizzle/drizzle-uow-executor.ts +1 -1
  74. package/src/adapters/drizzle/generate.test.ts +573 -150
  75. package/src/adapters/drizzle/generate.ts +187 -36
  76. package/src/adapters/drizzle/migrate-drizzle.test.ts +30 -6
  77. package/src/adapters/drizzle/shared.ts +31 -1
  78. package/src/adapters/drizzle/test-utils.ts +3 -1
  79. package/src/adapters/kysely/kysely-adapter-pglite.test.ts +25 -27
  80. package/src/adapters/kysely/kysely-adapter.ts +35 -58
  81. package/src/adapters/kysely/kysely-query-builder.ts +75 -44
  82. package/src/adapters/kysely/kysely-query-compiler.ts +3 -1
  83. package/src/adapters/kysely/kysely-query.ts +8 -2
  84. package/src/adapters/kysely/kysely-shared.ts +23 -0
  85. package/src/adapters/kysely/kysely-uow-compiler.ts +5 -2
  86. package/src/adapters/kysely/migration/execute-mysql.test.ts +2 -2
  87. package/src/adapters/kysely/migration/execute-postgres.test.ts +19 -19
  88. package/src/adapters/kysely/migration/execute.ts +48 -17
  89. package/src/adapters/kysely/migration/kysely-migrator.test.ts +19 -37
  90. package/src/fragment.test.ts +1 -0
  91. package/src/migration-engine/auto-from-schema.ts +14 -18
  92. package/src/migration-engine/create.ts +1 -6
  93. package/src/migration-engine/generation-engine.test.ts +597 -0
  94. package/src/migration-engine/generation-engine.ts +356 -0
  95. package/src/migration-engine/shared.ts +1 -4
  96. package/src/mod.ts +0 -66
  97. package/src/query/condition-builder.ts +24 -8
  98. package/src/query/result-transform.ts +7 -1
  99. package/src/schema/create.test.ts +4 -1
  100. package/src/schema/create.ts +132 -24
  101. package/src/schema/serialize.ts +21 -7
  102. package/src/shared/settings-schema.ts +61 -0
  103. package/src/util/deep-equal.ts +21 -7
  104. package/src/util/import-generator.ts +3 -1
  105. package/src/util/parse.ts +3 -1
  106. package/tsdown.config.ts +1 -0
  107. package/.turbo/turbo-test.log +0 -37
  108. package/.turbo/turbo-types$colon$check.log +0 -1
@@ -33,13 +33,33 @@ describe("generateSchema", () => {
33
33
 
34
34
  describe("postgresql", () => {
35
35
  it("should generate PostgreSQL schema", () => {
36
- const generated = generateSchema(testSchema, "postgresql");
36
+ const generated = generateSchema([{ namespace: "test", schema: testSchema }], "postgresql");
37
37
  expect(generated).toMatchInlineSnapshot(`
38
- "import { pgTable, varchar, text, integer, bigserial, uniqueIndex, index, bigint, foreignKey } from "drizzle-orm/pg-core"
38
+ "import { pgTable, varchar, text, bigserial, integer, uniqueIndex, index, bigint, foreignKey } from "drizzle-orm/pg-core"
39
39
  import { createId } from "@fragno-dev/db/id"
40
40
  import { relations } from "drizzle-orm"
41
41
 
42
- export const users = pgTable("users", {
42
+ // ============================================================================
43
+ // Settings Table (shared across all fragments)
44
+ // ============================================================================
45
+
46
+ export const fragno_db_settings = pgTable("fragno_db_settings", {
47
+ id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
48
+ key: text("key").notNull(),
49
+ value: text("value").notNull(),
50
+ _internalId: bigserial("_internalId", { mode: "number" }).primaryKey().notNull(),
51
+ _version: integer("_version").notNull().default(0)
52
+ }, (table) => [
53
+ uniqueIndex("unique_key").on(table.key)
54
+ ])
55
+
56
+ export const fragnoDbSettingSchemaVersion = 1;
57
+
58
+ // ============================================================================
59
+ // Fragment: test
60
+ // ============================================================================
61
+
62
+ export const users_test = pgTable("users_test", {
43
63
  id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
44
64
  name: text("name").notNull(),
45
65
  email: text("email").notNull(),
@@ -47,11 +67,11 @@ describe("generateSchema", () => {
47
67
  _internalId: bigserial("_internalId", { mode: "number" }).primaryKey().notNull(),
48
68
  _version: integer("_version").notNull().default(0)
49
69
  }, (table) => [
50
- uniqueIndex("idx_email").on(table.email),
51
- index("idx_name").on(table.name)
70
+ uniqueIndex("idx_email_test").on(table.email),
71
+ index("idx_name_test").on(table.name)
52
72
  ])
53
73
 
54
- export const posts = pgTable("posts", {
74
+ export const posts_test = pgTable("posts_test", {
55
75
  id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
56
76
  title: text("title").notNull(),
57
77
  content: text("content").notNull(),
@@ -62,33 +82,61 @@ describe("generateSchema", () => {
62
82
  }, (table) => [
63
83
  foreignKey({
64
84
  columns: [table.userId],
65
- foreignColumns: [users._internalId],
66
- name: "posts_users_author_fk"
85
+ foreignColumns: [users_test._internalId],
86
+ name: "fk_posts_users_author_test"
67
87
  }),
68
- index("idx_user").on(table.userId),
69
- index("idx_title").on(table.title)
88
+ index("idx_user_test").on(table.userId),
89
+ index("idx_title_test").on(table.title)
70
90
  ])
71
91
 
72
- export const postsRelations = relations(posts, ({ one }) => ({
73
- author: one(users, {
92
+ export const posts_testRelations = relations(posts_test, ({ one }) => ({
93
+ author: one(users_test, {
74
94
  relationName: "posts_users",
75
- fields: [posts.userId],
76
- references: [users._internalId]
95
+ fields: [posts_test.userId],
96
+ references: [users_test._internalId]
77
97
  })
78
- }));"
98
+ }));
99
+
100
+ export const test_schema = {
101
+ "users_test": users_test,
102
+ users: users_test,
103
+ "posts_test": posts_test,
104
+ posts: posts_test,
105
+ schemaVersion: 3
106
+ }"
79
107
  `);
80
108
  });
81
109
  });
82
110
 
83
111
  describe("mysql", () => {
84
112
  it("should generate MySQL schema", () => {
85
- const generated = generateSchema(testSchema, "mysql");
113
+ const generated = generateSchema([{ namespace: "test", schema: testSchema }], "mysql");
86
114
  expect(generated).toMatchInlineSnapshot(`
87
- "import { mysqlTable, varchar, text, integer, bigint, uniqueIndex, index, foreignKey } from "drizzle-orm/mysql-core"
115
+ "import { mysqlTable, varchar, text, bigint, integer, uniqueIndex, index, foreignKey } from "drizzle-orm/mysql-core"
88
116
  import { createId } from "@fragno-dev/db/id"
89
117
  import { relations } from "drizzle-orm"
90
118
 
91
- export const users = mysqlTable("users", {
119
+ // ============================================================================
120
+ // Settings Table (shared across all fragments)
121
+ // ============================================================================
122
+
123
+ export const fragno_db_settings = mysqlTable("fragno_db_settings", {
124
+ id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
125
+ key: text("key").notNull(),
126
+ value: text("value").notNull(),
127
+ _internalId: bigint("_internalId").primaryKey().autoincrement().notNull(),
128
+ _version: integer("_version").notNull().default(0)
129
+ }, (table) => [
130
+ uniqueIndex("unique_key").on(table.key)
131
+ ])
132
+
133
+ export const fragnoDbSettingSchemaVersion = 1;
134
+
135
+ // ============================================================================
136
+ // Fragment: test
137
+ // ============================================================================
138
+
139
+ export const users_test = mysqlTable("users_test", {
92
140
  id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
93
141
  name: text("name").notNull(),
94
142
  email: text("email").notNull(),
@@ -96,11 +144,11 @@ describe("generateSchema", () => {
96
144
  _internalId: bigint("_internalId").primaryKey().autoincrement().notNull(),
97
145
  _version: integer("_version").notNull().default(0)
98
146
  }, (table) => [
99
- uniqueIndex("idx_email").on(table.email),
100
- index("idx_name").on(table.name)
147
+ uniqueIndex("idx_email_test").on(table.email),
148
+ index("idx_name_test").on(table.name)
101
149
  ])
102
150
 
103
- export const posts = mysqlTable("posts", {
151
+ export const posts_test = mysqlTable("posts_test", {
104
152
  id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
105
153
  title: text("title").notNull(),
106
154
  content: text("content").notNull(),
@@ -111,33 +159,61 @@ describe("generateSchema", () => {
111
159
  }, (table) => [
112
160
  foreignKey({
113
161
  columns: [table.userId],
114
- foreignColumns: [users._internalId],
115
- name: "posts_users_author_fk"
162
+ foreignColumns: [users_test._internalId],
163
+ name: "fk_posts_users_author_test"
116
164
  }),
117
- index("idx_user").on(table.userId),
118
- index("idx_title").on(table.title)
165
+ index("idx_user_test").on(table.userId),
166
+ index("idx_title_test").on(table.title)
119
167
  ])
120
168
 
121
- export const postsRelations = relations(posts, ({ one }) => ({
122
- author: one(users, {
169
+ export const posts_testRelations = relations(posts_test, ({ one }) => ({
170
+ author: one(users_test, {
123
171
  relationName: "posts_users",
124
- fields: [posts.userId],
125
- references: [users._internalId]
172
+ fields: [posts_test.userId],
173
+ references: [users_test._internalId]
126
174
  })
127
- }));"
175
+ }));
176
+
177
+ export const test_schema = {
178
+ "users_test": users_test,
179
+ users: users_test,
180
+ "posts_test": posts_test,
181
+ posts: posts_test,
182
+ schemaVersion: 3
183
+ }"
128
184
  `);
129
185
  });
130
186
  });
131
187
 
132
188
  describe("sqlite", () => {
133
189
  it("should generate SQLite schema", () => {
134
- const generated = generateSchema(testSchema, "sqlite");
190
+ const generated = generateSchema([{ namespace: "test", schema: testSchema }], "sqlite");
135
191
  expect(generated).toMatchInlineSnapshot(`
136
192
  "import { sqliteTable, text, integer, uniqueIndex, index, blob, foreignKey } from "drizzle-orm/sqlite-core"
137
193
  import { createId } from "@fragno-dev/db/id"
138
194
  import { relations } from "drizzle-orm"
139
195
 
140
- export const users = sqliteTable("users", {
196
+ // ============================================================================
197
+ // Settings Table (shared across all fragments)
198
+ // ============================================================================
199
+
200
+ export const fragno_db_settings = sqliteTable("fragno_db_settings", {
201
+ id: text("id").notNull().$defaultFn(() => createId()),
202
+ key: text("key").notNull(),
203
+ value: text("value").notNull(),
204
+ _internalId: integer("_internalId").primaryKey().autoincrement().notNull(),
205
+ _version: integer("_version").notNull().default(0)
206
+ }, (table) => [
207
+ uniqueIndex("unique_key").on(table.key)
208
+ ])
209
+
210
+ export const fragnoDbSettingSchemaVersion = 1;
211
+
212
+ // ============================================================================
213
+ // Fragment: test
214
+ // ============================================================================
215
+
216
+ export const users_test = sqliteTable("users_test", {
141
217
  id: text("id").notNull().$defaultFn(() => createId()),
142
218
  name: text("name").notNull(),
143
219
  email: text("email").notNull(),
@@ -145,11 +221,11 @@ describe("generateSchema", () => {
145
221
  _internalId: integer("_internalId").primaryKey().autoincrement().notNull(),
146
222
  _version: integer("_version").notNull().default(0)
147
223
  }, (table) => [
148
- uniqueIndex("idx_email").on(table.email),
149
- index("idx_name").on(table.name)
224
+ uniqueIndex("idx_email_test").on(table.email),
225
+ index("idx_name_test").on(table.name)
150
226
  ])
151
227
 
152
- export const posts = sqliteTable("posts", {
228
+ export const posts_test = sqliteTable("posts_test", {
153
229
  id: text("id").notNull().$defaultFn(() => createId()),
154
230
  title: text("title").notNull(),
155
231
  content: text("content").notNull(),
@@ -160,20 +236,28 @@ describe("generateSchema", () => {
160
236
  }, (table) => [
161
237
  foreignKey({
162
238
  columns: [table.userId],
163
- foreignColumns: [users._internalId],
164
- name: "posts_users_author_fk"
239
+ foreignColumns: [users_test._internalId],
240
+ name: "fk_posts_users_author_test"
165
241
  }),
166
- index("idx_user").on(table.userId),
167
- index("idx_title").on(table.title)
242
+ index("idx_user_test").on(table.userId),
243
+ index("idx_title_test").on(table.title)
168
244
  ])
169
245
 
170
- export const postsRelations = relations(posts, ({ one }) => ({
171
- author: one(users, {
246
+ export const posts_testRelations = relations(posts_test, ({ one }) => ({
247
+ author: one(users_test, {
172
248
  relationName: "posts_users",
173
- fields: [posts.userId],
174
- references: [users._internalId]
249
+ fields: [posts_test.userId],
250
+ references: [users_test._internalId]
175
251
  })
176
- }));"
252
+ }));
253
+
254
+ export const test_schema = {
255
+ "users_test": users_test,
256
+ users: users_test,
257
+ "posts_test": posts_test,
258
+ posts: posts_test,
259
+ schemaVersion: 3
260
+ }"
177
261
  `);
178
262
  });
179
263
  });
@@ -182,23 +266,106 @@ describe("generateSchema", () => {
182
266
  it("should handle runtime default values", () => {
183
267
  const timestampSchema = schema((s) => {
184
268
  return s.addTable("events", (t) => {
185
- return t
186
- .addColumn("id", idColumn())
187
- .addColumn("createdAt", column("timestamp").defaultTo$("now"));
269
+ return t.addColumn("id", idColumn()).addColumn(
270
+ "createdAt",
271
+ column("timestamp").defaultTo$((b) => b.now()),
272
+ );
188
273
  });
189
274
  });
190
275
 
191
- const generated = generateSchema(timestampSchema, "postgresql");
276
+ const generated = generateSchema(
277
+ [{ namespace: "test", schema: timestampSchema }],
278
+ "postgresql",
279
+ );
192
280
  expect(generated).toMatchInlineSnapshot(`
193
- "import { pgTable, varchar, timestamp, bigserial, integer } from "drizzle-orm/pg-core"
281
+ "import { pgTable, varchar, text, bigserial, integer, uniqueIndex, timestamp } from "drizzle-orm/pg-core"
194
282
  import { createId } from "@fragno-dev/db/id"
195
283
 
196
- export const events = pgTable("events", {
284
+ // ============================================================================
285
+ // Settings Table (shared across all fragments)
286
+ // ============================================================================
287
+
288
+ export const fragno_db_settings = pgTable("fragno_db_settings", {
289
+ id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
290
+ key: text("key").notNull(),
291
+ value: text("value").notNull(),
292
+ _internalId: bigserial("_internalId", { mode: "number" }).primaryKey().notNull(),
293
+ _version: integer("_version").notNull().default(0)
294
+ }, (table) => [
295
+ uniqueIndex("unique_key").on(table.key)
296
+ ])
297
+
298
+ export const fragnoDbSettingSchemaVersion = 1;
299
+
300
+ // ============================================================================
301
+ // Fragment: test
302
+ // ============================================================================
303
+
304
+ export const events_test = pgTable("events_test", {
305
+ id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
306
+ createdAt: timestamp("createdAt").notNull().$defaultFn(() => new Date()),
307
+ _internalId: bigserial("_internalId", { mode: "number" }).primaryKey().notNull(),
308
+ _version: integer("_version").notNull().default(0)
309
+ })
310
+
311
+ export const test_schema = {
312
+ "events_test": events_test,
313
+ events: events_test,
314
+ schemaVersion: 1
315
+ }"
316
+ `);
317
+ });
318
+
319
+ it("should handle database-level default values", () => {
320
+ const timestampSchema = schema((s) => {
321
+ return s.addTable("events", (t) => {
322
+ return t.addColumn("id", idColumn()).addColumn(
323
+ "createdAt",
324
+ column("timestamp").defaultTo((b) => b.now()),
325
+ );
326
+ });
327
+ });
328
+
329
+ const generated = generateSchema(
330
+ [{ namespace: "test", schema: timestampSchema }],
331
+ "postgresql",
332
+ );
333
+ expect(generated).toMatchInlineSnapshot(`
334
+ "import { pgTable, varchar, text, bigserial, integer, uniqueIndex, timestamp } from "drizzle-orm/pg-core"
335
+ import { createId } from "@fragno-dev/db/id"
336
+
337
+ // ============================================================================
338
+ // Settings Table (shared across all fragments)
339
+ // ============================================================================
340
+
341
+ export const fragno_db_settings = pgTable("fragno_db_settings", {
342
+ id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
343
+ key: text("key").notNull(),
344
+ value: text("value").notNull(),
345
+ _internalId: bigserial("_internalId", { mode: "number" }).primaryKey().notNull(),
346
+ _version: integer("_version").notNull().default(0)
347
+ }, (table) => [
348
+ uniqueIndex("unique_key").on(table.key)
349
+ ])
350
+
351
+ export const fragnoDbSettingSchemaVersion = 1;
352
+
353
+ // ============================================================================
354
+ // Fragment: test
355
+ // ============================================================================
356
+
357
+ export const events_test = pgTable("events_test", {
197
358
  id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
198
359
  createdAt: timestamp("createdAt").notNull().defaultNow(),
199
360
  _internalId: bigserial("_internalId", { mode: "number" }).primaryKey().notNull(),
200
361
  _version: integer("_version").notNull().default(0)
201
- })"
362
+ })
363
+
364
+ export const test_schema = {
365
+ "events_test": events_test,
366
+ events: events_test,
367
+ schemaVersion: 1
368
+ }"
202
369
  `);
203
370
  });
204
371
  });
@@ -211,11 +378,10 @@ describe("generateSchema", () => {
211
378
  });
212
379
  });
213
380
 
214
- const generated = generateSchema(binarySchema, "postgresql");
381
+ const generated = generateSchema([{ namespace: "test", schema: binarySchema }], "postgresql");
215
382
  expect(generated).toMatchInlineSnapshot(`
216
- "import { pgTable, varchar, customType, bigserial, integer } from "drizzle-orm/pg-core"
383
+ "import { pgTable, varchar, text, bigserial, integer, uniqueIndex, customType } from "drizzle-orm/pg-core"
217
384
  import { createId } from "@fragno-dev/db/id"
218
-
219
385
  const customBinary = customType<
220
386
  {
221
387
  data: Uint8Array;
@@ -233,12 +399,38 @@ describe("generateSchema", () => {
233
399
  }
234
400
  });
235
401
 
236
- export const files = pgTable("files", {
402
+ // ============================================================================
403
+ // Settings Table (shared across all fragments)
404
+ // ============================================================================
405
+
406
+ export const fragno_db_settings = pgTable("fragno_db_settings", {
407
+ id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
408
+ key: text("key").notNull(),
409
+ value: text("value").notNull(),
410
+ _internalId: bigserial("_internalId", { mode: "number" }).primaryKey().notNull(),
411
+ _version: integer("_version").notNull().default(0)
412
+ }, (table) => [
413
+ uniqueIndex("unique_key").on(table.key)
414
+ ])
415
+
416
+ export const fragnoDbSettingSchemaVersion = 1;
417
+
418
+ // ============================================================================
419
+ // Fragment: test
420
+ // ============================================================================
421
+
422
+ export const files_test = pgTable("files_test", {
237
423
  id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
238
424
  data: customBinary("data").notNull(),
239
425
  _internalId: bigserial("_internalId", { mode: "number" }).primaryKey().notNull(),
240
426
  _version: integer("_version").notNull().default(0)
241
- })"
427
+ })
428
+
429
+ export const test_schema = {
430
+ "files_test": files_test,
431
+ files: files_test,
432
+ schemaVersion: 1
433
+ }"
242
434
  `);
243
435
  });
244
436
  });
@@ -269,26 +461,49 @@ describe("generateSchema", () => {
269
461
  });
270
462
 
271
463
  it("should generate PostgreSQL schema with many relations", () => {
272
- const generated = generateSchema(oneToManySchema, "postgresql");
464
+ const generated = generateSchema(
465
+ [{ namespace: "test", schema: oneToManySchema }],
466
+ "postgresql",
467
+ );
273
468
  expect(generated).toMatchInlineSnapshot(`
274
- "import { pgTable, varchar, text, bigserial, integer, bigint, foreignKey, index } from "drizzle-orm/pg-core"
469
+ "import { pgTable, varchar, text, bigserial, integer, uniqueIndex, bigint, foreignKey, index } from "drizzle-orm/pg-core"
275
470
  import { createId } from "@fragno-dev/db/id"
276
471
  import { relations } from "drizzle-orm"
277
472
 
278
- export const users = pgTable("users", {
473
+ // ============================================================================
474
+ // Settings Table (shared across all fragments)
475
+ // ============================================================================
476
+
477
+ export const fragno_db_settings = pgTable("fragno_db_settings", {
478
+ id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
479
+ key: text("key").notNull(),
480
+ value: text("value").notNull(),
481
+ _internalId: bigserial("_internalId", { mode: "number" }).primaryKey().notNull(),
482
+ _version: integer("_version").notNull().default(0)
483
+ }, (table) => [
484
+ uniqueIndex("unique_key").on(table.key)
485
+ ])
486
+
487
+ export const fragnoDbSettingSchemaVersion = 1;
488
+
489
+ // ============================================================================
490
+ // Fragment: test
491
+ // ============================================================================
492
+
493
+ export const users_test = pgTable("users_test", {
279
494
  id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
280
495
  name: text("name").notNull(),
281
496
  _internalId: bigserial("_internalId", { mode: "number" }).primaryKey().notNull(),
282
497
  _version: integer("_version").notNull().default(0)
283
498
  })
284
499
 
285
- export const usersRelations = relations(users, ({ many }) => ({
286
- posts: many(posts, {
500
+ export const users_testRelations = relations(users_test, ({ many }) => ({
501
+ posts: many(posts_test, {
287
502
  relationName: "users_posts"
288
503
  })
289
504
  }));
290
505
 
291
- export const posts = pgTable("posts", {
506
+ export const posts_test = pgTable("posts_test", {
292
507
  id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
293
508
  title: text("title").notNull(),
294
509
  userId: bigint("userId", { mode: "number" }).notNull(),
@@ -297,43 +512,71 @@ describe("generateSchema", () => {
297
512
  }, (table) => [
298
513
  foreignKey({
299
514
  columns: [table.userId],
300
- foreignColumns: [users._internalId],
301
- name: "posts_users_author_fk"
515
+ foreignColumns: [users_test._internalId],
516
+ name: "fk_posts_users_author_test"
302
517
  }),
303
- index("idx_user").on(table.userId)
518
+ index("idx_user_test").on(table.userId)
304
519
  ])
305
520
 
306
- export const postsRelations = relations(posts, ({ one }) => ({
307
- author: one(users, {
521
+ export const posts_testRelations = relations(posts_test, ({ one }) => ({
522
+ author: one(users_test, {
308
523
  relationName: "posts_users",
309
- fields: [posts.userId],
310
- references: [users._internalId]
524
+ fields: [posts_test.userId],
525
+ references: [users_test._internalId]
311
526
  })
312
- }));"
527
+ }));
528
+
529
+ export const test_schema = {
530
+ "users_test": users_test,
531
+ users: users_test,
532
+ "posts_test": posts_test,
533
+ posts: posts_test,
534
+ schemaVersion: 4
535
+ }"
313
536
  `);
314
537
  });
315
538
 
316
539
  it("should generate MySQL schema with many relations", () => {
317
- const generated = generateSchema(oneToManySchema, "mysql");
540
+ const generated = generateSchema([{ namespace: "test", schema: oneToManySchema }], "mysql");
318
541
  expect(generated).toMatchInlineSnapshot(`
319
- "import { mysqlTable, varchar, text, bigint, integer, foreignKey, index } from "drizzle-orm/mysql-core"
542
+ "import { mysqlTable, varchar, text, bigint, integer, uniqueIndex, foreignKey, index } from "drizzle-orm/mysql-core"
320
543
  import { createId } from "@fragno-dev/db/id"
321
544
  import { relations } from "drizzle-orm"
322
545
 
323
- export const users = mysqlTable("users", {
546
+ // ============================================================================
547
+ // Settings Table (shared across all fragments)
548
+ // ============================================================================
549
+
550
+ export const fragno_db_settings = mysqlTable("fragno_db_settings", {
551
+ id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
552
+ key: text("key").notNull(),
553
+ value: text("value").notNull(),
554
+ _internalId: bigint("_internalId").primaryKey().autoincrement().notNull(),
555
+ _version: integer("_version").notNull().default(0)
556
+ }, (table) => [
557
+ uniqueIndex("unique_key").on(table.key)
558
+ ])
559
+
560
+ export const fragnoDbSettingSchemaVersion = 1;
561
+
562
+ // ============================================================================
563
+ // Fragment: test
564
+ // ============================================================================
565
+
566
+ export const users_test = mysqlTable("users_test", {
324
567
  id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
325
568
  name: text("name").notNull(),
326
569
  _internalId: bigint("_internalId").primaryKey().autoincrement().notNull(),
327
570
  _version: integer("_version").notNull().default(0)
328
571
  })
329
572
 
330
- export const usersRelations = relations(users, ({ many }) => ({
331
- posts: many(posts, {
573
+ export const users_testRelations = relations(users_test, ({ many }) => ({
574
+ posts: many(posts_test, {
332
575
  relationName: "users_posts"
333
576
  })
334
577
  }));
335
578
 
336
- export const posts = mysqlTable("posts", {
579
+ export const posts_test = mysqlTable("posts_test", {
337
580
  id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
338
581
  title: text("title").notNull(),
339
582
  userId: bigint("userId").notNull(),
@@ -342,43 +585,71 @@ describe("generateSchema", () => {
342
585
  }, (table) => [
343
586
  foreignKey({
344
587
  columns: [table.userId],
345
- foreignColumns: [users._internalId],
346
- name: "posts_users_author_fk"
588
+ foreignColumns: [users_test._internalId],
589
+ name: "fk_posts_users_author_test"
347
590
  }),
348
- index("idx_user").on(table.userId)
591
+ index("idx_user_test").on(table.userId)
349
592
  ])
350
593
 
351
- export const postsRelations = relations(posts, ({ one }) => ({
352
- author: one(users, {
594
+ export const posts_testRelations = relations(posts_test, ({ one }) => ({
595
+ author: one(users_test, {
353
596
  relationName: "posts_users",
354
- fields: [posts.userId],
355
- references: [users._internalId]
597
+ fields: [posts_test.userId],
598
+ references: [users_test._internalId]
356
599
  })
357
- }));"
600
+ }));
601
+
602
+ export const test_schema = {
603
+ "users_test": users_test,
604
+ users: users_test,
605
+ "posts_test": posts_test,
606
+ posts: posts_test,
607
+ schemaVersion: 4
608
+ }"
358
609
  `);
359
610
  });
360
611
 
361
612
  it("should generate SQLite schema with many relations", () => {
362
- const generated = generateSchema(oneToManySchema, "sqlite");
613
+ const generated = generateSchema([{ namespace: "test", schema: oneToManySchema }], "sqlite");
363
614
  expect(generated).toMatchInlineSnapshot(`
364
- "import { sqliteTable, text, integer, blob, foreignKey, index } from "drizzle-orm/sqlite-core"
615
+ "import { sqliteTable, text, integer, uniqueIndex, blob, foreignKey, index } from "drizzle-orm/sqlite-core"
365
616
  import { createId } from "@fragno-dev/db/id"
366
617
  import { relations } from "drizzle-orm"
367
618
 
368
- export const users = sqliteTable("users", {
619
+ // ============================================================================
620
+ // Settings Table (shared across all fragments)
621
+ // ============================================================================
622
+
623
+ export const fragno_db_settings = sqliteTable("fragno_db_settings", {
624
+ id: text("id").notNull().$defaultFn(() => createId()),
625
+ key: text("key").notNull(),
626
+ value: text("value").notNull(),
627
+ _internalId: integer("_internalId").primaryKey().autoincrement().notNull(),
628
+ _version: integer("_version").notNull().default(0)
629
+ }, (table) => [
630
+ uniqueIndex("unique_key").on(table.key)
631
+ ])
632
+
633
+ export const fragnoDbSettingSchemaVersion = 1;
634
+
635
+ // ============================================================================
636
+ // Fragment: test
637
+ // ============================================================================
638
+
639
+ export const users_test = sqliteTable("users_test", {
369
640
  id: text("id").notNull().$defaultFn(() => createId()),
370
641
  name: text("name").notNull(),
371
642
  _internalId: integer("_internalId").primaryKey().autoincrement().notNull(),
372
643
  _version: integer("_version").notNull().default(0)
373
644
  })
374
645
 
375
- export const usersRelations = relations(users, ({ many }) => ({
376
- posts: many(posts, {
646
+ export const users_testRelations = relations(users_test, ({ many }) => ({
647
+ posts: many(posts_test, {
377
648
  relationName: "users_posts"
378
649
  })
379
650
  }));
380
651
 
381
- export const posts = sqliteTable("posts", {
652
+ export const posts_test = sqliteTable("posts_test", {
382
653
  id: text("id").notNull().$defaultFn(() => createId()),
383
654
  title: text("title").notNull(),
384
655
  userId: blob("userId", { mode: "bigint" }).notNull(),
@@ -387,19 +658,27 @@ describe("generateSchema", () => {
387
658
  }, (table) => [
388
659
  foreignKey({
389
660
  columns: [table.userId],
390
- foreignColumns: [users._internalId],
391
- name: "posts_users_author_fk"
661
+ foreignColumns: [users_test._internalId],
662
+ name: "fk_posts_users_author_test"
392
663
  }),
393
- index("idx_user").on(table.userId)
664
+ index("idx_user_test").on(table.userId)
394
665
  ])
395
666
 
396
- export const postsRelations = relations(posts, ({ one }) => ({
397
- author: one(users, {
667
+ export const posts_testRelations = relations(posts_test, ({ one }) => ({
668
+ author: one(users_test, {
398
669
  relationName: "posts_users",
399
- fields: [posts.userId],
400
- references: [users._internalId]
670
+ fields: [posts_test.userId],
671
+ references: [users_test._internalId]
401
672
  })
402
- }));"
673
+ }));
674
+
675
+ export const test_schema = {
676
+ "users_test": users_test,
677
+ users: users_test,
678
+ "posts_test": posts_test,
679
+ posts: posts_test,
680
+ schemaVersion: 4
681
+ }"
403
682
  `);
404
683
  });
405
684
 
@@ -422,44 +701,78 @@ describe("generateSchema", () => {
422
701
  });
423
702
  });
424
703
 
425
- const generated = generateSchema(manyOnlySchema, "postgresql");
704
+ const generated = generateSchema(
705
+ [{ namespace: "test", schema: manyOnlySchema }],
706
+ "postgresql",
707
+ );
426
708
 
427
709
  // Categories table should NOT have a constraint callback (no foreign keys, no indexes)
428
710
  const categoriesTableMatch = generated.match(
429
- /export const categories = pgTable\("categories", \{[^}]+\}\)/,
711
+ /export const categories_test = pgTable\("categories_test", \{[^}]+\}\)/,
430
712
  );
431
713
  expect(categoriesTableMatch).toBeTruthy();
432
714
 
433
715
  // Should have relations with many
434
716
  expect(generated).toContain(
435
- "export const categoriesRelations = relations(categories, ({ many }) => ({",
717
+ "export const categories_testRelations = relations(categories_test, ({ many }) => ({",
436
718
  );
437
- expect(generated).toContain("products: many(products");
719
+ expect(generated).toContain("products: many(products_test");
720
+
721
+ // Should have schema export
722
+ expect(generated).toContain("export const test_schema = {");
438
723
  expect(generated).toMatchInlineSnapshot(`
439
- "import { pgTable, varchar, text, bigserial, integer, bigint } from "drizzle-orm/pg-core"
724
+ "import { pgTable, varchar, text, bigserial, integer, uniqueIndex, bigint } from "drizzle-orm/pg-core"
440
725
  import { createId } from "@fragno-dev/db/id"
441
726
  import { relations } from "drizzle-orm"
442
727
 
443
- export const categories = pgTable("categories", {
728
+ // ============================================================================
729
+ // Settings Table (shared across all fragments)
730
+ // ============================================================================
731
+
732
+ export const fragno_db_settings = pgTable("fragno_db_settings", {
733
+ id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
734
+ key: text("key").notNull(),
735
+ value: text("value").notNull(),
736
+ _internalId: bigserial("_internalId", { mode: "number" }).primaryKey().notNull(),
737
+ _version: integer("_version").notNull().default(0)
738
+ }, (table) => [
739
+ uniqueIndex("unique_key").on(table.key)
740
+ ])
741
+
742
+ export const fragnoDbSettingSchemaVersion = 1;
743
+
744
+ // ============================================================================
745
+ // Fragment: test
746
+ // ============================================================================
747
+
748
+ export const categories_test = pgTable("categories_test", {
444
749
  id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
445
750
  name: text("name").notNull(),
446
751
  _internalId: bigserial("_internalId", { mode: "number" }).primaryKey().notNull(),
447
752
  _version: integer("_version").notNull().default(0)
448
753
  })
449
754
 
450
- export const categoriesRelations = relations(categories, ({ many }) => ({
451
- products: many(products, {
755
+ export const categories_testRelations = relations(categories_test, ({ many }) => ({
756
+ products: many(products_test, {
452
757
  relationName: "categories_products"
453
758
  })
454
759
  }));
455
760
 
456
- export const products = pgTable("products", {
761
+ export const products_test = pgTable("products_test", {
457
762
  id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
458
763
  name: text("name").notNull(),
459
764
  categoryId: bigint("categoryId", { mode: "number" }).notNull(),
460
765
  _internalId: bigserial("_internalId", { mode: "number" }).primaryKey().notNull(),
461
766
  _version: integer("_version").notNull().default(0)
462
- })"
767
+ })
768
+
769
+ export const test_schema = {
770
+ "categories_test": categories_test,
771
+ categories: categories_test,
772
+ "products_test": products_test,
773
+ products: products_test,
774
+ schemaVersion: 3
775
+ }"
463
776
  `);
464
777
  });
465
778
 
@@ -484,22 +797,45 @@ describe("generateSchema", () => {
484
797
  });
485
798
  });
486
799
 
487
- const generated = generateSchema(selfManySchema, "postgresql");
800
+ const generated = generateSchema(
801
+ [{ namespace: "test", schema: selfManySchema }],
802
+ "postgresql",
803
+ );
488
804
 
489
805
  // Should have both one and many relations
490
- expect(generated).toContain("parent: one(category");
491
- expect(generated).toContain("children: many(category");
806
+ expect(generated).toContain("parent: one(category_test");
807
+ expect(generated).toContain("children: many(category_test");
492
808
 
493
809
  // Should only have one foreign key (from the "one" relation)
494
810
  const fkMatches = generated.match(/foreignKey\(/g);
495
811
  expect(fkMatches).toHaveLength(1);
496
812
 
497
813
  expect(generated).toMatchInlineSnapshot(`
498
- "import { pgTable, varchar, text, bigint, bigserial, integer, foreignKey } from "drizzle-orm/pg-core"
814
+ "import { pgTable, varchar, text, bigserial, integer, uniqueIndex, bigint, foreignKey } from "drizzle-orm/pg-core"
499
815
  import { createId } from "@fragno-dev/db/id"
500
816
  import { relations } from "drizzle-orm"
501
817
 
502
- export const category = pgTable("category", {
818
+ // ============================================================================
819
+ // Settings Table (shared across all fragments)
820
+ // ============================================================================
821
+
822
+ export const fragno_db_settings = pgTable("fragno_db_settings", {
823
+ id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
824
+ key: text("key").notNull(),
825
+ value: text("value").notNull(),
826
+ _internalId: bigserial("_internalId", { mode: "number" }).primaryKey().notNull(),
827
+ _version: integer("_version").notNull().default(0)
828
+ }, (table) => [
829
+ uniqueIndex("unique_key").on(table.key)
830
+ ])
831
+
832
+ export const fragnoDbSettingSchemaVersion = 1;
833
+
834
+ // ============================================================================
835
+ // Fragment: test
836
+ // ============================================================================
837
+
838
+ export const category_test = pgTable("category_test", {
503
839
  id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
504
840
  name: text("name").notNull(),
505
841
  parentId: bigint("parentId", { mode: "number" }),
@@ -509,20 +845,26 @@ describe("generateSchema", () => {
509
845
  foreignKey({
510
846
  columns: [table.parentId],
511
847
  foreignColumns: [table._internalId],
512
- name: "category_category_parent_fk"
848
+ name: "fk_category_category_parent_test"
513
849
  })
514
850
  ])
515
851
 
516
- export const categoryRelations = relations(category, ({ one, many }) => ({
517
- parent: one(category, {
852
+ export const category_testRelations = relations(category_test, ({ one, many }) => ({
853
+ parent: one(category_test, {
518
854
  relationName: "category_category",
519
- fields: [category.parentId],
520
- references: [category._internalId]
855
+ fields: [category_test.parentId],
856
+ references: [category_test._internalId]
521
857
  }),
522
- children: many(category, {
858
+ children: many(category_test, {
523
859
  relationName: "category_category"
524
860
  })
525
- }));"
861
+ }));
862
+
863
+ export const test_schema = {
864
+ "category_test": category_test,
865
+ category: category_test,
866
+ schemaVersion: 3
867
+ }"
526
868
  `);
527
869
  });
528
870
  });
@@ -545,13 +887,36 @@ describe("generateSchema", () => {
545
887
  });
546
888
 
547
889
  it("should generate PostgreSQL self-referencing foreign key using table parameter", () => {
548
- const generated = generateSchema(selfRefSchema, "postgresql");
890
+ const generated = generateSchema(
891
+ [{ namespace: "test", schema: selfRefSchema }],
892
+ "postgresql",
893
+ );
549
894
  expect(generated).toMatchInlineSnapshot(`
550
- "import { pgTable, varchar, text, bigint, bigserial, integer, foreignKey, index } from "drizzle-orm/pg-core"
895
+ "import { pgTable, varchar, text, bigserial, integer, uniqueIndex, bigint, foreignKey, index } from "drizzle-orm/pg-core"
551
896
  import { createId } from "@fragno-dev/db/id"
552
897
  import { relations } from "drizzle-orm"
553
898
 
554
- export const comment = pgTable("comment", {
899
+ // ============================================================================
900
+ // Settings Table (shared across all fragments)
901
+ // ============================================================================
902
+
903
+ export const fragno_db_settings = pgTable("fragno_db_settings", {
904
+ id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
905
+ key: text("key").notNull(),
906
+ value: text("value").notNull(),
907
+ _internalId: bigserial("_internalId", { mode: "number" }).primaryKey().notNull(),
908
+ _version: integer("_version").notNull().default(0)
909
+ }, (table) => [
910
+ uniqueIndex("unique_key").on(table.key)
911
+ ])
912
+
913
+ export const fragnoDbSettingSchemaVersion = 1;
914
+
915
+ // ============================================================================
916
+ // Fragment: test
917
+ // ============================================================================
918
+
919
+ export const comment_test = pgTable("comment_test", {
555
920
  id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
556
921
  content: text("content").notNull(),
557
922
  parentId: bigint("parentId", { mode: "number" }),
@@ -561,29 +926,55 @@ describe("generateSchema", () => {
561
926
  foreignKey({
562
927
  columns: [table.parentId],
563
928
  foreignColumns: [table._internalId],
564
- name: "comment_comment_parent_fk"
929
+ name: "fk_comment_comment_parent_test"
565
930
  }),
566
- index("idx_parent").on(table.parentId)
931
+ index("idx_parent_test").on(table.parentId)
567
932
  ])
568
933
 
569
- export const commentRelations = relations(comment, ({ one }) => ({
570
- parent: one(comment, {
934
+ export const comment_testRelations = relations(comment_test, ({ one }) => ({
935
+ parent: one(comment_test, {
571
936
  relationName: "comment_comment",
572
- fields: [comment.parentId],
573
- references: [comment._internalId]
937
+ fields: [comment_test.parentId],
938
+ references: [comment_test._internalId]
574
939
  })
575
- }));"
940
+ }));
941
+
942
+ export const test_schema = {
943
+ "comment_test": comment_test,
944
+ comment: comment_test,
945
+ schemaVersion: 2
946
+ }"
576
947
  `);
577
948
  });
578
949
 
579
950
  it("should generate MySQL self-referencing foreign key using table parameter", () => {
580
- const generated = generateSchema(selfRefSchema, "mysql");
951
+ const generated = generateSchema([{ namespace: "test", schema: selfRefSchema }], "mysql");
581
952
  expect(generated).toMatchInlineSnapshot(`
582
- "import { mysqlTable, varchar, text, bigint, integer, foreignKey, index } from "drizzle-orm/mysql-core"
953
+ "import { mysqlTable, varchar, text, bigint, integer, uniqueIndex, foreignKey, index } from "drizzle-orm/mysql-core"
583
954
  import { createId } from "@fragno-dev/db/id"
584
955
  import { relations } from "drizzle-orm"
585
956
 
586
- export const comment = mysqlTable("comment", {
957
+ // ============================================================================
958
+ // Settings Table (shared across all fragments)
959
+ // ============================================================================
960
+
961
+ export const fragno_db_settings = mysqlTable("fragno_db_settings", {
962
+ id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
963
+ key: text("key").notNull(),
964
+ value: text("value").notNull(),
965
+ _internalId: bigint("_internalId").primaryKey().autoincrement().notNull(),
966
+ _version: integer("_version").notNull().default(0)
967
+ }, (table) => [
968
+ uniqueIndex("unique_key").on(table.key)
969
+ ])
970
+
971
+ export const fragnoDbSettingSchemaVersion = 1;
972
+
973
+ // ============================================================================
974
+ // Fragment: test
975
+ // ============================================================================
976
+
977
+ export const comment_test = mysqlTable("comment_test", {
587
978
  id: varchar("id", { length: 30 }).notNull().$defaultFn(() => createId()),
588
979
  content: text("content").notNull(),
589
980
  parentId: bigint("parentId"),
@@ -593,29 +984,55 @@ describe("generateSchema", () => {
593
984
  foreignKey({
594
985
  columns: [table.parentId],
595
986
  foreignColumns: [table._internalId],
596
- name: "comment_comment_parent_fk"
987
+ name: "fk_comment_comment_parent_test"
597
988
  }),
598
- index("idx_parent").on(table.parentId)
989
+ index("idx_parent_test").on(table.parentId)
599
990
  ])
600
991
 
601
- export const commentRelations = relations(comment, ({ one }) => ({
602
- parent: one(comment, {
992
+ export const comment_testRelations = relations(comment_test, ({ one }) => ({
993
+ parent: one(comment_test, {
603
994
  relationName: "comment_comment",
604
- fields: [comment.parentId],
605
- references: [comment._internalId]
995
+ fields: [comment_test.parentId],
996
+ references: [comment_test._internalId]
606
997
  })
607
- }));"
998
+ }));
999
+
1000
+ export const test_schema = {
1001
+ "comment_test": comment_test,
1002
+ comment: comment_test,
1003
+ schemaVersion: 2
1004
+ }"
608
1005
  `);
609
1006
  });
610
1007
 
611
1008
  it("should generate SQLite self-referencing foreign key using table parameter", () => {
612
- const generated = generateSchema(selfRefSchema, "sqlite");
1009
+ const generated = generateSchema([{ namespace: "test", schema: selfRefSchema }], "sqlite");
613
1010
  expect(generated).toMatchInlineSnapshot(`
614
- "import { sqliteTable, text, blob, integer, foreignKey, index } from "drizzle-orm/sqlite-core"
1011
+ "import { sqliteTable, text, integer, uniqueIndex, blob, foreignKey, index } from "drizzle-orm/sqlite-core"
615
1012
  import { createId } from "@fragno-dev/db/id"
616
1013
  import { relations } from "drizzle-orm"
617
1014
 
618
- export const comment = sqliteTable("comment", {
1015
+ // ============================================================================
1016
+ // Settings Table (shared across all fragments)
1017
+ // ============================================================================
1018
+
1019
+ export const fragno_db_settings = sqliteTable("fragno_db_settings", {
1020
+ id: text("id").notNull().$defaultFn(() => createId()),
1021
+ key: text("key").notNull(),
1022
+ value: text("value").notNull(),
1023
+ _internalId: integer("_internalId").primaryKey().autoincrement().notNull(),
1024
+ _version: integer("_version").notNull().default(0)
1025
+ }, (table) => [
1026
+ uniqueIndex("unique_key").on(table.key)
1027
+ ])
1028
+
1029
+ export const fragnoDbSettingSchemaVersion = 1;
1030
+
1031
+ // ============================================================================
1032
+ // Fragment: test
1033
+ // ============================================================================
1034
+
1035
+ export const comment_test = sqliteTable("comment_test", {
619
1036
  id: text("id").notNull().$defaultFn(() => createId()),
620
1037
  content: text("content").notNull(),
621
1038
  parentId: blob("parentId", { mode: "bigint" }),
@@ -625,18 +1042,24 @@ describe("generateSchema", () => {
625
1042
  foreignKey({
626
1043
  columns: [table.parentId],
627
1044
  foreignColumns: [table._internalId],
628
- name: "comment_comment_parent_fk"
1045
+ name: "fk_comment_comment_parent_test"
629
1046
  }),
630
- index("idx_parent").on(table.parentId)
1047
+ index("idx_parent_test").on(table.parentId)
631
1048
  ])
632
1049
 
633
- export const commentRelations = relations(comment, ({ one }) => ({
634
- parent: one(comment, {
1050
+ export const comment_testRelations = relations(comment_test, ({ one }) => ({
1051
+ parent: one(comment_test, {
635
1052
  relationName: "comment_comment",
636
- fields: [comment.parentId],
637
- references: [comment._internalId]
1053
+ fields: [comment_test.parentId],
1054
+ references: [comment_test._internalId]
638
1055
  })
639
- }));"
1056
+ }));
1057
+
1058
+ export const test_schema = {
1059
+ "comment_test": comment_test,
1060
+ comment: comment_test,
1061
+ schemaVersion: 2
1062
+ }"
640
1063
  `);
641
1064
  });
642
1065
  });