uql-orm 0.21.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/README.md +5 -4
  2. package/dist/bunSql/bunSqlCockroachDialect.d.ts +2 -2
  3. package/dist/bunSql/bunSqlCockroachDialect.js +4 -10
  4. package/dist/bunSql/bunSqlPostgresDialect.d.ts +2 -2
  5. package/dist/bunSql/bunSqlPostgresDialect.js +4 -10
  6. package/dist/cockroachdb/cockroachDialect.d.ts +20 -4
  7. package/dist/cockroachdb/cockroachDialect.js +33 -18
  8. package/dist/d1/d1Querier.d.ts +4 -3
  9. package/dist/d1/d1Querier.js +0 -3
  10. package/dist/d1/d1SqliteDialect.d.ts +7 -0
  11. package/dist/d1/d1SqliteDialect.js +9 -0
  12. package/dist/dialect/abstractDialect.d.ts +8 -3
  13. package/dist/dialect/abstractDialect.js +9 -4
  14. package/dist/dialect/abstractSqlDialect.d.ts +35 -7
  15. package/dist/dialect/abstractSqlDialect.js +76 -35
  16. package/dist/dialect/index.d.ts +1 -0
  17. package/dist/dialect/index.js +1 -0
  18. package/dist/dialect/indexSqlDialect.d.ts +57 -0
  19. package/dist/dialect/indexSqlDialect.js +101 -0
  20. package/dist/dialect/mysqlLikeSqlDialect.d.ts +16 -1
  21. package/dist/dialect/mysqlLikeSqlDialect.js +32 -1
  22. package/dist/dialect/pgLikeSqlDialect.d.ts +33 -15
  23. package/dist/dialect/pgLikeSqlDialect.js +90 -56
  24. package/dist/dialect/vectorCast.d.ts +21 -0
  25. package/dist/dialect/vectorCast.js +28 -0
  26. package/dist/dialect/vectorSqlDialect.d.ts +10 -3
  27. package/dist/dialect/vectorSqlDialect.js +19 -8
  28. package/dist/entity/decorator/index-decorator.d.ts +2 -9
  29. package/dist/entity/metadata/definition.d.ts +5 -4
  30. package/dist/entity/metadata/definition.js +4 -3
  31. package/dist/libsql/libsqlDialect.d.ts +12 -2
  32. package/dist/libsql/libsqlDialect.js +14 -2
  33. package/dist/libsql/libsqlQuerier.d.ts +9 -22
  34. package/dist/libsql/libsqlQuerier.js +9 -85
  35. package/dist/libsql/libsqlQuerierPool.d.ts +10 -8
  36. package/dist/libsql/libsqlQuerierPool.js +17 -15
  37. package/dist/maria/mariaDialect.d.ts +26 -4
  38. package/dist/maria/mariaDialect.js +54 -15
  39. package/dist/migrate/builder/migrationBuilder.d.ts +9 -29
  40. package/dist/migrate/builder/migrationBuilder.js +58 -76
  41. package/dist/migrate/builder/splitSqlStatements.d.ts +0 -2
  42. package/dist/migrate/builder/splitSqlStatements.js +0 -2
  43. package/dist/migrate/builder/tableBuilder.d.ts +12 -2
  44. package/dist/migrate/builder/tableBuilder.js +71 -119
  45. package/dist/migrate/builder/types.d.ts +30 -41
  46. package/dist/migrate/cli.d.ts +3 -2
  47. package/dist/migrate/cli.js +21 -48
  48. package/dist/migrate/codegen/entityCodeGenerator.d.ts +0 -4
  49. package/dist/migrate/codegen/entityCodeGenerator.js +5 -63
  50. package/dist/migrate/codegen/fieldOptionsSource.d.ts +10 -0
  51. package/dist/migrate/codegen/fieldOptionsSource.js +55 -0
  52. package/dist/migrate/codegen/index.d.ts +0 -2
  53. package/dist/migrate/codegen/index.js +0 -4
  54. package/dist/migrate/generator/indexNodeToSchema.d.ts +9 -0
  55. package/dist/migrate/generator/indexNodeToSchema.js +14 -0
  56. package/dist/migrate/generator/mongoCommand.d.ts +57 -0
  57. package/dist/migrate/generator/mongoCommand.js +26 -0
  58. package/dist/migrate/generator/mongoSchemaGenerator.d.ts +9 -20
  59. package/dist/migrate/generator/mongoSchemaGenerator.js +40 -82
  60. package/dist/migrate/index.d.ts +0 -1
  61. package/dist/migrate/index.js +0 -1
  62. package/dist/migrate/introspection/abstractSqlSchemaIntrospector.d.ts +25 -10
  63. package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js +46 -32
  64. package/dist/migrate/introspection/baseSqlIntrospector.d.ts +0 -1
  65. package/dist/migrate/introspection/baseSqlIntrospector.js +3 -12
  66. package/dist/migrate/introspection/mongoIntrospector.js +2 -2
  67. package/dist/migrate/introspection/mysqlIntrospector.d.ts +5 -8
  68. package/dist/migrate/introspection/mysqlIntrospector.js +4 -10
  69. package/dist/migrate/introspection/postgresIntrospector.d.ts +5 -8
  70. package/dist/migrate/introspection/postgresIntrospector.js +4 -10
  71. package/dist/migrate/introspection/sqliteIntrospector.d.ts +6 -5
  72. package/dist/migrate/introspection/sqliteIntrospector.js +26 -18
  73. package/dist/migrate/migrator.d.ts +23 -3
  74. package/dist/migrate/migrator.js +57 -69
  75. package/dist/migrate/schemaGenerator.d.ts +26 -37
  76. package/dist/migrate/schemaGenerator.js +69 -174
  77. package/dist/migrate/schemaGeneratorAsync.d.ts +2 -2
  78. package/dist/migrate/schemaGeneratorAsync.js +3 -3
  79. package/dist/migrate/storage/databaseStorage.js +4 -4
  80. package/dist/mongo/mongoDialect.d.ts +2 -0
  81. package/dist/mongo/mongoDialect.js +14 -3
  82. package/dist/mysql/mysqlDialect.d.ts +8 -0
  83. package/dist/mysql/mysqlDialect.js +13 -0
  84. package/dist/schema/canonicalType.d.ts +14 -2
  85. package/dist/schema/canonicalType.js +41 -31
  86. package/dist/schema/index.d.ts +1 -1
  87. package/dist/schema/schemaASTBuilder.d.ts +8 -1
  88. package/dist/schema/schemaASTBuilder.js +56 -47
  89. package/dist/schema/types.d.ts +10 -37
  90. package/dist/sqlite/abstractSqliteQuerier.d.ts +39 -0
  91. package/dist/sqlite/abstractSqliteQuerier.js +44 -0
  92. package/dist/sqlite/bunSqliteAdapter.bun.d.ts +26 -0
  93. package/dist/sqlite/bunSqliteAdapter.bun.js +25 -0
  94. package/dist/sqlite/hranaQuerier.d.ts +54 -0
  95. package/dist/sqlite/hranaQuerier.js +90 -0
  96. package/dist/sqlite/hranaQuerierPool.d.ts +21 -0
  97. package/dist/sqlite/hranaQuerierPool.js +25 -0
  98. package/dist/sqlite/index.d.ts +2 -1
  99. package/dist/sqlite/index.js +2 -1
  100. package/dist/sqlite/sqliteDialect.d.ts +18 -4
  101. package/dist/sqlite/sqliteDialect.js +24 -24
  102. package/dist/sqlite/sqliteQuerier.d.ts +16 -9
  103. package/dist/sqlite/sqliteQuerier.js +4 -27
  104. package/dist/sqlite/sqliteQuerierPool.d.ts +14 -4
  105. package/dist/sqlite/sqliteQuerierPool.js +16 -5
  106. package/dist/turso/index.d.ts +3 -0
  107. package/dist/turso/index.js +3 -0
  108. package/dist/turso/local.d.ts +3 -0
  109. package/dist/turso/local.js +3 -0
  110. package/dist/turso/tursoDialect.d.ts +15 -0
  111. package/dist/turso/tursoDialect.js +18 -0
  112. package/dist/turso/tursoLocalQuerier.d.ts +25 -0
  113. package/dist/turso/tursoLocalQuerier.js +20 -0
  114. package/dist/turso/tursoLocalQuerierPool.d.ts +32 -0
  115. package/dist/turso/tursoLocalQuerierPool.js +39 -0
  116. package/dist/turso/tursoQuerier.d.ts +10 -0
  117. package/dist/turso/tursoQuerier.js +10 -0
  118. package/dist/turso/tursoQuerierPool.d.ts +39 -0
  119. package/dist/turso/tursoQuerierPool.js +38 -0
  120. package/dist/type/config.d.ts +0 -6
  121. package/dist/type/dialect.d.ts +12 -4
  122. package/dist/type/dialect.js +7 -1
  123. package/dist/type/entity.d.ts +66 -5
  124. package/dist/type/migration.d.ts +32 -23
  125. package/dist/type/vector.d.ts +5 -2
  126. package/dist/util/index.d.ts +1 -0
  127. package/dist/util/index.js +1 -0
  128. package/dist/util/indexColumn.util.d.ts +6 -0
  129. package/dist/util/indexColumn.util.js +26 -0
  130. package/package.json +16 -3
  131. package/dist/migrate/codegen/entityMerger.d.ts +0 -114
  132. package/dist/migrate/codegen/entityMerger.js +0 -293
  133. package/dist/migrate/codegen/migrationCodeGenerator.d.ts +0 -61
  134. package/dist/migrate/codegen/migrationCodeGenerator.js +0 -355
  135. package/dist/migrate/generator/index.d.ts +0 -2
  136. package/dist/migrate/generator/index.js +0 -2
  137. package/dist/migrate/sync/index.d.ts +0 -6
  138. package/dist/migrate/sync/index.js +0 -6
  139. package/dist/migrate/sync/schemaSync.d.ts +0 -131
  140. package/dist/migrate/sync/schemaSync.js +0 -259
  141. package/dist/sqlite/betterSqlite3Dialect.d.ts +0 -9
  142. package/dist/sqlite/betterSqlite3Dialect.js +0 -9
