@carbonorm/carbonnode 6.0.20 → 6.1.1

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.
Files changed (90) hide show
  1. package/README.md +521 -259
  2. package/dist/constants/C6Constants.d.ts +342 -338
  3. package/dist/executors/SqlExecutor.d.ts +1 -0
  4. package/dist/index.cjs.js +746 -290
  5. package/dist/index.cjs.js.map +1 -1
  6. package/dist/index.d.ts +1 -0
  7. package/dist/index.esm.js +737 -291
  8. package/dist/index.esm.js.map +1 -1
  9. package/dist/orm/builders/AggregateBuilder.d.ts +5 -1
  10. package/dist/orm/builders/ConditionBuilder.d.ts +2 -3
  11. package/dist/orm/builders/ExpressionSerializer.d.ts +22 -0
  12. package/dist/orm/builders/PaginationBuilder.d.ts +4 -6
  13. package/dist/orm/queryHelpers.d.ts +12 -1
  14. package/dist/orm/utils/sqlUtils.d.ts +1 -0
  15. package/dist/types/mysqlTypes.d.ts +6 -1
  16. package/dist/types/ormInterfaces.d.ts +7 -5
  17. package/dist/utils/sqlAllowList.d.ts +5 -3
  18. package/package.json +2 -2
  19. package/scripts/assets/handlebars/C6.test.ts.handlebars +4 -4
  20. package/src/__tests__/expressServer.e2e.test.ts +26 -17
  21. package/src/__tests__/fixtures/c6.fixture.ts +33 -0
  22. package/src/__tests__/httpExecutorSingular.e2e.test.ts +53 -14
  23. package/src/__tests__/normalizeSingularRequest.test.ts +26 -8
  24. package/src/__tests__/sakila-db/C6.js +1 -1
  25. package/src/__tests__/sakila-db/C6.mysqldump.json +1 -1
  26. package/src/__tests__/sakila-db/C6.mysqldump.sql +1 -1
  27. package/src/__tests__/sakila-db/C6.sqlAllowList.json +1 -1
  28. package/src/__tests__/sakila-db/C6.test.ts +4 -4
  29. package/src/__tests__/sakila-db/C6.ts +1 -1
  30. package/src/__tests__/sakila-db/sqlResponses/C6.actor.post.json +6 -6
  31. package/src/__tests__/sakila-db/sqlResponses/C6.actor.post.latest.json +3 -3
  32. package/src/__tests__/sakila-db/sqlResponses/C6.actor.put.json +1 -1
  33. package/src/__tests__/sakila-db/sqlResponses/C6.actor.put.lookup.json +3 -3
  34. package/src/__tests__/sakila-db/sqlResponses/C6.address.post.json +19 -12
  35. package/src/__tests__/sakila-db/sqlResponses/C6.address.post.latest.json +5 -5
  36. package/src/__tests__/sakila-db/sqlResponses/C6.address.put.json +1 -1
  37. package/src/__tests__/sakila-db/sqlResponses/C6.address.put.lookup.json +5 -5
  38. package/src/__tests__/sakila-db/sqlResponses/C6.category.post.json +4 -4
  39. package/src/__tests__/sakila-db/sqlResponses/C6.category.post.latest.json +2 -2
  40. package/src/__tests__/sakila-db/sqlResponses/C6.category.put.json +1 -1
  41. package/src/__tests__/sakila-db/sqlResponses/C6.category.put.lookup.json +2 -2
  42. package/src/__tests__/sakila-db/sqlResponses/C6.city.post.json +4 -4
  43. package/src/__tests__/sakila-db/sqlResponses/C6.city.post.latest.json +2 -2
  44. package/src/__tests__/sakila-db/sqlResponses/C6.city.put.json +1 -1
  45. package/src/__tests__/sakila-db/sqlResponses/C6.city.put.lookup.json +2 -2
  46. package/src/__tests__/sakila-db/sqlResponses/C6.country.post.json +4 -4
  47. package/src/__tests__/sakila-db/sqlResponses/C6.country.post.latest.json +2 -2
  48. package/src/__tests__/sakila-db/sqlResponses/C6.country.put.json +1 -1
  49. package/src/__tests__/sakila-db/sqlResponses/C6.country.put.lookup.json +2 -2
  50. package/src/__tests__/sakila-db/sqlResponses/C6.customer.post.json +10 -10
  51. package/src/__tests__/sakila-db/sqlResponses/C6.customer.post.latest.json +5 -5
  52. package/src/__tests__/sakila-db/sqlResponses/C6.customer.put.json +1 -1
  53. package/src/__tests__/sakila-db/sqlResponses/C6.customer.put.lookup.json +5 -5
  54. package/src/__tests__/sakila-db/sqlResponses/C6.film.post.json +4 -4
  55. package/src/__tests__/sakila-db/sqlResponses/C6.film.post.latest.json +2 -2
  56. package/src/__tests__/sakila-db/sqlResponses/C6.film.put.json +1 -1
  57. package/src/__tests__/sakila-db/sqlResponses/C6.film.put.lookup.json +2 -2
  58. package/src/__tests__/sakila-db/sqlResponses/C6.inventory.post.json +2 -2
  59. package/src/__tests__/sakila-db/sqlResponses/C6.inventory.post.latest.json +1 -1
  60. package/src/__tests__/sakila-db/sqlResponses/C6.inventory.put.json +1 -1
  61. package/src/__tests__/sakila-db/sqlResponses/C6.inventory.put.lookup.json +1 -1
  62. package/src/__tests__/sakila-db/sqlResponses/C6.language.post.json +4 -4
  63. package/src/__tests__/sakila-db/sqlResponses/C6.language.post.latest.json +2 -2
  64. package/src/__tests__/sakila-db/sqlResponses/C6.language.put.json +1 -1
  65. package/src/__tests__/sakila-db/sqlResponses/C6.language.put.lookup.json +2 -2
  66. package/src/__tests__/sakila-db/sqlResponses/C6.payment.post.json +4 -4
  67. package/src/__tests__/sakila-db/sqlResponses/C6.payment.post.latest.json +2 -2
  68. package/src/__tests__/sakila-db/sqlResponses/C6.payment.put.lookup.json +2 -2
  69. package/src/__tests__/sakila-db/sqlResponses/C6.rental.post.json +6 -6
  70. package/src/__tests__/sakila-db/sqlResponses/C6.rental.post.latest.json +3 -3
  71. package/src/__tests__/sakila-db/sqlResponses/C6.rental.put.json +1 -1
  72. package/src/__tests__/sakila-db/sqlResponses/C6.rental.put.lookup.json +3 -3
  73. package/src/__tests__/sqlAllowList.test.ts +56 -1
  74. package/src/__tests__/sqlBuilders.complex.test.ts +62 -74
  75. package/src/__tests__/sqlBuilders.expressions.test.ts +58 -30
  76. package/src/__tests__/sqlBuilders.test.ts +106 -5
  77. package/src/constants/C6Constants.ts +3 -1
  78. package/src/executors/HttpExecutor.ts +2 -1
  79. package/src/executors/SqlExecutor.ts +29 -4
  80. package/src/index.ts +1 -0
  81. package/src/orm/builders/AggregateBuilder.ts +67 -106
  82. package/src/orm/builders/ConditionBuilder.ts +72 -103
  83. package/src/orm/builders/ExpressionSerializer.ts +275 -0
  84. package/src/orm/builders/PaginationBuilder.ts +24 -34
  85. package/src/orm/queryHelpers.ts +29 -0
  86. package/src/orm/utils/sqlUtils.ts +172 -4
  87. package/src/types/mysqlTypes.ts +130 -9
  88. package/src/types/ormInterfaces.ts +7 -7
  89. package/src/utils/normalizeSingularRequest.ts +11 -4
  90. package/src/utils/sqlAllowList.ts +44 -11
