uql-orm 0.21.0 → 0.23.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/browser/uql-browser.min.js.map +3 -3
- 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 +49 -8
- package/dist/dialect/abstractSqlDialect.js +95 -47
- 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 +26 -1
- package/dist/dialect/mysqlLikeSqlDialect.js +57 -1
- package/dist/dialect/pgLikeSqlDialect.d.ts +37 -22
- package/dist/dialect/pgLikeSqlDialect.js +97 -68
- 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/bag.d.ts +35 -0
- package/dist/entity/decorator/bag.js +54 -0
- package/dist/entity/decorator/entity.d.ts +28 -2
- package/dist/entity/decorator/entity.js +40 -2
- package/dist/entity/decorator/members.d.ts +51 -0
- package/dist/entity/decorator/members.js +51 -0
- package/dist/entity/index.d.ts +3 -1
- package/dist/entity/index.js +3 -1
- package/dist/entity/metadata/definition.d.ts +23 -8
- package/dist/entity/metadata/definition.js +56 -100
- package/dist/http/contract.js +1 -2
- package/dist/http/handler.js +5 -26
- package/dist/http/query.js +1 -1
- 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/acquireQuerierForMigrations.d.ts +13 -1
- package/dist/migrate/acquireQuerierForMigrations.js +28 -0
- 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-config.js +24 -8
- package/dist/migrate/cli.d.ts +3 -2
- package/dist/migrate/cli.js +26 -49
- package/dist/migrate/codegen/entityCodeGenerator.d.ts +0 -4
- package/dist/migrate/codegen/entityCodeGenerator.js +8 -67
- 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 -3
- package/dist/migrate/codegen/index.js +0 -6
- package/dist/migrate/drift/driftDetector.d.ts +10 -1
- package/dist/migrate/drift/driftDetector.js +22 -5
- 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 +30 -11
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js +61 -57
- package/dist/migrate/introspection/baseSqlIntrospector.d.ts +0 -1
- package/dist/migrate/introspection/baseSqlIntrospector.js +3 -12
- package/dist/migrate/introspection/mongoIntrospector.js +9 -15
- 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 +101 -150
- 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.d.ts +2 -0
- package/dist/migrate/storage/databaseStorage.js +12 -27
- package/dist/mongo/mongoDialect.d.ts +2 -0
- package/dist/mongo/mongoDialect.js +14 -3
- package/dist/mongo/mongodbQuerier.js +171 -229
- package/dist/mysql/mysqlDialect.d.ts +8 -0
- package/dist/mysql/mysqlDialect.js +13 -0
- package/dist/nestjs/uqlContextInterceptor.js +58 -22
- package/dist/nestjs/uqlModule.d.ts +2 -11
- package/dist/nestjs/uqlModule.js +93 -44
- package/dist/postgres/postgresDialect.js +2 -2
- package/dist/querier/abstractQuerier.d.ts +28 -0
- package/dist/querier/abstractQuerier.js +47 -22
- package/dist/querier/abstractQuerierPool.d.ts +3 -0
- package/dist/querier/abstractQuerierPool.js +5 -3
- package/dist/querier/abstractSqlQuerier.d.ts +1 -3
- package/dist/querier/abstractSqlQuerier.js +48 -96
- package/dist/querier/index.d.ts +3 -1
- package/dist/querier/index.js +3 -1
- package/dist/querier/querierContext.browser.d.ts +12 -0
- package/dist/querier/querierContext.browser.js +18 -0
- package/dist/querier/querierContext.d.ts +22 -0
- package/dist/querier/querierContext.js +42 -0
- package/dist/querier/queryError.d.ts +22 -0
- package/dist/querier/queryError.js +20 -0
- package/dist/querier/transactional.d.ts +26 -0
- package/dist/querier/transactional.js +43 -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 +9 -2
- package/dist/schema/schemaASTBuilder.js +58 -49
- package/dist/schema/types.d.ts +10 -58
- package/dist/sqlite/abstractSqliteQuerier.d.ts +46 -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 +68 -0
- package/dist/sqlite/hranaQuerierPool.d.ts +21 -0
- package/dist/sqlite/hranaQuerierPool.js +25 -0
- package/dist/sqlite/index.d.ts +3 -1
- package/dist/sqlite/index.js +3 -1
- package/dist/sqlite/localSqliteQuerierPool.d.ts +31 -0
- package/dist/sqlite/localSqliteQuerierPool.js +34 -0
- package/dist/sqlite/nodeSqliteAdapter.d.ts +35 -0
- package/dist/sqlite/nodeSqliteAdapter.js +28 -0
- package/dist/sqlite/nodeSqliteQuerierPool.d.ts +28 -0
- package/dist/sqlite/nodeSqliteQuerierPool.js +29 -0
- package/dist/sqlite/sqliteDialect.d.ts +18 -5
- package/dist/sqlite/sqliteDialect.js +23 -36
- package/dist/sqlite/sqliteQuerier.d.ts +16 -9
- package/dist/sqlite/sqliteQuerier.js +4 -27
- package/dist/sqlite/sqliteQuerierPool.d.ts +11 -14
- package/dist/sqlite/sqliteQuerierPool.js +16 -24
- 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 +154 -26
- package/dist/type/migration.d.ts +32 -23
- package/dist/type/querier.d.ts +6 -0
- package/dist/type/vector.d.ts +5 -2
- package/dist/util/hook.util.js +1 -1
- 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 +21 -16
- package/dist/entity/decorator/field.d.ts +0 -2
- package/dist/entity/decorator/field.js +0 -7
- package/dist/entity/decorator/filter.d.ts +0 -7
- package/dist/entity/decorator/filter.js +0 -11
- package/dist/entity/decorator/hook.d.ts +0 -7
- package/dist/entity/decorator/hook.js +0 -14
- package/dist/entity/decorator/id.d.ts +0 -2
- package/dist/entity/decorator/id.js +0 -7
- package/dist/entity/decorator/index-decorator.d.ts +0 -29
- package/dist/entity/decorator/index-decorator.js +0 -26
- package/dist/entity/decorator/index.d.ts +0 -8
- package/dist/entity/decorator/index.js +0 -8
- package/dist/entity/decorator/relation.d.ts +0 -8
- package/dist/entity/decorator/relation.js +0 -19
- 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/codegen/smartRelationDetector.d.ts +0 -47
- package/dist/migrate/codegen/smartRelationDetector.js +0 -134
- 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/querier/decorator/index.d.ts +0 -4
- package/dist/querier/decorator/index.js +0 -4
- package/dist/querier/decorator/injectQuerier.d.ts +0 -3
- package/dist/querier/decorator/injectQuerier.js +0 -33
- package/dist/querier/decorator/log.d.ts +0 -32
- package/dist/querier/decorator/log.js +0 -52
- package/dist/querier/decorator/serialized.d.ts +0 -6
- package/dist/querier/decorator/serialized.js +0 -13
- package/dist/querier/decorator/transactional.d.ts +0 -6
- package/dist/querier/decorator/transactional.js +0 -48
- package/dist/sqlite/betterSqlite3Dialect.d.ts +0 -9
- package/dist/sqlite/betterSqlite3Dialect.js +0 -9
|
@@ -1,355 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Migration Code Generator
|
|
3
|
-
*
|
|
4
|
-
* Generates TypeScript migration code from SchemaDiff.
|
|
5
|
-
* This enables auto-generating migrations from entity changes.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Generates TypeScript migration code from schema diffs.
|
|
9
|
-
*/
|
|
10
|
-
export class MigrationCodeGenerator {
|
|
11
|
-
indent;
|
|
12
|
-
includeComments;
|
|
13
|
-
constructor(options = {}) {
|
|
14
|
-
this.indent = options.indent ?? ' ';
|
|
15
|
-
this.includeComments = options.includeComments ?? true;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Generate migration code from a single SchemaDiff.
|
|
19
|
-
*/
|
|
20
|
-
generate(diff) {
|
|
21
|
-
const description = this.generateDescription(diff);
|
|
22
|
-
if (diff.type === 'create') {
|
|
23
|
-
return {
|
|
24
|
-
up: this.generateCreateTable(diff),
|
|
25
|
-
down: this.generateDropTable(diff.tableName),
|
|
26
|
-
description,
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
if (diff.type === 'drop') {
|
|
30
|
-
return {
|
|
31
|
-
up: this.generateDropTable(diff.tableName),
|
|
32
|
-
down: '// Cannot auto-generate: original table structure unknown',
|
|
33
|
-
description,
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
// alter
|
|
37
|
-
return {
|
|
38
|
-
up: this.generateAlterUp(diff),
|
|
39
|
-
down: this.generateAlterDown(diff),
|
|
40
|
-
description,
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Generate migration code from multiple diffs.
|
|
45
|
-
*/
|
|
46
|
-
generateAll(diffs) {
|
|
47
|
-
const ups = [];
|
|
48
|
-
const downs = [];
|
|
49
|
-
const descriptions = [];
|
|
50
|
-
for (const diff of diffs) {
|
|
51
|
-
const result = this.generate(diff);
|
|
52
|
-
ups.push(result.up);
|
|
53
|
-
downs.push(result.down);
|
|
54
|
-
descriptions.push(result.description);
|
|
55
|
-
}
|
|
56
|
-
return {
|
|
57
|
-
up: ups.join('\n\n'),
|
|
58
|
-
down: downs.reverse().join('\n\n'), // Reverse for correct rollback order
|
|
59
|
-
description: descriptions.join('; '),
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Generate a complete migration file template.
|
|
64
|
-
*/
|
|
65
|
-
generateFile(diffs, name) {
|
|
66
|
-
const { up, down, description } = this.generateAll(diffs);
|
|
67
|
-
const timestamp = new Date()
|
|
68
|
-
.toISOString()
|
|
69
|
-
.replace(/[-:T.Z]/g, '')
|
|
70
|
-
.slice(0, 14);
|
|
71
|
-
const migrationName = name ?? `migration_${timestamp}`;
|
|
72
|
-
return `/**
|
|
73
|
-
* Migration: ${migrationName}
|
|
74
|
-
* ${description}
|
|
75
|
-
*
|
|
76
|
-
* Generated at: ${new Date().toISOString()}
|
|
77
|
-
*/
|
|
78
|
-
|
|
79
|
-
import type { IMigrationBuilder } from 'uql-orm';
|
|
80
|
-
|
|
81
|
-
export async function up(builder: IMigrationBuilder): Promise<void> {
|
|
82
|
-
${this.indentBlock(up, 1)}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export async function down(builder: IMigrationBuilder): Promise<void> {
|
|
86
|
-
${this.indentBlock(down, 1)}
|
|
87
|
-
}
|
|
88
|
-
`;
|
|
89
|
-
}
|
|
90
|
-
// ===========================================================================
|
|
91
|
-
// Private: Code Generation
|
|
92
|
-
// ===========================================================================
|
|
93
|
-
generateCreateTable(diff) {
|
|
94
|
-
const columns = diff.columnsToAdd ?? [];
|
|
95
|
-
const lines = [];
|
|
96
|
-
lines.push(`await builder.createTable('${diff.tableName}', (table) => {`);
|
|
97
|
-
for (const col of columns) {
|
|
98
|
-
lines.push(`${this.indent}${this.generateColumnCall(col)};`);
|
|
99
|
-
}
|
|
100
|
-
// Add indexes if any
|
|
101
|
-
for (const idx of diff.indexesToAdd ?? []) {
|
|
102
|
-
lines.push(`${this.indent}${this.generateIndexCall(idx)};`);
|
|
103
|
-
}
|
|
104
|
-
lines.push('});');
|
|
105
|
-
return lines.join('\n');
|
|
106
|
-
}
|
|
107
|
-
generateDropTable(tableName) {
|
|
108
|
-
return `await builder.dropTable('${tableName}');`;
|
|
109
|
-
}
|
|
110
|
-
generateAlterUp(diff) {
|
|
111
|
-
const lines = [];
|
|
112
|
-
// Add columns
|
|
113
|
-
for (const col of diff.columnsToAdd ?? []) {
|
|
114
|
-
lines.push(this.generateAddColumn(diff.tableName, col));
|
|
115
|
-
}
|
|
116
|
-
// Alter columns
|
|
117
|
-
for (const { to } of diff.columnsToAlter ?? []) {
|
|
118
|
-
lines.push(this.generateAlterColumn(diff.tableName, to));
|
|
119
|
-
}
|
|
120
|
-
// Drop columns
|
|
121
|
-
for (const colName of diff.columnsToDrop ?? []) {
|
|
122
|
-
lines.push(`await builder.dropColumn('${diff.tableName}', '${colName}');`);
|
|
123
|
-
}
|
|
124
|
-
// Add indexes
|
|
125
|
-
for (const idx of diff.indexesToAdd ?? []) {
|
|
126
|
-
lines.push(this.generateCreateIndex(diff.tableName, idx));
|
|
127
|
-
}
|
|
128
|
-
// Drop indexes
|
|
129
|
-
for (const idxName of diff.indexesToDrop ?? []) {
|
|
130
|
-
lines.push(`await builder.dropIndex('${diff.tableName}', '${idxName}');`);
|
|
131
|
-
}
|
|
132
|
-
// Add foreign keys
|
|
133
|
-
for (const fk of diff.foreignKeysToAdd ?? []) {
|
|
134
|
-
lines.push(this.generateAddForeignKey(diff.tableName, fk));
|
|
135
|
-
}
|
|
136
|
-
// Drop foreign keys
|
|
137
|
-
for (const fkName of diff.foreignKeysToDrop ?? []) {
|
|
138
|
-
lines.push(`await builder.dropForeignKey('${diff.tableName}', '${fkName}');`);
|
|
139
|
-
}
|
|
140
|
-
return lines.join('\n');
|
|
141
|
-
}
|
|
142
|
-
generateAlterDown(diff) {
|
|
143
|
-
const lines = [];
|
|
144
|
-
// Reverse: drop added columns
|
|
145
|
-
for (const col of diff.columnsToAdd ?? []) {
|
|
146
|
-
lines.push(`await builder.dropColumn('${diff.tableName}', '${col.name}');`);
|
|
147
|
-
}
|
|
148
|
-
// Reverse: restore altered columns
|
|
149
|
-
for (const { from } of diff.columnsToAlter ?? []) {
|
|
150
|
-
lines.push(this.generateAlterColumn(diff.tableName, from));
|
|
151
|
-
}
|
|
152
|
-
// Reverse: re-add dropped columns (if we have the schema)
|
|
153
|
-
// Note: This requires the original column definition
|
|
154
|
-
if (diff.columnsToDrop?.length) {
|
|
155
|
-
lines.push(`// TODO: Re-add dropped columns: ${diff.columnsToDrop.join(', ')}`);
|
|
156
|
-
}
|
|
157
|
-
// Reverse: drop added indexes
|
|
158
|
-
for (const idx of diff.indexesToAdd ?? []) {
|
|
159
|
-
lines.push(`await builder.dropIndex('${diff.tableName}', '${idx.name}');`);
|
|
160
|
-
}
|
|
161
|
-
// Reverse: re-add dropped indexes
|
|
162
|
-
if (diff.indexesToDrop?.length) {
|
|
163
|
-
lines.push(`// TODO: Re-add dropped indexes: ${diff.indexesToDrop.join(', ')}`);
|
|
164
|
-
}
|
|
165
|
-
// Reverse: drop added foreign keys
|
|
166
|
-
for (const fk of diff.foreignKeysToAdd ?? []) {
|
|
167
|
-
if (fk.name) {
|
|
168
|
-
lines.push(`await builder.dropForeignKey('${diff.tableName}', '${fk.name}');`);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
// Reverse: re-add dropped foreign keys
|
|
172
|
-
if (diff.foreignKeysToDrop?.length) {
|
|
173
|
-
lines.push(`// TODO: Re-add dropped foreign keys: ${diff.foreignKeysToDrop.join(', ')}`);
|
|
174
|
-
}
|
|
175
|
-
return lines.join('\n');
|
|
176
|
-
}
|
|
177
|
-
generateAddColumn(tableName, col) {
|
|
178
|
-
const options = this.generateColumnOptions(col);
|
|
179
|
-
return `await builder.addColumn('${tableName}', '${col.name}', (col) => col${options});`;
|
|
180
|
-
}
|
|
181
|
-
generateAlterColumn(tableName, col) {
|
|
182
|
-
const options = this.generateColumnOptions(col);
|
|
183
|
-
return `await builder.alterColumn('${tableName}', '${col.name}', (col) => col${options});`;
|
|
184
|
-
}
|
|
185
|
-
generateCreateIndex(tableName, idx) {
|
|
186
|
-
const cols = idx.columns.map((c) => `'${c}'`).join(', ');
|
|
187
|
-
const opts = [];
|
|
188
|
-
if (idx.name)
|
|
189
|
-
opts.push(`name: '${idx.name}'`);
|
|
190
|
-
if (idx.unique)
|
|
191
|
-
opts.push('unique: true');
|
|
192
|
-
const optsStr = opts.length ? `, { ${opts.join(', ')} }` : '';
|
|
193
|
-
return `await builder.createIndex('${tableName}', [${cols}]${optsStr});`;
|
|
194
|
-
}
|
|
195
|
-
generateAddForeignKey(tableName, fk) {
|
|
196
|
-
const cols = fk.columns.map((c) => `'${c}'`).join(', ');
|
|
197
|
-
const refCols = fk.referencedColumns.map((c) => `'${c}'`).join(', ');
|
|
198
|
-
const opts = [];
|
|
199
|
-
if (fk.name)
|
|
200
|
-
opts.push(`name: '${fk.name}'`);
|
|
201
|
-
if (fk.onDelete && fk.onDelete !== 'NO ACTION')
|
|
202
|
-
opts.push(`onDelete: '${fk.onDelete}'`);
|
|
203
|
-
if (fk.onUpdate && fk.onUpdate !== 'NO ACTION')
|
|
204
|
-
opts.push(`onUpdate: '${fk.onUpdate}'`);
|
|
205
|
-
const optsStr = opts.length ? `, { ${opts.join(', ')} }` : '';
|
|
206
|
-
return `await builder.addForeignKey('${tableName}', [${cols}], { table: '${fk.referencedTable}', columns: [${refCols}] }${optsStr});`;
|
|
207
|
-
}
|
|
208
|
-
// ===========================================================================
|
|
209
|
-
// Private: Column Call Generation
|
|
210
|
-
// ===========================================================================
|
|
211
|
-
generateColumnCall(col) {
|
|
212
|
-
const method = this.getColumnMethod(col);
|
|
213
|
-
const options = this.generateColumnOptionsObject(col);
|
|
214
|
-
return `table.${method}('${col.name}'${options})`;
|
|
215
|
-
}
|
|
216
|
-
generateIndexCall(idx) {
|
|
217
|
-
const cols = idx.columns.map((c) => `'${c}'`).join(', ');
|
|
218
|
-
if (idx.unique) {
|
|
219
|
-
return `table.unique([${cols}], '${idx.name}')`;
|
|
220
|
-
}
|
|
221
|
-
return `table.index([${cols}], '${idx.name}')`;
|
|
222
|
-
}
|
|
223
|
-
getColumnMethod(col) {
|
|
224
|
-
const type = col.type;
|
|
225
|
-
// Check for auto-increment primary key → id()
|
|
226
|
-
if (col.isPrimaryKey && col.isAutoIncrement) {
|
|
227
|
-
return 'id';
|
|
228
|
-
}
|
|
229
|
-
// Map type string to method name
|
|
230
|
-
const typeMap = {
|
|
231
|
-
integer: 'integer',
|
|
232
|
-
int: 'integer',
|
|
233
|
-
bigint: 'bigint',
|
|
234
|
-
smallint: 'smallint',
|
|
235
|
-
float: 'float',
|
|
236
|
-
double: 'double',
|
|
237
|
-
decimal: 'decimal',
|
|
238
|
-
numeric: 'decimal',
|
|
239
|
-
varchar: 'string',
|
|
240
|
-
char: 'char',
|
|
241
|
-
text: 'text',
|
|
242
|
-
boolean: 'boolean',
|
|
243
|
-
bool: 'boolean',
|
|
244
|
-
date: 'date',
|
|
245
|
-
time: 'time',
|
|
246
|
-
timestamp: 'timestamp',
|
|
247
|
-
timestamptz: 'timestamptz',
|
|
248
|
-
json: 'json',
|
|
249
|
-
jsonb: 'jsonb',
|
|
250
|
-
uuid: 'uuid',
|
|
251
|
-
blob: 'blob',
|
|
252
|
-
bytea: 'blob',
|
|
253
|
-
vector: 'vector',
|
|
254
|
-
};
|
|
255
|
-
const lowerType = type.toLowerCase().replace(/\(.*\)/, ''); // Remove (255) etc
|
|
256
|
-
return typeMap[lowerType] ?? 'string';
|
|
257
|
-
}
|
|
258
|
-
generateColumnOptionsObject(col) {
|
|
259
|
-
const opts = [];
|
|
260
|
-
// Type-specific options
|
|
261
|
-
if (col.length !== undefined && col.length !== 255) {
|
|
262
|
-
opts.push(`length: ${col.length}`);
|
|
263
|
-
}
|
|
264
|
-
if (col.precision !== undefined) {
|
|
265
|
-
opts.push(`precision: ${col.precision}`);
|
|
266
|
-
}
|
|
267
|
-
if (col.scale !== undefined) {
|
|
268
|
-
opts.push(`scale: ${col.scale}`);
|
|
269
|
-
}
|
|
270
|
-
// Common options (only include non-defaults)
|
|
271
|
-
if (col.nullable) {
|
|
272
|
-
opts.push('nullable: true');
|
|
273
|
-
}
|
|
274
|
-
if (col.isUnique && !col.isPrimaryKey) {
|
|
275
|
-
opts.push('unique: true');
|
|
276
|
-
}
|
|
277
|
-
if (col.isPrimaryKey && !col.isAutoIncrement) {
|
|
278
|
-
opts.push('primaryKey: true');
|
|
279
|
-
}
|
|
280
|
-
if (col.defaultValue !== undefined) {
|
|
281
|
-
opts.push(`defaultValue: ${this.formatValue(col.defaultValue)}`);
|
|
282
|
-
}
|
|
283
|
-
if (opts.length === 0)
|
|
284
|
-
return '';
|
|
285
|
-
return `, { ${opts.join(', ')} }`;
|
|
286
|
-
}
|
|
287
|
-
generateColumnOptions(col) {
|
|
288
|
-
const parts = [];
|
|
289
|
-
if (!col.nullable) {
|
|
290
|
-
parts.push('.notNullable()');
|
|
291
|
-
}
|
|
292
|
-
if (col.isUnique) {
|
|
293
|
-
parts.push('.unique()');
|
|
294
|
-
}
|
|
295
|
-
if (col.defaultValue !== undefined) {
|
|
296
|
-
parts.push(`.defaultValue(${this.formatValue(col.defaultValue)})`);
|
|
297
|
-
}
|
|
298
|
-
return parts.join('');
|
|
299
|
-
}
|
|
300
|
-
formatValue(value) {
|
|
301
|
-
if (value === null)
|
|
302
|
-
return 'null';
|
|
303
|
-
if (typeof value === 'string') {
|
|
304
|
-
// Check for SQL expressions
|
|
305
|
-
if (value.toUpperCase().includes('CURRENT_TIMESTAMP') ||
|
|
306
|
-
value.includes('()') ||
|
|
307
|
-
value.toUpperCase().includes('NOW')) {
|
|
308
|
-
return `t.raw('${value}')`;
|
|
309
|
-
}
|
|
310
|
-
return `'${value.replace(/'/g, "\\'")}'`;
|
|
311
|
-
}
|
|
312
|
-
if (typeof value === 'boolean')
|
|
313
|
-
return String(value);
|
|
314
|
-
if (typeof value === 'number')
|
|
315
|
-
return String(value);
|
|
316
|
-
return JSON.stringify(value);
|
|
317
|
-
}
|
|
318
|
-
// ===========================================================================
|
|
319
|
-
// Private: Utilities
|
|
320
|
-
// ===========================================================================
|
|
321
|
-
generateDescription(diff) {
|
|
322
|
-
const parts = [];
|
|
323
|
-
if (diff.type === 'create') {
|
|
324
|
-
parts.push(`Create table '${diff.tableName}'`);
|
|
325
|
-
}
|
|
326
|
-
else if (diff.type === 'drop') {
|
|
327
|
-
parts.push(`Drop table '${diff.tableName}'`);
|
|
328
|
-
}
|
|
329
|
-
else {
|
|
330
|
-
if (diff.columnsToAdd?.length) {
|
|
331
|
-
parts.push(`Add ${diff.columnsToAdd.length} column(s)`);
|
|
332
|
-
}
|
|
333
|
-
if (diff.columnsToAlter?.length) {
|
|
334
|
-
parts.push(`Alter ${diff.columnsToAlter.length} column(s)`);
|
|
335
|
-
}
|
|
336
|
-
if (diff.columnsToDrop?.length) {
|
|
337
|
-
parts.push(`Drop ${diff.columnsToDrop.length} column(s)`);
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
return parts.join(', ') || `Alter table '${diff.tableName}'`;
|
|
341
|
-
}
|
|
342
|
-
indentBlock(code, level) {
|
|
343
|
-
const prefix = this.indent.repeat(level);
|
|
344
|
-
return code
|
|
345
|
-
.split('\n')
|
|
346
|
-
.map((line) => (line.trim() ? prefix + line : line))
|
|
347
|
-
.join('\n');
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
/**
|
|
351
|
-
* Factory function to create a MigrationCodeGenerator.
|
|
352
|
-
*/
|
|
353
|
-
export function createMigrationCodeGenerator(options) {
|
|
354
|
-
return new MigrationCodeGenerator(options);
|
|
355
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Smart Relation Detector
|
|
3
|
-
*
|
|
4
|
-
* Uses heuristics and schema analysis to detect relationships between tables:
|
|
5
|
-
* - Explicit foreign keys (highest confidence)
|
|
6
|
-
* - Junction tables for ManyToMany
|
|
7
|
-
* - Unique FK columns for OneToOne
|
|
8
|
-
*/
|
|
9
|
-
import type { SchemaAST } from '../../schema/schemaAST.js';
|
|
10
|
-
import type { DetectedRelation } from '../../schema/types.js';
|
|
11
|
-
/**
|
|
12
|
-
* Configuration for relation detection.
|
|
13
|
-
*/
|
|
14
|
-
export interface RelationDetectorOptions {
|
|
15
|
-
/** Minimum confidence threshold (0-1) to include in results */
|
|
16
|
-
minConfidence?: number;
|
|
17
|
-
/** Custom singularize function */
|
|
18
|
-
singularize?: (name: string) => string;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Detects relationships in a SchemaAST using multiple heuristics.
|
|
22
|
-
*/
|
|
23
|
-
export declare class SmartRelationDetector {
|
|
24
|
-
private readonly ast;
|
|
25
|
-
private readonly options;
|
|
26
|
-
constructor(ast: SchemaAST, options?: RelationDetectorOptions);
|
|
27
|
-
/**
|
|
28
|
-
* Detect all relationships in the schema.
|
|
29
|
-
*/
|
|
30
|
-
detectAll(): DetectedRelation[];
|
|
31
|
-
/**
|
|
32
|
-
* Detect junction tables that represent ManyToMany relationships.
|
|
33
|
-
*/
|
|
34
|
-
private detectJunctionTables;
|
|
35
|
-
/**
|
|
36
|
-
* Detect relations where unique FK should upgrade to OneToOne.
|
|
37
|
-
*/
|
|
38
|
-
private detectOneToOneRelations;
|
|
39
|
-
/**
|
|
40
|
-
* Default singularize function (delegates to shared utility).
|
|
41
|
-
*/
|
|
42
|
-
private defaultSingularize;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Create a SmartRelationDetector for the given AST.
|
|
46
|
-
*/
|
|
47
|
-
export declare function createRelationDetector(ast: SchemaAST, options?: RelationDetectorOptions): SmartRelationDetector;
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Smart Relation Detector
|
|
3
|
-
*
|
|
4
|
-
* Uses heuristics and schema analysis to detect relationships between tables:
|
|
5
|
-
* - Explicit foreign keys (highest confidence)
|
|
6
|
-
* - Junction tables for ManyToMany
|
|
7
|
-
* - Unique FK columns for OneToOne
|
|
8
|
-
*/
|
|
9
|
-
import { singularize } from '../../util/string.util.js';
|
|
10
|
-
/**
|
|
11
|
-
* Detects relationships in a SchemaAST using multiple heuristics.
|
|
12
|
-
*/
|
|
13
|
-
export class SmartRelationDetector {
|
|
14
|
-
ast;
|
|
15
|
-
options;
|
|
16
|
-
constructor(ast, options = {}) {
|
|
17
|
-
this.ast = ast;
|
|
18
|
-
this.options = {
|
|
19
|
-
minConfidence: options.minConfidence ?? 0.5,
|
|
20
|
-
singularize: options.singularize ?? this.defaultSingularize.bind(this),
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Detect all relationships in the schema.
|
|
25
|
-
*/
|
|
26
|
-
detectAll() {
|
|
27
|
-
const relations = [];
|
|
28
|
-
// 1. Add explicit FK relationships (confidence: 1.0)
|
|
29
|
-
for (const rel of this.ast.relationships) {
|
|
30
|
-
relations.push({
|
|
31
|
-
type: rel.type,
|
|
32
|
-
from: {
|
|
33
|
-
table: rel.from.table,
|
|
34
|
-
columns: rel.from.columns,
|
|
35
|
-
},
|
|
36
|
-
to: {
|
|
37
|
-
table: rel.to.table,
|
|
38
|
-
columns: rel.to.columns,
|
|
39
|
-
},
|
|
40
|
-
through: rel.through,
|
|
41
|
-
confidence: 1.0,
|
|
42
|
-
source: 'explicit_fk',
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
// 2. Detect junction tables (ManyToMany)
|
|
46
|
-
const junctionRelations = this.detectJunctionTables();
|
|
47
|
-
relations.push(...junctionRelations);
|
|
48
|
-
// 3. Detect unique FK -> OneToOne upgrades
|
|
49
|
-
const oneToOneUpgrades = this.detectOneToOneRelations(relations);
|
|
50
|
-
relations.push(...oneToOneUpgrades);
|
|
51
|
-
// Filter by confidence
|
|
52
|
-
return relations.filter((r) => r.confidence >= this.options.minConfidence);
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Detect junction tables that represent ManyToMany relationships.
|
|
56
|
-
*/
|
|
57
|
-
detectJunctionTables() {
|
|
58
|
-
const relations = [];
|
|
59
|
-
for (const table of this.ast.tables.values()) {
|
|
60
|
-
if (!this.ast.isJunctionTable(table))
|
|
61
|
-
continue;
|
|
62
|
-
const outgoingRels = table.outgoingRelations;
|
|
63
|
-
if (outgoingRels.length !== 2)
|
|
64
|
-
continue;
|
|
65
|
-
const [rel1, rel2] = outgoingRels;
|
|
66
|
-
// Create ManyToMany relation
|
|
67
|
-
relations.push({
|
|
68
|
-
type: 'ManyToMany',
|
|
69
|
-
from: {
|
|
70
|
-
table: rel1.to.table,
|
|
71
|
-
columns: rel1.to.columns,
|
|
72
|
-
},
|
|
73
|
-
to: {
|
|
74
|
-
table: rel2.to.table,
|
|
75
|
-
columns: rel2.to.columns,
|
|
76
|
-
},
|
|
77
|
-
through: table,
|
|
78
|
-
confidence: 0.95,
|
|
79
|
-
source: 'junction_table',
|
|
80
|
-
});
|
|
81
|
-
// Also create inverse relation
|
|
82
|
-
relations.push({
|
|
83
|
-
type: 'ManyToMany',
|
|
84
|
-
from: {
|
|
85
|
-
table: rel2.to.table,
|
|
86
|
-
columns: rel2.to.columns,
|
|
87
|
-
},
|
|
88
|
-
to: {
|
|
89
|
-
table: rel1.to.table,
|
|
90
|
-
columns: rel1.to.columns,
|
|
91
|
-
},
|
|
92
|
-
through: table,
|
|
93
|
-
confidence: 0.95,
|
|
94
|
-
source: 'junction_table',
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
return relations;
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Detect relations where unique FK should upgrade to OneToOne.
|
|
101
|
-
*/
|
|
102
|
-
detectOneToOneRelations(existingRelations) {
|
|
103
|
-
const upgrades = [];
|
|
104
|
-
for (const rel of existingRelations) {
|
|
105
|
-
if (rel.source !== 'explicit_fk')
|
|
106
|
-
continue;
|
|
107
|
-
const fromCol = rel.from.columns[0];
|
|
108
|
-
if (fromCol?.isUnique && rel.type === 'ManyToOne') {
|
|
109
|
-
// Upgrade to OneToOne
|
|
110
|
-
upgrades.push({
|
|
111
|
-
type: 'OneToOne',
|
|
112
|
-
from: rel.from,
|
|
113
|
-
to: rel.to,
|
|
114
|
-
through: rel.through,
|
|
115
|
-
confidence: 0.9,
|
|
116
|
-
source: 'unique_fk',
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
return upgrades;
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Default singularize function (delegates to shared utility).
|
|
124
|
-
*/
|
|
125
|
-
defaultSingularize(name) {
|
|
126
|
-
return singularize(name);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Create a SmartRelationDetector for the given AST.
|
|
131
|
-
*/
|
|
132
|
-
export function createRelationDetector(ast, options) {
|
|
133
|
-
return new SmartRelationDetector(ast, options);
|
|
134
|
-
}
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Schema Sync
|
|
3
|
-
*
|
|
4
|
-
* Orchestrates schema synchronization between entities and database
|
|
5
|
-
* with configurable direction modes.
|
|
6
|
-
*/
|
|
7
|
-
import type { SchemaDiffResult, SyncDirection, SyncOptions } from '../../schema/types.js';
|
|
8
|
-
import type { SchemaIntrospector, Type } from '../../type/index.js';
|
|
9
|
-
/**
|
|
10
|
-
* Result of a schema sync operation.
|
|
11
|
-
*/
|
|
12
|
-
export interface SchemaSyncResult {
|
|
13
|
-
/** Direction of the sync */
|
|
14
|
-
direction: SyncDirection;
|
|
15
|
-
/** Whether the sync was successful */
|
|
16
|
-
success: boolean;
|
|
17
|
-
/** Changes applied to database */
|
|
18
|
-
dbChanges: SchemaDiffResult | undefined;
|
|
19
|
-
/** Changes applied to entities */
|
|
20
|
-
entityChanges: SchemaDiffResult | undefined;
|
|
21
|
-
/** Conflicts that need manual resolution */
|
|
22
|
-
conflicts: SyncConflict[];
|
|
23
|
-
/** Human-readable summary */
|
|
24
|
-
summary: string;
|
|
25
|
-
/** Structured summary of changes */
|
|
26
|
-
details: {
|
|
27
|
-
db: {
|
|
28
|
-
created: number;
|
|
29
|
-
dropped: number;
|
|
30
|
-
altered: number;
|
|
31
|
-
};
|
|
32
|
-
entity: {
|
|
33
|
-
created: number;
|
|
34
|
-
dropped: number;
|
|
35
|
-
altered: number;
|
|
36
|
-
};
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* A conflict between entity and database schemas.
|
|
41
|
-
*/
|
|
42
|
-
export interface SyncConflict {
|
|
43
|
-
/** Type of conflict */
|
|
44
|
-
type: 'type_mismatch' | 'constraint_mismatch' | 'column_mismatch' | 'relation_mismatch';
|
|
45
|
-
/** Table name */
|
|
46
|
-
table: string;
|
|
47
|
-
/** Column name (if applicable) */
|
|
48
|
-
column?: string;
|
|
49
|
-
/** What entity expects */
|
|
50
|
-
entityValue: unknown;
|
|
51
|
-
/** What database has */
|
|
52
|
-
dbValue: unknown;
|
|
53
|
-
/** Suggested resolution */
|
|
54
|
-
suggestion: string;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Options for schema sync operation.
|
|
58
|
-
*/
|
|
59
|
-
export interface SchemaSyncOptions extends SyncOptions {
|
|
60
|
-
/** Entities to sync */
|
|
61
|
-
entities: Type<unknown>[];
|
|
62
|
-
/** Schema introspector for database */
|
|
63
|
-
introspector: SchemaIntrospector;
|
|
64
|
-
/** Output directory for generated entities (db-to-entity mode) */
|
|
65
|
-
entityOutputDir?: string;
|
|
66
|
-
/** Dry run - don't apply changes */
|
|
67
|
-
dryRun?: boolean;
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Service for synchronizing schemas between entities and database.
|
|
71
|
-
*/
|
|
72
|
-
export declare class SchemaSync {
|
|
73
|
-
private readonly options;
|
|
74
|
-
constructor(options: SchemaSyncOptions);
|
|
75
|
-
/**
|
|
76
|
-
* Execute schema synchronization.
|
|
77
|
-
*/
|
|
78
|
-
sync(): Promise<SchemaSyncResult>;
|
|
79
|
-
/**
|
|
80
|
-
* Sync from entities to database (push).
|
|
81
|
-
*/
|
|
82
|
-
private syncEntityToDb;
|
|
83
|
-
/**
|
|
84
|
-
* Sync from database to entities (pull).
|
|
85
|
-
*/
|
|
86
|
-
private syncDbToEntity;
|
|
87
|
-
/**
|
|
88
|
-
* Bidirectional sync with conflict detection.
|
|
89
|
-
*/
|
|
90
|
-
private syncBidirectional;
|
|
91
|
-
/**
|
|
92
|
-
* Build SchemaAST from entities.
|
|
93
|
-
*/
|
|
94
|
-
private buildEntityAST;
|
|
95
|
-
/**
|
|
96
|
-
* Build SchemaAST from database.
|
|
97
|
-
*/
|
|
98
|
-
private buildDatabaseAST;
|
|
99
|
-
/**
|
|
100
|
-
* Filter destructive changes for safe mode.
|
|
101
|
-
*/
|
|
102
|
-
private filterDestructiveChanges;
|
|
103
|
-
/**
|
|
104
|
-
* Detect conflicts between bidirectional changes.
|
|
105
|
-
*/
|
|
106
|
-
private detectConflicts;
|
|
107
|
-
/**
|
|
108
|
-
* Filter out conflicting changes.
|
|
109
|
-
*/
|
|
110
|
-
private filterConflictingChanges;
|
|
111
|
-
/**
|
|
112
|
-
* Get counts of changes from a diff.
|
|
113
|
-
*/
|
|
114
|
-
private getDiffCounts;
|
|
115
|
-
/**
|
|
116
|
-
* Format summary for single-direction sync.
|
|
117
|
-
*/
|
|
118
|
-
private formatSummary;
|
|
119
|
-
/**
|
|
120
|
-
* Format summary for bidirectional sync.
|
|
121
|
-
*/
|
|
122
|
-
private formatBidirectionalSummary;
|
|
123
|
-
/**
|
|
124
|
-
* Format type for display.
|
|
125
|
-
*/
|
|
126
|
-
private formatType;
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Create a SchemaSync instance.
|
|
130
|
-
*/
|
|
131
|
-
export declare function createSchemaSync(options: SchemaSyncOptions): SchemaSync;
|