@carbonorm/carbonnode 3.8.4 → 3.9.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/index.cjs.js CHANGED
@@ -61,6 +61,7 @@ var C6Constants = {
61
61
  INNER: 'INNER',
62
62
  INTERVAL: 'INTERVAL',
63
63
  JOIN: 'JOIN',
64
+ FROM: 'FROM',
64
65
  LEFT: 'LEFT',
65
66
  LEFT_OUTER: 'LEFT_OUTER',
66
67
  LESS_THAN: '<',
@@ -92,6 +93,7 @@ var C6Constants = {
92
93
  SECOND: 'SECOND',
93
94
  SECOND_MICROSECOND: 'SECOND_MICROSECOND',
94
95
  SELECT: 'SELECT',
96
+ SUBSELECT: 'SUBSELECT',
95
97
  // MySQL Spatial Functions
96
98
  ST_AREA: 'ST_Area',
97
99
  ST_ASBINARY: 'ST_AsBinary',
@@ -1254,9 +1256,16 @@ var AggregateBuilder = /** @class */ (function (_super) {
1254
1256
  _this.selectAliases = new Set();
1255
1257
  return _this;
1256
1258
  }
1257
- AggregateBuilder.prototype.buildAggregateField = function (field) {
1259
+ // Overridden in ConditionBuilder where alias tracking is available.
1260
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1261
+ AggregateBuilder.prototype.assertValidIdentifier = function (_identifier, _context) {
1262
+ // no-op placeholder for subclasses that do not implement alias validation
1263
+ };
1264
+ AggregateBuilder.prototype.buildAggregateField = function (field, params) {
1258
1265
  var _this = this;
1266
+ var _a, _b;
1259
1267
  if (typeof field === 'string') {
1268
+ this.assertValidIdentifier(field, 'SELECT field');
1260
1269
  return field;
1261
1270
  }
1262
1271
  if (!Array.isArray(field) || field.length === 0) {
@@ -1269,8 +1278,33 @@ var AggregateBuilder = /** @class */ (function (_super) {
1269
1278
  args.pop();
1270
1279
  }
1271
1280
  var F = String(fn).toUpperCase();
1281
+ if (F === C6C.SUBSELECT) {
1282
+ if (!params) {
1283
+ throw new Error('Scalar subselects in SELECT require parameter tracking.');
1284
+ }
1285
+ var subRequest = args[0];
1286
+ var subSql = (_b = (_a = this).buildScalarSubSelect) === null || _b === void 0 ? void 0 : _b.call(_a, subRequest, params);
1287
+ if (!subSql) {
1288
+ throw new Error('Failed to build scalar subselect.');
1289
+ }
1290
+ var expr_1 = subSql;
1291
+ if (alias) {
1292
+ this.selectAliases.add(alias);
1293
+ expr_1 += " AS ".concat(alias);
1294
+ }
1295
+ this.config.verbose && console.log("[SELECT] ".concat(expr_1));
1296
+ return expr_1;
1297
+ }
1272
1298
  var argList = args
1273
- .map(function (arg) { return Array.isArray(arg) ? _this.buildAggregateField(arg) : arg; })
1299
+ .map(function (arg) {
1300
+ if (Array.isArray(arg))
1301
+ return _this.buildAggregateField(arg, params);
1302
+ if (typeof arg === 'string') {
1303
+ _this.assertValidIdentifier(arg, 'SELECT expression');
1304
+ return arg;
1305
+ }
1306
+ return String(arg);
1307
+ })
1274
1308
  .join(', ');
1275
1309
  var expr;
1276
1310
  if (F === 'DISTINCT') {
@@ -1289,11 +1323,91 @@ var AggregateBuilder = /** @class */ (function (_super) {
1289
1323
  return AggregateBuilder;
1290
1324
  }(Executor));
1291
1325
 
1326
+ // Alias a table name with a given alias
1327
+ var DERIVED_TABLE_PREFIX = '__c6DerivedTable__';
1328
+ var DERIVED_ID_SYMBOL = Symbol('c6DerivedTableId');
1329
+ var derivedTableLookup = new Map();
1330
+ var derivedTableReverseLookup = new WeakMap();
1331
+ var derivedTableCounter = 0;
1332
+ var isDerivedTableKey = function (key) {
1333
+ return typeof key === 'string' && key.startsWith(DERIVED_TABLE_PREFIX);
1334
+ };
1335
+ var resolveDerivedTable = function (key) {
1336
+ return derivedTableLookup.get(key);
1337
+ };
1338
+ var derivedTable = function (spec) {
1339
+ if (!spec || typeof spec !== 'object') {
1340
+ throw new Error('Derived table definition must be an object.');
1341
+ }
1342
+ var aliasRaw = spec[C6C.AS];
1343
+ if (typeof aliasRaw !== 'string' || aliasRaw.trim() === '') {
1344
+ throw new Error('Derived tables require a non-empty alias via C6C.AS.');
1345
+ }
1346
+ if (!spec[C6C.SUBSELECT] || typeof spec[C6C.SUBSELECT] !== 'object') {
1347
+ throw new Error('Derived tables require a nested SELECT payload under C6C.SUBSELECT.');
1348
+ }
1349
+ var id = derivedTableReverseLookup.get(spec);
1350
+ if (!id) {
1351
+ id = "".concat(DERIVED_TABLE_PREFIX).concat(++derivedTableCounter);
1352
+ derivedTableReverseLookup.set(spec, id);
1353
+ derivedTableLookup.set(id, spec);
1354
+ Object.defineProperty(spec, DERIVED_ID_SYMBOL, {
1355
+ value: id,
1356
+ configurable: false,
1357
+ enumerable: false,
1358
+ writable: false
1359
+ });
1360
+ }
1361
+ var alias = aliasRaw.trim();
1362
+ derivedTableLookup.set(id, spec);
1363
+ Object.defineProperty(spec, 'toString', {
1364
+ value: function () { return "".concat(id, " ").concat(alias); },
1365
+ configurable: true,
1366
+ enumerable: false,
1367
+ writable: true
1368
+ });
1369
+ return spec;
1370
+ };
1371
+ var A = function (tableName, alias) {
1372
+ return "".concat(tableName, " ").concat(alias);
1373
+ };
1374
+ // Qualify a column constant (e.g. 'property_units.parcel_id') to an alias
1375
+ var F = function (qualifiedCol, alias) {
1376
+ return "".concat(alias, ".").concat(qualifiedCol.split('.').pop());
1377
+ };
1378
+ // Equal join condition using full-qualified column constants
1379
+ var fieldEq = function (leftCol, rightCol, leftAlias, rightAlias) {
1380
+ var _a;
1381
+ return (_a = {},
1382
+ _a[F(leftCol, leftAlias)] = F(rightCol, rightAlias),
1383
+ _a);
1384
+ };
1385
+ // ST_Distance_Sphere for aliased fields
1386
+ var distSphere = function (fromCol, toCol, fromAlias, toAlias) {
1387
+ return [C6C.ST_DISTANCE_SPHERE, F(fromCol, fromAlias), F(toCol, toAlias)];
1388
+ };
1389
+ // Build a bounding-box expression.
1390
+ //
1391
+ // Arguments must be provided in `(minLng, minLat, maxLng, maxLat)` order. The
1392
+ // helper does not attempt to swap or validate coordinates; if a minimum value
1393
+ // is greater than its corresponding maximum value, MySQL's `ST_MakeEnvelope`
1394
+ // returns `NULL`.
1395
+ var bbox = function (minLng, minLat, maxLng, maxLat) {
1396
+ return [C6C.ST_SRID, [C6C.ST_MAKEENVELOPE,
1397
+ [C6C.ST_POINT, minLng, minLat],
1398
+ [C6C.ST_POINT, maxLng, maxLat]], 4326];
1399
+ };
1400
+ // ST_Contains for map envelope/shape queries
1401
+ var stContains = function (envelope, shape) {
1402
+ return [C6C.ST_CONTAINS, envelope, shape];
1403
+ };
1404
+
1292
1405
  var ConditionBuilder = /** @class */ (function (_super) {
1293
1406
  tslib.__extends(ConditionBuilder, _super);
1294
1407
  function ConditionBuilder() {
1295
1408
  var _this = _super !== null && _super.apply(this, arguments) || this;
1296
1409
  _this.aliasMap = {};
1410
+ _this.derivedAliases = new Set();
1297
1411
  _this.OPERATORS = new Set([
1298
1412
  C6C.EQUAL, C6C.NOT_EQUAL, C6C.LESS_THAN, C6C.LESS_THAN_OR_EQUAL_TO,
1299
1413
  C6C.GREATER_THAN, C6C.GREATER_THAN_OR_EQUAL_TO,
@@ -1318,21 +1432,43 @@ var ConditionBuilder = /** @class */ (function (_super) {
1318
1432
  ConditionBuilder.prototype.initAlias = function (baseTable, joins) {
1319
1433
  var _a;
1320
1434
  this.aliasMap = (_a = {}, _a[baseTable] = baseTable, _a);
1435
+ this.derivedAliases = new Set();
1321
1436
  if (!joins)
1322
1437
  return;
1323
1438
  for (var joinType in joins) {
1324
1439
  for (var raw in joins[joinType]) {
1325
- var _b = raw.split(' '), table = _b[0], alias = _b[1];
1326
- this.aliasMap[alias || table] = table;
1440
+ var _b = raw.trim().split(/\s+/, 2), table = _b[0], alias = _b[1];
1441
+ if (!table)
1442
+ continue;
1443
+ this.registerAlias(alias || table, table);
1327
1444
  }
1328
1445
  }
1329
1446
  };
1447
+ ConditionBuilder.prototype.registerAlias = function (alias, table) {
1448
+ this.aliasMap[alias] = table;
1449
+ if (isDerivedTableKey(table)) {
1450
+ this.derivedAliases.add(alias);
1451
+ }
1452
+ };
1453
+ ConditionBuilder.prototype.assertValidIdentifier = function (identifier, context) {
1454
+ if (typeof identifier !== 'string')
1455
+ return;
1456
+ if (!identifier.includes('.'))
1457
+ return;
1458
+ var alias = identifier.split('.', 2)[0];
1459
+ if (!(alias in this.aliasMap)) {
1460
+ throw new Error("Unknown table or alias '".concat(alias, "' referenced in ").concat(context, ": '").concat(identifier, "'."));
1461
+ }
1462
+ };
1330
1463
  ConditionBuilder.prototype.isColumnRef = function (ref) {
1331
1464
  var _a, _b;
1332
1465
  if (typeof ref !== 'string' || !ref.includes('.'))
1333
1466
  return false;
1334
1467
  var _c = ref.split('.', 2), prefix = _c[0], column = _c[1];
1335
1468
  var tableName = this.aliasMap[prefix] || prefix;
1469
+ if (isDerivedTableKey(tableName) || this.derivedAliases.has(prefix)) {
1470
+ return true;
1471
+ }
1336
1472
  var table = (_b = (_a = this.config.C6) === null || _a === void 0 ? void 0 : _a.TABLES) === null || _b === void 0 ? void 0 : _b[tableName];
1337
1473
  if (!table)
1338
1474
  return false;
@@ -1361,6 +1497,9 @@ var ConditionBuilder = /** @class */ (function (_super) {
1361
1497
  }
1362
1498
  var _e = val.split('.'), prefix = _e[0], column = _e[1];
1363
1499
  var tableName = (_b = this.aliasMap[prefix]) !== null && _b !== void 0 ? _b : prefix;
1500
+ if (isDerivedTableKey(tableName) || this.derivedAliases.has(prefix)) {
1501
+ return true;
1502
+ }
1364
1503
  var table = (_d = (_c = this.config.C6) === null || _c === void 0 ? void 0 : _c.TABLES) === null || _d === void 0 ? void 0 : _d[tableName];
1365
1504
  if (!table || !table.COLUMNS)
1366
1505
  return false;
@@ -1403,6 +1542,26 @@ var ConditionBuilder = /** @class */ (function (_super) {
1403
1542
  // Normalize common variants
1404
1543
  var valueNorm = (value === C6C.NULL) ? null : value;
1405
1544
  var displayOp = typeof op === 'string' ? op.replace('_', ' ') : op;
1545
+ var extractSubSelect = function (input) {
1546
+ if (Array.isArray(input) && input.length >= 2 && input[0] === C6C.SUBSELECT) {
1547
+ return input[1];
1548
+ }
1549
+ if (input && typeof input === 'object' && C6C.SUBSELECT in input) {
1550
+ return input[C6C.SUBSELECT];
1551
+ }
1552
+ return undefined;
1553
+ };
1554
+ var rightSubSelectPayload = extractSubSelect(valueNorm);
1555
+ var buildSubSelect = function (payload) {
1556
+ if (!payload)
1557
+ return undefined;
1558
+ var builder = _this.buildScalarSubSelect;
1559
+ if (typeof builder !== 'function') {
1560
+ throw new Error('Scalar subselect handling requires JoinBuilder context.');
1561
+ }
1562
+ return builder.call(_this, payload, params);
1563
+ };
1564
+ var rightSubSelectSql = buildSubSelect(rightSubSelectPayload);
1406
1565
  // Support function-based expressions like [C6C.ST_DISTANCE_SPHERE, col1, col2]
1407
1566
  if (typeof column === 'string' &&
1408
1567
  _this.OPERATORS.has(column) &&
@@ -1429,7 +1588,7 @@ var ConditionBuilder = /** @class */ (function (_super) {
1429
1588
  var leftIsCol = _this.isColumnRef(column);
1430
1589
  var leftIsRef = _this.isTableReference(column);
1431
1590
  var rightIsCol = typeof value === 'string' && _this.isColumnRef(value);
1432
- if (!leftIsCol && !leftIsRef && !rightIsCol) {
1591
+ if (!leftIsCol && !leftIsRef && !rightIsCol && !rightSubSelectSql) {
1433
1592
  throw new Error("Potential SQL injection detected: '".concat(column, " ").concat(op, " ").concat(value, "'"));
1434
1593
  }
1435
1594
  _this.validateOperator(op);
@@ -1462,6 +1621,13 @@ var ConditionBuilder = /** @class */ (function (_super) {
1462
1621
  return matchClause;
1463
1622
  }
1464
1623
  if ((op === C6C.IN || op === C6C.NOT_IN) && Array.isArray(value)) {
1624
+ if (rightSubSelectSql) {
1625
+ if (!leftIsRef) {
1626
+ throw new Error("IN operator requires a table reference as the left operand. Column '".concat(column, "' is not a valid table reference."));
1627
+ }
1628
+ var normalized_1 = op.replace('_', ' ');
1629
+ return "( ".concat(column, " ").concat(normalized_1, " ").concat(rightSubSelectSql, " )");
1630
+ }
1465
1631
  var placeholders = value.map(function (v) {
1466
1632
  return _this.isColumnRef(v) ? v : _this.addParam(params, column, v);
1467
1633
  }).join(', ');
@@ -1481,10 +1647,13 @@ var ConditionBuilder = /** @class */ (function (_super) {
1481
1647
  }
1482
1648
  return "(".concat(column, ") ").concat(op.replace('_', ' '), " ").concat(_this.addParam(params, column, start), " AND ").concat(_this.addParam(params, column, end));
1483
1649
  }
1484
- var rightIsRef = _this.isTableReference(value);
1650
+ var rightIsRef = rightSubSelectSql ? false : _this.isTableReference(value);
1485
1651
  if (leftIsRef && rightIsRef) {
1486
1652
  return "(".concat(column, ") ").concat(displayOp, " ").concat(value);
1487
1653
  }
1654
+ if (leftIsRef && rightSubSelectSql) {
1655
+ return "(".concat(column, ") ").concat(displayOp, " ").concat(rightSubSelectSql);
1656
+ }
1488
1657
  if (leftIsRef && !rightIsRef) {
1489
1658
  return "(".concat(column, ") ").concat(displayOp, " ").concat(_this.addParam(params, column, valueNorm));
1490
1659
  }
@@ -1580,85 +1749,117 @@ var JoinBuilder = /** @class */ (function (_super) {
1580
1749
  function JoinBuilder() {
1581
1750
  return _super !== null && _super.apply(this, arguments) || this;
1582
1751
  }
1752
+ JoinBuilder.prototype.createSelectBuilder = function (_request) {
1753
+ throw new Error('Subclasses must implement createSelectBuilder to support derived table serialization.');
1754
+ };
1583
1755
  JoinBuilder.prototype.buildJoinClauses = function (joinArgs, params) {
1584
1756
  var sql = '';
1585
- for (var joinType in joinArgs) {
1757
+ var _loop_1 = function (joinType) {
1586
1758
  var joinKind = joinType.replace('_', ' ').toUpperCase();
1587
- for (var raw in joinArgs[joinType]) {
1588
- var _a = raw.split(' '), table = _a[0], alias = _a[1];
1589
- this.aliasMap[alias || table] = table;
1590
- var onClause = this.buildBooleanJoinedConditions(joinArgs[joinType][raw], true, params);
1591
- var joinSql = alias ? "`".concat(table, "` AS `").concat(alias, "`") : "`".concat(table, "`");
1592
- sql += " ".concat(joinKind, " JOIN ").concat(joinSql, " ON ").concat(onClause);
1759
+ var entries = [];
1760
+ var joinSection = joinArgs[joinType];
1761
+ if (joinSection instanceof Map) {
1762
+ joinSection.forEach(function (value, key) {
1763
+ entries.push([key, value]);
1764
+ });
1765
+ }
1766
+ else {
1767
+ for (var raw in joinSection) {
1768
+ entries.push([raw, joinSection[raw]]);
1769
+ }
1770
+ }
1771
+ for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
1772
+ var _a = entries_1[_i], rawKey = _a[0], conditions = _a[1];
1773
+ var raw = typeof rawKey === 'string' ? rawKey : String(rawKey);
1774
+ var _b = raw.trim().split(/\s+/, 2), table = _b[0], aliasCandidate = _b[1];
1775
+ if (!table)
1776
+ continue;
1777
+ if (isDerivedTableKey(table)) {
1778
+ var derived = resolveDerivedTable(table);
1779
+ if (!derived) {
1780
+ throw new Error("Derived table '".concat(table, "' was not registered. Wrap the object with derivedTable(...) before using it in JOIN."));
1781
+ }
1782
+ var configuredAliasRaw = derived[C6C.AS];
1783
+ var configuredAlias = typeof configuredAliasRaw === 'string' ? configuredAliasRaw.trim() : '';
1784
+ var alias = (aliasCandidate !== null && aliasCandidate !== void 0 ? aliasCandidate : configuredAlias).trim();
1785
+ if (!alias) {
1786
+ throw new Error('Derived tables require an alias via C6C.AS.');
1787
+ }
1788
+ this_1.registerAlias(alias, table);
1789
+ var subRequest = derived[C6C.SUBSELECT];
1790
+ if (!subRequest || typeof subRequest !== 'object') {
1791
+ throw new Error('Derived tables must include a C6C.SUBSELECT payload.');
1792
+ }
1793
+ var fromTable = subRequest[C6C.FROM];
1794
+ if (typeof fromTable !== 'string' || fromTable.trim() === '') {
1795
+ throw new Error('Derived table subselects require a base table defined with C6C.FROM.');
1796
+ }
1797
+ var subBuilder = this_1.createSelectBuilder(subRequest);
1798
+ var _c = subBuilder.build(fromTable, true), subSql = _c.sql, subParams = _c.params;
1799
+ var normalizedSql = this_1.integrateSubSelectParams(subSql, subParams, params);
1800
+ var formatted = normalizedSql.trim().split('\n').map(function (line) { return " ".concat(line); }).join('\n');
1801
+ var joinSql = "(\n".concat(formatted, "\n) AS `").concat(alias, "`");
1802
+ var onClause = this_1.buildBooleanJoinedConditions(conditions, true, params);
1803
+ sql += " ".concat(joinKind, " JOIN ").concat(joinSql);
1804
+ if (onClause) {
1805
+ sql += " ON ".concat(onClause);
1806
+ }
1807
+ }
1808
+ else {
1809
+ var alias = aliasCandidate;
1810
+ if (alias) {
1811
+ this_1.registerAlias(alias, table);
1812
+ }
1813
+ var joinSql = alias ? "`".concat(table, "` AS `").concat(alias, "`") : "`".concat(table, "`");
1814
+ var onClause = this_1.buildBooleanJoinedConditions(conditions, true, params);
1815
+ sql += " ".concat(joinKind, " JOIN ").concat(joinSql);
1816
+ if (onClause) {
1817
+ sql += " ON ".concat(onClause);
1818
+ }
1819
+ }
1593
1820
  }
1821
+ };
1822
+ var this_1 = this;
1823
+ for (var joinType in joinArgs) {
1824
+ _loop_1(joinType);
1594
1825
  }
1595
1826
  this.config.verbose && console.log("[JOIN] ".concat(sql.trim()));
1596
1827
  return sql;
1597
1828
  };
1598
- return JoinBuilder;
1599
- }(ConditionBuilder));
1600
-
1601
- var DeleteQueryBuilder = /** @class */ (function (_super) {
1602
- tslib.__extends(DeleteQueryBuilder, _super);
1603
- function DeleteQueryBuilder() {
1604
- return _super !== null && _super.apply(this, arguments) || this;
1605
- }
1606
- DeleteQueryBuilder.prototype.build = function (table) {
1607
- this.aliasMap = {};
1608
- var params = this.useNamedParams ? {} : [];
1609
- this.initAlias(table, this.request.JOIN);
1610
- var sql = "DELETE `".concat(table, "` FROM `").concat(table, "`");
1611
- if (this.request.JOIN) {
1612
- sql += this.buildJoinClauses(this.request.JOIN, params);
1613
- }
1614
- if (this.request.WHERE) {
1615
- sql += this.buildWhereClause(this.request.WHERE, params);
1616
- }
1617
- return { sql: sql, params: params };
1618
- };
1619
- return DeleteQueryBuilder;
1620
- }(JoinBuilder));
1621
-
1622
- var PostQueryBuilder = /** @class */ (function (_super) {
1623
- tslib.__extends(PostQueryBuilder, _super);
1624
- function PostQueryBuilder() {
1625
- return _super !== null && _super.apply(this, arguments) || this;
1626
- }
1627
- PostQueryBuilder.prototype.trimTablePrefix = function (table, column) {
1628
- if (!column.includes('.'))
1629
- return column;
1630
- var _a = column.split('.', 2), prefix = _a[0], col = _a[1];
1631
- if (prefix !== table) {
1632
- throw new Error("Invalid prefixed column: '".concat(column, "'. Expected prefix '").concat(table, ".'"));
1829
+ JoinBuilder.prototype.integrateSubSelectParams = function (subSql, subParams, target) {
1830
+ var _a;
1831
+ if (!subParams)
1832
+ return subSql;
1833
+ if (this.useNamedParams) {
1834
+ var normalized = subSql;
1835
+ var extras = subParams;
1836
+ for (var _i = 0, _b = Object.keys(extras); _i < _b.length; _i++) {
1837
+ var key = _b[_i];
1838
+ var placeholder = this.addParam(target, '', extras[key]);
1839
+ var original = ":".concat(key);
1840
+ if (original !== placeholder) {
1841
+ normalized = normalized.split(original).join(placeholder);
1842
+ }
1843
+ }
1844
+ return normalized;
1633
1845
  }
1634
- return col;
1846
+ (_a = target).push.apply(_a, subParams);
1847
+ return subSql;
1635
1848
  };
1636
- PostQueryBuilder.prototype.build = function (table) {
1637
- var _this = this;
1638
- this.aliasMap = {};
1639
- var verb = C6C.REPLACE in this.request ? C6C.REPLACE : C6C.INSERT;
1640
- var body = verb in this.request ? this.request[verb] : this.request;
1641
- var keys = Object.keys(body);
1642
- var params = [];
1643
- var placeholders = [];
1644
- for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
1645
- var key = keys_1[_i];
1646
- var value = body[key];
1647
- var placeholder = this.addParam(params, key, value);
1648
- placeholders.push(placeholder);
1849
+ JoinBuilder.prototype.buildScalarSubSelect = function (subRequest, params) {
1850
+ if (!subRequest || typeof subRequest !== 'object') {
1851
+ throw new Error('Scalar subselect requires a C6C.SUBSELECT object payload.');
1649
1852
  }
1650
- var sql = "".concat(verb, " INTO `").concat(table, "` (\n ").concat(keys.map(function (k) { return "`".concat(_this.trimTablePrefix(table, k), "`"); }).join(', '), "\n ) VALUES (\n ").concat(placeholders.join(', '), "\n )");
1651
- if (C6C.UPDATE in this.request) {
1652
- var updateData = this.request[C6C.UPDATE];
1653
- if (!Array.isArray(updateData)) {
1654
- throw new Error("Update data must be an array of keys to update, got: ".concat(JSON.stringify(updateData)));
1655
- }
1656
- var updateClause = updateData.map(function (k) { return "`".concat(k, "` = VALUES(`").concat(k, "`)"); }).join(', ');
1657
- sql += " ON DUPLICATE KEY UPDATE ".concat(updateClause);
1853
+ var fromTable = subRequest[C6C.FROM];
1854
+ if (typeof fromTable !== 'string' || fromTable.trim() === '') {
1855
+ throw new Error('Scalar subselects require a base table specified with C6C.FROM.');
1658
1856
  }
1659
- return { sql: sql, params: params };
1857
+ var subBuilder = this.createSelectBuilder(subRequest);
1858
+ var _a = subBuilder.build(fromTable, true), subSql = _a.sql, subParams = _a.params;
1859
+ var normalized = this.integrateSubSelectParams(subSql, subParams, params).trim();
1860
+ return "(".concat(normalized, ")");
1660
1861
  };
1661
- return PostQueryBuilder;
1862
+ return JoinBuilder;
1662
1863
  }(ConditionBuilder));
1663
1864
 
1664
1865
  var PaginationBuilder = /** @class */ (function (_super) {
@@ -1679,7 +1880,7 @@ var PaginationBuilder = /** @class */ (function (_super) {
1679
1880
  * }
1680
1881
  * ```
1681
1882
  */
1682
- PaginationBuilder.prototype.buildPaginationClause = function (pagination) {
1883
+ PaginationBuilder.prototype.buildPaginationClause = function (pagination, params) {
1683
1884
  var _this = this;
1684
1885
  var sql = "";
1685
1886
  /* -------- ORDER BY -------- */
@@ -1687,10 +1888,21 @@ var PaginationBuilder = /** @class */ (function (_super) {
1687
1888
  var orderParts = [];
1688
1889
  for (var _i = 0, _a = Object.entries(pagination[C6Constants.ORDER]); _i < _a.length; _i++) {
1689
1890
  var _b = _a[_i], key = _b[0], val = _b[1];
1891
+ if (typeof key === 'string' && key.includes('.')) {
1892
+ this.assertValidIdentifier(key, 'ORDER BY');
1893
+ }
1690
1894
  // FUNCTION CALL: val is an array of args
1691
1895
  if (Array.isArray(val)) {
1692
1896
  var args = val
1693
- .map(function (arg) { return Array.isArray(arg) ? _this.buildAggregateField(arg) : String(arg); })
1897
+ .map(function (arg) {
1898
+ if (Array.isArray(arg))
1899
+ return _this.buildAggregateField(arg, params);
1900
+ if (typeof arg === 'string' && arg.includes('.')) {
1901
+ _this.assertValidIdentifier(arg, 'ORDER BY argument');
1902
+ return arg;
1903
+ }
1904
+ return String(arg);
1905
+ })
1694
1906
  .join(", ");
1695
1907
  orderParts.push("".concat(key, "(").concat(args, ")"));
1696
1908
  }
@@ -1727,6 +1939,9 @@ var SelectQueryBuilder = /** @class */ (function (_super) {
1727
1939
  function SelectQueryBuilder() {
1728
1940
  return _super !== null && _super.apply(this, arguments) || this;
1729
1941
  }
1942
+ SelectQueryBuilder.prototype.createSelectBuilder = function (request) {
1943
+ return new SelectQueryBuilder(this.config, request, this.useNamedParams);
1944
+ };
1730
1945
  SelectQueryBuilder.prototype.build = function (table, isSubSelect) {
1731
1946
  var _this = this;
1732
1947
  var _a;
@@ -1741,7 +1956,7 @@ var SelectQueryBuilder = /** @class */ (function (_super) {
1741
1956
  var params = this.useNamedParams ? {} : [];
1742
1957
  var selectList = (_a = args.SELECT) !== null && _a !== void 0 ? _a : ['*'];
1743
1958
  var selectFields = selectList
1744
- .map(function (f) { return _this.buildAggregateField(f); })
1959
+ .map(function (f) { return _this.buildAggregateField(f, params); })
1745
1960
  .join(', ');
1746
1961
  var sql = "SELECT ".concat(selectFields, " FROM `").concat(table, "`");
1747
1962
  if (args.JOIN) {
@@ -1760,7 +1975,7 @@ var SelectQueryBuilder = /** @class */ (function (_super) {
1760
1975
  sql += " HAVING ".concat(this.buildBooleanJoinedConditions(args.HAVING, true, params));
1761
1976
  }
1762
1977
  if (args.PAGINATION) {
1763
- sql += this.buildPaginationClause(args.PAGINATION);
1978
+ sql += this.buildPaginationClause(args.PAGINATION, params);
1764
1979
  }
1765
1980
  else if (!isSubSelect) {
1766
1981
  sql += " LIMIT 100";
@@ -1771,11 +1986,80 @@ var SelectQueryBuilder = /** @class */ (function (_super) {
1771
1986
  return SelectQueryBuilder;
1772
1987
  }(PaginationBuilder));
1773
1988
 
1989
+ var DeleteQueryBuilder = /** @class */ (function (_super) {
1990
+ tslib.__extends(DeleteQueryBuilder, _super);
1991
+ function DeleteQueryBuilder() {
1992
+ return _super !== null && _super.apply(this, arguments) || this;
1993
+ }
1994
+ DeleteQueryBuilder.prototype.createSelectBuilder = function (request) {
1995
+ return new SelectQueryBuilder(this.config, request, this.useNamedParams);
1996
+ };
1997
+ DeleteQueryBuilder.prototype.build = function (table) {
1998
+ this.aliasMap = {};
1999
+ var params = this.useNamedParams ? {} : [];
2000
+ this.initAlias(table, this.request.JOIN);
2001
+ var sql = "DELETE `".concat(table, "` FROM `").concat(table, "`");
2002
+ if (this.request.JOIN) {
2003
+ sql += this.buildJoinClauses(this.request.JOIN, params);
2004
+ }
2005
+ if (this.request.WHERE) {
2006
+ sql += this.buildWhereClause(this.request.WHERE, params);
2007
+ }
2008
+ return { sql: sql, params: params };
2009
+ };
2010
+ return DeleteQueryBuilder;
2011
+ }(JoinBuilder));
2012
+
2013
+ var PostQueryBuilder = /** @class */ (function (_super) {
2014
+ tslib.__extends(PostQueryBuilder, _super);
2015
+ function PostQueryBuilder() {
2016
+ return _super !== null && _super.apply(this, arguments) || this;
2017
+ }
2018
+ PostQueryBuilder.prototype.trimTablePrefix = function (table, column) {
2019
+ if (!column.includes('.'))
2020
+ return column;
2021
+ var _a = column.split('.', 2), prefix = _a[0], col = _a[1];
2022
+ if (prefix !== table) {
2023
+ throw new Error("Invalid prefixed column: '".concat(column, "'. Expected prefix '").concat(table, ".'"));
2024
+ }
2025
+ return col;
2026
+ };
2027
+ PostQueryBuilder.prototype.build = function (table) {
2028
+ var _this = this;
2029
+ this.aliasMap = {};
2030
+ var verb = C6C.REPLACE in this.request ? C6C.REPLACE : C6C.INSERT;
2031
+ var body = verb in this.request ? this.request[verb] : this.request;
2032
+ var keys = Object.keys(body);
2033
+ var params = [];
2034
+ var placeholders = [];
2035
+ for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
2036
+ var key = keys_1[_i];
2037
+ var value = body[key];
2038
+ var placeholder = this.addParam(params, key, value);
2039
+ placeholders.push(placeholder);
2040
+ }
2041
+ var sql = "".concat(verb, " INTO `").concat(table, "` (\n ").concat(keys.map(function (k) { return "`".concat(_this.trimTablePrefix(table, k), "`"); }).join(', '), "\n ) VALUES (\n ").concat(placeholders.join(', '), "\n )");
2042
+ if (C6C.UPDATE in this.request) {
2043
+ var updateData = this.request[C6C.UPDATE];
2044
+ if (!Array.isArray(updateData)) {
2045
+ throw new Error("Update data must be an array of keys to update, got: ".concat(JSON.stringify(updateData)));
2046
+ }
2047
+ var updateClause = updateData.map(function (k) { return "`".concat(k, "` = VALUES(`").concat(k, "`)"); }).join(', ');
2048
+ sql += " ON DUPLICATE KEY UPDATE ".concat(updateClause);
2049
+ }
2050
+ return { sql: sql, params: params };
2051
+ };
2052
+ return PostQueryBuilder;
2053
+ }(ConditionBuilder));
2054
+
1774
2055
  var UpdateQueryBuilder = /** @class */ (function (_super) {
1775
2056
  tslib.__extends(UpdateQueryBuilder, _super);
1776
2057
  function UpdateQueryBuilder() {
1777
2058
  return _super !== null && _super.apply(this, arguments) || this;
1778
2059
  }
2060
+ UpdateQueryBuilder.prototype.createSelectBuilder = function (request) {
2061
+ return new SelectQueryBuilder(this.config, request, this.useNamedParams);
2062
+ };
1779
2063
  UpdateQueryBuilder.prototype.trimTablePrefix = function (table, column) {
1780
2064
  if (!column.includes('.'))
1781
2065
  return column;
@@ -1810,7 +2094,7 @@ var UpdateQueryBuilder = /** @class */ (function (_super) {
1810
2094
  sql += this.buildWhereClause(args.WHERE, params);
1811
2095
  }
1812
2096
  if (args.PAGINATION) {
1813
- sql += this.buildPaginationClause(args.PAGINATION);
2097
+ sql += this.buildPaginationClause(args.PAGINATION, params);
1814
2098
  }
1815
2099
  return { sql: sql, params: params };
1816
2100
  };
@@ -2206,41 +2490,6 @@ function ExpressHandler(_a) {
2206
2490
  }); };
2207
2491
  }
2208
2492
 
2209
- // Alias a table name with a given alias
2210
- var A = function (tableName, alias) {
2211
- return "".concat(tableName, " ").concat(alias);
2212
- };
2213
- // Qualify a column constant (e.g. 'property_units.parcel_id') to an alias
2214
- var F = function (qualifiedCol, alias) {
2215
- return "".concat(alias, ".").concat(qualifiedCol.split('.').pop());
2216
- };
2217
- // Equal join condition using full-qualified column constants
2218
- var fieldEq = function (leftCol, rightCol, leftAlias, rightAlias) {
2219
- var _a;
2220
- return (_a = {},
2221
- _a[F(leftCol, leftAlias)] = F(rightCol, rightAlias),
2222
- _a);
2223
- };
2224
- // ST_Distance_Sphere for aliased fields
2225
- var distSphere = function (fromCol, toCol, fromAlias, toAlias) {
2226
- return [C6C.ST_DISTANCE_SPHERE, F(fromCol, fromAlias), F(toCol, toAlias)];
2227
- };
2228
- // Build a bounding-box expression.
2229
- //
2230
- // Arguments must be provided in `(minLng, minLat, maxLng, maxLat)` order. The
2231
- // helper does not attempt to swap or validate coordinates; if a minimum value
2232
- // is greater than its corresponding maximum value, MySQL's `ST_MakeEnvelope`
2233
- // returns `NULL`.
2234
- var bbox = function (minLng, minLat, maxLng, maxLat) {
2235
- return [C6C.ST_SRID, [C6C.ST_MAKEENVELOPE,
2236
- [C6C.ST_POINT, minLng, minLat],
2237
- [C6C.ST_POINT, maxLng, maxLat]], 4326];
2238
- };
2239
- // ST_Contains for map envelope/shape queries
2240
- var stContains = function (envelope, shape) {
2241
- return [C6C.ST_CONTAINS, envelope, shape];
2242
- };
2243
-
2244
2493
  function determineRuntimeJsType(mysqlType) {
2245
2494
  var base = mysqlType.toLowerCase().split('(')[0];
2246
2495
  if ([
@@ -2369,6 +2618,7 @@ exports.checkCache = checkCache;
2369
2618
  exports.clearCache = clearCache;
2370
2619
  exports.convertForRequestBody = convertForRequestBody;
2371
2620
  exports.convertHexIfBinary = convertHexIfBinary;
2621
+ exports.derivedTable = derivedTable;
2372
2622
  exports.determineRuntimeJsType = determineRuntimeJsType;
2373
2623
  exports.distSphere = distSphere;
2374
2624
  exports.error = error;
@@ -2377,6 +2627,7 @@ exports.getEnvVar = getEnvVar;
2377
2627
  exports.getPrimaryKeyTypes = getPrimaryKeyTypes;
2378
2628
  exports.group = group;
2379
2629
  exports.info = info;
2630
+ exports.isDerivedTableKey = isDerivedTableKey;
2380
2631
  exports.isLocal = isLocal;
2381
2632
  exports.isNode = isNode;
2382
2633
  exports.isTest = isTest;
@@ -2386,6 +2637,7 @@ exports.onError = onError;
2386
2637
  exports.onSuccess = onSuccess;
2387
2638
  exports.removeInvalidKeys = removeInvalidKeys;
2388
2639
  exports.removePrefixIfExists = removePrefixIfExists;
2640
+ exports.resolveDerivedTable = resolveDerivedTable;
2389
2641
  exports.restOrm = restOrm;
2390
2642
  exports.restRequest = restRequest;
2391
2643
  exports.sortAndSerializeQueryObject = sortAndSerializeQueryObject;