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