@mikro-orm/sql 7.1.9-dev.24 → 7.1.9-dev.25

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.
@@ -1356,9 +1356,10 @@ export class AbstractSqlDriver extends DatabaseDriver {
1356
1356
  const childExclude = !Utils.isEmpty(options?.exclude)
1357
1357
  ? options.exclude.map(f => `${inverseProp.name}.${f}`)
1358
1358
  : [];
1359
- // the owner relation is virtual, so the FK columns have to be selected via the per-column pivot
1360
- // props a composite owner PK gets; a single column owner PK is covered by the flat prop itself
1361
- const ownerFields = ownerMeta.compositePK ? prop.joinColumns : [prop.discriminator];
1359
+ // the owner relation is virtual, so its FK columns have to be selected via the pivot props that
1360
+ // cover them; only the first owner of a shared pivot gets the flat prop named after the
1361
+ // discriminator, and it keeps that owner's columns, so later owners get per-column props instead
1362
+ const ownerFields = Utils.unique(prop.joinColumns.map(col => (pivotMeta.properties[col] ? col : prop.discriminator)));
1362
1363
  const fields = pivotJoin
1363
1364
  ? [inverseProp.name, ...ownerFields, prop.discriminatorColumn]
1364
1365
  : [inverseProp.name, ...ownerFields, prop.discriminatorColumn, ...childFields];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/sql",
3
- "version": "7.1.9-dev.24",
3
+ "version": "7.1.9-dev.25",
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
  "keywords": [
6
6
  "data-mapper",
@@ -53,7 +53,7 @@
53
53
  "@mikro-orm/core": "^7.1.8"
54
54
  },
55
55
  "peerDependencies": {
56
- "@mikro-orm/core": "7.1.9-dev.24"
56
+ "@mikro-orm/core": "7.1.9-dev.25"
57
57
  },
58
58
  "engines": {
59
59
  "node": ">= 22.17.0"
@@ -54,6 +54,8 @@ export declare class SqlSchemaGenerator extends AbstractSchemaGenerator<Abstract
54
54
  wrap?: boolean;
55
55
  ctx?: Transaction;
56
56
  }): Promise<void>;
57
+ /** Splits the SQL on the separator, keeping the separators that fall inside a string literal. */
58
+ private splitOutsideLiterals;
57
59
  /** Whether the statement has to be the first one in a query batch, e.g. `create trigger` on MSSQL. */
58
60
  protected startsBatch(_statement: string): boolean;
59
61
  dropTableIfExists(name: string, schema?: string): Promise<void>;
@@ -439,7 +439,7 @@ export class SqlSchemaGenerator extends AbstractSchemaGenerator {
439
439
  }
440
440
  async execute(sql, options = {}) {
441
441
  options.wrap ??= false;
442
- const lines = this.wrapSchema(sql, options).split('\n');
442
+ const lines = this.splitOutsideLiterals(this.wrapSchema(sql, options), '\n');
443
443
  const groups = [];
444
444
  let i = 0;
445
445
  for (const line of lines) {
@@ -468,14 +468,33 @@ export class SqlSchemaGenerator extends AbstractSchemaGenerator {
468
468
  return;
469
469
  }
470
470
  const statements = groups.flatMap(group => {
471
- return group
472
- .join('\n')
473
- .split(';\n')
471
+ return this.splitOutsideLiterals(group.join('\n'), ';\n')
474
472
  .map(s => s.trim())
475
473
  .filter(s => s);
476
474
  });
477
475
  await Utils.runSerial(statements, stmt => this.driver.execute(stmt));
478
476
  }
477
+ /** Splits the SQL on the separator, keeping the separators that fall inside a string literal. */
478
+ splitOutsideLiterals(sql, separator) {
479
+ const [idOpen, idClose] = this.platform.quoteIdentifier('');
480
+ // mysql escapes quotes as `\'`, the other dialects double them, which pairs up on its own
481
+ const esc = this.platform.quoteValue(`'`).includes(`\\'`) ? '\\\\.|' : '';
482
+ // complete literals, quoted identifiers and `--` comments, so that an apostrophe inside an
483
+ // identifier or a comment is not mistaken for one opening a literal
484
+ const tokens = new RegExp(`'(?:${esc}[^'])*'|\\${idOpen}[^\\${idClose}]*\\${idClose}|--[^\n]*`, 'g');
485
+ const parts = [];
486
+ for (const chunk of sql.split(separator)) {
487
+ const prev = parts.at(-1);
488
+ // whatever quote is left once the complete tokens are gone opened a literal we are still inside of
489
+ if (prev?.replace(tokens, '').includes(`'`)) {
490
+ parts[parts.length - 1] = prev + separator + chunk;
491
+ }
492
+ else {
493
+ parts.push(chunk);
494
+ }
495
+ }
496
+ return parts;
497
+ }
479
498
  /** Whether the statement has to be the first one in a query batch, e.g. `create trigger` on MSSQL. */
480
499
  startsBatch(_statement) {
481
500
  return false;