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
@@ -4,7 +4,8 @@
4
4
  * Type definitions for the fluent migration builder API.
5
5
  * Enables type-safe migrations without raw SQL.
6
6
  */
7
- import type { CanonicalType, ForeignKeyAction, IndexType } from '../../schema/types.js';
7
+ import type { CanonicalType, ForeignKeyAction } from '../../schema/types.js';
8
+ import type { IndexColumnInput, IndexOptions, IndexSchema } from '../../type/index.js';
8
9
  /**
9
10
  * Foreign key reference options.
10
11
  */
@@ -110,21 +111,6 @@ export interface FullColumnDefinition extends ColumnDefinition {
110
111
  /** Index name (if indexed) */
111
112
  index?: string | boolean;
112
113
  }
113
- /**
114
- * Index definition.
115
- */
116
- export interface IndexDefinition {
117
- /** Index name */
118
- name: string;
119
- /** Column names */
120
- columns: string[];
121
- /** Whether unique */
122
- unique: boolean;
123
- /** Index type (btree, hash, etc.) */
124
- type?: IndexType;
125
- /** Partial index WHERE clause */
126
- where?: string;
127
- }
128
114
  /**
129
115
  * Complete table definition.
130
116
  */
@@ -136,7 +122,7 @@ export interface TableDefinition {
136
122
  /** Primary key columns (for composite keys) */
137
123
  primaryKey?: string[];
138
124
  /** Index definitions */
139
- indexes: IndexDefinition[];
125
+ indexes: IndexSchema[];
140
126
  /** Foreign key definitions at table level */
141
127
  foreignKeys: TableForeignKeyDefinition[];
142
128
  /** Table comment */
@@ -234,7 +220,7 @@ export interface RenameColumnOperation extends MigrationOperation {
234
220
  export interface CreateIndexOperation extends MigrationOperation {
235
221
  type: 'createIndex';
236
222
  tableName: string;
237
- index: IndexDefinition;
223
+ index: IndexSchema;
238
224
  ifNotExists?: boolean;
239
225
  }
240
226
  /**
@@ -310,9 +296,13 @@ export interface IForeignKeyBuilder extends IColumnBuilder {
310
296
  onUpdate(action: ForeignKeyAction): this;
311
297
  }
312
298
  /**
313
- * Interface for table builder (fluent API).
299
+ * The column vocabulary: every column type the builder can declare, name first.
300
+ *
301
+ * Split out of {@link ITableBuilder} so `addColumn`/`alterColumn` can hand it to their callback. They
302
+ * used to take an {@link IColumnBuilder}, which has no way to say what type a column is - so the
303
+ * builder hard-coded `VARCHAR`, and every column a generated migration added or altered was a string.
314
304
  */
315
- export interface ITableBuilder {
305
+ export interface IColumnFactory {
316
306
  /** Add an auto-incrementing primary key */
317
307
  id(name?: string, options?: BaseColumnOptions): IColumnBuilder;
318
308
  /** Add an integer column */
@@ -353,6 +343,11 @@ export interface ITableBuilder {
353
343
  blob(name: string, options?: BaseColumnOptions): IColumnBuilder;
354
344
  /** Add a vector column (for embeddings) */
355
345
  vector(name: string, options?: VectorColumnOptions): IColumnBuilder;
346
+ }
347
+ /**
348
+ * Interface for table builder (fluent API).
349
+ */
350
+ export interface ITableBuilder extends IColumnFactory {
356
351
  /** Add createdAt timestamp column */
357
352
  createdAt(): IColumnBuilder;
358
353
  /** Add updatedAt timestamp column */
@@ -361,10 +356,10 @@ export interface ITableBuilder {
361
356
  timestamps(): void;
362
357
  /** Add composite primary key */
363
358
  primaryKey(columns: string[]): this;
364
- /** Add composite unique constraint */
365
- unique(columns: string[], name?: string): this;
366
- /** Add composite index */
367
- index(columns: string[], name?: string): this;
359
+ /** Add a composite unique index; takes the same options as `@Index`, or just its name. */
360
+ unique(columns: readonly IndexColumnInput[], options?: string | IndexOptions): this;
361
+ /** Add a composite index; takes the same options as `@Index`, or just its name. */
362
+ index(columns: readonly IndexColumnInput[], options?: string | IndexOptions): this;
368
363
  /** Add table-level foreign key */
369
364
  foreignKey(columns: string[]): ITableForeignKeyBuilder;
370
365
  /** Add a comment to the table */
@@ -389,19 +384,16 @@ export interface ITableForeignKeyBuilder {
389
384
  * Interface for altering a table.
390
385
  */
391
386
  export interface IAlterTableBuilder {
392
- /** Add a column to the table */
393
- addColumn(name: string, callback: (column: IColumnBuilder) => void): this;
387
+ /** Add a column, declared exactly as in `createTable`: `addColumn((c) => c.timestamp('createdAt'))`. */
388
+ addColumn(callback: (columns: IColumnFactory) => IColumnBuilder): this;
394
389
  /** Drop a column from the table */
395
390
  dropColumn(name: string): this;
396
391
  /** Rename a column */
397
392
  renameColumn(oldName: string, newName: string): this;
398
- /** Alter a column definition */
399
- alterColumn(name: string, callback: (column: IColumnBuilder) => void): this;
393
+ /** Redeclare a column, named and typed as it should end up. */
394
+ alterColumn(callback: (columns: IColumnFactory) => IColumnBuilder): this;
400
395
  /** Add an index to the table */
401
- addIndex(columns: string[], options?: {
402
- name?: string;
403
- unique?: boolean;
404
- }): this;
396
+ addIndex(columns: readonly IndexColumnInput[], options?: IndexOptions): this;
405
397
  /** Drop an index from the table */
406
398
  dropIndex(name: string): this;
407
399
  /** Add a foreign key to the table */
@@ -431,19 +423,16 @@ export interface IMigrationBuilder {
431
423
  renameTable(oldName: string, newName: string): Promise<void>;
432
424
  /** Alter an existing table */
433
425
  alterTable(name: string, callback: (table: IAlterTableBuilder) => void): Promise<void>;
434
- /** Add a column to an existing table */
435
- addColumn(tableName: string, columnName: string, callback: (column: IColumnBuilder) => void): Promise<void>;
426
+ /** Add a column, declared exactly as in `createTable`: `addColumn('t', (c) => c.timestamp('at'))`. */
427
+ addColumn(tableName: string, callback: (columns: IColumnFactory) => IColumnBuilder): Promise<void>;
436
428
  /** Drop a column from a table */
437
429
  dropColumn(tableName: string, columnName: string): Promise<void>;
438
- /** Alter a column */
439
- alterColumn(tableName: string, columnName: string, callback: (column: IColumnBuilder) => void): Promise<void>;
430
+ /** Redeclare a column, named and typed as it should end up. */
431
+ alterColumn(tableName: string, callback: (columns: IColumnFactory) => IColumnBuilder): Promise<void>;
440
432
  /** Rename a column */
441
433
  renameColumn(tableName: string, oldName: string, newName: string): Promise<void>;
442
- /** Create an index */
443
- createIndex(tableName: string, columns: string[], options?: {
444
- name?: string;
445
- unique?: boolean;
446
- }): Promise<void>;
434
+ /** Create an index; takes the same options as `@Index`, so a generated migration can restate them. */
435
+ createIndex(tableName: string, columns: readonly IndexColumnInput[], options?: IndexOptions): Promise<void>;
447
436
  /** Drop an index */
448
437
  dropIndex(tableName: string, indexName: string): Promise<void>;
449
438
  /** Add a foreign key */
@@ -1,10 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import type { AbstractDialect } from '../dialect/index.js';
3
- import type { Config, NamingStrategy } from '../type/index.js';
3
+ import type { ForeignKeyAction } from '../schema/types.js';
4
+ import type { Config } from '../type/index.js';
4
5
  import { Migrator } from './migrator.js';
5
6
  import { createSchemaGeneratorAsync } from './schemaGeneratorAsync.js';
6
7
  /** Sync helper for SQL dialects only; returns `undefined` for MongoDB - use {@link createSchemaGeneratorAsync}. */
7
- export declare function getSchemaGenerator(dialect: AbstractDialect, namingStrategy?: NamingStrategy): import("../type/migration.js").SchemaGenerator | undefined;
8
+ export declare function getSchemaGenerator(dialect: AbstractDialect, defaultForeignKeyAction?: ForeignKeyAction): import("./schemaGenerator.js").SqlSchemaGenerator | undefined;
8
9
  export { createSchemaGeneratorAsync };
9
10
  export declare function main(args?: string[]): Promise<void>;
10
11
  export declare function runUp(migrator: Migrator, args: string[]): Promise<void>;
@@ -9,10 +9,9 @@ import { detectDrift } from './drift/driftDetector.js';
9
9
  import { Migrator } from './migrator.js';
10
10
  import { createSchemaGenerator } from './schemaGenerator.js';
11
11
  import { createSchemaGeneratorAsync } from './schemaGeneratorAsync.js';
12
- import { createSchemaSync } from './sync/schemaSync.js';
13
12
  /** Sync helper for SQL dialects only; returns `undefined` for MongoDB - use {@link createSchemaGeneratorAsync}. */
14
- export function getSchemaGenerator(dialect, namingStrategy) {
15
- return createSchemaGenerator(dialect, namingStrategy);
13
+ export function getSchemaGenerator(dialect, defaultForeignKeyAction) {
14
+ return createSchemaGenerator(dialect, defaultForeignKeyAction);
16
15
  }
17
16
  export { createSchemaGeneratorAsync };
18
17
  export async function main(args = process.argv.slice(2)) {
@@ -40,11 +39,11 @@ export async function main(args = process.argv.slice(2)) {
40
39
  tableName: config.tableName,
41
40
  logger: console.log,
42
41
  entities: config.entities,
43
- namingStrategy: config.namingStrategy,
42
+ defaultForeignKeyAction: config.defaultForeignKeyAction,
44
43
  };
45
44
  const migrator = new Migrator(config.pool, options);
46
45
  if (!migrator.schemaGenerator) {
47
- const generator = await createSchemaGeneratorAsync(config.pool.dialect, config.namingStrategy);
46
+ const generator = await createSchemaGeneratorAsync(config.pool.dialect, config.defaultForeignKeyAction);
48
47
  if (!generator) {
49
48
  throw new TypeError(`Could not find a schema generator for dialect: ${dialectName}`);
50
49
  }
@@ -191,49 +190,25 @@ export async function runGenerateFromEntities(migrator, args) {
191
190
  console.log(`\nCreated migration from entities: ${filePath}`);
192
191
  }
193
192
  export async function runSync(migrator, args, config) {
194
- const force = args.includes('--force');
195
- const push = args.includes('--push');
196
- const pull = args.includes('--pull');
197
- const dryRun = args.includes('--dry-run');
198
- // Parse direction
199
- let direction = 'bidirectional';
200
- for (let i = 0; i < args.length; i++) {
201
- if (args[i] === '--direction' && args[i + 1]) {
202
- direction = args[++i];
203
- }
204
- }
205
- // Shorthand flags
206
- if (push)
207
- direction = 'entity-to-db';
208
- if (pull)
209
- direction = 'db-to-entity';
210
- if (force) {
193
+ if (args.includes('--force')) {
211
194
  console.log('\n⚠️ WARNING: This will drop and recreate all tables!');
212
195
  console.log(' All data will be lost. This should only be used in development.\n');
213
- await migrator.sync({ force });
196
+ await migrator.sync({ force: true });
214
197
  console.log('\nSchema sync completed.');
215
198
  return;
216
199
  }
217
- // Use SchemaSync for direction-aware sync
218
- if (config.entities && migrator.schemaIntrospector) {
219
- const schemaSync = createSchemaSync({
220
- entities: config.entities,
221
- introspector: migrator.schemaIntrospector,
222
- direction,
223
- safe: !args.includes('--unsafe'),
224
- dryRun,
225
- });
226
- const result = await schemaSync.sync();
227
- console.log('\n' + result.summary);
228
- if (result.conflicts.length > 0) {
229
- console.log('\n⚠️ Conflicts require manual resolution.');
230
- process.exit(1);
231
- }
200
+ // Pulling the database into entity files is what `generate:from-db` does; one implementation.
201
+ if (args.includes('--pull')) {
202
+ return runGenerateFromDb(migrator, args, config);
232
203
  }
233
- else {
234
- await migrator.sync({ force: false });
235
- console.log('\nSchema sync completed.');
204
+ const safe = !args.includes('--unsafe');
205
+ if (args.includes('--dry-run')) {
206
+ const statements = await migrator.planSync({ safe, drop: !safe });
207
+ console.log(statements.length ? `\n${statements.join('\n')}` : '\nSchema is already in sync.');
208
+ return;
236
209
  }
210
+ await migrator.autoSync({ safe, drop: !safe, logging: true });
211
+ console.log('\nSchema sync completed.');
237
212
  }
238
213
  export async function runGenerateFromDb(migrator, args, config) {
239
214
  // Parse output directory
@@ -359,13 +334,11 @@ Commands:
359
334
  generate:from-db Generate TypeScript entities from database
360
335
  --output, -o <dir> Output directory (default: ./src/entities)
361
336
 
362
- sync Sync schema with direction support
337
+ sync Apply the entity schema to the database
338
+ --dry-run Print the statements instead of running them
339
+ --unsafe Allow destructive changes (drops, column alterations)
340
+ --pull Go the other way: generate entities from the database
363
341
  --force Drop and recreate all tables (dangerous!)
364
- --direction <mode> Sync direction: bidirectional, entity-to-db, db-to-entity
365
- --push Shorthand for --direction entity-to-db
366
- --pull Shorthand for --direction db-to-entity
367
- --dry-run Preview changes without applying
368
- --unsafe Allow destructive changes
369
342
 
370
343
  drift:check Check for schema drift between entities and database
371
344
 
@@ -391,7 +364,7 @@ Examples:
391
364
  uql-orm/migrate generate add_users_table
392
365
  uql-orm/migrate generate:entities initial_schema
393
366
  uql-orm/migrate generate:from-db --output ./src/entities
394
- uql-orm/migrate sync --push
367
+ uql-orm/migrate sync --dry-run
395
368
  uql-orm/migrate sync --pull
396
369
  uql-orm/migrate drift:check
397
370
  `);
@@ -105,10 +105,6 @@ export declare class EntityCodeGenerator {
105
105
  * Format type for description.
106
106
  */
107
107
  private formatTypeDescription;
108
- /**
109
- * Format default value for code.
110
- */
111
- private formatDefaultValue;
112
108
  /**
113
109
  * Default class name transformer: table_name -> TableName (PascalCase, singular).
114
110
  */
@@ -9,8 +9,9 @@
9
9
  * - Indexes
10
10
  * - JSDoc comments for sync-added fields
11
11
  */
12
- import { canonicalToColumnType, canonicalToTypeScript } from '../../schema/canonicalType.js';
12
+ import { canonicalToTypeScript } from '../../schema/canonicalType.js';
13
13
  import { camelCase, pascalCase, singularize } from '../../util/string.util.js';
14
+ import { buildFieldOptionsSource } from './fieldOptionsSource.js';
14
15
  /**
15
16
  * Generates TypeScript entity code from SchemaAST.
16
17
  */
@@ -183,44 +184,9 @@ export class EntityCodeGenerator {
183
184
  * Build Field decorator options.
184
185
  */
185
186
  buildFieldOptions(col) {
186
- const options = [];
187
- // Column type
188
- const columnType = canonicalToColumnType(col.type);
189
- if (columnType) {
190
- options.push(`columnType: '${columnType}'`);
191
- }
192
- // Length
193
- if (col.type.length && col.type.category === 'string') {
194
- options.push(`length: ${col.type.length}`);
195
- }
196
- // Precision and scale
197
- if (col.type.precision) {
198
- options.push(`precision: ${col.type.precision}`);
199
- if (col.type.scale) {
200
- options.push(`scale: ${col.type.scale}`);
201
- }
202
- }
203
- // Nullable
204
- if (col.nullable) {
205
- options.push('nullable: true');
206
- }
207
- // Unique
208
- if (col.isUnique) {
209
- options.push('unique: true');
210
- }
211
- // Default value
212
- if (col.defaultValue !== undefined) {
213
- options.push(`defaultValue: ${this.formatDefaultValue(col.defaultValue)}`);
214
- }
215
- // Index (single column)
216
- if (this.options.includeIndexes) {
217
- const indexes = this.ast.getTableIndexes(col.table.name);
218
- const singleColIndex = indexes.find((idx) => idx.columns.length === 1 && idx.columns[0].name === col.name);
219
- if (singleColIndex) {
220
- options.push(`index: '${singleColIndex.name}'`);
221
- }
222
- }
223
- return options.length > 0 ? `{ ${options.join(', ')} }` : '';
187
+ const indexes = this.options.includeIndexes ? this.ast.getTableIndexes(col.table.name) : [];
188
+ const singleColIndex = indexes.find((idx) => idx.columns.length === 1 && idx.columns[0].name === col.name);
189
+ return buildFieldOptionsSource(col, singleColIndex?.name);
224
190
  }
225
191
  /**
226
192
  * Build relation definitions.
@@ -340,30 +306,6 @@ export class EntityCodeGenerator {
340
306
  desc += ' UNSIGNED';
341
307
  return desc;
342
308
  }
343
- /**
344
- * Format default value for code.
345
- */
346
- formatDefaultValue(value) {
347
- if (typeof value === 'string') {
348
- // Check for SQL expressions
349
- if (value.includes('(') ||
350
- value.toUpperCase() === 'CURRENT_TIMESTAMP' ||
351
- value.toUpperCase().includes('NEXTVAL')) {
352
- return `'${value}'`; // Keep as string for expressions
353
- }
354
- return `'${value.replace(/'/g, "\\'")}'`;
355
- }
356
- if (typeof value === 'boolean') {
357
- return value.toString();
358
- }
359
- if (typeof value === 'number') {
360
- return value.toString();
361
- }
362
- if (value === null) {
363
- return 'null';
364
- }
365
- return JSON.stringify(value);
366
- }
367
309
  /**
368
310
  * Default class name transformer: table_name -> TableName (PascalCase, singular).
369
311
  */
@@ -0,0 +1,10 @@
1
+ import type { ColumnNode } from '../../schema/types.js';
2
+ /**
3
+ * A column's `@Field({ ... })` options as source, or `''` when it needs none.
4
+ *
5
+ * Shared by the entity generator and the merger because they emit the same decorator. They each had
6
+ * their own copy, and the copies had drifted: the merger's dropped `unique` and `defaultValue`, so
7
+ * merging a column into an existing entity file quietly produced a weaker field than generating the
8
+ * file from scratch.
9
+ */
10
+ export declare function buildFieldOptionsSource(col: ColumnNode, indexName?: string): string;
@@ -0,0 +1,55 @@
1
+ import { canonicalToColumnType } from '../../schema/canonicalType.js';
2
+ /**
3
+ * A column's `@Field({ ... })` options as source, or `''` when it needs none.
4
+ *
5
+ * Shared by the entity generator and the merger because they emit the same decorator. They each had
6
+ * their own copy, and the copies had drifted: the merger's dropped `unique` and `defaultValue`, so
7
+ * merging a column into an existing entity file quietly produced a weaker field than generating the
8
+ * file from scratch.
9
+ */
10
+ export function buildFieldOptionsSource(col, indexName) {
11
+ const options = [];
12
+ const columnType = canonicalToColumnType(col.type);
13
+ if (columnType) {
14
+ options.push(`columnType: '${columnType}'`);
15
+ }
16
+ if (col.type.length && col.type.category === 'string') {
17
+ options.push(`length: ${col.type.length}`);
18
+ }
19
+ if (col.type.precision !== undefined) {
20
+ options.push(`precision: ${col.type.precision}`);
21
+ if (col.type.scale !== undefined) {
22
+ options.push(`scale: ${col.type.scale}`);
23
+ }
24
+ }
25
+ if (col.nullable) {
26
+ options.push('nullable: true');
27
+ }
28
+ if (col.isUnique) {
29
+ options.push('unique: true');
30
+ }
31
+ if (col.defaultValue !== undefined) {
32
+ options.push(`defaultValue: ${formatDefaultValueSource(col.defaultValue)}`);
33
+ }
34
+ if (indexName) {
35
+ options.push(`index: '${indexName}'`);
36
+ }
37
+ return options.length > 0 ? `{ ${options.join(', ')} }` : '';
38
+ }
39
+ /**
40
+ * A default value as source. Strings stay single-quoted, expressions included: `defaultValue: 'now()'`
41
+ * is what reaches the DDL. The generator used to branch on `CURRENT_TIMESTAMP`/`NEXTVAL`/`(` first, but
42
+ * both branches emitted a quoted string and only the fallthrough escaped embedded quotes.
43
+ */
44
+ function formatDefaultValueSource(value) {
45
+ if (typeof value === 'string') {
46
+ return `'${value.replace(/'/g, "\\'")}'`;
47
+ }
48
+ if (typeof value === 'boolean' || typeof value === 'number') {
49
+ return value.toString();
50
+ }
51
+ if (value === null) {
52
+ return 'null';
53
+ }
54
+ return JSON.stringify(value);
55
+ }
@@ -4,7 +4,5 @@
4
4
  * Generates TypeScript entity code from database schemas.
5
5
  */
6
6
  export { createEntityCodeGenerator, EntityCodeGenerator, type EntityCodeGeneratorOptions, type GeneratedEntity, } from './entityCodeGenerator.js';
7
- export { createEntityMerger, EntityMerger, type EntityMergerOptions, type FieldToAdd, type FieldToDeprecate, type MergeResult, } from './entityMerger.js';
8
- export { createMigrationCodeGenerator, type GeneratedMigration, MigrationCodeGenerator, type MigrationCodeOptions, } from './migrationCodeGenerator.js';
9
7
  export { buildSqlQuerierMigrationModule, EMPTY_MANUAL_MIGRATION_DOWN_INNER, EMPTY_MANUAL_MIGRATION_UP_INNER, emitSqlRunCall, emitSqlRunCalls, type SqlMigrationModuleOptions, } from './migrationFile.js';
10
8
  export { createRelationDetector, type RelationDetectorOptions, SmartRelationDetector, } from './smartRelationDetector.js';
@@ -5,10 +5,6 @@
5
5
  */
6
6
  // Entity code generator
7
7
  export { createEntityCodeGenerator, EntityCodeGenerator, } from './entityCodeGenerator.js';
8
- // Entity merger
9
- export { createEntityMerger, EntityMerger, } from './entityMerger.js';
10
- // Migration code generator
11
- export { createMigrationCodeGenerator, MigrationCodeGenerator, } from './migrationCodeGenerator.js';
12
8
  export { buildSqlQuerierMigrationModule, EMPTY_MANUAL_MIGRATION_DOWN_INNER, EMPTY_MANUAL_MIGRATION_UP_INNER, emitSqlRunCall, emitSqlRunCalls, } from './migrationFile.js';
13
9
  // Smart relation detector
14
10
  export { createRelationDetector, SmartRelationDetector, } from './smartRelationDetector.js';
@@ -0,0 +1,9 @@
1
+ import type { IndexNode } from '../../schema/types.js';
2
+ import type { IndexSchema } from '../../type/index.js';
3
+ /**
4
+ * An AST index as the generators and dialects want it. Spread rather than copied field by field:
5
+ * rebuilding it by hand is how the partial-index `where` once vanished without a trace. The node-only
6
+ * keys (`table`, `source`, `syncStatus`) are ignored downstream, and the vector type travels along
7
+ * because pgvector's operator-class names are built from it.
8
+ */
9
+ export declare function indexNodeToSchema(index: IndexNode): IndexSchema;
@@ -0,0 +1,14 @@
1
+ import { isVectorCategory } from '../../schema/canonicalType.js';
2
+ /**
3
+ * An AST index as the generators and dialects want it. Spread rather than copied field by field:
4
+ * rebuilding it by hand is how the partial-index `where` once vanished without a trace. The node-only
5
+ * keys (`table`, `source`, `syncStatus`) are ignored downstream, and the vector type travels along
6
+ * because pgvector's operator-class names are built from it.
7
+ */
8
+ export function indexNodeToSchema(index) {
9
+ return {
10
+ ...index,
11
+ columns: index.entries ?? index.columns.map((col) => ({ column: col.name })),
12
+ vectorType: index.columns.map((col) => col.type?.category).find(isVectorCategory),
13
+ };
14
+ }
@@ -0,0 +1,57 @@
1
+ /** The direction, or `'text'`, of one field in a MongoDB index key spec. */
2
+ export type MongoIndexKey = Record<string, 1 | -1 | 'text'>;
3
+ /**
4
+ * `SchemaGenerator` yields one string per statement, so {@link MongoSchemaGenerator} emits its
5
+ * commands as JSON and this is their schema.
6
+ *
7
+ * Declared next to the generator that writes them because the migrator used to restate the shape
8
+ * inline from `JSON.parse`, with `cmd.name!` assertions and a bare `action: string` - where a command
9
+ * it had no branch for (`renameCollection`) was silently a no-op.
10
+ */
11
+ export type MongoCommand = {
12
+ readonly action: 'createCollection';
13
+ readonly name: string;
14
+ } | {
15
+ readonly action: 'dropCollection';
16
+ readonly name: string;
17
+ } | {
18
+ readonly action: 'renameCollection';
19
+ readonly from: string;
20
+ readonly to: string;
21
+ } | {
22
+ readonly action: 'createIndex';
23
+ readonly collection: string;
24
+ readonly name: string;
25
+ readonly key: MongoIndexKey;
26
+ readonly options: {
27
+ readonly unique: boolean;
28
+ readonly name: string;
29
+ };
30
+ } | {
31
+ readonly action: 'dropIndex';
32
+ readonly collection: string;
33
+ readonly name: string;
34
+ };
35
+ export declare function serializeMongoCommand(command: MongoCommand): string;
36
+ /**
37
+ * What executing these commands needs of a database handle. Declared structurally rather than as the
38
+ * driver's `Db` so this module carries no dependency on the optional `mongodb` peer, and so a test can
39
+ * satisfy it with a plain object.
40
+ */
41
+ export type MongoCommandTarget = {
42
+ createCollection(name: string): Promise<unknown>;
43
+ renameCollection(from: string, to: string): Promise<unknown>;
44
+ collection(name: string): {
45
+ drop(): Promise<unknown>;
46
+ createIndex(key: MongoIndexKey, options: {
47
+ unique: boolean;
48
+ name: string;
49
+ }): Promise<unknown>;
50
+ dropIndex(name: string): Promise<unknown>;
51
+ };
52
+ };
53
+ /**
54
+ * Execute one emitted command. The single cast lives here, where the union it casts to is defined
55
+ * alongside the only code that writes these strings.
56
+ */
57
+ export declare function runMongoCommand(db: MongoCommandTarget, statement: string): Promise<unknown>;
@@ -0,0 +1,26 @@
1
+ export function serializeMongoCommand(command) {
2
+ return JSON.stringify(command);
3
+ }
4
+ /**
5
+ * Execute one emitted command. The single cast lives here, where the union it casts to is defined
6
+ * alongside the only code that writes these strings.
7
+ */
8
+ export function runMongoCommand(db, statement) {
9
+ const command = JSON.parse(statement);
10
+ switch (command.action) {
11
+ case 'createCollection':
12
+ return db.createCollection(command.name);
13
+ case 'dropCollection':
14
+ return db.collection(command.name).drop();
15
+ case 'renameCollection':
16
+ return db.renameCollection(command.from, command.to);
17
+ case 'createIndex':
18
+ return db.collection(command.collection).createIndex(command.key, command.options);
19
+ case 'dropIndex':
20
+ return db.collection(command.collection).dropIndex(command.name);
21
+ default:
22
+ // Unreachable for a command this module produced; a hand-written statement lands here rather
23
+ // than being silently skipped, which is how `renameCollection` went unnoticed.
24
+ throw new TypeError(`unsupported MongoDB migration command: ${statement}`);
25
+ }
26
+ }
@@ -11,38 +11,27 @@ export declare class MongoSchemaGenerator extends AbstractDialect implements Sch
11
11
  generateCreateTable<E>(entity: Type<E>, _options?: {
12
12
  ifNotExists?: boolean;
13
13
  }): string[];
14
- generateDropTable<E>(entity: Type<E>): string;
14
+ generateDropTable(tableName: string): string;
15
15
  generateAlterTable(diff: SchemaDiff): string[];
16
16
  generateAlterTableDown(diff: SchemaDiff): string[];
17
+ /**
18
+ * MongoDB's key spec is where its index options live: `-1` for a descending entry and `'text'` for a
19
+ * full-text index, which is what `$text` needs since a text index declares its own fields.
20
+ *
21
+ * @remarks The SQL-only modifiers are refused rather than dropped, for the same reason the SQL
22
+ * dialects refuse each other's - a silently weaker index is worse than a clear failure. `where`
23
+ * included: MongoDB's partial indexes take a filter document, not a SQL predicate.
24
+ */
17
25
  generateCreateIndex(tableName: string, index: IndexSchema): string;
18
26
  generateDropIndex(tableName: string, indexName: string): string;
19
27
  getSqlType(fieldOptions: FieldOptions, fieldType?: unknown): string;
20
- getBooleanType(): string;
21
- generateColumnDefinitions(): string[];
22
- generateColumnDefinition(): string;
23
- generateColumnDefinitionFromSchema(): string;
24
- generateTableConstraints(): string[];
25
- generateAlterColumnStatements(): string[];
26
- getTableOptions(): string;
27
- generateColumnComment(): string;
28
- formatDefaultValue(): string;
29
28
  generateCreateTableFromNode(table: TableNode, _options?: {
30
29
  ifNotExists?: boolean;
31
30
  }): string[];
32
31
  generateCreateIndexFromNode(index: IndexNode): string;
33
- generateDropTableFromNode(table: TableNode): string;
34
32
  generateCreateTableFromDefinition(table: TableDefinition, _options?: {
35
33
  ifNotExists?: boolean;
36
34
  }): string[];
37
- generateDropTableSql(tableName: string): string;
38
35
  generateRenameTableSql(oldName: string, newName: string): string;
39
- generateAddColumnSql(): string;
40
- generateDropColumnSql(): string;
41
- generateRenameColumnSql(): string;
42
- generateAlterColumnSql(): string;
43
- generateCreateIndexSql(tableName: string, index: IndexSchema): string;
44
- generateDropIndexSql(tableName: string, indexName: string): string;
45
- generateAddForeignKeySql(): string;
46
- generateDropForeignKeySql(): string;
47
36
  diffSchema<E>(entity: Type<E>, currentTable: TableNode | undefined): SchemaDiff | undefined;
48
37
  }