@@ -5,14 +5,41 @@
5
5
  * - OperationRecorder: Record operations only (for code generation)
6
6
  * - MigrationBuilder: Execute DDL operations (for integration tests/runtime)
7
7
  */
8
+ import { normalizeIndexColumn } from '../../util/index.js';
8
9
  import { createSchemaGenerator } from '../schemaGenerator.js';
9
- import { ColumnBuilder } from './columnBuilder.js';
10
- import { splitSqlStatementsOnSemicolons } from './splitSqlStatements.js';
10
+ import { splitSqlStatements } from './splitSqlStatements.js';
11
11
  import { TableBuilder } from './tableBuilder.js';
12
12
  /**
13
13
  * Builder for altering a table.
14
14
  * Delegates to parent builder for operation recording.
15
15
  */
16
+ /**
17
+ * One `createIndex` operation. Shared because the alter-table builder, the recorder and the
18
+ * executing builder all record the same thing, and an entry left unnormalized reaches the generator
19
+ * as a column literally named `[object Object]`.
20
+ */
21
+ function createIndexOperation(tableName, columns, options = {}) {
22
+ const { name, unique, ...index } = options;
23
+ const entries = columns.map(normalizeIndexColumn);
24
+ return {
25
+ type: 'createIndex',
26
+ tableName,
27
+ index: {
28
+ ...index,
29
+ name: name ?? `idx_${tableName}_${entries.map((entry) => entry.column).join('_')}`,
30
+ columns: entries,
31
+ unique: unique ?? false,
32
+ },
33
+ };
34
+ }
35
+ /**
36
+ * Declare one column through the same vocabulary `createTable` uses. A throwaway {@link TableBuilder}
37
+ * is that vocabulary: `addColumn`/`alterColumn` used to take a bare {@link IColumnBuilder}, which
38
+ * cannot express a type, so every column they recorded was hard-coded `VARCHAR`.
39
+ */
40
+ function buildOneColumn(callback) {
41
+ return callback(new TableBuilder('')).build();
42
+ }
16
43
  class AlterTableBuilder {
17
44
  tableName;
18
45
  parentBuilder;
@@ -20,13 +47,11 @@ class AlterTableBuilder {
20
47
  this.tableName = tableName;
21
48
  this.parentBuilder = parentBuilder;
22
49
  }
23
- addColumn(name, callback) {
24
- const builder = new ColumnBuilder(name, { category: 'string' });
25
- callback(builder);
50
+ addColumn(callback) {
26
51
  this.parentBuilder.recordOperationSync({
27
52
  type: 'addColumn',
28
53
  tableName: this.tableName,
29
- column: builder.build(),
54
+ column: buildOneColumn(callback),
30
55
  });
31
56
  return this;
32
57
  }
@@ -47,28 +72,18 @@ class AlterTableBuilder {
47
72
  });
48
73
  return this;
49
74
  }
