@carbonorm/carbonnode 3.8.3 → 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;
@@ -1400,6 +1539,29 @@ var ConditionBuilder = /** @class */ (function (_super) {
1400
1539
  if (params === void 0) { params = []; }
1401
1540
  var booleanOperator = andMode ? 'AND' : 'OR';
1402
1541
  var addCondition = function (column, op, value) {
1542
+ // Normalize common variants
1543
+ var valueNorm = (value === C6C.NULL) ? null : value;
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);
1403
1565
  // Support function-based expressions like [C6C.ST_DISTANCE_SPHERE, col1, col2]
1404
1566
  if (typeof column === 'string' &&
1405
1567
  _this.OPERATORS.has(column) &&
@@ -1426,7 +1588,7 @@ var ConditionBuilder = /** @class */ (function (_super) {
1426
1588
  var leftIsCol = _this.isColumnRef(column);
1427
1589
  var leftIsRef = _this.isTableReference(column);
1428
1590
  var rightIsCol = typeof value === 'string' && _this.isColumnRef(value);
1429
- if (!leftIsCol && !leftIsRef && !rightIsCol) {
1591
+ if (!leftIsCol && !leftIsRef && !rightIsCol && !rightSubSelectSql) {
1430
1592
  throw new Error("Potential SQL injection detected: '".concat(column, " ").concat(op, " ").concat(value, "'"));
1431
1593
  }
1432
1594
  _this.validateOperator(op);
@@ -1459,6 +1621,13 @@ var ConditionBuilder = /** @class */ (function (_super) {
1459
1621
  return matchClause;
1460
1622
  }
1461
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
+ }
1462
1631
  var placeholders = value.map(function (v) {
1463
1632
  return _this.isColumnRef(v) ? v : _this.addParam(params, column, v);
1464
1633
  }).join(', ');
@@ -1478,15 +1647,18 @@ var ConditionBuilder = /** @class */ (function (_super) {
1478
1647
  }
1479
1648
  return "(".concat(column, ") ").concat(op.replace('_', ' '), " ").concat(_this.addParam(params, column, start), " AND ").concat(_this.addParam(params, column, end));
1480
1649
  }
1481
- var rightIsRef = _this.isTableReference(value);
1650
+ var rightIsRef = rightSubSelectSql ? false : _this.isTableReference(value);
1482
1651
  if (leftIsRef && rightIsRef) {
1483
- return "(".concat(column, ") ").concat(op, " ").concat(value);
1652
+ return "(".concat(column, ") ").concat(displayOp, " ").concat(value);
1653
+ }
1654
+ if (leftIsRef && rightSubSelectSql) {
1655
+ return "(".concat(column, ") ").concat(displayOp, " ").concat(rightSubSelectSql);
1484
1656
  }
1485
1657
  if (leftIsRef && !rightIsRef) {
1486
- return "(".concat(column, ") ").concat(op, " ").concat(_this.addParam(params, column, value));
1658
+ return "(".concat(column, ") ").concat(displayOp, " ").concat(_this.addParam(params, column, valueNorm));
1487
1659
  }
1488
1660
  if (rightIsRef) {
1489
- return "(".concat(_this.addParam(params, column, column), ") ").concat(op, " ").concat(value);
1661
+ return "(".concat(_this.addParam(params, column, column), ") ").concat(displayOp, " ").concat(value);
1490
1662
  }
1491
1663
  throw new Error("Neither operand appears to be a table reference (".concat(column, ") or (").concat(value, ")"));
1492
1664
  };
@@ -1535,12 +1707,23 @@ var ConditionBuilder = /** @class */ (function (_super) {
1535
1707
  return subParts.join(" ".concat(mode ? 'AND' : 'OR', " "));
1536
1708
  };
1537
1709
  if (Array.isArray(set)) {
1538
- for (var _i = 0, set_1 = set; _i < set_1.length; _i++) {
1539
- var item = set_1[_i];
1540
- var sub = this.buildBooleanJoinedConditions(item, false, params);
1710
+ // Detect a single condition triple: [column, op, value]
1711
+ if (set.length === 3 && typeof set[0] === 'string' && typeof set[1] === 'string') {
1712
+ var _a = set, column = _a[0], rawOp = _a[1], rawVal = _a[2];
1713
+ var op = rawOp;
1714
+ var value = rawVal === C6C.NULL ? null : rawVal;
1715
+ var sub = addCondition(column, op, value);
1541
1716
  if (sub)
1542
1717
  parts.push(sub);
1543
1718
  }
1719
+ else {
1720
+ for (var _i = 0, set_1 = set; _i < set_1.length; _i++) {
1721
+ var item = set_1[_i];
1722
+ var sub = this.buildBooleanJoinedConditions(item, false, params);
1723
+ if (sub)
1724
+ parts.push(sub);
1725
+ }
1726
+ }
1544
1727
  }
1545
1728
  else if (typeof set === 'object' && set !== null) {
1546
1729
  var sub = buildFromObject(set, andMode);
@@ -1566,85 +1749,117 @@ var JoinBuilder = /** @class */ (function (_super) {
1566
1749
  function JoinBuilder() {
1567
1750
  return _super !== null && _super.apply(this, arguments) || this;
1568
1751
  }
1752
+ JoinBuilder.prototype.createSelectBuilder = function (_request) {
1753
+ throw new Error('Subclasses must implement createSelectBuilder to support derived table serialization.');
1754
+ };
1569
1755
  JoinBuilder.prototype.buildJoinClauses = function (joinArgs, params) {
1570
1756
  var sql = '';
1571
- for (var joinType in joinArgs) {
1757
+ var _loop_1 = function (joinType) {
1572
1758
  var joinKind = joinType.replace('_', ' ').toUpperCase();
1573
- for (var raw in joinArgs[joinType]) {
1574
- var _a = raw.split(' '), table = _a[0], alias = _a[1];
1575
- this.aliasMap[alias || table] = table;
1576
- var onClause = this.buildBooleanJoinedConditions(joinArgs[joinType][raw], true, params);
1577
- var joinSql = alias ? "`".concat(table, "` AS `").concat(alias, "`") : "`".concat(table, "`");
1578
- 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
+ }
1579
1820
  }
1821
+ };
1822
+ var this_1 = this;
1823
+ for (var joinType in joinArgs) {
1824
+ _loop_1(joinType);
1580
1825
  }
1581
1826
  this.config.verbose && console.log("[JOIN] ".concat(sql.trim()));
1582
1827
  return sql;
1583
1828
  };
1584
- return JoinBuilder;
1585
- }(ConditionBuilder));
1586
-
1587
- var DeleteQueryBuilder = /** @class */ (function (_super) {
1588
- tslib.__extends(DeleteQueryBuilder, _super);
1589
- function DeleteQueryBuilder() {
1590
- return _super !== null && _super.apply(this, arguments) || this;
1591
- }
1592
- DeleteQueryBuilder.prototype.build = function (table) {
1593
- this.aliasMap = {};
1594
- var params = this.useNamedParams ? {} : [];
1595
- this.initAlias(table, this.request.JOIN);
1596
- var sql = "DELETE `".concat(table, "` FROM `").concat(table, "`");
1597
- if (this.request.JOIN) {
1598
- sql += this.buildJoinClauses(this.request.JOIN, params);
1599
- }
1600
- if (this.request.WHERE) {
1601
- sql += this.buildWhereClause(this.request.WHERE, params);
1602
- }
1603
- return { sql: sql, params: params };
1604
- };
1605
- return DeleteQueryBuilder;
1606
- }(JoinBuilder));
1607
-
1608
- var PostQueryBuilder = /** @class */ (function (_super) {
1609
- tslib.__extends(PostQueryBuilder, _super);
1610
- function PostQueryBuilder() {
1611
- return _super !== null && _super.apply(this, arguments) || this;
1612
- }
1613
- PostQueryBuilder.prototype.trimTablePrefix = function (table, column) {
1614
- if (!column.includes('.'))
1615
- return column;
1616
- var _a = column.split('.', 2), prefix = _a[0], col = _a[1];
1617
- if (prefix !== table) {
1618
- 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;
1619
1845
  }
1620
- return col;
1846
+ (_a = target).push.apply(_a, subParams);
1847
+ return subSql;
1621
1848
  };
1622
- PostQueryBuilder.prototype.build = function (table) {
1623
- var _this = this;
1624
- this.aliasMap = {};
1625
- var verb = C6C.REPLACE in this.request ? C6C.REPLACE : C6C.INSERT;
1626
- var body = verb in this.request ? this.request[verb] : this.request;
1627
- var keys = Object.keys(body);
1628
- var params = [];
1629
- var placeholders = [];
1630
- for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
1631
- var key = keys_1[_i];
1632
- var value = body[key];
1633
- var placeholder = this.addParam(params, key, value);
1634
- 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.');
1635
1852
  }
1636
- 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 )");
1637
- if (C6C.UPDATE in this.request) {
1638
- var updateData = this.request[C6C.UPDATE];
1639
- if (!Array.isArray(updateData)) {
1640
- throw new Error("Update data must be an array of keys to update, got: ".concat(JSON.stringify(updateData)));
1641
- }
1642
- var updateClause = updateData.map(function (k) { return "`".concat(k, "` = VALUES(`").concat(k, "`)"); }).join(', ');
1643
- 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.');
1644
1856
  }
1645
- 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, ")");
1646
1861
  };
1647
- return PostQueryBuilder;
1862
+ return JoinBuilder;
1648
1863
  }(ConditionBuilder));
1649
1864
 
1650
1865
  var PaginationBuilder = /** @class */ (function (_super) {
@@ -1665,7 +1880,7 @@ var PaginationBuilder = /** @class */ (function (_super) {
1665
1880
  * }
1666
1881
  * ```
1667
1882
  */
1668
- PaginationBuilder.prototype.buildPaginationClause = function (pagination) {
1883
+ PaginationBuilder.prototype.buildPaginationClause = function (pagination, params) {
1669
1884
  var _this = this;
1670
1885
  var sql = "";
1671
1886
  /* -------- ORDER BY -------- */
@@ -1673,10 +1888,21 @@ var PaginationBuilder = /** @class */ (function (_super) {
1673
1888
  var orderParts = [];
1674
1889
  for (var _i = 0, _a = Object.entries(pagination[C6Constants.ORDER]); _i < _a.length; _i++) {
1675
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
+ }
1676
1894
  // FUNCTION CALL: val is an array of args
1677
1895
  if (Array.isArray(val)) {
1678
1896
  var args = val
1679
- .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
+ })
1680
1906
  .join(", ");
1681
1907
  orderParts.push("".concat(key, "(").concat(args, ")"));
1682
1908
  }
@@ -1713,6 +1939,9 @@ var SelectQueryBuilder = /** @class */ (function (_super) {
1713
1939
  function SelectQueryBuilder() {
1714
1940
  return _super !== null && _super.apply(this, arguments) || this;
1715
1941
  }
1942
+ SelectQueryBuilder.prototype.createSelectBuilder = function (request) {
1943
+ return new SelectQueryBuilder(this.config, request, this.useNamedParams);
1944
+ };
1716
1945
  SelectQueryBuilder.prototype.build = function (table, isSubSelect) {
1717
1946
  var _this = this;
1718
1947
  var _a;
@@ -1727,7 +1956,7 @@ var SelectQueryBuilder = /** @class */ (function (_super) {
1727
1956
  var params = this.useNamedParams ? {} : [];
1728
1957
  var selectList = (_a = args.SELECT) !== null && _a !== void 0 ? _a : ['*'];
1729
1958
  var selectFields = selectList
1730
- .map(function (f) { return _this.buildAggregateField(f); })
1959
+ .map(function (f) { return _this.buildAggregateField(f, params); })
1731
1960
  .join(', ');
1732
1961
  var sql = "SELECT ".concat(selectFields, " FROM `").concat(table, "`");
1733
1962
  if (args.JOIN) {
@@ -1746,7 +1975,7 @@ var SelectQueryBuilder = /** @class */ (function (_super) {
1746
1975
  sql += " HAVING ".concat(this.buildBooleanJoinedConditions(args.HAVING, true, params));
1747
1976
  }
1748
1977
  if (args.PAGINATION) {
1749
- sql += this.buildPaginationClause(args.PAGINATION);
1978
+ sql += this.buildPaginationClause(args.PAGINATION, params);
1750
1979
  }
1751
1980
  else if (!isSubSelect) {
1752
1981
  sql += " LIMIT 100";
@@ -1757,11 +1986,80 @@ var SelectQueryBuilder = /** @class */ (function (_super) {
1757
1986
  return SelectQueryBuilder;
1758
1987
  }(PaginationBuilder));
1759
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
+
1760
2055
  var UpdateQueryBuilder = /** @class */ (function (_super) {
1761
2056
  tslib.__extends(UpdateQueryBuilder, _super);
1762
2057
  function UpdateQueryBuilder() {
1763
2058
  return _super !== null && _super.apply(this, arguments) || this;
1764
2059
  }
2060
+ UpdateQueryBuilder.prototype.createSelectBuilder = function (request) {
2061
+ return new SelectQueryBuilder(this.config, request, this.useNamedParams);
2062
+ };
1765
2063
  UpdateQueryBuilder.prototype.trimTablePrefix = function (table, column) {
1766
2064
  if (!column.includes('.'))
1767
2065
  return column;
@@ -1796,7 +2094,7 @@ var UpdateQueryBuilder = /** @class */ (function (_super) {
1796
2094
  sql += this.buildWhereClause(args.WHERE, params);
1797
2095
  }
1798
2096
  if (args.PAGINATION) {
1799
- sql += this.buildPaginationClause(args.PAGINATION);
2097
+ sql += this.buildPaginationClause(args.PAGINATION, params);
1800
2098
  }
1801
2099
  return { sql: sql, params: params };
1802
2100
  };
@@ -2192,41 +2490,6 @@ function ExpressHandler(_a) {
2192
2490
  }); };
2193
2491
  }
2194
2492
 
2195
- // Alias a table name with a given alias
2196
- var A = function (tableName, alias) {
2197
- return "".concat(tableName, " ").concat(alias);
2198
- };
2199
- // Qualify a column constant (e.g. 'property_units.parcel_id') to an alias
2200
- var F = function (qualifiedCol, alias) {
2201
- return "".concat(alias, ".").concat(qualifiedCol.split('.').pop());
2202
- };
2203
- // Equal join condition using full-qualified column constants
2204
- var fieldEq = function (leftCol, rightCol, leftAlias, rightAlias) {
2205
- var _a;
2206
- return (_a = {},
2207
- _a[F(leftCol, leftAlias)] = F(rightCol, rightAlias),
2208
- _a);
2209
- };
2210
- // ST_Distance_Sphere for aliased fields
2211
- var distSphere = function (fromCol, toCol, fromAlias, toAlias) {
2212
- return [C6C.ST_DISTANCE_SPHERE, F(fromCol, fromAlias), F(toCol, toAlias)];
2213
- };
2214
- // Build a bounding-box expression.
2215
- //
2216
- // Arguments must be provided in `(minLng, minLat, maxLng, maxLat)` order. The
2217
- // helper does not attempt to swap or validate coordinates; if a minimum value
2218
- // is greater than its corresponding maximum value, MySQL's `ST_MakeEnvelope`
2219
- // returns `NULL`.
2220
- var bbox = function (minLng, minLat, maxLng, maxLat) {
2221
- return [C6C.ST_SRID, [C6C.ST_MAKEENVELOPE,
2222
- [C6C.ST_POINT, minLng, minLat],
2223
- [C6C.ST_POINT, maxLng, maxLat]], 4326];
2224
- };
2225
- // ST_Contains for map envelope/shape queries
2226
- var stContains = function (envelope, shape) {
2227
- return [C6C.ST_CONTAINS, envelope, shape];
2228
- };
2229
-
2230
2493
  function determineRuntimeJsType(mysqlType) {
2231
2494
  var base = mysqlType.toLowerCase().split('(')[0];
2232
2495
  if ([
@@ -2355,6 +2618,7 @@ exports.checkCache = checkCache;
2355
2618
  exports.clearCache = clearCache;
2356
2619
  exports.convertForRequestBody = convertForRequestBody;
2357
2620
  exports.convertHexIfBinary = convertHexIfBinary;
2621
+ exports.derivedTable = derivedTable;
2358
2622
  exports.determineRuntimeJsType = determineRuntimeJsType;
2359
2623
  exports.distSphere = distSphere;
2360
2624
  exports.error = error;
@@ -2363,6 +2627,7 @@ exports.getEnvVar = getEnvVar;
2363
2627
  exports.getPrimaryKeyTypes = getPrimaryKeyTypes;
2364
2628
  exports.group = group;
2365
2629
  exports.info = info;
2630
+ exports.isDerivedTableKey = isDerivedTableKey;
2366
2631
  exports.isLocal = isLocal;
2367
2632
  exports.isNode = isNode;
2368
2633
  exports.isTest = isTest;
@@ -2372,6 +2637,7 @@ exports.onError = onError;
2372
2637
  exports.onSuccess = onSuccess;
2373
2638
  exports.removeInvalidKeys = removeInvalidKeys;
2374
2639
  exports.removePrefixIfExists = removePrefixIfExists;
2640
+ exports.resolveDerivedTable = resolveDerivedTable;
2375
2641
  exports.restOrm = restOrm;
2376
2642
  exports.restRequest = restRequest;
2377
2643
  exports.sortAndSerializeQueryObject = sortAndSerializeQueryObject;