@carbonorm/carbonnode 6.0.12 → 6.0.13

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 (73) hide show
  1. package/dist/executors/SqlExecutor.d.ts +1 -0
  2. package/dist/handlers/ExpressHandler.d.ts +6 -14
  3. package/dist/index.cjs.js +164 -40
  4. package/dist/index.cjs.js.map +1 -1
  5. package/dist/index.esm.js +164 -40
  6. package/dist/index.esm.js.map +1 -1
  7. package/dist/types/ormInterfaces.d.ts +13 -3
  8. package/dist/utils/cacheManager.d.ts +2 -3
  9. package/package.json +1 -1
  10. package/src/__tests__/convertForRequestBody.test.ts +58 -0
  11. package/src/__tests__/expressServer.e2e.test.ts +62 -38
  12. package/src/__tests__/fixtures/createTestServer.ts +7 -3
  13. package/src/__tests__/httpExecutorSingular.e2e.test.ts +97 -60
  14. package/src/__tests__/logSql.test.ts +13 -0
  15. package/src/__tests__/sakila-db/C6.js +1 -1
  16. package/src/__tests__/sakila-db/C6.mysqldump.json +1 -1
  17. package/src/__tests__/sakila-db/C6.mysqldump.sql +1 -1
  18. package/src/__tests__/sakila-db/C6.sqlAllowList.json +11 -11
  19. package/src/__tests__/sakila-db/C6.ts +1 -1
  20. package/src/__tests__/sakila-db/sqlResponses/C6.actor.post.json +4 -4
  21. package/src/__tests__/sakila-db/sqlResponses/C6.actor.post.latest.json +3 -3
  22. package/src/__tests__/sakila-db/sqlResponses/C6.actor.put.json +1 -1
  23. package/src/__tests__/sakila-db/sqlResponses/C6.actor.put.lookup.json +3 -3
  24. package/src/__tests__/sakila-db/sqlResponses/C6.address.post.json +6 -6
  25. package/src/__tests__/sakila-db/sqlResponses/C6.address.post.latest.json +5 -5
  26. package/src/__tests__/sakila-db/sqlResponses/C6.address.put.json +1 -1
  27. package/src/__tests__/sakila-db/sqlResponses/C6.address.put.lookup.json +5 -5
  28. package/src/__tests__/sakila-db/sqlResponses/C6.category.post.json +3 -3
  29. package/src/__tests__/sakila-db/sqlResponses/C6.category.post.latest.json +2 -2
  30. package/src/__tests__/sakila-db/sqlResponses/C6.category.put.json +1 -1
  31. package/src/__tests__/sakila-db/sqlResponses/C6.category.put.lookup.json +2 -2
  32. package/src/__tests__/sakila-db/sqlResponses/C6.city.post.json +3 -3
  33. package/src/__tests__/sakila-db/sqlResponses/C6.city.post.latest.json +2 -2
  34. package/src/__tests__/sakila-db/sqlResponses/C6.city.put.json +1 -1
  35. package/src/__tests__/sakila-db/sqlResponses/C6.city.put.lookup.json +2 -2
  36. package/src/__tests__/sakila-db/sqlResponses/C6.country.post.json +3 -3
  37. package/src/__tests__/sakila-db/sqlResponses/C6.country.post.latest.json +2 -2
  38. package/src/__tests__/sakila-db/sqlResponses/C6.country.put.json +1 -1
  39. package/src/__tests__/sakila-db/sqlResponses/C6.country.put.lookup.json +2 -2
  40. package/src/__tests__/sakila-db/sqlResponses/C6.customer.post.json +6 -6
  41. package/src/__tests__/sakila-db/sqlResponses/C6.customer.post.latest.json +5 -5
  42. package/src/__tests__/sakila-db/sqlResponses/C6.customer.put.json +1 -1
  43. package/src/__tests__/sakila-db/sqlResponses/C6.customer.put.lookup.json +5 -5
  44. package/src/__tests__/sakila-db/sqlResponses/C6.film.post.json +3 -3
  45. package/src/__tests__/sakila-db/sqlResponses/C6.film.post.latest.json +2 -2
  46. package/src/__tests__/sakila-db/sqlResponses/C6.film.put.json +1 -1
  47. package/src/__tests__/sakila-db/sqlResponses/C6.film.put.lookup.json +2 -2
  48. package/src/__tests__/sakila-db/sqlResponses/C6.inventory.post.json +2 -2
  49. package/src/__tests__/sakila-db/sqlResponses/C6.inventory.post.latest.json +1 -1
  50. package/src/__tests__/sakila-db/sqlResponses/C6.inventory.put.json +1 -1
  51. package/src/__tests__/sakila-db/sqlResponses/C6.inventory.put.lookup.json +1 -1
  52. package/src/__tests__/sakila-db/sqlResponses/C6.language.post.json +3 -3
  53. package/src/__tests__/sakila-db/sqlResponses/C6.language.post.latest.json +2 -2
  54. package/src/__tests__/sakila-db/sqlResponses/C6.language.put.json +1 -1
  55. package/src/__tests__/sakila-db/sqlResponses/C6.language.put.lookup.json +2 -2
  56. package/src/__tests__/sakila-db/sqlResponses/C6.payment.post.json +3 -3
  57. package/src/__tests__/sakila-db/sqlResponses/C6.payment.post.latest.json +2 -2
  58. package/src/__tests__/sakila-db/sqlResponses/C6.payment.put.lookup.json +2 -2
  59. package/src/__tests__/sakila-db/sqlResponses/C6.rental.post.json +4 -4
  60. package/src/__tests__/sakila-db/sqlResponses/C6.rental.post.latest.json +3 -3
  61. package/src/__tests__/sakila-db/sqlResponses/C6.rental.put.json +1 -1
  62. package/src/__tests__/sakila-db/sqlResponses/C6.rental.put.lookup.json +3 -3
  63. package/src/__tests__/sqlBuilders.test.ts +46 -0
  64. package/src/api/convertForRequestBody.ts +9 -2
  65. package/src/api/restRequest.ts +1 -0
  66. package/src/executors/HttpExecutor.ts +1 -1
  67. package/src/executors/SqlExecutor.ts +64 -2
  68. package/src/handlers/ExpressHandler.ts +50 -39
  69. package/src/orm/builders/ConditionBuilder.ts +43 -1
  70. package/src/orm/queries/PostQueryBuilder.ts +24 -12
  71. package/src/types/ormInterfaces.ts +15 -3
  72. package/src/utils/cacheManager.ts +3 -4
  73. package/src/utils/colorSql.ts +18 -0
