@carbonorm/carbonnode 3.11.0 → 4.0.0
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/api/orm/builders/ConditionBuilder.d.ts +3 -0
- package/dist/api/orm/queries/PostQueryBuilder.d.ts +1 -1
- package/dist/api/restOrm.d.ts +4 -4
- package/dist/api/types/ormInterfaces.d.ts +32 -12
- package/dist/api/utils/cacheManager.d.ts +7 -8
- package/dist/index.cjs.js +267 -140
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +263 -139
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/cacheManager.test.ts +67 -0
- package/src/__tests__/expressServer.e2e.test.ts +104 -2
- package/src/__tests__/fixtures/c6.fixture.ts +2 -0
- package/src/__tests__/httpExecutorSingular.e2e.test.ts +35 -4
- package/src/__tests__/sakila-db/C6.js +1 -1
- package/src/__tests__/sakila-db/C6.ts +1 -1
- package/src/__tests__/sqlBuilders.test.ts +28 -0
- package/src/api/axiosInstance.ts +29 -0
- package/src/api/executors/HttpExecutor.ts +73 -97
- package/src/api/handlers/ExpressHandler.ts +30 -7
- package/src/api/orm/builders/ConditionBuilder.ts +54 -0
- package/src/api/orm/queries/PostQueryBuilder.ts +4 -2
- package/src/api/orm/queries/UpdateQueryBuilder.ts +3 -1
- package/src/api/types/ormInterfaces.ts +32 -18
- package/src/api/utils/cacheManager.ts +75 -34
- package/src/api/utils/testHelpers.ts +5 -3
- package/src/variables/isNode.ts +1 -8
package/dist/index.cjs.js
CHANGED
|
@@ -307,8 +307,30 @@ axiosInstance.interceptors.request.use(function (config) {
|
|
|
307
307
|
};
|
|
308
308
|
}
|
|
309
309
|
}
|
|
310
|
+
config.__carbonStart = performance.now();
|
|
310
311
|
return config;
|
|
311
312
|
});
|
|
313
|
+
axiosInstance.interceptors.response.use(function (response) {
|
|
314
|
+
var end = performance.now();
|
|
315
|
+
var start = response.config.__carbonStart;
|
|
316
|
+
response.__carbonTiming = {
|
|
317
|
+
start: start,
|
|
318
|
+
end: end,
|
|
319
|
+
duration: end - start,
|
|
320
|
+
};
|
|
321
|
+
return response;
|
|
322
|
+
}, function (error) {
|
|
323
|
+
if (error.config) {
|
|
324
|
+
var end = performance.now();
|
|
325
|
+
var start = error.config.__carbonStart;
|
|
326
|
+
error.__carbonTiming = {
|
|
327
|
+
start: start,
|
|
328
|
+
end: end,
|
|
329
|
+
duration: end - start,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
throw error;
|
|
333
|
+
});
|
|
312
334
|
|
|
313
335
|
function convertForRequestBody (restfulObject, tableName, C6, regexErrorHandler) {
|
|
314
336
|
if (regexErrorHandler === void 0) { regexErrorHandler = alert; }
|
|
@@ -410,10 +432,7 @@ function convertForRequestBody (restfulObject, tableName, C6, regexErrorHandler)
|
|
|
410
432
|
|
|
411
433
|
var isNode = function () {
|
|
412
434
|
var _a;
|
|
413
|
-
|
|
414
|
-
var isNodeEnv = typeof process !== 'undefined' && !!((_a = process.versions) === null || _a === void 0 ? void 0 : _a.node);
|
|
415
|
-
console.log("Is Node.js environment: ".concat(isNodeEnv));
|
|
416
|
-
return isNodeEnv;
|
|
435
|
+
return typeof process !== 'undefined' && !!((_a = process.versions) === null || _a === void 0 ? void 0 : _a.node);
|
|
417
436
|
};
|
|
418
437
|
|
|
419
438
|
/**
|
|
@@ -631,26 +650,64 @@ function removeInvalidKeys(request, c6Tables) {
|
|
|
631
650
|
return intersection;
|
|
632
651
|
}
|
|
633
652
|
|
|
634
|
-
//
|
|
635
|
-
//
|
|
636
|
-
|
|
637
|
-
|
|
653
|
+
// -----------------------------------------------------------------------------
|
|
654
|
+
// Cache Storage
|
|
655
|
+
// -----------------------------------------------------------------------------
|
|
656
|
+
var apiRequestCache = new Map();
|
|
657
|
+
var userCustomClearCache = [];
|
|
658
|
+
// -----------------------------------------------------------------------------
|
|
659
|
+
// Cache Key Generator (safe, fixed-size ~40 chars)
|
|
660
|
+
// -----------------------------------------------------------------------------
|
|
661
|
+
// -----------------------------------------------------------------------------
|
|
662
|
+
// Browser-safe deterministic hash (FNV-1a)
|
|
663
|
+
// -----------------------------------------------------------------------------
|
|
664
|
+
function fnv1a(str) {
|
|
665
|
+
var h = 0x811c9dc5;
|
|
666
|
+
for (var i = 0; i < str.length; i++) {
|
|
667
|
+
h ^= str.charCodeAt(i);
|
|
668
|
+
h = (h * 0x01000193) >>> 0;
|
|
669
|
+
}
|
|
670
|
+
return h.toString(16);
|
|
671
|
+
}
|
|
672
|
+
function makeCacheKey(method, tableName, requestData) {
|
|
673
|
+
var raw = JSON.stringify([method, tableName, requestData]);
|
|
674
|
+
return fnv1a(raw);
|
|
675
|
+
}
|
|
676
|
+
// -----------------------------------------------------------------------------
|
|
677
|
+
// Clear Cache (no shared-array bugs)
|
|
678
|
+
// -----------------------------------------------------------------------------
|
|
638
679
|
function clearCache(props) {
|
|
639
|
-
if (
|
|
640
|
-
console.warn(
|
|
680
|
+
if (!(props === null || props === void 0 ? void 0 : props.ignoreWarning)) {
|
|
681
|
+
console.warn("The REST API clearCache should only be used with extreme care!");
|
|
682
|
+
}
|
|
683
|
+
for (var _i = 0, userCustomClearCache_1 = userCustomClearCache; _i < userCustomClearCache_1.length; _i++) {
|
|
684
|
+
var fn = userCustomClearCache_1[_i];
|
|
685
|
+
try {
|
|
686
|
+
fn();
|
|
687
|
+
}
|
|
688
|
+
catch (_a) { }
|
|
641
689
|
}
|
|
642
|
-
|
|
643
|
-
exports.userCustomClearCache = exports.apiRequestCache = [];
|
|
690
|
+
apiRequestCache.clear();
|
|
644
691
|
}
|
|
645
|
-
|
|
646
|
-
|
|
692
|
+
// -----------------------------------------------------------------------------
|
|
693
|
+
// Check Cache (dedupe via hashed key)
|
|
694
|
+
// -----------------------------------------------------------------------------
|
|
695
|
+
function checkCache(method, tableName, requestData) {
|
|
696
|
+
var key = makeCacheKey(method, tableName, requestData);
|
|
697
|
+
var cached = apiRequestCache.get(key);
|
|
698
|
+
if (!cached)
|
|
647
699
|
return false;
|
|
648
|
-
|
|
649
|
-
console.
|
|
650
|
-
console.log('%c ' + requestMethod + ' ' + tableName, 'color: #0c0');
|
|
651
|
-
console.log('%c Request Data (note you may see the success and/or error prompt):', 'color: #0c0', request);
|
|
700
|
+
console.groupCollapsed("%c API cache hit for ".concat(method, " ").concat(tableName), "color:#0c0");
|
|
701
|
+
console.log("Request Data:", requestData);
|
|
652
702
|
console.groupEnd();
|
|
653
|
-
return
|
|
703
|
+
return cached.request;
|
|
704
|
+
}
|
|
705
|
+
// -----------------------------------------------------------------------------
|
|
706
|
+
// Store Cache Entry (drop-in compatible)
|
|
707
|
+
// -----------------------------------------------------------------------------
|
|
708
|
+
function setCache(method, tableName, requestData, cacheEntry) {
|
|
709
|
+
var key = makeCacheKey(method, tableName, requestData);
|
|
710
|
+
apiRequestCache.set(key, cacheEntry);
|
|
654
711
|
}
|
|
655
712
|
|
|
656
713
|
function sortAndSerializeQueryObject(tables, query) {
|
|
@@ -667,7 +724,10 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
667
724
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
668
725
|
}
|
|
669
726
|
HttpExecutor.prototype.isRestResponse = function (r) {
|
|
670
|
-
return !!r
|
|
727
|
+
return !!r
|
|
728
|
+
&& r.data != null
|
|
729
|
+
&& typeof r.data === 'object'
|
|
730
|
+
&& Array.isArray(r.data.rest);
|
|
671
731
|
};
|
|
672
732
|
HttpExecutor.prototype.stripTableNameFromKeys = function (obj) {
|
|
673
733
|
var _a;
|
|
@@ -763,26 +823,16 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
763
823
|
throw Error('Bad request method passed to getApi');
|
|
764
824
|
}
|
|
765
825
|
if (clearCache != null) {
|
|
766
|
-
|
|
826
|
+
userCustomClearCache.push(clearCache);
|
|
767
827
|
}
|
|
768
828
|
if (isLocal() && (this.config.verbose || ((_b = this.request) === null || _b === void 0 ? void 0 : _b.debug))) {
|
|
769
829
|
console.groupCollapsed('%c API:', 'color: #0c0', "(".concat(requestMethod, ") Request for (").concat(tableName, ")"));
|
|
770
830
|
console.log('request', this.request);
|
|
771
831
|
console.groupEnd();
|
|
772
832
|
}
|
|
773
|
-
// an undefined query would indicate queryCallback returned undefined,
|
|
774
|
-
// thus the request shouldn't fire as is in custom cache
|
|
775
|
-
if (undefined === this.request || null === this.request) {
|
|
776
|
-
if (isLocal()) {
|
|
777
|
-
console.groupCollapsed("API: (".concat(requestMethod, ") (").concat(tableName, ") query undefined/null \u2192 returning null"));
|
|
778
|
-
console.log('request', this.request);
|
|
779
|
-
console.groupEnd();
|
|
780
|
-
}
|
|
781
|
-
return [2 /*return*/, null];
|
|
782
|
-
}
|
|
783
833
|
query = this.request;
|
|
784
834
|
apiRequest = function () { return tslib.__awaiter(_this, void 0, void 0, function () {
|
|
785
|
-
var _a, debug, _b, cacheResults, dataInsertMultipleRows, success, _c, fetchDependencies, _d, error,
|
|
835
|
+
var _a, debug, _b, cacheResults, dataInsertMultipleRows, success, _c, fetchDependencies, _d, error, cachingConfirmed, cacheRequestData, querySerialized, cachedRequest, apiResponse, restRequestUri, needsConditionOrPrimaryCheck, TABLES, primaryKeyList, primaryKeyFullyQualified, primaryKey, whereVal, whereIsEmpty, providedPrimary, primaryVal, axiosActiveRequest_1;
|
|
786
836
|
var _e;
|
|
787
837
|
var _this = this;
|
|
788
838
|
var _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
@@ -798,63 +848,37 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
798
848
|
console.log('request', this.request);
|
|
799
849
|
console.groupEnd();
|
|
800
850
|
}
|
|
801
|
-
querySerialized = sortAndSerializeQueryObject(tables, query !== null && query !== void 0 ? query : {});
|
|
802
|
-
cacheResult = exports.apiRequestCache.find(function (cache) { return cache.requestArgumentsSerialized === querySerialized; });
|
|
803
851
|
cachingConfirmed = false;
|
|
804
|
-
|
|
805
|
-
if (
|
|
806
|
-
if (undefined === query
|
|
807
|
-
query
|
|
852
|
+
// determine if we need to paginate.
|
|
853
|
+
if (requestMethod === C6.GET) {
|
|
854
|
+
if (undefined === (query === null || query === void 0 ? void 0 : query[C6.PAGINATION])) {
|
|
855
|
+
if (undefined === query || null === query) {
|
|
856
|
+
query = {};
|
|
857
|
+
}
|
|
858
|
+
query[C6.PAGINATION] = {};
|
|
808
859
|
}
|
|
809
|
-
query[C6.PAGINATION] =
|
|
860
|
+
query[C6.PAGINATION][C6.PAGE] = query[C6.PAGINATION][C6.PAGE] || 1;
|
|
861
|
+
query[C6.PAGINATION][C6.LIMIT] = query[C6.PAGINATION][C6.LIMIT] || 100;
|
|
862
|
+
}
|
|
863
|
+
cacheRequestData = JSON.parse(JSON.stringify(query !== null && query !== void 0 ? query : {}));
|
|
864
|
+
querySerialized = sortAndSerializeQueryObject(tables, cacheRequestData !== null && cacheRequestData !== void 0 ? cacheRequestData : {});
|
|
865
|
+
cachedRequest = false;
|
|
866
|
+
if (cacheResults) {
|
|
867
|
+
cachedRequest = checkCache(requestMethod, tableName, cacheRequestData);
|
|
810
868
|
}
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
cacheCheck = checkCache(cacheResult, requestMethod, tableName, this.request);
|
|
818
|
-
if (!(false !== cacheCheck)) return [3 /*break*/, 3];
|
|
819
|
-
return [4 /*yield*/, cacheCheck];
|
|
820
|
-
case 2: return [2 /*return*/, (_r.sent()).data];
|
|
821
|
-
case 3:
|
|
822
|
-
++query[C6.PAGINATION][C6.PAGE];
|
|
823
|
-
querySerialized = sortAndSerializeQueryObject(tables, query !== null && query !== void 0 ? query : {});
|
|
824
|
-
cacheResult = exports.apiRequestCache.find(function (cache) { return cache.requestArgumentsSerialized === querySerialized; });
|
|
825
|
-
_r.label = 4;
|
|
826
|
-
case 4:
|
|
827
|
-
if (undefined !== cacheResult) return [3 /*break*/, 1];
|
|
828
|
-
_r.label = 5;
|
|
829
|
-
case 5:
|
|
830
|
-
if (debug && isLocal()) {
|
|
831
|
-
reactToastify.toast.warning("DEVS: Request pages exhausted in cache; firing network.", toastOptionsDevs);
|
|
869
|
+
if (!cachedRequest) return [3 /*break*/, 2];
|
|
870
|
+
return [4 /*yield*/, cachedRequest];
|
|
871
|
+
case 1: return [2 /*return*/, (_r.sent()).data];
|
|
872
|
+
case 2:
|
|
873
|
+
if (cacheResults) {
|
|
874
|
+
cachingConfirmed = true;
|
|
832
875
|
}
|
|
833
|
-
|
|
834
|
-
case 6:
|
|
835
|
-
cachingConfirmed = true;
|
|
836
|
-
return [3 /*break*/, 8];
|
|
837
|
-
case 7:
|
|
838
|
-
if (debug && isLocal())
|
|
876
|
+
else if (debug && isLocal()) {
|
|
839
877
|
reactToastify.toast.info("DEVS: Ignore cache was set to true.", toastOptionsDevs);
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
if (debug && isLocal()) {
|
|
878
|
+
}
|
|
879
|
+
if (cacheResults && debug && isLocal()) {
|
|
843
880
|
reactToastify.toast.success("DEVS: Request not in cache." + (requestMethod === C6.GET ? " Page (" + query[C6.PAGINATION][C6.PAGE] + ")" : ''), toastOptionsDevs);
|
|
844
881
|
}
|
|
845
|
-
return [3 /*break*/, 12];
|
|
846
|
-
case 9:
|
|
847
|
-
if (!cacheResults) return [3 /*break*/, 12];
|
|
848
|
-
if (!cacheResult) return [3 /*break*/, 11];
|
|
849
|
-
cacheCheck = checkCache(cacheResult, requestMethod, tableName, this.request);
|
|
850
|
-
if (!(false !== cacheCheck)) return [3 /*break*/, 11];
|
|
851
|
-
return [4 /*yield*/, cacheCheck];
|
|
852
|
-
case 10: return [2 /*return*/, (_r.sent()).data];
|
|
853
|
-
case 11:
|
|
854
|
-
cachingConfirmed = true;
|
|
855
|
-
_r.label = 12;
|
|
856
|
-
case 12:
|
|
857
|
-
returnGetNextPageFunction = false;
|
|
858
882
|
restRequestUri = restURL + operatingTable + '/';
|
|
859
883
|
needsConditionOrPrimaryCheck = (PUT === requestMethod || DELETE === requestMethod)
|
|
860
884
|
&& false === skipPrimaryCheck;
|
|
@@ -924,7 +948,7 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
924
948
|
config: this.config,
|
|
925
949
|
request: this.request
|
|
926
950
|
});
|
|
927
|
-
|
|
951
|
+
axiosActiveRequest_1 = (_e = axios)[requestMethod.toLowerCase()].apply(_e, tslib.__spreadArray([restRequestUri], (function () {
|
|
928
952
|
var convert = function (data) {
|
|
929
953
|
return convertForRequestBody(data, fullTableList, C6, function (message) { return reactToastify.toast.error(message, toastOptions); });
|
|
930
954
|
};
|
|
@@ -951,23 +975,30 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
951
975
|
}
|
|
952
976
|
})(), false));
|
|
953
977
|
if (cachingConfirmed) {
|
|
954
|
-
|
|
955
|
-
exports.apiRequestCache.push({
|
|
978
|
+
setCache(requestMethod, tableName, cacheRequestData, {
|
|
956
979
|
requestArgumentsSerialized: querySerialized,
|
|
957
|
-
request:
|
|
980
|
+
request: axiosActiveRequest_1,
|
|
958
981
|
});
|
|
959
982
|
}
|
|
960
983
|
// returning the promise with this then is important for tests. todo - we could make that optional.
|
|
961
984
|
// https://rapidapi.com/guides/axios-async-await
|
|
962
|
-
return [2 /*return*/,
|
|
963
|
-
var
|
|
985
|
+
return [2 /*return*/, axiosActiveRequest_1.then(function (response) { return tslib.__awaiter(_this, void 0, void 0, function () {
|
|
986
|
+
var hasNext, callback, responseData_1, pageLimit, got, dependencies_1, fetchReferences_1, apiRequestPromises, _loop_1, tableToFetch;
|
|
964
987
|
var _this = this;
|
|
965
|
-
var _a, _b, _c, _d;
|
|
966
|
-
return tslib.__generator(this, function (
|
|
967
|
-
switch (
|
|
988
|
+
var _a, _b, _c, _d, _e;
|
|
989
|
+
return tslib.__generator(this, function (_f) {
|
|
990
|
+
switch (_f.label) {
|
|
968
991
|
case 0:
|
|
969
992
|
// noinspection SuspiciousTypeOfGuard
|
|
970
993
|
if (typeof response.data === 'string') {
|
|
994
|
+
if (cachingConfirmed) {
|
|
995
|
+
setCache(requestMethod, tableName, cacheRequestData, {
|
|
996
|
+
requestArgumentsSerialized: querySerialized,
|
|
997
|
+
request: axiosActiveRequest_1,
|
|
998
|
+
response: response,
|
|
999
|
+
final: true,
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
971
1002
|
if (isTest()) {
|
|
972
1003
|
console.trace();
|
|
973
1004
|
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 + ')');
|
|
@@ -975,11 +1006,11 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
975
1006
|
return [2 /*return*/, Promise.reject(response)];
|
|
976
1007
|
}
|
|
977
1008
|
if (cachingConfirmed) {
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
1009
|
+
setCache(requestMethod, tableName, cacheRequestData, {
|
|
1010
|
+
requestArgumentsSerialized: querySerialized,
|
|
1011
|
+
request: axiosActiveRequest_1,
|
|
1012
|
+
response: response,
|
|
1013
|
+
});
|
|
983
1014
|
}
|
|
984
1015
|
this.runLifecycleHooks("afterExecution", {
|
|
985
1016
|
config: this.config,
|
|
@@ -1030,17 +1061,18 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
1030
1061
|
got = responseData_1.rest.length;
|
|
1031
1062
|
hasNext = pageLimit !== 1 && got === pageLimit;
|
|
1032
1063
|
if (hasNext) {
|
|
1033
|
-
responseData_1.next = apiRequest;
|
|
1064
|
+
responseData_1.next = apiRequest;
|
|
1034
1065
|
}
|
|
1035
1066
|
else {
|
|
1036
1067
|
responseData_1.next = undefined; // short page => done
|
|
1037
1068
|
}
|
|
1038
|
-
// If you keep this flag, make it reflect reality:
|
|
1039
|
-
returnGetNextPageFunction = hasNext;
|
|
1040
|
-
// and fix cache ‘final’ flag to match:
|
|
1041
1069
|
if (cachingConfirmed) {
|
|
1042
|
-
|
|
1043
|
-
|
|
1070
|
+
setCache(requestMethod, tableName, cacheRequestData, {
|
|
1071
|
+
requestArgumentsSerialized: querySerialized,
|
|
1072
|
+
request: axiosActiveRequest_1,
|
|
1073
|
+
response: response,
|
|
1074
|
+
final: !hasNext,
|
|
1075
|
+
});
|
|
1044
1076
|
}
|
|
1045
1077
|
if ((this.config.verbose || debug) && isLocal()) {
|
|
1046
1078
|
console.groupCollapsed("API: Response (".concat(requestMethod, " ").concat(tableName, ") len (").concat((_b = responseData_1.rest) === null || _b === void 0 ? void 0 : _b.length, ") of (").concat((_c = query === null || query === void 0 ? void 0 : query[C6.PAGINATION]) === null || _c === void 0 ? void 0 : _c[C6.LIMIT], ")"));
|
|
@@ -1050,7 +1082,7 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
1050
1082
|
}
|
|
1051
1083
|
if (!(fetchDependencies
|
|
1052
1084
|
&& 'number' === typeof fetchDependencies
|
|
1053
|
-
&& responseData_1.rest.length > 0)) return [3 /*break*/, 2];
|
|
1085
|
+
&& ((_d = responseData_1.rest) === null || _d === void 0 ? void 0 : _d.length) > 0)) return [3 /*break*/, 2];
|
|
1054
1086
|
console.groupCollapsed('%c API: Fetch Dependencies segment (' + requestMethod + ' ' + tableName + ')'
|
|
1055
1087
|
+ (fetchDependencies & exports.eFetchDependencies.CHILDREN ? ' | (CHILDREN|REFERENCED) ' : '')
|
|
1056
1088
|
+ (fetchDependencies & exports.eFetchDependencies.PARENTS ? ' | (PARENTS|REFERENCED_BY)' : '')
|
|
@@ -1121,7 +1153,7 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
1121
1153
|
}); });
|
|
1122
1154
|
console.log('fetchReferences', fetchReferences_1);
|
|
1123
1155
|
_loop_1 = function (tableToFetch) {
|
|
1124
|
-
var
|
|
1156
|
+
var _g;
|
|
1125
1157
|
if (fetchDependencies & exports.eFetchDependencies.C6ENTITY
|
|
1126
1158
|
&& 'string' === typeof tableName
|
|
1127
1159
|
&& tableName.endsWith("carbon_carbons")) {
|
|
@@ -1144,7 +1176,7 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
1144
1176
|
.split('_')
|
|
1145
1177
|
.map(function (part) { return part.charAt(0).toUpperCase() + part.slice(1); })
|
|
1146
1178
|
.join('_');
|
|
1147
|
-
var RestApi = (
|
|
1179
|
+
var RestApi = (_e = C6.ORM[ormKey]) !== null && _e !== void 0 ? _e : new Error("Fetch Dependencies could not find table (".concat(ormKey, ") in the set \u2209 [ ").concat(Object.keys(C6.ORM).join(', '), " ]"));
|
|
1148
1180
|
console.log('%c Fetch Dependencies will select (' + tableToFetch + ') using GET request', 'color: #33ccff');
|
|
1149
1181
|
var nextFetchDependencies = exports.eFetchDependencies.NONE;
|
|
1150
1182
|
if (fetchDependencies & exports.eFetchDependencies.RECURSIVE) {
|
|
@@ -1170,8 +1202,8 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
1170
1202
|
console.log('RestApi object', RestApi);
|
|
1171
1203
|
// this is a dynamic call to the rest api, any generated table may resolve with (RestApi)
|
|
1172
1204
|
// todo - using value to avoid joins.... but. maybe this should be a parameterizable option -- think race conditions; its safer to join
|
|
1173
|
-
apiRequestPromises.push(RestApi.Get((
|
|
1174
|
-
|
|
1205
|
+
apiRequestPromises.push(RestApi.Get((_g = {},
|
|
1206
|
+
_g[C6.WHERE] = Object.keys(fetchReferences_1[tableToFetch]).reduce(function (sum, column) {
|
|
1175
1207
|
fetchReferences_1[tableToFetch][column] = fetchReferences_1[tableToFetch][column].flat(Infinity);
|
|
1176
1208
|
if (0 === fetchReferences_1[tableToFetch][column].length) {
|
|
1177
1209
|
console.warn('The column (' + column + ') was not found in the response data. We will not fetch.', responseData_1);
|
|
@@ -1184,8 +1216,8 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
1184
1216
|
];
|
|
1185
1217
|
return sum;
|
|
1186
1218
|
}, {}),
|
|
1187
|
-
|
|
1188
|
-
|
|
1219
|
+
_g.fetchDependencies = nextFetchDependencies,
|
|
1220
|
+
_g)));
|
|
1189
1221
|
};
|
|
1190
1222
|
for (tableToFetch in fetchReferences_1) {
|
|
1191
1223
|
_loop_1(tableToFetch);
|
|
@@ -1193,7 +1225,7 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
1193
1225
|
console.groupEnd();
|
|
1194
1226
|
return [4 /*yield*/, Promise.all(apiRequestPromises)];
|
|
1195
1227
|
case 1:
|
|
1196
|
-
|
|
1228
|
+
_f.sent();
|
|
1197
1229
|
apiRequestPromises.map(function (promise) { return tslib.__awaiter(_this, void 0, void 0, function () {
|
|
1198
1230
|
var _a, _b;
|
|
1199
1231
|
return tslib.__generator(this, function (_c) {
|
|
@@ -1211,8 +1243,16 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
1211
1243
|
}
|
|
1212
1244
|
});
|
|
1213
1245
|
}); });
|
|
1214
|
-
|
|
1246
|
+
_f.label = 2;
|
|
1215
1247
|
case 2:
|
|
1248
|
+
if (cachingConfirmed && hasNext === undefined) {
|
|
1249
|
+
setCache(requestMethod, tableName, cacheRequestData, {
|
|
1250
|
+
requestArgumentsSerialized: querySerialized,
|
|
1251
|
+
request: axiosActiveRequest_1,
|
|
1252
|
+
response: response,
|
|
1253
|
+
final: true,
|
|
1254
|
+
});
|
|
1255
|
+
}
|
|
1216
1256
|
if (debug && isLocal()) {
|
|
1217
1257
|
reactToastify.toast.success("DEVS: (" + requestMethod + ") request complete.", toastOptionsDevs);
|
|
1218
1258
|
}
|
|
@@ -1223,16 +1263,12 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
1223
1263
|
}); }).then(function (response) { return response.data; })]; // this escapes from axios context
|
|
1224
1264
|
}
|
|
1225
1265
|
catch (throwableError) {
|
|
1226
|
-
if (isTest()) {
|
|
1227
|
-
throw new Error(JSON.stringify(throwableError));
|
|
1228
|
-
}
|
|
1229
1266
|
console.groupCollapsed('%c API: An error occurred in the try catch block. returning null!', 'color: #ff0000');
|
|
1230
1267
|
console.log('%c ' + requestMethod + ' ' + tableName, 'color: #A020F0');
|
|
1231
|
-
console.
|
|
1268
|
+
console.error(throwableError);
|
|
1232
1269
|
console.trace();
|
|
1233
1270
|
console.groupEnd();
|
|
1234
|
-
|
|
1235
|
-
return [2 /*return*/, null];
|
|
1271
|
+
throw new Error(JSON.stringify(throwableError));
|
|
1236
1272
|
}
|
|
1237
1273
|
return [2 /*return*/];
|
|
1238
1274
|
}
|
|
@@ -1791,6 +1827,62 @@ var ConditionBuilder = /** @class */ (function (_super) {
|
|
|
1791
1827
|
}
|
|
1792
1828
|
throw new Error('Unsupported operand type in SQL expression.');
|
|
1793
1829
|
};
|
|
1830
|
+
ConditionBuilder.prototype.isPlainArrayLiteral = function (value) {
|
|
1831
|
+
var _this = this;
|
|
1832
|
+
if (!Array.isArray(value))
|
|
1833
|
+
return false;
|
|
1834
|
+
return value.every(function (item) {
|
|
1835
|
+
if (item === null)
|
|
1836
|
+
return true;
|
|
1837
|
+
var type = typeof item;
|
|
1838
|
+
if (type === 'string' || type === 'number' || type === 'boolean')
|
|
1839
|
+
return true;
|
|
1840
|
+
if (Array.isArray(item))
|
|
1841
|
+
return _this.isPlainArrayLiteral(item);
|
|
1842
|
+
if (item && typeof item === 'object')
|
|
1843
|
+
return _this.isPlainObjectLiteral(item);
|
|
1844
|
+
return false;
|
|
1845
|
+
});
|
|
1846
|
+
};
|
|
1847
|
+
ConditionBuilder.prototype.isPlainObjectLiteral = function (value) {
|
|
1848
|
+
var _this = this;
|
|
1849
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
1850
|
+
return false;
|
|
1851
|
+
if (value instanceof Date)
|
|
1852
|
+
return false;
|
|
1853
|
+
if (typeof Buffer !== 'undefined' && Buffer.isBuffer && Buffer.isBuffer(value))
|
|
1854
|
+
return false;
|
|
1855
|
+
var normalized = value instanceof Map ? Object.fromEntries(value) : value;
|
|
1856
|
+
if (C6C.SUBSELECT in normalized)
|
|
1857
|
+
return false;
|
|
1858
|
+
var entries = Object.entries(normalized);
|
|
1859
|
+
if (entries.length === 0)
|
|
1860
|
+
return true;
|
|
1861
|
+
if (entries.some(function (_a) {
|
|
1862
|
+
var key = _a[0];
|
|
1863
|
+
return _this.isOperator(key) || _this.BOOLEAN_OPERATORS.has(key);
|
|
1864
|
+
})) {
|
|
1865
|
+
return false;
|
|
1866
|
+
}
|
|
1867
|
+
if (entries.some(function (_a) {
|
|
1868
|
+
var key = _a[0];
|
|
1869
|
+
return typeof key === 'string' && (_this.isColumnRef(key) || key.includes('.'));
|
|
1870
|
+
})) {
|
|
1871
|
+
return false;
|
|
1872
|
+
}
|
|
1873
|
+
return true;
|
|
1874
|
+
};
|
|
1875
|
+
ConditionBuilder.prototype.serializeUpdateValue = function (value, params, contextColumn) {
|
|
1876
|
+
var normalized = value instanceof Map ? Object.fromEntries(value) : value;
|
|
1877
|
+
if (this.isPlainArrayLiteral(normalized) || this.isPlainObjectLiteral(normalized)) {
|
|
1878
|
+
return this.addParam(params, contextColumn !== null && contextColumn !== void 0 ? contextColumn : '', JSON.stringify(normalized));
|
|
1879
|
+
}
|
|
1880
|
+
var _a = this.serializeOperand(normalized, params, contextColumn), sql = _a.sql, isReference = _a.isReference, isExpression = _a.isExpression, isSubSelect = _a.isSubSelect;
|
|
1881
|
+
if (!isReference && !isExpression && !isSubSelect && typeof normalized === 'object' && normalized !== null) {
|
|
1882
|
+
throw new Error('Unsupported operand type in SQL expression.');
|
|
1883
|
+
}
|
|
1884
|
+
return sql;
|
|
1885
|
+
};
|
|
1794
1886
|
ConditionBuilder.prototype.ensurePlainObject = function (value) {
|
|
1795
1887
|
if (value instanceof Map) {
|
|
1796
1888
|
return Object.fromEntries(value);
|
|
@@ -2647,12 +2739,14 @@ var PostQueryBuilder = /** @class */ (function (_super) {
|
|
|
2647
2739
|
var verb = C6C.REPLACE in this.request ? C6C.REPLACE : C6C.INSERT;
|
|
2648
2740
|
var body = verb in this.request ? this.request[verb] : this.request;
|
|
2649
2741
|
var keys = Object.keys(body);
|
|
2650
|
-
var params = [];
|
|
2742
|
+
var params = this.useNamedParams ? {} : [];
|
|
2651
2743
|
var placeholders = [];
|
|
2652
2744
|
for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
|
|
2653
2745
|
var key = keys_1[_i];
|
|
2654
2746
|
var value = body[key];
|
|
2655
|
-
var
|
|
2747
|
+
var trimmed = this.trimTablePrefix(table, key);
|
|
2748
|
+
var qualified = "".concat(table, ".").concat(trimmed);
|
|
2749
|
+
var placeholder = this.serializeUpdateValue(value, params, qualified);
|
|
2656
2750
|
placeholders.push(placeholder);
|
|
2657
2751
|
}
|
|
2658
2752
|
var sql = "".concat(verb, " INTO `").concat(table, "` (\n ").concat(keys.map(function (k) { return "`".concat(_this.trimTablePrefix(table, k), "`"); }).join(', '), "\n ) VALUES (\n ").concat(placeholders.join(', '), "\n )");
|
|
@@ -2704,7 +2798,9 @@ var UpdateQueryBuilder = /** @class */ (function (_super) {
|
|
|
2704
2798
|
var col = _a[0], val = _a[1];
|
|
2705
2799
|
var trimmed = _this.trimTablePrefix(table, col);
|
|
2706
2800
|
var qualified = "".concat(table, ".").concat(trimmed);
|
|
2707
|
-
|
|
2801
|
+
_this.assertValidIdentifier(qualified, 'UPDATE SET');
|
|
2802
|
+
var rightSql = _this.serializeUpdateValue(val, params, qualified);
|
|
2803
|
+
return "`".concat(trimmed, "` = ").concat(rightSql);
|
|
2708
2804
|
});
|
|
2709
2805
|
sql += " SET ".concat(setClauses.join(', '));
|
|
2710
2806
|
if (args.WHERE) {
|
|
@@ -3032,12 +3128,12 @@ function ExpressHandler(_a) {
|
|
|
3032
3128
|
var _this = this;
|
|
3033
3129
|
var C6 = _a.C6, mysqlPool = _a.mysqlPool;
|
|
3034
3130
|
return function (req, res, next) { return tslib.__awaiter(_this, void 0, void 0, function () {
|
|
3035
|
-
var incomingMethod, table, primary, methodOverrideRaw, methodOverride, treatAsGet, method, payload,
|
|
3036
|
-
var _a, _b, _c, _d, _e;
|
|
3037
|
-
return tslib.__generator(this, function (
|
|
3038
|
-
switch (
|
|
3131
|
+
var incomingMethod, table, primary, methodOverrideRaw, methodOverride, treatAsGet, method, payload, restModel, primaryKeys_1, primaryShortKeys_1, columnMap_1, resolveShortKey_1, hasPrimaryKeyValues, primaryKeyName, response, err_1;
|
|
3132
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
3133
|
+
return tslib.__generator(this, function (_h) {
|
|
3134
|
+
switch (_h.label) {
|
|
3039
3135
|
case 0:
|
|
3040
|
-
|
|
3136
|
+
_h.trys.push([0, 2, , 3]);
|
|
3041
3137
|
incomingMethod = req.method.toUpperCase();
|
|
3042
3138
|
table = req.params.table;
|
|
3043
3139
|
primary = req.params.primary;
|
|
@@ -3051,7 +3147,7 @@ function ExpressHandler(_a) {
|
|
|
3051
3147
|
try {
|
|
3052
3148
|
delete payload.METHOD;
|
|
3053
3149
|
}
|
|
3054
|
-
catch ( /* noop */
|
|
3150
|
+
catch ( /* noop */_j) { /* noop */ }
|
|
3055
3151
|
}
|
|
3056
3152
|
// Warn for unsupported overrides but continue normally
|
|
3057
3153
|
if (incomingMethod !== 'GET' && methodOverride && methodOverride !== 'GET') {
|
|
@@ -3061,29 +3157,56 @@ function ExpressHandler(_a) {
|
|
|
3061
3157
|
res.status(400).json({ error: "Invalid table: ".concat(table) });
|
|
3062
3158
|
return [2 /*return*/];
|
|
3063
3159
|
}
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3160
|
+
restModel = C6.TABLES[table];
|
|
3161
|
+
primaryKeys_1 = restModel.PRIMARY;
|
|
3162
|
+
primaryShortKeys_1 = (_d = restModel.PRIMARY_SHORT) !== null && _d !== void 0 ? _d : [];
|
|
3163
|
+
columnMap_1 = (_e = restModel.COLUMNS) !== null && _e !== void 0 ? _e : {};
|
|
3164
|
+
resolveShortKey_1 = function (fullKey, index) { var _a, _b, _c; return (_c = (_b = (_a = columnMap_1[fullKey]) !== null && _a !== void 0 ? _a : primaryShortKeys_1[index]) !== null && _b !== void 0 ? _b : fullKey.split('.').pop()) !== null && _c !== void 0 ? _c : fullKey; };
|
|
3165
|
+
hasPrimaryKeyValues = function (data) {
|
|
3166
|
+
if (!data || typeof data !== 'object')
|
|
3167
|
+
return false;
|
|
3168
|
+
var whereClause = data[C6C.WHERE];
|
|
3169
|
+
var hasKeyValue = function (obj, fullKey, shortKey) {
|
|
3170
|
+
if (!obj || typeof obj !== 'object')
|
|
3171
|
+
return false;
|
|
3172
|
+
var fullValue = obj[fullKey];
|
|
3173
|
+
if (fullValue !== undefined && fullValue !== null)
|
|
3174
|
+
return true;
|
|
3175
|
+
var shortValue = shortKey ? obj[shortKey] : undefined;
|
|
3176
|
+
return shortValue !== undefined && shortValue !== null;
|
|
3177
|
+
};
|
|
3178
|
+
return primaryKeys_1.every(function (fullKey, index) {
|
|
3179
|
+
var shortKey = resolveShortKey_1(fullKey, index);
|
|
3180
|
+
return hasKeyValue(whereClause, fullKey, shortKey) || hasKeyValue(data, fullKey, shortKey);
|
|
3181
|
+
});
|
|
3182
|
+
};
|
|
3183
|
+
if (primary && primaryKeys_1.length !== 1) {
|
|
3184
|
+
if (primaryKeys_1.length > 1 && hasPrimaryKeyValues(payload)) {
|
|
3185
|
+
primary = undefined;
|
|
3186
|
+
}
|
|
3187
|
+
else if (primaryKeys_1.length > 1) {
|
|
3067
3188
|
res.status(400).json({ error: "Table ".concat(table, " has multiple primary keys. Cannot implicitly determine key.") });
|
|
3068
3189
|
return [2 /*return*/];
|
|
3069
3190
|
}
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3191
|
+
else {
|
|
3192
|
+
res.status(400).json({
|
|
3193
|
+
error: "Table ".concat(table, " has no primary keys. Please specify one.")
|
|
3194
|
+
});
|
|
3195
|
+
return [2 /*return*/];
|
|
3196
|
+
}
|
|
3074
3197
|
}
|
|
3075
|
-
primaryKeyName =
|
|
3198
|
+
primaryKeyName = primaryKeys_1[0];
|
|
3076
3199
|
// If a primary key was provided in the URL, merge it into the payload.
|
|
3077
3200
|
// Support both complex requests using WHERE and singular requests
|
|
3078
3201
|
// where the primary key lives at the root of the payload.
|
|
3079
3202
|
if (primary) {
|
|
3080
3203
|
if (payload[C6C.WHERE]) {
|
|
3081
3204
|
payload[C6C.WHERE][primaryKeyName] =
|
|
3082
|
-
(
|
|
3205
|
+
(_f = payload[C6C.WHERE][primaryKeyName]) !== null && _f !== void 0 ? _f : primary;
|
|
3083
3206
|
}
|
|
3084
3207
|
else {
|
|
3085
3208
|
payload[primaryKeyName] =
|
|
3086
|
-
(
|
|
3209
|
+
(_g = payload[primaryKeyName]) !== null && _g !== void 0 ? _g : primary;
|
|
3087
3210
|
}
|
|
3088
3211
|
}
|
|
3089
3212
|
return [4 /*yield*/, restRequest({
|
|
@@ -3093,11 +3216,11 @@ function ExpressHandler(_a) {
|
|
|
3093
3216
|
restModel: C6.TABLES[table]
|
|
3094
3217
|
})(payload)];
|
|
3095
3218
|
case 1:
|
|
3096
|
-
response =
|
|
3219
|
+
response = _h.sent();
|
|
3097
3220
|
res.status(200).json(tslib.__assign({ success: true }, response));
|
|
3098
3221
|
return [3 /*break*/, 3];
|
|
3099
3222
|
case 2:
|
|
3100
|
-
err_1 =
|
|
3223
|
+
err_1 = _h.sent();
|
|
3101
3224
|
res.status(500).json({ success: false, error: err_1 });
|
|
3102
3225
|
next(err_1);
|
|
3103
3226
|
return [3 /*break*/, 3];
|
|
@@ -3182,10 +3305,11 @@ function error(message) {
|
|
|
3182
3305
|
}
|
|
3183
3306
|
|
|
3184
3307
|
function checkAllRequestsComplete() {
|
|
3185
|
-
var
|
|
3308
|
+
var cacheEntries = Array.from(apiRequestCache.values());
|
|
3309
|
+
var stillRunning = cacheEntries.filter(function (cache) { return undefined === cache.response; });
|
|
3186
3310
|
if (stillRunning.length !== 0) {
|
|
3187
3311
|
if (document === null || document === undefined) {
|
|
3188
|
-
throw new Error('document is undefined while waiting for API requests to complete (' + JSON.stringify(
|
|
3312
|
+
throw new Error('document is undefined while waiting for API requests to complete (' + JSON.stringify(cacheEntries) + ')');
|
|
3189
3313
|
}
|
|
3190
3314
|
// when requests return emtpy sets in full renders, it may not be possible to track their progress.
|
|
3191
3315
|
console.warn('stillRunning...', stillRunning);
|
|
@@ -3227,6 +3351,7 @@ exports.SelectQueryBuilder = SelectQueryBuilder;
|
|
|
3227
3351
|
exports.SqlExecutor = SqlExecutor;
|
|
3228
3352
|
exports.TestRestfulResponse = TestRestfulResponse;
|
|
3229
3353
|
exports.UpdateQueryBuilder = UpdateQueryBuilder;
|
|
3354
|
+
exports.apiRequestCache = apiRequestCache;
|
|
3230
3355
|
exports.axiosInstance = axiosInstance;
|
|
3231
3356
|
exports.bbox = bbox;
|
|
3232
3357
|
exports.carbonNodeQsStringify = carbonNodeQsStringify;
|
|
@@ -3257,10 +3382,12 @@ exports.removePrefixIfExists = removePrefixIfExists;
|
|
|
3257
3382
|
exports.resolveDerivedTable = resolveDerivedTable;
|
|
3258
3383
|
exports.restOrm = restOrm;
|
|
3259
3384
|
exports.restRequest = restRequest;
|
|
3385
|
+
exports.setCache = setCache;
|
|
3260
3386
|
exports.sortAndSerializeQueryObject = sortAndSerializeQueryObject;
|
|
3261
3387
|
exports.stContains = stContains;
|
|
3262
3388
|
exports.timeout = timeout;
|
|
3263
3389
|
exports.toastOptions = toastOptions;
|
|
3264
3390
|
exports.toastOptionsDevs = toastOptionsDevs;
|
|
3391
|
+
exports.userCustomClearCache = userCustomClearCache;
|
|
3265
3392
|
exports.warn = warn;
|
|
3266
3393
|
//# sourceMappingURL=index.cjs.js.map
|