@mikro-orm/sql 7.0.0-dev.98 → 7.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/AbstractSqlConnection.d.ts +6 -7
  2. package/AbstractSqlConnection.js +27 -24
  3. package/AbstractSqlDriver.d.ts +82 -23
  4. package/AbstractSqlDriver.js +584 -184
  5. package/AbstractSqlPlatform.d.ts +3 -4
  6. package/AbstractSqlPlatform.js +0 -4
  7. package/PivotCollectionPersister.d.ts +5 -0
  8. package/PivotCollectionPersister.js +30 -12
  9. package/SqlEntityManager.d.ts +2 -2
  10. package/dialects/mysql/{MySqlPlatform.d.ts → BaseMySqlPlatform.d.ts} +3 -2
  11. package/dialects/mysql/{MySqlPlatform.js → BaseMySqlPlatform.js} +5 -1
  12. package/dialects/mysql/MySqlSchemaHelper.d.ts +12 -1
  13. package/dialects/mysql/MySqlSchemaHelper.js +97 -6
  14. package/dialects/mysql/index.d.ts +1 -2
  15. package/dialects/mysql/index.js +1 -2
  16. package/dialects/postgresql/BasePostgreSqlPlatform.d.ts +106 -0
  17. package/dialects/postgresql/BasePostgreSqlPlatform.js +350 -0
  18. package/dialects/postgresql/FullTextType.d.ts +14 -0
  19. package/dialects/postgresql/FullTextType.js +59 -0
  20. package/dialects/postgresql/PostgreSqlExceptionConverter.d.ts +8 -0
  21. package/dialects/postgresql/PostgreSqlExceptionConverter.js +47 -0
  22. package/dialects/postgresql/PostgreSqlSchemaHelper.d.ts +90 -0
  23. package/dialects/postgresql/PostgreSqlSchemaHelper.js +732 -0
  24. package/dialects/postgresql/index.d.ts +3 -0
  25. package/dialects/postgresql/index.js +3 -0
  26. package/dialects/sqlite/BaseSqliteConnection.d.ts +1 -0
  27. package/dialects/sqlite/BaseSqliteConnection.js +14 -1
  28. package/dialects/sqlite/BaseSqlitePlatform.d.ts +6 -0
  29. package/dialects/sqlite/BaseSqlitePlatform.js +12 -0
  30. package/dialects/sqlite/SqliteSchemaHelper.d.ts +25 -0
  31. package/dialects/sqlite/SqliteSchemaHelper.js +145 -19
  32. package/dialects/sqlite/index.d.ts +0 -1
  33. package/dialects/sqlite/index.js +0 -1
  34. package/package.json +5 -6
  35. package/plugin/transformer.d.ts +1 -1
  36. package/plugin/transformer.js +1 -1
  37. package/query/CriteriaNode.d.ts +9 -5
  38. package/query/CriteriaNode.js +16 -15
  39. package/query/CriteriaNodeFactory.d.ts +6 -6
  40. package/query/CriteriaNodeFactory.js +33 -31
  41. package/query/NativeQueryBuilder.d.ts +3 -2
  42. package/query/NativeQueryBuilder.js +1 -2
  43. package/query/ObjectCriteriaNode.js +50 -35
  44. package/query/QueryBuilder.d.ts +548 -79
  45. package/query/QueryBuilder.js +537 -159
  46. package/query/QueryBuilderHelper.d.ts +22 -14
  47. package/query/QueryBuilderHelper.js +158 -69
  48. package/query/ScalarCriteriaNode.js +2 -2
  49. package/query/raw.d.ts +11 -3
  50. package/query/raw.js +1 -2
  51. package/schema/DatabaseSchema.d.ts +15 -2
  52. package/schema/DatabaseSchema.js +143 -15
  53. package/schema/DatabaseTable.d.ts +12 -0
  54. package/schema/DatabaseTable.js +91 -31
  55. package/schema/SchemaComparator.d.ts +8 -0
  56. package/schema/SchemaComparator.js +126 -3
  57. package/schema/SchemaHelper.d.ts +26 -3
  58. package/schema/SchemaHelper.js +98 -11
  59. package/schema/SqlSchemaGenerator.d.ts +10 -0
  60. package/schema/SqlSchemaGenerator.js +137 -9
  61. package/tsconfig.build.tsbuildinfo +1 -0
  62. package/typings.d.ts +74 -36
  63. package/dialects/postgresql/PostgreSqlTableCompiler.d.ts +0 -1
  64. package/dialects/postgresql/PostgreSqlTableCompiler.js +0 -1
@@ -1 +1,4 @@
1
1
  export * from './PostgreSqlNativeQueryBuilder.js';
2
+ export * from './BasePostgreSqlPlatform.js';
3
+ export * from './FullTextType.js';
4
+ export * from './PostgreSqlSchemaHelper.js';
@@ -1 +1,4 @@
1
1
  export * from './PostgreSqlNativeQueryBuilder.js';
