uql-orm 0.63.0 → 0.65.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/dist/bunSql/bunSqlQuerier.d.ts +3 -10
- package/dist/bunSql/bunSqlQuerier.js +2 -16
- package/dist/bunSql/bunSqlQuerierPool.d.ts +0 -2
- package/dist/bunSql/bunSqlQuerierPool.js +14 -16
- package/dist/d1/d1Querier.d.ts +13 -34
- package/dist/d1/d1Querier.js +1 -1
- package/dist/d1/d1QuerierPool.d.ts +3 -3
- package/dist/dialect/abstractDialect.d.ts +4 -9
- package/dist/dialect/abstractDialect.js +4 -5
- package/dist/dialect/abstractSqlDialect.d.ts +2 -2
- package/dist/dialect/index.d.ts +0 -1
- package/dist/dialect/index.js +2 -3
- package/dist/dialect/mysqlLikeSqlDialect.js +0 -3
- package/dist/dialect/pgLikeSqlDialect.d.ts +9 -1
- package/dist/dialect/pgLikeSqlDialect.js +8 -5
- package/dist/dialect/queryContext.d.ts +3 -3
- package/dist/entity/metadata/definition.d.ts +6 -0
- package/dist/entity/metadata/definition.js +109 -76
- package/dist/migrate/builder/expressions.js +1 -15
- package/dist/migrate/builder/migrationBuilder.d.ts +6 -28
- package/dist/migrate/builder/migrationBuilder.js +9 -83
- package/dist/migrate/builder/types.d.ts +14 -24
- package/dist/migrate/cli.d.ts +2 -7
- package/dist/migrate/cli.js +22 -43
- package/dist/migrate/codegen/entityCodeGenerator.d.ts +5 -0
- package/dist/migrate/codegen/entityCodeGenerator.js +29 -7
- package/dist/migrate/codegen/indexDecoratorSource.js +1 -5
- package/dist/migrate/codegen/migrationFile.d.ts +9 -1
- package/dist/migrate/codegen/migrationFile.js +2 -1
- package/dist/migrate/codegen/sourceLiteral.d.ts +2 -0
- package/dist/migrate/codegen/sourceLiteral.js +4 -0
- package/dist/migrate/ddl/indexDdl.d.ts +4 -2
- package/dist/migrate/ddl/indexDdl.js +16 -15
- package/dist/migrate/generator/mongoCommand.d.ts +9 -9
- package/dist/migrate/generator/mongoCommand.js +1 -1
- package/dist/migrate/generator/mongoSchemaGenerator.d.ts +21 -26
- package/dist/migrate/generator/mongoSchemaGenerator.js +103 -80
- package/dist/migrate/index.d.ts +2 -2
- package/dist/migrate/index.js +2 -2
- package/dist/migrate/indexPredicate.d.ts +8 -0
- package/dist/migrate/indexPredicate.js +52 -0
- package/dist/migrate/introspection/registry.d.ts +2 -2
- package/dist/migrate/introspection/registry.js +6 -11
- package/dist/migrate/migrationTarget.d.ts +23 -0
- package/dist/migrate/migrationTarget.js +50 -0
- package/dist/migrate/migrator.d.ts +18 -50
- package/dist/migrate/migrator.js +79 -199
- package/dist/migrate/schemaGenerator.d.ts +11 -14
- package/dist/migrate/schemaGenerator.js +42 -12
- package/dist/mongo/mongoDialect.d.ts +7 -2
- package/dist/mongo/mongoDialect.js +1 -4
- package/dist/mssql/mssqlDialect.js +0 -3
- package/dist/pglite/pgliteQuerier.d.ts +2 -6
- package/dist/pglite/pgliteQuerier.js +2 -9
- package/dist/postgres/index.d.ts +0 -1
- package/dist/postgres/index.js +0 -1
- package/dist/querier/abstractSharedHandleQuerierPool.d.ts +2 -5
- package/dist/querier/abstractSharedHandleQuerierPool.js +2 -5
- package/dist/querier/abstractSqlQuerier.d.ts +2 -3
- package/dist/querier/abstractSqlQuerier.js +8 -4
- package/dist/querier/cursorStream.d.ts +13 -0
- package/dist/{postgres/pgCursorStream.js → querier/cursorStream.js} +4 -13
- package/dist/schema/canonicalType.js +1 -1
- package/dist/schema/schemaASTBuilder.d.ts +2 -0
- package/dist/schema/schemaASTBuilder.js +43 -62
- package/dist/sqlite/abstractSqliteQuerier.d.ts +7 -3
- package/dist/sqlite/abstractSqliteQuerier.js +18 -4
- package/dist/sqlite/hranaQuerier.d.ts +1 -1
- package/dist/sqlite/localSqliteQuerierPool.d.ts +7 -0
- package/dist/sqlite/localSqliteQuerierPool.js +19 -0
- package/dist/sqlite/nodeSqliteQuerierPool.js +2 -3
- package/dist/sqlite/sqliteDialect.js +0 -3
- package/dist/sqlite/sqliteQuerier.d.ts +8 -5
- package/dist/sqlite/sqliteQuerier.js +4 -13
- package/dist/sqlite/sqliteQuerierPool.js +4 -4
- package/dist/turso/tursoSessionQuerier.d.ts +2 -2
- package/dist/turso/tursoSessionQuerier.js +16 -18
- package/dist/type/dialect.d.ts +25 -35
- package/dist/type/entity.d.ts +26 -28
- package/dist/type/migration.d.ts +11 -40
- package/dist/type/migratorDialect.d.ts +0 -9
- package/dist/type/migratorDialect.js +1 -16
- package/dist/type/querierPool.d.ts +0 -4
- package/dist/type/queryRaw.d.ts +2 -2
- package/dist/type/universalQuerier.d.ts +2 -2
- package/dist/util/ddlExpression.util.d.ts +3 -1
- package/dist/util/ddlExpression.util.js +14 -0
- package/dist/util/sqlLiteral.js +5 -3
- package/package.json +1 -3
- package/dist/migrate/schemaGeneratorAsync.d.ts +0 -7
- package/dist/migrate/schemaGeneratorAsync.js +0 -12
- package/dist/postgres/pgCursorStream.d.ts +0 -20
- package/dist/postgres/postgresWireDriverCapabilities.d.ts +0 -21
- package/dist/postgres/postgresWireDriverCapabilities.js +0 -21
- package/dist/sqlite/bunSqliteAdapter.bun.d.ts +0 -27
- package/dist/sqlite/bunSqliteAdapter.bun.js +0 -25
- package/dist/sqlite/nodeSqliteAdapter.d.ts +0 -33
- package/dist/sqlite/nodeSqliteAdapter.js +0 -25
package/dist/migrate/cli.js
CHANGED
|
@@ -7,14 +7,8 @@ import { createEntityCodeGenerator } from './codegen/entityCodeGenerator.js';
|
|
|
7
7
|
import { entityTypesSource } from './codegen/entityTypes.js';
|
|
8
8
|
import { detectDrift } from './drift/driftDetector.js';
|
|
9
9
|
import { Migrator } from './migrator.js';
|
|
10
|
-
import { buildEntityAST
|
|
11
|
-
import { createSchemaGeneratorAsync } from './schemaGeneratorAsync.js';
|
|
10
|
+
import { buildEntityAST } from './schemaGenerator.js';
|
|
12
11
|
import { DEFAULT_MIGRATIONS_TABLE } from './storage/databaseStorage.js';
|
|
13
|
-
/** Sync helper for SQL dialects only; returns `undefined` for MongoDB - use {@link createSchemaGeneratorAsync}. */
|
|
14
|
-
export function getSchemaGenerator(dialect, defaultForeignKeyAction) {
|
|
15
|
-
return createSchemaGenerator(dialect, defaultForeignKeyAction);
|
|
16
|
-
}
|
|
17
|
-
export { createSchemaGeneratorAsync };
|
|
18
12
|
export async function main(args = process.argv.slice(2)) {
|
|
19
13
|
let customPath;
|
|
20
14
|
const filteredArgs = [];
|
|
@@ -42,7 +36,6 @@ export async function main(args = process.argv.slice(2)) {
|
|
|
42
36
|
defaultForeignKeyAction: config.defaultForeignKeyAction,
|
|
43
37
|
};
|
|
44
38
|
const migrator = new Migrator(config.pool, options);
|
|
45
|
-
await migrator.ensureSchemaGenerator();
|
|
46
39
|
switch (command) {
|
|
47
40
|
case 'up':
|
|
48
41
|
await runUp(migrator, filteredArgs.slice(1));
|
|
@@ -63,7 +56,7 @@ export async function main(args = process.argv.slice(2)) {
|
|
|
63
56
|
break;
|
|
64
57
|
case 'generate:from-db':
|
|
65
58
|
case 'generate-from-db':
|
|
66
|
-
await runGenerateFromDb(migrator, filteredArgs.slice(1)
|
|
59
|
+
await runGenerateFromDb(migrator, filteredArgs.slice(1));
|
|
67
60
|
break;
|
|
68
61
|
case 'sync':
|
|
69
62
|
await runSync(migrator, filteredArgs.slice(1), config);
|
|
@@ -204,7 +197,7 @@ function readOutput(args) {
|
|
|
204
197
|
export async function runSync(migrator, args, config) {
|
|
205
198
|
// Pulling the database into entity files is what `generate:from-db` does; one implementation.
|
|
206
199
|
if (args.includes('--pull')) {
|
|
207
|
-
return runGenerateFromDb(migrator, args
|
|
200
|
+
return runGenerateFromDb(migrator, args);
|
|
208
201
|
}
|
|
209
202
|
const force = args.includes('--force');
|
|
210
203
|
const safe = !args.includes('--unsafe');
|
|
@@ -223,49 +216,35 @@ export async function runSync(migrator, args, config) {
|
|
|
223
216
|
await migrator.sync({ ...options, logging: true });
|
|
224
217
|
console.log('\nSchema sync completed.');
|
|
225
218
|
}
|
|
226
|
-
export async function runGenerateFromDb(migrator, args
|
|
219
|
+
export async function runGenerateFromDb(migrator, args) {
|
|
227
220
|
const outputDir = readOutput(args) ?? './src/entities';
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
// Ensure output directory exists
|
|
245
|
-
if (!fs.existsSync(outputDir)) {
|
|
246
|
-
fs.mkdirSync(outputDir, { recursive: true });
|
|
247
|
-
}
|
|
248
|
-
// Write entity files
|
|
249
|
-
for (const entity of entities) {
|
|
250
|
-
const filePath = path.join(outputDir, entity.fileName);
|
|
251
|
-
fs.writeFileSync(filePath, entity.code, 'utf-8');
|
|
252
|
-
console.log(` ✓ ${entity.className} -> ${filePath}`);
|
|
253
|
-
}
|
|
254
|
-
console.log(`\nGenerated ${entities.length} entities to ${outputDir}`);
|
|
221
|
+
console.log('\nAnalyzing database schema...');
|
|
222
|
+
const ast = await migrator.schemaIntrospector.introspect();
|
|
223
|
+
const tableCount = ast.tables.size;
|
|
224
|
+
console.log(`Found ${tableCount} table(s): ${Array.from(ast.tables.keys()).join(', ')}`);
|
|
225
|
+
console.log('\nGenerating entities...');
|
|
226
|
+
const generator = createEntityCodeGenerator(ast, {
|
|
227
|
+
addSyncComments: true,
|
|
228
|
+
includeRelations: true,
|
|
229
|
+
includeIndexes: true,
|
|
230
|
+
});
|
|
231
|
+
const entities = generator.generateAll();
|
|
232
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
233
|
+
for (const entity of entities) {
|
|
234
|
+
const filePath = path.join(outputDir, entity.fileName);
|
|
235
|
+
fs.writeFileSync(filePath, entity.code, 'utf-8');
|
|
236
|
+
console.log(` ✓ ${entity.className} -> ${filePath}`);
|
|
255
237
|
}
|
|
238
|
+
console.log(`\nGenerated ${entities.length} entities to ${outputDir}`);
|
|
256
239
|
}
|
|
257
240
|
export async function runDriftCheck(migrator, config) {
|
|
258
241
|
if (!config.entities || config.entities.length === 0) {
|
|
259
242
|
console.error('No entities configured. Add entities to your uql config.');
|
|
260
243
|
process.exit(1);
|
|
261
244
|
}
|
|
262
|
-
else if (!migrator.schemaIntrospector || !migrator.schemaGenerator) {
|
|
263
|
-
console.error('No introspector available. Check your pool configuration.');
|
|
264
|
-
process.exit(1);
|
|
265
|
-
}
|
|
266
245
|
else {
|
|
267
246
|
console.log('\nChecking for schema drift...');
|
|
268
|
-
const expectedAST = buildEntityAST(migrator.
|
|
247
|
+
const expectedAST = buildEntityAST(await migrator.getSchemaGenerator(), config.entities);
|
|
269
248
|
// Build actual schema from database
|
|
270
249
|
const actualAST = await migrator.schemaIntrospector.introspect();
|
|
271
250
|
// Detect drift. The dialect renders canonical types as SQL - without it every type formats as
|
|
@@ -98,6 +98,11 @@ export declare class EntityCodeGenerator {
|
|
|
98
98
|
* Build outgoing relation (ManyToOne or OneToOne where this table has FK).
|
|
99
99
|
*/
|
|
100
100
|
private buildOutgoingRelation;
|
|
101
|
+
/**
|
|
102
|
+
* The `references` callback of a to-one: its foreign key column where that is the target's whole primary
|
|
103
|
+
* key, column pairs otherwise, and nothing when the columns do not pair up.
|
|
104
|
+
*/
|
|
105
|
+
private referencesSource;
|
|
101
106
|
/**
|
|
102
107
|
* Build incoming relation (OneToMany where other tables have FK to this).
|
|
103
108
|
*/
|
|
@@ -14,6 +14,7 @@ import { DEFAULT_FOREIGN_KEY_ACTION, } from '../../schema/types.js';
|
|
|
14
14
|
import { camelCase, lowerFirst, pascalCase, singularize } from '../../util/string.util.js';
|
|
15
15
|
import { buildFieldOptionsSource, fieldNeedsRaw } from './fieldOptionsSource.js';
|
|
16
16
|
import { buildIndexDecoratorSource, indexNeedsRaw, isPlainFieldIndex } from './indexDecoratorSource.js';
|
|
17
|
+
import { memberSource } from './sourceLiteral.js';
|
|
17
18
|
/**
|
|
18
19
|
* Generates TypeScript entity code from SchemaAST.
|
|
19
20
|
*/
|
|
@@ -234,17 +235,38 @@ export class EntityCodeGenerator {
|
|
|
234
235
|
}
|
|
235
236
|
// Decorator. `onDelete`/`onUpdate` only when introspection found a real referential action, so a
|
|
236
237
|
// round-trip through an unconstrained column stays as terse as before.
|
|
237
|
-
const
|
|
238
|
+
const options = [`entity: () => ${relatedClassName}`];
|
|
239
|
+
const references = this.referencesSource(rel, relatedClassName);
|
|
240
|
+
if (references)
|
|
241
|
+
options.push(`references: ${references}`);
|
|
238
242
|
if (rel.onDelete && rel.onDelete !== DEFAULT_FOREIGN_KEY_ACTION)
|
|
239
|
-
|
|
243
|
+
options.push(`onDelete: '${rel.onDelete}'`);
|
|
240
244
|
if (rel.onUpdate && rel.onUpdate !== DEFAULT_FOREIGN_KEY_ACTION)
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
lines.push(` @${decoratorName}({ entity: () => ${relatedClassName}${fkActionsSource} })`);
|
|
245
|
+
options.push(`onUpdate: '${rel.onUpdate}'`);
|
|
246
|
+
lines.push(` @${decoratorName}({ ${options.join(', ')} })`);
|
|
244
247
|
// Property
|
|
245
248
|
lines.push(` ${propertyName}?: ${relatedClassName};`);
|
|
246
249
|
return lines.join('\n');
|
|
247
250
|
}
|
|
251
|
+
/**
|
|
252
|
+
* The `references` callback of a to-one: its foreign key column where that is the target's whole primary
|
|
253
|
+
* key, column pairs otherwise, and nothing when the columns do not pair up.
|
|
254
|
+
*/
|
|
255
|
+
referencesSource(rel, relatedClassName) {
|
|
256
|
+
if (!rel.from.columns.length || rel.from.columns.length !== rel.to.columns.length) {
|
|
257
|
+
return undefined;
|
|
258
|
+
}
|
|
259
|
+
const member = (param, column) => memberSource(param, this.options.propertyNameTransformer(column.name));
|
|
260
|
+
const own = lowerFirst(this.options.classNameTransformer(rel.from.table.name));
|
|
261
|
+
const key = rel.to.table.primaryKey;
|
|
262
|
+
if (rel.from.columns.length === 1 && key.length === 1 && rel.to.columns[0].name === key[0].name) {
|
|
263
|
+
return `(${own}) => ${member(own, rel.from.columns[0])}`;
|
|
264
|
+
}
|
|
265
|
+
const target = lowerFirst(relatedClassName);
|
|
266
|
+
const [local, foreign] = own === target ? ['local', 'foreign'] : [own, target];
|
|
267
|
+
const pairs = rel.from.columns.map((column, i) => `{ local: ${member(local, column)}, foreign: ${member(foreign, rel.to.columns[i])} }`);
|
|
268
|
+
return `(${local}, ${foreign}) => [${pairs.join(', ')}]`;
|
|
269
|
+
}
|
|
248
270
|
/**
|
|
249
271
|
* Build incoming relation (OneToMany where other tables have FK to this).
|
|
250
272
|
*/
|
|
@@ -262,9 +284,9 @@ export class EntityCodeGenerator {
|
|
|
262
284
|
lines.push(' */');
|
|
263
285
|
}
|
|
264
286
|
// The inverse side, mapped by the related class's property that points back at this one.
|
|
265
|
-
const inverseProp = this.options.propertyNameTransformer(this.options.singularize(table.name));
|
|
266
287
|
const param = lowerFirst(relatedClassName);
|
|
267
|
-
|
|
288
|
+
const inverse = memberSource(param, this.options.propertyNameTransformer(this.options.singularize(table.name)));
|
|
289
|
+
lines.push(` @${decoratorName}({ entity: () => ${relatedClassName}, mappedBy: (${param}) => ${inverse} })`);
|
|
268
290
|
// Property
|
|
269
291
|
if (inverseType === 'OneToMany' || inverseType === 'ManyToMany') {
|
|
270
292
|
lines.push(` ${propertyName}?: ${relatedClassName}[];`);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isVectorIndexType } from '../../type/index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { memberSource, rawTag } from './sourceLiteral.js';
|
|
3
3
|
/**
|
|
4
4
|
* A vector index carries its metric in the operator class pgvector names after it
|
|
5
5
|
* (`vector_cosine_ops`), which is the only place introspection can recover it from. `@Index` requires
|
|
@@ -93,7 +93,3 @@ function indexEntrySource(entry, propertyName, param) {
|
|
|
93
93
|
const modifiers = significantModifiers(entry);
|
|
94
94
|
return modifiers.length === 0 ? column : `{ column: ${column}, ${modifiers.join(', ')} }`;
|
|
95
95
|
}
|
|
96
|
-
/** `user.email`, or `user['first-name']` for a property name that is no identifier. */
|
|
97
|
-
function memberSource(param, property) {
|
|
98
|
-
return isIdentifierName(property) ? `${param}.${property}` : `${param}[${quoted(property)}]`;
|
|
99
|
-
}
|
|
@@ -28,14 +28,22 @@ export declare function emitMongoCommandCalls(statements: string[]): string;
|
|
|
28
28
|
export declare const EMPTY_MANUAL_MIGRATION_UP_INNER = " // Add your migration logic here.\n // Use one await querier.run(\"...\") per SQL statement when possible (same style as generate:entities).\n // Example (Postgres):\n // await querier.run(\"CREATE TABLE \\\"users\\\" (\\\"id\\\" SERIAL PRIMARY KEY);\");\n";
|
|
29
29
|
/** Body for `down` in a manual (empty) migration scaffold. */
|
|
30
30
|
export declare const EMPTY_MANUAL_MIGRATION_DOWN_INNER = " // Add your rollback logic here.\n // await querier.run(\"DROP TABLE IF EXISTS \\\"users\\\";\");\n";
|
|
31
|
-
/** How a migration on
|
|
31
|
+
/** How a migration on one querier is scaffolded empty, and how a generated statement is spelled in it. */
|
|
32
|
+
export type MigrationSource = {
|
|
33
|
+
readonly querier: MigrationQuerierType;
|
|
34
|
+
readonly emptyUp: string;
|
|
35
|
+
readonly emptyDown: string;
|
|
36
|
+
emit(statements: string[]): string;
|
|
37
|
+
};
|
|
32
38
|
export declare const migrationSource: {
|
|
33
39
|
SqlQuerier: {
|
|
40
|
+
querier: "SqlQuerier";
|
|
34
41
|
emptyUp: string;
|
|
35
42
|
emptyDown: string;
|
|
36
43
|
emit: typeof emitSqlRunCalls;
|
|
37
44
|
};
|
|
38
45
|
MongoQuerier: {
|
|
46
|
+
querier: "MongoQuerier";
|
|
39
47
|
emptyUp: string;
|
|
40
48
|
emptyDown: string;
|
|
41
49
|
emit: typeof emitMongoCommandCalls;
|
|
@@ -24,14 +24,15 @@ export const EMPTY_MANUAL_MIGRATION_UP_INNER = ` // Add your migration logic
|
|
|
24
24
|
export const EMPTY_MANUAL_MIGRATION_DOWN_INNER = ` // Add your rollback logic here.
|
|
25
25
|
// await querier.run("DROP TABLE IF EXISTS \\"users\\";");
|
|
26
26
|
`;
|
|
27
|
-
/** How a migration on each querier is scaffolded empty, and how a generated statement is spelled in it. */
|
|
28
27
|
export const migrationSource = {
|
|
29
28
|
SqlQuerier: {
|
|
29
|
+
querier: 'SqlQuerier',
|
|
30
30
|
emptyUp: EMPTY_MANUAL_MIGRATION_UP_INNER,
|
|
31
31
|
emptyDown: EMPTY_MANUAL_MIGRATION_DOWN_INNER,
|
|
32
32
|
emit: emitSqlRunCalls,
|
|
33
33
|
},
|
|
34
34
|
MongoQuerier: {
|
|
35
|
+
querier: 'MongoQuerier',
|
|
35
36
|
emptyUp: ` // Add your migration logic here, through the database handle.
|
|
36
37
|
// await querier.db.collection('users').updateMany({}, { $set: { active: true } });
|
|
37
38
|
`,
|
|
@@ -6,6 +6,8 @@ export declare function isIdentifierName(text: string): boolean;
|
|
|
6
6
|
* parsing.
|
|
7
7
|
*/
|
|
8
8
|
export declare function quoted(text: string): string;
|
|
9
|
+
/** `user.email`, or `user['first-name']` for a property name that is no identifier. */
|
|
10
|
+
export declare function memberSource(param: string, property: string): string;
|
|
9
11
|
/**
|
|
10
12
|
* SQL as a `raw` tagged template. A database reprints an expression as arbitrary text, and exactly
|
|
11
13
|
* three sequences can end or interpolate a template literal, so escaping those is the whole job.
|
|
@@ -10,6 +10,10 @@ export function isIdentifierName(text) {
|
|
|
10
10
|
export function quoted(text) {
|
|
11
11
|
return `'${text.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`;
|
|
12
12
|
}
|
|
13
|
+
/** `user.email`, or `user['first-name']` for a property name that is no identifier. */
|
|
14
|
+
export function memberSource(param, property) {
|
|
15
|
+
return isIdentifierName(property) ? `${param}.${property}` : `${param}[${quoted(property)}]`;
|
|
16
|
+
}
|
|
13
17
|
/**
|
|
14
18
|
* SQL as a `raw` tagged template. A database reprints an expression as arbitrary text, and exactly
|
|
15
19
|
* three sequences can end or interpolate a template literal, so escaping those is the whole job.
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { AbstractSqlDialect } from '../../dialect/abstractSqlDialect.js';
|
|
2
2
|
import { type IndexType } from '../../schema/types.js';
|
|
3
3
|
import { type IndexColumnSchema, type IndexFeature, type IndexJsonArray, type IndexSchema } from '../../type/index.js';
|
|
4
|
+
/** Refuses an index of a type `types` lacks, `hints` naming what to declare instead. */
|
|
5
|
+
export declare function assertIndexType(index: IndexSchema, types: ReadonlySet<IndexType>, dialectName: string, hints?: ReadonlyMap<IndexType, string>): void;
|
|
6
|
+
/** Refuses an index asking for a feature `features` lacks. */
|
|
7
|
+
export declare function assertIndexFeatures(index: IndexSchema, features: ReadonlySet<IndexFeature>, dialectName: string): void;
|
|
4
8
|
/**
|
|
5
9
|
* `CREATE INDEX` for SQL dialects: the statement and the fragments each engine spells differently.
|
|
6
10
|
* The migrator's rather than the dialect's, since {@link SqlSchemaGenerator} is the only thing that
|
|
@@ -28,8 +32,6 @@ export declare class IndexDdl<D extends AbstractSqlDialect = AbstractSqlDialect>
|
|
|
28
32
|
protected readonly indexTypes: ReadonlySet<IndexType>;
|
|
29
33
|
/** What to declare instead of a type this dialect lacks, appended to its refusal. */
|
|
30
34
|
protected readonly indexTypeHints: ReadonlyMap<IndexType, string>;
|
|
31
|
-
private assertIndexType;
|
|
32
|
-
private assertIndexFeatures;
|
|
33
35
|
/**
|
|
34
36
|
* Index types this dialect spells as a keyword of their own (`FULLTEXT INDEX`, `VECTOR INDEX`)
|
|
35
37
|
* rather than as an access method after the table. One table drives both, so a type that is a
|
|
@@ -17,6 +17,20 @@ const INDEX_FEATURE_PROBES = {
|
|
|
17
17
|
opsClass: (index) => index.entries.some((entry) => entry.opsClass !== undefined),
|
|
18
18
|
include: (index) => Boolean(index.include?.length),
|
|
19
19
|
};
|
|
20
|
+
/** Refuses an index of a type `types` lacks, `hints` naming what to declare instead. */
|
|
21
|
+
export function assertIndexType(index, types, dialectName, hints = new Map()) {
|
|
22
|
+
if (index.type && !types.has(index.type)) {
|
|
23
|
+
throw new TypeError(`${dialectName} has no ${index.type} index (index "${index.name}")` + (hints.get(index.type) ?? ''));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** Refuses an index asking for a feature `features` lacks. */
|
|
27
|
+
export function assertIndexFeatures(index, features, dialectName) {
|
|
28
|
+
for (const feature of getKeys(INDEX_FEATURE_PROBES)) {
|
|
29
|
+
if (INDEX_FEATURE_PROBES[feature](index) && !features.has(feature)) {
|
|
30
|
+
throw new TypeError(`${dialectName} does not support ${INDEX_FEATURE_LABELS[feature]} (index "${index.name}")`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
20
34
|
/**
|
|
21
35
|
* `CREATE INDEX` for SQL dialects: the statement and the fragments each engine spells differently.
|
|
22
36
|
* The migrator's rather than the dialect's, since {@link SqlSchemaGenerator} is the only thing that
|
|
@@ -30,8 +44,8 @@ export class IndexDdl {
|
|
|
30
44
|
this.dialect = dialect;
|
|
31
45
|
}
|
|
32
46
|
getCreateIndexStatement(tableName, index, opts = {}) {
|
|
33
|
-
|
|
34
|
-
|
|
47
|
+
assertIndexType(index, this.indexTypes, this.dialect.dialectName, this.indexTypeHints);
|
|
48
|
+
assertIndexFeatures(index, this.indexFeatures, this.dialect.dialectName);
|
|
35
49
|
const unique = index.unique ? 'UNIQUE ' : '';
|
|
36
50
|
const ifNotExists = (opts.ifNotExists ?? this.dialect.features.indexIfNotExists) ? 'IF NOT EXISTS ' : '';
|
|
37
51
|
const columns = index.entries.map((entry) => this.indexColumn(entry, index)).join(', ');
|
|
@@ -57,19 +71,6 @@ export class IndexDdl {
|
|
|
57
71
|
indexTypes = new Set(INDEX_TYPES);
|
|
58
72
|
/** What to declare instead of a type this dialect lacks, appended to its refusal. */
|
|
59
73
|
indexTypeHints = new Map();
|
|
60
|
-
assertIndexType(index) {
|
|
61
|
-
if (index.type && !this.indexTypes.has(index.type)) {
|
|
62
|
-
throw new TypeError(`${this.dialect.dialectName} has no ${index.type} index (index "${index.name}")` +
|
|
63
|
-
(this.indexTypeHints.get(index.type) ?? ''));
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
assertIndexFeatures(index) {
|
|
67
|
-
for (const feature of getKeys(INDEX_FEATURE_PROBES)) {
|
|
68
|
-
if (INDEX_FEATURE_PROBES[feature](index) && !this.indexFeatures.has(feature)) {
|
|
69
|
-
throw new TypeError(`${this.dialect.dialectName} does not support ${INDEX_FEATURE_LABELS[feature]} (index "${index.name}")`);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
74
|
/**
|
|
74
75
|
* Index types this dialect spells as a keyword of their own (`FULLTEXT INDEX`, `VECTOR INDEX`)
|
|
75
76
|
* rather than as an access method after the table. One table drives both, so a type that is a
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
/** The direction, or `'text'`, of one field in a MongoDB index key spec. */
|
|
2
2
|
export type MongoIndexKey = Record<string, 1 | -1 | 'text'>;
|
|
3
|
+
/** What a `createIndex` command hands the driver beside its key spec. */
|
|
4
|
+
export type MongoIndexOptions = {
|
|
5
|
+
readonly unique: boolean;
|
|
6
|
+
readonly name: string;
|
|
7
|
+
readonly partialFilterExpression?: Readonly<Record<string, unknown>>;
|
|
8
|
+
};
|
|
3
9
|
/**
|
|
4
10
|
* `SchemaGenerator` yields one string per statement, so {@link MongoSchemaGenerator} emits its
|
|
5
11
|
* commands as JSON and this is their schema.
|
|
6
12
|
*
|
|
7
13
|
* Declared next to the generator that writes them because the migrator used to restate the shape
|
|
8
14
|
* inline from `JSON.parse`, with `cmd.name!` assertions and a bare `action: string` - where a command
|
|
9
|
-
* it had no branch for
|
|
15
|
+
* it had no branch for was silently a no-op.
|
|
10
16
|
*/
|
|
11
17
|
export type MongoCommand = {
|
|
12
18
|
readonly action: 'createCollection';
|
|
@@ -23,10 +29,7 @@ export type MongoCommand = {
|
|
|
23
29
|
readonly collection: string;
|
|
24
30
|
readonly name: string;
|
|
25
31
|
readonly key: MongoIndexKey;
|
|
26
|
-
readonly options:
|
|
27
|
-
readonly unique: boolean;
|
|
28
|
-
readonly name: string;
|
|
29
|
-
};
|
|
32
|
+
readonly options: MongoIndexOptions;
|
|
30
33
|
} | {
|
|
31
34
|
readonly action: 'dropIndex';
|
|
32
35
|
readonly collection: string;
|
|
@@ -43,10 +46,7 @@ export type MongoCommandTarget = {
|
|
|
43
46
|
renameCollection(from: string, to: string): Promise<unknown>;
|
|
44
47
|
collection(name: string): {
|
|
45
48
|
drop(): Promise<unknown>;
|
|
46
|
-
createIndex(key: MongoIndexKey, options:
|
|
47
|
-
unique: boolean;
|
|
48
|
-
name: string;
|
|
49
|
-
}): Promise<unknown>;
|
|
49
|
+
createIndex(key: MongoIndexKey, options: MongoIndexOptions): Promise<unknown>;
|
|
50
50
|
dropIndex(name: string): Promise<unknown>;
|
|
51
51
|
};
|
|
52
52
|
};
|
|
@@ -27,7 +27,7 @@ export function runMongoCommand(db, statement) {
|
|
|
27
27
|
return db.collection(command.collection).dropIndex(command.name);
|
|
28
28
|
default:
|
|
29
29
|
// Unreachable for a command this module produced; a hand-written statement lands here rather
|
|
30
|
-
// than being silently skipped
|
|
30
|
+
// than being silently skipped.
|
|
31
31
|
throw unsupportedMongoCommand(statement);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { ForeignKeyAction,
|
|
3
|
-
import type
|
|
4
|
-
import type {
|
|
5
|
-
export declare class MongoSchemaGenerator extends
|
|
1
|
+
import { MongoDialect } from '../../mongo/mongoDialect.js';
|
|
2
|
+
import type { ForeignKeyAction, TableNode } from '../../schema/types.js';
|
|
3
|
+
import { type CreateSchemaOptions, type EntityWhereMeta, type IndexSchema, type NamingStrategy, type SchemaDiff, type SchemaGenerator, type Type } from '../../type/index.js';
|
|
4
|
+
import type { AnyMigrationOperation } from '../builder/types.js';
|
|
5
|
+
export declare class MongoSchemaGenerator extends MongoDialect implements SchemaGenerator {
|
|
6
6
|
protected readonly defaultForeignKeyAction?: ForeignKeyAction | undefined;
|
|
7
|
-
readonly dialectName = "mongodb";
|
|
8
|
-
protected readonly featureDefaults: import("../../type/dialect.js").DialectFeatures;
|
|
9
|
-
readonly insertIdSource: InsertIdSource;
|
|
10
7
|
constructor(namingStrategy?: NamingStrategy, defaultForeignKeyAction?: ForeignKeyAction | undefined);
|
|
11
8
|
/** A collection has no SQL to render a check, a computed column or an index expression into. */
|
|
12
9
|
compileDdl(): string;
|
|
@@ -19,13 +16,18 @@ export declare class MongoSchemaGenerator extends AbstractDialect implements Sch
|
|
|
19
16
|
generateDropSchema(entities: readonly Type<object>[]): string[];
|
|
20
17
|
private selected;
|
|
21
18
|
/**
|
|
22
|
-
* The indexes
|
|
23
|
-
*
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
* The indexes an entity declares, as the collection would hold them. One owner because two paths need
|
|
20
|
+
* it: creating a collection, and working out which of its indexes are missing.
|
|
21
|
+
*/
|
|
22
|
+
private indexesOf;
|
|
23
|
+
/** One declared index, its members resolved to document paths and its `where` to a filter document. */
|
|
24
|
+
private indexSchema;
|
|
25
|
+
/**
|
|
26
|
+
* The JSON of the document `partialFilterExpression` takes, refused where the predicate reaches past
|
|
27
|
+
* what that holds or what a migration carries as JSON.
|
|
26
28
|
*/
|
|
27
|
-
|
|
28
|
-
generateCreateTable<E>(entity: Type<E>, _options?: {
|
|
29
|
+
compileIndexPredicate(where: EntityWhereMeta<object>, entity: Type<object>, indexName: string): string;
|
|
30
|
+
generateCreateTable<E extends object>(entity: Type<E>, _options?: {
|
|
29
31
|
ifNotExists?: boolean;
|
|
30
32
|
}): string[];
|
|
31
33
|
generateDropTable(tableName: string): string;
|
|
@@ -35,20 +37,13 @@ export declare class MongoSchemaGenerator extends AbstractDialect implements Sch
|
|
|
35
37
|
* MongoDB's key spec is where its index options live: `-1` for a descending entry and `'text'` for a
|
|
36
38
|
* full-text index, which is what `$text` needs since a text index declares its own fields.
|
|
37
39
|
*
|
|
38
|
-
* @remarks The SQL-only
|
|
39
|
-
*
|
|
40
|
-
*
|
|
40
|
+
* @remarks The SQL-only options are refused by the checks the SQL dialects refuse each other's with - a
|
|
41
|
+
* silently weaker index is worse than a clear failure. `where` is the filter's JSON, as
|
|
42
|
+
* {@link compileIndexPredicate} writes it.
|
|
41
43
|
*/
|
|
42
44
|
generateCreateIndex(tableName: string, index: IndexSchema): string;
|
|
43
45
|
generateDropIndex(tableName: string, indexName: string): string;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
ifNotExists?: boolean;
|
|
47
|
-
}): string[];
|
|
48
|
-
generateCreateIndexFromNode(index: IndexNode): string;
|
|
49
|
-
generateCreateTableFromDefinition(table: TableDefinition, _options?: {
|
|
50
|
-
ifNotExists?: boolean;
|
|
51
|
-
}): string[];
|
|
52
|
-
generateRenameTableSql(oldName: string, newName: string): string;
|
|
46
|
+
/** A collection and its indexes, which is all a document store has: a column, a constraint or SQL throws. */
|
|
47
|
+
generateOperation(operation: AnyMigrationOperation): string[];
|
|
53
48
|
diffSchema(entity: Type<object>, currentTable: TableNode | undefined): SchemaDiff | undefined;
|
|
54
49
|
}
|