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.
- package/README.md +5 -4
- package/dist/bunSql/bunSqlCockroachDialect.d.ts +2 -2
- package/dist/bunSql/bunSqlCockroachDialect.js +4 -10
- package/dist/bunSql/bunSqlPostgresDialect.d.ts +2 -2
- package/dist/bunSql/bunSqlPostgresDialect.js +4 -10
- package/dist/cockroachdb/cockroachDialect.d.ts +20 -4
- package/dist/cockroachdb/cockroachDialect.js +33 -18
- package/dist/d1/d1Querier.d.ts +4 -3
- package/dist/d1/d1Querier.js +0 -3
- package/dist/d1/d1SqliteDialect.d.ts +7 -0
- package/dist/d1/d1SqliteDialect.js +9 -0
- package/dist/dialect/abstractDialect.d.ts +8 -3
- package/dist/dialect/abstractDialect.js +9 -4
- package/dist/dialect/abstractSqlDialect.d.ts +35 -7
- package/dist/dialect/abstractSqlDialect.js +76 -35
- package/dist/dialect/index.d.ts +1 -0
- package/dist/dialect/index.js +1 -0
- package/dist/dialect/indexSqlDialect.d.ts +57 -0
- package/dist/dialect/indexSqlDialect.js +101 -0
- package/dist/dialect/mysqlLikeSqlDialect.d.ts +16 -1
- package/dist/dialect/mysqlLikeSqlDialect.js +32 -1
- package/dist/dialect/pgLikeSqlDialect.d.ts +33 -15
- package/dist/dialect/pgLikeSqlDialect.js +90 -56
- package/dist/dialect/vectorCast.d.ts +21 -0
- package/dist/dialect/vectorCast.js +28 -0
- package/dist/dialect/vectorSqlDialect.d.ts +10 -3
- package/dist/dialect/vectorSqlDialect.js +19 -8
- package/dist/entity/decorator/index-decorator.d.ts +2 -9
- package/dist/entity/metadata/definition.d.ts +5 -4
- package/dist/entity/metadata/definition.js +4 -3
- package/dist/libsql/libsqlDialect.d.ts +12 -2
- package/dist/libsql/libsqlDialect.js +14 -2
- package/dist/libsql/libsqlQuerier.d.ts +9 -22
- package/dist/libsql/libsqlQuerier.js +9 -85
- package/dist/libsql/libsqlQuerierPool.d.ts +10 -8
- package/dist/libsql/libsqlQuerierPool.js +17 -15
- package/dist/maria/mariaDialect.d.ts +26 -4
- package/dist/maria/mariaDialect.js +54 -15
- package/dist/migrate/builder/migrationBuilder.d.ts +9 -29
- package/dist/migrate/builder/migrationBuilder.js +58 -76
- package/dist/migrate/builder/splitSqlStatements.d.ts +0 -2
- package/dist/migrate/builder/splitSqlStatements.js +0 -2
- package/dist/migrate/builder/tableBuilder.d.ts +12 -2
- package/dist/migrate/builder/tableBuilder.js +71 -119
- package/dist/migrate/builder/types.d.ts +30 -41
- package/dist/migrate/cli.d.ts +3 -2
- package/dist/migrate/cli.js +21 -48
- package/dist/migrate/codegen/entityCodeGenerator.d.ts +0 -4
- package/dist/migrate/codegen/entityCodeGenerator.js +5 -63
- package/dist/migrate/codegen/fieldOptionsSource.d.ts +10 -0
- package/dist/migrate/codegen/fieldOptionsSource.js +55 -0
- package/dist/migrate/codegen/index.d.ts +0 -2
- package/dist/migrate/codegen/index.js +0 -4
- package/dist/migrate/generator/indexNodeToSchema.d.ts +9 -0
- package/dist/migrate/generator/indexNodeToSchema.js +14 -0
- package/dist/migrate/generator/mongoCommand.d.ts +57 -0
- package/dist/migrate/generator/mongoCommand.js +26 -0
- package/dist/migrate/generator/mongoSchemaGenerator.d.ts +9 -20
- package/dist/migrate/generator/mongoSchemaGenerator.js +40 -82
- package/dist/migrate/index.d.ts +0 -1
- package/dist/migrate/index.js +0 -1
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.d.ts +25 -10
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js +46 -32
- package/dist/migrate/introspection/baseSqlIntrospector.d.ts +0 -1
- package/dist/migrate/introspection/baseSqlIntrospector.js +3 -12
- package/dist/migrate/introspection/mongoIntrospector.js +2 -2
- package/dist/migrate/introspection/mysqlIntrospector.d.ts +5 -8
- package/dist/migrate/introspection/mysqlIntrospector.js +4 -10
- package/dist/migrate/introspection/postgresIntrospector.d.ts +5 -8
- package/dist/migrate/introspection/postgresIntrospector.js +4 -10
- package/dist/migrate/introspection/sqliteIntrospector.d.ts +6 -5
- package/dist/migrate/introspection/sqliteIntrospector.js +26 -18
- package/dist/migrate/migrator.d.ts +23 -3
- package/dist/migrate/migrator.js +57 -69
- package/dist/migrate/schemaGenerator.d.ts +26 -37
- package/dist/migrate/schemaGenerator.js +69 -174
- package/dist/migrate/schemaGeneratorAsync.d.ts +2 -2
- package/dist/migrate/schemaGeneratorAsync.js +3 -3
- package/dist/migrate/storage/databaseStorage.js +4 -4
- package/dist/mongo/mongoDialect.d.ts +2 -0
- package/dist/mongo/mongoDialect.js +14 -3
- package/dist/mysql/mysqlDialect.d.ts +8 -0
- package/dist/mysql/mysqlDialect.js +13 -0
- package/dist/schema/canonicalType.d.ts +14 -2
- package/dist/schema/canonicalType.js +41 -31
- package/dist/schema/index.d.ts +1 -1
- package/dist/schema/schemaASTBuilder.d.ts +8 -1
- package/dist/schema/schemaASTBuilder.js +56 -47
- package/dist/schema/types.d.ts +10 -37
- package/dist/sqlite/abstractSqliteQuerier.d.ts +39 -0
- package/dist/sqlite/abstractSqliteQuerier.js +44 -0
- package/dist/sqlite/bunSqliteAdapter.bun.d.ts +26 -0
- package/dist/sqlite/bunSqliteAdapter.bun.js +25 -0
- package/dist/sqlite/hranaQuerier.d.ts +54 -0
- package/dist/sqlite/hranaQuerier.js +90 -0
- package/dist/sqlite/hranaQuerierPool.d.ts +21 -0
- package/dist/sqlite/hranaQuerierPool.js +25 -0
- package/dist/sqlite/index.d.ts +2 -1
- package/dist/sqlite/index.js +2 -1
- package/dist/sqlite/sqliteDialect.d.ts +18 -4
- package/dist/sqlite/sqliteDialect.js +24 -24
- package/dist/sqlite/sqliteQuerier.d.ts +16 -9
- package/dist/sqlite/sqliteQuerier.js +4 -27
- package/dist/sqlite/sqliteQuerierPool.d.ts +14 -4
- package/dist/sqlite/sqliteQuerierPool.js +16 -5
- package/dist/turso/index.d.ts +3 -0
- package/dist/turso/index.js +3 -0
- package/dist/turso/local.d.ts +3 -0
- package/dist/turso/local.js +3 -0
- package/dist/turso/tursoDialect.d.ts +15 -0
- package/dist/turso/tursoDialect.js +18 -0
- package/dist/turso/tursoLocalQuerier.d.ts +25 -0
- package/dist/turso/tursoLocalQuerier.js +20 -0
- package/dist/turso/tursoLocalQuerierPool.d.ts +32 -0
- package/dist/turso/tursoLocalQuerierPool.js +39 -0
- package/dist/turso/tursoQuerier.d.ts +10 -0
- package/dist/turso/tursoQuerier.js +10 -0
- package/dist/turso/tursoQuerierPool.d.ts +39 -0
- package/dist/turso/tursoQuerierPool.js +38 -0
- package/dist/type/config.d.ts +0 -6
- package/dist/type/dialect.d.ts +12 -4
- package/dist/type/dialect.js +7 -1
- package/dist/type/entity.d.ts +66 -5
- package/dist/type/migration.d.ts +32 -23
- package/dist/type/vector.d.ts +5 -2
- package/dist/util/index.d.ts +1 -0
- package/dist/util/index.js +1 -0
- package/dist/util/indexColumn.util.d.ts +6 -0
- package/dist/util/indexColumn.util.js +26 -0
- package/package.json +16 -3
- package/dist/migrate/codegen/entityMerger.d.ts +0 -114
- package/dist/migrate/codegen/entityMerger.js +0 -293
- package/dist/migrate/codegen/migrationCodeGenerator.d.ts +0 -61
- package/dist/migrate/codegen/migrationCodeGenerator.js +0 -355
- package/dist/migrate/generator/index.d.ts +0 -2
- package/dist/migrate/generator/index.js +0 -2
- package/dist/migrate/sync/index.d.ts +0 -6
- package/dist/migrate/sync/index.js +0 -6
- package/dist/migrate/sync/schemaSync.d.ts +0 -131
- package/dist/migrate/sync/schemaSync.js +0 -259
- package/dist/sqlite/betterSqlite3Dialect.d.ts +0 -9
- 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
|
|
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:
|
|
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:
|
|
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
|
-
*
|
|
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
|
|
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
|
|
365
|
-
unique(columns:
|
|
366
|
-
/** Add composite index */
|
|
367
|
-
index(columns:
|
|
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
|
|
393
|
-
addColumn(
|
|
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
|
-
/**
|
|
399
|
-
alterColumn(
|
|
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:
|
|
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
|
|
435
|
-
addColumn(tableName: string,
|
|
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
|
-
/**
|
|
439
|
-
alterColumn(tableName: string,
|
|
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:
|
|
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 */
|
package/dist/migrate/cli.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import type { AbstractDialect } from '../dialect/index.js';
|
|
3
|
-
import type {
|
|
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,
|
|
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>;
|
package/dist/migrate/cli.js
CHANGED
|
@@ -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,
|
|
15
|
-
return createSchemaGenerator(dialect,
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
//
|
|
218
|
-
if (
|
|
219
|
-
|
|
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
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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
|
|
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 --
|
|
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 {
|
|
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
|
|
187
|
-
|
|
188
|
-
|
|
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
|
|
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
|
}
|