@spinajs/orm-sql 2.0.481 → 2.0.484
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -3
- package/lib/cjs/compilers.d.ts +79 -3
- package/lib/cjs/compilers.d.ts.map +1 -1
- package/lib/cjs/compilers.js +243 -105
- package/lib/cjs/compilers.js.map +1 -1
- package/lib/cjs/converters.d.ts.map +1 -1
- package/lib/cjs/converters.js +1 -4
- package/lib/cjs/converters.js.map +1 -1
- package/lib/cjs/index.d.ts +13 -0
- package/lib/cjs/index.d.ts.map +1 -1
- package/lib/cjs/index.js +31 -2
- package/lib/cjs/index.js.map +1 -1
- package/lib/cjs/statements.d.ts.map +1 -1
- package/lib/cjs/statements.js +84 -24
- package/lib/cjs/statements.js.map +1 -1
- package/lib/mjs/compilers.d.ts +79 -3
- package/lib/mjs/compilers.d.ts.map +1 -1
- package/lib/mjs/compilers.js +241 -106
- package/lib/mjs/compilers.js.map +1 -1
- package/lib/mjs/converters.d.ts.map +1 -1
- package/lib/mjs/converters.js +1 -4
- package/lib/mjs/converters.js.map +1 -1
- package/lib/mjs/index.d.ts +13 -0
- package/lib/mjs/index.d.ts.map +1 -1
- package/lib/mjs/index.js +31 -2
- package/lib/mjs/index.js.map +1 -1
- package/lib/mjs/statements.d.ts.map +1 -1
- package/lib/mjs/statements.js +85 -25
- package/lib/mjs/statements.js.map +1 -1
- package/lib/tsconfig.cjs.tsbuildinfo +1 -1
- package/lib/tsconfig.mjs.tsbuildinfo +1 -1
- package/package.json +14 -14
package/lib/cjs/compilers.js
CHANGED
|
@@ -13,6 +13,9 @@ 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.escapeQualifiedIdentifier = escapeQualifiedIdentifier;
|
|
18
|
+
exports.escapeStringLiteral = escapeStringLiteral;
|
|
16
19
|
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
17
20
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
18
21
|
/* eslint-disable @typescript-eslint/no-empty-interface */
|
|
@@ -22,15 +25,58 @@ const orm_1 = require("@spinajs/orm");
|
|
|
22
25
|
const typescript_mix_1 = require("typescript-mix");
|
|
23
26
|
const di_1 = require("@spinajs/di");
|
|
24
27
|
const lodash_1 = __importDefault(require("lodash"));
|
|
28
|
+
/**
|
|
29
|
+
* Central identifier escaping for the MySQL-flavoured dialect.
|
|
30
|
+
*
|
|
31
|
+
* Wraps a table/column/alias/schema name in backticks and escapes any embedded
|
|
32
|
+
* backtick by doubling it (the MySQL rule). For a normal identifier (no special
|
|
33
|
+
* characters) the output is byte-identical to the previous raw interpolation
|
|
34
|
+
* (`` `${name}` ``), so existing generated SQL is unchanged; only names that
|
|
35
|
+
* actually contain a backtick produce different — and now safe — output.
|
|
36
|
+
*
|
|
37
|
+
* Dialects that quote differently (e.g. `[name]` with `]`-doubling) override
|
|
38
|
+
* this by shadowing the relevant compiler/statement, the same way
|
|
39
|
+
* {@link SqlTableAliasCompiler} is already overridden per driver.
|
|
40
|
+
*/
|
|
41
|
+
function escapeIdentifier(name) {
|
|
42
|
+
return '`' + String(name).replace(/`/g, '``') + '`';
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Escapes a possibly schema-qualified table name, quoting each dot-separated part
|
|
46
|
+
* on its own: `schema.table` becomes `` `schema`.`table` ``, not
|
|
47
|
+
* `` `schema.table` `` — the latter is a single identifier and MySQL rejects it
|
|
48
|
+
* with "Failed to open the referenced table".
|
|
49
|
+
*
|
|
50
|
+
* Needed because {@link TableQueryBuilder.references} takes the parent table as one
|
|
51
|
+
* string, so cross-schema foreign keys arrive here already qualified. A dot is
|
|
52
|
+
* therefore read as a qualifier separator; a table whose name genuinely contains a
|
|
53
|
+
* dot cannot be expressed through that API (it never could).
|
|
54
|
+
*/
|
|
55
|
+
function escapeQualifiedIdentifier(name) {
|
|
56
|
+
return String(name)
|
|
57
|
+
.split('.')
|
|
58
|
+
.map((part) => escapeIdentifier(part))
|
|
59
|
+
.join('.');
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Escapes a DDL string *literal* (SET/ENUM member, COMMENT, CHARACTER SET,
|
|
63
|
+
* COLLATE, string DEFAULT). These are single-quoted string literals, NOT
|
|
64
|
+
* identifiers, so the correct escaping is doubling embedded single quotes.
|
|
65
|
+
* Returns the value WITHOUT the surrounding quotes so callers keep their exact
|
|
66
|
+
* quoting; for a value with no quote the output is byte-identical.
|
|
67
|
+
*/
|
|
68
|
+
function escapeStringLiteral(value) {
|
|
69
|
+
return String(value).replace(/'/g, "''");
|
|
70
|
+
}
|
|
25
71
|
let SqlTableAliasCompiler = class SqlTableAliasCompiler {
|
|
26
72
|
compile(builder, tbl) {
|
|
27
73
|
let table = '';
|
|
28
74
|
if (builder.Database) {
|
|
29
|
-
table +=
|
|
75
|
+
table += `${escapeIdentifier(builder.Database)}.`;
|
|
30
76
|
}
|
|
31
|
-
table +=
|
|
77
|
+
table += escapeIdentifier(tbl ? tbl : builder.Table);
|
|
32
78
|
if (builder.TableAlias) {
|
|
33
|
-
table += ` as
|
|
79
|
+
table += ` as ${escapeIdentifier(builder.TableAlias)}`;
|
|
34
80
|
}
|
|
35
81
|
return table;
|
|
36
82
|
}
|
|
@@ -44,7 +90,7 @@ let SqlQueryCompiler = class SqlQueryCompiler extends orm_1.SelectQueryCompiler
|
|
|
44
90
|
super();
|
|
45
91
|
this._builder = _builder;
|
|
46
92
|
this._container = _container;
|
|
47
|
-
if (_builder === null
|
|
93
|
+
if (_builder === null || _builder === undefined) {
|
|
48
94
|
throw new exceptions_1.InvalidArgument('builder cannot be null or undefined');
|
|
49
95
|
}
|
|
50
96
|
}
|
|
@@ -72,11 +118,11 @@ let SqlOrderByQueryCompiler = class SqlOrderByQueryCompiler extends orm_1.OrderB
|
|
|
72
118
|
this._builder = builder;
|
|
73
119
|
}
|
|
74
120
|
compile() {
|
|
75
|
-
const
|
|
121
|
+
const sorts = this._builder.getSorts();
|
|
76
122
|
let stmt = '';
|
|
77
123
|
const bindings = [];
|
|
78
|
-
if (
|
|
79
|
-
stmt = ` ORDER BY
|
|
124
|
+
if (sorts.length > 0) {
|
|
125
|
+
stmt = ` ORDER BY ${sorts.map((s) => `${escapeIdentifier(s.column)} ${s.order}`).join(', ')}`;
|
|
80
126
|
}
|
|
81
127
|
return {
|
|
82
128
|
bindings,
|
|
@@ -117,7 +163,7 @@ let SqlForeignKeyQueryCompiler = class SqlForeignKeyQueryCompiler {
|
|
|
117
163
|
}
|
|
118
164
|
}
|
|
119
165
|
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}`;
|
|
166
|
+
const exprr = `FOREIGN KEY (${escapeIdentifier(this._builder.ForeignKeyField)}) REFERENCES ${escapeQualifiedIdentifier(this._builder.Table)}(${escapeIdentifier(this._builder.PrimaryKey)}) ON DELETE ${this._builder.OnDeleteAction} ON UPDATE ${this._builder.OnUpdateAction}`;
|
|
121
167
|
return {
|
|
122
168
|
bindings: [],
|
|
123
169
|
expression: exprr,
|
|
@@ -200,23 +246,24 @@ exports.SqlColumnsCompiler = SqlColumnsCompiler = __decorate([
|
|
|
200
246
|
], SqlColumnsCompiler);
|
|
201
247
|
let SqlWhereCompiler = class SqlWhereCompiler {
|
|
202
248
|
where(builder) {
|
|
203
|
-
const where = [];
|
|
204
249
|
const bindings = [];
|
|
205
|
-
|
|
206
|
-
builder
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
250
|
+
// Lazy statements must be built FIRST: their build() may have side effects
|
|
251
|
+
// that append further statements to the builder (e.g. a correlated EXISTS
|
|
252
|
+
// sub-query registers its correlation predicate lazily). Building them now and
|
|
253
|
+
// reusing the result guarantees the side effect runs exactly once, and lets the
|
|
254
|
+
// non-lazy pass below pick up any statements the lazy build appended. The lazy
|
|
255
|
+
// results are then emitted after the non-lazy ones (preserving legacy ordering).
|
|
256
|
+
const lazyEntries = builder.Statements.filter((x) => x instanceof orm_1.LazyQueryStatement).map((stmt) => ({
|
|
257
|
+
boolean: stmt.Boolean,
|
|
258
|
+
result: stmt.build(),
|
|
259
|
+
}));
|
|
260
|
+
const nonLazyEntries = builder.Statements
|
|
261
|
+
.filter((x) => !x.IsAggregate)
|
|
262
|
+
.filter((x) => !(x instanceof orm_1.LazyQueryStatement))
|
|
263
|
+
.map((stmt) => ({ boolean: stmt.Boolean, result: stmt.build() }));
|
|
217
264
|
return {
|
|
218
265
|
bindings,
|
|
219
|
-
expression:
|
|
266
|
+
expression: joinBuiltStatements(nonLazyEntries.concat(lazyEntries), bindings),
|
|
220
267
|
};
|
|
221
268
|
}
|
|
222
269
|
};
|
|
@@ -224,23 +271,41 @@ exports.SqlWhereCompiler = SqlWhereCompiler;
|
|
|
224
271
|
exports.SqlWhereCompiler = SqlWhereCompiler = __decorate([
|
|
225
272
|
(0, di_1.NewInstance)()
|
|
226
273
|
], SqlWhereCompiler);
|
|
274
|
+
/**
|
|
275
|
+
* Joins a list of already-built where/having statements into a single SQL
|
|
276
|
+
* expression, prefixing every statement after the first with its OWN boolean
|
|
277
|
+
* connector. This yields correct mixed grouping such as
|
|
278
|
+
* `a AND b OR c` for `where(a).where(b).orWhere(c)`, instead of applying a single
|
|
279
|
+
* builder-level connector uniformly. Bindings are collected in statement order.
|
|
280
|
+
*/
|
|
281
|
+
function joinBuiltStatements(statements, bindings) {
|
|
282
|
+
const parts = [];
|
|
283
|
+
statements.forEach(({ boolean, result }) => {
|
|
284
|
+
if (Array.isArray(result.Bindings)) {
|
|
285
|
+
bindings.push(...result.Bindings);
|
|
286
|
+
}
|
|
287
|
+
// A single statement always builds to one fragment; guard multi-fragment
|
|
288
|
+
// statements by joining them with AND (they carry no per-fragment connector).
|
|
289
|
+
const fragment = result.Statements.join(' AND ');
|
|
290
|
+
if (fragment === '') {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
if (parts.length === 0) {
|
|
294
|
+
parts.push(fragment);
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
parts.push(`${(boolean ?? orm_1.WhereBoolean.AND).toUpperCase()} ${fragment}`);
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
return parts.join(' ');
|
|
301
|
+
}
|
|
227
302
|
let SqlHavingCompiler = class SqlHavingCompiler {
|
|
228
303
|
having(builder) {
|
|
229
|
-
const where = [];
|
|
230
304
|
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
|
-
});
|
|
305
|
+
const aggregates = builder.Statements.filter((x) => x.IsAggregate).map((stmt) => ({ boolean: stmt.Boolean, result: stmt.build() }));
|
|
241
306
|
return {
|
|
242
307
|
bindings,
|
|
243
|
-
expression:
|
|
308
|
+
expression: joinBuiltStatements(aggregates, bindings),
|
|
244
309
|
};
|
|
245
310
|
}
|
|
246
311
|
};
|
|
@@ -348,7 +413,7 @@ let SqlUpdateQueryCompiler = class SqlUpdateQueryCompiler extends SqlQueryCompil
|
|
|
348
413
|
const exprr = [];
|
|
349
414
|
for (const prop of Object.keys(this._builder.Value)) {
|
|
350
415
|
const v = this._builder.Value[`${prop}`];
|
|
351
|
-
exprr.push(
|
|
416
|
+
exprr.push(`${escapeIdentifier(prop)} = ?`);
|
|
352
417
|
bindings = bindings.concat(this.tryConvertValue(v));
|
|
353
418
|
}
|
|
354
419
|
return {
|
|
@@ -415,22 +480,22 @@ let SqlOnDuplicateQueryCompiler = class SqlOnDuplicateQueryCompiler {
|
|
|
415
480
|
.getColumnsToUpdate()
|
|
416
481
|
.map((c) => {
|
|
417
482
|
if (lodash_1.default.isString(c)) {
|
|
418
|
-
|
|
483
|
+
// Reference the row being inserted via VALUES(col) instead of
|
|
484
|
+
// re-binding one specific row's value. Binding `parent.Values[0]`
|
|
485
|
+
// applied the FIRST row's values to every conflicting row in a
|
|
486
|
+
// multi row upsert.
|
|
487
|
+
return `${escapeIdentifier(c)} = VALUES(${escapeIdentifier(c)})`;
|
|
419
488
|
}
|
|
420
489
|
else {
|
|
421
490
|
return c.Query;
|
|
422
491
|
}
|
|
423
492
|
})
|
|
424
493
|
.join(',');
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
}
|
|
431
|
-
else {
|
|
432
|
-
return c.Bindings;
|
|
433
|
-
}
|
|
494
|
+
// Only RawQuery update columns contribute bindings - VALUES(col) needs
|
|
495
|
+
// none. flatMap keeps raw bindings flat; returning the array itself
|
|
496
|
+
// nested them and shifted every following placeholder.
|
|
497
|
+
const bindings = lodash_1.default.flatMap(this._builder.getColumnsToUpdate(), (c) => {
|
|
498
|
+
return lodash_1.default.isString(c) ? [] : c.Bindings ?? [];
|
|
434
499
|
});
|
|
435
500
|
return {
|
|
436
501
|
bindings,
|
|
@@ -451,7 +516,7 @@ let SqlIndexQueryCompiler = class SqlIndexQueryCompiler extends orm_1.IndexQuery
|
|
|
451
516
|
compile() {
|
|
452
517
|
return {
|
|
453
518
|
bindings: [],
|
|
454
|
-
expression: `CREATE ${this._builder.Unique ? 'UNIQUE ' : ''}INDEX
|
|
519
|
+
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
520
|
};
|
|
456
521
|
}
|
|
457
522
|
};
|
|
@@ -483,31 +548,54 @@ let SqlInsertQueryCompiler = class SqlInsertQueryCompiler extends SqlQueryCompil
|
|
|
483
548
|
expression: '',
|
|
484
549
|
};
|
|
485
550
|
}
|
|
551
|
+
/**
|
|
552
|
+
* Indices of the columns that take part in this INSERT.
|
|
553
|
+
*
|
|
554
|
+
* An auto increment primary key is omitted only when NO row supplies a value
|
|
555
|
+
* for it. If at least one row supplies one the column stays, and the rows
|
|
556
|
+
* that don't emit NULL so the engine assigns the value.
|
|
557
|
+
*
|
|
558
|
+
* Both {@link columns} and {@link values} MUST derive their shape from this
|
|
559
|
+
* single decision - deciding per-row in one place and per-batch in the other
|
|
560
|
+
* produced value tuples whose arity did not match the column list.
|
|
561
|
+
*/
|
|
562
|
+
keptColumnIndices() {
|
|
563
|
+
return this._builder
|
|
564
|
+
.getColumns()
|
|
565
|
+
.map((c, i) => ({ c, i }))
|
|
566
|
+
.filter(({ c, i }) => {
|
|
567
|
+
const descriptor = c.Descriptor;
|
|
568
|
+
if (descriptor && descriptor.AutoIncrement && descriptor.PrimaryKey) {
|
|
569
|
+
return this._builder.Values.some((x) => x[i] !== undefined && x[i] !== null);
|
|
570
|
+
}
|
|
571
|
+
return true;
|
|
572
|
+
})
|
|
573
|
+
.map(({ i }) => i);
|
|
574
|
+
}
|
|
486
575
|
values() {
|
|
487
576
|
if (this._builder.Values.length === 0) {
|
|
488
577
|
throw new exceptions_1.InvalidArgument('values count invalid');
|
|
489
578
|
}
|
|
579
|
+
const kept = this.keptColumnIndices();
|
|
490
580
|
const bindings = [];
|
|
491
581
|
let data = 'VALUES ';
|
|
492
582
|
data += this._builder.Values.map((val) => {
|
|
493
|
-
const toInsert =
|
|
494
|
-
|
|
583
|
+
const toInsert = kept.map((i) => {
|
|
584
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
585
|
+
const v = val[i];
|
|
495
586
|
// eslint-disable-next-line security/detect-object-injection
|
|
496
587
|
const descriptor = this._builder.getColumns()[i].Descriptor;
|
|
497
588
|
if (descriptor) {
|
|
498
589
|
if (!descriptor.Nullable && (v === null || v === undefined) && !descriptor.AutoIncrement) {
|
|
499
590
|
throw new exceptions_1.InvalidArgument(`value column ${descriptor.Name} cannot be null`);
|
|
500
591
|
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
return
|
|
592
|
+
// Auto increment PK this row does not supply. NULL (not DEFAULT) lets
|
|
593
|
+
// the engine assign it and is portable - sqlite does not accept the
|
|
594
|
+
// DEFAULT keyword inside a VALUES tuple.
|
|
595
|
+
if (descriptor.AutoIncrement && descriptor.PrimaryKey && (v === undefined || v === null)) {
|
|
596
|
+
return 'NULL';
|
|
506
597
|
}
|
|
507
598
|
}
|
|
508
|
-
return true;
|
|
509
|
-
})
|
|
510
|
-
.map((v) => {
|
|
511
599
|
if (v === undefined) {
|
|
512
600
|
return 'DEFAULT';
|
|
513
601
|
}
|
|
@@ -525,23 +613,15 @@ let SqlInsertQueryCompiler = class SqlInsertQueryCompiler extends SqlQueryCompil
|
|
|
525
613
|
};
|
|
526
614
|
}
|
|
527
615
|
columns() {
|
|
528
|
-
const columns = this.
|
|
529
|
-
.
|
|
530
|
-
|
|
531
|
-
|
|
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;
|
|
616
|
+
const columns = this.keptColumnIndices()
|
|
617
|
+
.map((i) => {
|
|
618
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
619
|
+
return this._builder.getColumns()[i].Column;
|
|
542
620
|
})
|
|
543
621
|
.map((c) => {
|
|
544
|
-
|
|
622
|
+
// RawQuery columns carry raw SQL - preserve the existing (unescaped)
|
|
623
|
+
// backtick wrapping. String columns go through the identifier escaper.
|
|
624
|
+
return c instanceof orm_1.RawQuery ? `\`${c.Query}\`` : escapeIdentifier(c);
|
|
545
625
|
});
|
|
546
626
|
if (columns.length === 0) {
|
|
547
627
|
throw new exceptions_1.InvalidArgument('invalid column count');
|
|
@@ -629,10 +709,22 @@ let SqlAlterTableQueryCompiler = class SqlAlterTableQueryCompiler extends orm_1.
|
|
|
629
709
|
}
|
|
630
710
|
if (this.builder.Columns.length !== 0) {
|
|
631
711
|
_outputs = _outputs.concat(this.builder.Columns.map((c) => {
|
|
632
|
-
|
|
712
|
+
// keep the compiler instance around - it carries the dialect's answer to
|
|
713
|
+
// "is my expression already a complete statement ?" (see IsStandaloneStatement)
|
|
714
|
+
const compiler = this.container.resolve(orm_1.AlterColumnQueryCompiler, [c]);
|
|
715
|
+
return { compiler, output: compiler.compile() };
|
|
716
|
+
})
|
|
717
|
+
// a driver may legitimately skip an alteration by compiling it to nothing.
|
|
718
|
+
// emitting it anyway would yield a dangling `ALTER TABLE \`x\`` - invalid SQL.
|
|
719
|
+
.filter(({ output }) => (output.expression ?? '').trim().length !== 0)
|
|
720
|
+
.map(({ compiler, output }) => {
|
|
721
|
+
// some dialects cannot express an alteration as a suffix of `ALTER TABLE x`
|
|
722
|
+
// eg. MSSQL renames a column with `EXEC sp_rename '[t].[old]', 'new', 'COLUMN'`,
|
|
723
|
+
// which is a complete statement and must be emitted verbatim.
|
|
724
|
+
const standalone = compiler.IsStandaloneStatement === true;
|
|
633
725
|
return {
|
|
634
|
-
bindings:
|
|
635
|
-
expression: `${_table} ${
|
|
726
|
+
bindings: output.bindings,
|
|
727
|
+
expression: standalone ? output.expression : `${_table} ${output.expression}`,
|
|
636
728
|
};
|
|
637
729
|
}));
|
|
638
730
|
}
|
|
@@ -669,7 +761,7 @@ let SqlTableCloneQueryCompiler = class SqlTableCloneQueryCompiler extends orm_1.
|
|
|
669
761
|
// if no filter is provided, copy all the data
|
|
670
762
|
expression: `SELECT * FROM ${_tblName}`,
|
|
671
763
|
};
|
|
672
|
-
const fExprr = `INSERT INTO
|
|
764
|
+
const fExprr = `INSERT INTO ${escapeIdentifier(this.builder.Table)} ${fOut.expression}`;
|
|
673
765
|
return [
|
|
674
766
|
out1,
|
|
675
767
|
{
|
|
@@ -851,7 +943,7 @@ let SqlTableQueryCompiler = class SqlTableQueryCompiler extends orm_1.TableQuery
|
|
|
851
943
|
}
|
|
852
944
|
_primaryKeys() {
|
|
853
945
|
const _keys = this.builder.Columns.filter((x) => x.PrimaryKey)
|
|
854
|
-
.map((c) =>
|
|
946
|
+
.map((c) => escapeIdentifier(c.Name))
|
|
855
947
|
.join(',');
|
|
856
948
|
if (!lodash_1.default.isEmpty(_keys)) {
|
|
857
949
|
return `PRIMARY KEY (${_keys})`;
|
|
@@ -872,7 +964,7 @@ let SqlColumnQueryCompiler = class SqlColumnQueryCompiler {
|
|
|
872
964
|
constructor(builder) {
|
|
873
965
|
this.builder = builder;
|
|
874
966
|
this._statementsMappings = {
|
|
875
|
-
set: (builder) => `SET(${builder.Args[0].map((a) => `'${a}
|
|
967
|
+
set: (builder) => `SET(${builder.Args[0].map((a) => `'${escapeStringLiteral(a)}'`).join(',')})`,
|
|
876
968
|
string: (builder) => `VARCHAR(${builder.Args[0] ? builder.Args[0] : 255})`,
|
|
877
969
|
boolean: () => `BOOLEAN`,
|
|
878
970
|
float: (builder) => {
|
|
@@ -882,8 +974,8 @@ let SqlColumnQueryCompiler = class SqlColumnQueryCompiler {
|
|
|
882
974
|
},
|
|
883
975
|
double: (builder) => this._statementsMappings.float(builder),
|
|
884
976
|
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}`,
|
|
977
|
+
enum: (builder) => `${builder.Type.toUpperCase()}(${builder.Args[0].map((a) => `'${escapeStringLiteral(a)}'`).join(',')})`,
|
|
978
|
+
binary: (builder) => `BINARY(${builder.Args[0] ?? 255})`,
|
|
887
979
|
smallint: (builder) => builder.Type.toUpperCase(),
|
|
888
980
|
tinyint: (builder) => builder.Type.toUpperCase(),
|
|
889
981
|
mediumint: (builder) => builder.Type.toUpperCase(),
|
|
@@ -904,12 +996,12 @@ let SqlColumnQueryCompiler = class SqlColumnQueryCompiler {
|
|
|
904
996
|
longblob: (builder) => builder.Type.toUpperCase(),
|
|
905
997
|
// COLUMN ADDITIONA PROPS
|
|
906
998
|
unsigned: () => 'UNSIGNED',
|
|
907
|
-
charset: (builder) => `CHARACTER SET '${builder.Charset}'`,
|
|
908
|
-
collation: (builder) => `COLLATE '${builder.Collation}'`,
|
|
999
|
+
charset: (builder) => `CHARACTER SET '${escapeStringLiteral(builder.Charset)}'`,
|
|
1000
|
+
collation: (builder) => `COLLATE '${escapeStringLiteral(builder.Collation)}'`,
|
|
909
1001
|
notnull: () => `NOT NULL`,
|
|
910
1002
|
default: () => this._defaultCompiler(),
|
|
911
1003
|
autoincrement: () => `AUTO_INCREMENT`,
|
|
912
|
-
comment: (builder) => `COMMENT '${builder.Comment}'`,
|
|
1004
|
+
comment: (builder) => `COMMENT '${escapeStringLiteral(builder.Comment)}'`,
|
|
913
1005
|
};
|
|
914
1006
|
if (!builder) {
|
|
915
1007
|
throw new Error('column query builder cannot be null');
|
|
@@ -917,7 +1009,7 @@ let SqlColumnQueryCompiler = class SqlColumnQueryCompiler {
|
|
|
917
1009
|
}
|
|
918
1010
|
compile() {
|
|
919
1011
|
const _stmt = [];
|
|
920
|
-
_stmt.push(
|
|
1012
|
+
_stmt.push(escapeIdentifier(this.builder.Name));
|
|
921
1013
|
_stmt.push(this._statementsMappings[this.builder.Type](this.builder));
|
|
922
1014
|
if (this.builder.Unsigned) {
|
|
923
1015
|
_stmt.push(this._statementsMappings.unsigned());
|
|
@@ -954,7 +1046,7 @@ let SqlColumnQueryCompiler = class SqlColumnQueryCompiler {
|
|
|
954
1046
|
return _stmt;
|
|
955
1047
|
}
|
|
956
1048
|
if (lodash_1.default.isString(this.builder.Default.Value)) {
|
|
957
|
-
_stmt = `DEFAULT '${this.builder.Default.Value.trim()}'`;
|
|
1049
|
+
_stmt = `DEFAULT '${escapeStringLiteral(this.builder.Default.Value.trim())}'`;
|
|
958
1050
|
}
|
|
959
1051
|
else if (lodash_1.default.isNumber(this.builder.Default.Value)) {
|
|
960
1052
|
_stmt = `DEFAULT ${this.builder.Default.Value}`;
|
|
@@ -970,39 +1062,85 @@ exports.SqlColumnQueryCompiler = SqlColumnQueryCompiler = __decorate([
|
|
|
970
1062
|
(0, di_1.NewInstance)(),
|
|
971
1063
|
__metadata("design:paramtypes", [orm_1.ColumnQueryBuilder])
|
|
972
1064
|
], SqlColumnQueryCompiler);
|
|
973
|
-
let SqlAlterColumnQueryCompiler = class SqlAlterColumnQueryCompiler extends
|
|
974
|
-
constructor(builder) {
|
|
975
|
-
super(
|
|
1065
|
+
let SqlAlterColumnQueryCompiler = class SqlAlterColumnQueryCompiler extends orm_1.AlterColumnQueryCompiler {
|
|
1066
|
+
constructor(container, builder) {
|
|
1067
|
+
super();
|
|
1068
|
+
this.container = container;
|
|
1069
|
+
this.builder = builder;
|
|
1070
|
+
if (!builder) {
|
|
1071
|
+
throw new exceptions_1.InvalidArgument('builder cannot be null or undefined');
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
/**
|
|
1075
|
+
* Renders the column body using the DRIVER's own column compiler, resolved
|
|
1076
|
+
* from the container (late binding) - exactly like the CREATE TABLE path does.
|
|
1077
|
+
* Previously this was `super.compile()`, which statically bound every driver
|
|
1078
|
+
* to orm-sql's MySQL dialect.
|
|
1079
|
+
*/
|
|
1080
|
+
_columnDefinition() {
|
|
1081
|
+
return this.container.resolve(orm_1.ColumnQueryCompiler, [this.builder]).compile();
|
|
1082
|
+
}
|
|
1083
|
+
/**
|
|
1084
|
+
* Whether the expression produced by `compile()` is already a complete, standalone
|
|
1085
|
+
* statement. When true, SqlAlterTableQueryCompiler emits it verbatim instead of
|
|
1086
|
+
* prefixing it with `ALTER TABLE <table> `.
|
|
1087
|
+
*
|
|
1088
|
+
* Needed by dialects whose alteration is not expressible as a suffix of ALTER TABLE,
|
|
1089
|
+
* eg. MSSQL's `EXEC sp_rename '[t].[old]', 'new', 'COLUMN'`.
|
|
1090
|
+
*
|
|
1091
|
+
* It is read AFTER `compile()`, so a subclass may decide per `builder.AlterType`.
|
|
1092
|
+
* Defaults to false - MySQL (this class) always emits a suffix.
|
|
1093
|
+
*/
|
|
1094
|
+
get IsStandaloneStatement() {
|
|
1095
|
+
return false;
|
|
1096
|
+
}
|
|
1097
|
+
/**
|
|
1098
|
+
* Dialect hooks. Returning `null` means "emit no statement at all" - the
|
|
1099
|
+
* parent AlterTableQueryCompiler filters such columns out.
|
|
1100
|
+
*/
|
|
1101
|
+
_add(definition) {
|
|
1102
|
+
// escapeIdentifier, not raw backticks: an identifier containing a backtick would
|
|
1103
|
+
// otherwise terminate the quote and splice arbitrary SQL into the DDL ( A3 ).
|
|
1104
|
+
return `ADD ${definition} ${this.builder.AfterColumn ? `AFTER ${escapeIdentifier(this.builder.AfterColumn)}` : ''}`;
|
|
1105
|
+
}
|
|
1106
|
+
_modify(definition) {
|
|
1107
|
+
return `MODIFY ${definition}`;
|
|
1108
|
+
}
|
|
1109
|
+
_rename() {
|
|
1110
|
+
return `RENAME COLUMN ${escapeIdentifier(this.builder.OldName)} TO ${escapeIdentifier(this.builder.Name)}`;
|
|
976
1111
|
}
|
|
977
1112
|
compile() {
|
|
978
|
-
|
|
979
|
-
if (builder.AlterType === orm_1.ColumnAlterationType.Rename) {
|
|
980
|
-
const bld = this.builder;
|
|
1113
|
+
// rename never renders a column body, so it must not resolve one
|
|
1114
|
+
if (this.builder.AlterType === orm_1.ColumnAlterationType.Rename) {
|
|
981
1115
|
return {
|
|
982
1116
|
bindings: [],
|
|
983
|
-
expression:
|
|
1117
|
+
expression: this._rename() ?? '',
|
|
984
1118
|
};
|
|
985
1119
|
}
|
|
986
|
-
const cDefinition =
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
expression
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
expression
|
|
997
|
-
|
|
1120
|
+
const cDefinition = this._columnDefinition();
|
|
1121
|
+
let expression;
|
|
1122
|
+
switch (this.builder.AlterType) {
|
|
1123
|
+
case orm_1.ColumnAlterationType.Add:
|
|
1124
|
+
expression = this._add(cDefinition.expression);
|
|
1125
|
+
break;
|
|
1126
|
+
case orm_1.ColumnAlterationType.Modify:
|
|
1127
|
+
expression = this._modify(cDefinition.expression);
|
|
1128
|
+
break;
|
|
1129
|
+
default:
|
|
1130
|
+
expression = cDefinition.expression;
|
|
1131
|
+
break;
|
|
998
1132
|
}
|
|
999
|
-
return
|
|
1133
|
+
return {
|
|
1134
|
+
bindings: cDefinition.bindings,
|
|
1135
|
+
expression: expression ?? '',
|
|
1136
|
+
};
|
|
1000
1137
|
}
|
|
1001
1138
|
};
|
|
1002
1139
|
exports.SqlAlterColumnQueryCompiler = SqlAlterColumnQueryCompiler;
|
|
1003
1140
|
exports.SqlAlterColumnQueryCompiler = SqlAlterColumnQueryCompiler = __decorate([
|
|
1004
1141
|
(0, di_1.NewInstance)(),
|
|
1005
|
-
|
|
1142
|
+
(0, di_1.Inject)(di_1.Container),
|
|
1143
|
+
__metadata("design:paramtypes", [di_1.Container, orm_1.AlterColumnQueryBuilder])
|
|
1006
1144
|
], SqlAlterColumnQueryCompiler);
|
|
1007
1145
|
let SqlEventQueryCompiler = class SqlEventQueryCompiler extends SqlQueryCompiler {
|
|
1008
1146
|
constructor(container, builder) {
|