package/dist/index.esm.js CHANGED
@@ -533,7 +533,11 @@ var logWithLevel = function (requiredLevel, context, logger) {
533
533
  };
534
534
 
535
535
  function convertForRequestBody (restfulObject, tableName, C6, regexErrorHandler) {
536
- if (regexErrorHandler === void 0) { regexErrorHandler = alert; }
536
+ if (regexErrorHandler === void 0) { regexErrorHandler = function (message) {
537
+ if (typeof globalThis !== "undefined" && typeof globalThis.alert === "function") {
538
+ globalThis.alert(message);
539
+ }
540
+ }; }
537
541
  var payload = {};
538
542
  var tableNames = Array.isArray(tableName) ? tableName : [tableName];
539
543
  var tableDefinitions = tableNames.map(function (name) {
@@ -556,7 +560,8 @@ function convertForRequestBody (restfulObject, tableName, C6, regexErrorHandler)
556
560
  C6Constants.DELETE,
557
561
  C6Constants.WHERE,
558
562
  C6Constants.JOIN,
559
- C6Constants.PAGINATION
563
+ C6Constants.PAGINATION,
564
+ "cacheResults",
560
565
  ].includes(value)) {
561
566
  var val_1 = restfulObject[value];
562
567
  if (Array.isArray(val_1)) {
@@ -570,6 +575,9 @@ function convertForRequestBody (restfulObject, tableName, C6, regexErrorHandler)
570
575
  return (__assign(__assign({}, acc), (_a = {}, _a[key] = val_1[key], _a)));
571
576
  }, {});
572
577
  }
