@spinajs/orm-sql 2.0.481 → 2.0.482

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.
@@ -13,6 +13,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.SqlRawSchemaQueryCompiler = exports.SqlDropEventQueryCompiler = exports.SqlEventQueryCompiler = exports.SqlAlterColumnQueryCompiler = exports.SqlColumnQueryCompiler = exports.SqlTableQueryCompiler = exports.SqlTableHistoryQueryCompiler = exports.SqlTruncateTableQueryCompiler = exports.SqlTableCloneQueryCompiler = exports.SqlAlterTableQueryCompiler = exports.SqlDropViewQueryCompiler = exports.SqlDropTableQueryCompiler = exports.SqlInsertQueryCompiler = exports.SqlIndexQueryCompiler = exports.SqlOnDuplicateQueryCompiler = exports.SqlDeleteQueryCompiler = exports.SqlUpdateQueryCompiler = exports.SqlSelectQueryCompiler = exports.SqlJoinCompiler = exports.SqlHavingCompiler = exports.SqlWhereCompiler = exports.SqlColumnsCompiler = exports.SqlGroupByCompiler = exports.SqlLimitQueryCompiler = exports.SqlForeignKeyQueryCompiler = exports.SqlWithRecursiveCompiler = exports.SqlOrderByQueryCompiler = exports.SqlQueryCompiler = exports.SqlTableAliasCompiler = void 0;
16
+ exports.escapeIdentifier = escapeIdentifier;
17
+ exports.escapeStringLiteral = escapeStringLiteral;
16
18
  /* eslint-disable @typescript-eslint/no-unsafe-call */
17
19
  /* eslint-disable @typescript-eslint/no-unsafe-member-access */
18
20
  /* eslint-disable @typescript-eslint/no-empty-interface */
@@ -22,15 +24,41 @@ const orm_1 = require("@spinajs/orm");
22
24
  const typescript_mix_1 = require("typescript-mix");
23
25
  const di_1 = require("@spinajs/di");
24
26
  const lodash_1 = __importDefault(require("lodash"));
