@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 +1007 -1223
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +1009 -1225
- package/dist/index.esm.js.map +1 -1
- package/package.json +5 -2
- package/src/api/convertForRequestBody.ts +23 -1
- package/src/api/executors/HttpExecutor.ts +3 -1
- package/src/api/executors/SqlExecutor.ts +1 -2
- package/src/api/orm/builders/ConditionBuilder.ts +4 -2
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
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(
|
|
282
|
-
throw new Error(
|
|
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 (
|
|
287
|
-
|
|
288
|
-
|
|
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
|
-
|
|
301
|
-
if (Array.isArray(
|
|
302
|
-
payload[value] =
|
|
297
|
+
const val = restfulObject[value];
|
|
298
|
+
if (Array.isArray(val)) {
|
|
299
|
+
payload[value] = val.sort();
|
|
303
300
|
}
|
|
304
|
-
else if (typeof
|
|
305
|
-
payload[value] = Object.keys(
|
|
301
|
+
else if (typeof val === 'object' && val !== null) {
|
|
302
|
+
payload[value] = Object.keys(val)
|
|
306
303
|
.sort()
|
|
307
|
-
.reduce(
|
|
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
|
-
|
|
306
|
+
continue;
|
|
313
307
|
}
|
|
314
308
|
if (shortReference in tableDefinition) {
|
|
315
|
-
|
|
316
|
-
|
|
309
|
+
const longName = tableDefinition[shortReference];
|
|
310
|
+
const columnValue = restfulObject[value];
|
|
317
311
|
payload[longName] = columnValue;
|
|
318
|
-
|
|
312
|
+
const regexValidations = tableDefinition.REGEX_VALIDATION[longName];
|
|
319
313
|
if (regexValidations instanceof RegExp) {
|
|
320
314
|
if (!regexValidations.test(columnValue)) {
|
|
321
|
-
regexErrorHandler(
|
|
322
|
-
throw new Error(
|
|
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 (
|
|
327
|
-
|
|
320
|
+
for (const errorMessage in regexValidations) {
|
|
321
|
+
const regex = regexValidations[errorMessage];
|
|
328
322
|
if (!regex.test(columnValue)) {
|
|
329
|
-
|
|
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(
|
|
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
|
-
|
|
351
|
-
var _a;
|
|
359
|
+
const isNode = () => {
|
|
352
360
|
console.log('Checking if running in Node.js environment...');
|
|
353
|
-
|
|
354
|
-
console.log(
|
|
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
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
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(
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
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
|
-
|
|
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
|
-
|
|
405
|
-
return
|
|
413
|
+
}, timeoutMs);
|
|
414
|
+
const timerId = timer();
|
|
415
|
+
return () => {
|
|
406
416
|
clearTimeout(timerId);
|
|
407
417
|
};
|
|
408
418
|
}
|
|
409
419
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
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
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
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
|
-
|
|
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
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
494
|
+
const POST = 'POST';
|
|
495
|
+
const PUT = 'PUT';
|
|
496
|
+
const GET = 'GET';
|
|
497
|
+
const DELETE = 'DELETE';
|
|
508
498
|
|
|
509
|
-
|
|
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
|
-
|
|
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
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|| undefined !==
|
|
534
|
-
|| undefined !==
|
|
535
|
-
|
|
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
|
|
530
|
+
return response.data.created ?? response.data.updated ?? response.data.deleted ?? true;
|
|
542
531
|
}
|
|
543
|
-
|
|
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
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
tableList.forEach(
|
|
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(
|
|
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 ===
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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] =
|
|
614
|
+
request[pk] = response.data?.created;
|
|
630
615
|
}
|
|
631
|
-
|
|
632
|
-
callback
|
|
616
|
+
this.config.reactBootstrap?.updateRestfulObjectArrays({
|
|
617
|
+
callback,
|
|
633
618
|
dataOrCallback: undefined !== request.dataInsertMultipleRows
|
|
634
|
-
? request.dataInsertMultipleRows.map(
|
|
635
|
-
|
|
636
|
-
|
|
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(
|
|
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
|
-
|
|
646
|
-
|
|
647
|
-
|
|
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
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
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
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
if (
|
|
694
|
-
console.groupCollapsed('%c API: (' + requestMethod + ')
|
|
695
|
-
console.log('
|
|
696
|
-
console.log('%c
|
|
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
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
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
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
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
|
-
|
|
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
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
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
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
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
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
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
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
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
|
-
|
|
1184
|
-
|
|
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
|
-
|
|
1190
|
-
|
|
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
|
-
|
|
1208
|
-
|
|
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
|
-
|
|
1221
|
-
|
|
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
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
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 +=
|
|
1164
|
+
expr += ` AS ${alias}`;
|
|
1233
1165
|
}
|
|
1234
|
-
this.config.verbose && console.log(
|
|
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
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
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 (
|
|
1263
|
-
for (
|
|
1264
|
-
|
|
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
|
-
|
|
1270
|
-
var _a, _b;
|
|
1183
|
+
}
|
|
1184
|
+
isColumnRef(ref) {
|
|
1271
1185
|
if (typeof ref !== 'string' || !ref.includes('.'))
|
|
1272
1186
|
return false;
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
1199
|
+
}
|
|
1200
|
+
execute() {
|
|
1286
1201
|
throw new Error("Method not implemented.");
|
|
1287
|
-
}
|
|
1288
|
-
|
|
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(
|
|
1215
|
+
throw new Error(`Invalid or unsupported SQL operator detected: '${op}'`);
|
|
1291
1216
|
}
|
|
1292
|
-
}
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
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
|
-
|
|
1222
|
+
const key = `param${Object.keys(params).length}`;
|
|
1299
1223
|
params[key] = val;
|
|
1300
|
-
return
|
|
1224
|
+
return `:${key}`;
|
|
1301
1225
|
}
|
|
1302
1226
|
else {
|
|
1303
1227
|
params.push(val);
|
|
1304
1228
|
return '?';
|
|
1305
1229
|
}
|
|
1306
|
-
}
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
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
|
-
|
|
1236
|
+
this.OPERATORS.has(column) &&
|
|
1316
1237
|
Array.isArray(op)) {
|
|
1317
1238
|
if (column === C6C.ST_DISTANCE_SPHERE) {
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
return
|
|
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
|
-
|
|
1324
|
-
|
|
1244
|
+
const leftIsCol = this.isColumnRef(column);
|
|
1245
|
+
const rightIsCol = typeof value === 'string' && this.isColumnRef(value);
|
|
1325
1246
|
if (!leftIsCol && !rightIsCol) {
|
|
1326
|
-
throw new Error(
|
|
1247
|
+
throw new Error(`Potential SQL injection detected: '${column} ${op} ${value}'`);
|
|
1327
1248
|
}
|
|
1328
|
-
|
|
1249
|
+
this.validateOperator(op);
|
|
1329
1250
|
if (op === C6C.MATCH_AGAINST && Array.isArray(value)) {
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
if (
|
|
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
|
-
|
|
1259
|
+
let againstClause;
|
|
1339
1260
|
switch ((mode || '').toUpperCase()) {
|
|
1340
1261
|
case 'BOOLEAN':
|
|
1341
|
-
againstClause =
|
|
1262
|
+
againstClause = this.useNamedParams ? `AGAINST(:${paramName} IN BOOLEAN MODE)` : `AGAINST(? IN BOOLEAN MODE)`;
|
|
1342
1263
|
break;
|
|
1343
1264
|
case 'WITH QUERY EXPANSION':
|
|
1344
|
-
againstClause =
|
|
1265
|
+
againstClause = this.useNamedParams ? `AGAINST(:${paramName} WITH QUERY EXPANSION)` : `AGAINST(? WITH QUERY EXPANSION)`;
|
|
1345
1266
|
break;
|
|
1346
1267
|
default: // NATURAL or undefined
|
|
1347
|
-
againstClause =
|
|
1268
|
+
againstClause = this.useNamedParams ? `AGAINST(:${paramName})` : `AGAINST(?)`;
|
|
1348
1269
|
break;
|
|
1349
1270
|
}
|
|
1350
1271
|
if (!leftIsCol) {
|
|
1351
|
-
throw new Error(
|
|
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
|
-
|
|
1354
|
-
|
|
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
|
-
|
|
1359
|
-
|
|
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(
|
|
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
|
|
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(
|
|
1288
|
+
throw new Error(`BETWEEN operator requires an array of two values. Received: ${JSON.stringify(value)}`);
|
|
1370
1289
|
}
|
|
1371
|
-
|
|
1290
|
+
const [start, end] = value;
|
|
1372
1291
|
if (!leftIsCol) {
|
|
1373
|
-
throw new Error(
|
|
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
|
|
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
|
|
1297
|
+
return `(${column}) ${op} ${value}`;
|
|
1379
1298
|
}
|
|
1380
1299
|
if (leftIsCol && !rightIsCol) {
|
|
1381
|
-
return
|
|
1300
|
+
return `(${column}) ${op} ${this.addParam(params, column, value)}`;
|
|
1382
1301
|
}
|
|
1383
1302
|
if (rightIsCol) {
|
|
1384
|
-
return
|
|
1303
|
+
return `(${this.addParam(params, column, column)}) ${op} ${value}`;
|
|
1385
1304
|
}
|
|
1386
|
-
throw new Error(
|
|
1305
|
+
throw new Error(`Neither operand appears to be a table reference`);
|
|
1387
1306
|
};
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
for (
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
1335
|
+
return subParts.join(` ${mode ? 'AND' : 'OR'} `);
|
|
1418
1336
|
};
|
|
1419
1337
|
if (Array.isArray(set)) {
|
|
1420
|
-
for (
|
|
1421
|
-
|
|
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
|
-
|
|
1345
|
+
const sub = buildFromObject(set, andMode);
|
|
1429
1346
|
if (sub)
|
|
1430
1347
|
parts.push(sub);
|
|
1431
1348
|
}
|
|
1432
|
-
|
|
1433
|
-
return clause ?
|
|
1434
|
-
}
|
|
1435
|
-
|
|
1436
|
-
|
|
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
|
-
|
|
1440
|
-
this.config.verbose && console.log(
|
|
1441
|
-
return
|
|
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
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
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
|
-
|
|
1459
|
-
|
|
1460
|
-
sql +=
|
|
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(
|
|
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
|
-
|
|
1475
|
-
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
class DeleteQueryBuilder extends JoinBuilder {
|
|
1381
|
+
build(table) {
|
|
1382
|
+
const params = this.useNamedParams ? {} : [];
|
|
1476
1383
|
this.initAlias(table, this.request.JOIN);
|
|
1477
|
-
|
|
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
|
|
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
|
-
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
class PostQueryBuilder extends ConditionBuilder {
|
|
1396
|
+
trimTablePrefix(table, column) {
|
|
1495
1397
|
if (!column.includes('.'))
|
|
1496
1398
|
return column;
|
|
1497
|
-
|
|
1399
|
+
const [prefix, col] = column.split('.', 2);
|
|
1498
1400
|
if (prefix !== table) {
|
|
1499
|
-
throw new Error(
|
|
1401
|
+
throw new Error(`Invalid prefixed column: '${column}'. Expected prefix '${table}.'`);
|
|
1500
1402
|
}
|
|
1501
1403
|
return col;
|
|
1502
|
-
}
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1422
|
+
const updateData = this.request[C6C.UPDATE];
|
|
1519
1423
|
if (!Array.isArray(updateData)) {
|
|
1520
|
-
throw new Error(
|
|
1424
|
+
throw new Error(`Update data must be an array of keys to update, got: ${JSON.stringify(updateData)}`);
|
|
1521
1425
|
}
|
|
1522
|
-
|
|
1523
|
-
sql +=
|
|
1426
|
+
const updateClause = updateData.map(k => `\`${k}\` = VALUES(\`${k}\`)`).join(', ');
|
|
1427
|
+
sql += ` ON DUPLICATE KEY UPDATE ${updateClause}`;
|
|
1524
1428
|
}
|
|
1525
|
-
return { sql
|
|
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
|
-
|
|
1549
|
-
|
|
1550
|
-
var _a;
|
|
1551
|
-
var sql = "";
|
|
1447
|
+
buildPaginationClause(pagination) {
|
|
1448
|
+
let sql = "";
|
|
1552
1449
|
/* -------- ORDER BY -------- */
|
|
1553
|
-
if (pagination
|
|
1554
|
-
|
|
1555
|
-
for (
|
|
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
|
-
|
|
1560
|
-
.map(
|
|
1455
|
+
const args = val
|
|
1456
|
+
.map((arg) => Array.isArray(arg) ? this.buildAggregateField(arg) : String(arg))
|
|
1561
1457
|
.join(", ");
|
|
1562
|
-
orderParts.push(
|
|
1458
|
+
orderParts.push(`${key}(${args})`);
|
|
1563
1459
|
}
|
|
1564
1460
|
// SIMPLE COLUMN + DIR (ASC/DESC)
|
|
1565
1461
|
else {
|
|
1566
|
-
orderParts.push(
|
|
1462
|
+
orderParts.push(`${key} ${String(val).toUpperCase()}`);
|
|
1567
1463
|
}
|
|
1568
1464
|
}
|
|
1569
1465
|
if (orderParts.length)
|
|
1570
|
-
sql +=
|
|
1466
|
+
sql += ` ORDER BY ${orderParts.join(", ")}`;
|
|
1571
1467
|
}
|
|
1572
1468
|
/* -------- LIMIT / OFFSET -------- */
|
|
1573
|
-
if (
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
sql +=
|
|
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(
|
|
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
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
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
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
.map(
|
|
1484
|
+
const params = this.useNamedParams ? {} : [];
|
|
1485
|
+
const selectList = args.SELECT ?? ['*'];
|
|
1486
|
+
const selectFields = selectList
|
|
1487
|
+
.map((f) => this.buildAggregateField(f))
|
|
1600
1488
|
.join(', ');
|
|
1601
|
-
|
|
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
|
-
|
|
1497
|
+
const groupBy = Array.isArray(args.GROUP_BY)
|
|
1610
1498
|
? args.GROUP_BY.join(', ')
|
|
1611
1499
|
: args.GROUP_BY;
|
|
1612
|
-
sql +=
|
|
1500
|
+
sql += ` GROUP BY ${groupBy}`;
|
|
1613
1501
|
}
|
|
1614
1502
|
if (args.HAVING) {
|
|
1615
|
-
sql +=
|
|
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 +=
|
|
1509
|
+
sql += ` LIMIT 100`;
|
|
1622
1510
|
}
|
|
1623
|
-
console.log(
|
|
1624
|
-
return { sql
|
|
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
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1647
|
-
|
|
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
|
|
1658
|
-
}
|
|
1659
|
-
|
|
1660
|
-
}(PaginationBuilder));
|
|
1536
|
+
return { sql, params };
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1661
1539
|
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
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
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
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
|
-
|
|
1741
|
-
return sql.replace(/\?/g,
|
|
1742
|
-
if (
|
|
1582
|
+
let index = 0;
|
|
1583
|
+
return sql.replace(/\?/g, () => {
|
|
1584
|
+
if (index >= params.length)
|
|
1743
1585
|
return '?';
|
|
1744
|
-
|
|
1745
|
-
return
|
|
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,
|
|
1750
|
-
|
|
1751
|
-
return
|
|
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
|
-
|
|
1596
|
+
}
|
|
1597
|
+
formatValue(val) {
|
|
1756
1598
|
if (val === null || val === undefined)
|
|
1757
1599
|
return 'NULL';
|
|
1758
1600
|
if (buffer.Buffer.isBuffer(val))
|
|
1759
|
-
return
|
|
1601
|
+
return `UNHEX('${val.toString('hex')}')`;
|
|
1760
1602
|
if (typeof val === 'string')
|
|
1761
|
-
return
|
|
1603
|
+
return `'${val.replace(/'/g, "''")}'`;
|
|
1762
1604
|
if (typeof val === 'number')
|
|
1763
1605
|
return val.toString();
|
|
1764
1606
|
if (val instanceof Date)
|
|
1765
|
-
return
|
|
1766
|
-
return
|
|
1767
|
-
}
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
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
|
-
|
|
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(
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
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
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
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
|
-
|
|
1868
|
-
|
|
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
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
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
|
-
|
|
1762
|
+
const validation = table.TYPE_VALIDATION[fullKey];
|
|
1963
1763
|
if (!validation)
|
|
1964
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
|