@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
@@ -0,0 +1,356 @@
1
+ import type { FragnoDatabase } from "../mod";
2
+ import type { AnySchema } from "../schema/create";
3
+ import type { PreparedMigration } from "./create";
4
+ import {
5
+ settingsSchema,
6
+ SETTINGS_NAMESPACE,
7
+ createSettingsManager,
8
+ } from "../shared/settings-schema";
9
+
10
+ export interface GenerationEngineResult {
11
+ schema: string;
12
+ path: string;
13
+ namespace: string;
14
+ }
15
+
16
+ export interface GenerationInternalResult {
17
+ schema: string;
18
+ path: string;
19
+ namespace: string;
20
+ fromVersion: number;
21
+ toVersion: number;
22
+ preparedMigration?: PreparedMigration;
23
+ }
24
+
25
+ export interface ExecuteMigrationResult {
26
+ namespace: string;
27
+ didMigrate: boolean;
28
+ fromVersion: number;
29
+ toVersion: number;
30
+ }
31
+
32
+ export async function generateMigrationsOrSchema<
33
+ const TDatabases extends FragnoDatabase<AnySchema>[],
34
+ >(
35
+ databases: TDatabases,
36
+ options?: {
37
+ path?: string;
38
+ toVersion?: number;
39
+ fromVersion?: number;
40
+ },
41
+ ): Promise<GenerationEngineResult[]> {
42
+ if (databases.length === 0) {
43
+ throw new Error("No databases provided for schema generation");
44
+ }
45
+
46
+ const firstDb = databases[0];
47
+ const adapter = firstDb.adapter;
48
+
49
+ // If adapter has createSchemaGenerator, use it for combined generation (e.g., Drizzle)
50
+ if (adapter.createSchemaGenerator) {
51
+ if (options?.toVersion !== undefined || options?.fromVersion !== undefined) {
52
+ console.warn(
53
+ "⚠️ Warning: --from and --to version options are not supported when generating schemas for multiple fragments and will be ignored.",
54
+ );
55
+ }
56
+
57
+ const fragments = databases.map((db) => ({
58
+ schema: db.schema,
59
+ namespace: db.namespace,
60
+ }));
61
+
62
+ const generator = adapter.createSchemaGenerator(fragments, {
63
+ path: options?.path,
64
+ });
65
+
66
+ return [
67
+ {
68
+ ...generator.generateSchema(),
69
+ namespace: firstDb.namespace,
70
+ },
71
+ ];
72
+ }
73
+
74
+ // Otherwise, use migration engine for individual generation (e.g., Kysely)
75
+ if (!adapter.createMigrationEngine) {
76
+ throw new Error(
77
+ "Adapter does not support migration-based schema generation. Ensure your adapter implements createMigrationEngine.",
78
+ );
79
+ }
80
+
81
+ if (!(await adapter.isConnectionHealthy())) {
82
+ throw new Error(
83
+ "Database connection is not healthy. Please check your database connection and try again.",
84
+ );
85
+ }
86
+
87
+ const settingsQueryEngine = adapter.createQueryEngine(settingsSchema, "");
88
+ const settingsManager = createSettingsManager(settingsQueryEngine, SETTINGS_NAMESPACE);
89
+
90
+ let settingsSourceVersion: number;
91
+ try {
92
+ const result = await settingsManager.get("version");
93
+
94
+ if (!result) {
95
+ settingsSourceVersion = 0;
96
+ } else {
97
+ settingsSourceVersion = parseInt(result.value);
98
+ }
99
+ } catch {
100
+ // We don't really have a way to verify this error happens because the key doesn't exist in the database
101
+ settingsSourceVersion = 0;
102
+ }
103
+
104
+ const generatedFiles: GenerationInternalResult[] = [];
105
+
106
+ const settingsMigrator = adapter.createMigrationEngine(settingsSchema, SETTINGS_NAMESPACE);
107
+ const settingsTargetVersion = settingsSchema.version;
108
+
109
+ // Generate settings table migration
110
+ const settingsMigration = await settingsMigrator.prepareMigrationTo(settingsTargetVersion, {
111
+ fromVersion: settingsSourceVersion,
112
+ });
113
+
114
+ if (!settingsMigration.getSQL) {
115
+ throw new Error(
116
+ "Migration engine does not support SQL generation. Ensure your adapter's migration engine provides getSQL().",
117
+ );
118
+ }
119
+
120
+ const settingsSql = settingsMigration.getSQL();
121
+
122
+ if (settingsSql.trim()) {
123
+ generatedFiles.push({
124
+ schema: settingsSql,
125
+ path: "settings-migration.sql", // Placeholder, will be renamed in post-processing
126
+ namespace: SETTINGS_NAMESPACE,
127
+ fromVersion: settingsSourceVersion,
128
+ toVersion: settingsTargetVersion,
129
+ preparedMigration: settingsMigration,
130
+ });
131
+ }
132
+
133
+ // Generate migration for each fragment
134
+ for (const db of databases) {
135
+ const dbAdapter = db.adapter;
136
+
137
+ // Use migration engine
138
+ if (!dbAdapter.createMigrationEngine) {
139
+ throw new Error(
140
+ `Adapter for ${db.namespace} does not support schema generation. ` +
141
+ `Ensure your adapter implements either createSchemaGenerator or createMigrationEngine.`,
142
+ );
143
+ }
144
+
145
+ const migrator = dbAdapter.createMigrationEngine(db.schema, db.namespace);
146
+ const targetVersion = options?.toVersion ?? db.schema.version;
147
+ const sourceVersion = options?.fromVersion ?? 0;
148
+
149
+ // Generate migration from source to target version
150
+ const preparedMigration = await migrator.prepareMigrationTo(targetVersion, {
151
+ fromVersion: sourceVersion,
152
+ });
153
+
154
+ if (!preparedMigration.getSQL) {
155
+ throw new Error(
156
+ "Migration engine does not support SQL generation. Ensure your adapter's migration engine provides getSQL().",
157
+ );
158
+ }
159
+
160
+ const sql = preparedMigration.getSQL();
161
+
162
+ // If no migrations needed, skip this fragment
163
+ if (sql.trim()) {
164
+ generatedFiles.push({
165
+ schema: sql,
166
+ path: "schema.sql", // Placeholder, will be renamed in post-processing
167
+ namespace: db.namespace,
168
+ fromVersion: sourceVersion,
169
+ toVersion: targetVersion,
170
+ preparedMigration: preparedMigration,
171
+ });
172
+ }
173
+ }
174
+
175
+ // Post-process filenames with ordering
176
+ return postProcessMigrationFilenames(generatedFiles);
177
+ }
178
+
179
+ /**
180
+ * Execute migrations for all fragments in the correct order.
181
+ * Migrates settings table first, then fragments alphabetically.
182
+ *
183
+ * @param databases - Array of FragnoDatabase instances to migrate
184
+ * @returns Array of execution results for each migration
185
+ */
186
+ export async function executeMigrations<const TDatabases extends FragnoDatabase<AnySchema>[]>(
187
+ databases: TDatabases,
188
+ ): Promise<ExecuteMigrationResult[]> {
189
+ if (databases.length === 0) {
190
+ throw new Error("No databases provided for migration");
191
+ }
192
+
193
+ const firstDb = databases[0];
194
+ const adapter = firstDb.adapter;
195
+
196
+ // Validate adapter supports migrations
197
+ if (!adapter.createMigrationEngine) {
198
+ throw new Error(
199
+ "Adapter does not support running migrations. The adapter only supports schema generation.\n" +
200
+ "Try using 'generateMigrationsOrSchema' instead to generate schema files.",
201
+ );
202
+ }
203
+
204
+ // Validate all use same adapter
205
+ const allSameAdapter = databases.every((db) => db.adapter === adapter);
206
+ if (!allSameAdapter) {
207
+ throw new Error(
208
+ "All fragments must use the same database adapter instance. Mixed adapters are not supported.",
209
+ );
210
+ }
211
+
212
+ if (!(await adapter.isConnectionHealthy())) {
213
+ throw new Error(
214
+ "Database connection is not healthy. Please check your database connection and try again.",
215
+ );
216
+ }
217
+
218
+ const results: ExecuteMigrationResult[] = [];
219
+ const migrationsToExecute: Array<{
220
+ namespace: string;
221
+ fromVersion: number;
222
+ toVersion: number;
223
+ preparedMigration: PreparedMigration;
224
+ }> = [];
225
+
226
+ // 1. Prepare settings table migration
227
+ const settingsQueryEngine = adapter.createQueryEngine(settingsSchema, "");
228
+ const settingsManager = createSettingsManager(settingsQueryEngine, SETTINGS_NAMESPACE);
229
+
230
+ let settingsSourceVersion: number;
231
+ try {
232
+ const result = await settingsManager.get("version");
233
+ settingsSourceVersion = result ? parseInt(result.value) : 0;
234
+ } catch {
235
+ settingsSourceVersion = 0;
236
+ }
237
+
238
+ const settingsMigrator = adapter.createMigrationEngine(settingsSchema, SETTINGS_NAMESPACE);
239
+ const settingsTargetVersion = settingsSchema.version;
240
+
241
+ if (settingsSourceVersion < settingsTargetVersion) {
242
+ const settingsMigration = await settingsMigrator.prepareMigrationTo(settingsTargetVersion, {
243
+ fromVersion: settingsSourceVersion,
244
+ updateSettings: true,
245
+ });
246
+
247
+ if (settingsMigration.operations.length > 0) {
248
+ migrationsToExecute.push({
249
+ namespace: SETTINGS_NAMESPACE,
250
+ fromVersion: settingsSourceVersion,
251
+ toVersion: settingsTargetVersion,
252
+ preparedMigration: settingsMigration,
253
+ });
254
+ }
255
+ }
256
+
257
+ // 2. Prepare fragment migrations (sorted alphabetically)
258
+ const sortedDatabases = [...databases].sort((a, b) => a.namespace.localeCompare(b.namespace));
259
+
260
+ for (const fragnoDb of sortedDatabases) {
261
+ const migrator = adapter.createMigrationEngine(fragnoDb.schema, fragnoDb.namespace);
262
+ const currentVersion = await migrator.getVersion();
263
+ const targetVersion = fragnoDb.schema.version;
264
+
265
+ if (currentVersion < targetVersion) {
266
+ const preparedMigration = await migrator.prepareMigrationTo(targetVersion, {
267
+ updateSettings: true,
268
+ });
269
+
270
+ if (preparedMigration.operations.length > 0) {
271
+ migrationsToExecute.push({
272
+ namespace: fragnoDb.namespace,
273
+ fromVersion: currentVersion,
274
+ toVersion: targetVersion,
275
+ preparedMigration: preparedMigration,
276
+ });
277
+ }
278
+ }
279
+ }
280
+
281
+ // 3. Execute all migrations in order
282
+ for (const migration of migrationsToExecute) {
283
+ await migration.preparedMigration.execute();
284
+ results.push({
285
+ namespace: migration.namespace,
286
+ didMigrate: true,
287
+ fromVersion: migration.fromVersion,
288
+ toVersion: migration.toVersion,
289
+ });
290
+ }
291
+
292
+ // 4. Add skipped migrations (already up-to-date)
293
+ for (const fragnoDb of databases) {
294
+ if (!results.find((r) => r.namespace === fragnoDb.namespace)) {
295
+ results.push({
296
+ namespace: fragnoDb.namespace,
297
+ didMigrate: false,
298
+ fromVersion: fragnoDb.schema.version,
299
+ toVersion: fragnoDb.schema.version,
300
+ });
301
+ }
302
+ }
303
+
304
+ return results;
305
+ }
306
+
307
+ /**
308
+ * Post-processes migration files to add ordering and standardize naming.
309
+ *
310
+ * Sorts files with settings namespace first, then alphabetically by namespace,
311
+ * and assigns ordering numbers. Transforms filenames to format:
312
+ * `<date>_<n>_f<from>_t<to>_<namespace>.sql`
313
+ *
314
+ * @param files - Array of generated migration files with version information
315
+ * @returns Array of files with standardized paths and ordering
316
+ */
317
+ export function postProcessMigrationFilenames(
318
+ files: GenerationInternalResult[],
319
+ ): GenerationEngineResult[] {
320
+ if (files.length === 0) {
321
+ return [];
322
+ }
323
+
324
+ // Sort files: settings namespace first, then alphabetically by namespace
325
+ const sortedFiles = [...files].sort((a, b) => {
326
+ if (a.namespace === SETTINGS_NAMESPACE) {
327
+ return -1;
328
+ }
329
+ if (b.namespace === SETTINGS_NAMESPACE) {
330
+ return 1;
331
+ }
332
+ return a.namespace.localeCompare(b.namespace);
333
+ });
334
+
335
+ // Generate date prefix for filenames
336
+ const date = new Date().toISOString().split("T")[0].replace(/-/g, "");
337
+
338
+ // Rename files with ordering
339
+ return sortedFiles.map((file, index) => {
340
+ const fromVersion = file.fromVersion ?? 0;
341
+ const toVersion = file.toVersion ?? 0;
342
+
343
+ // Create new filename with ordering
344
+ const orderNum = (index + 1).toString().padStart(3, "0");
345
+ const fromPadded = fromVersion.toString().padStart(3, "0");
346
+ const toPadded = toVersion.toString().padStart(3, "0");
347
+ const safeName = file.namespace.replace(/[^a-z0-9-]/gi, "_");
348
+ const newPath = `${date}_${orderNum}_f${fromPadded}_t${toPadded}_${safeName}.sql`;
349
+
350
+ return {
351
+ schema: file.schema,
352
+ path: newPath,
353
+ namespace: file.namespace,
354
+ };
355
+ });
356
+ }
@@ -20,10 +20,7 @@ export interface ColumnInfo {
20
20
  | `varchar(${number})`;
21
21
  isNullable: boolean;
22
22
  role: "external-id" | "internal-id" | "version" | "reference" | "regular";
23
- default?: {
24
- value?: unknown;
25
- runtime?: "now" | "auto";
26
- };
23
+ default?: { value: unknown } | { dbSpecial: "now" } | { runtime: "cuid" | "now" };
27
24
  }
