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