50
- alterColumn(name, callback) {
51
- const builder = new ColumnBuilder(name, { category: 'string' });
52
- callback(builder);
75
+ alterColumn(callback) {
76
+ const column = buildOneColumn(callback);
53
77
  this.parentBuilder.recordOperationSync({
54
78
  type: 'alterColumn',
55
79
  tableName: this.tableName,
56
- columnName: name,
57
- changes: builder.build(),
80
+ columnName: column.name,
81
+ changes: column,
58
82
  });
59
83
  return this;
60
84
  }
61
85
  addIndex(columns, options) {
62
- const indexName = options?.name ?? `idx_${this.tableName}_${columns.join('_')}`;
63
- this.parentBuilder.recordOperationSync({
64
- type: 'createIndex',
65
- tableName: this.tableName,
66
- index: {
67
- name: indexName,
68
- columns,
69
- unique: options?.unique ?? false,
70
- },
71
- });
86
+ this.parentBuilder.recordOperationSync(createIndexOperation(this.tableName, columns, options));
72
87
  return this;
73
88
  }
74
89
  dropIndex(name) {
@@ -142,13 +157,11 @@ export class OperationRecorder {
142
157
  // ============================================================================
143
158
  // Column Operations
144
159
  // ============================================================================
145
- async addColumn(tableName, columnName, callback) {
146
- const builder = new ColumnBuilder(columnName, { category: 'string' });
147
- callback(builder);
160
+ async addColumn(tableName, callback) {
148
161
  this.recordOperationSync({
149
162
  type: 'addColumn',
150
163
  tableName,
151
- column: builder.build(),
164
+ column: buildOneColumn(callback),
152
165
  });
153
166
  }
154
167
  async dropColumn(tableName, columnName) {
@@ -158,14 +171,13 @@ export class OperationRecorder {
158
171
  columnName,
159
172
  });
160
173
  }
161
- async alterColumn(tableName, columnName, callback) {
162
- const builder = new ColumnBuilder(columnName, { category: 'string' });
163
- callback(builder);
174
+ async alterColumn(tableName, callback) {
175
+ const column = buildOneColumn(callback);
164
176
  this.recordOperationSync({
165
177
  type: 'alterColumn',
166
178
  tableName,
167
- columnName,
168
- changes: builder.build(),
179
+ columnName: column.name,
180
+ changes: column,
169
181
  });
170
182
  }
171
183
  async renameColumn(tableName, oldName, newName) {
@@ -179,18 +191,8 @@ export class OperationRecorder {
179
191
  // ============================================================================
180
192
  // Index Operations
181
193
  // ============================================================================
182
- async createIndex(tableName, columns, options = {}) {
183
- const indexName = options.name ?? `idx_${tableName}_${columns.join('_')}`;
184
- this.recordOperationSync({
185
- type: 'createIndex',
186
- tableName,
187
- index: {
188
- name: indexName,
189
- columns,
190
- unique: options.unique ?? false,
191
- where: options.where,
192
- },
193
- });
194
+ async createIndex(tableName, columns, options) {
195
+ this.recordOperationSync(createIndexOperation(tableName, columns, options));
194
196
  }
195
197
  async dropIndex(tableName, indexName) {
196
198
  this.recordOperationSync({
@@ -260,10 +262,10 @@ export class OperationRecorder {
260
262
  export class MigrationBuilder extends OperationRecorder {
261
263
  querier;
262
264
  sqlGenerator;
263
- constructor(querier, options = {}) {
265
+ constructor(querier) {
264
266
  super();
265
267
  this.querier = querier;
266
- const generator = createSchemaGenerator(querier.dialect, options.namingStrategy);
268
+ const generator = createSchemaGenerator(querier.dialect);
267
269
  if (!generator) {
268
270
  throw new TypeError(`Could not find a schema generator for dialect: ${querier.dialect.dialectName}`);
269
271
  }
@@ -314,13 +316,11 @@ export class MigrationBuilder extends OperationRecorder {
314
316
  this.operations.push(operation);
315
317
  await this.execute(operation);
316
318
  }
317
- async addColumn(tableName, columnName, callback) {
318
- const builder = new ColumnBuilder(columnName, { category: 'string' });
319
- callback(builder);
319
+ async addColumn(tableName, callback) {
320
320
  const operation = {
321
321
  type: 'addColumn',
322
322
  tableName,
323
- column: builder.build(),
323
+ column: buildOneColumn(callback),
324
324
  };
325
325
  this.operations.push(operation);
326
326
  await this.execute(operation);
@@ -334,14 +334,13 @@ export class MigrationBuilder extends OperationRecorder {
334
334
  this.operations.push(operation);
335
335
  await this.execute(operation);
336
336
  }
337
- async alterColumn(tableName, columnName, callback) {
338
- const builder = new ColumnBuilder(columnName, { category: 'string' });
339
- callback(builder);
337
+ async alterColumn(tableName, callback) {
338
+ const column = buildOneColumn(callback);
340
339
  const operation = {
341
340
  type: 'alterColumn',
342
341
  tableName,
343
- columnName,
344
- changes: builder.build(),
342
+ columnName: column.name,
343
+ changes: column,
345
344
  };
346
345
  this.operations.push(operation);
347
346
  await this.execute(operation);
@@ -356,18 +355,8 @@ export class MigrationBuilder extends OperationRecorder {
356
355
  this.operations.push(operation);
357
356
  await this.execute(operation);
358
357
  }
359
- async createIndex(tableName, columns, options = {}) {
360
- const indexName = options.name ?? `idx_${tableName}_${columns.join('_')}`;
361
- const operation = {
362
- type: 'createIndex',
363
- tableName,
364
- index: {
365
- name: indexName,
366
- columns,
367
- unique: options.unique ?? false,
368
- where: options.where,
369
- },
370
- };
358
+ async createIndex(tableName, columns, options) {
359
+ const operation = createIndexOperation(tableName, columns, options);
371
360
  this.operations.push(operation);
372
361
  await this.execute(operation);
373
362
  }
@@ -420,7 +409,7 @@ export class MigrationBuilder extends OperationRecorder {
420
409
  }
421
410
  const sql = this.operationToSql(operation);
422
411
  if (sql) {
423
- for (const statement of splitSqlStatementsOnSemicolons(sql)) {
412
+ for (const statement of splitSqlStatements(sql)) {
424
413
  await this.querier.run(statement);
425
414
  }
426
415
  }
@@ -431,7 +420,7 @@ export class MigrationBuilder extends OperationRecorder {
431
420
  // One line per statement in preview; execute() runs each separately (#87).
432
421
  return this.getCreateTableStatements(operation).join('\n');
433
422
  case 'dropTable':
434
- return this.sqlGenerator.generateDropTableSql(operation.tableName, {
423
+ return this.sqlGenerator.generateDropTable(operation.tableName, {
435
424
  ifExists: operation.ifExists,
436
425
  cascade: operation.cascade,
437
426
  });
@@ -446,9 +435,9 @@ export class MigrationBuilder extends OperationRecorder {
446
435
  case 'alterColumn':
447
436
  return this.sqlGenerator.generateAlterColumnSql(operation.tableName, operation.columnName, operation.changes);
448
437
  case 'createIndex':
449
- return this.sqlGenerator.generateCreateIndexSql(operation.tableName, operation.index);
438
+ return this.sqlGenerator.generateCreateIndex(operation.tableName, operation.index);
450
439
  case 'dropIndex':
451
- return this.sqlGenerator.generateDropIndexSql(operation.tableName, operation.indexName);
440
+ return this.sqlGenerator.generateDropIndex(operation.tableName, operation.indexName);
452
441
  case 'addForeignKey':
453
442
  return this.sqlGenerator.generateAddForeignKeySql(operation.tableName, operation.foreignKey);
454
443
  case 'dropForeignKey':
@@ -460,10 +449,3 @@ export class MigrationBuilder extends OperationRecorder {
460
449
  }
461
450
  }
462
451
  }
463
- /**
464
- * Create an operation recorder for dry-run (recording only).
465
- * @deprecated Use `new OperationRecorder()` directly
466
- */
467
- export function createDryRunBuilder() {
468
- return new OperationRecorder();
469
- }
@@ -13,5 +13,3 @@
13
13
  * - Comments: -- and /* ... *\/
14
14
  */
15
15
  export declare function splitSqlStatements(sql: string): string[];
16
- /** Legacy alias kept for backward compatibility. */
17
- export declare const splitSqlStatementsOnSemicolons: typeof splitSqlStatements;
@@ -39,5 +39,3 @@ export function splitSqlStatements(sql) {
39
39
  }
40
40
  return statements;
41
41
  }
42
- /** Legacy alias kept for backward compatibility. */
43
- export const splitSqlStatementsOnSemicolons = splitSqlStatements;
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Fluent API for defining tables in migrations.
5
5
  */
6
+ import type { IndexColumnInput, IndexOptions } from '../../type/index.js';
6
7
  import type { BaseColumnOptions, DecimalColumnOptions, IColumnBuilder, ITableBuilder, ITableForeignKeyBuilder, StringColumnOptions, TableDefinition, VectorColumnOptions } from './types.js';
7
8
  /**
8
9
  * Builder for table definitions with a fluent API.
@@ -31,16 +32,25 @@ export declare class TableBuilder implements ITableBuilder {
31
32
  timestamp(name: string, options?: BaseColumnOptions): IColumnBuilder;
32
33
  timestamptz(name: string, options?: BaseColumnOptions): IColumnBuilder;
33
34
  json(name: string, options?: BaseColumnOptions): IColumnBuilder;
35
+ /** One canonical json category; the dialect decides between `JSON` and `JSONB`. */
34
36
  jsonb(name: string, options?: BaseColumnOptions): IColumnBuilder;
35
37
  uuid(name: string, options?: BaseColumnOptions): IColumnBuilder;
36
38
  blob(name: string, options?: BaseColumnOptions): IColumnBuilder;
37
39
  vector(name: string, options?: VectorColumnOptions): IColumnBuilder;
40
+ private add;
38
41
  createdAt(): IColumnBuilder;
39
42
  updatedAt(): IColumnBuilder;
40
43
  timestamps(): void;
41
44
  primaryKey(columns: string[]): this;
42
- unique(columns: string[], name?: string): this;
43
- index(columns: string[], name?: string): this;
45
+ unique(columns: readonly IndexColumnInput[], options?: string | IndexOptions): this;
46
+ index(columns: readonly IndexColumnInput[], options?: string | IndexOptions): this;
47
+ /**
48
+ * `@Index` and `table.index(...)` differ only in how the name is defaulted, so both normalize their
49
+ * entries here: the generator renders expressions and per-column modifiers from the normalized
50
+ * form, and anything left as a bare string would reach it as a column literally named `[object
51
+ * Object]`.
52
+ */
53
+ private addIndex;
44
54
  foreignKey(columns: string[]): ITableForeignKeyBuilder;
45
55
  comment(text: string): this;
46
56
  /**
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Fluent API for defining tables in migrations.
5
5
  */
6
+ import { normalizeIndexColumn } from '../../util/index.js';
6
7
  import { ColumnBuilder } from './columnBuilder.js';
7
8
  import { t } from './expressions.js';
8
9
  /**
@@ -68,137 +69,83 @@ export class TableBuilder {
68
69
  // Numeric Types
69
70
  // ============================================================================
70
71
  id(name = 'id', options = {}) {
71
- const col = new ColumnBuilder(name, { category: 'integer' }, { ...options, primaryKey: true, autoIncrement: true });
72
- this._columnBuilders.push(col);
73
- return col;
74
- }
75
- integer(name, options = {}) {
76
- const col = new ColumnBuilder(name, { category: 'integer' }, options);
77
- this._columnBuilders.push(col);
78
- return col;
79
- }
80
- smallint(name, options = {}) {
81
- const col = new ColumnBuilder(name, { category: 'integer', size: 'small' }, options);
82
- this._columnBuilders.push(col);
83
- return col;
84
- }
85
- bigint(name, options = {}) {
86
- const col = new ColumnBuilder(name, { category: 'integer', size: 'big' }, options);
87
- this._columnBuilders.push(col);
88
- return col;
89
- }
90
- float(name, options = {}) {
91
- const col = new ColumnBuilder(name, { category: 'float' }, options);
92
- this._columnBuilders.push(col);
93
- return col;
94
- }
95
- double(name, options = {}) {
96
- const col = new ColumnBuilder(name, { category: 'float', size: 'big' }, options);
97
- this._columnBuilders.push(col);
98
- return col;
72
+ return this.add(name, { category: 'integer' }, { ...options, primaryKey: true, autoIncrement: true });
73
+ }
74
+ integer(name, options) {
75
+ return this.add(name, { category: 'integer' }, options);
76
+ }
77
+ smallint(name, options) {
78
+ return this.add(name, { category: 'integer', size: 'small' }, options);
79
+ }
80
+ bigint(name, options) {
81
+ return this.add(name, { category: 'integer', size: 'big' }, options);
82
+ }
83
+ float(name, options) {
84
+ return this.add(name, { category: 'float' }, options);
85
+ }
86
+ double(name, options) {
87
+ return this.add(name, { category: 'float', size: 'big' }, options);
99
88
  }
100
89
  decimal(name, options = {}) {
101
90
  const { precision, scale, ...rest } = options;
102
- const col = new ColumnBuilder(name, { category: 'decimal', precision, scale }, rest);
103
- this._columnBuilders.push(col);
104
- return col;
91
+ return this.add(name, { category: 'decimal', precision, scale }, rest);
105
92
  }
106
- // ============================================================================
107
- // String Types
108
- // ============================================================================
109
93
  string(name, options = {}) {
110
94
  const { length = 255, ...rest } = options;
111
- const col = new ColumnBuilder(name, { category: 'string', length }, rest);
112
- this._columnBuilders.push(col);
113
- return col;
95
+ return this.add(name, { category: 'string', length }, rest);
114
96
  }
115
97
  char(name, options = {}) {
116
98
  const { length = 1, ...rest } = options;
117
- const col = new ColumnBuilder(name, { category: 'string', length }, rest);
118
- this._columnBuilders.push(col);
119
- return col;
99
+ return this.add(name, { category: 'string', length }, rest);
120
100
  }
121
- text(name, options = {}) {
122
- const col = new ColumnBuilder(name, { category: 'string' }, options);
123
- this._columnBuilders.push(col);
124
- return col;
101
+ text(name, options) {
102
+ return this.add(name, { category: 'string' }, options);
125
103
  }
126
- // ============================================================================
127
- // Boolean
128
- // ============================================================================
129
- boolean(name, options = {}) {
130
- const col = new ColumnBuilder(name, { category: 'boolean' }, options);
131
- this._columnBuilders.push(col);
132
- return col;
104
+ boolean(name, options) {
105
+ return this.add(name, { category: 'boolean' }, options);
133
106
  }
134
- // ============================================================================
135
- // Date/Time Types
136
- // ============================================================================
137
- date(name, options = {}) {
138
- const col = new ColumnBuilder(name, { category: 'date' }, options);
139
- this._columnBuilders.push(col);
140
- return col;
141
- }
142
- time(name, options = {}) {
143
- const col = new ColumnBuilder(name, { category: 'time' }, options);
144
- this._columnBuilders.push(col);
145
- return col;
146
- }
147
- timestamp(name, options = {}) {
148
- const col = new ColumnBuilder(name, { category: 'timestamp' }, options);
149
- this._columnBuilders.push(col);
150
- return col;
151
- }
152
- timestamptz(name, options = {}) {
153
- const col = new ColumnBuilder(name, { category: 'timestamp', withTimezone: true }, options);
154
- this._columnBuilders.push(col);
155
- return col;
107
+ date(name, options) {
108
+ return this.add(name, { category: 'date' }, options);
156
109
  }
157
- // ============================================================================
158
- // JSON Types
159
- // ============================================================================
160
- json(name, options = {}) {
161
- const col = new ColumnBuilder(name, { category: 'json' }, options);
162
- this._columnBuilders.push(col);
163
- return col;
110
+ time(name, options) {
111
+ return this.add(name, { category: 'time' }, options);
164
112
  }
165
- jsonb(name, options = {}) {
166
- // JSONB is the same category, dialect handles the difference
167
- const col = new ColumnBuilder(name, { category: 'json' }, options);
168
- this._columnBuilders.push(col);
169
- return col;
113
+ timestamp(name, options) {
114
+ return this.add(name, { category: 'timestamp' }, options);
170
115
  }
171
- // ============================================================================
172
- // Other Types
173
- // ============================================================================
174
- uuid(name, options = {}) {
175
- const col = new ColumnBuilder(name, { category: 'uuid' }, options);
176
- this._columnBuilders.push(col);
177
- return col;
116
+ timestamptz(name, options) {
117
+ return this.add(name, { category: 'timestamp', withTimezone: true }, options);
118
+ }
119
+ json(name, options) {
120
+ return this.add(name, { category: 'json' }, options);
121
+ }
122
+ /** One canonical json category; the dialect decides between `JSON` and `JSONB`. */
123
+ jsonb(name, options) {
124
+ return this.add(name, { category: 'json' }, options);
125
+ }
126
+ uuid(name, options) {
127
+ return this.add(name, { category: 'uuid' }, options);
178
128
  }
179
- blob(name, options = {}) {
180
- const col = new ColumnBuilder(name, { category: 'blob' }, options);
181
- this._columnBuilders.push(col);
182
- return col;
129
+ blob(name, options) {
130
+ return this.add(name, { category: 'blob' }, options);
183
131
  }
184
132
  vector(name, options = {}) {
185
133
  const { dimensions, ...rest } = options;
186
- const col = new ColumnBuilder(name, { category: 'vector', length: dimensions }, rest);
187
- this._columnBuilders.push(col);
188
- return col;
134
+ return this.add(name, { category: 'vector', length: dimensions }, rest);
135
+ }
136
+ add(name, type, options = {}) {
137
+ const column = new ColumnBuilder(name, type, options);
138
+ this._columnBuilders.push(column);
139
+ return column;
189
140
  }
190
141
  // ============================================================================
191
142
  // Convenience Methods
192
143
  // ============================================================================
193
144
  createdAt() {
194
- const col = new ColumnBuilder('createdAt', { category: 'timestamp' }, { defaultValue: t.now() });
195
- this._columnBuilders.push(col);
196
- return col;
145
+ return this.add('createdAt', { category: 'timestamp' }, { defaultValue: t.now() });
197
146
  }
198
147
  updatedAt() {
199
- const col = new ColumnBuilder('updatedAt', { category: 'timestamp' }, { defaultValue: t.now() });
200
- this._columnBuilders.push(col);
201
- return col;
148
+ return this.add('updatedAt', { category: 'timestamp' }, { defaultValue: t.now() });
202
149
  }
203
150
  timestamps() {
204
151
  this.createdAt();
@@ -211,21 +158,26 @@ export class TableBuilder {
211
158
  this._primaryKey = columns;
212
159
  return this;
213
160
  }
214
- unique(columns, name) {
215
- const indexName = name ?? `uq_${this._name}_${columns.join('_')}`;
216
- this._indexes.push({
217
- name: indexName,
218
- columns,
219
- unique: true,
220
- });
221
- return this;
161
+ unique(columns, options) {
162
+ return this.addIndex('uq', columns, options, true);
163
+ }
164
+ index(columns, options) {
165
+ return this.addIndex('idx', columns, options, false);
222
166
  }
223
- index(columns, name) {
224
- const indexName = name ?? `idx_${this._name}_${columns.join('_')}`;
167
+ /**
168
+ * `@Index` and `table.index(...)` differ only in how the name is defaulted, so both normalize their
169
+ * entries here: the generator renders expressions and per-column modifiers from the normalized
170
+ * form, and anything left as a bare string would reach it as a column literally named `[object
171
+ * Object]`.
172
+ */
173
+ addIndex(prefix, columns, options, unique) {
174
+ const { name, ...rest } = typeof options === 'string' ? { name: options } : (options ?? {});
175
+ const entries = columns.map(normalizeIndexColumn);
225
176
  this._indexes.push({
226
- name: indexName,
227
- columns,
228
- unique: false,
177
+ ...rest,
178
+ name: name ?? `${prefix}_${this._name}_${entries.map((entry) => entry.column).join('_')}`,
179
+ columns: entries,
180
+ unique,
229
181
  });
230
182
  return this;
231
183
  }
@@ -255,7 +207,7 @@ export class TableBuilder {
255
207
  if (!this._indexes.some((idx) => idx.name === indexName)) {
256
208
  this._indexes.push({
257
209
  name: indexName,
258
- columns: [col.name],
210
+ columns: [{ column: col.name }],
259
211
  unique: col.unique,
260
212
  });
261
213
  }