@carbonorm/carbonnode 3.5.6 → 3.5.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.js CHANGED
@@ -2,13 +2,12 @@
2
2
 
3
3
  var axios = require('axios');
4
4
  var Qs = require('qs');
5
- var tslib = require('tslib');
6
5
  var reactToastify = require('react-toastify');
7
6
  var namedPlaceholders = require('named-placeholders');
8
7
  var buffer = require('buffer');
9
8
 
10
9
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
11
- var C6Constants = {
10
+ const C6Constants = {
12
11
  // try to 1=1 match the Rest abstract class
13
12
  ADDDATE: 'ADDDATE',
14
13
  ADDTIME: 'ADDTIME',
@@ -166,7 +165,7 @@ var C6Constants = {
166
165
  FINISH: 'FINISH',
167
166
  VALIDATE_C6_ENTITY_ID_REGEX: '#^([a-fA-F0-9]{20,35})$#',
168
167
  };
169
- var C6C = C6Constants;
168
+ const C6C = C6Constants;
170
169
 
171
170
  // @link https://www.npmjs.com/package/axios-cache-adapter
172
171
  // updating these values
@@ -271,22 +270,20 @@ var axiosInstance = (axios.create({
271
270
  */
272
271
  }));
273
272
 
274
- function convertForRequestBody (restfulObject, tableName, C6, regexErrorHandler) {
275
- if (regexErrorHandler === void 0) { regexErrorHandler = alert; }
276
- var payload = {};
277
- var tableNames = Array.isArray(tableName) ? tableName : [tableName];
278
- var tableDefinitions = tableNames.map(function (name) {
279
- var tableDefinition = Object.values(C6.TABLES).find(function (t) { return t.TABLE_NAME === name; });
273
+ function convertForRequestBody (restfulObject, tableName, C6, regexErrorHandler = alert) {
274
+ const payload = {};
275
+ const tableNames = Array.isArray(tableName) ? tableName : [tableName];
276
+ const tableDefinitions = tableNames.map((name) => {
277
+ const tableDefinition = Object.values(C6.TABLES).find((t) => t.TABLE_NAME === name);
280
278
  if (!tableDefinition) {
281
- console.error("Table name (".concat(name, ") is not found in the C6.TABLES object."), C6.TABLES);
282
- throw new Error("Table name (".concat(name, ") is not found in the C6.TABLES object."));
279
+ console.error(`Table name (${name}) is not found in the C6.TABLES object.`, C6.TABLES);
280
+ throw new Error(`Table name (${name}) is not found in the C6.TABLES object.`);
283
281
  }
284
282
  return tableDefinition;
285
283
  });
286
- for (var _i = 0, tableDefinitions_1 = tableDefinitions; _i < tableDefinitions_1.length; _i++) {
287
- var tableDefinition = tableDefinitions_1[_i];
288
- var _loop_1 = function (value) {
289
- var shortReference = value.toUpperCase();
284
+ for (const tableDefinition of tableDefinitions) {
285
+ for (const value of Object.keys(restfulObject)) {
286
+ const shortReference = value.toUpperCase();
290
287
  if ([
291
288
  C6Constants.GET,
292
289
  C6Constants.POST,
@@ -297,61 +294,72 @@ function convertForRequestBody (restfulObject, tableName, C6, regexErrorHandler)
297
294
  C6Constants.JOIN,
298
295
  C6Constants.PAGINATION
299
296
  ].includes(value)) {
300
- var val_1 = restfulObject[value];
301
- if (Array.isArray(val_1)) {
302
- payload[value] = val_1.sort();
297
+ const val = restfulObject[value];
298
+ if (Array.isArray(val)) {
299
+ payload[value] = val.sort();
303
300
  }
304
- else if (typeof val_1 === 'object' && val_1 !== null) {
305
- payload[value] = Object.keys(val_1)
301
+ else if (typeof val === 'object' && val !== null) {
302
+ payload[value] = Object.keys(val)
306
303
  .sort()
307
- .reduce(function (acc, key) {
308
- var _a;
309
- return (tslib.__assign(tslib.__assign({}, acc), (_a = {}, _a[key] = val_1[key], _a)));
310
- }, {});
304
+ .reduce((acc, key) => ({ ...acc, [key]: val[key] }), {});
311
305
  }
312
- return "continue";
306
+ continue;
313
307
  }
314
308
  if (shortReference in tableDefinition) {
315
- var longName = tableDefinition[shortReference];
316
- var columnValue = restfulObject[value];
309
+ const longName = tableDefinition[shortReference];
310
+ const columnValue = restfulObject[value];
317
311
  payload[longName] = columnValue;
318
- var regexValidations = tableDefinition.REGEX_VALIDATION[longName];
312
+ const regexValidations = tableDefinition.REGEX_VALIDATION[longName];
319
313
  if (regexValidations instanceof RegExp) {
320
314
  if (!regexValidations.test(columnValue)) {
321
- regexErrorHandler("Failed to match regex (".concat(regexValidations, ") for column (").concat(longName, ")"));
322
- throw new Error("Failed to match regex (".concat(regexValidations, ") for column (").concat(longName, ")"));
315
+ regexErrorHandler(`Failed to match regex (${regexValidations}) for column (${longName})`);
316
+ throw new Error(`Failed to match regex (${regexValidations}) for column (${longName})`);
323
317
  }
324
318
  }
325
319
  else if (typeof regexValidations === 'object' && regexValidations !== null) {
326
- for (var errorMessage in regexValidations) {
327
- var regex = regexValidations[errorMessage];
320
+ for (const errorMessage in regexValidations) {
321
+ const regex = regexValidations[errorMessage];
328
322
  if (!regex.test(columnValue)) {
329
- var devErrorMessage = "Failed to match regex (".concat(regex, ") for column (").concat(longName, ")");
323
+ const devErrorMessage = `Failed to match regex (${regex}) for column (${longName})`;
324
+ regexErrorHandler(errorMessage || devErrorMessage);
325
+ throw new Error(devErrorMessage);
326
+ }
327
+ }
328
+ }
329
+ }
330
+ else if (Object.values(tableDefinition.COLUMNS).includes(value)) {
331
+ // Already a fully qualified column name
332
+ const columnValue = restfulObject[value];
333
+ payload[value] = columnValue;
334
+ const regexValidations = tableDefinition.REGEX_VALIDATION[value];
335
+ if (regexValidations instanceof RegExp) {
336
+ if (!regexValidations.test(columnValue)) {
337
+ regexErrorHandler(`Failed to match regex (${regexValidations}) for column (${value})`);
338
+ throw new Error(`Failed to match regex (${regexValidations}) for column (${value})`);
339
+ }
340
+ }
341
+ else if (typeof regexValidations === 'object' && regexValidations !== null) {
342
+ for (const errorMessage in regexValidations) {
343
+ const regex = regexValidations[errorMessage];
344
+ if (!regex.test(columnValue)) {
345
+ const devErrorMessage = `Failed to match regex (${regex}) for column (${value})`;
330
346
  regexErrorHandler(errorMessage || devErrorMessage);
331
347
  throw new Error(devErrorMessage);
332
348
  }
333
349
  }
334
350
  }
335
351
  }
336
- };
337
- for (var _a = 0, _b = Object.keys(restfulObject); _a < _b.length; _a++) {
338
- var value = _b[_a];
339
- _loop_1(value);
340
352
  }
341
353
  }
342
354
  return Object.keys(payload)
343
355
  .sort()
344
- .reduce(function (acc, key) {
345
- var _a;
346
- return (tslib.__assign(tslib.__assign({}, acc), (_a = {}, _a[key] = payload[key], _a)));
347
- }, {});
356
+ .reduce((acc, key) => ({ ...acc, [key]: payload[key] }), {});
348
357
  }
349
358
 
350
- var isNode = function () {
351
- var _a;
359
+ const isNode = () => {
352
360
  console.log('Checking if running in Node.js environment...');
353
- var isNodeEnv = typeof process !== 'undefined' && !!((_a = process.versions) === null || _a === void 0 ? void 0 : _a.node);
354
- console.log("Is Node.js environment: ".concat(isNodeEnv));
361
+ const isNodeEnv = typeof process !== 'undefined' && !!process.versions?.node;
362
+ console.log(`Is Node.js environment: ${isNodeEnv}`);
355
363
  return isNodeEnv;
356
364
  };
357
365
 
@@ -359,112 +367,94 @@ var isNode = function () {
359
367
  * Facade: routes API calls to SQL or HTTP executors based on runtime context.
360
368
  */
361
369
  function restRequest(configX) {
362
- var _this = this;
363
- return function (request) { return tslib.__awaiter(_this, void 0, void 0, function () {
364
- var config, SqlExecutor, executor, HttpExecutor, http;
365
- var _a;
366
- return tslib.__generator(this, function (_b) {
367
- switch (_b.label) {
368
- case 0:
369
- config = typeof configX === "function" ? configX() : configX;
370
- (_a = config.verbose) !== null && _a !== void 0 ? _a : (config.verbose = true); // Default to verbose logging if not set
371
- if (!(isNode() && config.mysqlPool)) return [3 /*break*/, 2];
372
- return [4 /*yield*/, Promise.resolve().then(function () { return SqlExecutor$1; })];
373
- case 1:
374
- SqlExecutor = (_b.sent()).SqlExecutor;
375
- executor = new SqlExecutor(config, request);
376
- return [2 /*return*/, executor.execute()];
377
- case 2: return [4 /*yield*/, Promise.resolve().then(function () { return HttpExecutor$1; })];
378
- case 3:
379
- HttpExecutor = (_b.sent()).HttpExecutor;
380
- http = new HttpExecutor(config, request);
381
- return [2 /*return*/, http.execute()];
382
- }
383
- });
384
- }); };
370
+ return async (request) => {
371
+ const config = typeof configX === "function" ? configX() : configX;
372
+ config.verbose ??= true; // Default to verbose logging if not set
373
+ // SQL path if on Node with a provided pool
374
+ if (isNode() && config.mysqlPool) {
375
+ const { SqlExecutor } = await Promise.resolve().then(function () { return SqlExecutor$1; });
376
+ const executor = new SqlExecutor(config, request);
377
+ return executor.execute();
378
+ }
379
+ // HTTP path fallback
380
+ const { HttpExecutor } = await Promise.resolve().then(function () { return HttpExecutor$1; });
381
+ const http = new HttpExecutor(config, request);
382
+ return http.execute();
383
+ };
385
384
  }
386
385
 
387
386
  function restOrm(configFn) {
388
387
  return {
389
- Get: restRequest(function () { return (tslib.__assign(tslib.__assign({}, configFn()), { requestMethod: "GET" })); }),
390
- Put: restRequest(function () { return (tslib.__assign(tslib.__assign({}, configFn()), { requestMethod: "PUT" })); }),
391
- Post: restRequest(function () { return (tslib.__assign(tslib.__assign({}, configFn()), { requestMethod: "POST" })); }),
392
- Delete: restRequest(function () { return (tslib.__assign(tslib.__assign({}, configFn()), { requestMethod: "DELETE" })); })
388
+ Get: restRequest(() => ({
389
+ ...configFn(),
390
+ requestMethod: "GET"
391
+ })),
392
+ Put: restRequest(() => ({
393
+ ...configFn(),
394
+ requestMethod: "PUT"
395
+ })),
396
+ Post: restRequest(() => ({
397
+ ...configFn(),
398
+ requestMethod: "POST"
399
+ })),
400
+ Delete: restRequest(() => ({
401
+ ...configFn(),
402
+ requestMethod: "DELETE"
403
+ }))
393
404
  };
394
405
  }
395
406
 
396
- function timeout(shouldContinueAfterTimeout, cb, timeoutMs) {
397
- if (timeoutMs === void 0) { timeoutMs = 3000; }
398
- var timer = function () { return setTimeout(function () {
407
+ function timeout(shouldContinueAfterTimeout, cb, timeoutMs = 3000) {
408
+ const timer = () => setTimeout(() => {
399
409
  if (false === shouldContinueAfterTimeout()) {
400
410
  return;
401
411
  }
402
412
  cb();
403
- }, timeoutMs); };
404
- var timerId = timer();
405
- return function () {
413
+ }, timeoutMs);
414
+ const timerId = timer();
415
+ return () => {
406
416
  clearTimeout(timerId);
407
417
  };
408
418
  }
409
419
 
410
- var Executor = /** @class */ (function () {
411
- function Executor(config, request, useNamedParams) {
412
- if (useNamedParams === void 0) { useNamedParams = false; }
420
+ class Executor {
421
+ config;
422
+ request;
423
+ useNamedParams;
424
+ constructor(config, request, useNamedParams = false) {
413
425
  this.config = config;
414
426
  this.request = request;
415
427
  this.useNamedParams = useNamedParams;
416
428
  }
417
- Executor.prototype.runLifecycleHooks = function (phase, args) {
418
- return tslib.__awaiter(this, void 0, void 0, function () {
419
- var lifecycleGroup, _i, _a, _b, key, fn, err_1;
420
- var _c;
421
- return tslib.__generator(this, function (_d) {
422
- switch (_d.label) {
423
- case 0:
424
- lifecycleGroup = (_c = this.config.restModel.LIFECYCLE_HOOKS[this.config.requestMethod]) === null || _c === void 0 ? void 0 : _c[phase];
425
- if (!lifecycleGroup)
426
- return [2 /*return*/];
427
- _i = 0, _a = Object.entries(lifecycleGroup);
428
- _d.label = 1;
429
- case 1:
430
- if (!(_i < _a.length)) return [3 /*break*/, 6];
431
- _b = _a[_i], key = _b[0], fn = _b[1];
432
- if (!(typeof fn === "function")) return [3 /*break*/, 5];
433
- if (this.config.verbose || args.request.debug) {
434
- console.groupCollapsed("[LIFECYCLE] ".concat(this.config.requestMethod, ".").concat(String(phase), ":").concat(key));
435
- console.log("config:", args.config);
436
- console.log("request:", args.request);
437
- if ("response" in args) {
438
- console.log("response:", args.response);
439
- }
440
- console.groupEnd();
441
- }
442
- _d.label = 2;
443
- case 2:
444
- _d.trys.push([2, 4, , 5]);
445
- // todo - this
446
- return [4 /*yield*/, fn(args)];
447
- case 3:
448
- // todo - this
449
- _d.sent();
450
- return [3 /*break*/, 5];
451
- case 4:
452
- err_1 = _d.sent();
453
- console.error("[LIFECYCLE ERROR] ".concat(this.config.requestMethod, ".").concat(String(phase), ":").concat(key), err_1);
454
- throw err_1;
455
- case 5:
456
- _i++;
457
- return [3 /*break*/, 1];
458
- case 6: return [2 /*return*/];
429
+ async runLifecycleHooks(phase, args) {
430
+ const lifecycleGroup = this.config.restModel.LIFECYCLE_HOOKS[this.config.requestMethod]?.[phase];
431
+ if (!lifecycleGroup)
432
+ return;
433
+ for (const [key, fn] of Object.entries(lifecycleGroup)) {
434
+ if (typeof fn === "function") {
435
+ if (this.config.verbose || args.request.debug) {
436
+ console.groupCollapsed(`[LIFECYCLE] ${this.config.requestMethod}.${String(phase)}:${key}`);
437
+ console.log("config:", args.config);
438
+ console.log("request:", args.request);
439
+ if ("response" in args) {
440
+ console.log("response:", args.response);
441
+ }
442
+ console.groupEnd();
459
443
  }
460
- });
461
- });
462
- };
463
- return Executor;
464
- }());
444
+ try {
445
+ // todo - this
446
+ await fn(args);
447
+ }
448
+ catch (err) {
449
+ console.error(`[LIFECYCLE ERROR] ${this.config.requestMethod}.${String(phase)}:${key}`, err);
450
+ throw err;
451
+ }
452
+ }
453
+ }
454
+ }
455
+ }
465
456
 
466
- function getEnvVar(key, fallback) {
467
- if (fallback === void 0) { fallback = ''; }
457
+ function getEnvVar(key, fallback = '') {
468
458
  // Vite-style injection
469
459
  // @ts-ignore
470
460
  if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs.js', document.baseURI).href)) }) !== 'undefined' && undefined && key in undefined) {
@@ -501,12 +491,12 @@ exports.eFetchDependencies = void 0;
501
491
  })(exports.eFetchDependencies || (exports.eFetchDependencies = {}));
502
492
 
503
493
  // Refined TypeScript types for CarbonORM
504
- var POST = 'POST';
505
- var PUT = 'PUT';
506
- var GET = 'GET';
507
- var DELETE = 'DELETE';
494
+ const POST = 'POST';
495
+ const PUT = 'PUT';
496
+ const GET = 'GET';
497
+ const DELETE = 'DELETE';
508
498
 
509
- var toastOptions = {
499
+ const toastOptions = {
510
500
  position: "bottom-left",
511
501
  autoClose: 10000,
512
502
  hideProgressBar: false,
@@ -515,7 +505,7 @@ var toastOptions = {
515
505
  draggable: true,
516
506
  theme: "dark",
517
507
  };
518
- var toastOptionsDevs = {
508
+ const toastOptionsDevs = {
519
509
  position: "bottom-right",
520
510
  autoClose: 3000,
521
511
  hideProgressBar: false,
@@ -527,20 +517,19 @@ var toastOptionsDevs = {
527
517
 
528
518
  // When we capture DropExceptions and display them as a custom page, this will change.
529
519
  function TestRestfulResponse(response, success, error) {
530
- var _a, _b, _c, _d, _e, _f, _g, _h;
531
- if (undefined === ((_a = response.data) === null || _a === void 0 ? void 0 : _a['ERROR TYPE'])
532
- && (undefined !== ((_b = response === null || response === void 0 ? void 0 : response.data) === null || _b === void 0 ? void 0 : _b.rest)
533
- || undefined !== ((_c = response.data) === null || _c === void 0 ? void 0 : _c.created)
534
- || undefined !== ((_d = response.data) === null || _d === void 0 ? void 0 : _d.updated)
535
- || undefined !== ((_e = response.data) === null || _e === void 0 ? void 0 : _e.deleted))) {
536
- var successReturn = 'function' === typeof success ? success === null || success === void 0 ? void 0 : success(response) : success;
520
+ if (undefined === response.data?.['ERROR TYPE']
521
+ && (undefined !== response?.data?.rest
522
+ || undefined !== response.data?.created
523
+ || undefined !== response.data?.updated
524
+ || undefined !== response.data?.deleted)) {
525
+ let successReturn = 'function' === typeof success ? success?.(response) : success;
537
526
  if (typeof successReturn === 'string') {
538
527
  reactToastify.toast.success(successReturn, toastOptions);
539
528
  }
540
529
  // this could end up with bad results for deleting id's === 0
541
- return (_h = (_g = (_f = response.data.created) !== null && _f !== void 0 ? _f : response.data.updated) !== null && _g !== void 0 ? _g : response.data.deleted) !== null && _h !== void 0 ? _h : true;
530
+ return response.data.created ?? response.data.updated ?? response.data.deleted ?? true;
542
531
  }
543
- var errorReturn = 'function' === typeof error ? error === null || error === void 0 ? void 0 : error(response) : error;
532
+ let errorReturn = 'function' === typeof error ? error?.(response) : error;
544
533
  if (typeof errorReturn === 'string') {
545
534
  reactToastify.toast.error(errorReturn, toastOptions);
546
535
  }
@@ -553,15 +542,15 @@ function removePrefixIfExists(tableName, prefix) {
553
542
  return tableName;
554
543
  }
555
544
  function removeInvalidKeys(request, c6Tables) {
556
- var intersection = {};
557
- var restfulObjectKeys = [];
558
- var tableList = Object.values(c6Tables);
559
- tableList.forEach(function (table) { return Object.values(table.COLUMNS).forEach(function (column) {
545
+ let intersection = {};
546
+ let restfulObjectKeys = [];
547
+ const tableList = Object.values(c6Tables);
548
+ tableList.forEach(table => Object.values(table.COLUMNS).forEach(column => {
560
549
  if (false === restfulObjectKeys.includes(column)) {
561
550
  restfulObjectKeys.push(column);
562
551
  }
563
- }); });
564
- Object.keys(request).forEach(function (key) {
552
+ }));
553
+ Object.keys(request).forEach(key => {
565
554
  if (restfulObjectKeys.includes(key)) {
566
555
  intersection[key] = request[key];
567
556
  }
@@ -575,10 +564,10 @@ function removeInvalidKeys(request, c6Tables) {
575
564
  exports.apiRequestCache = [];
576
565
  exports.userCustomClearCache = [];
577
566
  function clearCache(props) {
578
- if (false === (props === null || props === void 0 ? void 0 : props.ignoreWarning)) {
567
+ if (false === props?.ignoreWarning) {
579
568
  console.warn('The rest api clearCache should only be used with extreme care! Avoid using this in favor of using `cacheResults : boolean`.');
580
569
  }
581
- exports.userCustomClearCache.map(function (f) { return 'function' === typeof f && f(); });
570
+ exports.userCustomClearCache.map((f) => 'function' === typeof f && f());
582
571
  exports.userCustomClearCache = exports.apiRequestCache = [];
583
572
  }
584
573
  function checkCache(cacheResult, requestMethod, tableName, request) {
@@ -593,601 +582,551 @@ function checkCache(cacheResult, requestMethod, tableName, request) {
593
582
  }
594
583
 
595
584
  function sortAndSerializeQueryObject(tables, query) {
596
- var orderedQuery = Object.keys(query).sort().reduce(function (obj, key) {
585
+ const orderedQuery = Object.keys(query).sort().reduce((obj, key) => {
597
586
  obj[key] = query[key];
598
587
  return obj;
599
588
  }, {});
600
589
  return tables + ' ' + JSON.stringify(orderedQuery);
601
590
  }
602
591
 
603
- var HttpExecutor = /** @class */ (function (_super) {
604
- tslib.__extends(HttpExecutor, _super);
605
- function HttpExecutor() {
606
- return _super !== null && _super.apply(this, arguments) || this;
607
- }
608
- HttpExecutor.prototype.putState = function (response, request, callback) {
609
- var _a, _b;
610
- (_a = this.config.reactBootstrap) === null || _a === void 0 ? void 0 : _a.updateRestfulObjectArrays({
611
- callback: callback,
592
+ class HttpExecutor extends Executor {
593
+ putState(response, request, callback) {
594
+ this.config.reactBootstrap?.updateRestfulObjectArrays({
595
+ callback,
612
596
  dataOrCallback: [
613
- removeInvalidKeys(tslib.__assign(tslib.__assign({}, request), (_b = response === null || response === void 0 ? void 0 : response.data) === null || _b === void 0 ? void 0 : _b.rest), this.config.C6.TABLES)
597
+ removeInvalidKeys({
598
+ ...request,
599
+ ...response?.data?.rest,
600
+ }, this.config.C6.TABLES)
614
601
  ],
615
602
  stateKey: this.config.restModel.TABLE_NAME,
616
603
  uniqueObjectId: this.config.restModel.PRIMARY_SHORT
617
604
  });
618
- };
619
- HttpExecutor.prototype.postState = function (response, request, callback) {
620
- var _this = this;
621
- var _a, _b, _c;
605
+ }
606
+ postState(response, request, callback) {
622
607
  if (1 !== this.config.restModel.PRIMARY_SHORT.length) {
623
608
  console.error("C6 received unexpected result's given the primary key length");
624
609
  }
625
610
  else {
626
- var pk = this.config.restModel.PRIMARY_SHORT[0];
611
+ const pk = this.config.restModel.PRIMARY_SHORT[0];
627
612
  // TODO - should overrides be handled differently? Why override: (react/php), driver missmatches, aux data..
628
613
  // @ts-ignore - this is technically a correct error, but we allow it anyway...
629
- request[pk] = (_a = response.data) === null || _a === void 0 ? void 0 : _a.created;
614
+ request[pk] = response.data?.created;
630
615
  }
631
- (_b = this.config.reactBootstrap) === null || _b === void 0 ? void 0 : _b.updateRestfulObjectArrays({
632
- callback: callback,
616
+ this.config.reactBootstrap?.updateRestfulObjectArrays({
617
+ callback,
633
618
  dataOrCallback: undefined !== request.dataInsertMultipleRows
634
- ? request.dataInsertMultipleRows.map(function (request, index) {
635
- var _a;
636
- return removeInvalidKeys(tslib.__assign(tslib.__assign({}, request), (index === 0 ? (_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.rest : {})), _this.config.C6.TABLES);
619
+ ? request.dataInsertMultipleRows.map((request, index) => {
620
+ return removeInvalidKeys({
621
+ ...request,
622
+ ...(index === 0 ? response?.data?.rest : {}),
623
+ }, this.config.C6.TABLES);
637
624
  })
638
625
  : [
639
- removeInvalidKeys(tslib.__assign(tslib.__assign({}, request), (_c = response === null || response === void 0 ? void 0 : response.data) === null || _c === void 0 ? void 0 : _c.rest), this.config.C6.TABLES)
626
+ removeInvalidKeys({
627
+ ...request,
628
+ ...response?.data?.rest,
629
+ }, this.config.C6.TABLES)
640
630
  ],
641
631
  stateKey: this.config.restModel.TABLE_NAME,
642
632
  uniqueObjectId: this.config.restModel.PRIMARY_SHORT
643
633
  });
644
- };
645
- HttpExecutor.prototype.deleteState = function (_response, request, callback) {
646
- var _a;
647
- (_a = this.config.reactBootstrap) === null || _a === void 0 ? void 0 : _a.deleteRestfulObjectArrays({
648
- callback: callback,
634
+ }
635
+ deleteState(_response, request, callback) {
636
+ this.config.reactBootstrap?.deleteRestfulObjectArrays({
637
+ callback,
649
638
  dataOrCallback: [
650
639
  request,
651
640
  ],
652
641
  stateKey: this.config.restModel.TABLE_NAME,
653
642
  uniqueObjectId: this.config.restModel.PRIMARY_SHORT
654
643
  });
655
- };
656
- HttpExecutor.prototype.execute = function () {
657
- return tslib.__awaiter(this, void 0, void 0, function () {
658
- var _a, C6, axios, restURL, withCredentials, restModel, reactBootstrap, requestMethod, skipPrimaryCheck, clearCache, tableName, fullTableList, operatingTableFullName, operatingTable, tables, query, apiRequest;
659
- var _this = this;
660
- return tslib.__generator(this, function (_b) {
661
- switch (_b.label) {
662
- case 0:
663
- _a = this.config, C6 = _a.C6, axios = _a.axios, restURL = _a.restURL, withCredentials = _a.withCredentials, restModel = _a.restModel, reactBootstrap = _a.reactBootstrap, requestMethod = _a.requestMethod, skipPrimaryCheck = _a.skipPrimaryCheck, clearCache = _a.clearCache;
664
- console.log('this.config', this.config);
665
- return [4 /*yield*/, this.runLifecycleHooks("beforeProcessing", {
666
- config: this.config,
667
- request: this.request,
668
- })];
669
- case 1:
670
- _b.sent();
671
- tableName = restModel.TABLE_NAME;
672
- fullTableList = Array.isArray(tableName) ? tableName : [tableName];
673
- operatingTableFullName = fullTableList[0];
674
- operatingTable = removePrefixIfExists(operatingTableFullName, C6.PREFIX);
675
- tables = fullTableList.join(',');
644
+ }
645
+ async execute() {
646
+ const { C6, axios, restURL, withCredentials, restModel, reactBootstrap, requestMethod, skipPrimaryCheck, clearCache, } = this.config;
647
+ console.log('this.config', this.config);
648
+ await this.runLifecycleHooks("beforeProcessing", {
649
+ config: this.config,
650
+ request: this.request,
651
+ });
652
+ const tableName = restModel.TABLE_NAME;
653
+ const fullTableList = Array.isArray(tableName) ? tableName : [tableName];
654
+ const operatingTableFullName = fullTableList[0];
655
+ const operatingTable = removePrefixIfExists(operatingTableFullName, C6.PREFIX);
656
+ const tables = fullTableList.join(',');
657
+ switch (requestMethod) {
658
+ case GET:
659
+ case POST:
660
+ case PUT:
661
+ case DELETE:
662
+ break;
663
+ default:
664
+ throw Error('Bad request method passed to getApi');
665
+ }
666
+ if (null !== clearCache || undefined !== clearCache) {
667
+ exports.userCustomClearCache[tables + requestMethod] = clearCache;
668
+ }
669
+ console.groupCollapsed('%c API: (' + requestMethod + ') Request for (' + tableName + ')', 'color: #0c0');
670
+ console.log('request', this.request);
671
+ console.groupEnd();
672
+ // an undefined query would indicate queryCallback returned undefined,
673
+ // thus the request shouldn't fire as is in custom cache
674
+ if (undefined === this.request || null === this.request) {
675
+ console.groupCollapsed('%c API: (' + requestMethod + ') Request Query for (' + tableName + ') undefined, returning null (will not fire)!', 'color: #c00');
676
+ console.log('request', this.request);
677
+ console.log('%c Returning (undefined|null) for a query would indicate a custom cache hit (outside API.tsx), thus the request should not fire.', 'color: #c00');
678
+ console.trace();
679
+ console.groupEnd();
680
+ return null;
681
+ }
682
+ let query = this.request;
683
+ if (C6.GET === requestMethod) {
684
+ if (undefined === query[C6.PAGINATION]) {
685
+ query[C6.PAGINATION] = {};
686
+ }
687
+ query[C6.PAGINATION][C6.PAGE] = query[C6.PAGINATION][C6.PAGE] || 1;
688
+ query[C6.PAGINATION][C6.LIMIT] = query[C6.PAGINATION][C6.LIMIT] || 100;
689
+ }
690
+ // this is parameterless and could return itself with a new page number, or undefined if the end is reached
691
+ const apiRequest = async () => {
692
+ const { debug, cacheResults = (C6.GET === requestMethod), dataInsertMultipleRows, success, fetchDependencies = exports.eFetchDependencies.NONE, error = "An unexpected API error occurred!" } = this.request;
693
+ if (C6.GET === requestMethod
694
+ && undefined !== query?.[C6.PAGINATION]?.[C6.PAGE]
695
+ && 1 !== query[C6.PAGINATION][C6.PAGE]) {
696
+ console.groupCollapsed('Request on table (' + tableName + ') is firing for page (' + query[C6.PAGINATION][C6.PAGE] + '), please wait!');
697
+ console.log('Request Data (note you may see the success and/or error prompt):', this.request);
698
+ console.trace();
699
+ console.groupEnd();
700
+ }
701
+ // The problem with creating cache keys with a stringified object is the order of keys matters and it's possible for the same query to be stringified differently.
702
+ // Here we ensure the key order will be identical between two of the same requests. https://stackoverflow.com/questions/5467129/sort-javascript-object-by-key
703
+ // literally impossible for query to be undefined or null here but the editor is too busy licking windows to understand that
704
+ let querySerialized = sortAndSerializeQueryObject(tables, query ?? {});
705
+ let cacheResult = exports.apiRequestCache.find(cache => cache.requestArgumentsSerialized === querySerialized);
706
+ let cachingConfirmed = false;
707
+ // determine if we need to paginate.
708
+ if (requestMethod === C6.GET) {
709
+ if (undefined === query?.[C6.PAGINATION]) {
710
+ if (undefined === query || null === query) {
711
+ query = {};
712
+ }
713
+ query[C6.PAGINATION] = {};
714
+ }
715
+ query[C6.PAGINATION][C6.PAGE] = query[C6.PAGINATION][C6.PAGE] || 1;
716
+ query[C6.PAGINATION][C6.LIMIT] = query[C6.PAGINATION][C6.LIMIT] || 100;
717
+ // this will evaluate true most the time
718
+ if (true === cacheResults) {
719
+ // just find the next, non-fetched, page and return a function to request it
720
+ if (undefined !== cacheResult) { // we will return in this loop
721
+ do {
722
+ const cacheCheck = checkCache(cacheResult, requestMethod, tableName, this.request);
723
+ if (false !== cacheCheck) {
724
+ return (await cacheCheck).data;
725
+ }
726
+ // this line incrementing page is why we return recursively
727
+ ++query[C6.PAGINATION][C6.PAGE];
728
+ // this json stringify is to capture the new page number
729
+ querySerialized = sortAndSerializeQueryObject(tables, query ?? {});
730
+ cacheResult = exports.apiRequestCache.find(cache => cache.requestArgumentsSerialized === querySerialized);
731
+ } while (undefined !== cacheResult);
732
+ if (debug && isLocal()) {
733
+ reactToastify.toast.warning("DEVS: Request in cache. (" + exports.apiRequestCache.findIndex(cache => cache.requestArgumentsSerialized === querySerialized) + "). Returning function to request page (" + query[C6.PAGINATION][C6.PAGE] + ")", toastOptionsDevs);
734
+ }
735
+ // @ts-ignore - this is an incorrect warning on TS, it's well typed
736
+ return apiRequest;
737
+ }
738
+ cachingConfirmed = true;
739
+ }
740
+ else {
741
+ if (debug && isLocal()) {
742
+ reactToastify.toast.info("DEVS: Ignore cache was set to true.", toastOptionsDevs);
743
+ }
744
+ }
745
+ if (debug && isLocal()) {
746
+ reactToastify.toast.success("DEVS: Request not in cache." + (requestMethod === C6.GET ? "Page (" + query[C6.PAGINATION][C6.PAGE] + ")." : '') + " Logging cache 2 console.", toastOptionsDevs);
747
+ }
748
+ }
749
+ else if (cacheResults) { // if we are not getting, we are updating, deleting, or inserting
750
+ if (cacheResult) {
751
+ const cacheCheck = checkCache(cacheResult, requestMethod, tableName, this.request);
752
+ if (false !== cacheCheck) {
753
+ return (await cacheCheck).data;
754
+ }
755
+ }
756
+ cachingConfirmed = true;
757
+ // push to cache so we do not repeat the request
758
+ }
759
+ let addBackPK;
760
+ let apiResponse;
761
+ let returnGetNextPageFunction = false;
762
+ let restRequestUri = restURL + operatingTable + '/';
763
+ const needsConditionOrPrimaryCheck = (PUT === requestMethod || DELETE === requestMethod)
764
+ && false === skipPrimaryCheck;
765
+ const TABLES = C6.TABLES;
766
+ // todo - aggregate primary key check with condition check
767
+ // check if PK exists in query, clone so pop does not affect the real data
768
+ const primaryKey = structuredClone(TABLES[operatingTable]?.PRIMARY)?.pop()?.split('.')?.pop();
769
+ if (needsConditionOrPrimaryCheck) {
770
+ if (undefined === primaryKey) {
771
+ if (null === query
772
+ || undefined === query
773
+ || undefined === query?.[C6.WHERE]
774
+ || (true === Array.isArray(query[C6.WHERE])
775
+ || query[C6.WHERE].length === 0)
776
+ || (Object.keys(query?.[C6.WHERE]).length === 0)) {
777
+ console.error(query);
778
+ throw Error('Failed to parse primary key information. Query: (' + JSON.stringify(query) + ') Primary Key: (' + JSON.stringify(primaryKey) + ') TABLES[operatingTable]?.PRIMARY: (' + JSON.stringify(TABLES[operatingTable]?.PRIMARY) + ') for operatingTable (' + operatingTable + ').');
779
+ }
780
+ }
781
+ else {
782
+ if (undefined === query
783
+ || null === query
784
+ || false === primaryKey in query) {
785
+ if (true === debug && isLocal()) {
786
+ reactToastify.toast.error('DEVS: The primary key (' + primaryKey + ') was not provided!!');
787
+ }
788
+ throw Error('You must provide the primary key (' + primaryKey + ') for table (' + operatingTable + '). Request (' + JSON.stringify(this.request, undefined, 4) + ') Query (' + JSON.stringify(query) + ')');
789
+ }
790
+ if (undefined === query?.[primaryKey]
791
+ || null === query?.[primaryKey]) {
792
+ reactToastify.toast.error('The primary key (' + primaryKey + ') provided is undefined or null explicitly!!');
793
+ throw Error('The primary key (' + primaryKey + ') provided in the request was exactly equal to undefined.');
794
+ }
795
+ }
796
+ }
797
+ // A part of me exists that wants to remove this, but it's a good feature
798
+ // this allows developers the ability to cache requests based on primary key
799
+ // for tables like `photos` this can be a huge performance boost
800
+ if (undefined !== query
801
+ && null !== query
802
+ && undefined !== primaryKey
803
+ && primaryKey in query) {
804
+ restRequestUri += query[primaryKey] + '/';
805
+ const removedPkValue = query[primaryKey];
806
+ addBackPK = () => {
807
+ query ??= {};
808
+ query[primaryKey] = removedPkValue;
809
+ };
810
+ delete query[primaryKey];
811
+ console.log('query', query, 'primaryKey', primaryKey, 'removedPkValue', removedPkValue);
812
+ }
813
+ else {
814
+ console.log('query', query);
815
+ }
816
+ try {
817
+ console.groupCollapsed('%c API: (' + requestMethod + ') Request Query for (' + operatingTable + ') is about to fire, will return with promise!', 'color: #A020F0');
818
+ console.log(this.request);
819
+ console.log('%c If this is the first request for this datatype; thus the value being set is currently undefined, please remember to update the state to null.', 'color: #A020F0');
820
+ console.log('%c Remember undefined indicated the request has not fired, null indicates the request is firing, an empty array would signal no data was returned for the sql stmt.', 'color: #A020F0');
821
+ console.trace();
822
+ console.groupEnd();
823
+ this.runLifecycleHooks("beforeExecution", {
824
+ config: this.config,
825
+ request: this.request
826
+ });
827
+ const axiosActiveRequest = axios[requestMethod.toLowerCase()](restRequestUri, ...(() => {
828
+ const convert = (data) => convertForRequestBody(data, fullTableList, C6, (message) => reactToastify.toast.error(message, toastOptions));
829
+ const baseConfig = {
830
+ withCredentials: withCredentials,
831
+ };
832
+ switch (requestMethod) {
833
+ case GET:
834
+ return [{
835
+ ...baseConfig,
836
+ params: query
837
+ }];
838
+ case POST:
839
+ if (dataInsertMultipleRows !== undefined) {
840
+ return [
841
+ dataInsertMultipleRows.map(convert),
842
+ baseConfig
843
+ ];
844
+ }
845
+ return [convert(query), baseConfig];
846
+ case PUT:
847
+ return [convert(query), baseConfig];
848
+ case DELETE:
849
+ return [{
850
+ ...baseConfig,
851
+ data: convert(query)
852
+ }];
853
+ default:
854
+ throw new Error(`The request method (${requestMethod}) was not recognized.`);
855
+ }
856
+ })());
857
+ if (cachingConfirmed) {
858
+ // push to cache so we do not repeat the request
859
+ exports.apiRequestCache.push({
860
+ requestArgumentsSerialized: querySerialized,
861
+ request: axiosActiveRequest
862
+ });
863
+ }
864
+ // todo - wip verify this works
865
+ // we had removed the value from the request to add to the URI.
866
+ addBackPK?.(); // adding back so post-processing methods work
867
+ // returning the promise with this then is important for tests. todo - we could make that optional.
868
+ // https://rapidapi.com/guides/axios-async-await
869
+ return axiosActiveRequest.then(async (response) => {
870
+ // noinspection SuspiciousTypeOfGuard
871
+ if (typeof response.data === 'string') {
872
+ if (isTest()) {
873
+ console.trace();
874
+ throw new Error('The response data was a string this typically indicated html was sent. Make sure all cookies (' + JSON.stringify(response.config.headers) + ') needed are present! (' + response.data + ')');
875
+ }
876
+ return Promise.reject(response);
877
+ }
878
+ if (cachingConfirmed) {
879
+ const cacheIndex = exports.apiRequestCache.findIndex(cache => cache.requestArgumentsSerialized === querySerialized);
880
+ // TODO - currently nonthing is setting this correctly
881
+ exports.apiRequestCache[cacheIndex].final = false === returnGetNextPageFunction;
882
+ // only cache get method requests
883
+ exports.apiRequestCache[cacheIndex].response = response;
884
+ }
885
+ this.runLifecycleHooks("afterExecution", {
886
+ config: this.config,
887
+ request: this.request,
888
+ response
889
+ });
890
+ // todo - this feels dumb now, but i digress
891
+ apiResponse = TestRestfulResponse(response, success, error);
892
+ if (false === apiResponse) {
893
+ if (debug && isLocal()) {
894
+ reactToastify.toast.warning("DEVS: TestRestfulResponse returned false for (" + operatingTable + ").", toastOptionsDevs);
895
+ }
896
+ return response;
897
+ }
898
+ const callback = () => this.runLifecycleHooks("afterCommit", {
899
+ config: this.config,
900
+ request: this.request,
901
+ response
902
+ });
903
+ if (undefined !== reactBootstrap && response) {
676
904
  switch (requestMethod) {
677
905
  case GET:
906
+ response.data && reactBootstrap.updateRestfulObjectArrays({
907
+ dataOrCallback: Array.isArray(response.data.rest) ? response.data.rest : [response.data.rest],
908
+ stateKey: this.config.restModel.TABLE_NAME,
909
+ uniqueObjectId: this.config.restModel.PRIMARY_SHORT,
910
+ callback
911
+ });
912
+ break;
678
913
  case POST:
914
+ this.postState(response, this.request, callback);
915
+ break;
679
916
  case PUT:
917
+ this.putState(response, this.request, callback);
918
+ break;
680
919
  case DELETE:
920
+ this.deleteState(response, this.request, callback);
681
921
  break;
682
- default:
683
- throw Error('Bad request method passed to getApi');
684
922
  }
685
- if (null !== clearCache || undefined !== clearCache) {
686
- exports.userCustomClearCache[tables + requestMethod] = clearCache;
687
- }
688
- console.groupCollapsed('%c API: (' + requestMethod + ') Request for (' + tableName + ')', 'color: #0c0');
689
- console.log('request', this.request);
690
- console.groupEnd();
691
- // an undefined query would indicate queryCallback returned undefined,
692
- // thus the request shouldn't fire as is in custom cache
693
- if (undefined === this.request || null === this.request) {
694
- console.groupCollapsed('%c API: (' + requestMethod + ') Request Query for (' + tableName + ') undefined, returning null (will not fire)!', 'color: #c00');
695
- console.log('request', this.request);
696
- console.log('%c Returning (undefined|null) for a query would indicate a custom cache hit (outside API.tsx), thus the request should not fire.', 'color: #c00');
923
+ }
924
+ else {
925
+ callback();
926
+ }
927
+ if (C6.GET === requestMethod) {
928
+ const responseData = response.data;
929
+ returnGetNextPageFunction = 1 !== query?.[C6.PAGINATION]?.[C6.LIMIT] &&
930
+ query?.[C6.PAGINATION]?.[C6.LIMIT] === responseData.rest.length;
931
+ if (false === isTest() || this.config.verbose) {
932
+ console.groupCollapsed('%c API: Response (' + requestMethod + ' ' + tableName + ') returned length (' + responseData.rest?.length + ') of possible (' + query?.[C6.PAGINATION]?.[C6.LIMIT] + ') limit!', 'color: #0c0');
933
+ console.log('%c ' + requestMethod + ' ' + tableName, 'color: #0c0');
934
+ console.log('%c Request Data (note you may see the success and/or error prompt):', 'color: #0c0', this.request);
935
+ console.log('%c Response Data:', 'color: #0c0', responseData.rest);
936
+ console.log('%c Will return get next page function:' + (returnGetNextPageFunction ? '' : ' (Will not return with explicit limit 1 set)'), 'color: #0c0', true === returnGetNextPageFunction);
697
937
  console.trace();
698
938
  console.groupEnd();
699
- return [2 /*return*/, null];
700
939
  }
701
- query = this.request;
702
- if (C6.GET === requestMethod) {
703
- if (undefined === query[C6.PAGINATION]) {
704
- query[C6.PAGINATION] = {};
940
+ if (false === returnGetNextPageFunction) {
941
+ responseData.next = apiRequest;
942
+ }
943
+ else {
944
+ responseData.next = undefined;
945
+ if (true === debug
946
+ && isLocal()) {
947
+ reactToastify.toast.success("DEVS: Response returned length (" + responseData.rest?.length + ") less than limit (" + query?.[C6.PAGINATION]?.[C6.LIMIT] + ").", toastOptionsDevs);
705
948
  }
706
- query[C6.PAGINATION][C6.PAGE] = query[C6.PAGINATION][C6.PAGE] || 1;
707
- query[C6.PAGINATION][C6.LIMIT] = query[C6.PAGINATION][C6.LIMIT] || 100;
708
949
  }
709
- apiRequest = function () { return tslib.__awaiter(_this, void 0, void 0, function () {
710
- var _a, debug, _b, cacheResults, dataInsertMultipleRows, success, _c, fetchDependencies, _d, error, querySerialized, cacheResult, cachingConfirmed, cacheCheck, cacheCheck, addBackPK, apiResponse, returnGetNextPageFunction, restRequestUri, needsConditionOrPrimaryCheck, TABLES, primaryKey, removedPkValue_1, axiosActiveRequest;
711
- var _e;
712
- var _this = this;
713
- var _f, _g, _h, _j, _k, _l;
714
- return tslib.__generator(this, function (_m) {
715
- switch (_m.label) {
716
- case 0:
717
- _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 ? exports.eFetchDependencies.NONE : _c, _d = _a.error, error = _d === void 0 ? "An unexpected API error occurred!" : _d;
718
- if (C6.GET === requestMethod
719
- && undefined !== ((_f = query === null || query === void 0 ? void 0 : query[C6.PAGINATION]) === null || _f === void 0 ? void 0 : _f[C6.PAGE])
720
- && 1 !== query[C6.PAGINATION][C6.PAGE]) {
721
- console.groupCollapsed('Request on table (' + tableName + ') is firing for page (' + query[C6.PAGINATION][C6.PAGE] + '), please wait!');
722
- console.log('Request Data (note you may see the success and/or error prompt):', this.request);
723
- console.trace();
724
- console.groupEnd();
725
- }
726
- querySerialized = sortAndSerializeQueryObject(tables, query !== null && query !== void 0 ? query : {});
727
- cacheResult = exports.apiRequestCache.find(function (cache) { return cache.requestArgumentsSerialized === querySerialized; });
728
- cachingConfirmed = false;
729
- if (!(requestMethod === C6.GET)) return [3 /*break*/, 9];
730
- if (undefined === (query === null || query === void 0 ? void 0 : query[C6.PAGINATION])) {
731
- if (undefined === query || null === query) {
732
- query = {};
733
- }
734
- query[C6.PAGINATION] = {};
735
- }
736
- query[C6.PAGINATION][C6.PAGE] = query[C6.PAGINATION][C6.PAGE] || 1;
737
- query[C6.PAGINATION][C6.LIMIT] = query[C6.PAGINATION][C6.LIMIT] || 100;
738
- if (!(true === cacheResults)) return [3 /*break*/, 7];
739
- if (!(undefined !== cacheResult)) return [3 /*break*/, 6];
740
- _m.label = 1;
741
- case 1:
742
- cacheCheck = checkCache(cacheResult, requestMethod, tableName, this.request);
743
- if (!(false !== cacheCheck)) return [3 /*break*/, 3];
744
- return [4 /*yield*/, cacheCheck];
745
- case 2: return [2 /*return*/, (_m.sent()).data];
746
- case 3:
747
- // this line incrementing page is why we return recursively
748
- ++query[C6.PAGINATION][C6.PAGE];
749
- // this json stringify is to capture the new page number
750
- querySerialized = sortAndSerializeQueryObject(tables, query !== null && query !== void 0 ? query : {});
751
- cacheResult = exports.apiRequestCache.find(function (cache) { return cache.requestArgumentsSerialized === querySerialized; });
752
- _m.label = 4;
753
- case 4:
754
- if (undefined !== cacheResult) return [3 /*break*/, 1];
755
- _m.label = 5;
756
- case 5:
757
- if (debug && isLocal()) {
758
- reactToastify.toast.warning("DEVS: Request in cache. (" + exports.apiRequestCache.findIndex(function (cache) { return cache.requestArgumentsSerialized === querySerialized; }) + "). Returning function to request page (" + query[C6.PAGINATION][C6.PAGE] + ")", toastOptionsDevs);
759
- }
760
- // @ts-ignore - this is an incorrect warning on TS, it's well typed
761
- return [2 /*return*/, apiRequest];
762
- case 6:
763
- cachingConfirmed = true;
764
- return [3 /*break*/, 8];
765
- case 7:
766
- if (debug && isLocal()) {
767
- reactToastify.toast.info("DEVS: Ignore cache was set to true.", toastOptionsDevs);
768
- }
769
- _m.label = 8;
770
- case 8:
771
- if (debug && isLocal()) {
772
- reactToastify.toast.success("DEVS: Request not in cache." + (requestMethod === C6.GET ? "Page (" + query[C6.PAGINATION][C6.PAGE] + ")." : '') + " Logging cache 2 console.", toastOptionsDevs);
773
- }
774
- return [3 /*break*/, 12];
775
- case 9:
776
- if (!cacheResults) return [3 /*break*/, 12];
777
- if (!cacheResult) return [3 /*break*/, 11];
778
- cacheCheck = checkCache(cacheResult, requestMethod, tableName, this.request);
779
- if (!(false !== cacheCheck)) return [3 /*break*/, 11];
780
- return [4 /*yield*/, cacheCheck];
781
- case 10: return [2 /*return*/, (_m.sent()).data];
782
- case 11:
783
- cachingConfirmed = true;
784
- _m.label = 12;
785
- case 12:
786
- returnGetNextPageFunction = false;
787
- restRequestUri = restURL + operatingTable + '/';
788
- needsConditionOrPrimaryCheck = (PUT === requestMethod || DELETE === requestMethod)
789
- && false === skipPrimaryCheck;
790
- TABLES = C6.TABLES;
791
- primaryKey = (_k = (_j = (_h = structuredClone((_g = TABLES[operatingTable]) === null || _g === void 0 ? void 0 : _g.PRIMARY)) === null || _h === void 0 ? void 0 : _h.pop()) === null || _j === void 0 ? void 0 : _j.split('.')) === null || _k === void 0 ? void 0 : _k.pop();
792
- if (needsConditionOrPrimaryCheck) {
793
- if (undefined === primaryKey) {
794
- if (null === query
795
- || undefined === query
796
- || undefined === (query === null || query === void 0 ? void 0 : query[C6.WHERE])
797
- || (true === Array.isArray(query[C6.WHERE])
798
- || query[C6.WHERE].length === 0)
799
- || (Object.keys(query === null || query === void 0 ? void 0 : query[C6.WHERE]).length === 0)) {
800
- console.error(query);
801
- throw Error('Failed to parse primary key information. Query: (' + JSON.stringify(query) + ') Primary Key: (' + JSON.stringify(primaryKey) + ') TABLES[operatingTable]?.PRIMARY: (' + JSON.stringify((_l = TABLES[operatingTable]) === null || _l === void 0 ? void 0 : _l.PRIMARY) + ') for operatingTable (' + operatingTable + ').');
802
- }
803
- }
804
- else {
805
- if (undefined === query
806
- || null === query
807
- || false === primaryKey in query) {
808
- if (true === debug && isLocal()) {
809
- reactToastify.toast.error('DEVS: The primary key (' + primaryKey + ') was not provided!!');
810
- }
811
- throw Error('You must provide the primary key (' + primaryKey + ') for table (' + operatingTable + '). Request (' + JSON.stringify(this.request, undefined, 4) + ') Query (' + JSON.stringify(query) + ')');
812
- }
813
- if (undefined === (query === null || query === void 0 ? void 0 : query[primaryKey])
814
- || null === (query === null || query === void 0 ? void 0 : query[primaryKey])) {
815
- reactToastify.toast.error('The primary key (' + primaryKey + ') provided is undefined or null explicitly!!');
816
- throw Error('The primary key (' + primaryKey + ') provided in the request was exactly equal to undefined.');
950
+ if (fetchDependencies
951
+ && 'number' === typeof fetchDependencies
952
+ && responseData.rest.length > 0) {
953
+ console.groupCollapsed('%c API: Fetch Dependencies segment (' + requestMethod + ' ' + tableName + ')'
954
+ + (fetchDependencies & exports.eFetchDependencies.CHILDREN ? ' | (CHILDREN|REFERENCED) ' : '')
955
+ + (fetchDependencies & exports.eFetchDependencies.PARENTS ? ' | (PARENTS|REFERENCED_BY)' : '')
956
+ + (fetchDependencies & exports.eFetchDependencies.C6ENTITY ? ' | (C6ENTITY)' : '')
957
+ + (fetchDependencies & exports.eFetchDependencies.RECURSIVE ? ' | (RECURSIVE)' : ''), 'color: #33ccff');
958
+ console.groupCollapsed('Collapsed JS Trace');
959
+ console.trace(); // hidden in collapsed group
960
+ console.groupEnd();
961
+ // noinspection JSBitwiseOperatorUsage
962
+ let dependencies = {};
963
+ // Remember this is a binary bitwise operation, so we can check for multiple dependencies at once
964
+ if (fetchDependencies & exports.eFetchDependencies.C6ENTITY) {
965
+ dependencies = operatingTable.endsWith("carbon_carbons")
966
+ ? {
967
+ // the context of the entity system is a bit different
968
+ ...fetchDependencies & exports.eFetchDependencies.CHILDREN // REFERENCED === CHILDREN
969
+ ? C6.TABLES[operatingTable].TABLE_REFERENCED_BY
970
+ : {},
971
+ ...fetchDependencies & exports.eFetchDependencies.PARENTS // REFERENCES === PARENTS
972
+ ? C6.TABLES[operatingTable].TABLE_REFERENCES
973
+ : {}
974
+ } : {
975
+ // the context of the entity system is a bit different
976
+ ...fetchDependencies & exports.eFetchDependencies.CHILDREN // REFERENCED === CHILDREN
977
+ ? {
978
+ ...Object.keys(C6.TABLES[operatingTable].TABLE_REFERENCES).reduce((accumulator, columnName) => {
979
+ if (!C6.TABLES[operatingTable].PRIMARY_SHORT.includes(columnName)) {
980
+ accumulator[columnName] = C6.TABLES[operatingTable].TABLE_REFERENCES[columnName];
817
981
  }
818
- }
819
- }
820
- // A part of me exists that wants to remove this, but it's a good feature
821
- // this allows developers the ability to cache requests based on primary key
822
- // for tables like `photos` this can be a huge performance boost
823
- if (undefined !== query
824
- && null !== query
825
- && undefined !== primaryKey
826
- && primaryKey in query) {
827
- restRequestUri += query[primaryKey] + '/';
828
- removedPkValue_1 = query[primaryKey];
829
- addBackPK = function () {
830
- query !== null && query !== void 0 ? query : (query = {});
831
- query[primaryKey] = removedPkValue_1;
832
- };
833
- delete query[primaryKey];
834
- console.log('query', query, 'primaryKey', primaryKey, 'removedPkValue', removedPkValue_1);
835
- }
836
- else {
837
- console.log('query', query);
982
+ return accumulator;
983
+ }, {}),
984
+ ...C6.TABLES[operatingTable].TABLE_REFERENCED_BY // it is unlikely that a C6 table will have any TABLE_REFERENCED_BY
838
985
  }
839
- try {
840
- console.groupCollapsed('%c API: (' + requestMethod + ') Request Query for (' + operatingTable + ') is about to fire, will return with promise!', 'color: #A020F0');
841
- console.log(this.request);
842
- console.log('%c If this is the first request for this datatype; thus the value being set is currently undefined, please remember to update the state to null.', 'color: #A020F0');
843
- console.log('%c Remember undefined indicated the request has not fired, null indicates the request is firing, an empty array would signal no data was returned for the sql stmt.', 'color: #A020F0');
844
- console.trace();
845
- console.groupEnd();
846
- this.runLifecycleHooks("beforeExecution", {
847
- config: this.config,
848
- request: this.request
849
- });
850
- axiosActiveRequest = (_e = axios)[requestMethod.toLowerCase()].apply(_e, tslib.__spreadArray([restRequestUri], (function () {
851
- var convert = function (data) {
852
- return convertForRequestBody(data, fullTableList, C6, function (message) { return reactToastify.toast.error(message, toastOptions); });
853
- };
854
- var baseConfig = {
855
- withCredentials: withCredentials,
856
- };
857
- switch (requestMethod) {
858
- case GET:
859
- return [tslib.__assign(tslib.__assign({}, baseConfig), { params: query })];
860
- case POST:
861
- if (dataInsertMultipleRows !== undefined) {
862
- return [
863
- dataInsertMultipleRows.map(convert),
864
- baseConfig
865
- ];
866
- }
867
- return [convert(query), baseConfig];
868
- case PUT:
869
- return [convert(query), baseConfig];
870
- case DELETE:
871
- return [tslib.__assign(tslib.__assign({}, baseConfig), { data: convert(query) })];
872
- default:
873
- throw new Error("The request method (".concat(requestMethod, ") was not recognized."));
874
- }
875
- })(), false));
876
- if (cachingConfirmed) {
877
- // push to cache so we do not repeat the request
878
- exports.apiRequestCache.push({
879
- requestArgumentsSerialized: querySerialized,
880
- request: axiosActiveRequest
881
- });
986
+ : {},
987
+ ...fetchDependencies & exports.eFetchDependencies.PARENTS // REFERENCES === PARENTS
988
+ ? C6.TABLES[operatingTable].PRIMARY_SHORT.reduce((accumulator, primaryKey) => {
989
+ if (primaryKey in C6.TABLES[operatingTable].TABLE_REFERENCES) {
990
+ accumulator[primaryKey] = C6.TABLES[operatingTable].TABLE_REFERENCES[primaryKey];
882
991
  }
883
- // todo - wip verify this works
884
- // we had removed the value from the request to add to the URI.
885
- addBackPK === null || addBackPK === void 0 ? void 0 : addBackPK(); // adding back so post-processing methods work
886
- // returning the promise with this then is important for tests. todo - we could make that optional.
887
- // https://rapidapi.com/guides/axios-async-await
888
- return [2 /*return*/, axiosActiveRequest.then(function (response) { return tslib.__awaiter(_this, void 0, void 0, function () {
889
- var cacheIndex, callback, responseData_1, dependencies_1, fetchReferences_1, apiRequestPromises, _loop_1, _a, _b, _c, _i, tableToFetch;
890
- var _this = this;
891
- var _d, _e, _f, _g, _h, _j;
892
- return tslib.__generator(this, function (_k) {
893
- switch (_k.label) {
894
- case 0:
895
- // noinspection SuspiciousTypeOfGuard
896
- if (typeof response.data === 'string') {
897
- if (isTest()) {
898
- console.trace();
899
- throw new Error('The response data was a string this typically indicated html was sent. Make sure all cookies (' + JSON.stringify(response.config.headers) + ') needed are present! (' + response.data + ')');
900
- }
901
- return [2 /*return*/, Promise.reject(response)];
902
- }
903
- if (cachingConfirmed) {
904
- cacheIndex = exports.apiRequestCache.findIndex(function (cache) { return cache.requestArgumentsSerialized === querySerialized; });
905
- // TODO - currently nonthing is setting this correctly
906
- exports.apiRequestCache[cacheIndex].final = false === returnGetNextPageFunction;
907
- // only cache get method requests
908
- exports.apiRequestCache[cacheIndex].response = response;
909
- }
910
- this.runLifecycleHooks("afterExecution", {
911
- config: this.config,
912
- request: this.request,
913
- response: response
914
- });
915
- // todo - this feels dumb now, but i digress
916
- apiResponse = TestRestfulResponse(response, success, error);
917
- if (false === apiResponse) {
918
- if (debug && isLocal()) {
919
- reactToastify.toast.warning("DEVS: TestRestfulResponse returned false for (" + operatingTable + ").", toastOptionsDevs);
920
- }
921
- return [2 /*return*/, response];
922
- }
923
- callback = function () { return _this.runLifecycleHooks("afterCommit", {
924
- config: _this.config,
925
- request: _this.request,
926
- response: response
927
- }); };
928
- if (undefined !== reactBootstrap && response) {
929
- switch (requestMethod) {
930
- case GET:
931
- response.data && reactBootstrap.updateRestfulObjectArrays({
932
- dataOrCallback: Array.isArray(response.data.rest) ? response.data.rest : [response.data.rest],
933
- stateKey: this.config.restModel.TABLE_NAME,
934
- uniqueObjectId: this.config.restModel.PRIMARY_SHORT,
935
- callback: callback
936
- });
937
- break;
938
- case POST:
939
- this.postState(response, this.request, callback);
940
- break;
941
- case PUT:
942
- this.putState(response, this.request, callback);
943
- break;
944
- case DELETE:
945
- this.deleteState(response, this.request, callback);
946
- break;
947
- }
948
- }
949
- else {
950
- callback();
951
- }
952
- if (!(C6.GET === requestMethod)) return [3 /*break*/, 6];
953
- responseData_1 = response.data;
954
- returnGetNextPageFunction = 1 !== ((_d = query === null || query === void 0 ? void 0 : query[C6.PAGINATION]) === null || _d === void 0 ? void 0 : _d[C6.LIMIT]) &&
955
- ((_e = query === null || query === void 0 ? void 0 : query[C6.PAGINATION]) === null || _e === void 0 ? void 0 : _e[C6.LIMIT]) === responseData_1.rest.length;
956
- if (false === isTest() || this.config.verbose) {
957
- console.groupCollapsed('%c API: Response (' + requestMethod + ' ' + tableName + ') returned length (' + ((_f = responseData_1.rest) === null || _f === void 0 ? void 0 : _f.length) + ') of possible (' + ((_g = query === null || query === void 0 ? void 0 : query[C6.PAGINATION]) === null || _g === void 0 ? void 0 : _g[C6.LIMIT]) + ') limit!', 'color: #0c0');
958
- console.log('%c ' + requestMethod + ' ' + tableName, 'color: #0c0');
959
- console.log('%c Request Data (note you may see the success and/or error prompt):', 'color: #0c0', this.request);
960
- console.log('%c Response Data:', 'color: #0c0', responseData_1.rest);
961
- console.log('%c Will return get next page function:' + (returnGetNextPageFunction ? '' : ' (Will not return with explicit limit 1 set)'), 'color: #0c0', true === returnGetNextPageFunction);
962
- console.trace();
963
- console.groupEnd();
964
- }
965
- if (false === returnGetNextPageFunction) {
966
- responseData_1.next = apiRequest;
967
- }
968
- else {
969
- responseData_1.next = undefined;
970
- if (true === debug
971
- && isLocal()) {
972
- reactToastify.toast.success("DEVS: Response returned length (" + ((_h = responseData_1.rest) === null || _h === void 0 ? void 0 : _h.length) + ") less than limit (" + ((_j = query === null || query === void 0 ? void 0 : query[C6.PAGINATION]) === null || _j === void 0 ? void 0 : _j[C6.LIMIT]) + ").", toastOptionsDevs);
973
- }
974
- }
975
- if (!(fetchDependencies
976
- && 'number' === typeof fetchDependencies
977
- && responseData_1.rest.length > 0)) return [3 /*break*/, 6];
978
- console.groupCollapsed('%c API: Fetch Dependencies segment (' + requestMethod + ' ' + tableName + ')'
979
- + (fetchDependencies & exports.eFetchDependencies.CHILDREN ? ' | (CHILDREN|REFERENCED) ' : '')
980
- + (fetchDependencies & exports.eFetchDependencies.PARENTS ? ' | (PARENTS|REFERENCED_BY)' : '')
981
- + (fetchDependencies & exports.eFetchDependencies.C6ENTITY ? ' | (C6ENTITY)' : '')
982
- + (fetchDependencies & exports.eFetchDependencies.RECURSIVE ? ' | (RECURSIVE)' : ''), 'color: #33ccff');
983
- console.groupCollapsed('Collapsed JS Trace');
984
- console.trace(); // hidden in collapsed group
985
- console.groupEnd();
986
- dependencies_1 = {};
987
- // Remember this is a binary bitwise operation, so we can check for multiple dependencies at once
988
- if (fetchDependencies & exports.eFetchDependencies.C6ENTITY) {
989
- dependencies_1 = operatingTable.endsWith("carbon_carbons")
990
- ? tslib.__assign(tslib.__assign({}, fetchDependencies & exports.eFetchDependencies.CHILDREN // REFERENCED === CHILDREN
991
- ? C6.TABLES[operatingTable].TABLE_REFERENCED_BY
992
- : {}), fetchDependencies & exports.eFetchDependencies.PARENTS // REFERENCES === PARENTS
993
- ? C6.TABLES[operatingTable].TABLE_REFERENCES
994
- : {}) : tslib.__assign(tslib.__assign({}, fetchDependencies & exports.eFetchDependencies.CHILDREN // REFERENCED === CHILDREN
995
- ? tslib.__assign(tslib.__assign({}, Object.keys(C6.TABLES[operatingTable].TABLE_REFERENCES).reduce(function (accumulator, columnName) {
996
- if (!C6.TABLES[operatingTable].PRIMARY_SHORT.includes(columnName)) {
997
- accumulator[columnName] = C6.TABLES[operatingTable].TABLE_REFERENCES[columnName];
998
- }
999
- return accumulator;
1000
- }, {})), C6.TABLES[operatingTable].TABLE_REFERENCED_BY // it is unlikely that a C6 table will have any TABLE_REFERENCED_BY
1001
- ) : {}), fetchDependencies & exports.eFetchDependencies.PARENTS // REFERENCES === PARENTS
1002
- ? C6.TABLES[operatingTable].PRIMARY_SHORT.reduce(function (accumulator, primaryKey) {
1003
- if (primaryKey in C6.TABLES[operatingTable].TABLE_REFERENCES) {
1004
- accumulator[primaryKey] = C6.TABLES[operatingTable].TABLE_REFERENCES[primaryKey];
1005
- }
1006
- return accumulator;
1007
- }, {})
1008
- : {});
1009
- }
1010
- else {
1011
- // this is the natural mysql context
1012
- dependencies_1 = tslib.__assign(tslib.__assign({}, fetchDependencies & exports.eFetchDependencies.REFERENCED // REFERENCED === CHILDREN
1013
- ? C6.TABLES[operatingTable].TABLE_REFERENCED_BY
1014
- : {}), fetchDependencies & exports.eFetchDependencies.REFERENCES // REFERENCES === PARENTS
1015
- ? C6.TABLES[operatingTable].TABLE_REFERENCES
1016
- : {});
1017
- }
1018
- fetchReferences_1 = {};
1019
- apiRequestPromises = [];
1020
- console.log('%c Dependencies', 'color: #005555', dependencies_1);
1021
- Object.keys(dependencies_1)
1022
- .forEach(function (column) { return dependencies_1[column]
1023
- .forEach(function (constraint) {
1024
- var _a, _b, _c, _d;
1025
- var _e, _f, _g;
1026
- var columnValues = (_b = (_a = responseData_1.rest[column]) !== null && _a !== void 0 ? _a : responseData_1.rest.map(function (row) {
1027
- if (operatingTable.endsWith("carbons")
1028
- && 'entity_tag' in row
1029
- && !constraint.TABLE.endsWith(row['entity_tag'].split('\\').pop().toLowerCase())) {
1030
- return false; // map
1031
- }
1032
- if (!(column in row)) {
1033
- return false;
1034
- }
1035
- // todo - row[column] is a FK value, we should optionally remove values that are already in state
1036
- // this could be any column in the table constraint.TABLE, not just the primary key
1037
- return row[column];
1038
- }).filter(function (n) { return n; })) !== null && _b !== void 0 ? _b : [];
1039
- if (columnValues.length === 0) {
1040
- return; // forEach
1041
- }
1042
- (_c = fetchReferences_1[_e = constraint.TABLE]) !== null && _c !== void 0 ? _c : (fetchReferences_1[_e] = {});
1043
- (_d = (_f = fetchReferences_1[constraint.TABLE])[_g = constraint.COLUMN]) !== null && _d !== void 0 ? _d : (_f[_g] = []);
1044
- fetchReferences_1[constraint.TABLE][constraint.COLUMN].push(columnValues);
1045
- }); });
1046
- console.log('fetchReferences', fetchReferences_1);
1047
- _loop_1 = function (tableToFetch) {
1048
- var referencesTables, shouldContinue, fetchTable, RestApi, nextFetchDependencies;
1049
- var _l;
1050
- return tslib.__generator(this, function (_m) {
1051
- switch (_m.label) {
1052
- case 0:
1053
- if (fetchDependencies & exports.eFetchDependencies.C6ENTITY
1054
- && 'string' === typeof tableName
1055
- && tableName.endsWith("carbon_carbons")) {
1056
- referencesTables = responseData_1.rest.reduce(function (accumulator, row) {
1057
- if ('entity_tag' in row && !accumulator.includes(row['entity_tag'])) {
1058
- accumulator.push(row['entity_tag']);
1059
- }
1060
- return accumulator;
1061
- }, []).map(function (entityTag) { return entityTag.split('\\').pop().toLowerCase(); });
1062
- shouldContinue = referencesTables.find(function (referencesTable) { return tableToFetch.endsWith(referencesTable); });
1063
- if (!shouldContinue) {
1064
- console.log('%c C6ENTITY: The constraintTableName (' + tableToFetch + ') did not end with any value in referencesTables', 'color: #c00', referencesTables);
1065
- return [2 /*return*/, "continue"];
1066
- }
1067
- console.log('%c C6ENTITY: The constraintTableName (' + tableToFetch + ') will be fetched.', 'color: #0c0');
1068
- }
1069
- return [4 /*yield*/, C6.IMPORT(tableToFetch)];
1070
- case 1:
1071
- fetchTable = _m.sent();
1072
- RestApi = fetchTable.default;
1073
- console.log('%c Fetch Dependencies will select (' + tableToFetch + ') using GET request', 'color: #33ccff');
1074
- nextFetchDependencies = exports.eFetchDependencies.NONE;
1075
- if (fetchDependencies & exports.eFetchDependencies.RECURSIVE) {
1076
- if (fetchDependencies & exports.eFetchDependencies.ALL) {
1077
- throw Error('Recursive fetch dependencies with both PARENT and CHILD reference will result in an infin1ite loop. As there is not real ending condition, this is not supported.');
1078
- }
1079
- nextFetchDependencies = fetchDependencies;
1080
- }
1081
- else if (fetchDependencies & exports.eFetchDependencies.C6ENTITY) {
1082
- if (tableToFetch === "carbon_carbons") {
1083
- nextFetchDependencies = fetchDependencies;
1084
- }
1085
- else {
1086
- nextFetchDependencies = fetchDependencies ^ exports.eFetchDependencies.C6ENTITY;
1087
- }
1088
- }
1089
- console.log('fetchReferences', fetchReferences_1[tableToFetch], "Current fetchDependencies for (" + operatingTable + "):", fetchDependencies, "New fetchDependencies for (" + tableToFetch + "): ", nextFetchDependencies);
1090
- // todo - filter out ids that exist in state?!? note - remember that this does not necessarily mean the pk, but only known is its an FK to somewhere
1091
- // it not certain that they are using carbons' entities either
1092
- // this is a dynamic call to the rest api, any generated table may resolve with (RestApi)
1093
- // todo - using value to avoid joins.... but. maybe this should be a parameterizable option -- think race conditions; its safer to join
1094
- apiRequestPromises.push(RestApi.Get((_l = {},
1095
- _l[C6.WHERE] = {
1096
- 0: Object.keys(fetchReferences_1[tableToFetch]).reduce(function (sum, column) {
1097
- fetchReferences_1[tableToFetch][column] = fetchReferences_1[tableToFetch][column].flat(Infinity);
1098
- if (0 === fetchReferences_1[tableToFetch][column].length) {
1099
- console.warn('The column (' + column + ') was not found in the response data. We will not fetch.', responseData_1);
1100
- return false;
1101
- }
1102
- sum[column] = fetchReferences_1[tableToFetch][column].length === 1
1103
- ? fetchReferences_1[tableToFetch][column][0]
1104
- : [
1105
- C6.IN, fetchReferences_1[tableToFetch][column]
1106
- ];
1107
- return sum;
1108
- }, {})
1109
- },
1110
- _l.fetchDependencies = nextFetchDependencies,
1111
- _l)));
1112
- return [2 /*return*/];
1113
- }
1114
- });
1115
- };
1116
- _a = fetchReferences_1;
1117
- _b = [];
1118
- for (_c in _a)
1119
- _b.push(_c);
1120
- _i = 0;
1121
- _k.label = 1;
1122
- case 1:
1123
- if (!(_i < _b.length)) return [3 /*break*/, 4];
1124
- _c = _b[_i];
1125
- if (!(_c in _a)) return [3 /*break*/, 3];
1126
- tableToFetch = _c;
1127
- return [5 /*yield**/, _loop_1(tableToFetch)];
1128
- case 2:
1129
- _k.sent();
1130
- _k.label = 3;
1131
- case 3:
1132
- _i++;
1133
- return [3 /*break*/, 1];
1134
- case 4:
1135
- console.groupEnd();
1136
- return [4 /*yield*/, Promise.all(apiRequestPromises)];
1137
- case 5:
1138
- _k.sent();
1139
- apiRequestPromises.map(function (promise) { return tslib.__awaiter(_this, void 0, void 0, function () {
1140
- var _a, _b;
1141
- return tslib.__generator(this, function (_c) {
1142
- switch (_c.label) {
1143
- case 0:
1144
- if (!Array.isArray(this.request.fetchDependencies)) {
1145
- // to reassign value we must ref the root
1146
- this.request.fetchDependencies = [];
1147
- }
1148
- _b = (_a = this.request.fetchDependencies).push;
1149
- return [4 /*yield*/, promise];
1150
- case 1:
1151
- _b.apply(_a, [_c.sent()]);
1152
- return [2 /*return*/];
1153
- }
1154
- });
1155
- }); });
1156
- _k.label = 6;
1157
- case 6:
1158
- if (debug && isLocal()) {
1159
- reactToastify.toast.success("DEVS: (" + requestMethod + ") request complete.", toastOptionsDevs);
1160
- }
1161
- // this is the literal axios return
1162
- return [2 /*return*/, response];
1163
- }
1164
- });
1165
- }); }).then(function (response) { return response.data; })]; // this escapes from axios context
992
+ return accumulator;
993
+ }, {})
994
+ : {}
995
+ };
996
+ }
997
+ else {
998
+ // this is the natural mysql context
999
+ dependencies = {
1000
+ ...fetchDependencies & exports.eFetchDependencies.REFERENCED // REFERENCED === CHILDREN
1001
+ ? C6.TABLES[operatingTable].TABLE_REFERENCED_BY
1002
+ : {},
1003
+ ...fetchDependencies & exports.eFetchDependencies.REFERENCES // REFERENCES === PARENTS
1004
+ ? C6.TABLES[operatingTable].TABLE_REFERENCES
1005
+ : {}
1006
+ };
1007
+ }
1008
+ let fetchReferences = {};
1009
+ let apiRequestPromises = [];
1010
+ console.log('%c Dependencies', 'color: #005555', dependencies);
1011
+ Object.keys(dependencies)
1012
+ .forEach(column => dependencies[column]
1013
+ .forEach((constraint) => {
1014
+ const columnValues = responseData.rest[column] ?? responseData.rest.map((row) => {
1015
+ if (operatingTable.endsWith("carbons")
1016
+ && 'entity_tag' in row
1017
+ && !constraint.TABLE.endsWith(row['entity_tag'].split('\\').pop().toLowerCase())) {
1018
+ return false; // map
1019
+ }
1020
+ if (!(column in row)) {
1021
+ return false;
1022
+ }
1023
+ // todo - row[column] is a FK value, we should optionally remove values that are already in state
1024
+ // this could be any column in the table constraint.TABLE, not just the primary key
1025
+ return row[column];
1026
+ }).filter(n => n) ?? [];
1027
+ if (columnValues.length === 0) {
1028
+ return; // forEach
1029
+ }
1030
+ fetchReferences[constraint.TABLE] ??= {};
1031
+ fetchReferences[constraint.TABLE][constraint.COLUMN] ??= [];
1032
+ fetchReferences[constraint.TABLE][constraint.COLUMN].push(columnValues);
1033
+ }));
1034
+ console.log('fetchReferences', fetchReferences);
1035
+ for (const tableToFetch in fetchReferences) {
1036
+ if (fetchDependencies & exports.eFetchDependencies.C6ENTITY
1037
+ && 'string' === typeof tableName
1038
+ && tableName.endsWith("carbon_carbons")) {
1039
+ // todo - rethink the table ref entity system - when tables are renamed? no hooks exist in mysql
1040
+ // since were already filtering on column, we can assume the first row constraint is the same as the rest
1041
+ const referencesTables = responseData.rest.reduce((accumulator, row) => {
1042
+ if ('entity_tag' in row && !accumulator.includes(row['entity_tag'])) {
1043
+ accumulator.push(row['entity_tag']);
1166
1044
  }
1167
- catch (throwableError) {
1168
- if (isTest()) {
1169
- throw new Error(JSON.stringify(throwableError));
1045
+ return accumulator;
1046
+ }, []).map((entityTag) => entityTag.split('\\').pop().toLowerCase());
1047
+ const shouldContinue = referencesTables.find((referencesTable) => tableToFetch.endsWith(referencesTable));
1048
+ if (!shouldContinue) {
1049
+ console.log('%c C6ENTITY: The constraintTableName (' + tableToFetch + ') did not end with any value in referencesTables', 'color: #c00', referencesTables);
1050
+ continue;
1051
+ }
1052
+ console.log('%c C6ENTITY: The constraintTableName (' + tableToFetch + ') will be fetched.', 'color: #0c0');
1053
+ }
1054
+ const fetchTable = await C6.IMPORT(tableToFetch);
1055
+ const RestApi = fetchTable.default;
1056
+ console.log('%c Fetch Dependencies will select (' + tableToFetch + ') using GET request', 'color: #33ccff');
1057
+ let nextFetchDependencies = exports.eFetchDependencies.NONE;
1058
+ if (fetchDependencies & exports.eFetchDependencies.RECURSIVE) {
1059
+ if (fetchDependencies & exports.eFetchDependencies.ALL) {
1060
+ throw Error('Recursive fetch dependencies with both PARENT and CHILD reference will result in an infin1ite loop. As there is not real ending condition, this is not supported.');
1061
+ }
1062
+ nextFetchDependencies = fetchDependencies;
1063
+ }
1064
+ else if (fetchDependencies & exports.eFetchDependencies.C6ENTITY) {
1065
+ if (tableToFetch === "carbon_carbons") {
1066
+ nextFetchDependencies = fetchDependencies;
1067
+ }
1068
+ else {
1069
+ nextFetchDependencies = fetchDependencies ^ exports.eFetchDependencies.C6ENTITY;
1070
+ }
1071
+ }
1072
+ console.log('fetchReferences', fetchReferences[tableToFetch], "Current fetchDependencies for (" + operatingTable + "):", fetchDependencies, "New fetchDependencies for (" + tableToFetch + "): ", nextFetchDependencies);
1073
+ // todo - filter out ids that exist in state?!? note - remember that this does not necessarily mean the pk, but only known is its an FK to somewhere
1074
+ // it not certain that they are using carbons' entities either
1075
+ // this is a dynamic call to the rest api, any generated table may resolve with (RestApi)
1076
+ // todo - using value to avoid joins.... but. maybe this should be a parameterizable option -- think race conditions; its safer to join
1077
+ apiRequestPromises.push(RestApi.Get({
1078
+ [C6.WHERE]: {
1079
+ 0: Object.keys(fetchReferences[tableToFetch]).reduce((sum, column) => {
1080
+ fetchReferences[tableToFetch][column] = fetchReferences[tableToFetch][column].flat(Infinity);
1081
+ if (0 === fetchReferences[tableToFetch][column].length) {
1082
+ console.warn('The column (' + column + ') was not found in the response data. We will not fetch.', responseData);
1083
+ return false;
1170
1084
  }
1171
- console.groupCollapsed('%c API: An error occurred in the try catch block. returning null!', 'color: #ff0000');
1172
- console.log('%c ' + requestMethod + ' ' + tableName, 'color: #A020F0');
1173
- console.warn(throwableError);
1174
- console.trace();
1175
- console.groupEnd();
1176
- TestRestfulResponse(throwableError, success, error);
1177
- return [2 /*return*/, null];
1178
- }
1179
- return [2 /*return*/];
1085
+ sum[column] = fetchReferences[tableToFetch][column].length === 1
1086
+ ? fetchReferences[tableToFetch][column][0]
1087
+ : [
1088
+ C6.IN, fetchReferences[tableToFetch][column]
1089
+ ];
1090
+ return sum;
1091
+ }, {})
1092
+ },
1093
+ fetchDependencies: nextFetchDependencies
1094
+ }));
1095
+ }
1096
+ console.groupEnd();
1097
+ await Promise.all(apiRequestPromises);
1098
+ apiRequestPromises.map(async (promise) => {
1099
+ if (!Array.isArray(this.request.fetchDependencies)) {
1100
+ // to reassign value we must ref the root
1101
+ this.request.fetchDependencies = [];
1180
1102
  }
1103
+ this.request.fetchDependencies.push(await promise);
1181
1104
  });
1182
- }); };
1183
- return [4 /*yield*/, apiRequest()];
1184
- case 2: return [2 /*return*/, _b.sent()];
1105
+ }
1106
+ }
1107
+ if (debug && isLocal()) {
1108
+ reactToastify.toast.success("DEVS: (" + requestMethod + ") request complete.", toastOptionsDevs);
1109
+ }
1110
+ // this is the literal axios return
1111
+ return response;
1112
+ }).then(response => response.data); // this escapes from axios context
1113
+ }
1114
+ catch (throwableError) {
1115
+ if (isTest()) {
1116
+ throw new Error(JSON.stringify(throwableError));
1185
1117
  }
1186
- });
1187
- });
1188
- };
1189
- return HttpExecutor;
1190
- }(Executor));
1118
+ console.groupCollapsed('%c API: An error occurred in the try catch block. returning null!', 'color: #ff0000');
1119
+ console.log('%c ' + requestMethod + ' ' + tableName, 'color: #A020F0');
1120
+ console.warn(throwableError);
1121
+ console.trace();
1122
+ console.groupEnd();
1123
+ TestRestfulResponse(throwableError, success, error);
1124
+ return null;
1125
+ }
1126
+ };
1127
+ return await apiRequest();
1128
+ }
1129
+ }
1191
1130
 
1192
1131
  var HttpExecutor$1 = /*#__PURE__*/Object.freeze({
1193
1132
  __proto__: null,
@@ -1204,209 +1143,188 @@ function convertHexIfBinary(_col, val, columnDef) {
1204
1143
  return val;
1205
1144
  }
1206
1145
 
1207
- var AggregateBuilder = /** @class */ (function (_super) {
1208
- tslib.__extends(AggregateBuilder, _super);
1209
- function AggregateBuilder() {
1210
- return _super !== null && _super.apply(this, arguments) || this;
1211
- }
1212
- AggregateBuilder.prototype.buildAggregateField = function (field) {
1213
- var _this = this;
1146
+ class AggregateBuilder extends Executor {
1147
+ buildAggregateField(field) {
1214
1148
  if (typeof field === 'string') {
1215
1149
  return field;
1216
1150
  }
1217
1151
  if (!Array.isArray(field) || field.length === 0) {
1218
1152
  throw new Error('Invalid SELECT field entry');
1219
1153
  }
1220
- var fn = field[0], args = field.slice(1);
1221
- var alias;
1154
+ let [fn, ...args] = field;
1155
+ let alias;
1222
1156
  if (args.length >= 2 && String(args[args.length - 2]).toUpperCase() === 'AS') {
1223
1157
  alias = String(args.pop());
1224
1158
  args.pop();
1225
1159
  }
1226
- var F = String(fn).toUpperCase();
1227
- var argList = args.map(function (arg) {
1228
- return Array.isArray(arg) ? _this.buildAggregateField(arg) : arg;
1229
- }).join(', ');
1230
- var expr = "".concat(F, "(").concat(argList, ")");
1160
+ const F = String(fn).toUpperCase();
1161
+ const argList = args.map(arg => Array.isArray(arg) ? this.buildAggregateField(arg) : arg).join(', ');
1162
+ let expr = `${F}(${argList})`;
1231
1163
  if (alias) {
1232
- expr += " AS ".concat(alias);
1164
+ expr += ` AS ${alias}`;
1233
1165
  }
1234
- this.config.verbose && console.log("[SELECT] ".concat(expr));
1166
+ this.config.verbose && console.log(`[SELECT] ${expr}`);
1235
1167
  return expr;
1236
- };
1237
- return AggregateBuilder;
1238
- }(Executor));
1239
-
1240
- var ConditionBuilder = /** @class */ (function (_super) {
1241
- tslib.__extends(ConditionBuilder, _super);
1242
- function ConditionBuilder() {
1243
- var _this = _super !== null && _super.apply(this, arguments) || this;
1244
- _this.aliasMap = {};
1245
- _this.OPERATORS = new Set([
1246
- C6C.EQUAL, C6C.NOT_EQUAL, C6C.LESS_THAN, C6C.LESS_THAN_OR_EQUAL_TO,
1247
- C6C.GREATER_THAN, C6C.GREATER_THAN_OR_EQUAL_TO,
1248
- C6C.LIKE, C6C.NOT_LIKE,
1249
- C6C.IN, C6C.NOT_IN, 'NOT IN',
1250
- C6C.IS, C6C.IS_NOT,
1251
- C6C.BETWEEN, 'NOT BETWEEN',
1252
- C6C.MATCH_AGAINST,
1253
- C6C.ST_DISTANCE_SPHERE
1254
- ]);
1255
- return _this;
1256
1168
  }
1257
- ConditionBuilder.prototype.initAlias = function (baseTable, joins) {
1258
- var _a;
1259
- this.aliasMap = (_a = {}, _a[baseTable] = baseTable, _a);
1169
+ }
1170
+
1171
+ class ConditionBuilder extends AggregateBuilder {
1172
+ aliasMap = {};
1173
+ initAlias(baseTable, joins) {
1174
+ this.aliasMap = { [baseTable]: baseTable };
1260
1175
  if (!joins)
1261
1176
  return;
1262
- for (var joinType in joins) {
1263
- for (var raw in joins[joinType]) {
1264
- var _b = raw.split(' '), table = _b[0], alias = _b[1];
1177
+ for (const joinType in joins) {
1178
+ for (const raw in joins[joinType]) {
1179
+ const [table, alias] = raw.split(' ');
1265
1180
  this.aliasMap[alias || table] = table;
1266
1181
  }
1267
1182
  }
1268
- };
1269
- ConditionBuilder.prototype.isColumnRef = function (ref) {
1270
- var _a, _b;
1183
+ }
1184
+ isColumnRef(ref) {
1271
1185
  if (typeof ref !== 'string' || !ref.includes('.'))
1272
1186
  return false;
1273
- var _c = ref.split('.', 2), prefix = _c[0], column = _c[1];
1274
- var tableName = this.aliasMap[prefix] || prefix;
1275
- var table = (_b = (_a = this.config.C6) === null || _a === void 0 ? void 0 : _a.TABLES) === null || _b === void 0 ? void 0 : _b[tableName];
1187
+ const [prefix, column] = ref.split('.', 2);
1188
+ const tableName = this.aliasMap[prefix] || prefix;
1189
+ const table = this.config.C6?.TABLES?.[tableName];
1276
1190
  if (!table)
1277
1191
  return false;
1278
- var fullKey = "".concat(tableName, ".").concat(column);
1192
+ const fullKey = `${tableName}.${column}`;
1279
1193
  if (table.COLUMNS && (fullKey in table.COLUMNS))
1280
1194
  return true;
1281
- if (table.COLUMNS && Object.values(table.COLUMNS).includes(column))
1195
+ if (table.COLUMNS && Object.values(table.COLUMNS).includes(ref))
1282
1196
  return true;
1197
+ this.config.verbose && console.log(`[COLUMN REF] ${ref} is not a valid column reference`);
1283
1198
  return false;
1284
- };
1285
- ConditionBuilder.prototype.execute = function () {
1199
+ }
1200
+ execute() {
1286
1201
  throw new Error("Method not implemented.");
1287
- };
1288
- ConditionBuilder.prototype.validateOperator = function (op) {
1202
+ }
1203
+ OPERATORS = new Set([
1204
+ C6C.EQUAL, C6C.NOT_EQUAL, C6C.LESS_THAN, C6C.LESS_THAN_OR_EQUAL_TO,
1205
+ C6C.GREATER_THAN, C6C.GREATER_THAN_OR_EQUAL_TO,
1206
+ C6C.LIKE, C6C.NOT_LIKE,
1207
+ C6C.IN, C6C.NOT_IN, 'NOT IN',
1208
+ C6C.IS, C6C.IS_NOT,
1209
+ C6C.BETWEEN, 'NOT BETWEEN',
1210
+ C6C.MATCH_AGAINST,
1211
+ C6C.ST_DISTANCE_SPHERE
1212
+ ]);
1213
+ validateOperator(op) {
1289
1214
  if (!this.OPERATORS.has(op)) {
1290
- throw new Error("Invalid or unsupported SQL operator detected: '".concat(op, "'"));
1215
+ throw new Error(`Invalid or unsupported SQL operator detected: '${op}'`);
1291
1216
  }
1292
- };
1293
- ConditionBuilder.prototype.addParam = function (params, column, value) {
1294
- var _a, _b;
1295
- var columnDef = (_b = (_a = this.config.C6[column.split('.')[0]]) === null || _a === void 0 ? void 0 : _a.TYPE_VALIDATION) === null || _b === void 0 ? void 0 : _b[column];
1296
- var val = convertHexIfBinary(column, value, columnDef);
1217
+ }
1218
+ addParam(params, column, value) {
1219
+ const columnDef = this.config.C6[column.split('.')[0]]?.TYPE_VALIDATION?.[column];
1220
+ const val = convertHexIfBinary(column, value, columnDef);
1297
1221
  if (this.useNamedParams) {
1298
- var key = "param".concat(Object.keys(params).length);
1222
+ const key = `param${Object.keys(params).length}`;
1299
1223
  params[key] = val;
1300
- return ":".concat(key);
1224
+ return `:${key}`;
1301
1225
  }
1302
1226
  else {
1303
1227
  params.push(val);
1304
1228
  return '?';
1305
1229
  }
1306
- };
1307
- ConditionBuilder.prototype.buildBooleanJoinedConditions = function (set, andMode, params) {
1308
- var _this = this;
1309
- if (andMode === void 0) { andMode = true; }
1310
- if (params === void 0) { params = []; }
1311
- var booleanOperator = andMode ? 'AND' : 'OR';
1312
- var addCondition = function (column, op, value) {
1230
+ }
1231
+ buildBooleanJoinedConditions(set, andMode = true, params = []) {
1232
+ const booleanOperator = andMode ? 'AND' : 'OR';
1233
+ const addCondition = (column, op, value) => {
1313
1234
  // Support function-based expressions like [C6C.ST_DISTANCE_SPHERE, col1, col2]
1314
1235
  if (typeof column === 'string' &&
1315
- _this.OPERATORS.has(column) &&
1236
+ this.OPERATORS.has(column) &&
1316
1237
  Array.isArray(op)) {
1317
1238
  if (column === C6C.ST_DISTANCE_SPHERE) {
1318
- var col1 = op[0], col2 = op[1];
1319
- var threshold = Array.isArray(value) ? value[0] : value;
1320
- return "ST_Distance_Sphere(".concat(col1, ", ").concat(col2, ") < ").concat(_this.addParam(params, '', threshold));
1239
+ const [col1, col2] = op;
1240
+ const threshold = Array.isArray(value) ? value[0] : value;
1241
+ return `ST_Distance_Sphere(${col1}, ${col2}) < ${this.addParam(params, '', threshold)}`;
1321
1242
  }
1322
1243
  }
1323
- var leftIsCol = _this.isColumnRef(column);
1324
- var rightIsCol = typeof value === 'string' && _this.isColumnRef(value);
1244
+ const leftIsCol = this.isColumnRef(column);
1245
+ const rightIsCol = typeof value === 'string' && this.isColumnRef(value);
1325
1246
  if (!leftIsCol && !rightIsCol) {
1326
- throw new Error("Potential SQL injection detected: '".concat(column, " ").concat(op, " ").concat(value, "'"));
1247
+ throw new Error(`Potential SQL injection detected: '${column} ${op} ${value}'`);
1327
1248
  }
1328
- _this.validateOperator(op);
1249
+ this.validateOperator(op);
1329
1250
  if (op === C6C.MATCH_AGAINST && Array.isArray(value)) {
1330
- var search = value[0], mode = value[1];
1331
- var paramName = _this.useNamedParams ? "param".concat(Object.keys(params).length) : null;
1332
- if (_this.useNamedParams) {
1251
+ const [search, mode] = value;
1252
+ const paramName = this.useNamedParams ? `param${Object.keys(params).length}` : null;
1253
+ if (this.useNamedParams) {
1333
1254
  params[paramName] = search;
1334
1255
  }
1335
1256
  else {
1336
1257
  params.push(search);
1337
1258
  }
1338
- var againstClause = void 0;
1259
+ let againstClause;
1339
1260
  switch ((mode || '').toUpperCase()) {
1340
1261
  case 'BOOLEAN':
1341
- againstClause = _this.useNamedParams ? "AGAINST(:".concat(paramName, " IN BOOLEAN MODE)") : "AGAINST(? IN BOOLEAN MODE)";
1262
+ againstClause = this.useNamedParams ? `AGAINST(:${paramName} IN BOOLEAN MODE)` : `AGAINST(? IN BOOLEAN MODE)`;
1342
1263
  break;
1343
1264
  case 'WITH QUERY EXPANSION':
1344
- againstClause = _this.useNamedParams ? "AGAINST(:".concat(paramName, " WITH QUERY EXPANSION)") : "AGAINST(? WITH QUERY EXPANSION)";
1265
+ againstClause = this.useNamedParams ? `AGAINST(:${paramName} WITH QUERY EXPANSION)` : `AGAINST(? WITH QUERY EXPANSION)`;
1345
1266
  break;
1346
1267
  default: // NATURAL or undefined
1347
- againstClause = _this.useNamedParams ? "AGAINST(:".concat(paramName, ")") : "AGAINST(?)";
1268
+ againstClause = this.useNamedParams ? `AGAINST(:${paramName})` : `AGAINST(?)`;
1348
1269
  break;
1349
1270
  }
1350
1271
  if (!leftIsCol) {
1351
- throw new Error("MATCH_AGAINST requires a table reference as the left operand. Column '".concat(column, "' is not a valid table reference."));
1272
+ throw new Error(`MATCH_AGAINST requires a table reference as the left operand. Column '${column}' is not a valid table reference.`);
1352
1273
  }
1353
- var matchClause = "(MATCH(".concat(column, ") ").concat(againstClause, ")");
1354
- _this.config.verbose && console.log("[MATCH_AGAINST] ".concat(matchClause));
1274
+ const matchClause = `(MATCH(${column}) ${againstClause})`;
1275
+ this.config.verbose && console.log(`[MATCH_AGAINST] ${matchClause}`);
1355
1276
  return matchClause;
1356
1277
  }
1357
1278
  if ((op === C6C.IN || op === C6C.NOT_IN) && Array.isArray(value)) {
1358
- var placeholders = value.map(function (v) {
1359
- return _this.isColumnRef(v) ? v : _this.addParam(params, column, v);
1360
- }).join(', ');
1361
- var normalized = op.replace('_', ' ');
1279
+ const placeholders = value.map(v => this.isColumnRef(v) ? v : this.addParam(params, column, v)).join(', ');
1280
+ const normalized = op.replace('_', ' ');
1362
1281
  if (!leftIsCol) {
1363
- throw new Error("IN operator requires a table reference as the left operand. Column '".concat(column, "' is not a valid table reference."));
1282
+ throw new Error(`IN operator requires a table reference as the left operand. Column '${column}' is not a valid table reference.`);
1364
1283
  }
1365
- return "( ".concat(column, " ").concat(normalized, " (").concat(placeholders, ") )");
1284
+ return `( ${column} ${normalized} (${placeholders}) )`;
1366
1285
  }
1367
1286
  if (op === C6C.BETWEEN || op === 'NOT BETWEEN') {
1368
1287
  if (!Array.isArray(value) || value.length !== 2) {
1369
- throw new Error("BETWEEN operator requires an array of two values");
1288
+ throw new Error(`BETWEEN operator requires an array of two values. Received: ${JSON.stringify(value)}`);
1370
1289
  }
1371
- var start = value[0], end = value[1];
1290
+ const [start, end] = value;
1372
1291
  if (!leftIsCol) {
1373
- throw new Error("BETWEEN operator requires a table reference as the left operand. Column '".concat(column, "' is not a valid table reference."));
1292
+ throw new Error(`BETWEEN operator requires a table reference as the left operand. Column '${column}' is not a valid table reference.`);
1374
1293
  }
1375
- return "(".concat(column, ") ").concat(op.replace('_', ' '), " ").concat(_this.addParam(params, column, start), " AND ").concat(_this.addParam(params, column, end));
1294
+ return `(${column}) ${op.replace('_', ' ')} ${this.addParam(params, column, start)} AND ${this.addParam(params, column, end)}`;
1376
1295
  }
1377
1296
  if (leftIsCol && rightIsCol) {
1378
- return "(".concat(column, ") ").concat(op, " ").concat(value);
1297
+ return `(${column}) ${op} ${value}`;
1379
1298
  }
1380
1299
  if (leftIsCol && !rightIsCol) {
1381
- return "(".concat(column, ") ").concat(op, " ").concat(_this.addParam(params, column, value));
1300
+ return `(${column}) ${op} ${this.addParam(params, column, value)}`;
1382
1301
  }
1383
1302
  if (rightIsCol) {
1384
- return "(".concat(_this.addParam(params, column, column), ") ").concat(op, " ").concat(value);
1303
+ return `(${this.addParam(params, column, column)}) ${op} ${value}`;
1385
1304
  }
1386
- throw new Error("Neither operand appears to be a table reference");
1305
+ throw new Error(`Neither operand appears to be a table reference`);
1387
1306
  };
1388
- var parts = [];
1389
- var buildFromObject = function (obj, mode) {
1390
- var subParts = [];
1391
- for (var _i = 0, _a = Object.entries(obj); _i < _a.length; _i++) {
1392
- var _b = _a[_i], k = _b[0], v = _b[1];
1307
+ const parts = [];
1308
+ const buildFromObject = (obj, mode) => {
1309
+ const subParts = [];
1310
+ for (const [k, v] of Object.entries(obj)) {
1393
1311
  // numeric keys represent nested OR groups
1394
1312
  if (!isNaN(Number(k))) {
1395
- var sub = _this.buildBooleanJoinedConditions(v, false, params);
1313
+ const sub = this.buildBooleanJoinedConditions(v, false, params);
1396
1314
  if (sub)
1397
1315
  subParts.push(sub);
1398
1316
  continue;
1399
1317
  }
1400
1318
  if (typeof v === 'object' && v !== null && Object.keys(v).length === 1) {
1401
- var _c = Object.entries(v)[0], op = _c[0], val = _c[1];
1319
+ const [op, val] = Object.entries(v)[0];
1402
1320
  subParts.push(addCondition(k, op, val));
1403
1321
  }
1404
1322
  else if (Array.isArray(v) && v.length >= 2 && typeof v[0] === 'string') {
1405
- var _d = v, op = _d[0], val = _d[1];
1323
+ const [op, val] = v;
1406
1324
  subParts.push(addCondition(k, op, val));
1407
1325
  }
1408
1326
  else if (typeof v === 'object' && v !== null) {
1409
- var sub = _this.buildBooleanJoinedConditions(v, mode, params);
1327
+ const sub = this.buildBooleanJoinedConditions(v, mode, params);
1410
1328
  if (sub)
1411
1329
  subParts.push(sub);
1412
1330
  }
@@ -1414,124 +1332,105 @@ var ConditionBuilder = /** @class */ (function (_super) {
1414
1332
  subParts.push(addCondition(k, '=', v));
1415
1333
  }
1416
1334
  }
1417
- return subParts.join(" ".concat(mode ? 'AND' : 'OR', " "));
1335
+ return subParts.join(` ${mode ? 'AND' : 'OR'} `);
1418
1336
  };
1419
1337
  if (Array.isArray(set)) {
1420
- for (var _i = 0, set_1 = set; _i < set_1.length; _i++) {
1421
- var item = set_1[_i];
1422
- var sub = this.buildBooleanJoinedConditions(item, false, params);
1338
+ for (const item of set) {
1339
+ const sub = this.buildBooleanJoinedConditions(item, false, params);
1423
1340
  if (sub)
1424
1341
  parts.push(sub);
1425
1342
  }
1426
1343
  }
1427
1344
  else if (typeof set === 'object' && set !== null) {
1428
- var sub = buildFromObject(set, andMode);
1345
+ const sub = buildFromObject(set, andMode);
1429
1346
  if (sub)
1430
1347
  parts.push(sub);
1431
1348
  }
1432
- var clause = parts.join(" ".concat(booleanOperator, " "));
1433
- return clause ? "(".concat(clause, ")") : '';
1434
- };
1435
- ConditionBuilder.prototype.buildWhereClause = function (whereArg, params) {
1436
- var clause = this.buildBooleanJoinedConditions(whereArg, true, params);
1349
+ const clause = parts.join(` ${booleanOperator} `);
1350
+ return clause ? `(${clause})` : '';
1351
+ }
1352
+ buildWhereClause(whereArg, params) {
1353
+ const clause = this.buildBooleanJoinedConditions(whereArg, true, params);
1437
1354
  if (!clause)
1438
1355
  return '';
1439
- var trimmed = clause.replace(/^\((.*)\)$/, '$1');
1440
- this.config.verbose && console.log("[WHERE] ".concat(trimmed));
1441
- return " WHERE ".concat(trimmed);
1442
- };
1443
- return ConditionBuilder;
1444
- }(AggregateBuilder));
1445
-
1446
- var JoinBuilder = /** @class */ (function (_super) {
1447
- tslib.__extends(JoinBuilder, _super);
1448
- function JoinBuilder() {
1449
- return _super !== null && _super.apply(this, arguments) || this;
1356
+ const trimmed = clause.replace(/^\((.*)\)$/, '$1');
1357
+ this.config.verbose && console.log(`[WHERE] ${trimmed}`);
1358
+ return ` WHERE ${trimmed}`;
1450
1359
  }
1451
- JoinBuilder.prototype.buildJoinClauses = function (joinArgs, params) {
1452
- var sql = '';
1453
- for (var joinType in joinArgs) {
1454
- var joinKind = joinType.replace('_', ' ').toUpperCase();
1455
- for (var raw in joinArgs[joinType]) {
1456
- var _a = raw.split(' '), table = _a[0], alias = _a[1];
1360
+ }
1361
+
1362
+ class JoinBuilder extends ConditionBuilder {
1363
+ buildJoinClauses(joinArgs, params) {
1364
+ let sql = '';
1365
+ for (const joinType in joinArgs) {
1366
+ const joinKind = joinType.replace('_', ' ').toUpperCase();
1367
+ for (const raw in joinArgs[joinType]) {
1368
+ const [table, alias] = raw.split(' ');
1457
1369
  this.aliasMap[alias || table] = table;
1458
- var onClause = this.buildBooleanJoinedConditions(joinArgs[joinType][raw], true, params);
1459
- var joinSql = alias ? "`".concat(table, "` AS `").concat(alias, "`") : "`".concat(table, "`");
1460
- sql += " ".concat(joinKind, " JOIN ").concat(joinSql, " ON ").concat(onClause);
1370
+ const onClause = this.buildBooleanJoinedConditions(joinArgs[joinType][raw], true, params);
1371
+ const joinSql = alias ? `\`${table}\` AS \`${alias}\`` : `\`${table}\``;
1372
+ sql += ` ${joinKind} JOIN ${joinSql} ON ${onClause}`;
1461
1373
  }
1462
1374
  }
1463
- this.config.verbose && console.log("[JOIN] ".concat(sql.trim()));
1375
+ this.config.verbose && console.log(`[JOIN] ${sql.trim()}`);
1464
1376
  return sql;
1465
- };
1466
- return JoinBuilder;
1467
- }(ConditionBuilder));
1468
-
1469
- var DeleteQueryBuilder = /** @class */ (function (_super) {
1470
- tslib.__extends(DeleteQueryBuilder, _super);
1471
- function DeleteQueryBuilder() {
1472
- return _super !== null && _super.apply(this, arguments) || this;
1473
1377
  }
1474
- DeleteQueryBuilder.prototype.build = function (table) {
1475
- var params = this.useNamedParams ? {} : [];
1378
+ }
1379
+
1380
+ class DeleteQueryBuilder extends JoinBuilder {
1381
+ build(table) {
1382
+ const params = this.useNamedParams ? {} : [];
1476
1383
  this.initAlias(table, this.request.JOIN);
1477
- var sql = "DELETE `".concat(table, "` FROM `").concat(table, "`");
1384
+ let sql = `DELETE \`${table}\` FROM \`${table}\``;
1478
1385
  if (this.request.JOIN) {
1479
1386
  sql += this.buildJoinClauses(this.request.JOIN, params);
1480
1387
  }
1481
1388
  if (this.request.WHERE) {
1482
1389
  sql += this.buildWhereClause(this.request.WHERE, params);
1483
1390
  }
1484
- return { sql: sql, params: params };
1485
- };
1486
- return DeleteQueryBuilder;
1487
- }(JoinBuilder));
1488
-
1489
- var PostQueryBuilder = /** @class */ (function (_super) {
1490
- tslib.__extends(PostQueryBuilder, _super);
1491
- function PostQueryBuilder() {
1492
- return _super !== null && _super.apply(this, arguments) || this;
1391
+ return { sql, params };
1493
1392
  }
1494
- PostQueryBuilder.prototype.trimTablePrefix = function (table, column) {
1393
+ }
1394
+
1395
+ class PostQueryBuilder extends ConditionBuilder {
1396
+ trimTablePrefix(table, column) {
1495
1397
  if (!column.includes('.'))
1496
1398
  return column;
1497
- var _a = column.split('.', 2), prefix = _a[0], col = _a[1];
1399
+ const [prefix, col] = column.split('.', 2);
1498
1400
  if (prefix !== table) {
1499
- throw new Error("Invalid prefixed column: '".concat(column, "'. Expected prefix '").concat(table, ".'"));
1401
+ throw new Error(`Invalid prefixed column: '${column}'. Expected prefix '${table}.'`);
1500
1402
  }
1501
1403
  return col;
1502
- };
1503
- PostQueryBuilder.prototype.build = function (table) {
1504
- var _this = this;
1505
- var verb = C6C.REPLACE in this.request ? C6C.REPLACE : C6C.INSERT;
1506
- var body = verb in this.request ? this.request[verb] : this.request;
1507
- var keys = Object.keys(body);
1508
- var params = [];
1509
- var placeholders = [];
1510
- for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
1511
- var key = keys_1[_i];
1512
- var value = body[key];
1513
- var placeholder = this.addParam(params, key, value);
1404
+ }
1405
+ build(table) {
1406
+ const verb = C6C.REPLACE in this.request ? C6C.REPLACE : C6C.INSERT;
1407
+ const body = verb in this.request ? this.request[verb] : this.request;
1408
+ const keys = Object.keys(body);
1409
+ const params = [];
1410
+ const placeholders = [];
1411
+ for (const key of keys) {
1412
+ const value = body[key];
1413
+ const placeholder = this.addParam(params, key, value);
1514
1414
  placeholders.push(placeholder);
1515
1415
  }
1516
- 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 )");
1416
+ let sql = `${verb} INTO \`${table}\` (
1417
+ ${keys.map(k => `\`${this.trimTablePrefix(table, k)}\``).join(', ')}
1418
+ ) VALUES (
1419
+ ${placeholders.join(', ')}
1420
+ )`;
1517
1421
  if (C6C.UPDATE in this.request) {
1518
- var updateData = this.request[C6C.UPDATE];
1422
+ const updateData = this.request[C6C.UPDATE];
1519
1423
  if (!Array.isArray(updateData)) {
1520
- throw new Error("Update data must be an array of keys to update, got: ".concat(JSON.stringify(updateData)));
1424
+ throw new Error(`Update data must be an array of keys to update, got: ${JSON.stringify(updateData)}`);
1521
1425
  }
1522
- var updateClause = updateData.map(function (k) { return "`".concat(k, "` = VALUES(`").concat(k, "`)"); }).join(', ');
1523
- sql += " ON DUPLICATE KEY UPDATE ".concat(updateClause);
1426
+ const updateClause = updateData.map(k => `\`${k}\` = VALUES(\`${k}\`)`).join(', ');
1427
+ sql += ` ON DUPLICATE KEY UPDATE ${updateClause}`;
1524
1428
  }
1525
- return { sql: sql, params: params };
1526
- };
1527
- return PostQueryBuilder;
1528
- }(ConditionBuilder));
1529
-
1530
- var PaginationBuilder = /** @class */ (function (_super) {
1531
- tslib.__extends(PaginationBuilder, _super);
1532
- function PaginationBuilder() {
1533
- return _super !== null && _super.apply(this, arguments) || this;
1429
+ return { sql, params };
1534
1430
  }
1431
+ }
1432
+
1433
+ class PaginationBuilder extends JoinBuilder {
1535
1434
  /**
1536
1435
  * MySQL ORDER/LIMIT/OFFSET generator.
1537
1436
  *
@@ -1545,60 +1444,49 @@ var PaginationBuilder = /** @class */ (function (_super) {
1545
1444
  * }
1546
1445
  * ```
1547
1446
  */
1548
- PaginationBuilder.prototype.buildPaginationClause = function (pagination) {
1549
- var _this = this;
1550
- var _a;
1551
- var sql = "";
1447
+ buildPaginationClause(pagination) {
1448
+ let sql = "";
1552
1449
  /* -------- ORDER BY -------- */
1553
- if (pagination === null || pagination === void 0 ? void 0 : pagination[C6Constants.ORDER]) {
1554
- var orderParts = [];
1555
- for (var _i = 0, _b = Object.entries(pagination[C6Constants.ORDER]); _i < _b.length; _i++) {
1556
- var _c = _b[_i], key = _c[0], val = _c[1];
1450
+ if (pagination?.[C6Constants.ORDER]) {
1451
+ const orderParts = [];
1452
+ for (const [key, val] of Object.entries(pagination[C6Constants.ORDER])) {
1557
1453
  // FUNCTION CALL: val is an array of args
1558
1454
  if (Array.isArray(val)) {
1559
- var args = val
1560
- .map(function (arg) { return Array.isArray(arg) ? _this.buildAggregateField(arg) : String(arg); })
1455
+ const args = val
1456
+ .map((arg) => Array.isArray(arg) ? this.buildAggregateField(arg) : String(arg))
1561
1457
  .join(", ");
1562
- orderParts.push("".concat(key, "(").concat(args, ")"));
1458
+ orderParts.push(`${key}(${args})`);
1563
1459
  }
1564
1460
  // SIMPLE COLUMN + DIR (ASC/DESC)
1565
1461
  else {
1566
- orderParts.push("".concat(key, " ").concat(String(val).toUpperCase()));
1462
+ orderParts.push(`${key} ${String(val).toUpperCase()}`);
1567
1463
  }
1568
1464
  }
1569
1465
  if (orderParts.length)
1570
- sql += " ORDER BY ".concat(orderParts.join(", "));
1466
+ sql += ` ORDER BY ${orderParts.join(", ")}`;
1571
1467
  }
1572
1468
  /* -------- LIMIT / OFFSET -------- */
1573
- if ((pagination === null || pagination === void 0 ? void 0 : pagination[C6Constants.LIMIT]) != null) {
1574
- var lim = parseInt(pagination[C6Constants.LIMIT], 10);
1575
- var page = parseInt((_a = pagination[C6Constants.PAGE]) !== null && _a !== void 0 ? _a : 1, 10);
1576
- var offset = (page - 1) * lim;
1577
- sql += " LIMIT ".concat(offset, ", ").concat(lim);
1469
+ if (pagination?.[C6Constants.LIMIT] != null) {
1470
+ const lim = parseInt(pagination[C6Constants.LIMIT], 10);
1471
+ const page = parseInt(pagination[C6Constants.PAGE] ?? 1, 10);
1472
+ const offset = (page - 1) * lim;
1473
+ sql += ` LIMIT ${offset}, ${lim}`;
1578
1474
  }
1579
- this.config.verbose && console.log("[PAGINATION] ".concat(sql.trim()));
1475
+ this.config.verbose && console.log(`[PAGINATION] ${sql.trim()}`);
1580
1476
  return sql;
1581
- };
1582
- return PaginationBuilder;
1583
- }(JoinBuilder));
1584
-
1585
- var SelectQueryBuilder = /** @class */ (function (_super) {
1586
- tslib.__extends(SelectQueryBuilder, _super);
1587
- function SelectQueryBuilder() {
1588
- return _super !== null && _super.apply(this, arguments) || this;
1589
1477
  }
1590
- SelectQueryBuilder.prototype.build = function (table, isSubSelect) {
1591
- var _this = this;
1592
- var _a;
1593
- if (isSubSelect === void 0) { isSubSelect = false; }
1594
- var args = this.request;
1478
+ }
1479
+
1480
+ class SelectQueryBuilder extends PaginationBuilder {
1481
+ build(table, isSubSelect = false) {
1482
+ const args = this.request;
1595
1483
  this.initAlias(table, args.JOIN);
1596
- var params = this.useNamedParams ? {} : [];
1597
- var selectList = (_a = args.SELECT) !== null && _a !== void 0 ? _a : ['*'];
1598
- var selectFields = selectList
1599
- .map(function (f) { return _this.buildAggregateField(f); })
1484
+ const params = this.useNamedParams ? {} : [];
1485
+ const selectList = args.SELECT ?? ['*'];
1486
+ const selectFields = selectList
1487
+ .map((f) => this.buildAggregateField(f))
1600
1488
  .join(', ');
1601
- var sql = "SELECT ".concat(selectFields, " FROM `").concat(table, "`");
1489
+ let sql = `SELECT ${selectFields} FROM \`${table}\``;
1602
1490
  if (args.JOIN) {
1603
1491
  sql += this.buildJoinClauses(args.JOIN, params);
1604
1492
  }
@@ -1606,228 +1494,165 @@ var SelectQueryBuilder = /** @class */ (function (_super) {
1606
1494
  sql += this.buildWhereClause(args.WHERE, params);
1607
1495
  }
1608
1496
  if (args.GROUP_BY) {
1609
- var groupBy = Array.isArray(args.GROUP_BY)
1497
+ const groupBy = Array.isArray(args.GROUP_BY)
1610
1498
  ? args.GROUP_BY.join(', ')
1611
1499
  : args.GROUP_BY;
1612
- sql += " GROUP BY ".concat(groupBy);
1500
+ sql += ` GROUP BY ${groupBy}`;
1613
1501
  }
1614
1502
  if (args.HAVING) {
1615
- sql += " HAVING ".concat(this.buildBooleanJoinedConditions(args.HAVING, true, params));
1503
+ sql += ` HAVING ${this.buildBooleanJoinedConditions(args.HAVING, true, params)}`;
1616
1504
  }
1617
1505
  if (args.PAGINATION) {
1618
1506
  sql += this.buildPaginationClause(args.PAGINATION);
1619
1507
  }
1620
1508
  else if (!isSubSelect) {
1621
- sql += " LIMIT 100";
1509
+ sql += ` LIMIT 100`;
1622
1510
  }
1623
- console.log("[SELECT] ".concat(sql.trim()));
1624
- return { sql: sql, params: params };
1625
- };
1626
- return SelectQueryBuilder;
1627
- }(PaginationBuilder));
1628
-
1629
- var UpdateQueryBuilder = /** @class */ (function (_super) {
1630
- tslib.__extends(UpdateQueryBuilder, _super);
1631
- function UpdateQueryBuilder() {
1632
- return _super !== null && _super.apply(this, arguments) || this;
1511
+ console.log(`[SELECT] ${sql.trim()}`);
1512
+ return { sql, params };
1633
1513
  }
1634
- UpdateQueryBuilder.prototype.build = function (table) {
1635
- var _this = this;
1636
- var args = this.request;
1637
- var params = this.useNamedParams ? {} : [];
1514
+ }
1515
+
1516
+ class UpdateQueryBuilder extends PaginationBuilder {
1517
+ build(table) {
1518
+ const args = this.request;
1519
+ const params = this.useNamedParams ? {} : [];
1638
1520
  this.initAlias(table, args.JOIN);
1639
- var sql = "UPDATE `".concat(table, "`");
1521
+ let sql = `UPDATE \`${table}\``;
1640
1522
  if (args.JOIN) {
1641
1523
  sql += this.buildJoinClauses(args.JOIN, params);
1642
1524
  }
1643
1525
  if (!(C6C.UPDATE in this.request)) {
1644
1526
  throw new Error("No update data provided in the request.");
1645
1527
  }
1646
- var setClauses = Object.entries(this.request[C6C.UPDATE]).map(function (_a) {
1647
- var col = _a[0], val = _a[1];
1648
- return _this.addParam(params, col, val);
1649
- });
1650
- sql += " SET ".concat(setClauses.join(', '));
1528
+ const setClauses = Object.entries(this.request[C6C.UPDATE]).map(([col, val]) => this.addParam(params, col, val));
1529
+ sql += ` SET ${setClauses.join(', ')}`;
1651
1530
  if (args.WHERE) {
1652
1531
  sql += this.buildWhereClause(args.WHERE, params);
1653
1532
  }
1654
1533
  if (args.PAGINATION) {
1655
1534
  sql += this.buildPaginationClause(args.PAGINATION);
1656
1535
  }
1657
- return { sql: sql, params: params };
1658
- };
1659
- return UpdateQueryBuilder;
1660
- }(PaginationBuilder));
1536
+ return { sql, params };
1537
+ }
1538
+ }
1661
1539
 
1662
- var SqlExecutor = /** @class */ (function (_super) {
1663
- tslib.__extends(SqlExecutor, _super);
1664
- function SqlExecutor() {
1665
- var _this = _super !== null && _super.apply(this, arguments) || this;
1666
- _this.serialize = function (row) { return Object.fromEntries(Object.entries(row).map(function (_a) {
1667
- var k = _a[0], v = _a[1];
1668
- return [k, buffer.Buffer.isBuffer(v) ? v.toString('hex').toUpperCase() : v];
1669
- })); };
1670
- return _this;
1540
+ class SqlExecutor extends Executor {
1541
+ async execute() {
1542
+ const { TABLE_NAME } = this.config.restModel;
1543
+ const method = this.config.requestMethod;
1544
+ this.config.verbose && console.log(`[SQL EXECUTOR] ▶️ Executing ${method} on table "${TABLE_NAME}"`);
1545
+ this.config.verbose && console.log(`[SQL EXECUTOR] 🧩 Request:`, JSON.stringify(this.request, undefined, 2));
1546
+ switch (method) {
1547
+ case 'GET': {
1548
+ const rest = await this.runQuery();
1549
+ return rest;
1550
+ }
1551
+ case 'POST': {
1552
+ const result = await this.runQuery();
1553
+ return result;
1554
+ }
1555
+ case 'PUT': {
1556
+ const result = await this.runQuery();
1557
+ return result;
1558
+ }
1559
+ case 'DELETE': {
1560
+ const result = await this.runQuery();
1561
+ return result;
1562
+ }
1563
+ default:
1564
+ throw new Error(`Unsupported request method: ${method}`);
1565
+ }
1671
1566
  }
1672
- SqlExecutor.prototype.execute = function () {
1673
- return tslib.__awaiter(this, void 0, void 0, function () {
1674
- var TABLE_NAME, method, _a, rest, result, result, result;
1675
- return tslib.__generator(this, function (_b) {
1676
- switch (_b.label) {
1677
- case 0:
1678
- TABLE_NAME = this.config.restModel.TABLE_NAME;
1679
- method = this.config.requestMethod;
1680
- this.config.verbose && console.log("[SQL EXECUTOR] \u25B6\uFE0F Executing ".concat(method, " on table \"").concat(TABLE_NAME, "\""));
1681
- this.config.verbose && console.log("[SQL EXECUTOR] \uD83E\uDDE9 Request body:", this.request.body);
1682
- this.config.verbose && console.log("[SQL EXECUTOR] \uD83E\uDDE9 Request query:", this.request.query);
1683
- _a = method;
1684
- switch (_a) {
1685
- case 'GET': return [3 /*break*/, 1];
1686
- case 'POST': return [3 /*break*/, 3];
1687
- case 'PUT': return [3 /*break*/, 5];
1688
- case 'DELETE': return [3 /*break*/, 7];
1689
- }
1690
- return [3 /*break*/, 9];
1691
- case 1: return [4 /*yield*/, this.runQuery()];
1692
- case 2:
1693
- rest = _b.sent();
1694
- return [2 /*return*/, rest];
1695
- case 3: return [4 /*yield*/, this.runQuery()];
1696
- case 4:
1697
- result = _b.sent();
1698
- return [2 /*return*/, result];
1699
- case 5: return [4 /*yield*/, this.runQuery()];
1700
- case 6:
1701
- result = _b.sent();
1702
- return [2 /*return*/, result];
1703
- case 7: return [4 /*yield*/, this.runQuery()];
1704
- case 8:
1705
- result = _b.sent();
1706
- return [2 /*return*/, result];
1707
- case 9: throw new Error("Unsupported request method: ".concat(method));
1708
- }
1709
- });
1710
- });
1711
- };
1712
- SqlExecutor.prototype.withConnection = function (cb) {
1713
- return tslib.__awaiter(this, void 0, void 0, function () {
1714
- var conn;
1715
- return tslib.__generator(this, function (_a) {
1716
- switch (_a.label) {
1717
- case 0:
1718
- console.log("[SQL EXECUTOR] \uD83D\uDCE1 Getting DB connection");
1719
- return [4 /*yield*/, this.config.mysqlPool.getConnection()];
1720
- case 1:
1721
- conn = _a.sent();
1722
- _a.label = 2;
1723
- case 2:
1724
- _a.trys.push([2, , 4, 5]);
1725
- this.config.verbose && console.log("[SQL EXECUTOR] \u2705 Connection acquired");
1726
- return [4 /*yield*/, cb(conn)];
1727
- case 3: return [2 /*return*/, _a.sent()];
1728
- case 4:
1729
- this.config.verbose && console.log("[SQL EXECUTOR] \uD83D\uDD0C Releasing DB connection");
1730
- conn.release();
1731
- return [7 /*endfinally*/];
1732
- case 5: return [2 /*return*/];
1733
- }
1734
- });
1735
- });
1736
- };
1737
- SqlExecutor.prototype.formatSQLWithParams = function (sql, params) {
1738
- var _this = this;
1567
+ async withConnection(cb) {
1568
+ console.log(`[SQL EXECUTOR] 📡 Getting DB connection`);
1569
+ const conn = await this.config.mysqlPool.getConnection();
1570
+ try {
1571
+ this.config.verbose && console.log(`[SQL EXECUTOR] ✅ Connection acquired`);
1572
+ return await cb(conn);
1573
+ }
1574
+ finally {
1575
+ this.config.verbose && console.log(`[SQL EXECUTOR] 🔌 Releasing DB connection`);
1576
+ conn.release();
1577
+ }
1578
+ }
1579
+ serialize = (row) => Object.fromEntries(Object.entries(row).map(([k, v]) => [k, buffer.Buffer.isBuffer(v) ? v.toString('hex').toUpperCase() : v]));
1580
+ formatSQLWithParams(sql, params) {
1739
1581
  if (Array.isArray(params)) {
1740
- var index_1 = 0;
1741
- return sql.replace(/\?/g, function () {
1742
- if (index_1 >= params.length)
1582
+ let index = 0;
1583
+ return sql.replace(/\?/g, () => {
1584
+ if (index >= params.length)
1743
1585
  return '?';
1744
- var val = params[index_1++];
1745
- return _this.formatValue(val);
1586
+ const val = params[index++];
1587
+ return this.formatValue(val);
1746
1588
  });
1747
1589
  }
1748
1590
  else {
1749
- return sql.replace(/:([a-zA-Z0-9_]+)/g, function (_, key) {
1750
- var val = params[key];
1751
- return _this.formatValue(val);
1591
+ return sql.replace(/:([a-zA-Z0-9_]+)/g, (_, key) => {
1592
+ const val = params[key];
1593
+ return this.formatValue(val);
1752
1594
  });
1753
1595
  }
1754
- };
1755
- SqlExecutor.prototype.formatValue = function (val) {
1596
+ }
1597
+ formatValue(val) {
1756
1598
  if (val === null || val === undefined)
1757
1599
  return 'NULL';
1758
1600
  if (buffer.Buffer.isBuffer(val))
1759
- return "UNHEX('".concat(val.toString('hex'), "')");
1601
+ return `UNHEX('${val.toString('hex')}')`;
1760
1602
  if (typeof val === 'string')
1761
- return "'".concat(val.replace(/'/g, "''"), "'");
1603
+ return `'${val.replace(/'/g, "''")}'`;
1762
1604
  if (typeof val === 'number')
1763
1605
  return val.toString();
1764
1606
  if (val instanceof Date)
1765
- return "'".concat(val.toISOString().slice(0, 19).replace('T', ' '), "'");
1766
- return "'".concat(JSON.stringify(val), "'");
1767
- };
1768
- SqlExecutor.prototype.runQuery = function () {
1769
- return tslib.__awaiter(this, void 0, void 0, function () {
1770
- var TABLE_NAME, method, builder, QueryResult, formatted, toUnnamed, _a, sql, values;
1771
- var _this = this;
1772
- return tslib.__generator(this, function (_b) {
1773
- switch (_b.label) {
1774
- case 0:
1775
- TABLE_NAME = this.config.restModel.TABLE_NAME;
1776
- method = this.config.requestMethod;
1777
- switch (method) {
1778
- case 'GET':
1779
- builder = new SelectQueryBuilder(this.config, this.request);
1780
- break;
1781
- case 'PUT':
1782
- builder = new UpdateQueryBuilder(this.config, this.request);
1783
- break;
1784
- case 'DELETE':
1785
- builder = new DeleteQueryBuilder(this.config, this.request);
1786
- break;
1787
- case 'POST':
1788
- builder = new PostQueryBuilder(this.config, this.request);
1789
- break;
1790
- default:
1791
- throw new Error("Unsupported query method: ".concat(method));
1792
- }
1793
- QueryResult = builder.build(TABLE_NAME);
1794
- this.config.verbose && console.log("[SQL EXECUTOR] \uD83E\uDDE0 Generated ".concat(method.toUpperCase(), " SQL:"), QueryResult);
1795
- formatted = this.formatSQLWithParams(QueryResult.sql, QueryResult.params);
1796
- this.config.verbose && console.log("[SQL EXECUTOR] \uD83E\uDDE0 Formatted ".concat(method.toUpperCase(), " SQL:"), formatted);
1797
- toUnnamed = namedPlaceholders();
1798
- _a = toUnnamed(QueryResult.sql, QueryResult.params), sql = _a[0], values = _a[1];
1799
- return [4 /*yield*/, this.withConnection(function (conn) { return tslib.__awaiter(_this, void 0, void 0, function () {
1800
- var result;
1801
- return tslib.__generator(this, function (_a) {
1802
- switch (_a.label) {
1803
- case 0: return [4 /*yield*/, conn.query(sql, values)];
1804
- case 1:
1805
- result = (_a.sent())[0];
1806
- if (method === 'GET') {
1807
- this.config.verbose && console.log("[SQL EXECUTOR] \uD83D\uDCE6 Rows fetched:", result);
1808
- return [2 /*return*/, {
1809
- rest: result.map(this.serialize),
1810
- sql: { sql: sql, values: values }
1811
- }];
1812
- }
1813
- else {
1814
- this.config.verbose && console.log("[SQL EXECUTOR] \u270F\uFE0F Rows affected:", result.affectedRows);
1815
- return [2 /*return*/, {
1816
- affected: result.affectedRows,
1817
- rest: [],
1818
- sql: { sql: sql, values: values }
1819
- }];
1820
- }
1821
- }
1822
- });
1823
- }); })];
1824
- case 1: return [2 /*return*/, _b.sent()];
1825
- }
1826
- });
1607
+ return `'${val.toISOString().slice(0, 19).replace('T', ' ')}'`;
1608
+ return `'${JSON.stringify(val)}'`;
1609
+ }
1610
+ async runQuery() {
1611
+ const { TABLE_NAME } = this.config.restModel;
1612
+ const method = this.config.requestMethod;
1613
+ let builder;
1614
+ switch (method) {
1615
+ case 'GET':
1616
+ builder = new SelectQueryBuilder(this.config, this.request);
1617
+ break;
1618
+ case 'PUT':
1619
+ builder = new UpdateQueryBuilder(this.config, this.request);
1620
+ break;
1621
+ case 'DELETE':
1622
+ builder = new DeleteQueryBuilder(this.config, this.request);
1623
+ break;
1624
+ case 'POST':
1625
+ builder = new PostQueryBuilder(this.config, this.request);
1626
+ break;
1627
+ default:
1628
+ throw new Error(`Unsupported query method: ${method}`);
1629
+ }
1630
+ const QueryResult = builder.build(TABLE_NAME);
1631
+ this.config.verbose && console.log(`[SQL EXECUTOR] 🧠 Generated ${method.toUpperCase()} SQL:`, QueryResult);
1632
+ const formatted = this.formatSQLWithParams(QueryResult.sql, QueryResult.params);
1633
+ this.config.verbose && console.log(`[SQL EXECUTOR] 🧠 Formatted ${method.toUpperCase()} SQL:`, formatted);
1634
+ const toUnnamed = namedPlaceholders();
1635
+ const [sql, values] = toUnnamed(QueryResult.sql, QueryResult.params);
1636
+ return await this.withConnection(async (conn) => {
1637
+ const [result] = await conn.query(sql, values);
1638
+ if (method === 'GET') {
1639
+ this.config.verbose && console.log(`[SQL EXECUTOR] 📦 Rows fetched:`, result);
1640
+ return {
1641
+ rest: result.map(this.serialize),
1642
+ sql: { sql, values }
1643
+ };
1644
+ }
1645
+ else {
1646
+ this.config.verbose && console.log(`[SQL EXECUTOR] ✏️ Rows affected:`, result.affectedRows);
1647
+ return {
1648
+ affected: result.affectedRows,
1649
+ rest: [],
1650
+ sql: { sql, values }
1651
+ };
1652
+ }
1827
1653
  });
1828
- };
1829
- return SqlExecutor;
1830
- }(Executor));
1654
+ }
1655
+ }
1831
1656
 
1832
1657
  var SqlExecutor$1 = /*#__PURE__*/Object.freeze({
1833
1658
  __proto__: null,
@@ -1836,101 +1661,80 @@ var SqlExecutor$1 = /*#__PURE__*/Object.freeze({
1836
1661
 
1837
1662
  // TODO - WE MUST make this a generic - optional, but helpful
1838
1663
  // note sure how it would help anyone actually...
1839
- function ExpressHandler(_a) {
1840
- var _this = this;
1841
- var C6 = _a.C6, mysqlPool = _a.mysqlPool;
1842
- return function (req, res, next) { return tslib.__awaiter(_this, void 0, void 0, function () {
1843
- var method, table, primary, payload, primaryKeys, primaryKeyName, response, err_1;
1844
- return tslib.__generator(this, function (_a) {
1845
- switch (_a.label) {
1846
- case 0:
1847
- _a.trys.push([0, 2, , 3]);
1848
- method = req.method.toUpperCase();
1849
- table = req.params.table;
1850
- primary = req.params.primary;
1851
- payload = method === 'GET' ? req.query : req.body;
1852
- if (!(table in C6.TABLES)) {
1853
- res.status(400).json({ error: "Invalid table: ".concat(table) });
1854
- return [2 /*return*/];
1664
+ function ExpressHandler({ C6, mysqlPool }) {
1665
+ return async (req, res, next) => {
1666
+ try {
1667
+ const method = req.method.toUpperCase();
1668
+ const table = req.params.table;
1669
+ const primary = req.params.primary;
1670
+ const payload = method === 'GET' ? req.query : req.body;
1671
+ if (!(table in C6.TABLES)) {
1672
+ res.status(400).json({ error: `Invalid table: ${table}` });
1673
+ return;
1674
+ }
1675
+ const primaryKeys = C6.TABLES[table].PRIMARY;
1676
+ if (primary && primaryKeys.length !== 1) {
1677
+ if (primaryKeys.length > 1) {
1678
+ res.status(400).json({ error: `Table ${table} has multiple primary keys. Cannot implicitly determine key.` });
1679
+ return;
1680
+ }
1681
+ res.status(400).json({
1682
+ error: `Table ${table} has no primary keys. Please specify one.`
1683
+ });
1684
+ return;
1685
+ }
1686
+ const primaryKeyName = primaryKeys[0];
1687
+ // 👇 Call restRequest for the resolved method
1688
+ // TODO - add primary conditionally based on method signature
1689
+ switch (method) {
1690
+ case 'GET':
1691
+ if (primary) {
1692
+ payload[C6C.WHERE][primaryKeyName] = primary;
1855
1693
  }
1856
- primaryKeys = C6.TABLES[table].PRIMARY;
1857
- if (primary && primaryKeys.length !== 1) {
1858
- if (primaryKeys.length > 1) {
1859
- res.status(400).json({ error: "Table ".concat(table, " has multiple primary keys. Cannot implicitly determine key.") });
1860
- return [2 /*return*/];
1861
- }
1862
- res.status(400).json({
1863
- error: "Table ".concat(table, " has no primary keys. Please specify one.")
1864
- });
1865
- return [2 /*return*/];
1694
+ break;
1695
+ case 'PUT':
1696
+ case 'DELETE':
1697
+ if (primary) {
1698
+ payload[C6C.WHERE][primaryKeyName] = primary;
1866
1699
  }
1867
- primaryKeyName = primaryKeys[0];
1868
- // 👇 Call restRequest for the resolved method
1869
- // TODO - add primary conditionally based on method signature
1870
- switch (method) {
1871
- case 'GET':
1872
- if (primary) {
1873
- payload[C6C.WHERE][primaryKeyName] = primary;
1874
- }
1875
- break;
1876
- case 'PUT':
1877
- case 'DELETE':
1878
- if (primary) {
1879
- payload[C6C.WHERE][primaryKeyName] = primary;
1880
- }
1881
- else {
1882
- res.status(400).json({ error: "Invalid request: ".concat(method, " requires a primary key.") });
1883
- }
1884
- break;
1885
- case 'POST':
1886
- break;
1887
- default:
1888
- res.status(405).json({ error: "Method ".concat(method, " not allowed") });
1889
- return [2 /*return*/];
1700
+ else {
1701
+ res.status(400).json({ error: `Invalid request: ${method} requires a primary key.` });
1890
1702
  }
1891
- return [4 /*yield*/, restRequest({
1892
- C6: C6,
1893
- mysqlPool: mysqlPool,
1894
- requestMethod: method,
1895
- restModel: C6.TABLES[table]
1896
- })(payload)];
1897
- case 1:
1898
- response = _a.sent();
1899
- res.status(200).json(tslib.__assign({ success: true }, response));
1900
- return [3 /*break*/, 3];
1901
- case 2:
1902
- err_1 = _a.sent();
1903
- res.status(500).json({ success: false, error: err_1 });
1904
- next(err_1);
1905
- return [3 /*break*/, 3];
1906
- case 3: return [2 /*return*/];
1703
+ break;
1704
+ case 'POST':
1705
+ break;
1706
+ default:
1707
+ res.status(405).json({ error: `Method ${method} not allowed` });
1708
+ return;
1907
1709
  }
1908
- });
1909
- }); };
1710
+ const response = await restRequest({
1711
+ C6,
1712
+ mysqlPool,
1713
+ requestMethod: method,
1714
+ restModel: C6.TABLES[table]
1715
+ })(payload);
1716
+ res.status(200).json({ success: true, ...response });
1717
+ }
1718
+ catch (err) {
1719
+ res.status(500).json({ success: false, error: err });
1720
+ next(err);
1721
+ }
1722
+ };
1910
1723
  }
1911
1724
 
1912
1725
  // Alias a table name with a given alias
1913
- var A = function (tableName, alias) {
1914
- return "".concat(tableName, " ").concat(alias);
1915
- };
1726
+ const A = (tableName, alias) => `${tableName} ${alias}`;
1916
1727
  // Qualify a column constant (e.g. 'property_units.parcel_id') to an alias
1917
- var F = function (qualifiedCol, alias) {
1918
- return "".concat(alias, ".").concat(qualifiedCol.split('.').pop());
1919
- };
1728
+ const F = (qualifiedCol, alias) => `${alias}.${qualifiedCol.split('.').pop()}`;
1920
1729
  // Equal join condition using full-qualified column constants
1921
- var fieldEq = function (leftCol, rightCol, leftAlias, rightAlias) {
1922
- var _a;
1923
- return (_a = {},
1924
- _a[F(leftCol, leftAlias)] = F(rightCol, rightAlias),
1925
- _a);
1926
- };
1730
+ const fieldEq = (leftCol, rightCol, leftAlias, rightAlias) => ({
1731
+ [F(leftCol, leftAlias)]: F(rightCol, rightAlias)
1732
+ });
1927
1733
  // ST_Distance_Sphere for aliased fields
1928
- var distSphere = function (fromCol, toCol, fromAlias, toAlias) {
1929
- return [C6C.ST_DISTANCE_SPHERE, F(fromCol, fromAlias), F(toCol, toAlias)];
1930
- };
1734
+ const distSphere = (fromCol, toCol, fromAlias, toAlias) => [C6C.ST_DISTANCE_SPHERE, F(fromCol, fromAlias), F(toCol, toAlias)];
1931
1735
 
1932
1736
  function determineRuntimeJsType(mysqlType) {
1933
- var base = mysqlType.toLowerCase().split('(')[0];
1737
+ const base = mysqlType.toLowerCase().split('(')[0];
1934
1738
  if ([
1935
1739
  'binary', 'varbinary', 'blob', 'tinyblob', 'mediumblob', 'longblob'
1936
1740
  ].includes(base))
@@ -1951,23 +1755,15 @@ function determineRuntimeJsType(mysqlType) {
1951
1755
  return 'string';
1952
1756
  }
1953
1757
  function getPrimaryKeyTypes(table) {
1954
- var _a;
1955
- var result = {};
1956
- var _loop_1 = function (key) {
1957
- var fullKey = (_a = Object.entries(table.COLUMNS).find(function (_a) {
1958
- _a[0]; var short = _a[1];
1959
- return short === key;
1960
- })) === null || _a === void 0 ? void 0 : _a[0];
1758
+ const result = {};
1759
+ for (const key of table.PRIMARY_SHORT) {
1760
+ const fullKey = Object.entries(table.COLUMNS).find(([_, short]) => short === key)?.[0];
1961
1761
  if (typeof fullKey === 'string') {
1962
- var validation = table.TYPE_VALIDATION[fullKey];
1762
+ const validation = table.TYPE_VALIDATION[fullKey];
1963
1763
  if (!validation)
1964
- return "continue";
1764
+ continue;
1965
1765
  result[key] = determineRuntimeJsType(validation.MYSQL_TYPE);
1966
1766
  }
1967
- };
1968
- for (var _i = 0, _b = table.PRIMARY_SHORT; _i < _b.length; _i++) {
1969
- var key = _b[_i];
1970
- _loop_1(key);
1971
1767
  }
1972
1768
  return result;
1973
1769
  }
@@ -1976,42 +1772,30 @@ function getPrimaryKeyTypes(table) {
1976
1772
  * Conditionally group a log if verbose.
1977
1773
  */
1978
1774
  function group(title, data) {
1979
- console.groupCollapsed("%c".concat(title), "color: #007acc");
1775
+ console.groupCollapsed(`%c${title}`, "color: #007acc");
1980
1776
  if (data !== undefined)
1981
1777
  console.log(data);
1982
1778
  console.groupEnd();
1983
1779
  }
1984
- function info(message) {
1985
- var optional = [];
1986
- for (var _i = 1; _i < arguments.length; _i++) {
1987
- optional[_i - 1] = arguments[_i];
1988
- }
1989
- console.info.apply(console, tslib.__spreadArray(["%cINFO: ".concat(message), "color: #0a0"], optional, false));
1780
+ function info(message, ...optional) {
1781
+ console.info(`%cINFO: ${message}`, "color: #0a0", ...optional);
1990
1782
  }
1991
- function warn(message) {
1992
- var optional = [];
1993
- for (var _i = 1; _i < arguments.length; _i++) {
1994
- optional[_i - 1] = arguments[_i];
1995
- }
1996
- console.warn.apply(console, tslib.__spreadArray(["%cWARN: ".concat(message), "color: #e90"], optional, false));
1783
+ function warn(message, ...optional) {
1784
+ console.warn(`%cWARN: ${message}`, "color: #e90", ...optional);
1997
1785
  }
1998
- function error(message) {
1999
- var optional = [];
2000
- for (var _i = 1; _i < arguments.length; _i++) {
2001
- optional[_i - 1] = arguments[_i];
2002
- }
2003
- console.error.apply(console, tslib.__spreadArray(["%cERROR: ".concat(message), "color: #c00"], optional, false));
1786
+ function error(message, ...optional) {
1787
+ console.error(`%cERROR: ${message}`, "color: #c00", ...optional);
2004
1788
  }
2005
1789
 
2006
1790
  function checkAllRequestsComplete() {
2007
- var stillRunning = exports.apiRequestCache.filter(function (cache) { return undefined === cache.response; });
1791
+ const stillRunning = exports.apiRequestCache.filter((cache) => undefined === cache.response);
2008
1792
  if (stillRunning.length !== 0) {
2009
1793
  if (document === null || document === undefined) {
2010
1794
  throw new Error('document is undefined while waiting for API requests to complete (' + JSON.stringify(exports.apiRequestCache) + ')');
2011
1795
  }
2012
1796
  // when requests return emtpy sets in full renders, it may not be possible to track their progress.
2013
1797
  console.warn('stillRunning...', stillRunning);
2014
- return stillRunning.map(function (cache) { return cache.requestArgumentsSerialized; });
1798
+ return stillRunning.map((cache) => cache.requestArgumentsSerialized);
2015
1799
  }
2016
1800
  return true;
2017
1801
  }
@@ -2024,7 +1808,7 @@ function onError(message) {
2024
1808
  }
2025
1809
 
2026
1810
  function isVerbose () {
2027
- var envVerbose = getEnvVar('VERBOSE') || getEnvVar('REACT_APP_VERBOSE') || getEnvVar('VITE_VERBOSE') || '';
1811
+ const envVerbose = getEnvVar('VERBOSE') || getEnvVar('REACT_APP_VERBOSE') || getEnvVar('VITE_VERBOSE') || '';
2028
1812
  return ['true', '1', 'yes', 'on'].includes(envVerbose.toLowerCase());
2029
1813
  }
2030
1814