squel 6.2.0 → 6.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/esm/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var package_default = {
3
3
  name: "squel",
4
- version: "6.2.0",
4
+ version: "6.3.0",
5
5
  description: "SQL query string builder",
6
6
  keywords: [
7
7
  "sql",
@@ -107,7 +107,7 @@ function _clone(src) {
107
107
  if (_isPlainObject(src) || _isArray(src)) {
108
108
  const ret = new anySrc.constructor;
109
109
  for (const key of Object.getOwnPropertyNames(src)) {
110
- if (typeof anySrc[key] !== "function") {
110
+ if (typeof anySrc[key] !== "function" && key !== "_queryBuilder") {
111
111
  ret[key] = _clone(anySrc[key]);
112
112
  }
113
113
  }
@@ -530,6 +530,178 @@ function _buildSquel(flavour = null) {
530
530
  return { text: totalStr, values: totalValues };
531
531
  }
532
532
  };
533
+ cls.Over = class extends cls.BaseBuilder {
534
+ _funcExpr;
535
+ _funcParams;
536
+ _partitionFields;
537
+ _orderFields;
538
+ _rows;
539
+ _range;
540
+ constructor(funcExpr, funcParams = [], options) {
541
+ super(options);
542
+ this._funcExpr = funcExpr;
543
+ this._funcParams = funcParams || [];
544
+ this._partitionFields = [];
545
+ this._orderFields = [];
546
+ this._rows = null;
547
+ this._range = null;
548
+ }
549
+ partitionBy(...fields) {
550
+ let flatFields = [];
551
+ for (const field of fields) {
552
+ if (_isArray(field)) {
553
+ flatFields = flatFields.concat(field);
554
+ } else {
555
+ flatFields.push(field);
556
+ }
557
+ }
558
+ for (const field of flatFields) {
559
+ this._partitionFields.push(this._sanitizeField(field));
560
+ }
561
+ return this;
562
+ }
563
+ orderBy(field, dir, ...values) {
564
+ field = this._sanitizeField(field);
565
+ let direction;
566
+ if (typeof dir === "string") {
567
+ direction = dir;
568
+ } else if (dir === undefined) {
569
+ direction = "ASC";
570
+ } else if (dir === null) {
571
+ direction = null;
572
+ } else {
573
+ direction = dir ? "ASC" : "DESC";
574
+ }
575
+ this._orderFields.push({ field, dir: direction, values: values || [] });
576
+ return this;
577
+ }
578
+ rowsBetween(start, end) {
579
+ if (end === undefined) {
580
+ this._rows = `ROWS BETWEEN ${start}`;
581
+ } else {
582
+ this._rows = `ROWS BETWEEN ${start} AND ${end}`;
583
+ }
584
+ this._range = null;
585
+ return this;
586
+ }
587
+ rangeBetween(start, end) {
588
+ if (end === undefined) {
589
+ this._range = `RANGE BETWEEN ${start}`;
590
+ } else {
591
+ this._range = `RANGE BETWEEN ${start} AND ${end}`;
592
+ }
593
+ this._rows = null;
594
+ return this;
595
+ }
596
+ _toParamString(options = {}) {
597
+ const values = [];
598
+ let funcRet;
599
+ if (cls.isSquelBuilder(this._funcExpr)) {
600
+ funcRet = this._funcExpr._toParamString({
601
+ buildParameterized: options.buildParameterized
602
+ });
603
+ } else {
604
+ funcRet = this._buildString(this._funcExpr, this._funcParams, {
605
+ buildParameterized: options.buildParameterized
606
+ });
607
+ }
608
+ funcRet.values.forEach((v) => values.push(v));
609
+ let overPartsStr = "";
610
+ if (this._partitionFields.length > 0) {
611
+ let partitionStr = "";
612
+ for (const field of this._partitionFields) {
613
+ partitionStr = _pad(partitionStr, ", ");
614
+ if (cls.isSquelBuilder(field)) {
615
+ const ret = field._toParamString({
616
+ buildParameterized: options.buildParameterized
617
+ });
618
+ partitionStr += ret.text;
619
+ ret.values.forEach((v) => values.push(v));
620
+ } else {
621
+ partitionStr += this._formatFieldName(field);
622
+ }
623
+ }
624
+ overPartsStr = `PARTITION BY ${partitionStr}`;
625
+ }
626
+ if (this._orderFields.length > 0) {
627
+ let orderStr = "";
628
+ for (const { field, dir, values: orderVals } of this._orderFields) {
629
+ orderStr = _pad(orderStr, ", ");
630
+ let ret;
631
+ if (cls.isSquelBuilder(field)) {
632
+ ret = field._toParamString({
633
+ buildParameterized: options.buildParameterized
634
+ });
635
+ } else {
636
+ ret = this._buildString(field, orderVals, {
637
+ buildParameterized: options.buildParameterized
638
+ });
639
+ }
640
+ orderStr += ret.text;
641
+ ret.values.forEach((v) => values.push(v));
642
+ if (dir !== null) {
643
+ orderStr += ` ${dir}`;
644
+ }
645
+ }
646
+ overPartsStr = _pad(overPartsStr, " ") + `ORDER BY ${orderStr}`;
647
+ }
648
+ const frameClause = this._rows || this._range;
649
+ if (frameClause) {
650
+ overPartsStr = _pad(overPartsStr, " ") + frameClause;
651
+ }
652
+ return {
653
+ text: `${funcRet.text} OVER (${overPartsStr})`,
654
+ values
655
+ };
656
+ }
657
+ };
658
+ cls.JsonExtract = class extends cls.BaseBuilder {
659
+ _field;
660
+ _path;
661
+ constructor(field, path, options) {
662
+ super(options);
663
+ this._field = field;
664
+ this._path = path;
665
+ }
666
+ _toParamString(options = {}) {
667
+ const values = [];
668
+ let fieldStr = "";
669
+ if (cls.isSquelBuilder(this._field)) {
670
+ const ret = this._field._toParamString({
671
+ buildParameterized: options.buildParameterized
672
+ });
673
+ fieldStr = ret.text;
674
+ ret.values.forEach((v) => values.push(v));
675
+ } else {
676
+ fieldStr = this._formatFieldName(this._field);
677
+ }
678
+ let cleanPath = this._path;
679
+ if (cleanPath.startsWith("$")) {
680
+ cleanPath = cleanPath.slice(1);
681
+ }
682
+ if (cleanPath.startsWith(".")) {
683
+ cleanPath = cleanPath.slice(1);
684
+ }
685
+ const parts = cleanPath.split(".").filter(Boolean);
686
+ let sql = "";
687
+ if (flavour === "postgres") {
688
+ if (parts.length === 0) {
689
+ sql = fieldStr;
690
+ } else {
691
+ sql = fieldStr;
692
+ for (let i = 0;i < parts.length; i++) {
693
+ const op = i === parts.length - 1 ? "->>" : "->";
694
+ sql += `${op}'${parts[i]}'`;
695
+ }
696
+ }
697
+ } else if (flavour === "mssql") {
698
+ sql = `JSON_VALUE(${fieldStr}, '${this._path}')`;
699
+ } else {
700
+ sql = `json_extract(${fieldStr}, '${this._path}')`;
701
+ }
702
+ return { text: sql, values };
703
+ }
704
+ };
533
705
  cls.Block = class extends cls.BaseBuilder {
534
706
  constructor(options) {
535
707
  super(options);
@@ -1043,7 +1215,7 @@ function _buildSquel(flavour = null) {
1043
1215
  _toParamString(options = {}) {
1044
1216
  let totalStr = "";
1045
1217
  const totalValues = [];
1046
- for (const { type, table, alias, condition } of this._joins) {
1218
+ for (const { type, table, alias, condition, isApply } of this._joins) {
1047
1219
  totalStr = _pad(totalStr, this.options.separator);
1048
1220
  let tableStr;
1049
1221
  if (cls.isSquelBuilder(table)) {
@@ -1056,7 +1228,11 @@ function _buildSquel(flavour = null) {
1056
1228
  } else {
1057
1229
  tableStr = this._formatTableName(table);
1058
1230
  }
1059
- totalStr += `${type} JOIN ${tableStr}`;
1231
+ if (isApply) {
1232
+ totalStr += `${type} ${tableStr}`;
1233
+ } else {
1234
+ totalStr += `${type} JOIN ${tableStr}`;
1235
+ }
1060
1236
  if (alias)
1061
1237
  totalStr += ` ${this._formatTableAlias(alias)}`;
1062
1238
  if (condition) {
@@ -1129,12 +1305,93 @@ function _buildSquel(flavour = null) {
1129
1305
  };
1130
1306
  }
1131
1307
  };
1308
+ cls.WithBlock = class extends cls.Block {
1309
+ _tables;
1310
+ constructor(options) {
1311
+ super(options);
1312
+ this._tables = [];
1313
+ }
1314
+ with(alias, table) {
1315
+ this._tables.push({ alias, table, recursive: false });
1316
+ }
1317
+ withRecursive(alias, table) {
1318
+ this._tables.push({ alias, table, recursive: true });
1319
+ }
1320
+ _toParamString(options = {}) {
1321
+ const parts = [];
1322
+ const values = [];
1323
+ let anyRecursive = false;
1324
+ for (const { alias, table, recursive } of this._tables) {
1325
+ if (recursive) {
1326
+ anyRecursive = true;
1327
+ }
1328
+ const ret = table._toParamString({
1329
+ buildParameterized: options.buildParameterized,
1330
+ nested: true
1331
+ });
1332
+ parts.push(`${alias} AS ${ret.text}`);
1333
+ ret.values.forEach((v) => values.push(v));
1334
+ }
1335
+ if (!parts.length) {
1336
+ return { text: "", values: [] };
1337
+ }
1338
+ const isMssql = this.options.useRecursiveKeyword === false;
1339
+ const prefix = anyRecursive && !isMssql ? "WITH RECURSIVE" : "WITH";
1340
+ return {
1341
+ text: `${prefix} ${parts.join(", ")}`,
1342
+ values
1343
+ };
1344
+ }
1345
+ };
1346
+ cls.ReturningBlock = class extends cls.Block {
1347
+ _fields;
1348
+ constructor(options) {
1349
+ super(options);
1350
+ this._fields = [];
1351
+ }
1352
+ returning(field, alias = null, options = {}) {
1353
+ alias = alias ? this._sanitizeFieldAlias(alias) : alias;
1354
+ field = this._sanitizeField(field);
1355
+ const existingField = this._fields.filter((f) => f.name === field && f.alias === alias);
1356
+ if (existingField.length)
1357
+ return this;
1358
+ this._fields.push({ name: field, alias, options });
1359
+ }
1360
+ _toParamString(options = {}) {
1361
+ const { buildParameterized } = options;
1362
+ let totalStr = "";
1363
+ const totalValues = [];
1364
+ for (const field of this._fields) {
1365
+ totalStr = _pad(totalStr, ", ");
1366
+ const { name, alias, options: fieldOptions } = field;
1367
+ if (typeof name === "string") {
1368
+ totalStr += this._formatFieldName(name, fieldOptions);
1369
+ } else {
1370
+ const ret = name._toParamString({ nested: true, buildParameterized });
1371
+ totalStr += ret.text;
1372
+ ret.values.forEach((v) => totalValues.push(v));
1373
+ }
1374
+ if (alias)
1375
+ totalStr += ` AS ${this._formatFieldAlias(alias)}`;
1376
+ }
1377
+ return {
1378
+ text: totalStr.length > 0 ? `RETURNING ${totalStr}` : "",
1379
+ values: totalValues
1380
+ };
1381
+ }
1382
+ };
1132
1383
  cls.QueryBuilder = class extends cls.BaseBuilder {
1133
1384
  blocks;
1134
1385
  constructor(options, blocks) {
1135
1386
  super(options);
1136
1387
  this.blocks = blocks || [];
1137
1388
  for (const block of this.blocks) {
1389
+ Object.defineProperty(block, "_queryBuilder", {
1390
+ value: this,
1391
+ enumerable: false,
1392
+ writable: true,
1393
+ configurable: true
1394
+ });
1138
1395
  const exposedMethods = block.exposedMethods();
1139
1396
  for (const methodName in exposedMethods) {
1140
1397
  const methodBody = exposedMethods[methodName];
@@ -1143,7 +1400,10 @@ function _buildSquel(flavour = null) {
1143
1400
  }
1144
1401
  ((b, name, body) => {
1145
1402
  this[name] = (...args) => {
1146
- body.call(b, ...args);
1403
+ const ret = body.call(b, ...args);
1404
+ if (ret !== undefined && ret !== b) {
1405
+ return ret;
1406
+ }
1147
1407
  return this;
1148
1408
  };
1149
1409
  })(block, methodName, methodBody);
@@ -1199,6 +1459,7 @@ function _buildSquel(flavour = null) {
1199
1459
  cls.Select = class extends cls.QueryBuilder {
1200
1460
  constructor(options, blocks = null) {
1201
1461
  blocks = blocks || [
1462
+ new cls.WithBlock(options),
1202
1463
  new cls.StringBlock(options, "SELECT"),
1203
1464
  new cls.FunctionBlock(options),
1204
1465
  new cls.DistinctBlock(options),
@@ -1220,12 +1481,14 @@ function _buildSquel(flavour = null) {
1220
1481
  cls.Update = class extends cls.QueryBuilder {
1221
1482
  constructor(options, blocks = null) {
1222
1483
  blocks = blocks || [
1484
+ new cls.WithBlock(options),
1223
1485
  new cls.StringBlock(options, "UPDATE"),
1224
1486
  new cls.UpdateTableBlock(options),
1225
1487
  new cls.SetFieldBlock(options),
1226
1488
  new cls.WhereBlock(options),
1227
1489
  new cls.OrderByBlock(options),
1228
- new cls.LimitBlock(options)
1490
+ new cls.LimitBlock(options),
1491
+ new cls.ReturningBlock(options)
1229
1492
  ];
1230
1493
  super(options, blocks);
1231
1494
  }
@@ -1233,13 +1496,15 @@ function _buildSquel(flavour = null) {
1233
1496
  cls.Delete = class extends cls.QueryBuilder {
1234
1497
  constructor(options, blocks = null) {
1235
1498
  blocks = blocks || [
1499
+ new cls.WithBlock(options),
1236
1500
  new cls.StringBlock(options, "DELETE"),
1237
1501
  new cls.TargetTableBlock(options),
1238
1502
  new cls.FromTableBlock(_extend({}, options, { singleTable: true })),
1239
1503
  new cls.JoinBlock(options),
1240
1504
  new cls.WhereBlock(options),
1241
1505
  new cls.OrderByBlock(options),
1242
- new cls.LimitBlock(options)
1506
+ new cls.LimitBlock(options),
1507
+ new cls.ReturningBlock(options)
1243
1508
  ];
1244
1509
  super(options, blocks);
1245
1510
  }
@@ -1247,10 +1512,12 @@ function _buildSquel(flavour = null) {
1247
1512
  cls.Insert = class extends cls.QueryBuilder {
1248
1513
  constructor(options, blocks = null) {
1249
1514
  blocks = blocks || [
1515
+ new cls.WithBlock(options),
1250
1516
  new cls.StringBlock(options, "INSERT"),
1251
1517
  new cls.IntoTableBlock(options),
1252
1518
  new cls.InsertFieldValueBlock(options),
1253
- new cls.InsertFieldsFromQueryBlock(options)
1519
+ new cls.InsertFieldsFromQueryBlock(options),
1520
+ new cls.ReturningBlock(options)
1254
1521
  ];
1255
1522
  super(options, blocks);
1256
1523
  }
@@ -1274,6 +1541,8 @@ function _buildSquel(flavour = null) {
1274
1541
  inst.function(...args);
1275
1542
  return inst;
1276
1543
  },
1544
+ over: (funcExpr, ...funcParams) => new cls.Over(funcExpr, funcParams),
1545
+ jsonExtract: (field, path) => new cls.JsonExtract(field, path),
1277
1546
  registerValueHandler: cls.registerValueHandler
1278
1547
  };
1279
1548
  _squel.remove = _squel.delete;
@@ -1299,10 +1568,40 @@ var core_default = squel;
1299
1568
  // src/mysql.ts
1300
1569
  squel.flavours.mysql = (_squel) => {
1301
1570
  const cls = _squel.cls;
1571
+
1572
+ class MysqlOnDuplicateKeyUpdateHelper {
1573
+ builder;
1574
+ block;
1575
+ constructor(builder, block) {
1576
+ this.builder = builder;
1577
+ this.block = block;
1578
+ }
1579
+ }
1302
1580
  cls.MysqlOnDuplicateKeyUpdateBlock = class extends cls.AbstractSetFieldBlock {
1303
1581
  onDupUpdate(field, value, options) {
1304
1582
  this._set(field, value, options);
1305
1583
  }
1584
+ onDuplicateKeyUpdate() {
1585
+ const helper = new MysqlOnDuplicateKeyUpdateHelper(this._queryBuilder, this);
1586
+ return new Proxy(helper, {
1587
+ get(target, prop, receiver) {
1588
+ if (prop === "set") {
1589
+ return (field, value, options) => {
1590
+ target.block._set(field, value, options);
1591
+ return receiver;
1592
+ };
1593
+ }
1594
+ const val = target.builder[prop];
1595
+ if (typeof val === "function") {
1596
+ return (...args) => {
1597
+ const ret = val.apply(target.builder, args);
1598
+ return ret === target.builder ? receiver : ret;
1599
+ };
1600
+ }
1601
+ return val;
1602
+ }
1603
+ });
1604
+ }
1306
1605
  _toParamString(options = {}) {
1307
1606
  let totalStr = "";
1308
1607
  const totalValues = [];
@@ -1331,6 +1630,7 @@ squel.flavours.mysql = (_squel) => {
1331
1630
  cls.Insert = class extends cls.QueryBuilder {
1332
1631
  constructor(options, blocks = null) {
1333
1632
  blocks = blocks || [
1633
+ new cls.WithBlock(options),
1334
1634
  new cls.StringBlock(options, "INSERT"),
1335
1635
  new cls.IntoTableBlock(options),
1336
1636
  new cls.InsertFieldValueBlock(options),
@@ -1343,6 +1643,7 @@ squel.flavours.mysql = (_squel) => {
1343
1643
  cls.Replace = class extends cls.QueryBuilder {
1344
1644
  constructor(options, blocks = null) {
1345
1645
  blocks = blocks || [
1646
+ new cls.WithBlock(options),
1346
1647
  new cls.StringBlock(options, "REPLACE"),
1347
1648
  new cls.IntoTableBlock(options),
1348
1649
  new cls.InsertFieldValueBlock(options),
@@ -1361,6 +1662,15 @@ squel.flavours.postgres = (_squel) => {
1361
1662
  cls.DefaultQueryBuilderOptions.numberedParametersStartAt = 1;
1362
1663
  cls.DefaultQueryBuilderOptions.autoQuoteAliasNames = false;
1363
1664
  cls.DefaultQueryBuilderOptions.useAsForTableAliasNames = true;
1665
+
1666
+ class PostgresOnConflictUpdateHelper {
1667
+ builder;
1668
+ block;
1669
+ constructor(builder, block) {
1670
+ this.builder = builder;
1671
+ this.block = block;
1672
+ }
1673
+ }
1364
1674
  cls.PostgresOnConflictKeyUpdateBlock = class extends cls.AbstractSetFieldBlock {
1365
1675
  _onConflict;
1366
1676
  _dupFields;
@@ -1371,17 +1681,46 @@ squel.flavours.postgres = (_squel) => {
1371
1681
  }
1372
1682
  onConflict(conflictFields, fields) {
1373
1683
  this._onConflict = true;
1374
- if (!conflictFields)
1375
- return;
1376
- if (!_isArray(conflictFields)) {
1377
- conflictFields = [conflictFields];
1684
+ if (conflictFields) {
1685
+ if (!_isArray(conflictFields)) {
1686
+ conflictFields = [conflictFields];
1687
+ }
1688
+ this._dupFields = conflictFields.map(this._sanitizeField.bind(this));
1378
1689
  }
1379
- this._dupFields = conflictFields.map(this._sanitizeField.bind(this));
1380
1690
  if (fields) {
1381
1691
  Object.keys(fields).forEach((key) => {
1382
1692
  this._set(key, fields[key]);
1383
1693
  });
1384
1694
  }
1695
+ return this._queryBuilder;
1696
+ }
1697
+ doUpdate() {
1698
+ const helper = new PostgresOnConflictUpdateHelper(this._queryBuilder, this);
1699
+ return new Proxy(helper, {
1700
+ get(target, prop, receiver) {
1701
+ if (prop === "set") {
1702
+ return (field, value, options) => {
1703
+ target.block._set(field, value, options);
1704
+ return receiver;
1705
+ };
1706
+ }
1707
+ const val = target.builder[prop];
1708
+ if (typeof val === "function") {
1709
+ return (...args) => {
1710
+ const ret = val.apply(target.builder, args);
1711
+ return ret === target.builder ? receiver : ret;
1712
+ };
1713
+ }
1714
+ return val;
1715
+ }
1716
+ });
1717
+ }
1718
+ doNothing() {
1719
+ this._onConflict = true;
1720
+ this._fields = [];
1721
+ this._values = [[]];
1722
+ this._valueOptions = [[]];
1723
+ return this._queryBuilder;
1385
1724
  }
1386
1725
  _toParamString(options = {}) {
1387
1726
  let totalStr = "";
@@ -1411,69 +1750,6 @@ squel.flavours.postgres = (_squel) => {
1411
1750
  return returned;
1412
1751
  }
1413
1752
  };
1414
- cls.ReturningBlock = class extends cls.Block {
1415
- _fields;
1416
- constructor(options) {
1417
- super(options);
1418
- this._fields = [];
1419
- }
1420
- returning(field, alias = null, options = {}) {
1421
- alias = alias ? this._sanitizeFieldAlias(alias) : alias;
1422
- field = this._sanitizeField(field);
1423
- const existingField = this._fields.filter((f) => f.name === field && f.alias === alias);
1424
- if (existingField.length)
1425
- return this;
1426
- this._fields.push({ name: field, alias, options });
1427
- }
1428
- _toParamString(options = {}) {
1429
- const { buildParameterized } = options;
1430
- let totalStr = "";
1431
- const totalValues = [];
1432
- for (const field of this._fields) {
1433
- totalStr = _pad(totalStr, ", ");
1434
- const { name, alias, options: fieldOptions } = field;
1435
- if (typeof name === "string") {
1436
- totalStr += this._formatFieldName(name, fieldOptions);
1437
- } else {
1438
- const ret = name._toParamString({ nested: true, buildParameterized });
1439
- totalStr += ret.text;
1440
- ret.values.forEach((v) => totalValues.push(v));
1441
- }
1442
- if (alias)
1443
- totalStr += ` AS ${this._formatFieldAlias(alias)}`;
1444
- }
1445
- return {
1446
- text: totalStr.length > 0 ? `RETURNING ${totalStr}` : "",
1447
- values: totalValues
1448
- };
1449
- }
1450
- };
1451
- cls.WithBlock = class extends cls.Block {
1452
- _tables;
1453
- constructor(options) {
1454
- super(options);
1455
- this._tables = [];
1456
- }
1457
- with(alias, table) {
1458
- this._tables.push({ alias, table });
1459
- }
1460
- _toParamString(options = {}) {
1461
- const parts = [];
1462
- const values = [];
1463
- for (const { alias, table } of this._tables) {
1464
- const ret = table._toParamString({
1465
- buildParameterized: options.buildParameterized,
1466
- nested: true
1467
- });
1468
- parts.push(`${alias} AS ${ret.text}`);
1469
- ret.values.forEach((v) => values.push(v));
1470
- }
1471
- return {
1472
- text: parts.length ? `WITH ${parts.join(", ")}` : "",
1473
- values
1474
- };
1475
- }
1476
- };
1477
1753
  cls.UsingBlock = class extends cls.AbstractTableBlock {
1478
1754
  constructor(options) {
1479
1755
  super({ ...options, prefix: "USING" });
@@ -1587,6 +1863,7 @@ squel.flavours.mssql = (_squel) => {
1587
1863
  cls.DefaultQueryBuilderOptions.replaceSingleQuotes = true;
1588
1864
  cls.DefaultQueryBuilderOptions.autoQuoteAliasNames = false;
1589
1865
  cls.DefaultQueryBuilderOptions.numberedParametersPrefix = "@";
1866
+ cls.DefaultQueryBuilderOptions.useRecursiveKeyword = false;
1590
1867
  _squel.registerValueHandler(Date, (value) => {
1591
1868
  const date = value;
1592
1869
  return `'${date.getUTCFullYear()}-${date.getUTCMonth() + 1}-${date.getUTCDate()} ${date.getUTCHours()}:${date.getUTCMinutes()}:${date.getUTCSeconds()}'`;
@@ -1686,19 +1963,36 @@ squel.flavours.mssql = (_squel) => {
1686
1963
  super(options);
1687
1964
  this._outputs = [];
1688
1965
  }
1689
- output(fields) {
1690
- if (typeof fields === "string") {
1691
- this._outputs.push(`INSERTED.${this._sanitizeField(fields)}`);
1692
- } else {
1693
- fields.forEach((f) => {
1694
- this._outputs.push(`INSERTED.${this._sanitizeField(f)}`);
1966
+ outputs(outputs) {
1967
+ for (const output in outputs) {
1968
+ this.output(output, outputs[output]);
1969
+ }
1970
+ }
1971
+ output(output, alias = null) {
1972
+ if (typeof output === "string") {
1973
+ output = this._sanitizeField(output);
1974
+ alias = alias ? this._sanitizeFieldAlias(alias) : alias;
1975
+ this._outputs.push({
1976
+ name: `INSERTED.${output}`,
1977
+ alias
1978
+ });
1979
+ } else if (Array.isArray(output)) {
1980
+ output.forEach((f) => {
1981
+ this.output(f);
1695
1982
  });
1696
1983
  }
1697
1984
  }
1698
1985
  _toParamString(options) {
1699
1986
  const ret = super._toParamString(options);
1700
1987
  if (ret.text.length && this._outputs.length > 0) {
1701
- const innerStr = `OUTPUT ${this._outputs.join(", ")} `;
1988
+ const parts = this._outputs.map((o) => {
1989
+ let str = o.name;
1990
+ if (o.alias) {
1991
+ str += ` AS ${this._formatFieldAlias(o.alias)}`;
1992
+ }
1993
+ return str;
1994
+ });
1995
+ const innerStr = `OUTPUT ${parts.join(", ")} `;
1702
1996
  const valuesPos = ret.text.indexOf("VALUES");
1703
1997
  ret.text = ret.text.substring(0, valuesPos) + innerStr + ret.text.substring(valuesPos);
1704
1998
  }
@@ -1739,16 +2033,40 @@ squel.flavours.mssql = (_squel) => {
1739
2033
  return { text: totalStr, values: [] };
1740
2034
  }
1741
2035
  };
2036
+ cls.MssqlJoinBlock = class extends cls.JoinBlock {
2037
+ apply(table, alias = null, type = "CROSS") {
2038
+ table = this._sanitizeTable(table, true);
2039
+ alias = alias ? this._sanitizeTableAlias(alias) : alias;
2040
+ let applyType = type.toUpperCase();
2041
+ if (!applyType.endsWith("APPLY")) {
2042
+ applyType = `${applyType} APPLY`;
2043
+ }
2044
+ this._joins.push({
2045
+ type: applyType,
2046
+ table,
2047
+ alias,
2048
+ condition: null,
2049
+ isApply: true
2050
+ });
2051
+ }
2052
+ cross_apply(table, alias = null) {
2053
+ this.apply(table, alias, "CROSS");
2054
+ }
2055
+ outer_apply(table, alias = null) {
2056
+ this.apply(table, alias, "OUTER");
2057
+ }
2058
+ };
1742
2059
  cls.Select = class extends cls.QueryBuilder {
1743
2060
  constructor(options, blocks = null) {
1744
2061
  const limitOffsetTopBlock = new cls.MssqlLimitOffsetTopBlock(options);
1745
2062
  blocks = blocks || [
2063
+ new cls.WithBlock(options),
1746
2064
  new cls.StringBlock(options, "SELECT"),
1747
2065
  new cls.DistinctBlock(options),
1748
2066
  limitOffsetTopBlock.TOP(),
1749
2067
  new cls.GetFieldBlock(options),
1750
2068
  new cls.FromTableBlock(options),
1751
- new cls.JoinBlock(options),
2069
+ new cls.MssqlJoinBlock(options),
1752
2070
  new cls.WhereBlock(options),
1753
2071
  new cls.GroupByBlock(options),
1754
2072
  new cls.HavingBlock(options),
@@ -1763,6 +2081,7 @@ squel.flavours.mssql = (_squel) => {
1763
2081
  cls.Update = class extends cls.QueryBuilder {
1764
2082
  constructor(options, blocks = null) {
1765
2083
  blocks = blocks || [
2084
+ new cls.WithBlock(options),
1766
2085
  new cls.StringBlock(options, "UPDATE"),
1767
2086
  new cls.MssqlUpdateTopBlock(options),
1768
2087
  new cls.UpdateTableBlock(options),
@@ -1776,6 +2095,7 @@ squel.flavours.mssql = (_squel) => {
1776
2095
  cls.Delete = class extends cls.QueryBuilder {
1777
2096
  constructor(options, blocks = null) {
1778
2097
  blocks = blocks || [
2098
+ new cls.WithBlock(options),
1779
2099
  new cls.StringBlock(options, "DELETE"),
1780
2100
  new cls.TargetTableBlock(options),
1781
2101
  new cls.FromTableBlock(_extend({}, options, { singleTable: true })),
@@ -1791,6 +2111,7 @@ squel.flavours.mssql = (_squel) => {
1791
2111
  cls.Insert = class extends cls.QueryBuilder {
1792
2112
  constructor(options, blocks = null) {
1793
2113
  blocks = blocks || [
2114
+ new cls.WithBlock(options),
1794
2115
  new cls.StringBlock(options, "INSERT"),
1795
2116
  new cls.IntoTableBlock(options),
1796
2117
  new cls.MssqlInsertFieldValueBlock(options),
@@ -1799,6 +2120,199 @@ squel.flavours.mssql = (_squel) => {
1799
2120
  super(options, blocks);
1800
2121
  }
1801
2122
  };
2123
+ cls.MergeIntoBlock = class extends cls.Block {
2124
+ _table = null;
2125
+ _alias = null;
2126
+ into(table, alias = null) {
2127
+ this._table = this._sanitizeTable(table);
2128
+ this._alias = alias ? this._sanitizeTableAlias(alias) : null;
2129
+ }
2130
+ _toParamString() {
2131
+ if (!this._table)
2132
+ throw new Error("into() needs to be called");
2133
+ let str = this._formatTableName(this._table);
2134
+ if (this._alias) {
2135
+ str += ` AS ${this._formatTableAlias(this._alias)}`;
2136
+ }
2137
+ return { text: str, values: [] };
2138
+ }
2139
+ };
2140
+ cls.MergeUsingBlock = class extends cls.Block {
2141
+ _source = null;
2142
+ _alias = null;
2143
+ _condition = null;
2144
+ using(source, alias = null, condition = null) {
2145
+ this._source = typeof source === "string" ? this._sanitizeTable(source) : this._sanitizeBaseBuilder(source);
2146
+ this._alias = alias ? this._sanitizeTableAlias(alias) : null;
2147
+ this._condition = condition ? this._sanitizeExpression(condition) : null;
2148
+ }
2149
+ _toParamString(options = {}) {
2150
+ if (!this._source)
2151
+ throw new Error("using() needs to be called");
2152
+ let sourceStr = "";
2153
+ const values = [];
2154
+ if (typeof this._source === "string") {
2155
+ sourceStr = this._formatTableName(this._source);
2156
+ } else {
2157
+ const ret = this._source._toParamString({
2158
+ buildParameterized: options.buildParameterized,
2159
+ nested: true
2160
+ });
2161
+ sourceStr = ret.text;
2162
+ ret.values.forEach((v) => values.push(v));
2163
+ }
2164
+ if (this._alias) {
2165
+ sourceStr += ` AS ${this._formatTableAlias(this._alias)}`;
2166
+ }
2167
+ let conditionStr = "";
2168
+ if (this._condition) {
2169
+ let ret;
2170
+ if (typeof this._condition === "string") {
2171
+ ret = this._buildString(this._condition, [], {
2172
+ buildParameterized: options.buildParameterized
2173
+ });
2174
+ } else {
2175
+ ret = this._condition._toParamString({
2176
+ buildParameterized: options.buildParameterized
2177
+ });
2178
+ }
2179
+ conditionStr = ` ON ${this._applyNestingFormatting(ret.text)}`;
2180
+ ret.values.forEach((v) => values.push(v));
2181
+ }
2182
+ return {
2183
+ text: `USING ${sourceStr}${conditionStr}`,
2184
+ values
2185
+ };
2186
+ }
2187
+ };
2188
+
2189
+ class MergeMatchedClauseHelper {
2190
+ builder;
2191
+ clause;
2192
+ constructor(builder, clause) {
2193
+ this.builder = builder;
2194
+ this.clause = clause;
2195
+ }
2196
+ update(fields) {
2197
+ this.clause.action = { type: "UPDATE", fields };
2198
+ return this.builder;
2199
+ }
2200
+ delete() {
2201
+ this.clause.action = { type: "DELETE" };
2202
+ return this.builder;
2203
+ }
2204
+ }
2205
+
2206
+ class MergeNotMatchedClauseHelper {
2207
+ builder;
2208
+ clause;
2209
+ constructor(builder, clause) {
2210
+ this.builder = builder;
2211
+ this.clause = clause;
2212
+ }
2213
+ insert(fields) {
2214
+ this.clause.action = { type: "INSERT", fields };
2215
+ return this.builder;
2216
+ }
2217
+ }
2218
+ cls.MergeWhenBlock = class extends cls.Block {
2219
+ _clauses;
2220
+ constructor(options) {
2221
+ super(options);
2222
+ this._clauses = [];
2223
+ }
2224
+ whenMatched(condition = null) {
2225
+ const clause = { type: "MATCHED", condition, action: null };
2226
+ this._clauses.push(clause);
2227
+ return new MergeMatchedClauseHelper(this._queryBuilder, clause);
2228
+ }
2229
+ whenNotMatched(condition = null) {
2230
+ const clause = { type: "NOT_MATCHED", condition, action: null };
2231
+ this._clauses.push(clause);
2232
+ return new MergeNotMatchedClauseHelper(this._queryBuilder, clause);
2233
+ }
2234
+ _toParamString(options = {}) {
2235
+ let totalStr = "";
2236
+ const totalValues = [];
2237
+ for (const clause of this._clauses) {
2238
+ if (!clause.action)
2239
+ continue;
2240
+ totalStr = _pad(totalStr, " ");
2241
+ let condStr = "";
2242
+ if (clause.condition) {
2243
+ const ret = this._buildString(clause.condition, [], {
2244
+ buildParameterized: options.buildParameterized
2245
+ });
2246
+ condStr = ` AND ${ret.text}`;
2247
+ ret.values.forEach((v) => totalValues.push(v));
2248
+ }
2249
+ let actionStr = "";
2250
+ if (clause.action.type === "UPDATE") {
2251
+ let setStr = "";
2252
+ for (const key of Object.keys(clause.action.fields)) {
2253
+ setStr = _pad(setStr, ", ");
2254
+ const val = clause.action.fields[key];
2255
+ if (val && typeof val._toParamString === "function") {
2256
+ const ret = val._toParamString({
2257
+ buildParameterized: options.buildParameterized
2258
+ });
2259
+ setStr += `${this._formatFieldName(key)} = ${ret.text}`;
2260
+ ret.values.forEach((v) => totalValues.push(v));
2261
+ } else {
2262
+ const ret = this._buildString(`${this._formatFieldName(key)} = ${this.options.parameterCharacter}`, [val], {
2263
+ buildParameterized: options.buildParameterized
2264
+ });
2265
+ setStr += ret.text;
2266
+ ret.values.forEach((v) => totalValues.push(v));
2267
+ }
2268
+ }
2269
+ actionStr = `THEN UPDATE SET ${setStr}`;
2270
+ } else if (clause.action.type === "DELETE") {
2271
+ actionStr = "THEN DELETE";
2272
+ } else if (clause.action.type === "INSERT") {
2273
+ const cols = Object.keys(clause.action.fields).map((c) => this._formatFieldName(c)).join(", ");
2274
+ let valsStr = "";
2275
+ for (const key of Object.keys(clause.action.fields)) {
2276
+ valsStr = _pad(valsStr, ", ");
2277
+ const val = clause.action.fields[key];
2278
+ if (val && typeof val._toParamString === "function") {
2279
+ const ret = val._toParamString({
2280
+ buildParameterized: options.buildParameterized
2281
+ });
2282
+ valsStr += ret.text;
2283
+ ret.values.forEach((v) => totalValues.push(v));
2284
+ } else {
2285
+ const ret = this._buildString(this.options.parameterCharacter, [val], {
2286
+ buildParameterized: options.buildParameterized
2287
+ });
2288
+ valsStr += ret.text;
2289
+ ret.values.forEach((v) => totalValues.push(v));
2290
+ }
2291
+ }
2292
+ actionStr = `THEN INSERT (${cols}) VALUES (${valsStr})`;
2293
+ }
2294
+ const whenWord = clause.type === "MATCHED" ? "WHEN MATCHED" : "WHEN NOT MATCHED";
2295
+ totalStr += `${whenWord}${condStr} ${actionStr}`;
2296
+ }
2297
+ return {
2298
+ text: totalStr.length ? `${totalStr};` : "",
2299
+ values: totalValues
2300
+ };
2301
+ }
2302
+ };
2303
+ cls.Merge = class extends cls.QueryBuilder {
2304
+ constructor(options, blocks = null) {
2305
+ blocks = blocks || [
2306
+ new cls.WithBlock(options),
2307
+ new cls.StringBlock(options, "MERGE INTO"),
2308
+ new cls.MergeIntoBlock(options),
2309
+ new cls.MergeUsingBlock(options),
2310
+ new cls.MergeWhenBlock(options)
2311
+ ];
2312
+ super(options, blocks);
2313
+ }
2314
+ };
2315
+ _squel.merge = (options, blocks) => new cls.Merge(options, blocks);
1802
2316
  };
1803
2317
 
1804
2318
  // src/index.ts
@@ -1808,4 +2322,4 @@ export {
1808
2322
  src_default as default
1809
2323
  };
1810
2324
 
1811
- //# debugId=F51DFA53E8AD876F64756E2164756E21
2325
+ //# debugId=C3B9A8DC1888720164756E2164756E21