27
+ /**
28
+ * Central identifier escaping for the MySQL-flavoured dialect.
29
+ *
30
+ * Wraps a table/column/alias/schema name in backticks and escapes any embedded
31
+ * backtick by doubling it (the MySQL rule). For a normal identifier (no special
32
+ * characters) the output is byte-identical to the previous raw interpolation
33
+ * (`` `${name}` ``), so existing generated SQL is unchanged; only names that
34
+ * actually contain a backtick produce different — and now safe — output.
35
+ *
36
+ * Dialects that quote differently (e.g. `[name]` with `]`-doubling) override
37
+ * this by shadowing the relevant compiler/statement, the same way
38
+ * {@link SqlTableAliasCompiler} is already overridden per driver.
39
+ */
40
+ function escapeIdentifier(name) {
41
+ return '`' + String(name).replace(/`/g, '``') + '`';
42
+ }
43
+ /**
44
+ * Escapes a DDL string *literal* (SET/ENUM member, COMMENT, CHARACTER SET,
45
+ * COLLATE, string DEFAULT). These are single-quoted string literals, NOT
46
+ * identifiers, so the correct escaping is doubling embedded single quotes.
47
+ * Returns the value WITHOUT the surrounding quotes so callers keep their exact
48
+ * quoting; for a value with no quote the output is byte-identical.
49
+ */
50
+ function escapeStringLiteral(value) {
51
+ return String(value).replace(/'/g, "''");
52
+ }
25
53
  let SqlTableAliasCompiler = class SqlTableAliasCompiler {
26
54
  compile(builder, tbl) {
27
55
  let table = '';
28
56
  if (builder.Database) {
29
- table += `\`${builder.Database}\`.`;
57
+ table += `${escapeIdentifier(builder.Database)}.`;
30
58
  }
31
- table += `\`${tbl ? tbl : builder.Table}\``;
59
+ table += escapeIdentifier(tbl ? tbl : builder.Table);
32
60
  if (builder.TableAlias) {
33
- table += ` as \`${builder.TableAlias}\``;
61
+ table += ` as ${escapeIdentifier(builder.TableAlias)}`;
34
62
  }
35
63
  return table;
36
64
  }
@@ -44,7 +72,7 @@ let SqlQueryCompiler = class SqlQueryCompiler extends orm_1.SelectQueryCompiler
44
72
  super();
45
73
  this._builder = _builder;
46
74
  this._container = _container;
47
- if (_builder === null && _builder === undefined) {
75
+ if (_builder === null || _builder === undefined) {
48
76
  throw new exceptions_1.InvalidArgument('builder cannot be null or undefined');
49
77
  }
50
78
  }
@@ -72,11 +100,11 @@ let SqlOrderByQueryCompiler = class SqlOrderByQueryCompiler extends orm_1.OrderB
72
100
  this._builder = builder;
73
101
  }
74
102
  compile() {
75
- const sort = this._builder.getSort();
103
+ const sorts = this._builder.getSorts();
76
104
  let stmt = '';
77
105
  const bindings = [];
78
- if (sort) {
79
- stmt = ` ORDER BY \`${sort.column}\` ${sort.order}`;
106
+ if (sorts.length > 0) {
107
+ stmt = ` ORDER BY ${sorts.map((s) => `${escapeIdentifier(s.column)} ${s.order}`).join(', ')}`;
80
108
  }
81
109
  return {
82
110
  bindings,
@@ -117,7 +145,7 @@ let SqlForeignKeyQueryCompiler = class SqlForeignKeyQueryCompiler {
117
145
  }
118
146
  }
119
147
  compile() {
120
- const exprr = `FOREIGN KEY (${this._builder.ForeignKeyField}) REFERENCES ${this._builder.Table}(${this._builder.PrimaryKey}) ON DELETE ${this._builder.OnDeleteAction} ON UPDATE ${this._builder.OnUpdateAction}`;
148
+ const exprr = `FOREIGN KEY (${escapeIdentifier(this._builder.ForeignKeyField)}) REFERENCES ${escapeIdentifier(this._builder.Table)}(${escapeIdentifier(this._builder.PrimaryKey)}) ON DELETE ${this._builder.OnDeleteAction} ON UPDATE ${this._builder.OnUpdateAction}`;
121
149
  return {
122
150
  bindings: [],
123
151
  expression: exprr,
@@ -200,23 +228,24 @@ exports.SqlColumnsCompiler = SqlColumnsCompiler = __decorate([
200
228
  ], SqlColumnsCompiler);
201
229
  let SqlWhereCompiler = class SqlWhereCompiler {
202
230
  where(builder) {
203
- const where = [];
204
231
  const bindings = [];
205
- const lazyBindings = builder.Statements.filter((x) => x instanceof orm_1.LazyQueryStatement).map((x) => x.build());
206
- builder.Statements.filter((x) => !x.IsAggregate).filter(x => !(x instanceof orm_1.LazyQueryStatement))
207
- .map((x) => {
208
- return x.build();
209
- })
210
- .concat(lazyBindings)
211
- .forEach((r) => {
212
- where.push(...r.Statements);
213
- if (Array.isArray(r.Bindings)) {
214
- bindings.push(...r.Bindings);
215
- }
216
- });
232
+ // Lazy statements must be built FIRST: their build() may have side effects
233
+ // that append further statements to the builder (e.g. a correlated EXISTS
234
+ // sub-query registers its correlation predicate lazily). Building them now and
235
+ // reusing the result guarantees the side effect runs exactly once, and lets the
236
+ // non-lazy pass below pick up any statements the lazy build appended. The lazy
237
+ // results are then emitted after the non-lazy ones (preserving legacy ordering).
238
+ const lazyEntries = builder.Statements.filter((x) => x instanceof orm_1.LazyQueryStatement).map((stmt) => ({
239
+ boolean: stmt.Boolean,
240
+ result: stmt.build(),
241
+ }));
242
+ const nonLazyEntries = builder.Statements
243
+ .filter((x) => !x.IsAggregate)
244
+ .filter((x) => !(x instanceof orm_1.LazyQueryStatement))
245
+ .map((stmt) => ({ boolean: stmt.Boolean, result: stmt.build() }));
217
246
  return {
218
247
  bindings,
219
- expression: where.join(` ${builder.Op.toUpperCase()} `),
248
+ expression: joinBuiltStatements(nonLazyEntries.concat(lazyEntries), bindings),
220
249
  };
221
250
  }
222
251
  };
@@ -224,23 +253,41 @@ exports.SqlWhereCompiler = SqlWhereCompiler;
224
253
  exports.SqlWhereCompiler = SqlWhereCompiler = __decorate([
225
254
  (0, di_1.NewInstance)()
226
255
  ], SqlWhereCompiler);
256
+ /**
257
+ * Joins a list of already-built where/having statements into a single SQL
258
+ * expression, prefixing every statement after the first with its OWN boolean
259
+ * connector. This yields correct mixed grouping such as
260
+ * `a AND b OR c` for `where(a).where(b).orWhere(c)`, instead of applying a single
261
+ * builder-level connector uniformly. Bindings are collected in statement order.
262
+ */
263
+ function joinBuiltStatements(statements, bindings) {
264
+ const parts = [];
265
+ statements.forEach(({ boolean, result }) => {
266
+ if (Array.isArray(result.Bindings)) {
267
+ bindings.push(...result.Bindings);
268
+ }
269
+ // A single statement always builds to one fragment; guard multi-fragment
270
+ // statements by joining them with AND (they carry no per-fragment connector).
271
+ const fragment = result.Statements.join(' AND ');
272
+ if (fragment === '') {
273
+ return;
274
+ }
275
+ if (parts.length === 0) {
276
+ parts.push(fragment);
277
+ }
278
+ else {
279
+ parts.push(`${(boolean ?? orm_1.WhereBoolean.AND).toUpperCase()} ${fragment}`);
280
+ }
281
+ });
282
+ return parts.join(' ');
283
+ }
227
284
  let SqlHavingCompiler = class SqlHavingCompiler {
228
285
  having(builder) {
229
- const where = [];
230
286
  const bindings = [];
231
- builder.Statements.filter((x) => x.IsAggregate)
232
- .map((x) => {
233
- return x.build();
234
- })
235
- .forEach((r) => {
236
- where.push(...r.Statements);
237
- if (Array.isArray(r.Bindings)) {
238
- bindings.push(...r.Bindings);
239
- }
240
- });
287
+ const aggregates = builder.Statements.filter((x) => x.IsAggregate).map((stmt) => ({ boolean: stmt.Boolean, result: stmt.build() }));
241
288
  return {
242
289
  bindings,
243
- expression: where.join(` ${builder.Op.toUpperCase()} `),
290
+ expression: joinBuiltStatements(aggregates, bindings),
244
291
  };
245
292
  }
246
293
  };
@@ -348,7 +395,7 @@ let SqlUpdateQueryCompiler = class SqlUpdateQueryCompiler extends SqlQueryCompil
348
395
  const exprr = [];
349
396
  for (const prop of Object.keys(this._builder.Value)) {
350
397
  const v = this._builder.Value[`${prop}`];
351
- exprr.push(`\`${prop}\` = ?`);
398
+ exprr.push(`${escapeIdentifier(prop)} = ?`);
352
399
  bindings = bindings.concat(this.tryConvertValue(v));
353
400
  }
354
401
  return {
@@ -415,22 +462,22 @@ let SqlOnDuplicateQueryCompiler = class SqlOnDuplicateQueryCompiler {
415
462
  .getColumnsToUpdate()
416
463
  .map((c) => {
417
464
  if (lodash_1.default.isString(c)) {
418
- return `\`${c}\` = ?`;
465
+ // Reference the row being inserted via VALUES(col) instead of
466
+ // re-binding one specific row's value. Binding `parent.Values[0]`
467
+ // applied the FIRST row's values to every conflicting row in a
468
+ // multi row upsert.
469
+ return `${escapeIdentifier(c)} = VALUES(${escapeIdentifier(c)})`;
419
470
  }
420
471
  else {
421
472
  return c.Query;
422
473
  }
423
474
  })
424
475
  .join(',');
425
- const parent = this._builder.getParent();
426
- const valueMap = parent.getColumns().map((c) => c.Column);
427
- const bindings = this._builder.getColumnsToUpdate().map((c) => {
428
- if (lodash_1.default.isString(c)) {
429
- return parent.Values[0][valueMap.indexOf(c)];
430
- }
431
- else {
432
- return c.Bindings;
433
- }
476
+ // Only RawQuery update columns contribute bindings - VALUES(col) needs
477
+ // none. flatMap keeps raw bindings flat; returning the array itself
478
+ // nested them and shifted every following placeholder.
479
+ const bindings = lodash_1.default.flatMap(this._builder.getColumnsToUpdate(), (c) => {
480
+ return lodash_1.default.isString(c) ? [] : c.Bindings ?? [];
434
481
  });
435
482
  return {
436
483
  bindings,
@@ -451,7 +498,7 @@ let SqlIndexQueryCompiler = class SqlIndexQueryCompiler extends orm_1.IndexQuery
451
498
  compile() {
452
499
  return {
453
500
  bindings: [],
454
- expression: `CREATE ${this._builder.Unique ? 'UNIQUE ' : ''}INDEX \`${this._builder.Name}\` ON \`${this._builder.Table}\` (${this._builder.Columns.map((c) => `\`${c}\``).join(',')});`,
501
+ expression: `CREATE ${this._builder.Unique ? 'UNIQUE ' : ''}INDEX ${escapeIdentifier(this._builder.Name)} ON ${escapeIdentifier(this._builder.Table)} (${this._builder.Columns.map((c) => escapeIdentifier(c)).join(',')});`,
455
502
  };
456
503
  }
457
504
  };
@@ -483,31 +530,54 @@ let SqlInsertQueryCompiler = class SqlInsertQueryCompiler extends SqlQueryCompil
483
530
  expression: '',
484
531
  };
485
532
  }
533
+ /**
534
+ * Indices of the columns that take part in this INSERT.
535
+ *
536
+ * An auto increment primary key is omitted only when NO row supplies a value
537
+ * for it. If at least one row supplies one the column stays, and the rows
538
+ * that don't emit NULL so the engine assigns the value.
539
+ *
540
+ * Both {@link columns} and {@link values} MUST derive their shape from this
541
+ * single decision - deciding per-row in one place and per-batch in the other
542
+ * produced value tuples whose arity did not match the column list.
543
+ */
544
+ keptColumnIndices() {
545
+ return this._builder
546
+ .getColumns()
547
+ .map((c, i) => ({ c, i }))
548
+ .filter(({ c, i }) => {
549
+ const descriptor = c.Descriptor;
550
+ if (descriptor && descriptor.AutoIncrement && descriptor.PrimaryKey) {
551
+ return this._builder.Values.some((x) => x[i] !== undefined && x[i] !== null);
552
+ }
553
+ return true;
554
+ })
555
+ .map(({ i }) => i);
556
+ }
486
557
  values() {
487
558
  if (this._builder.Values.length === 0) {
488
559
  throw new exceptions_1.InvalidArgument('values count invalid');
489
560
  }
561
+ const kept = this.keptColumnIndices();
490
562
  const bindings = [];
491
563
  let data = 'VALUES ';
492
564
  data += this._builder.Values.map((val) => {
493
- const toInsert = val
494
- .filter((v, i) => {
565
+ const toInsert = kept.map((i) => {
566
+ // eslint-disable-next-line security/detect-object-injection
567
+ const v = val[i];
495
568
  // eslint-disable-next-line security/detect-object-injection
496
569
  const descriptor = this._builder.getColumns()[i].Descriptor;
497
570
  if (descriptor) {
498
571
  if (!descriptor.Nullable && (v === null || v === undefined) && !descriptor.AutoIncrement) {
499
572
  throw new exceptions_1.InvalidArgument(`value column ${descriptor.Name} cannot be null`);
500
573
  }
501
- if (descriptor.AutoIncrement && descriptor.PrimaryKey) {
502
- if (v !== undefined && v !== null) {
503
- return true;
504
- }
505
- return false;
574
+ // Auto increment PK this row does not supply. NULL (not DEFAULT) lets
575
+ // the engine assign it and is portable - sqlite does not accept the
576
+ // DEFAULT keyword inside a VALUES tuple.
577
+ if (descriptor.AutoIncrement && descriptor.PrimaryKey && (v === undefined || v === null)) {
578
+ return 'NULL';
506
579
  }
507
580
  }
508
- return true;
509
- })
510
- .map((v) => {
511
581
  if (v === undefined) {
512
582
  return 'DEFAULT';
513
583
  }
@@ -525,23 +595,15 @@ let SqlInsertQueryCompiler = class SqlInsertQueryCompiler extends SqlQueryCompil
525
595
  };
526
596
  }
527
597
  columns() {
528
- const columns = this._builder
529
- .getColumns()
530
- .filter((c, i) => {
531
- const descriptor = c.Descriptor;
532
- if (descriptor && descriptor.AutoIncrement && descriptor.PrimaryKey) {
533
- if (this._builder.Values.every((x) => x[i] !== undefined && x[i] !== null)) {
534
- return true;
535
- }
536
- return false;
537
- }
538
- return true;
539
- })
540
- .map((c) => {
541
- return c.Column;
598
+ const columns = this.keptColumnIndices()
599
+ .map((i) => {
600
+ // eslint-disable-next-line security/detect-object-injection
601
+ return this._builder.getColumns()[i].Column;
542
602
  })
543
603
  .map((c) => {
544
- return `\`${c instanceof orm_1.RawQuery ? c.Query : c}\``;
604
+ // RawQuery columns carry raw SQL - preserve the existing (unescaped)
605
+ // backtick wrapping. String columns go through the identifier escaper.
606
+ return c instanceof orm_1.RawQuery ? `\`${c.Query}\`` : escapeIdentifier(c);
545
607
  });
546
608
  if (columns.length === 0) {
547
609
  throw new exceptions_1.InvalidArgument('invalid column count');
@@ -629,10 +691,22 @@ let SqlAlterTableQueryCompiler = class SqlAlterTableQueryCompiler extends orm_1.
629
691
  }
630
692
  if (this.builder.Columns.length !== 0) {
631
693
  _outputs = _outputs.concat(this.builder.Columns.map((c) => {
632
- const compiler = this.container.resolve(orm_1.AlterColumnQueryCompiler, [c]).compile();
694
+ // keep the compiler instance around - it carries the dialect's answer to
695
+ // "is my expression already a complete statement ?" (see IsStandaloneStatement)
696
+ const compiler = this.container.resolve(orm_1.AlterColumnQueryCompiler, [c]);
697
+ return { compiler, output: compiler.compile() };
698
+ })
699
+ // a driver may legitimately skip an alteration by compiling it to nothing.
700
+ // emitting it anyway would yield a dangling `ALTER TABLE \`x\`` - invalid SQL.
701
+ .filter(({ output }) => (output.expression ?? '').trim().length !== 0)
702
+ .map(({ compiler, output }) => {
703
+ // some dialects cannot express an alteration as a suffix of `ALTER TABLE x`
704
+ // eg. MSSQL renames a column with `EXEC sp_rename '[t].[old]', 'new', 'COLUMN'`,
705
+ // which is a complete statement and must be emitted verbatim.
706
+ const standalone = compiler.IsStandaloneStatement === true;
633
707
  return {
634
- bindings: compiler.bindings,
635
- expression: `${_table} ${compiler.expression}`,
708
+ bindings: output.bindings,
709
+ expression: standalone ? output.expression : `${_table} ${output.expression}`,
636
710
  };
637
711
  }));
638
712
  }
@@ -669,7 +743,7 @@ let SqlTableCloneQueryCompiler = class SqlTableCloneQueryCompiler extends orm_1.
669
743
  // if no filter is provided, copy all the data
670
744
  expression: `SELECT * FROM ${_tblName}`,
671
745
  };
672
- const fExprr = `INSERT INTO \`${this.builder.Table}\` ${fOut.expression}`;
746
+ const fExprr = `INSERT INTO ${escapeIdentifier(this.builder.Table)} ${fOut.expression}`;
673
747
  return [
674
748
  out1,
675
749
  {
@@ -851,7 +925,7 @@ let SqlTableQueryCompiler = class SqlTableQueryCompiler extends orm_1.TableQuery
851
925
  }
852
926
  _primaryKeys() {
853
927
  const _keys = this.builder.Columns.filter((x) => x.PrimaryKey)
854
- .map((c) => `\`${c.Name}\``)
928
+ .map((c) => escapeIdentifier(c.Name))
855
929
  .join(',');
856
930
  if (!lodash_1.default.isEmpty(_keys)) {
857
931
  return `PRIMARY KEY (${_keys})`;
@@ -872,7 +946,7 @@ let SqlColumnQueryCompiler = class SqlColumnQueryCompiler {
872
946
  constructor(builder) {
873
947
  this.builder = builder;
874
948
  this._statementsMappings = {
875
- set: (builder) => `SET(${builder.Args[0].map((a) => `'${a}\'`).join(',')})`,
949
+ set: (builder) => `SET(${builder.Args[0].map((a) => `'${escapeStringLiteral(a)}'`).join(',')})`,
876
950
  string: (builder) => `VARCHAR(${builder.Args[0] ? builder.Args[0] : 255})`,
877
951
  boolean: () => `BOOLEAN`,
878
952
  float: (builder) => {
@@ -882,8 +956,8 @@ let SqlColumnQueryCompiler = class SqlColumnQueryCompiler {
882
956
  },
883
957
  double: (builder) => this._statementsMappings.float(builder),
884
958
  decimal: (builder) => this._statementsMappings.float(builder),
885
- enum: (builder) => `${builder.Type.toUpperCase()}(${builder.Args[0].map((a) => `'${a}'`).join(',')})`,
886
- binary: (builder) => `BINARY(${builder.Args[0] ?? 255}`,
959
+ enum: (builder) => `${builder.Type.toUpperCase()}(${builder.Args[0].map((a) => `'${escapeStringLiteral(a)}'`).join(',')})`,
960
+ binary: (builder) => `BINARY(${builder.Args[0] ?? 255})`,
887
961
  smallint: (builder) => builder.Type.toUpperCase(),
888
962
  tinyint: (builder) => builder.Type.toUpperCase(),
889
963
  mediumint: (builder) => builder.Type.toUpperCase(),
@@ -904,12 +978,12 @@ let SqlColumnQueryCompiler = class SqlColumnQueryCompiler {
904
978
  longblob: (builder) => builder.Type.toUpperCase(),
905
979
  // COLUMN ADDITIONA PROPS
906
980
  unsigned: () => 'UNSIGNED',
907
- charset: (builder) => `CHARACTER SET '${builder.Charset}'`,
908
- collation: (builder) => `COLLATE '${builder.Collation}'`,
981
+ charset: (builder) => `CHARACTER SET '${escapeStringLiteral(builder.Charset)}'`,
982
+ collation: (builder) => `COLLATE '${escapeStringLiteral(builder.Collation)}'`,
909
983
  notnull: () => `NOT NULL`,
910
984
  default: () => this._defaultCompiler(),
911
985
  autoincrement: () => `AUTO_INCREMENT`,
912
- comment: (builder) => `COMMENT '${builder.Comment}'`,
986
+ comment: (builder) => `COMMENT '${escapeStringLiteral(builder.Comment)}'`,
913
987
  };
914
988
  if (!builder) {
915
989
  throw new Error('column query builder cannot be null');
@@ -917,7 +991,7 @@ let SqlColumnQueryCompiler = class SqlColumnQueryCompiler {
917
991
  }
918
992
  compile() {
919
993
  const _stmt = [];
920
- _stmt.push(`\`${this.builder.Name}\``);
994
+ _stmt.push(escapeIdentifier(this.builder.Name));
921
995
  _stmt.push(this._statementsMappings[this.builder.Type](this.builder));
922
996
  if (this.builder.Unsigned) {
923
997
  _stmt.push(this._statementsMappings.unsigned());
@@ -954,7 +1028,7 @@ let SqlColumnQueryCompiler = class SqlColumnQueryCompiler {
954
1028
  return _stmt;
955
1029
  }
956
1030
  if (lodash_1.default.isString(this.builder.Default.Value)) {
957
- _stmt = `DEFAULT '${this.builder.Default.Value.trim()}'`;
1031
+ _stmt = `DEFAULT '${escapeStringLiteral(this.builder.Default.Value.trim())}'`;
958
1032
  }
959
1033
  else if (lodash_1.default.isNumber(this.builder.Default.Value)) {
960
1034
  _stmt = `DEFAULT ${this.builder.Default.Value}`;
@@ -970,39 +1044,85 @@ exports.SqlColumnQueryCompiler = SqlColumnQueryCompiler = __decorate([
970
1044
  (0, di_1.NewInstance)(),
971
1045
  __metadata("design:paramtypes", [orm_1.ColumnQueryBuilder])
972
1046
  ], SqlColumnQueryCompiler);
973
- let SqlAlterColumnQueryCompiler = class SqlAlterColumnQueryCompiler extends SqlColumnQueryCompiler {
974
- constructor(builder) {
975
- super(builder);
1047
+ let SqlAlterColumnQueryCompiler = class SqlAlterColumnQueryCompiler extends orm_1.AlterColumnQueryCompiler {
1048
+ constructor(container, builder) {
1049
+ super();
1050
+ this.container = container;
1051
+ this.builder = builder;
1052
+ if (!builder) {
1053
+ throw new exceptions_1.InvalidArgument('builder cannot be null or undefined');
1054
+ }
1055
+ }
1056
+ /**
1057
+ * Renders the column body using the DRIVER's own column compiler, resolved
1058
+ * from the container (late binding) - exactly like the CREATE TABLE path does.
1059
+ * Previously this was `super.compile()`, which statically bound every driver
1060
+ * to orm-sql's MySQL dialect.
1061
+ */
1062
+ _columnDefinition() {
1063
+ return this.container.resolve(orm_1.ColumnQueryCompiler, [this.builder]).compile();
1064
+ }
1065
+ /**
1066
+ * Whether the expression produced by `compile()` is already a complete, standalone
1067
+ * statement. When true, SqlAlterTableQueryCompiler emits it verbatim instead of
1068
+ * prefixing it with `ALTER TABLE <table> `.
1069
+ *
1070
+ * Needed by dialects whose alteration is not expressible as a suffix of ALTER TABLE,
1071
+ * eg. MSSQL's `EXEC sp_rename '[t].[old]', 'new', 'COLUMN'`.
1072
+ *
1073
+ * It is read AFTER `compile()`, so a subclass may decide per `builder.AlterType`.
1074
+ * Defaults to false - MySQL (this class) always emits a suffix.
1075
+ */
1076
+ get IsStandaloneStatement() {
1077
+ return false;
1078
+ }
1079
+ /**
1080
+ * Dialect hooks. Returning `null` means "emit no statement at all" - the
1081
+ * parent AlterTableQueryCompiler filters such columns out.
1082
+ */
1083
+ _add(definition) {
1084
+ // escapeIdentifier, not raw backticks: an identifier containing a backtick would
1085
+ // otherwise terminate the quote and splice arbitrary SQL into the DDL ( A3 ).
1086
+ return `ADD ${definition} ${this.builder.AfterColumn ? `AFTER ${escapeIdentifier(this.builder.AfterColumn)}` : ''}`;
1087
+ }
1088
+ _modify(definition) {
1089
+ return `MODIFY ${definition}`;
1090
+ }
1091
+ _rename() {
1092
+ return `RENAME COLUMN ${escapeIdentifier(this.builder.OldName)} TO ${escapeIdentifier(this.builder.Name)}`;
976
1093
  }
977
1094
  compile() {
978
- const builder = this.builder;
979
- if (builder.AlterType === orm_1.ColumnAlterationType.Rename) {
980
- const bld = this.builder;
1095
+ // rename never renders a column body, so it must not resolve one
1096
+ if (this.builder.AlterType === orm_1.ColumnAlterationType.Rename) {
981
1097
  return {
982
1098
  bindings: [],
983
- expression: `RENAME COLUMN \`${bld.OldName}\` TO \`${bld.Name}\``,
984
- };
985
- }
986
- const cDefinition = super.compile();
987
- if (builder.AlterType === orm_1.ColumnAlterationType.Add) {
988
- return {
989
- bindings: cDefinition.bindings,
990
- expression: `ADD ${cDefinition.expression} ${builder.AfterColumn ? `AFTER \`${builder.AfterColumn}\`` : ''}`,
1099
+ expression: this._rename() ?? '',
991
1100
  };
992
1101
  }
993
- if (builder.AlterType === orm_1.ColumnAlterationType.Modify) {
994
- return {
995
- bindings: cDefinition.bindings,
996
- expression: `MODIFY ${cDefinition.expression}`,
997
- };
1102
+ const cDefinition = this._columnDefinition();
1103
+ let expression;
1104
+ switch (this.builder.AlterType) {
1105
+ case orm_1.ColumnAlterationType.Add:
1106
+ expression = this._add(cDefinition.expression);
1107
+ break;
1108
+ case orm_1.ColumnAlterationType.Modify:
1109
+ expression = this._modify(cDefinition.expression);
1110
+ break;
1111
+ default:
1112
+ expression = cDefinition.expression;
1113
+ break;
998
1114
  }
999
- return cDefinition;
1115
+ return {
1116
+ bindings: cDefinition.bindings,
1117
+ expression: expression ?? '',
1118
+ };
1000
1119
  }
1001
1120
  };
1002
1121
  exports.SqlAlterColumnQueryCompiler = SqlAlterColumnQueryCompiler;
1003
1122
  exports.SqlAlterColumnQueryCompiler = SqlAlterColumnQueryCompiler = __decorate([
1004
1123
  (0, di_1.NewInstance)(),
1005
- __metadata("design:paramtypes", [orm_1.AlterColumnQueryBuilder])
1124
+ (0, di_1.Inject)(di_1.Container),
1125
+ __metadata("design:paramtypes", [di_1.Container, orm_1.AlterColumnQueryBuilder])
1006
1126
  ], SqlAlterColumnQueryCompiler);
1007
1127
  let SqlEventQueryCompiler = class SqlEventQueryCompiler extends SqlQueryCompiler {
1008
1128
  constructor(container, builder) {