2
+ export * from './BasePostgreSqlPlatform.js';
3
+ export * from './FullTextType.js';
4
+ export * from './PostgreSqlSchemaHelper.js';
@@ -3,4 +3,5 @@ export declare abstract class BaseSqliteConnection extends AbstractSqlConnection
3
3
  connect(options?: {
4
4
  skipOnConnect?: boolean;
5
5
  }): Promise<void>;
6
+ protected attachDatabases(): Promise<void>;
6
7
  }
@@ -3,6 +3,19 @@ import { AbstractSqlConnection } from '../../AbstractSqlConnection.js';
3
3
  export class BaseSqliteConnection extends AbstractSqlConnection {
4
4
  async connect(options) {
5
5
  await super.connect(options);
6
- await this.client.executeQuery(CompiledQuery.raw('pragma foreign_keys = on'));
6
+ await this.getClient().executeQuery(CompiledQuery.raw('pragma foreign_keys = on'));
7
+ await this.attachDatabases();
8
+ }
9
+ async attachDatabases() {
10
+ const attachDatabases = this.config.get('attachDatabases');
11
+ if (!attachDatabases?.length) {
12
+ return;
13
+ }
14
+ const { fs } = await import('@mikro-orm/core/fs-utils');
15
+ const baseDir = this.config.get('baseDir');
16
+ for (const db of attachDatabases) {
17
+ const path = fs.absolutePath(db.path, baseDir);
18
+ await this.execute(`attach database '${path}' as ${this.platform.quoteIdentifier(db.name)}`);
19
+ }
7
20
  }
8
21
  }