578
+ else {
579
+ payload[value] = val_1;
580
+ }
573
581
  return "continue";
574
582
  }
575
583
  if (shortReference in tableDefinition) {
@@ -901,7 +909,7 @@ function checkCache(method, tableName, requestData) {
901
909
  var cached = apiRequestCache.get(key);
902
910
  if (!cached)
903
911
  return false;
904
- if (shouldLog(LogLevel.DEBUG, undefined)) {
912
+ if (shouldLog(LogLevel.INFO, undefined)) {
905
913
  console.groupCollapsed("%c API cache hit for ".concat(method, " ").concat(tableName), "color:#0c0");
906
914
  console.log("Request Data:", requestData);
907
915
  console.groupEnd();
@@ -2128,14 +2136,51 @@ var ConditionBuilder = /** @class */ (function (_super) {
2128
2136
  return typeof mysqlType === 'string' && mysqlType.toLowerCase().includes('json');
2129
2137
  };
2130
2138
  ConditionBuilder.prototype.serializeUpdateValue = function (value, params, contextColumn) {
2139
+ var _a;
2140
+ var _this = this;
2131
2141
  var normalized = value instanceof Map ? Object.fromEntries(value) : value;
2132
2142
  var allowColumnRefs = this.isJsonColumn(contextColumn);
2133
2143
  if (this.isPlainArrayLiteral(normalized, allowColumnRefs)
2134
2144
  || this.isPlainObjectLiteral(normalized, allowColumnRefs)) {
2135
2145
  return this.addParam(params, contextColumn !== null && contextColumn !== void 0 ? contextColumn : '', JSON.stringify(normalized));
2136
2146
  }
2137
- var _a = this.serializeOperand(normalized, params, contextColumn), sql = _a.sql, isReference = _a.isReference, isExpression = _a.isExpression, isSubSelect = _a.isSubSelect;
2147
+ var sql;
2148
+ var isReference;
2149
+ var isExpression;
2150
+ var isSubSelect;
2151
+ var shouldStringifyObjectFallback = function (candidate) {
2152
+ if (typeof candidate !== 'object'
2153
+ || candidate === null
2154
+ || candidate instanceof Date
2155
+ || (typeof Buffer !== 'undefined' && Buffer.isBuffer && Buffer.isBuffer(candidate))) {
2156
+ return false;
2157
+ }
2158
+ var normalizedCandidate = candidate instanceof Map
2159
+ ? Object.fromEntries(candidate)
2160
+ : candidate;
2161
+ var entries = Object.entries(normalizedCandidate);
2162
+ if (entries.length !== 1) {
2163
+ return true;
2164
+ }
2165
+ var key = entries[0][0];
2166
+ if (_this.isOperator(key) || _this.BOOLEAN_OPERATORS.has(key)) {
2167
+ return false;
2168
+ }
2169
+ return true;
2170
+ };
2171
+ try {
2172
+ (_a = this.serializeOperand(normalized, params, contextColumn), sql = _a.sql, isReference = _a.isReference, isExpression = _a.isExpression, isSubSelect = _a.isSubSelect);
2173
+ }
2174
+ catch (err) {
2175
+ if (shouldStringifyObjectFallback(normalized)) {
2176
+ return this.addParam(params, contextColumn !== null && contextColumn !== void 0 ? contextColumn : '', JSON.stringify(normalized));
2177
+ }
2178
+ throw err;
2179
+ }
2138
2180
  if (!isReference && !isExpression && !isSubSelect && typeof normalized === 'object' && normalized !== null) {
2181
+ if (shouldStringifyObjectFallback(normalized)) {
2182
+ return this.addParam(params, contextColumn !== null && contextColumn !== void 0 ? contextColumn : '', JSON.stringify(normalized));
2183
+ }
2139
2184
  throw new Error('Unsupported operand type in SQL expression.');
2140
2185
  }
2141
2186
  return sql;
@@ -2949,11 +2994,27 @@ function collapseBinds(sql) {
2949
2994
  return "".concat(C$1.DIM, "? \u00D7").concat(count).concat(RESET);
2950
2995
  });
2951
2996
  }
2997
+ /**
2998
+ * ( ? ×9 ), ( ? ×9 ), ( ? ×9 ) -> ( ? ×9 ) ×3
2999
+ */
3000
+ function collapseRepeatedValueRows(sql) {
3001
+ var repeatedRowPattern = /(\((?:\x1b\[[0-9;]*m)?\?\s*×\d+(?:\x1b\[[0-9;]*m)?\)|\(\s*(?:\?\s*,\s*)+\?\s*\))(?:\s*,\s*\1){2,}/g;
3002
+ return sql.replace(repeatedRowPattern, function (match, row) {
3003
+ var _a, _b;
3004
+ var rowMatches = match.match(new RegExp(row.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"));
3005
+ var count = (_a = rowMatches === null || rowMatches === void 0 ? void 0 : rowMatches.length) !== null && _a !== void 0 ? _a : 1;
3006
+ var normalizedRow = row.includes("×")
3007
+ ? row
3008
+ : "(".concat(C$1.DIM, "? \u00D7").concat(((_b = row.match(/\?/g)) !== null && _b !== void 0 ? _b : []).length).concat(RESET, ")");
3009
+ return "".concat(normalizedRow, " ").concat(C$1.DIM, "\u00D7").concat(count).concat(RESET);
3010
+ });
3011
+ }
2952
3012
  /* ---------- main formatter ---------- */
2953
3013
  function colorSql(sql) {
2954
3014
  var s = sql.trim();
2955
3015
  /* 1️⃣ collapse bind noise */
2956
3016
  s = collapseBinds(s);
3017
+ s = collapseRepeatedValueRows(s);
2957
3018
  /* 2️⃣ table.column coloring (core visual grouping) */
2958
3019
  s = s.replace(/\b(`?\w+`?)\.(\w+)\b/g, function (_, table, column) {
2959
3020
  return "".concat(tableColor(table)).concat(table).concat(RESET, ".") +
@@ -2970,7 +3031,7 @@ function colorSql(sql) {
2970
3031
  return s;
2971
3032
  }
2972
3033
 
2973
- var version = "6.0.12";
3034
+ var version = "6.0.13";
2974
3035
 
2975
3036
  var DEFAULT_STEP = 8;
2976
3037
  function parseSemver(version) {
@@ -3157,21 +3218,35 @@ var PostQueryBuilder = /** @class */ (function (_super) {
3157
3218
  };
3158
3219
  PostQueryBuilder.prototype.build = function (table) {
3159
3220
  var _this = this;
3221
+ var _a, _b;
3160
3222
  this.aliasMap = {};
3161
3223
  var verb = C6C.REPLACE in this.request ? C6C.REPLACE : C6C.INSERT;
3162
- var body = verb in this.request ? this.request[verb] : this.request;
3163
- var keys = Object.keys(body);
3224
+ var directRows = Array.isArray(this.request)
3225
+ ? this.request
3226
+ : [];
3227
+ var rows = directRows.length > 0
3228
+ ? directRows
3229
+ : Array.isArray(this.request.dataInsertMultipleRows) &&
3230
+ this.request.dataInsertMultipleRows.length > 0
3231
+ ? this.request.dataInsertMultipleRows
3232
+ : [verb in this.request ? this.request[verb] : this.request];
3233
+ var keys = Object.keys((_a = rows[0]) !== null && _a !== void 0 ? _a : {});
3164
3234
  var params = this.useNamedParams ? {} : [];
3165
- var placeholders = [];
3166
- for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
3167
- var key = keys_1[_i];
3168
- var value = body[key];
3169
- var trimmed = this.trimTablePrefix(table, key);
3170
- var qualified = "".concat(table, ".").concat(trimmed);
3171
- var placeholder = this.serializeUpdateValue(value, params, qualified);
3172
- placeholders.push(placeholder);
3235
+ var rowPlaceholders = [];
3236
+ for (var _i = 0, rows_1 = rows; _i < rows_1.length; _i++) {
3237
+ var row = rows_1[_i];
3238
+ var placeholders = [];
3239
+ for (var _c = 0, keys_1 = keys; _c < keys_1.length; _c++) {
3240
+ var key = keys_1[_c];
3241
+ var value = (_b = row[key]) !== null && _b !== void 0 ? _b : null;
3242
+ var trimmed = this.trimTablePrefix(table, key);
3243
+ var qualified = "".concat(table, ".").concat(trimmed);
3244
+ var placeholder = this.serializeUpdateValue(value, params, qualified);
3245
+ placeholders.push(placeholder);
3246
+ }
3247
+ rowPlaceholders.push("(".concat(placeholders.join(', '), ")"));
3173
3248
  }
3174
- 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 )");
3249
+ var sql = "".concat(verb, " INTO `").concat(table, "` (\n ").concat(keys.map(function (k) { return "`".concat(_this.trimTablePrefix(table, k), "`"); }).join(', '), "\n ) VALUES\n ").concat(rowPlaceholders.join(',\n '));
3175
3250
  if (C6C.UPDATE in this.request) {
3176
3251
  var updateData = this.request[C6C.UPDATE];
3177
3252
  if (!Array.isArray(updateData)) {
@@ -3860,19 +3935,55 @@ var SqlExecutor = /** @class */ (function (_super) {
3860
3935
  };
3861
3936
  SqlExecutor.prototype.runQuery = function () {
3862
3937
  return __awaiter(this, void 0, void 0, function () {
3863
- var method, tableName, logContext, sqlExecution;
3938
+ var method, tableName, logContext, cacheResults, cacheRequestData, requestArgumentsSerialized, cachedRequest, sqlExecution, queryPromise, cacheRequest, cacheResponse;
3864
3939
  var _this = this;
3865
- return __generator(this, function (_a) {
3866
- switch (_a.label) {
3940
+ var _a, _b;
3941
+ return __generator(this, function (_c) {
3942
+ switch (_c.label) {
3867
3943
  case 0:
3868
3944
  method = this.config.requestMethod;
3869
3945
  tableName = this.config.restModel.TABLE_NAME;
3870
3946
  logContext = getLogContext(this.config, this.request);
3947
+ cacheResults = method === C6Constants.GET
3948
+ && !this.config.sqlAllowListPath
3949
+ && ((_a = this.request) === null || _a === void 0 ? void 0 : _a.cacheResults) !== false;
3950
+ cacheRequestData = cacheResults
3951
+ ? JSON.parse(JSON.stringify((_b = this.request) !== null && _b !== void 0 ? _b : {}))
3952
+ : undefined;
3953
+ requestArgumentsSerialized = cacheResults
3954
+ ? sortAndSerializeQueryObject(tableName, cacheRequestData !== null && cacheRequestData !== void 0 ? cacheRequestData : {})
3955
+ : undefined;
3956
+ if (!cacheResults) return [3 /*break*/, 2];
3957
+ cachedRequest = checkCache(method, tableName, cacheRequestData);
3958
+ if (!cachedRequest) return [3 /*break*/, 2];
3959
+ return [4 /*yield*/, cachedRequest];
3960
+ case 1: return [2 /*return*/, (_c.sent()).data];
3961
+ case 2:
3871
3962
  sqlExecution = this.buildSqlExecutionContext(method, tableName, logContext);
3872
- return [4 /*yield*/, this.withConnection(function (conn) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
3873
- return [2 /*return*/, this.executeQueryWithLifecycle(conn, method, sqlExecution, logContext)];
3874
- }); }); })];
3875
- case 1: return [2 /*return*/, _a.sent()];
3963
+ queryPromise = this.withConnection(function (conn) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
3964
+ return [2 /*return*/, this.executeQueryWithLifecycle(conn, method, sqlExecution, logContext)];
3965
+ }); }); });
3966
+ if (!(!cacheResults || !cacheRequestData || !requestArgumentsSerialized)) return [3 /*break*/, 4];
3967
+ return [4 /*yield*/, queryPromise];
3968
+ case 3: return [2 /*return*/, _c.sent()];
3969
+ case 4:
3970
+ cacheRequest = queryPromise.then(function (data) {
3971
+ return _this.createCacheResponseEnvelope(method, tableName, data);
3972
+ });
3973
+ setCache(method, tableName, cacheRequestData, {
3974
+ requestArgumentsSerialized: requestArgumentsSerialized,
3975
+ request: cacheRequest,
3976
+ });
3977
+ return [4 /*yield*/, cacheRequest];
3978
+ case 5:
3979
+ cacheResponse = _c.sent();
3980
+ setCache(method, tableName, cacheRequestData, {
3981
+ requestArgumentsSerialized: requestArgumentsSerialized,
3982
+ request: cacheRequest,
3983
+ response: cacheResponse,
3984
+ final: true,
3985
+ });
3986
+ return [2 /*return*/, cacheResponse.data];
3876
3987
  }
3877
3988
  });
3878
3989
  });
@@ -3920,6 +4031,15 @@ var SqlExecutor = /** @class */ (function (_super) {
3920
4031
  var data = Object.assign({ success: true }, response);
3921
4032
  return { data: data };
3922
4033
  };
4034
+ SqlExecutor.prototype.createCacheResponseEnvelope = function (method, tableName, data) {
4035
+ return {
4036
+ data: data,
4037
+ config: {
4038
+ method: method.toLowerCase(),
4039
+ url: "/rest/".concat(tableName),
4040
+ },
4041
+ };
4042
+ };
3923
4043
  SqlExecutor.prototype.executeQueryWithLifecycle = function (conn, method, sqlExecution, logContext) {
3924
4044
  return __awaiter(this, void 0, void 0, function () {
3925
4045
  var useTransaction, committed, result, response, hookResponse, err_1, rollbackErr_1;
@@ -4025,22 +4145,23 @@ var SqlExecutor$1 = /*#__PURE__*/Object.freeze({
4025
4145
  SqlExecutor: SqlExecutor
4026
4146
  });
4027
4147
 
4028
- function restExpressRequest(_a) {
4029
- var router = _a.router, _b = _a.routePath, routePath = _b === void 0 ? "/rest/:table{/:primary}" : _b, handlerConfig = __rest(_a, ["router", "routePath"]);
4148
+ function restExpressRequest(routerConfig) {
4149
+ var router = routerConfig.router, _a = routerConfig.routePath, routePath = _a === void 0 ? "/rest/:table{/:primary}" : _a, handlerConfig = __rest(routerConfig, ["router", "routePath"]);
4030
4150
  router.all(routePath, ExpressHandler(handlerConfig));
4031
4151
  }
4032
4152
  // TODO - WE MUST make this a generic - optional, but helpful
4033
4153
  // note sure how it would help anyone actually...
4034
- function ExpressHandler(_a) {
4154
+ function ExpressHandler(configX) {
4035
4155
  var _this = this;
4036
- var C6 = _a.C6, mysqlPool = _a.mysqlPool, sqlAllowListPath = _a.sqlAllowListPath, websocketBroadcast = _a.websocketBroadcast;
4037
- return function (req, res, next) { return __awaiter(_this, void 0, void 0, function () {
4038
- var incomingMethod, table, primary, methodOverrideRaw, methodOverride, treatAsGet, method, payload, restModel, primaryKeys_1, primaryShortKeys_1, columnMap_1, resolveShortKey_1, hasPrimaryKeyValues, primaryKeyName, response, err_1;
4156
+ return function (req, res) { return __awaiter(_this, void 0, void 0, function () {
4157
+ var config, C6, incomingMethod, table, primary, methodOverrideRaw, methodOverride, treatAsGet, method, payload, normalized, restModel, primaryKeys_1, primaryShortKeys_1, columnMap_1, resolveShortKey_1, hasPrimaryKeyValues, primaryKeyName, response, err_1, message;
4039
4158
  var _a, _b, _c, _d, _e, _f, _g;
4040
4159
  return __generator(this, function (_h) {
4041
4160
  switch (_h.label) {
4042
4161
  case 0:
4043
4162
  _h.trys.push([0, 2, , 3]);
4163
+ config = typeof configX === "function" ? configX() : configX;
4164
+ C6 = config.C6;
4044
4165
  incomingMethod = req.method.toUpperCase();
4045
4166
  table = req.params.table;
4046
4167
  primary = req.params.primary;
@@ -4049,12 +4170,21 @@ function ExpressHandler(_a) {
4049
4170
  treatAsGet = incomingMethod === 'POST' && methodOverride === 'GET';
4050
4171
  method = treatAsGet ? 'GET' : incomingMethod;
4051
4172
  payload = treatAsGet ? __assign({}, req.body) : (method === 'GET' ? req.query : req.body);
4173
+ // Query strings are text; coerce known boolean controls.
4174
+ if (typeof (payload === null || payload === void 0 ? void 0 : payload.cacheResults) === "string") {
4175
+ normalized = payload.cacheResults.toLowerCase();
4176
+ if (normalized === "false")
4177
+ payload.cacheResults = false;
4178
+ if (normalized === "true")
4179
+ payload.cacheResults = true;
4180
+ }
4052
4181
  // Remove transport-only METHOD flag so it never leaks into ORM parsing
4053
4182
  if (treatAsGet && 'METHOD' in payload) {
4054
4183
  try {
4055
4184
  delete payload.METHOD;
4056
4185
  }
4057
- catch ( /* noop */_j) { /* noop */ }
4186
+ catch ( /* noop */_j) { /* noop */
4187
+ }
4058
4188
  }
4059
4189
  // Warn for unsupported overrides but continue normally
4060
4190
  if (incomingMethod !== 'GET' && methodOverride && methodOverride !== 'GET') {
@@ -4116,22 +4246,16 @@ function ExpressHandler(_a) {
4116
4246
  (_g = payload[primaryKeyName]) !== null && _g !== void 0 ? _g : primary;
4117
4247
  }
4118
4248
  }
4119
- return [4 /*yield*/, restRequest({
4120
- C6: C6,
4121
- mysqlPool: mysqlPool,
4122
- sqlAllowListPath: sqlAllowListPath,
4123
- websocketBroadcast: websocketBroadcast,
4124
- requestMethod: method,
4125
- restModel: C6.TABLES[table]
4126
- })(payload)];
4249
+ return [4 /*yield*/, restRequest(__assign(__assign({}, config), { requestMethod: method, restModel: C6.TABLES[table] }))(payload)];
4127
4250
  case 1:
4128
4251
  response = _h.sent();
4129
4252
  res.status(200).json(__assign({ success: true }, response));
4130
4253
  return [3 /*break*/, 3];
4131
4254
  case 2:
4132
4255
  err_1 = _h.sent();
4133
- res.status(500).json({ success: false, error: err_1 });
4134
- next(err_1);
4256
+ message = err_1 instanceof Error ? err_1.message : String(err_1);
4257
+ logWithLevel(LogLevel.ERROR, undefined, console.error, message);
4258
+ res.status(500).json({ success: false, error: message });
4135
4259
  return [3 /*break*/, 3];
4136
4260
  case 3: return [2 /*return*/];
4137
4261
  }