package/dist/index.esm.js CHANGED
@@ -160,6 +160,7 @@ var C6Constants = {
160
160
  AND: 'AND',
161
161
  BETWEEN: 'BETWEEN',
162
162
  CONCAT: 'CONCAT',
163
+ CALL: 'CALL',
163
164
  CONVERT_TZ: 'CONVERT_TZ',
164
165
  COUNT: 'COUNT',
165
166
  COUNT_ALL: 'COUNT_ALL',
@@ -214,6 +215,7 @@ var C6Constants = {
214
215
  LESS_THAN: '<',
215
216
  LESS_THAN_OR_EQUAL_TO: '<=',
216
217
  LIKE: 'LIKE',
218
+ LIT: 'LIT',
217
219
  LIMIT: 'LIMIT',
218
220
  LOCALTIME: 'LOCALTIME',
219
221
  LOCALTIMESTAMP: 'LOCALTIMESTAMP',
@@ -951,7 +953,7 @@ function colorSql(sql) {
951
953
  return s;
952
954
  }
953
955
 
954
- var version = "6.0.20";
956
+ var version = "6.1.1";
955
957
 
956
958
  var DEFAULT_STEP = 8;
957
959
  function parseSemver(version) {
@@ -1288,16 +1290,16 @@ var HttpExecutor = /** @class */ (function (_super) {
1288
1290
  }
1289
1291
  query = this.request;
1290
1292
  apiRequest = function () { return __awaiter(_this, void 0, void 0, function () {
1291
- var _a, debug, _b, cacheResults, dataInsertMultipleRows, success, _c, fetchDependencies, _d, error, cachingConfirmed, cacheRequestData, cacheAllowListStatus, evictFromCache, querySerialized, cachedRequest, cachedData, apiResponse, restRequestUri, needsConditionOrPrimaryCheck, TABLES, primaryKeyList, primaryKeyFullyQualified, primaryKey, whereVal, whereIsEmpty, providedPrimary, primaryVal, axiosActiveRequest_1;
1292
- var _e;
1293
+ var _a, debug, _b, cacheResults, _c, skipReactBootstrap, dataInsertMultipleRows, success, _d, fetchDependencies, _e, error, cachingConfirmed, cacheRequestData, cacheAllowListStatus, evictFromCache, querySerialized, cachedRequest, cachedData, apiResponse, restRequestUri, needsConditionOrPrimaryCheck, TABLES, primaryKeyList, primaryKeyFullyQualified, primaryKey, whereVal, whereIsEmpty, providedPrimary, primaryVal, axiosActiveRequest_1;
1294
+ var _f;
1293
1295
  var _this = this;
1294
- var _f, _g, _h, _j, _k, _l;
1295
- return __generator(this, function (_m) {
1296
- switch (_m.label) {
1296
+ var _g, _h, _j, _k, _l, _m;
1297
+ return __generator(this, function (_o) {
1298
+ switch (_o.label) {
1297
1299
  case 0:
1298
- _a = this.request, debug = _a.debug, _b = _a.cacheResults, cacheResults = _b === void 0 ? (C6.GET === requestMethod) : _b, dataInsertMultipleRows = _a.dataInsertMultipleRows, success = _a.success, _c = _a.fetchDependencies, fetchDependencies = _c === void 0 ? eFetchDependencies.NONE : _c, _d = _a.error, error = _d === void 0 ? "An unexpected API error occurred!" : _d;
1300
+ _a = this.request, debug = _a.debug, _b = _a.cacheResults, cacheResults = _b === void 0 ? (C6.GET === requestMethod) : _b, _c = _a.skipReactBootstrap, skipReactBootstrap = _c === void 0 ? false : _c, dataInsertMultipleRows = _a.dataInsertMultipleRows, success = _a.success, _d = _a.fetchDependencies, fetchDependencies = _d === void 0 ? eFetchDependencies.NONE : _d, _e = _a.error, error = _e === void 0 ? "An unexpected API error occurred!" : _e;
1299
1301
  if (C6.GET === requestMethod
1300
- && undefined !== ((_f = query === null || query === void 0 ? void 0 : query[C6.PAGINATION]) === null || _f === void 0 ? void 0 : _f[C6.PAGE])
1302
+ && undefined !== ((_g = query === null || query === void 0 ? void 0 : query[C6.PAGINATION]) === null || _g === void 0 ? void 0 : _g[C6.PAGE])
1301
1303
  && 1 !== query[C6.PAGINATION][C6.PAGE]
1302
1304
  && isLocal()
1303
1305
  && shouldLog(LogLevel.DEBUG, logContext)) {
@@ -1332,7 +1334,7 @@ var HttpExecutor = /** @class */ (function (_super) {
1332
1334
  if (!cachedRequest) return [3 /*break*/, 2];
1333
1335
  return [4 /*yield*/, cachedRequest];
1334
1336
  case 1:
1335
- cachedData = (_m.sent()).data;
1337
+ cachedData = (_o.sent()).data;
1336
1338
  if (evictFromCache
1337
1339
  && cachedData
1338
1340
  && typeof cachedData === "object"
@@ -1354,9 +1356,9 @@ var HttpExecutor = /** @class */ (function (_super) {
1354
1356
  needsConditionOrPrimaryCheck = (PUT === requestMethod || DELETE === requestMethod)
1355
1357
  && false === skipPrimaryCheck;
1356
1358
  TABLES = C6.TABLES;
1357
- primaryKeyList = structuredClone((_g = TABLES[operatingTable]) === null || _g === void 0 ? void 0 : _g.PRIMARY);
1359
+ primaryKeyList = structuredClone((_h = TABLES[operatingTable]) === null || _h === void 0 ? void 0 : _h.PRIMARY);
1358
1360
  primaryKeyFullyQualified = primaryKeyList === null || primaryKeyList === void 0 ? void 0 : primaryKeyList.pop();
1359
- primaryKey = (_h = primaryKeyFullyQualified === null || primaryKeyFullyQualified === void 0 ? void 0 : primaryKeyFullyQualified.split('.')) === null || _h === void 0 ? void 0 : _h.pop();
1361
+ primaryKey = (_j = primaryKeyFullyQualified === null || primaryKeyFullyQualified === void 0 ? void 0 : primaryKeyFullyQualified.split('.')) === null || _j === void 0 ? void 0 : _j.pop();
1360
1362
  if (needsConditionOrPrimaryCheck) {
1361
1363
  if (undefined === primaryKey) {
1362
1364
  whereVal = query === null || query === void 0 ? void 0 : query[C6.WHERE];
@@ -1365,7 +1367,7 @@ var HttpExecutor = /** @class */ (function (_super) {
1365
1367
  (typeof whereVal === 'object' && !Array.isArray(whereVal) && Object.keys(whereVal).length === 0);
1366
1368
  if (whereIsEmpty) {
1367
1369
  logWithLevel(LogLevel.ERROR, logContext, console.error, query);
1368
- throw Error('Failed to parse primary key information. Query: (' + JSON.stringify(query) + ') Primary Key: (' + JSON.stringify(primaryKey) + ') TABLES[operatingTable]?.PRIMARY: (' + JSON.stringify((_j = TABLES[operatingTable]) === null || _j === void 0 ? void 0 : _j.PRIMARY) + ') for operatingTable (' + operatingTable + ').');
1370
+ throw Error('Failed to parse primary key information. Query: (' + JSON.stringify(query) + ') Primary Key: (' + JSON.stringify(primaryKey) + ') TABLES[operatingTable]?.PRIMARY: (' + JSON.stringify((_k = TABLES[operatingTable]) === null || _k === void 0 ? void 0 : _k.PRIMARY) + ') for operatingTable (' + operatingTable + ').');
1369
1371
  }
1370
1372
  }
1371
1373
  else {
@@ -1377,7 +1379,7 @@ var HttpExecutor = /** @class */ (function (_super) {
1377
1379
  }
1378
1380
  throw Error('You must provide the primary key (' + primaryKey + ') for table (' + operatingTable + '). Request (' + JSON.stringify(this.request, undefined, 4) + ') Query (' + JSON.stringify(query) + ')');
1379
1381
  }
1380
- providedPrimary = (_k = query === null || query === void 0 ? void 0 : query[primaryKey]) !== null && _k !== void 0 ? _k : (primaryKeyFullyQualified ? query === null || query === void 0 ? void 0 : query[primaryKeyFullyQualified] : undefined);
1382
+ providedPrimary = (_l = query === null || query === void 0 ? void 0 : query[primaryKey]) !== null && _l !== void 0 ? _l : (primaryKeyFullyQualified ? query === null || query === void 0 ? void 0 : query[primaryKeyFullyQualified] : undefined);
1381
1383
  if (undefined === providedPrimary || null === providedPrimary) {
1382
1384
  notifyToast("error", "The primary key (".concat(primaryKey, ") provided is undefined or null explicitly!!"));
1383
1385
  throw Error('The primary key (' + primaryKey + ') provided in the request was exactly equal to undefined.');
@@ -1391,7 +1393,7 @@ var HttpExecutor = /** @class */ (function (_super) {
1391
1393
  && undefined !== query
1392
1394
  && null !== query
1393
1395
  && undefined !== primaryKey) {
1394
- primaryVal = (_l = query[primaryKey]) !== null && _l !== void 0 ? _l : (primaryKeyFullyQualified ? query[primaryKeyFullyQualified] : undefined);
1396
+ primaryVal = (_m = query[primaryKey]) !== null && _m !== void 0 ? _m : (primaryKeyFullyQualified ? query[primaryKeyFullyQualified] : undefined);
1395
1397
  if (undefined !== primaryVal) {
1396
1398
  restRequestUri += primaryVal + '/';
1397
1399
  if (isLocal() && shouldLog(LogLevel.DEBUG, logContext)) {
@@ -1419,7 +1421,7 @@ var HttpExecutor = /** @class */ (function (_super) {
1419
1421
  config: this.config,
1420
1422
  request: this.request
1421
1423
  });
1422
- axiosActiveRequest_1 = (_e = axios)[requestMethod.toLowerCase()].apply(_e, __spreadArray([restRequestUri], (function () {
1424
+ axiosActiveRequest_1 = (_f = axios)[requestMethod.toLowerCase()].apply(_f, __spreadArray([restRequestUri], (function () {
1423
1425
  var convert = function (data) {
1424
1426
  return convertForRequestBody(data, fullTableList, C6, function (message) { return notifyToast("error", message, toastOptions); });
1425
1427
  };
@@ -1508,7 +1510,7 @@ var HttpExecutor = /** @class */ (function (_super) {
1508
1510
  request: _this.request,
1509
1511
  response: response
1510
1512
  }); };
1511
- if (undefined !== reactBootstrap && response) {
1513
+ if (undefined !== reactBootstrap && response && !skipReactBootstrap) {
1512
1514
  switch (requestMethod) {
1513
1515
  case GET:
1514
1516
  response.data && reactBootstrap.updateRestfulObjectArrays({
@@ -1796,15 +1798,489 @@ var HttpExecutor$1 = /*#__PURE__*/Object.freeze({
1796
1798
  });
1797
1799
 
1798
1800
  function convertHexIfBinary(_col, val, columnDef) {
1801
+ var _a;
1799
1802
  if (typeof val === 'string' &&
1800
1803
  /^[0-9a-fA-F]{32}$/.test(val) &&
1801
1804
  typeof columnDef === 'object' &&
1802
- columnDef.MYSQL_TYPE.toUpperCase().includes('BINARY')) {
1805
+ String((_a = columnDef.MYSQL_TYPE) !== null && _a !== void 0 ? _a : '').toUpperCase().includes('BINARY')) {
1803
1806
  return Buffer.from(val, 'hex');
1804
1807
  }
1805
1808
  return val;
1806
1809
  }
1810
+ var TEMPORAL_TYPES = new Set([
1811
+ 'date',
1812
+ 'datetime',
1813
+ 'timestamp',
1814
+ 'time',
1815
+ 'year',
1816
+ ]);
1817
+ var MYSQL_DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
1818
+ var MYSQL_DATETIME_REGEX = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:\.\d{1,6})?$/;
1819
+ var MYSQL_TIME_REGEX = /^-?\d{2,3}:\d{2}:\d{2}(?:\.\d{1,6})?$/;
1820
+ var ISO_DATETIME_REGEX = /^(\d{4}-\d{2}-\d{2})[Tt](\d{2}:\d{2}:\d{2})(\.\d{1,6})?([zZ]|[+-]\d{2}:\d{2})?$/;
1821
+ var pad2 = function (value) { return value.toString().padStart(2, '0'); };
1822
+ function trimFraction(value, precision) {
1823
+ var _a = value.split('.', 2), base = _a[0], fractionRaw = _a[1];
1824
+ if (precision <= 0 || !fractionRaw)
1825
+ return base;
1826
+ return "".concat(base, ".").concat(fractionRaw.slice(0, precision).padEnd(precision, '0'));
1827
+ }
1828
+ function normalizeFraction(raw, precision) {
1829
+ if (precision <= 0)
1830
+ return '';
1831
+ if (!raw)
1832
+ return '';
1833
+ var digits = raw.startsWith('.') ? raw.slice(1) : raw;
1834
+ return ".".concat(digits.slice(0, precision).padEnd(precision, '0'));
1835
+ }
1836
+ function formatDateUtc(value) {
1837
+ return "".concat(value.getUTCFullYear(), "-").concat(pad2(value.getUTCMonth() + 1), "-").concat(pad2(value.getUTCDate()));
1838
+ }
1839
+ function formatTimeUtc(value, precision) {
1840
+ var base = "".concat(pad2(value.getUTCHours()), ":").concat(pad2(value.getUTCMinutes()), ":").concat(pad2(value.getUTCSeconds()));
1841
+ if (precision <= 0)
1842
+ return base;
1843
+ var millis = value.getUTCMilliseconds().toString().padStart(3, '0');
1844
+ var fraction = millis.slice(0, Math.min(precision, 3)).padEnd(precision, '0');
1845
+ return "".concat(base, ".").concat(fraction);
1846
+ }
1847
+ function formatDateTimeUtc(value, precision) {
1848
+ return "".concat(formatDateUtc(value), " ").concat(formatTimeUtc(value, precision));
1849
+ }
1850
+ function parseEpochNumber(value) {
1851
+ if (!Number.isFinite(value))
1852
+ return undefined;
1853
+ var abs = Math.abs(value);
1854
+ if (abs >= 1e12) {
1855
+ var date = new Date(value);
1856
+ return Number.isNaN(date.getTime()) ? undefined : date;
1857
+ }
1858
+ if (abs >= 1e9) {
1859
+ var date = new Date(value * 1000);
1860
+ return Number.isNaN(date.getTime()) ? undefined : date;
1861
+ }
1862
+ return undefined;
1863
+ }
1864
+ function parseTemporalType(columnDef) {
1865
+ var _a;
1866
+ var raw = String((_a = columnDef === null || columnDef === void 0 ? void 0 : columnDef.MYSQL_TYPE) !== null && _a !== void 0 ? _a : '').trim().toLowerCase();
1867
+ if (!raw)
1868
+ return { baseType: undefined, precision: 0 };
1869
+ var base = raw.split(/[\s(]/, 1)[0];
1870
+ if (!TEMPORAL_TYPES.has(base))
1871
+ return { baseType: undefined, precision: 0 };
1872
+ var precisionMatch = raw.match(/^(?:datetime|timestamp|time)\((\d+)\)/);
1873
+ if (!precisionMatch)
1874
+ return { baseType: base, precision: 0 };
1875
+ var parsed = Number.parseInt(precisionMatch[1], 10);
1876
+ if (!Number.isFinite(parsed))
1877
+ return { baseType: base, precision: 0 };
1878
+ return { baseType: base, precision: Math.max(0, Math.min(6, parsed)) };
1879
+ }
1880
+ function normalizeTemporalString(value, baseType, precision) {
1881
+ var trimmed = value.trim();
1882
+ if (!trimmed)
1883
+ return value;
1884
+ if (baseType === 'date') {
1885
+ if (MYSQL_DATE_REGEX.test(trimmed))
1886
+ return trimmed;
1887
+ var iso_1 = trimmed.match(ISO_DATETIME_REGEX);
1888
+ if (iso_1) {
1889
+ var datePart = iso_1[1], timezonePart = iso_1[4];
1890
+ if (!timezonePart)
1891
+ return datePart;
1892
+ var parsed_1 = new Date(trimmed);
1893
+ return Number.isNaN(parsed_1.getTime()) ? value : formatDateUtc(parsed_1);
1894
+ }
1895
+ var parsed_2 = new Date(trimmed);
1896
+ return Number.isNaN(parsed_2.getTime()) ? value : formatDateUtc(parsed_2);
1897
+ }
1898
+ if (baseType === 'time') {
1899
+ if (MYSQL_TIME_REGEX.test(trimmed))
1900
+ return trimFraction(trimmed, precision);
1901
+ var iso_2 = trimmed.match(ISO_DATETIME_REGEX);
1902
+ if (iso_2) {
1903
+ var timePart = iso_2[2], fractionPart = iso_2[3], timezonePart = iso_2[4];
1904
+ if (!timezonePart) {
1905
+ return "".concat(timePart).concat(normalizeFraction(fractionPart, precision));
1906
+ }
1907
+ var parsed_3 = new Date(trimmed);
1908
+ return Number.isNaN(parsed_3.getTime()) ? value : formatTimeUtc(parsed_3, precision);
1909
+ }
1910
+ var parsed_4 = new Date(trimmed);
1911
+ return Number.isNaN(parsed_4.getTime()) ? value : formatTimeUtc(parsed_4, precision);
1912
+ }
1913
+ if (baseType === 'year') {
1914
+ if (/^\d{2,4}$/.test(trimmed))
1915
+ return trimmed;
1916
+ var parsed_5 = new Date(trimmed);
1917
+ return Number.isNaN(parsed_5.getTime()) ? value : String(parsed_5.getUTCFullYear());
1918
+ }
1919
+ if (MYSQL_DATETIME_REGEX.test(trimmed))
1920
+ return trimFraction(trimmed, precision);
1921
+ var iso = trimmed.match(ISO_DATETIME_REGEX);
1922
+ if (iso) {
1923
+ var datePart = iso[1], timePart = iso[2], fractionPart = iso[3], timezonePart = iso[4];
1924
+ if (!timezonePart) {
1925
+ return "".concat(datePart, " ").concat(timePart).concat(normalizeFraction(fractionPart, precision));
1926
+ }
1927
+ var parsed_6 = new Date(trimmed);
1928
+ return Number.isNaN(parsed_6.getTime()) ? value : formatDateTimeUtc(parsed_6, precision);
1929
+ }
1930
+ var parsed = new Date(trimmed);
1931
+ return Number.isNaN(parsed.getTime()) ? value : formatDateTimeUtc(parsed, precision);
1932
+ }
1933
+ function convertTemporalIfNeeded(value, columnDef) {
1934
+ var _a = parseTemporalType(columnDef), baseType = _a.baseType, precision = _a.precision;
1935
+ if (!baseType)
1936
+ return value;
1937
+ if (value === null || value === undefined)
1938
+ return value;
1939
+ if (typeof Buffer !== 'undefined' && Buffer.isBuffer && Buffer.isBuffer(value))
1940
+ return value;
1941
+ if (value instanceof Date) {
1942
+ if (baseType === 'date')
1943
+ return formatDateUtc(value);
1944
+ if (baseType === 'time')
1945
+ return formatTimeUtc(value, precision);
1946
+ if (baseType === 'year')
1947
+ return String(value.getUTCFullYear());
1948
+ return formatDateTimeUtc(value, precision);
1949
+ }
1950
+ if (typeof value === 'number') {
1951
+ var parsed = parseEpochNumber(value);
1952
+ if (!parsed)
1953
+ return value;
1954
+ if (baseType === 'date')
1955
+ return formatDateUtc(parsed);
1956
+ if (baseType === 'time')
1957
+ return formatTimeUtc(parsed, precision);
1958
+ if (baseType === 'year')
1959
+ return String(parsed.getUTCFullYear());
1960
+ return formatDateTimeUtc(parsed, precision);
1961
+ }
1962
+ if (typeof value === 'string') {
1963
+ return normalizeTemporalString(value, baseType, precision);
1964
+ }
1965
+ return value;
1966
+ }
1967
+ function convertSqlValueForColumn(col, val, columnDef) {
1968
+ var binaryConverted = convertHexIfBinary(col, val, columnDef);
1969
+ return convertTemporalIfNeeded(binaryConverted, columnDef);
1970
+ }
1971
+
1972
+ // ========================
1973
+ // SQL Operators & Expressions
1974
+ // ========================
1975
+ var SQL_KNOWN_FUNCTIONS = [
1976
+ 'ADDDATE',
1977
+ 'ADDTIME',
1978
+ 'CONCAT',
1979
+ 'CONVERT_TZ',
1980
+ 'COUNT',
1981
+ 'COUNT_ALL',
1982
+ 'CURRENT_DATE',
1983
+ 'CURRENT_TIMESTAMP',
1984
+ 'DAY',
1985
+ 'DAY_HOUR',
1986
+ 'DAY_MICROSECOND',
1987
+ 'DAY_MINUTE',
1988
+ 'DAY_SECOND',
1989
+ 'DAYNAME',
1990
+ 'DAYOFMONTH',
1991
+ 'DAYOFWEEK',
1992
+ 'DAYOFYEAR',
1993
+ 'DATE',
1994
+ 'DATE_ADD',
1995
+ 'DATEDIFF',
1996
+ 'DATE_SUB',
1997
+ 'DATE_FORMAT',
1998
+ 'EXTRACT',
1999
+ 'FROM_DAYS',
2000
+ 'FROM_UNIXTIME',
2001
+ 'GET_FORMAT',
2002
+ 'GROUP_CONCAT',
2003
+ 'HEX',
2004
+ 'HOUR',
2005
+ 'HOUR_MICROSECOND',
2006
+ 'HOUR_MINUTE',
2007
+ 'HOUR_SECOND',
2008
+ 'INTERVAL',
2009
+ 'LOCALTIME',
2010
+ 'LOCALTIMESTAMP',
2011
+ 'MAKEDATE',
2012
+ 'MAKETIME',
2013
+ 'MAX',
2014
+ 'MBRContains',
2015
+ 'MICROSECOND',
2016
+ 'MIN',
2017
+ 'MINUTE',
2018
+ 'MINUTE_MICROSECOND',
2019
+ 'MINUTE_SECOND',
2020
+ 'MONTH',
2021
+ 'MONTHNAME',
2022
+ 'NOW',
2023
+ 'POINT',
2024
+ 'POLYGON',
2025
+ 'SECOND',
2026
+ 'SECOND_MICROSECOND',
2027
+ 'ST_Area',
2028
+ 'ST_AsBinary',
2029
+ 'ST_AsText',
2030
+ 'ST_Buffer',
2031
+ 'ST_Contains',
2032
+ 'ST_Crosses',
2033
+ 'ST_Difference',
2034
+ 'ST_Dimension',
2035
+ 'ST_Disjoint',
2036
+ 'ST_Distance',
2037
+ 'ST_Distance_Sphere',
2038
+ 'ST_EndPoint',
2039
+ 'ST_Envelope',
2040
+ 'ST_Equals',
2041
+ 'ST_GeomFromGeoJSON',
2042
+ 'ST_GeomFromText',
2043
+ 'ST_GeomFromWKB',
2044
+ 'ST_Intersects',
2045
+ 'ST_Length',
2046
+ 'ST_MakeEnvelope',
2047
+ 'ST_Overlaps',
2048
+ 'ST_Point',
2049
+ 'ST_SetSRID',
2050
+ 'ST_SRID',
2051
+ 'ST_StartPoint',
2052
+ 'ST_SymDifference',
2053
+ 'ST_Touches',
2054
+ 'ST_Union',
2055
+ 'ST_Within',
2056
+ 'ST_X',
2057
+ 'ST_Y',
2058
+ 'STR_TO_DATE',
2059
+ 'SUBDATE',
2060
+ 'SUBTIME',
2061
+ 'SUM',
2062
+ 'SYSDATE',
2063
+ 'TIME',
2064
+ 'TIME_FORMAT',
2065
+ 'TIME_TO_SEC',
2066
+ 'TIMEDIFF',
2067
+ 'TIMESTAMP',
2068
+ 'TIMESTAMPADD',
2069
+ 'TIMESTAMPDIFF',
2070
+ 'TO_DAYS',
2071
+ 'TO_SECONDS',
2072
+ 'TRANSACTION_TIMESTAMP',
2073
+ 'UNHEX',
2074
+ 'UNIX_TIMESTAMP',
2075
+ 'UTC_DATE',
2076
+ 'UTC_TIME',
2077
+ 'UTC_TIMESTAMP',
2078
+ 'WEEKDAY',
2079
+ 'WEEKOFYEAR',
2080
+ 'YEARWEEK',
2081
+ ];
2082
+
2083
+ var IDENTIFIER_REGEX = /^[A-Za-z_][A-Za-z0-9_]*$/;
2084
+ var isFiniteNumber = function (value) {
2085
+ return typeof value === 'number' && Number.isFinite(value);
2086
+ };
2087
+ var normalizeToken = function (token) { return token.trim(); };
2088
+ var ensureParams = function (opts) {
2089
+ if (!opts.params) {
2090
+ throw new Error("".concat(opts.context, " requires parameter tracking for literal bindings."));
2091
+ }
2092
+ if (!opts.hooks.addParam) {
2093
+ throw new Error("".concat(opts.context, " requires addParam support for literal bindings."));
2094
+ }
2095
+ return opts.params;
2096
+ };
2097
+ var serializeStringReference = function (raw, opts) {
2098
+ var value = raw.trim();
2099
+ if (value === '*') {
2100
+ return {
2101
+ sql: value,
2102
+ isReference: true,
2103
+ isExpression: false,
2104
+ isSubSelect: false,
2105
+ };
2106
+ }
2107
+ if (!opts.hooks.isReference(value)) {
2108
+ throw new Error("Bare string '".concat(raw, "' is not a reference in ").concat(opts.context, ". Wrap literal strings with [C6C.LIT, value]."));
2109
+ }
2110
+ if (value.includes('.')) {
2111
+ opts.hooks.assertValidIdentifier(value, opts.context);
2112
+ }
2113
+ return {
2114
+ sql: value,
2115
+ isReference: true,
2116
+ isExpression: false,
2117
+ isSubSelect: false,
2118
+ };
2119
+ };
2120
+ var serializeLiteralValue = function (value, opts) {
2121
+ var _a;
2122
+ if (value === null || value === C6C.NULL) {
2123
+ return {
2124
+ sql: 'NULL',
2125
+ isReference: false,
2126
+ isExpression: false,
2127
+ isSubSelect: false,
2128
+ };
2129
+ }
2130
+ if (isFiniteNumber(value)) {
2131
+ return {
2132
+ sql: String(value),
2133
+ isReference: false,
2134
+ isExpression: false,
2135
+ isSubSelect: false,
2136
+ };
2137
+ }
2138
+ if (typeof value === 'boolean') {
2139
+ return {
2140
+ sql: value ? 'TRUE' : 'FALSE',
2141
+ isReference: false,
2142
+ isExpression: false,
2143
+ isSubSelect: false,
2144
+ };
2145
+ }
2146
+ if (typeof Buffer !== 'undefined' && Buffer.isBuffer && Buffer.isBuffer(value)) {
2147
+ var params = ensureParams(opts);
2148
+ return {
2149
+ sql: opts.hooks.addParam(params, (_a = opts.contextColumn) !== null && _a !== void 0 ? _a : '', value),
2150
+ isReference: false,
2151
+ isExpression: false,
2152
+ isSubSelect: false,
2153
+ };
2154
+ }
2155
+ throw new Error("Unsupported literal value in ".concat(opts.context, ". Use [C6C.LIT, value] for non-reference strings or complex values."));
2156
+ };
2157
+ var validateAlias = function (aliasRaw, context) {
2158
+ if (typeof aliasRaw !== 'string' || aliasRaw.trim() === '') {
2159
+ throw new Error("[C6C.AS] in ".concat(context, " expects a non-empty alias string."));
2160
+ }
2161
+ var alias = aliasRaw.trim();
2162
+ if (!IDENTIFIER_REGEX.test(alias)) {
2163
+ throw new Error("[C6C.AS] alias '".concat(alias, "' in ").concat(context, " must be a valid SQL identifier."));
2164
+ }
2165
+ return alias;
2166
+ };
2167
+ var validateFunctionName = function (nameRaw, context) {
2168
+ if (typeof nameRaw !== 'string' || nameRaw.trim() === '') {
2169
+ throw new Error("[C6C.CALL] in ".concat(context, " expects the custom function name as a non-empty string."));
2170
+ }
2171
+ var name = normalizeToken(nameRaw);
2172
+ if (!IDENTIFIER_REGEX.test(name)) {
2173
+ throw new Error("[C6C.CALL] function '".concat(name, "' in ").concat(context, " must be a valid SQL identifier."));
2174
+ }
2175
+ return name;
2176
+ };
2177
+ var serializeFunctionArgs = function (args, opts) { return args
2178
+ .map(function (arg) { return serializeSqlExpression(arg, opts).sql; })
2179
+ .join(', '); };
2180
+ var serializeSqlExpression = function (value, opts) {
2181
+ var _a, _b, _c;
2182
+ if (value instanceof Map) {
2183
+ value = Object.fromEntries(value);
2184
+ }
2185
+ if (Array.isArray(value)) {
2186
+ if (value.length === 0) {
2187
+ throw new Error("Invalid empty expression array in ".concat(opts.context, "."));
2188
+ }
2189
+ var headRaw = value[0], tail = value.slice(1);
2190
+ if (typeof headRaw !== 'string') {
2191
+ throw new Error("Expression arrays in ".concat(opts.context, " must start with a string token."));
2192
+ }
2193
+ var head = normalizeToken(headRaw);
2194
+ var token = head.toUpperCase();
2195
+ if (token === C6C.AS) {
2196
+ if (tail.length !== 2) {
2197
+ throw new Error("[C6C.AS] in ".concat(opts.context, " expects [C6C.AS, expression, alias]."));
2198
+ }
2199
+ var inner = serializeSqlExpression(tail[0], opts);
2200
+ var alias = validateAlias(tail[1], opts.context);
2201
+ (_b = (_a = opts.hooks).onAlias) === null || _b === void 0 ? void 0 : _b.call(_a, alias);
2202
+ return {
2203
+ sql: "".concat(inner.sql, " AS ").concat(alias),
2204
+ isReference: false,
2205
+ isExpression: true,
2206
+ isSubSelect: inner.isSubSelect,
2207
+ };
2208
+ }
2209
+ if (token === C6C.DISTINCT) {
2210
+ if (tail.length !== 1) {
2211
+ throw new Error("[C6C.DISTINCT] in ".concat(opts.context, " expects [C6C.DISTINCT, expression]."));
2212
+ }
2213
+ var inner = serializeSqlExpression(tail[0], opts);
2214
+ return {
2215
+ sql: "DISTINCT ".concat(inner.sql),
2216
+ isReference: false,
2217
+ isExpression: true,
2218
+ isSubSelect: inner.isSubSelect,
2219
+ };
2220
+ }
2221
+ if (token === C6C.LIT || token === C6C.PARAM) {
2222
+ if (tail.length !== 1) {
2223
+ throw new Error("[".concat(head, "] in ").concat(opts.context, " expects [").concat(head, ", value]."));
2224
+ }
2225
+ var params = ensureParams(opts);
2226
+ return {
2227
+ sql: opts.hooks.addParam(params, (_c = opts.contextColumn) !== null && _c !== void 0 ? _c : '', tail[0]),
2228
+ isReference: false,
2229
+ isExpression: false,
2230
+ isSubSelect: false,
2231
+ };
2232
+ }
2233
+ if (token === C6C.SUBSELECT) {
2234
+ if (tail.length !== 1) {
2235
+ throw new Error("[C6C.SUBSELECT] in ".concat(opts.context, " expects [C6C.SUBSELECT, payload]."));
2236
+ }
2237
+ if (!opts.hooks.buildScalarSubSelect) {
2238
+ throw new Error("Scalar subselects in ".concat(opts.context, " require subselect builder support."));
2239
+ }
2240
+ var params = ensureParams(opts);
2241
+ var subSql = opts.hooks.buildScalarSubSelect(tail[0], params);
2242
+ return {
2243
+ sql: subSql,
2244
+ isReference: false,
2245
+ isExpression: true,
2246
+ isSubSelect: true,
2247
+ };
2248
+ }
2249
+ if (token === C6C.CALL) {
2250
+ var fnNameRaw = tail[0], args = tail.slice(1);
2251
+ var fnName = validateFunctionName(fnNameRaw, opts.context);
2252
+ var sqlArgs_1 = serializeFunctionArgs(args, opts);
2253
+ return {
2254
+ sql: "".concat(fnName, "(").concat(sqlArgs_1, ")"),
2255
+ isReference: false,
2256
+ isExpression: true,
2257
+ isSubSelect: false,
2258
+ };
2259
+ }
2260
+ if (tail.length >= 2 && String(tail[tail.length - 2]).toUpperCase() === C6C.AS) {
2261
+ throw new Error("Legacy positional AS syntax is not supported in ".concat(opts.context, ". Use [C6C.AS, expression, alias]."));
2262
+ }
2263
+ if (opts.hooks.isKnownFunction && !opts.hooks.isKnownFunction(head)) {
2264
+ throw new Error("Unknown SQL function '".concat(head, "' in ").concat(opts.context, ". Use [C6C.CALL, 'FUNCTION_NAME', ...args] for custom functions."));
2265
+ }
2266
+ var sqlArgs = serializeFunctionArgs(tail, opts);
2267
+ return {
2268
+ sql: "".concat(token, "(").concat(sqlArgs, ")"),
2269
+ isReference: false,
2270
+ isExpression: true,
2271
+ isSubSelect: false,
2272
+ };
2273
+ }
2274
+ if (typeof value === 'string') {
2275
+ return serializeStringReference(value, opts);
2276
+ }
2277
+ if (value && typeof value === 'object') {
2278
+ throw new Error("Object-rooted expressions are not supported in ".concat(opts.context, ". Use tuple syntax instead."));
2279
+ }
2280
+ return serializeLiteralValue(value, opts);
2281
+ };
1807
2282
 
2283
+ var KNOWN_FUNCTION_LOOKUP = new Set(SQL_KNOWN_FUNCTIONS.map(function (name) { return String(name).toUpperCase(); }));
1808
2284
  var AggregateBuilder = /** @class */ (function (_super) {
1809
2285
  __extends(AggregateBuilder, _super);
1810
2286
  function AggregateBuilder() {
@@ -1817,112 +2293,71 @@ var AggregateBuilder = /** @class */ (function (_super) {
1817
2293
  AggregateBuilder.prototype.assertValidIdentifier = function (_identifier, _context) {
1818
2294
  // no-op placeholder for subclasses that do not implement alias validation
1819
2295
  };
1820
- AggregateBuilder.prototype.buildAggregateField = function (field, params) {
1821
- var _this = this;
1822
- var _a, _b;
1823
- if (typeof field === 'string') {
1824
- this.assertValidIdentifier(field, 'SELECT field');
1825
- return field;
1826
- }
1827
- if (!Array.isArray(field) || field.length === 0) {
1828
- throw new Error('Invalid SELECT field entry');
1829
- }
1830
- // If the array represents a tuple/literal list (e.g., [lng, lat]) rather than a
1831
- // function call like [FN, ...args], serialize the list as a comma-separated
1832
- // literal sequence so parent calls (like ORDER BY FN(<here>)) can embed it.
1833
- var isNumericString = function (s) { return /^-?\d+(?:\.\d+)?$/.test(String(s).trim()); };
1834
- if (typeof field[0] !== 'string' || isNumericString(field[0])) {
1835
- return field
1836
- .map(function (arg) {
1837
- if (Array.isArray(arg))
1838
- return _this.buildAggregateField(arg, params);
1839
- return String(arg);
1840
- })
1841
- .join(', ');
1842
- }
1843
- var fn = field[0], args = field.slice(1);
1844
- var alias;
1845
- if (args.length >= 2 && String(args[args.length - 2]).toUpperCase() === 'AS') {
1846
- alias = String(args.pop());
1847
- args.pop();
1848
- }
1849
- var F = String(fn).toUpperCase();
1850
- var isGeomFromText = F === C6C.ST_GEOMFROMTEXT.toUpperCase();
1851
- if (args.length === 1 && Array.isArray(args[0])) {
1852
- args = args[0];
1853
- }
1854
- // Parameter placeholder helper: [C6C.PARAM, value]
1855
- if (F === C6C.PARAM) {
1856
- if (!params) {
1857
- throw new Error('PARAM requires parameter tracking.');
1858
- }
1859
- var value = args[0];
1860
- // Use empty column context; ORDER/SELECT literals have no column typing.
1861
- // @ts-ignore addParam is provided by ConditionBuilder in our hierarchy.
1862
- return this.addParam(params, '', value);
1863
- }
1864
- if (F === C6C.SUBSELECT) {
1865
- if (!params) {
1866
- throw new Error('Scalar subselects in SELECT require parameter tracking.');
1867
- }
1868
- var subRequest = args[0];
1869
- var subSql = (_b = (_a = this).buildScalarSubSelect) === null || _b === void 0 ? void 0 : _b.call(_a, subRequest, params);
1870
- if (!subSql) {
1871
- throw new Error('Failed to build scalar subselect.');
1872
- }
1873
- var expr_1 = subSql;
1874
- if (alias) {
1875
- this.selectAliases.add(alias);
1876
- expr_1 += " AS ".concat(alias);
1877
- }
1878
- logWithLevel(LogLevel.DEBUG, getLogContext(this.config, this.request), console.log, "[SELECT] ".concat(expr_1));
1879
- return expr_1;
1880
- }
1881
- var identifierPathRegex = /^[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*$/;
1882
- var argList = args
1883
- .map(function (arg, index) {
1884
- if (Array.isArray(arg))
1885
- return _this.buildAggregateField(arg, params);
1886
- if (typeof arg === 'string') {
1887
- if (identifierPathRegex.test(arg)) {
1888
- _this.assertValidIdentifier(arg, 'SELECT expression');
1889
- return arg;
1890
- }
1891
- // Treat numeric-looking strings as literals, not identifier paths
1892
- if (isNumericString(arg))
1893
- return arg;
1894
- if (isGeomFromText && index === 0) {
1895
- var trimmed = arg.trim();
1896
- var alreadyQuoted = trimmed.startsWith("'") && trimmed.endsWith("'") && trimmed.length >= 2;
1897
- if (alreadyQuoted) {
1898
- return trimmed;
1899
- }
1900
- var escaped = arg.replace(/'/g, "''");
1901
- return "'".concat(escaped, "'");
1902
- }
1903
- return arg;
1904
- }
1905
- return String(arg);
1906
- })
1907
- .join(', ');
1908
- var expr;
1909
- if (F === 'DISTINCT') {
1910
- expr = "DISTINCT ".concat(argList);
2296
+ AggregateBuilder.prototype.isReferenceExpression = function (value) {
2297
+ if (typeof value !== 'string')
2298
+ return false;
2299
+ var trimmed = value.trim();
2300
+ if (trimmed.length === 0)
2301
+ return false;
2302
+ if (trimmed === '*')
2303
+ return true;
2304
+ if (/^[A-Za-z_][A-Za-z0-9_]*\.\*$/.test(trimmed)) {
2305
+ this.assertValidIdentifier(trimmed, 'SQL reference');
2306
+ return true;
1911
2307
  }
1912
- else {
1913
- expr = "".concat(F, "(").concat(argList, ")");
2308
+ if (/^[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*$/.test(trimmed)) {
2309
+ this.assertValidIdentifier(trimmed, 'SQL reference');
2310
+ return true;
1914
2311
  }
1915
- if (alias) {
1916
- this.selectAliases.add(alias);
1917
- expr += " AS ".concat(alias);
2312
+ if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(trimmed) && this.selectAliases.has(trimmed)) {
2313
+ return true;
1918
2314
  }
1919
- logWithLevel(LogLevel.DEBUG, getLogContext(this.config, this.request), console.log, "[SELECT] ".concat(expr));
1920
- return expr;
2315
+ return false;
2316
+ };
2317
+ AggregateBuilder.prototype.isKnownFunction = function (functionName) {
2318
+ return KNOWN_FUNCTION_LOOKUP.has(functionName.trim().toUpperCase());
2319
+ };
2320
+ AggregateBuilder.prototype.serializeExpression = function (expression, params, context, contextColumn) {
2321
+ var _this = this;
2322
+ if (context === void 0) { context = 'SQL expression'; }
2323
+ return serializeSqlExpression(expression, {
2324
+ params: params,
2325
+ context: context,
2326
+ contextColumn: contextColumn,
2327
+ hooks: {
2328
+ assertValidIdentifier: function (identifier, hookContext) {
2329
+ _this.assertValidIdentifier(identifier, hookContext);
2330
+ },
2331
+ isReference: function (value) { return _this.isReferenceExpression(value); },
2332
+ addParam: function (target, column, value) {
2333
+ var addParam = _this.addParam;
2334
+ if (typeof addParam !== 'function') {
2335
+ throw new Error('Expression literal binding requires addParam support.');
2336
+ }
2337
+ return addParam.call(_this, target, column, value);
2338
+ },
2339
+ buildScalarSubSelect: function (subRequest, target) {
2340
+ var builder = _this.buildScalarSubSelect;
2341
+ if (typeof builder !== 'function') {
2342
+ throw new Error('Scalar subselects require SelectQueryBuilder context.');
2343
+ }
2344
+ return builder.call(_this, subRequest, target);
2345
+ },
2346
+ onAlias: function (alias) {
2347
+ _this.selectAliases.add(alias);
2348
+ },
2349
+ isKnownFunction: function (functionName) { return _this.isKnownFunction(functionName); },
2350
+ },
2351
+ });
2352
+ };
2353
+ AggregateBuilder.prototype.buildAggregateField = function (field, params) {
2354
+ var serialized = this.serializeExpression(field, params, 'SELECT expression');
2355
+ logWithLevel(LogLevel.DEBUG, getLogContext(this.config, this.request), console.log, "[SELECT] ".concat(serialized.sql));
2356
+ return serialized.sql;
1921
2357
  };
1922
2358
  return AggregateBuilder;
1923
2359
  }(Executor));
1924
2360
 
1925
- // Alias a table name with a given alias
1926
2361
  var DERIVED_TABLE_PREFIX = '__c6DerivedTable__';
1927
2362
  var DERIVED_ID_SYMBOL = Symbol('c6DerivedTableId');
1928
2363
  var derivedTableLookup = new Map();
@@ -2000,6 +2435,29 @@ var bbox = function (minLng, minLat, maxLng, maxLat) {
2000
2435
  var stContains = function (envelope, shape) {
2001
2436
  return [C6C.ST_CONTAINS, envelope, shape];
2002
2437
  };
2438
+ // Strongly-typed known function helper.
2439
+ var fn = function (functionName) {
2440
+ var args = [];
2441
+ for (var _i = 1; _i < arguments.length; _i++) {
2442
+ args[_i - 1] = arguments[_i];
2443
+ }
2444
+ return __spreadArray([functionName], args, true);
2445
+ };
2446
+ // Escape hatch for custom function names.
2447
+ var call = function (functionName) {
2448
+ var args = [];
2449
+ for (var _i = 1; _i < arguments.length; _i++) {
2450
+ args[_i - 1] = arguments[_i];
2451
+ }
2452
+ return __spreadArray([C6C.CALL, functionName], args, true);
2453
+ };
2454
+ var alias = function (expression, aliasName) { return [C6C.AS, expression, aliasName]; };
2455
+ var distinct = function (expression) { return [C6C.DISTINCT, expression]; };
2456
+ var lit = function (value) { return [C6C.LIT, value]; };
2457
+ var order = function (expression, direction) {
2458
+ if (direction === void 0) { direction = C6C.ASC; }
2459
+ return [expression, direction];
2460
+ };
2003
2461
 
2004
2462
  var ConditionBuilder = /** @class */ (function (_super) {
2005
2463
  __extends(ConditionBuilder, _super);
@@ -2106,6 +2564,26 @@ var ConditionBuilder = /** @class */ (function (_super) {
2106
2564
  return true;
2107
2565
  return false;
2108
2566
  };
2567
+ ConditionBuilder.prototype.isReferenceExpression = function (value) {
2568
+ var trimmed = value.trim();
2569
+ if (trimmed === '*') {
2570
+ return true;
2571
+ }
2572
+ if (trimmed.includes('.')) {
2573
+ if (/^[A-Za-z_][A-Za-z0-9_]*\.\*$/.test(trimmed)) {
2574
+ return true;
2575
+ }
2576
+ if (this.isTableReference(trimmed) || this.isColumnRef(trimmed)) {
2577
+ return true;
2578
+ }
2579
+ if (/^[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*$/.test(trimmed)) {
2580
+ this.assertValidIdentifier(trimmed, 'SQL reference');
2581
+ return true;
2582
+ }
2583
+ return false;
2584
+ }
2585
+ return _super.prototype.isReferenceExpression.call(this, trimmed);
2586
+ };
2109
2587
  ConditionBuilder.prototype.execute = function () {
2110
2588
  throw new Error("Method not implemented.");
2111
2589
  };
@@ -2135,16 +2613,8 @@ var ConditionBuilder = /** @class */ (function (_super) {
2135
2613
  Object.values(table.COLUMNS).includes(column));
2136
2614
  };
2137
2615
  ConditionBuilder.prototype.addParam = function (params, column, value) {
2138
- var _a, _b, _c, _d, _e;
2139
- // Determine column definition from C6.TABLES to support type-aware conversions (e.g., BINARY hex -> Buffer)
2140
- var columnDef;
2141
- if (typeof column === 'string' && column.includes('.')) {
2142
- var _f = column.split('.', 2), tableName = _f[0], colName = _f[1];
2143
- var table = (_b = (_a = this.config.C6) === null || _a === void 0 ? void 0 : _a.TABLES) === null || _b === void 0 ? void 0 : _b[tableName];
2144
- // Support both short-keyed and fully-qualified TYPE_VALIDATION entries
2145
- columnDef = (_d = (_c = table === null || table === void 0 ? void 0 : table.TYPE_VALIDATION) === null || _c === void 0 ? void 0 : _c[colName]) !== null && _d !== void 0 ? _d : (_e = table === null || table === void 0 ? void 0 : table.TYPE_VALIDATION) === null || _e === void 0 ? void 0 : _e["".concat(tableName, ".").concat(colName)];
2146
- }
2147
- var val = convertHexIfBinary(column, value, columnDef);
2616
+ var columnDef = this.resolveColumnDefinition(column);
2617
+ var val = convertSqlValueForColumn(column, value, columnDef);
2148
2618
  if (this.useNamedParams) {
2149
2619
  var key = "param".concat(Object.keys(params).length);
2150
2620
  params[key] = val;
@@ -2180,41 +2650,6 @@ var ConditionBuilder = /** @class */ (function (_super) {
2180
2650
  ConditionBuilder.prototype.isOperator = function (op) {
2181
2651
  return !!this.normalizeOperatorKey(op);
2182
2652
  };
2183
- ConditionBuilder.prototype.looksLikeSafeFunctionExpression = function (value) {
2184
- if (typeof value !== 'string')
2185
- return false;
2186
- var trimmed = value.trim();
2187
- if (trimmed.length === 0)
2188
- return false;
2189
- if (trimmed.includes(';') || trimmed.includes('--') || trimmed.includes('/*') || trimmed.includes('*/')) {
2190
- return false;
2191
- }
2192
- if (!trimmed.includes('(') || !trimmed.endsWith(')')) {
2193
- return false;
2194
- }
2195
- var functionMatch = trimmed.match(/^([A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*)\s*\(/);
2196
- if (!functionMatch) {
2197
- return false;
2198
- }
2199
- var allowedCharacters = /^[A-Za-z0-9_().,'"\s-]+$/;
2200
- if (!allowedCharacters.test(trimmed)) {
2201
- return false;
2202
- }
2203
- var depth = 0;
2204
- for (var _i = 0, trimmed_1 = trimmed; _i < trimmed_1.length; _i++) {
2205
- var char = trimmed_1[_i];
2206
- if (char === '(') {
2207
- depth += 1;
2208
- }
2209
- else if (char === ')') {
2210
- depth -= 1;
2211
- if (depth < 0) {
2212
- return false;
2213
- }
2214
- }
2215
- }
2216
- return depth === 0;
2217
- };
2218
2653
  ConditionBuilder.prototype.ensureWrapped = function (expression) {
2219
2654
  var trimmed = expression.trim();
2220
2655
  if (!trimmed)
@@ -2242,42 +2677,6 @@ var ConditionBuilder = /** @class */ (function (_super) {
2242
2677
  })
2243
2678
  .join(" ".concat(operator, " "));
2244
2679
  };
2245
- ConditionBuilder.prototype.normalizeFunctionField = function (field, params) {
2246
- var _this = this;
2247
- if (field instanceof Map) {
2248
- field = Object.fromEntries(field);
2249
- }
2250
- if (Array.isArray(field)) {
2251
- if (field.length === 0)
2252
- return field;
2253
- var fn = field[0], args = field.slice(1);
2254
- var normalizedArgs = args.map(function (arg) { return _this.normalizeFunctionField(arg, params); });
2255
- return __spreadArray([fn], normalizedArgs, true);
2256
- }
2257
- if (field && typeof field === 'object') {
2258
- if (C6C.SUBSELECT in field) {
2259
- var builder = this.buildScalarSubSelect;
2260
- if (typeof builder !== 'function') {
2261
- throw new Error('Scalar subselect handling requires JoinBuilder context.');
2262
- }
2263
- return builder.call(this, field[C6C.SUBSELECT], params);
2264
- }
2265
- var entries = Object.entries(field);
2266
- if (entries.length === 1) {
2267
- var _a = entries[0], key = _a[0], value = _a[1];
2268
- if (this.isOperator(key)) {
2269
- return this.buildOperatorExpression(key, value, params);
2270
- }
2271
- return this.buildFunctionCall(key, value, params);
2272
- }
2273
- }
2274
- return field;
2275
- };
2276
- ConditionBuilder.prototype.buildFunctionCall = function (fn, value, params) {
2277
- var args = Array.isArray(value) ? value : [value];
2278
- var normalized = this.normalizeFunctionField(__spreadArray([fn], args, true), params);
2279
- return this.buildAggregateField(normalized, params);
2280
- };
2281
2680
  ConditionBuilder.prototype.serializeOperand = function (operand, params, contextColumn) {
2282
2681
  var _a;
2283
2682
  var _this = this;
@@ -2292,18 +2691,14 @@ var ConditionBuilder = /** @class */ (function (_super) {
2292
2691
  return { sql: asParam(operand), isReference: false, isExpression: false, isSubSelect: false };
2293
2692
  }
2294
2693
  if (typeof operand === 'string') {
2295
- if (this.isTableReference(operand) || this.isColumnRef(operand)) {
2296
- return { sql: operand, isReference: true, isExpression: false, isSubSelect: false };
2694
+ var trimmed = operand.trim();
2695
+ if (this.isReferenceExpression(trimmed) || this.isTableReference(trimmed) || this.isColumnRef(trimmed)) {
2696
+ return { sql: trimmed, isReference: true, isExpression: false, isSubSelect: false };
2297
2697
  }
2298
- if (this.looksLikeSafeFunctionExpression(operand)) {
2299
- return { sql: operand.trim(), isReference: false, isExpression: true, isSubSelect: false };
2300
- }
2301
- return { sql: asParam(operand), isReference: false, isExpression: false, isSubSelect: false };
2698
+ throw new Error("Bare string '".concat(operand, "' is not a reference. Wrap literal strings with [C6C.LIT, value]."));
2302
2699
  }
2303
2700
  if (Array.isArray(operand)) {
2304
- var normalized = this.normalizeFunctionField(operand, params);
2305
- var sql = this.buildAggregateField(normalized, params);
2306
- return { sql: sql, isReference: false, isExpression: true, isSubSelect: false };
2701
+ return this.serializeExpression(operand, params, 'SQL expression', contextColumn);
2307
2702
  }
2308
2703
  if (operand instanceof Map) {
2309
2704
  operand = Object.fromEntries(operand);
@@ -2321,24 +2716,38 @@ var ConditionBuilder = /** @class */ (function (_super) {
2321
2716
  if (entries.length === 1) {
2322
2717
  var _b = entries[0], key = _b[0], value = _b[1];
2323
2718
  if (this.isOperator(key)) {
2324
- var sql_1 = this.buildOperatorExpression(key, value, params);
2325
- return { sql: this.ensureWrapped(sql_1), isReference: false, isExpression: true, isSubSelect: false };
2719
+ var sql = this.buildOperatorExpression(key, value, params);
2720
+ return { sql: this.ensureWrapped(sql), isReference: false, isExpression: true, isSubSelect: false };
2326
2721
  }
2327
2722
  if (this.BOOLEAN_OPERATORS.has(key)) {
2328
- var sql_2 = this.buildBooleanExpression((_a = {}, _a[key] = value, _a), params, 'AND');
2329
- return { sql: this.ensureWrapped(sql_2), isReference: false, isExpression: true, isSubSelect: false };
2723
+ var sql = this.buildBooleanExpression((_a = {}, _a[key] = value, _a), params, 'AND');
2724
+ return { sql: this.ensureWrapped(sql), isReference: false, isExpression: true, isSubSelect: false };
2330
2725
  }
2331
- var sql = this.buildFunctionCall(key, value, params);
2332
- return { sql: sql, isReference: false, isExpression: true, isSubSelect: false };
2726
+ throw new Error('Object-rooted expressions are not supported. Use tuple syntax instead.');
2333
2727
  }
2334
2728
  }
2335
2729
  throw new Error('Unsupported operand type in SQL expression.');
2336
2730
  };
2731
+ ConditionBuilder.prototype.isExpressionTuple = function (value) {
2732
+ if (!Array.isArray(value) || value.length === 0 || typeof value[0] !== 'string') {
2733
+ return false;
2734
+ }
2735
+ var token = String(value[0]).toUpperCase();
2736
+ return (token === C6C.AS
2737
+ || token === C6C.DISTINCT
2738
+ || token === C6C.CALL
2739
+ || token === C6C.LIT
2740
+ || token === C6C.PARAM
2741
+ || token === C6C.SUBSELECT
2742
+ || this.isKnownFunction(value[0]));
2743
+ };
2337
2744
  ConditionBuilder.prototype.isPlainArrayLiteral = function (value, allowColumnRefs) {
2338
2745
  var _this = this;
2339
2746
  if (allowColumnRefs === void 0) { allowColumnRefs = false; }
2340
2747
  if (!Array.isArray(value))
2341
2748
  return false;
2749
+ if (this.isExpressionTuple(value))
2750
+ return false;
2342
2751
  return value.every(function (item) {
2343
2752
  if (item === null)
2344
2753
  return true;
@@ -2408,6 +2817,16 @@ var ConditionBuilder = /** @class */ (function (_super) {
2408
2817
  || this.isPlainObjectLiteral(normalized, allowColumnRefs)) {
2409
2818
  return this.addParam(params, contextColumn !== null && contextColumn !== void 0 ? contextColumn : '', JSON.stringify(normalized));
2410
2819
  }
2820
+ if (normalized === C6C.NULL
2821
+ || normalized === null
2822
+ || typeof normalized === 'string'
2823
+ || typeof normalized === 'number'
2824
+ || typeof normalized === 'boolean'
2825
+ || normalized instanceof Date
2826
+ || (typeof Buffer !== 'undefined' && Buffer.isBuffer && Buffer.isBuffer(normalized))) {
2827
+ var scalar = normalized === C6C.NULL ? null : normalized;
2828
+ return this.addParam(params, contextColumn !== null && contextColumn !== void 0 ? contextColumn : '', scalar);
2829
+ }
2411
2830
  var sql;
2412
2831
  var isReference;
2413
2832
  var isExpression;
@@ -2491,7 +2910,10 @@ var ConditionBuilder = /** @class */ (function (_super) {
2491
2910
  }
2492
2911
  var payload = this.ensurePlainObject(payloadRaw);
2493
2912
  var subSelect;
2494
- if (payload && typeof payload === 'object' && C6C.SUBSELECT in payload) {
2913
+ if (Array.isArray(payload) && payload.length === 2 && String(payload[0]).toUpperCase() === C6C.SUBSELECT) {
2914
+ subSelect = this.ensurePlainObject(payload[1]);
2915
+ }
2916
+ else if (payload && typeof payload === 'object' && C6C.SUBSELECT in payload) {
2495
2917
  subSelect = this.ensurePlainObject(payload[C6C.SUBSELECT]);
2496
2918
  }
2497
2919
  else if (payload && typeof payload === 'object') {
@@ -2585,7 +3007,11 @@ var ConditionBuilder = /** @class */ (function (_super) {
2585
3007
  throw new Error('MATCH_AGAINST expects an array [search, mode?].');
2586
3008
  }
2587
3009
  var search = right[0], mode = right[1];
2588
- var placeholder = this.addParam(params, leftInfo_1.sql, search);
3010
+ var searchInfo = this.serializeOperand(search, params, leftInfo_1.sql);
3011
+ if (searchInfo.isReference || searchInfo.isExpression || searchInfo.isSubSelect) {
3012
+ throw new Error('MATCH_AGAINST search payload must be a literal value (wrap strings with [C6C.LIT, value]).');
3013
+ }
3014
+ var placeholder = searchInfo.sql;
2589
3015
  var againstClause = void 0;
2590
3016
  switch (typeof mode === 'string' ? mode.toUpperCase() : '') {
2591
3017
  case 'BOOLEAN':
@@ -2687,7 +3113,7 @@ var ConditionBuilder = /** @class */ (function (_super) {
2687
3113
  if (!Array.isArray(value)) {
2688
3114
  throw new Error("".concat(column, " expects an array of arguments."));
2689
3115
  }
2690
- return this.buildFunctionCall(column, value, params);
3116
+ return this.serializeExpression(__spreadArray([column], value, true), params, "WHERE function ".concat(column), column).sql;
2691
3117
  }
2692
3118
  }
2693
3119
  if (typeof Buffer !== 'undefined' && Buffer.isBuffer && Buffer.isBuffer(value)) {
@@ -3130,56 +3556,34 @@ var PaginationBuilder = /** @class */ (function (_super) {
3130
3556
  *
3131
3557
  * Accepted structures:
3132
3558
  * ```ts
3133
- * ORDER: {
3134
- * // simple column with direction
3135
- * [property_units.UNIT_ID]: "DESC",
3136
- * // function call (array of arguments)
3137
- * [C6Constants.ST_DISTANCE_SPHERE]: [property_units.LOCATION, F(property_units.LOCATION, "pu_target")]
3138
- * }
3559
+ * ORDER: [
3560
+ * [property_units.UNIT_ID, "DESC"],
3561
+ * [[C6Constants.ST_DISTANCE_SPHERE, property_units.LOCATION, F(property_units.LOCATION, "pu_target")], "ASC"],
3562
+ * ]
3139
3563
  * ```
3140
3564
  */
3141
3565
  PaginationBuilder.prototype.buildPaginationClause = function (pagination, params) {
3142
- var _this = this;
3143
3566
  var sql = "";
3144
3567
  /* -------- ORDER BY -------- */
3145
3568
  if (pagination === null || pagination === void 0 ? void 0 : pagination[C6Constants.ORDER]) {
3146
3569
  var orderParts = [];
3147
- var _loop_1 = function (key, val) {
3148
- if (typeof key === 'string' && key.includes('.')) {
3149
- this_1.assertValidIdentifier(key, 'ORDER BY');
3150
- }
3151
- // FUNCTION CALL: val is an array of args
3152
- if (Array.isArray(val)) {
3153
- var identifierPathRegex_1 = /^[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*$/;
3154
- var isNumericString_1 = function (s) { return /^-?\d+(?:\.\d+)?$/.test(s.trim()); };
3155
- var args = val
3156
- .map(function (arg) {
3157
- if (Array.isArray(arg))
3158
- return _this.buildAggregateField(arg, params);
3159
- if (typeof arg === 'string') {
3160
- if (identifierPathRegex_1.test(arg)) {
3161
- _this.assertValidIdentifier(arg, 'ORDER BY argument');
3162
- return arg;
3163
- }
3164
- // numeric-looking strings should be treated as literals
3165
- if (isNumericString_1(arg))
3166
- return arg;
3167
- return arg;
3168
- }
3169
- return String(arg);
3170
- })
3171
- .join(", ");
3172
- orderParts.push("".concat(key, "(").concat(args, ")"));
3173
- }
3174
- // SIMPLE COLUMN + DIR (ASC/DESC)
3175
- else {
3176
- orderParts.push("".concat(key, " ").concat(String(val).toUpperCase()));
3570
+ var orderSpec = pagination[C6Constants.ORDER];
3571
+ if (!Array.isArray(orderSpec)) {
3572
+ throw new Error('PAGINATION.ORDER expects an array of terms using [expression, direction?] syntax.');
3573
+ }
3574
+ for (var _i = 0, orderSpec_1 = orderSpec; _i < orderSpec_1.length; _i++) {
3575
+ var rawTerm = orderSpec_1[_i];
3576
+ var expression = rawTerm;
3577
+ var direction = C6Constants.ASC;
3578
+ if (Array.isArray(rawTerm)
3579
+ && rawTerm.length === 2
3580
+ && typeof rawTerm[1] === 'string'
3581
+ && (String(rawTerm[1]).toUpperCase() === C6Constants.ASC || String(rawTerm[1]).toUpperCase() === C6Constants.DESC)) {
3582
+ expression = rawTerm[0];
3583
+ direction = String(rawTerm[1]).toUpperCase();
3177
3584
  }
3178
- };
3179
- var this_1 = this;
3180
- for (var _i = 0, _a = Object.entries(pagination[C6Constants.ORDER]); _i < _a.length; _i++) {
3181
- var _b = _a[_i], key = _b[0], val = _b[1];
3182
- _loop_1(key, val);
3585
+ var serialized = this.serializeExpression(expression, params, 'ORDER BY expression');
3586
+ orderParts.push("".concat(serialized.sql, " ").concat(direction));
3183
3587
  }
3184
3588
  if (orderParts.length)
3185
3589
  sql += " ORDER BY ".concat(orderParts.join(", "));
@@ -3469,7 +3873,7 @@ function normalizeSingularRequest(requestMethod, request, restModel, removedPrim
3469
3873
  throw new Error("Singular request requires all primary key(s) [".concat(pkShorts.join(', '), "] for table (").concat(restModel.TABLE_NAME, "). Missing: [").concat(missing.join(', '), "]"));
3470
3874
  }
3471
3875
  // Strip API metadata that should remain at root
3472
- var _d = request, dataInsertMultipleRows = _d.dataInsertMultipleRows, cacheResults = _d.cacheResults, fetchDependencies = _d.fetchDependencies, debug = _d.debug, success = _d.success, error = _d.error, rest = __rest(_d, ["dataInsertMultipleRows", "cacheResults", "fetchDependencies", "debug", "success", "error"]);
3876
+ var _d = request, dataInsertMultipleRows = _d.dataInsertMultipleRows, cacheResults = _d.cacheResults, skipReactBootstrap = _d.skipReactBootstrap, fetchDependencies = _d.fetchDependencies, debug = _d.debug, success = _d.success, error = _d.error, rest = __rest(_d, ["dataInsertMultipleRows", "cacheResults", "skipReactBootstrap", "fetchDependencies", "debug", "success", "error"]);
3473
3877
  // Map short primary keys to fully-qualified column names
3474
3878
  var shortToFull = {};
3475
3879
  for (var _e = 0, _f = Object.entries(restModel.COLUMNS || {}); _e < _f.length; _e++) {
@@ -3481,22 +3885,26 @@ function normalizeSingularRequest(requestMethod, request, restModel, removedPrim
3481
3885
  var k = _a[0], v = _a[1];
3482
3886
  return [(_b = shortToFull[k]) !== null && _b !== void 0 ? _b : k, v];
3483
3887
  }));
3888
+ var pkWhereExpressions = Object.fromEntries(Object.entries(pkFullValues).map(function (_a) {
3889
+ var column = _a[0], value = _a[1];
3890
+ return [column, [C6Constants.EQUAL, [C6Constants.LIT, value]]];
3891
+ }));
3484
3892
  if (requestMethod === C6Constants.GET) {
3485
3893
  var normalized_1 = {
3486
- WHERE: __assign({}, pkFullValues),
3894
+ WHERE: __assign({}, pkWhereExpressions),
3487
3895
  };
3488
3896
  // Preserve pagination if any was added previously
3489
3897
  if (request[C6Constants.PAGINATION]) {
3490
3898
  normalized_1[C6Constants.PAGINATION] = request[C6Constants.PAGINATION];
3491
3899
  }
3492
- return __assign(__assign({}, normalized_1), { dataInsertMultipleRows: dataInsertMultipleRows, cacheResults: cacheResults, fetchDependencies: fetchDependencies, debug: debug, success: success, error: error });
3900
+ return __assign(__assign({}, normalized_1), { dataInsertMultipleRows: dataInsertMultipleRows, cacheResults: cacheResults, skipReactBootstrap: skipReactBootstrap, fetchDependencies: fetchDependencies, debug: debug, success: success, error: error });
3493
3901
  }
3494
3902
  if (requestMethod === C6Constants.DELETE) {
3495
3903
  var normalized_2 = (_a = {},
3496
3904
  _a[C6Constants.DELETE] = true,
3497
- _a.WHERE = __assign({}, pkFullValues),
3905
+ _a.WHERE = __assign({}, pkWhereExpressions),
3498
3906
  _a);
3499
- return __assign(__assign({}, normalized_2), { dataInsertMultipleRows: dataInsertMultipleRows, cacheResults: cacheResults, fetchDependencies: fetchDependencies, debug: debug, success: success, error: error });
3907
+ return __assign(__assign({}, normalized_2), { dataInsertMultipleRows: dataInsertMultipleRows, cacheResults: cacheResults, skipReactBootstrap: skipReactBootstrap, fetchDependencies: fetchDependencies, debug: debug, success: success, error: error });
3500
3908
  }
3501
3909
  // PUT
3502
3910
  var updateBody = {};
@@ -3515,11 +3923,12 @@ function normalizeSingularRequest(requestMethod, request, restModel, removedPrim
3515
3923
  }
3516
3924
  var normalized = (_b = {},
3517
3925
  _b[C6Constants.UPDATE] = updateBody,
3518
- _b.WHERE = __assign({}, pkFullValues),
3926
+ _b.WHERE = __assign({}, pkWhereExpressions),
3519
3927
  _b);
3520
- return __assign(__assign({}, normalized), { dataInsertMultipleRows: dataInsertMultipleRows, cacheResults: cacheResults, fetchDependencies: fetchDependencies, debug: debug, success: success, error: error });
3928
+ return __assign(__assign({}, normalized), { dataInsertMultipleRows: dataInsertMultipleRows, cacheResults: cacheResults, skipReactBootstrap: skipReactBootstrap, fetchDependencies: fetchDependencies, debug: debug, success: success, error: error });
3521
3929
  }
3522
3930
 
3931
+ var DEFAULT_NORMALIZER_CACHE_KEY = "__default__";
3523
3932
  var allowListCache = new Map();
3524
3933
  var ANSI_ESCAPE_REGEX = /\x1b\[[0-9;]*m/g;
3525
3934
  var COLLAPSED_BIND_ROW_REGEX = /\(\?\s*×\d+\)/g;
@@ -3571,7 +3980,17 @@ var normalizeSql = function (sql) {
3571
3980
  normalized = normalized.replace(/;\s*$/, "");
3572
3981
  return normalized.replace(/\s+/g, " ").trim();
3573
3982
  };
3574
- var parseAllowList = function (raw, sourcePath) {
3983
+ var normalizeSqlWith = function (sql, sqlQueryNormalizer) {
3984
+ var normalized = normalizeSql(sql);
3985
+ if (!sqlQueryNormalizer)
3986
+ return normalized;
3987
+ var customized = sqlQueryNormalizer(normalized);
3988
+ if (typeof customized !== "string") {
3989
+ throw new Error("sqlQueryNormalizer must return a string.");
3990
+ }
3991
+ return customized.replace(/\s+/g, " ").trim();
3992
+ };
3993
+ var parseAllowList = function (raw, sourcePath, sqlQueryNormalizer) {
3575
3994
  var parsed;
3576
3995
  try {
3577
3996
  parsed = JSON.parse(raw);
@@ -3584,59 +4003,63 @@ var parseAllowList = function (raw, sourcePath) {
3584
4003
  }
3585
4004
  var sqlEntries = parsed
3586
4005
  .filter(function (entry) { return typeof entry === "string"; })
3587
- .map(normalizeSql)
4006
+ .map(function (entry) { return normalizeSqlWith(entry, sqlQueryNormalizer); })
3588
4007
  .filter(function (entry) { return entry.length > 0; });
3589
4008
  if (sqlEntries.length !== parsed.length) {
3590
4009
  throw new Error("SQL allowlist at ".concat(sourcePath, " must contain only string entries."));
3591
4010
  }
3592
4011
  return sqlEntries;
3593
4012
  };
3594
- var loadSqlAllowList = function (allowListPath) { return __awaiter(void 0, void 0, void 0, function () {
3595
- var _a, readFile, stat, fileStat, cached, raw, sqlEntries, allowList;
3596
- return __generator(this, function (_b) {
3597
- switch (_b.label) {
4013
+ var loadSqlAllowList = function (allowListPath, sqlQueryNormalizer) { return __awaiter(void 0, void 0, void 0, function () {
4014
+ var _a, readFile, stat, fileStat, pathCache, cacheKey, cached, raw, sqlEntries, allowList;
4015
+ var _b;
4016
+ return __generator(this, function (_c) {
4017
+ switch (_c.label) {
3598
4018
  case 0:
3599
4019
  if (!isNode()) {
3600
4020
  throw new Error("SQL allowlist validation requires a Node runtime.");
3601
4021
  }
3602
4022
  return [4 /*yield*/, import('node:fs/promises')];
3603
4023
  case 1:
3604
- _a = _b.sent(), readFile = _a.readFile, stat = _a.stat;
3605
- _b.label = 2;
4024
+ _a = _c.sent(), readFile = _a.readFile, stat = _a.stat;
4025
+ _c.label = 2;
3606
4026
  case 2:
3607
- _b.trys.push([2, 4, , 5]);
4027
+ _c.trys.push([2, 4, , 5]);
3608
4028
  return [4 /*yield*/, stat(allowListPath)];
3609
4029
  case 3:
3610
- fileStat = _b.sent();
4030
+ fileStat = _c.sent();
3611
4031
  return [3 /*break*/, 5];
3612
4032
  case 4:
3613
- _b.sent();
4033
+ _c.sent();
3614
4034
  throw new Error("SQL allowlist file not found at ".concat(allowListPath, "."));
3615
4035
  case 5:
3616
- cached = allowListCache.get(allowListPath);
4036
+ pathCache = (_b = allowListCache.get(allowListPath)) !== null && _b !== void 0 ? _b : new Map();
4037
+ cacheKey = sqlQueryNormalizer !== null && sqlQueryNormalizer !== void 0 ? sqlQueryNormalizer : DEFAULT_NORMALIZER_CACHE_KEY;
4038
+ cached = pathCache.get(cacheKey);
3617
4039
  if (cached &&
3618
4040
  cached.mtimeMs === fileStat.mtimeMs &&
3619
4041
  cached.size === fileStat.size) {
3620
4042
  return [2 /*return*/, cached.allowList];
3621
4043
  }
3622
- _b.label = 6;
4044
+ _c.label = 6;
3623
4045
  case 6:
3624
- _b.trys.push([6, 8, , 9]);
4046
+ _c.trys.push([6, 8, , 9]);
3625
4047
  return [4 /*yield*/, readFile(allowListPath, "utf-8")];
3626
4048
  case 7:
3627
- raw = _b.sent();
4049
+ raw = _c.sent();
3628
4050
  return [3 /*break*/, 9];
3629
4051
  case 8:
3630
- _b.sent();
4052
+ _c.sent();
3631
4053
  throw new Error("SQL allowlist file not found at ".concat(allowListPath, "."));
3632
4054
  case 9:
3633
- sqlEntries = parseAllowList(raw, allowListPath);
4055
+ sqlEntries = parseAllowList(raw, allowListPath, sqlQueryNormalizer);
3634
4056
  allowList = new Set(sqlEntries);
3635
- allowListCache.set(allowListPath, {
4057
+ pathCache.set(cacheKey, {
3636
4058
  allowList: allowList,
3637
4059
  mtimeMs: fileStat.mtimeMs,
3638
4060
  size: fileStat.size,
3639
4061
  });
4062
+ allowListCache.set(allowListPath, pathCache);
3640
4063
  return [2 /*return*/, allowList];
3641
4064
  }
3642
4065
  });
@@ -3663,15 +4086,15 @@ var extractSqlEntries = function (payload) {
3663
4086
  }
3664
4087
  return [];
3665
4088
  };
3666
- var collectSqlAllowListEntries = function (payload, entries) {
4089
+ var collectSqlAllowListEntries = function (payload, entries, sqlQueryNormalizer) {
3667
4090
  if (entries === void 0) { entries = new Set(); }
3668
4091
  var sqlEntries = extractSqlEntries(payload)
3669
- .map(normalizeSql)
4092
+ .map(function (entry) { return normalizeSqlWith(entry, sqlQueryNormalizer); })
3670
4093
  .filter(function (entry) { return entry.length > 0; });
3671
4094
  sqlEntries.forEach(function (entry) { return entries.add(entry); });
3672
4095
  return entries;
3673
4096
  };
3674
- var compileSqlAllowList = function (allowListPath, entries) { return __awaiter(void 0, void 0, void 0, function () {
4097
+ var compileSqlAllowList = function (allowListPath, entries, sqlQueryNormalizer) { return __awaiter(void 0, void 0, void 0, function () {
3675
4098
  var _a, writeFile, mkdir, path, compiled;
3676
4099
  return __generator(this, function (_b) {
3677
4100
  switch (_b.label) {
@@ -3689,7 +4112,7 @@ var compileSqlAllowList = function (allowListPath, entries) { return __awaiter(v
3689
4112
  case 3:
3690
4113
  _b.sent();
3691
4114
  compiled = Array.from(new Set(Array.from(entries)
3692
- .map(normalizeSql)
4115
+ .map(function (entry) { return normalizeSqlWith(entry, sqlQueryNormalizer); })
3693
4116
  .filter(function (entry) { return entry.length > 0; }))).sort();
3694
4117
  return [4 /*yield*/, writeFile(allowListPath, JSON.stringify(compiled, null, 2))];
3695
4118
  case 4:
@@ -4065,6 +4488,7 @@ var SqlExecutor = /** @class */ (function (_super) {
4065
4488
  C6Constants.REPLACE,
4066
4489
  "dataInsertMultipleRows",
4067
4490
  "cacheResults",
4491
+ "skipReactBootstrap",
4068
4492
  "fetchDependencies",
4069
4493
  "debug",
4070
4494
  "success",
@@ -4148,9 +4572,10 @@ var SqlExecutor = /** @class */ (function (_super) {
4148
4572
  }
4149
4573
  }
4150
4574
  if (value !== undefined) {
4151
- pkValues[pkShort] = value;
4575
+ pkValues[pkShort] = this_1.unwrapPrimaryKeyValue(value);
4152
4576
  }
4153
4577
  };
4578
+ var this_1 = this;
4154
4579
  for (var _i = 0, primaryShorts_1 = primaryShorts; _i < primaryShorts_1.length; _i++) {
4155
4580
  var pkShort = primaryShorts_1[_i];
4156
4581
  _loop_1(pkShort);
@@ -4160,6 +4585,26 @@ var SqlExecutor = /** @class */ (function (_super) {
4160
4585
  }
4161
4586
  return Object.keys(pkValues).length > 0 ? pkValues : null;
4162
4587
  };
4588
+ SqlExecutor.prototype.unwrapPrimaryKeyValue = function (value) {
4589
+ if (!Array.isArray(value))
4590
+ return value;
4591
+ if (value.length === 2) {
4592
+ var head = value[0], tail = value[1];
4593
+ if (head === C6Constants.EQUAL) {
4594
+ return this.unwrapPrimaryKeyValue(tail);
4595
+ }
4596
+ if (head === C6Constants.LIT || head === C6Constants.PARAM) {
4597
+ return tail;
4598
+ }
4599
+ }
4600
+ if (value.length === 3) {
4601
+ var operator = value[1], right = value[2];
4602
+ if (operator === C6Constants.EQUAL) {
4603
+ return this.unwrapPrimaryKeyValue(right);
4604
+ }
4605
+ }
4606
+ return value;
4607
+ };
4163
4608
  SqlExecutor.prototype.extractPrimaryKeyValuesFromData = function (data) {
4164
4609
  if (!data)
4165
4610
  return null;
@@ -4520,7 +4965,7 @@ var SqlExecutor = /** @class */ (function (_super) {
4520
4965
  };
4521
4966
  SqlExecutor.prototype.validateSqlAllowList = function (sql) {
4522
4967
  return __awaiter(this, void 0, void 0, function () {
4523
- var allowListPath, allowList, normalized;
4968
+ var allowListPath, sqlQueryNormalizer, allowList, normalized;
4524
4969
  var _a;
4525
4970
  return __generator(this, function (_b) {
4526
4971
  switch (_b.label) {
@@ -4529,10 +4974,11 @@ var SqlExecutor = /** @class */ (function (_super) {
4529
4974
  if (!allowListPath) {
4530
4975
  return [2 /*return*/, "not verified"];
4531
4976
  }
4532
- return [4 /*yield*/, loadSqlAllowList(allowListPath)];
4977
+ sqlQueryNormalizer = this.config.sqlQueryNormalizer;
4978
+ return [4 /*yield*/, loadSqlAllowList(allowListPath, sqlQueryNormalizer)];
4533
4979
  case 1:
4534
4980
  allowList = _b.sent();
4535
- normalized = normalizeSql(sql);
4981
+ normalized = normalizeSqlWith(sql, sqlQueryNormalizer);
4536
4982
  if (!allowList.has(normalized)) {
4537
4983
  throw createSqlAllowListBlockedError({
4538
4984
  tableName: typeof ((_a = this.config.restModel) === null || _a === void 0 ? void 0 : _a.TABLE_NAME) === "string"
@@ -4780,5 +5226,5 @@ function isVerbose() {
4780
5226
  return resolveLogLevel() >= LogLevel.DEBUG;
4781
5227
  }
4782
5228
 
4783
- export { A, AggregateBuilder, C6C, C6Constants, ConditionBuilder, DELETE, DeleteQueryBuilder, Executor, ExpressHandler, F, GET, HttpExecutor, JoinBuilder, LogLevel, POST, PUT, PaginationBuilder, PostQueryBuilder, SelectQueryBuilder, SqlExecutor, TestRestfulResponse, UpdateQueryBuilder, apiRequestCache, applyLogLevelDefaults, axiosInstance, bbox, carbonNodeQsStringify, checkAllRequestsComplete, checkCache, clearCache, collectSqlAllowListEntries, colorSql, compileSqlAllowList, convertForRequestBody, convertHexIfBinary, derivedTable, determineRuntimeJsType, distSphere, eFetchDependencies, error, evictCacheEntry, extractSqlEntries, fieldEq, getEnv, getEnvBool, getEnvDebug, getEnvLogLevel, getLogContext, getPrimaryKeyTypes, group, info, isDerivedTableKey, isLocal, isNode, isTest, isVerbose, loadSqlAllowList, logSql, logWithLevel, normalizeSingularRequest, normalizeSql, notifyToast, onError, onSuccess, parseLogLevel, removeInvalidKeys, removePrefixIfExists, resolveDerivedTable, resolveLogLevel, restExpressRequest, restOrm, restRequest, setCache, setToastHandler, shouldLog, sortAndSerializeQueryObject, stContains, timeout, toastOptions, toastOptionsDevs, userCustomClearCache, versionToRgb as versionColor, warn };
5229
+ export { A, AggregateBuilder, C6C, C6Constants, ConditionBuilder, DELETE, DeleteQueryBuilder, Executor, ExpressHandler, F, GET, HttpExecutor, JoinBuilder, LogLevel, POST, PUT, PaginationBuilder, PostQueryBuilder, SQL_KNOWN_FUNCTIONS, SelectQueryBuilder, SqlExecutor, TestRestfulResponse, UpdateQueryBuilder, alias, apiRequestCache, applyLogLevelDefaults, axiosInstance, bbox, call, carbonNodeQsStringify, checkAllRequestsComplete, checkCache, clearCache, collectSqlAllowListEntries, colorSql, compileSqlAllowList, convertForRequestBody, convertHexIfBinary, convertSqlValueForColumn, derivedTable, determineRuntimeJsType, distSphere, distinct, eFetchDependencies, error, evictCacheEntry, extractSqlEntries, fieldEq, fn, getEnv, getEnvBool, getEnvDebug, getEnvLogLevel, getLogContext, getPrimaryKeyTypes, group, info, isDerivedTableKey, isLocal, isNode, isTest, isVerbose, lit, loadSqlAllowList, logSql, logWithLevel, normalizeSingularRequest, normalizeSql, normalizeSqlWith, notifyToast, onError, onSuccess, order, parseLogLevel, removeInvalidKeys, removePrefixIfExists, resolveDerivedTable, resolveLogLevel, restExpressRequest, restOrm, restRequest, serializeSqlExpression, setCache, setToastHandler, shouldLog, sortAndSerializeQueryObject, stContains, timeout, toastOptions, toastOptionsDevs, userCustomClearCache, versionToRgb as versionColor, warn };
4784
5230
  //# sourceMappingURL=index.esm.js.map