@@ -64,6 +64,12 @@ export declare abstract class BaseSqlitePlatform extends AbstractSqlPlatform {
64
64
  processDateProperty(value: unknown): string | number | Date;
65
65
  getIndexName(tableName: string, columns: string[], type: 'index' | 'unique' | 'foreign' | 'primary' | 'sequence'): string;
66
66
  supportsDeferredUniqueConstraints(): boolean;
67
+ /**
68
+ * SQLite supports schemas via ATTACH DATABASE. Returns true when there are
69
+ * attached databases configured.
70
+ */
71
+ supportsSchemas(): boolean;
72
+ getDefaultSchemaName(): string | undefined;
67
73
  getFullTextWhereClause(): string;
68
74
  quoteVersionValue(value: Date | number, prop: EntityProperty): Date | string | number;
69
75
  quoteValue(value: any): string;
@@ -86,6 +86,18 @@ export class BaseSqlitePlatform extends AbstractSqlPlatform {
86
86
  supportsDeferredUniqueConstraints() {
87
87
  return false;
88
88
  }
89
+ /**
90
+ * SQLite supports schemas via ATTACH DATABASE. Returns true when there are
91
+ * attached databases configured.
92
+ */
93
+ supportsSchemas() {
94
+ const attachDatabases = this.config.get('attachDatabases');
95
+ return !!attachDatabases?.length;
96
+ }
97
+ getDefaultSchemaName() {
98
+ // Return 'main' only when schema support is active (i.e., databases are attached)
99
+ return this.supportsSchemas() ? 'main' : undefined;
100
+ }
89
101
  getFullTextWhereClause() {
90
102
  return `:column: match :query`;
91
103
  }
@@ -8,7 +8,14 @@ export declare class SqliteSchemaHelper extends SchemaHelper {
8
8
  disableForeignKeysSQL(): string;
9
9
  enableForeignKeysSQL(): string;
10
10
  supportsSchemaConstraints(): boolean;
11
+ getCreateNamespaceSQL(name: string): string;
12
+ getDropNamespaceSQL(name: string): string;
11
13
  getListTablesSQL(): string;
14
+ getAllTables(connection: AbstractSqlConnection, schemas?: string[]): Promise<Table[]>;
15
+ getNamespaces(connection: AbstractSqlConnection): Promise<string[]>;
16
+ private getIgnoredViewsCondition;
17
+ getListViewsSQL(): string;
18
+ loadViews(schema: DatabaseSchema, connection: AbstractSqlConnection, schemaName?: string): Promise<void>;
12
19
  getDropDatabaseSQL(name: string): string;
13
20
  loadInformationSchema(schema: DatabaseSchema, connection: AbstractSqlConnection, tables: Table[], schemas?: string[]): Promise<void>;
14
21
  createTable(table: DatabaseTable, alter?: boolean): string[];
@@ -18,6 +25,19 @@ export declare class SqliteSchemaHelper extends SchemaHelper {
18
25
  getDropColumnsSQL(tableName: string, columns: Column[], schemaName?: string): string;
19
26
  getCreateIndexSQL(tableName: string, index: IndexDef): string;
20
27
  private parseTableDefinition;
28
+ /**
29
+ * Returns schema prefix for pragma and sqlite_master queries.
30
+ * Returns empty string for main database (no prefix needed).
31
+ */
32
+ private getSchemaPrefix;
33
+ /**
34
+ * Returns all database names excluding 'temp'.
35
+ */
36
+ private getDatabaseList;
37
+ /**
38
+ * Extracts the SELECT part from a CREATE VIEW statement.
39
+ */
40
+ private extractViewDefinition;
21
41
  private getColumns;
22
42
  private getEnumDefinitions;
23
43
  getPrimaryKeys(connection: AbstractSqlConnection, indexes: IndexDef[], tableName: string, schemaName?: string): Promise<string[]>;
@@ -33,6 +53,11 @@ export declare class SqliteSchemaHelper extends SchemaHelper {
33
53
  */
34
54
  isImplicitIndex(name: string): boolean;
35
55
  dropIndex(table: string, index: IndexDef, oldIndexName?: string): string;
56
+ /**
57
+ * SQLite does not support schema-qualified table names in REFERENCES clauses.
58
+ * Foreign key references can only point to tables in the same database.
59
+ */
60
+ getReferencedTableName(referencedTableName: string, schema?: string): string;
36
61
  alterTable(diff: TableDifference, safe?: boolean): string[];
37
62
  private getAlterTempTableSQL;
38
63
  }
@@ -1,5 +1,19 @@
1
1
  import { Utils } from '@mikro-orm/core';
2
2
  import { SchemaHelper } from '../../schema/SchemaHelper.js';
3
+ /** SpatiaLite system views that should be automatically ignored */
4
+ const SPATIALITE_VIEWS = [
5
+ 'geometry_columns',
6
+ 'spatial_ref_sys',
7
+ 'views_geometry_columns',
8
+ 'virts_geometry_columns',
9
+ 'geom_cols_ref_sys',
10
+ 'spatial_ref_sys_aux',
11
+ 'vector_layers',
12
+ 'vector_layers_auth',
13
+ 'vector_layers_field_infos',
14
+ 'vector_layers_statistics',
15
+ 'ElementaryGeometries',
16
+ ];
3
17
  export class SqliteSchemaHelper extends SchemaHelper {
4
18
  disableForeignKeysSQL() {
5
19
  return 'pragma foreign_keys = off;';
@@ -10,10 +24,67 @@ export class SqliteSchemaHelper extends SchemaHelper {
10
24
  supportsSchemaConstraints() {
11
25
  return false;
12
26
  }
27
+ getCreateNamespaceSQL(name) {
28
+ return '';
29
+ }
30
+ getDropNamespaceSQL(name) {
31
+ return '';
32
+ }
13
33
  getListTablesSQL() {
14
34
  return `select name as table_name from sqlite_master where type = 'table' and name != 'sqlite_sequence' and name != 'geometry_columns' and name != 'spatial_ref_sys' `
15
35
  + `union all select name as table_name from sqlite_temp_master where type = 'table' order by name`;
16
36
  }
37
+ async getAllTables(connection, schemas) {
38
+ const databases = await this.getDatabaseList(connection);
39
+ const hasAttachedDbs = databases.length > 1; // More than just 'main'
40
+ // If no attached databases, use original behavior
41
+ if (!hasAttachedDbs && !schemas?.length) {
42
+ return connection.execute(this.getListTablesSQL());
43
+ }
44
+ // With attached databases, query each one
45
+ const targetSchemas = schemas?.length ? schemas : databases;
46
+ const allTables = [];
47
+ for (const dbName of targetSchemas) {
48
+ const prefix = this.getSchemaPrefix(dbName);
49
+ const tables = await connection.execute(`select name from ${prefix}sqlite_master where type = 'table' ` +
50
+ `and name != 'sqlite_sequence' and name != 'geometry_columns' and name != 'spatial_ref_sys'`);
51
+ for (const t of tables) {
52
+ allTables.push({ table_name: t.name, schema_name: dbName });
53
+ }
54
+ }
55
+ return allTables;
56
+ }
57
+ async getNamespaces(connection) {
58
+ return this.getDatabaseList(connection);
59
+ }
60
+ getIgnoredViewsCondition() {
61
+ return SPATIALITE_VIEWS.map(v => `name != '${v}'`).join(' and ');
62
+ }
63
+ getListViewsSQL() {
64
+ return `select name as view_name, sql as view_definition from sqlite_master where type = 'view' and ${this.getIgnoredViewsCondition()} order by name`;
65
+ }
66
+ async loadViews(schema, connection, schemaName) {
67
+ const databases = await this.getDatabaseList(connection);
68
+ const hasAttachedDbs = databases.length > 1; // More than just 'main'
69
+ // If no attached databases and no specific schema, use original behavior
70
+ if (!hasAttachedDbs && !schemaName) {
71
+ const views = await connection.execute(this.getListViewsSQL());
72
+ for (const view of views) {
73
+ schema.addView(view.view_name, schemaName, this.extractViewDefinition(view.view_definition));
74
+ }
75
+ return;
76
+ }
77
+ // With attached databases, query each one
78
+ /* v8 ignore next - schemaName branch not commonly used */
79
+ const targetDbs = schemaName ? [schemaName] : databases;
80
+ for (const dbName of targetDbs) {
81
+ const prefix = this.getSchemaPrefix(dbName);
82
+ const views = await connection.execute(`select name as view_name, sql as view_definition from ${prefix}sqlite_master where type = 'view' and ${this.getIgnoredViewsCondition()} order by name`);
83
+ for (const view of views) {
84
+ schema.addView(view.view_name, dbName, this.extractViewDefinition(view.view_definition));
85
+ }
86
+ }
87
+ }
17
88
  getDropDatabaseSQL(name) {
18
89
  if (name === ':memory:') {
19
90
  return '';
@@ -29,7 +100,7 @@ export class SqliteSchemaHelper extends SchemaHelper {
29
100
  const checks = await this.getChecks(connection, table.name, table.schema);
30
101
  const pks = await this.getPrimaryKeys(connection, indexes, table.name, table.schema);
31
102
  const fks = await this.getForeignKeys(connection, table.name, table.schema);
32
- const enums = await this.getEnumDefinitions(connection, table.name);
103
+ const enums = await this.getEnumDefinitions(connection, table.name, table.schema);
33
104
  table.init(cols, indexes, checks, pks, fks, enums);
34
105
  }
35
106
  }
@@ -61,6 +132,9 @@ export class SqliteSchemaHelper extends SchemaHelper {
61
132
  sql += ', ' + parts.join(', ');
62
133
  }
63
134
  sql += ')';
135
+ if (table.comment) {
136
+ sql += ` /* ${table.comment} */`;
137
+ }
64
138
  const ret = [];
65
139
  this.append(ret, sql);
66
140
  for (const index of table.getIndexes()) {
@@ -118,16 +192,27 @@ export class SqliteSchemaHelper extends SchemaHelper {
118
192
  if (index.expression) {
119
193
  return index.expression;
120
194
  }
121
- tableName = this.quote(tableName);
122
- const keyName = this.quote(index.keyName);
123
- const sql = `create ${index.unique ? 'unique ' : ''}index ${keyName} on ${tableName} `;
195
+ // SQLite requires: CREATE INDEX schema.index_name ON table_name (columns)
196
+ // NOT: CREATE INDEX index_name ON schema.table_name (columns)
197
+ const [schemaName, rawTableName] = this.splitTableName(tableName);
198
+ const quotedTableName = this.quote(rawTableName);
199
+ // If there's a schema, prefix the index name with it
200
+ let keyName;
201
+ if (schemaName && schemaName !== 'main') {
202
+ keyName = `${this.quote(schemaName)}.${this.quote(index.keyName)}`;
203
+ }
204
+ else {
205
+ keyName = this.quote(index.keyName);
206
+ }
207
+ const sqlPrefix = `create ${index.unique ? 'unique ' : ''}index ${keyName} on ${quotedTableName}`;
208
+ /* v8 ignore next 4 */
124
209
  if (index.columnNames.some(column => column.includes('.'))) {
125
210
  // JSON columns can have unique index but not unique constraint, and we need to distinguish those, so we can properly drop them
126
- const sql = `create ${index.unique ? 'unique ' : ''}index ${keyName} on ${tableName} `;
127
211
  const columns = this.platform.getJsonIndexDefinition(index);
128
- return `${sql}(${columns.join(', ')})`;
212
+ return `${sqlPrefix} (${columns.join(', ')})`;
129
213
  }
130
- return `${sql}(${index.columnNames.map(c => this.quote(c)).join(', ')})`;
214
+ // Use getIndexColumns to support advanced options like sort order and collation
215
+ return `${sqlPrefix} (${this.getIndexColumns(index)})`;
131
216
  }
132
217
  parseTableDefinition(sql, cols) {
133
218
  const columns = {};
@@ -152,9 +237,35 @@ export class SqliteSchemaHelper extends SchemaHelper {
152
237
  }
153
238
  return { columns, constraints };
154
239
  }
240
+ /**
241
+ * Returns schema prefix for pragma and sqlite_master queries.
242
+ * Returns empty string for main database (no prefix needed).
243
+ */
244
+ getSchemaPrefix(schemaName) {
245
+ if (!schemaName || schemaName === 'main') {
246
+ return '';
247
+ }
248
+ return `${this.platform.quoteIdentifier(schemaName)}.`;
249
+ }
250
+ /**
251
+ * Returns all database names excluding 'temp'.
252
+ */
253
+ async getDatabaseList(connection) {
254
+ const databases = await connection.execute('pragma database_list');
255
+ return databases.filter(d => d.name !== 'temp').map(d => d.name);
256
+ }
257
+ /**
258
+ * Extracts the SELECT part from a CREATE VIEW statement.
259
+ */
260
+ extractViewDefinition(viewDefinition) {
261
+ const match = viewDefinition?.match(/create\s+view\s+[`"']?\w+[`"']?\s+as\s+(.*)/i);
262
+ /* v8 ignore next - fallback for non-standard view definitions */
263
+ return match ? match[1] : viewDefinition;
264
+ }
155
265
  async getColumns(connection, tableName, schemaName) {
156
- const columns = await connection.execute(`pragma table_xinfo('${tableName}')`);
157
- const sql = `select sql from sqlite_master where type = ? and name = ?`;
266
+ const prefix = this.getSchemaPrefix(schemaName);
267
+ const columns = await connection.execute(`pragma ${prefix}table_xinfo('${tableName}')`);
268
+ const sql = `select sql from ${prefix}sqlite_master where type = ? and name = ?`;
158
269
  const tableDefinition = await connection.execute(sql, ['table', tableName], 'get');
159
270
  const composite = columns.reduce((count, col) => count + (col.pk ? 1 : 0), 0) > 1;
160
271
  // there can be only one, so naive check like this should be enough
@@ -185,8 +296,9 @@ export class SqliteSchemaHelper extends SchemaHelper {
185
296
  };
186
297
  });
187
298
  }
188
- async getEnumDefinitions(connection, tableName) {
189
- const sql = `select sql from sqlite_master where type = ? and name = ?`;
299
+ async getEnumDefinitions(connection, tableName, schemaName) {
300
+ const prefix = this.getSchemaPrefix(schemaName);
301
+ const sql = `select sql from ${prefix}sqlite_master where type = ? and name = ?`;
190
302
  const tableDefinition = await connection.execute(sql, ['table', tableName], 'get');
191
303
  const checkConstraints = [...(tableDefinition.sql.match(/[`["'][^`\]"']+[`\]"'] text check \(.*?\)/gi) ?? [])];
192
304
  return checkConstraints.reduce((o, item) => {
@@ -201,14 +313,16 @@ export class SqliteSchemaHelper extends SchemaHelper {
201
313
  }, {});
202
314
  }
203
315
  async getPrimaryKeys(connection, indexes, tableName, schemaName) {
204
- const sql = `pragma table_info(\`${tableName}\`)`;
316
+ const prefix = this.getSchemaPrefix(schemaName);
317
+ const sql = `pragma ${prefix}table_info(\`${tableName}\`)`;
205
318
  const cols = await connection.execute(sql);
206
319
  return cols.filter(col => !!col.pk).map(col => col.name);
207
320
  }
208
321
  async getIndexes(connection, tableName, schemaName) {
209
- const sql = `pragma table_info(\`${tableName}\`)`;
322
+ const prefix = this.getSchemaPrefix(schemaName);
323
+ const sql = `pragma ${prefix}table_info(\`${tableName}\`)`;
210
324
  const cols = await connection.execute(sql);
211
- const indexes = await connection.execute(`pragma index_list(\`${tableName}\`)`);
325
+ const indexes = await connection.execute(`pragma ${prefix}index_list(\`${tableName}\`)`);
212
326
  const ret = [];
213
327
  for (const col of cols.filter(c => c.pk)) {
214
328
  ret.push({
@@ -220,7 +334,7 @@ export class SqliteSchemaHelper extends SchemaHelper {
220
334
  });
221
335
  }
222
336
  for (const index of indexes.filter(index => !this.isImplicitIndex(index.name))) {
223
- const res = await connection.execute(`pragma index_info(\`${index.name}\`)`);
337
+ const res = await connection.execute(`pragma ${prefix}index_info(\`${index.name}\`)`);
224
338
  ret.push(...res.map(row => ({
225
339
  columnNames: [row.name],
226
340
  keyName: index.name,
@@ -259,14 +373,17 @@ export class SqliteSchemaHelper extends SchemaHelper {
259
373
  return checks;
260
374
  }
261
375
  async getColumnDefinitions(connection, tableName, schemaName) {
262
- const columns = await connection.execute(`pragma table_xinfo('${tableName}')`);
263
- const sql = `select sql from sqlite_master where type = ? and name = ?`;
376
+ const prefix = this.getSchemaPrefix(schemaName);
377
+ const columns = await connection.execute(`pragma ${prefix}table_xinfo('${tableName}')`);
378
+ const sql = `select sql from ${prefix}sqlite_master where type = ? and name = ?`;
264
379
  const tableDefinition = await connection.execute(sql, ['table', tableName], 'get');
265
380
  return this.parseTableDefinition(tableDefinition.sql, columns);
266
381
  }
267
382
  async getForeignKeys(connection, tableName, schemaName) {
268
383
  const { constraints } = await this.getColumnDefinitions(connection, tableName, schemaName);
269
- const fks = await connection.execute(`pragma foreign_key_list(\`${tableName}\`)`);
384
+ const prefix = this.getSchemaPrefix(schemaName);
385
+ const fks = await connection.execute(`pragma ${prefix}foreign_key_list(\`${tableName}\`)`);
386
+ const qualifiedTableName = schemaName ? `${schemaName}.${tableName}` : tableName;
270
387
  return fks.reduce((ret, fk) => {
271
388
  const constraintName = this.platform.getIndexName(tableName, [fk.from], 'foreign');
272
389
  const constraint = constraints?.find(c => c.includes(constraintName));
@@ -274,7 +391,7 @@ export class SqliteSchemaHelper extends SchemaHelper {
274
391
  constraintName,
275
392
  columnName: fk.from,
276
393
  columnNames: [fk.from],
277
- localTableName: tableName,
394
+ localTableName: qualifiedTableName,
278
395
  referencedTableName: fk.table,
279
396
  referencedColumnName: fk.to,
280
397
  referencedColumnNames: [fk.to],
@@ -305,6 +422,15 @@ export class SqliteSchemaHelper extends SchemaHelper {
305
422
  dropIndex(table, index, oldIndexName = index.keyName) {
306
423
  return `drop index ${this.quote(oldIndexName)}`;
307
424
  }
425
+ /**
426
+ * SQLite does not support schema-qualified table names in REFERENCES clauses.
427
+ * Foreign key references can only point to tables in the same database.
428
+ */
429
+ getReferencedTableName(referencedTableName, schema) {
430
+ const [schemaName, tableName] = this.splitTableName(referencedTableName);
431
+ // Strip any schema prefix - SQLite REFERENCES clause doesn't support it
432
+ return tableName;
433
+ }
308
434
  alterTable(diff, safe) {
309
435
  const ret = [];
310
436
  const [schemaName, tableName] = this.splitTableName(diff.name);
@@ -2,4 +2,3 @@ export * from './BaseSqliteConnection.js';
2
2
  export * from './BaseSqlitePlatform.js';
3
3
  export * from './SqliteSchemaHelper.js';
4
4
  export * from './SqliteNativeQueryBuilder.js';
5
- export * from './SqliteExceptionConverter.js';
@@ -2,4 +2,3 @@ export * from './BaseSqliteConnection.js';
2
2
  export * from './BaseSqlitePlatform.js';
3
3
  export * from './SqliteSchemaHelper.js';
4
4
  export * from './SqliteNativeQueryBuilder.js';
5
- export * from './SqliteExceptionConverter.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/sql",
3
- "version": "7.0.0-dev.98",
3
+ "version": "7.0.0-rc.0",
4
4
  "description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -41,7 +41,7 @@
41
41
  "node": ">= 22.17.0"
42
42
  },
43
43
  "scripts": {
44
- "build": "yarn clean && yarn compile && yarn copy",
44
+ "build": "yarn compile && yarn copy",
45
45
  "clean": "yarn run -T rimraf ./dist",
46
46
  "compile": "yarn run -T tsc -p tsconfig.build.json",
47
47
  "copy": "node ../../scripts/copy.mjs"
@@ -50,13 +50,12 @@
50
50
  "access": "public"
51
51
  },
52
52
  "dependencies": {
53
- "kysely": "0.28.8",
54
- "sqlstring": "2.3.3"
53
+ "kysely": "0.28.11"
55
54
  },
56
55
  "devDependencies": {
57
- "@mikro-orm/core": "^6.6.2"
56
+ "@mikro-orm/core": "^6.6.4"
58
57
  },
59
58
  "peerDependencies": {
60
- "@mikro-orm/core": "7.0.0-dev.98"
59
+ "@mikro-orm/core": "7.0.0-rc.0"
61
60
  }
62
61
  }
@@ -23,7 +23,7 @@ export declare class MikroTransformer extends OperationNodeTransformer {
23
23
  * Global map of all entities involved in the query.
24
24
  * Populated during AST transformation and used for result transformation.
25
25
  */
26
- protected readonly entityMap: Map<string, EntityMetadata<any>>;
26
+ protected readonly entityMap: Map<string, EntityMetadata<any, import("@mikro-orm/core").EntityCtor<any>>>;
27
27
  constructor(em: SqlEntityManager, options?: MikroKyselyPluginOptions);
28
28
  reset(): void;
29
29
  getOutputEntityMap(): Map<string, EntityMetadata>;
@@ -706,7 +706,7 @@ export class MikroTransformer extends OperationNodeTransformer {
706
706
  * Find entity metadata by table name or entity name
707
707
  */
708
708
  findEntityMetadata(name) {
709
- const byEntity = this.metadata.find(name);
709
+ const byEntity = this.metadata.getByClassName(name, false);
710
710
  if (byEntity) {
711
711
  return byEntity;
712
712
  }
@@ -1,4 +1,4 @@
1
- import { type EntityKey, type EntityProperty, type MetadataStorage } from '@mikro-orm/core';
1
+ import { type EntityKey, type EntityProperty, type MetadataStorage, type RawQueryFragmentSymbol, type EntityName } from '@mikro-orm/core';
2
2
  import type { ICriteriaNode, ICriteriaNodeProcessOptions, IQueryBuilder } from '../typings.js';
3
3
  /**
4
4
  * Helper for working with deeply nested where/orderBy/having criteria. Uses composite pattern to build tree from the payload.
@@ -7,21 +7,25 @@ import type { ICriteriaNode, ICriteriaNodeProcessOptions, IQueryBuilder } from '
7
7
  */
8
8
  export declare class CriteriaNode<T extends object> implements ICriteriaNode<T> {
9
9
  protected readonly metadata: MetadataStorage;
10
- readonly entityName: string;
10
+ readonly entityName: EntityName<T>;
11
11
  readonly parent?: ICriteriaNode<T> | undefined;
12
- readonly key?: EntityKey<T> | undefined;
12
+ readonly key?: (EntityKey<T> | RawQueryFragmentSymbol) | undefined;
13
+ readonly validate: boolean;
13
14
  readonly strict: boolean;
14
15
  payload: any;
15
16
  prop?: EntityProperty<T>;
16
17
  index?: number;
17
- constructor(metadata: MetadataStorage, entityName: string, parent?: ICriteriaNode<T> | undefined, key?: EntityKey<T> | undefined, validate?: boolean, strict?: boolean);
18
+ constructor(metadata: MetadataStorage, entityName: EntityName<T>, parent?: ICriteriaNode<T> | undefined, key?: (EntityKey<T> | RawQueryFragmentSymbol) | undefined, validate?: boolean, strict?: boolean);
18
19
  process(qb: IQueryBuilder<T>, options?: ICriteriaNodeProcessOptions): any;
19
20
  unwrap(): any;
20
21
  shouldInline(payload: any): boolean;
21
22
  willAutoJoin(qb: IQueryBuilder<T>, alias?: string, options?: ICriteriaNodeProcessOptions): boolean;
22
23
  shouldRename(payload: any): boolean;
23
24
  renameFieldToPK<T>(qb: IQueryBuilder<T>, ownerAlias?: string): string;
24
- getPath(addIndex?: boolean): string;
25
+ getPath(opts?: {
26
+ addIndex?: boolean;
27
+ parentPath?: string;
28
+ }): string;
25
29
  private isPivotJoin;
26
30
  getPivotPath(path: string): string;
27
31
  aliased(field: string, alias?: string): string;
@@ -9,6 +9,7 @@ export class CriteriaNode {
9
9
  entityName;
10
10
  parent;
11
11
  key;
12
+ validate;
12
13
  strict;
13
14
  payload;
14
15
  prop;
@@ -18,9 +19,10 @@ export class CriteriaNode {
18
19
  this.entityName = entityName;
19
20
  this.parent = parent;
20
21
  this.key = key;
22
+ this.validate = validate;
21
23
  this.strict = strict;
22
24
  const meta = parent && metadata.find(parent.entityName);
23
- if (meta && key) {
25
+ if (meta && key && !RawQueryFragment.isKnownFragmentSymbol(key)) {
24
26
  const pks = Utils.splitPrimaryKeys(key);
25
27
  if (pks.length > 1) {
26
28
  return;
@@ -29,8 +31,8 @@ export class CriteriaNode {
29
31
  this.prop = meta.props.find(prop => prop.name === k || (prop.fieldNames?.length === 1 && prop.fieldNames[0] === k && prop.persist !== false));
30
32
  const isProp = this.prop || meta.props.find(prop => (prop.fieldNames || []).includes(k));
31
33
  // do not validate if the key is prefixed or type casted (e.g. `k::text`)
32
- if (validate && !isProp && !k.includes('.') && !k.includes('::') && !Utils.isOperator(k) && !RawQueryFragment.isKnownFragment(k)) {
33
- throw new Error(`Trying to query by not existing property ${entityName}.${k}`);
34
+ if (validate && !isProp && !k.includes('.') && !k.includes('::') && !Utils.isOperator(k)) {
35
+ throw new Error(`Trying to query by not existing property ${Utils.className(entityName)}.${k}`);
34
36
  }
35
37
  }
36
38
  }
@@ -50,11 +52,9 @@ export class CriteriaNode {
50
52
  shouldRename(payload) {
51
53
  const type = this.prop ? this.prop.kind : null;
52
54
  const composite = this.prop?.joinColumns ? this.prop.joinColumns.length > 1 : false;
53
- const customExpression = RawQueryFragment.isKnownFragment(this.key);
54
- const scalar = payload === null || Utils.isPrimaryKey(payload) || payload instanceof RegExp || payload instanceof Date || customExpression;
55
- const plainObject = Utils.isPlainObject(payload);
56
- const keys = plainObject ? Object.keys(payload) : [];
57
- const operator = plainObject && keys.every(k => Utils.isOperator(k, false));
55
+ const rawField = RawQueryFragment.isKnownFragmentSymbol(this.key);
56
+ const scalar = payload === null || Utils.isPrimaryKey(payload) || payload instanceof RegExp || payload instanceof Date || rawField;
57
+ const operator = Utils.isPlainObject(payload) && Utils.getObjectQueryKeys(payload).every(k => Utils.isOperator(k, false));
58
58
  if (composite) {
59
59
  return true;
60
60
  }
@@ -78,13 +78,13 @@ export class CriteriaNode {
78
78
  }
79
79
  return Utils.getPrimaryKeyHash(this.prop.referencedColumnNames.map(col => `${alias}.${col}`));
80
80
  }
81
- getPath(addIndex = false) {
81
+ getPath(opts) {
82
82
  // use index on parent only if we are processing to-many relation
83
83
  const addParentIndex = this.prop && [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(this.prop.kind);
84
- const parentPath = this.parent?.getPath(addParentIndex) ?? this.entityName;
85
- const index = addIndex && this.index != null ? `[${this.index}]` : '';
84
+ const parentPath = opts?.parentPath ?? this.parent?.getPath({ addIndex: addParentIndex }) ?? Utils.className(this.entityName);
85
+ const index = opts?.addIndex && this.index != null ? `[${this.index}]` : '';
86
86
  // ignore group operators to allow easier mapping (e.g. for orderBy)
87
- const key = this.key && !['$and', '$or', '$not'].includes(this.key) ? '.' + this.key : '';
87
+ const key = this.key && !RawQueryFragment.isKnownFragmentSymbol(this.key) && !['$and', '$or', '$not'].includes(this.key) ? '.' + this.key : '';
88
88
  const ret = parentPath + index + key;
89
89
  if (this.isPivotJoin()) {
90
90
  // distinguish pivot table join from target entity join
@@ -96,9 +96,9 @@ export class CriteriaNode {
96
96
  if (!this.key || !this.prop) {
97
97
  return false;
98
98
  }
99
- const customExpression = RawQueryFragment.isKnownFragment(this.key);
100
- const scalar = this.payload === null || Utils.isPrimaryKey(this.payload) || this.payload instanceof RegExp || this.payload instanceof Date || customExpression;
101
- const operator = Utils.isObject(this.payload) && Object.keys(this.payload).every(k => Utils.isOperator(k, false));
99
+ const rawField = RawQueryFragment.isKnownFragmentSymbol(this.key);
100
+ const scalar = this.payload === null || Utils.isPrimaryKey(this.payload) || this.payload instanceof RegExp || this.payload instanceof Date || rawField;
101
+ const operator = Utils.isObject(this.payload) && Utils.getObjectQueryKeys(this.payload).every(k => Utils.isOperator(k, false));
102
102
  return this.prop.kind === ReferenceKind.MANY_TO_MANY && (scalar || operator);
103
103
  }
104
104
  getPivotPath(path) {
@@ -111,6 +111,7 @@ export class CriteriaNode {
111
111
  return this.strict;
112
112
  }
113
113
  /** @ignore */
114
+ /* v8 ignore next */
114
115
  [Symbol.for('nodejs.util.inspect.custom')]() {
115
116
  const o = {};
116
117
  ['entityName', 'key', 'index', 'payload']
@@ -1,12 +1,12 @@
1
- import { type Dictionary, type EntityKey, type EntityMetadata, type MetadataStorage } from '@mikro-orm/core';
1
+ import { type Dictionary, type EntityKey, type EntityMetadata, type EntityName, type MetadataStorage, type RawQueryFragmentSymbol } from '@mikro-orm/core';
2
2
  import type { ICriteriaNode } from '../typings.js';
3
3
  /**
4
4
  * @internal
5
5
  */
6
6
  export declare class CriteriaNodeFactory {
7
- static createNode<T extends object>(metadata: MetadataStorage, entityName: string, payload: any, parent?: ICriteriaNode<T>, key?: EntityKey<T>): ICriteriaNode<T>;
8
- static createScalarNode<T extends object>(metadata: MetadataStorage, entityName: string, payload: any, parent?: ICriteriaNode<T>, key?: EntityKey<T>): ICriteriaNode<T>;
9
- static createArrayNode<T extends object>(metadata: MetadataStorage, entityName: string, payload: any[], parent?: ICriteriaNode<T>, key?: EntityKey<T>): ICriteriaNode<T>;
10
- static createObjectNode<T extends object>(metadata: MetadataStorage, entityName: string, payload: Dictionary, parent?: ICriteriaNode<T>, key?: EntityKey<T>): ICriteriaNode<T>;
11
- static createObjectItemNode<T extends object>(metadata: MetadataStorage, entityName: string, node: ICriteriaNode<T>, payload: Dictionary, key: EntityKey<T>, meta?: EntityMetadata<T>): ICriteriaNode<T>;
7
+ static createNode<T extends object>(metadata: MetadataStorage, entityName: EntityName<T>, payload: any, parent?: ICriteriaNode<T>, key?: EntityKey<T> | RawQueryFragmentSymbol, validate?: boolean): ICriteriaNode<T>;
8
+ static createScalarNode<T extends object>(metadata: MetadataStorage, entityName: EntityName<T>, payload: any, parent?: ICriteriaNode<T>, key?: EntityKey<T> | RawQueryFragmentSymbol, validate?: boolean): ICriteriaNode<T>;
9
+ static createArrayNode<T extends object>(metadata: MetadataStorage, entityName: EntityName<T>, payload: any[], parent?: ICriteriaNode<T>, key?: EntityKey<T>, validate?: boolean): ICriteriaNode<T>;
10
+ static createObjectNode<T extends object>(metadata: MetadataStorage, entityName: EntityName<T>, payload: Dictionary, parent?: ICriteriaNode<T>, key?: EntityKey<T>, validate?: boolean): ICriteriaNode<T>;
11
+ static createObjectItemNode<T extends object>(metadata: MetadataStorage, entityName: EntityName<T>, node: ICriteriaNode<T>, payload: Dictionary, key: EntityKey<T> | RawQueryFragmentSymbol, meta?: EntityMetadata<T>, validate?: boolean): ICriteriaNode<T>;
12
12
  }