28
25
 
29
26
  export type MigrationOperation =
package/src/mod.ts CHANGED
@@ -115,72 +115,6 @@ export class FragnoDatabase<const T extends AnySchema> {
115
115
  get adapter() {
116
116
  return this.#adapter;
117
117
  }
118
-
119
- async generateSchema(options?: {
120
- path?: string;
121
- toVersion?: number;
122
- fromVersion?: number;
123
- }): Promise<{ schema: string; path: string }> {
124
- const adapter = this.#adapter;
125
-
126
- if (adapter.createSchemaGenerator) {
127
- if (options?.toVersion !== undefined || options?.fromVersion !== undefined) {
128
- console.warn("⚠️ toVersion and fromVersion are not supported for schema generation.");
129
- }
130
-
131
- const generator = adapter.createSchemaGenerator(this.#schema, this.#namespace);
132
- const defaultPath = options?.path ?? "schema.ts";
133
- return generator.generateSchema({
134
- path: defaultPath,
135
- toVersion: options?.toVersion,
136
- fromVersion: options?.fromVersion,
137
- });
138
- }
139
-
140
- if (adapter.createMigrationEngine) {
141
- const migrator = adapter.createMigrationEngine(this.#schema, this.#namespace);
142
- const targetVersion = options?.toVersion ?? this.#schema.version;
143
- const sourceVersion = options?.fromVersion;
144
-
145
- // Get current version for file naming if not provided
146
- const currentVersion = sourceVersion ?? (await migrator.getVersion());
147
-
148
- // Determine the default path using the migrator's getDefaultFileName if available
149
- const defaultPath =
150
- options?.path ??
151
- (migrator.getDefaultFileName
152
- ? migrator.getDefaultFileName(this.#namespace, currentVersion, targetVersion)
153
- : "schema.sql");
154
-
155
- // Generate migration from source to target version
156
- const preparedMigration = await migrator.prepareMigrationTo(targetVersion, {
157
- updateSettings: true,
158
- fromVersion: sourceVersion,
159
- });
160
-
161
- if (!preparedMigration.getSQL) {
162
- throw new Error(
163
- "Migration engine does not support SQL generation. Ensure your adapter's migration engine provides getSQL().",
164
- );
165
- }
166
-
167
- const sql = preparedMigration.getSQL();
168
-
169
- // If no migrations needed, return informative message
170
- if (!sql.trim()) {
171
- throw new Error("No migrations needed. Database is already at the target version.");
172
- }
173
-
174
- return {
175
- schema: sql,
176
- path: defaultPath,
177
- };
178
- }
179
-
180
- throw new Error(
181
- "Adapter does not support schema generation. Ensure your adapter implements either createSchemaGenerator or createMigrationEngine.",
182
- );
183
- }
184
118
  }
185
119
 
186
120
  export function defineFragnoDatabase<const TSchema extends AnySchema>(
@@ -95,7 +95,9 @@ export function createBuilder<Columns extends Record<string, AnyColumn>>(
95
95
  if (args.length === 3) {
96
96
  const [a, operator, b] = args;
97
97
 
98
- if (!operators.includes(operator)) throw new Error(`Unsupported operator: ${operator}`);
98
+ if (!operators.includes(operator)) {
99
+ throw new Error(`Unsupported operator: ${operator}`);
100
+ }
99
101
 
100
102
  return {
101
103
  type: "compare",
@@ -116,7 +118,9 @@ export function createBuilder<Columns extends Record<string, AnyColumn>>(
116
118
  builder.isNull = (a) => builder(a, "is", null);
117
119
  builder.isNotNull = (a) => builder(a, "is not", null);
118
120
  builder.not = (condition) => {
119
- if (typeof condition === "boolean") return !condition;
121
+ if (typeof condition === "boolean") {
122
+ return !condition;
123
+ }
120
124
 
121
125
  return {
122
126
  type: "not",
@@ -131,13 +135,19 @@ export function createBuilder<Columns extends Record<string, AnyColumn>>(
131
135
  } as const;
132
136
 
133
137
  for (const item of conditions) {
134
- if (item === true) return true;
135
- if (item === false) continue;
138
+ if (item === true) {
139
+ return true;
140
+ }
141
+ if (item === false) {
142
+ continue;
143
+ }
136
144
 
137
145
  out.items.push(item);
138
146
  }
139
147
 
140
- if (out.items.length === 0) return false;
148
+ if (out.items.length === 0) {
149
+ return false;
150
+ }
141
151
  return out;
142
152
  };
143
153
 
@@ -148,13 +158,19 @@ export function createBuilder<Columns extends Record<string, AnyColumn>>(
148
158
  } as const;
149
159
 
150
160
  for (const item of conditions) {
151
- if (item === true) continue;
152
- if (item === false) return false;
161
+ if (item === true) {
162
+ continue;
163
+ }
164
+ if (item === false) {
165
+ return false;
166
+ }
153
167
 
154
168
  out.items.push(item);
155
169
  }
156
170
 
157
- if (out.items.length === 0) return true;
171
+ if (out.items.length === 0) {
172
+ return true;
173
+ }
158
174
  return out;
159
175
  };
160
176
 
@@ -51,10 +51,16 @@ export function generateRuntimeDefault(column: AnyColumn): unknown {
51
51
  return undefined;
52
52
  }
53
53
 
54
+ // If it's a database-level special function (defaultTo(b => b.now())), return undefined
55
+ // as the database should handle this via DEFAULT NOW() or equivalent
56
+ if ("dbSpecial" in column.default) {
57
+ return undefined;
58
+ }
59
+
54
60
  // Handle runtime defaults (defaultTo$)
55
61
  const runtime = column.default.runtime;
56
62
 
57
- if (runtime === "auto") {
63
+ if (runtime === "cuid") {
58
64
  return createId();
59
65
  }
60
66
 
@@ -66,7 +66,10 @@ describe("create", () => {
66
66
  return s.addTable("test", (t) => {
67
67
  return t
68
68
  .addColumn("id", idColumn())
69
- .addColumn("createdAt", column("timestamp").defaultTo$("now"))
69
+ .addColumn(
70
+ "createdAt",
71
+ column("timestamp").defaultTo$((b) => b.now()),
72
+ )
70
73
  .addColumn("status", column("string").defaultTo("active"));
71
74
  });
72
75
  });