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