@carbonorm/carbonnode 3.11.0 → 4.0.1
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/README.md +123 -493
- package/dist/api/orm/builders/ConditionBuilder.d.ts +5 -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 +289 -140
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +285 -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 +45 -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 +74 -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,84 @@ 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, allowColumnRefs) {
|
|
1831
|
+
var _this = this;
|
|
1832
|
+
if (allowColumnRefs === void 0) { allowColumnRefs = false; }
|
|
1833
|
+
if (!Array.isArray(value))
|
|
1834
|
+
return false;
|
|
1835
|
+
return value.every(function (item) {
|
|
1836
|
+
if (item === null)
|
|
1837
|
+
return true;
|
|
1838
|
+
var type = typeof item;
|
|
1839
|
+
if (type === 'string' || type === 'number' || type === 'boolean')
|
|
1840
|
+
return true;
|
|
1841
|
+
if (Array.isArray(item))
|
|
1842
|
+
return _this.isPlainArrayLiteral(item, allowColumnRefs);
|
|
1843
|
+
if (item && typeof item === 'object')
|
|
1844
|
+
return _this.isPlainObjectLiteral(item, allowColumnRefs);
|
|
1845
|
+
return false;
|
|
1846
|
+
});
|
|
1847
|
+
};
|
|
1848
|
+
ConditionBuilder.prototype.isPlainObjectLiteral = function (value, allowColumnRefs) {
|
|
1849
|
+
var _this = this;
|
|
1850
|
+
if (allowColumnRefs === void 0) { allowColumnRefs = false; }
|
|
1851
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
1852
|
+
return false;
|
|
1853
|
+
if (value instanceof Date)
|
|
1854
|
+
return false;
|
|
1855
|
+
if (typeof Buffer !== 'undefined' && Buffer.isBuffer && Buffer.isBuffer(value))
|
|
1856
|
+
return false;
|
|
1857
|
+
var normalized = value instanceof Map ? Object.fromEntries(value) : value;
|
|
1858
|
+
if (C6C.SUBSELECT in normalized)
|
|
1859
|
+
return false;
|
|
1860
|
+
var entries = Object.entries(normalized);
|
|
1861
|
+
if (entries.length === 0)
|
|
1862
|
+
return true;
|
|
1863
|
+
if (entries.some(function (_a) {
|
|
1864
|
+
var key = _a[0];
|
|
1865
|
+
return _this.isOperator(key) || _this.BOOLEAN_OPERATORS.has(key);
|
|
1866
|
+
})) {
|
|
1867
|
+
return false;
|
|
1868
|
+
}
|
|
1869
|
+
if (!allowColumnRefs) {
|
|
1870
|
+
if (entries.some(function (_a) {
|
|
1871
|
+
var key = _a[0];
|
|
1872
|
+
return typeof key === 'string' && (_this.isColumnRef(key) || key.includes('.'));
|
|
1873
|
+
})) {
|
|
1874
|
+
return false;
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
return true;
|
|
1878
|
+
};
|
|
1879
|
+
ConditionBuilder.prototype.resolveColumnDefinition = function (column) {
|
|
1880
|
+
var _a, _b, _c, _d;
|
|
1881
|
+
if (!column || typeof column !== 'string' || !column.includes('.'))
|
|
1882
|
+
return undefined;
|
|
1883
|
+
var _e = column.split('.', 2), prefix = _e[0], colName = _e[1];
|
|
1884
|
+
var tableName = (_a = this.aliasMap[prefix]) !== null && _a !== void 0 ? _a : prefix;
|
|
1885
|
+
var table = (_c = (_b = this.config.C6) === null || _b === void 0 ? void 0 : _b.TABLES) === null || _c === void 0 ? void 0 : _c[tableName];
|
|
1886
|
+
if (!(table === null || table === void 0 ? void 0 : table.TYPE_VALIDATION))
|
|
1887
|
+
return undefined;
|
|
1888
|
+
return (_d = table.TYPE_VALIDATION[colName]) !== null && _d !== void 0 ? _d : table.TYPE_VALIDATION["".concat(tableName, ".").concat(colName)];
|
|
1889
|
+
};
|
|
1890
|
+
ConditionBuilder.prototype.isJsonColumn = function (column) {
|
|
1891
|
+
var columnDef = this.resolveColumnDefinition(column);
|
|
1892
|
+
var mysqlType = columnDef === null || columnDef === void 0 ? void 0 : columnDef.MYSQL_TYPE;
|
|
1893
|
+
return typeof mysqlType === 'string' && mysqlType.toLowerCase().includes('json');
|
|
1894
|
+
};
|
|
1895
|
+
ConditionBuilder.prototype.serializeUpdateValue = function (value, params, contextColumn) {
|
|
1896
|
+
var normalized = value instanceof Map ? Object.fromEntries(value) : value;
|
|
1897
|
+
var allowColumnRefs = this.isJsonColumn(contextColumn);
|
|
1898
|
+
if (this.isPlainArrayLiteral(normalized, allowColumnRefs)
|
|
1899
|
+
|| this.isPlainObjectLiteral(normalized, allowColumnRefs)) {
|
|
1900
|
+
return this.addParam(params, contextColumn !== null && contextColumn !== void 0 ? contextColumn : '', JSON.stringify(normalized));
|
|
1901
|
+
}
|
|
1902
|
+
var _a = this.serializeOperand(normalized, params, contextColumn), sql = _a.sql, isReference = _a.isReference, isExpression = _a.isExpression, isSubSelect = _a.isSubSelect;
|
|
1903
|
+
if (!isReference && !isExpression && !isSubSelect && typeof normalized === 'object' && normalized !== null) {
|
|
1904
|
+
throw new Error('Unsupported operand type in SQL expression.');
|
|
1905
|
+
}
|
|
1906
|
+
return sql;
|
|
1907
|
+
};
|
|
1794
1908
|
ConditionBuilder.prototype.ensurePlainObject = function (value) {
|
|
1795
1909
|
if (value instanceof Map) {
|
|
1796
1910
|
return Object.fromEntries(value);
|
|
@@ -2647,12 +2761,14 @@ var PostQueryBuilder = /** @class */ (function (_super) {
|
|
|
2647
2761
|
var verb = C6C.REPLACE in this.request ? C6C.REPLACE : C6C.INSERT;
|
|
2648
2762
|
var body = verb in this.request ? this.request[verb] : this.request;
|
|
2649
2763
|
var keys = Object.keys(body);
|
|
2650
|
-
var params = [];
|
|
2764
|
+
var params = this.useNamedParams ? {} : [];
|
|
2651
2765
|
var placeholders = [];
|
|
2652
2766
|
for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
|
|
2653
2767
|
var key = keys_1[_i];
|
|
2654
2768
|
var value = body[key];
|
|
2655
|
-
var
|
|
2769
|
+
var trimmed = this.trimTablePrefix(table, key);
|
|
2770
|
+
var qualified = "".concat(table, ".").concat(trimmed);
|
|
2771
|
+
var placeholder = this.serializeUpdateValue(value, params, qualified);
|
|
2656
2772
|
placeholders.push(placeholder);
|
|
2657
2773
|
}
|
|
2658
2774
|
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 +2820,9 @@ var UpdateQueryBuilder = /** @class */ (function (_super) {
|
|
|
2704
2820
|
var col = _a[0], val = _a[1];
|
|
2705
2821
|
var trimmed = _this.trimTablePrefix(table, col);
|
|
2706
2822
|
var qualified = "".concat(table, ".").concat(trimmed);
|
|
2707
|
-
|
|
2823
|
+
_this.assertValidIdentifier(qualified, 'UPDATE SET');
|
|
2824
|
+
var rightSql = _this.serializeUpdateValue(val, params, qualified);
|
|
2825
|
+
return "`".concat(trimmed, "` = ").concat(rightSql);
|
|
2708
2826
|
});
|
|
2709
2827
|
sql += " SET ".concat(setClauses.join(', '));
|
|
2710
2828
|
if (args.WHERE) {
|
|
@@ -3032,12 +3150,12 @@ function ExpressHandler(_a) {
|
|
|
3032
3150
|
var _this = this;
|
|
3033
3151
|
var C6 = _a.C6, mysqlPool = _a.mysqlPool;
|
|
3034
3152
|
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 (
|
|
3153
|
+
var incomingMethod, table, primary, methodOverrideRaw, methodOverride, treatAsGet, method, payload, restModel, primaryKeys_1, primaryShortKeys_1, columnMap_1, resolveShortKey_1, hasPrimaryKeyValues, primaryKeyName, response, err_1;
|
|
3154
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
3155
|
+
return tslib.__generator(this, function (_h) {
|
|
3156
|
+
switch (_h.label) {
|
|
3039
3157
|
case 0:
|
|
3040
|
-
|
|
3158
|
+
_h.trys.push([0, 2, , 3]);
|
|
3041
3159
|
incomingMethod = req.method.toUpperCase();
|
|
3042
3160
|
table = req.params.table;
|
|
3043
3161
|
primary = req.params.primary;
|
|
@@ -3051,7 +3169,7 @@ function ExpressHandler(_a) {
|
|
|
3051
3169
|
try {
|
|
3052
3170
|
delete payload.METHOD;
|
|
3053
3171
|
}
|
|
3054
|
-
catch ( /* noop */
|
|
3172
|
+
catch ( /* noop */_j) { /* noop */ }
|
|
3055
3173
|
}
|
|
3056
3174
|
// Warn for unsupported overrides but continue normally
|
|
3057
3175
|
if (incomingMethod !== 'GET' && methodOverride && methodOverride !== 'GET') {
|
|
@@ -3061,29 +3179,56 @@ function ExpressHandler(_a) {
|
|
|
3061
3179
|
res.status(400).json({ error: "Invalid table: ".concat(table) });
|
|
3062
3180
|
return [2 /*return*/];
|
|
3063
3181
|
}
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3182
|
+
restModel = C6.TABLES[table];
|
|
3183
|
+
primaryKeys_1 = restModel.PRIMARY;
|
|
3184
|
+
primaryShortKeys_1 = (_d = restModel.PRIMARY_SHORT) !== null && _d !== void 0 ? _d : [];
|
|
3185
|
+
columnMap_1 = (_e = restModel.COLUMNS) !== null && _e !== void 0 ? _e : {};
|
|
3186
|
+
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; };
|
|
3187
|
+
hasPrimaryKeyValues = function (data) {
|
|
3188
|
+
if (!data || typeof data !== 'object')
|
|
3189
|
+
return false;
|
|
3190
|
+
var whereClause = data[C6C.WHERE];
|
|
3191
|
+
var hasKeyValue = function (obj, fullKey, shortKey) {
|
|
3192
|
+
if (!obj || typeof obj !== 'object')
|
|
3193
|
+
return false;
|
|
3194
|
+
var fullValue = obj[fullKey];
|
|
3195
|
+
if (fullValue !== undefined && fullValue !== null)
|
|
3196
|
+
return true;
|
|
3197
|
+
var shortValue = shortKey ? obj[shortKey] : undefined;
|
|
3198
|
+
return shortValue !== undefined && shortValue !== null;
|
|
3199
|
+
};
|
|
3200
|
+
return primaryKeys_1.every(function (fullKey, index) {
|
|
3201
|
+
var shortKey = resolveShortKey_1(fullKey, index);
|
|
3202
|
+
return hasKeyValue(whereClause, fullKey, shortKey) || hasKeyValue(data, fullKey, shortKey);
|
|
3203
|
+
});
|
|
3204
|
+
};
|
|
3205
|
+
if (primary && primaryKeys_1.length !== 1) {
|
|
3206
|
+
if (primaryKeys_1.length > 1 && hasPrimaryKeyValues(payload)) {
|
|
3207
|
+
primary = undefined;
|
|
3208
|
+
}
|
|
3209
|
+
else if (primaryKeys_1.length > 1) {
|
|
3067
3210
|
res.status(400).json({ error: "Table ".concat(table, " has multiple primary keys. Cannot implicitly determine key.") });
|
|
3068
3211
|
return [2 /*return*/];
|
|
3069
3212
|
}
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3213
|
+
else {
|
|
3214
|
+
res.status(400).json({
|
|
3215
|
+
error: "Table ".concat(table, " has no primary keys. Please specify one.")
|
|
3216
|
+
});
|
|
3217
|
+
return [2 /*return*/];
|
|
3218
|
+
}
|
|
3074
3219
|
}
|
|
3075
|
-
primaryKeyName =
|
|
3220
|
+
primaryKeyName = primaryKeys_1[0];
|
|
3076
3221
|
// If a primary key was provided in the URL, merge it into the payload.
|
|
3077
3222
|
// Support both complex requests using WHERE and singular requests
|
|
3078
3223
|
// where the primary key lives at the root of the payload.
|
|
3079
3224
|
if (primary) {
|
|
3080
3225
|
if (payload[C6C.WHERE]) {
|
|
3081
3226
|
payload[C6C.WHERE][primaryKeyName] =
|
|
3082
|
-
(
|
|
3227
|
+
(_f = payload[C6C.WHERE][primaryKeyName]) !== null && _f !== void 0 ? _f : primary;
|
|
3083
3228
|
}
|
|
3084
3229
|
else {
|
|
3085
3230
|
payload[primaryKeyName] =
|
|
3086
|
-
(
|
|
3231
|
+
(_g = payload[primaryKeyName]) !== null && _g !== void 0 ? _g : primary;
|
|
3087
3232
|
}
|
|
3088
3233
|
}
|
|
3089
3234
|
return [4 /*yield*/, restRequest({
|
|
@@ -3093,11 +3238,11 @@ function ExpressHandler(_a) {
|
|
|
3093
3238
|
restModel: C6.TABLES[table]
|
|
3094
3239
|
})(payload)];
|
|
3095
3240
|
case 1:
|
|
3096
|
-
response =
|
|
3241
|
+
response = _h.sent();
|
|
3097
3242
|
res.status(200).json(tslib.__assign({ success: true }, response));
|
|
3098
3243
|
return [3 /*break*/, 3];
|
|
3099
3244
|
case 2:
|
|
3100
|
-
err_1 =
|
|
3245
|
+
err_1 = _h.sent();
|
|
3101
3246
|
res.status(500).json({ success: false, error: err_1 });
|
|
3102
3247
|
next(err_1);
|
|
3103
3248
|
return [3 /*break*/, 3];
|
|
@@ -3182,10 +3327,11 @@ function error(message) {
|
|
|
3182
3327
|
}
|
|
3183
3328
|
|
|
3184
3329
|
function checkAllRequestsComplete() {
|
|
3185
|
-
var
|
|
3330
|
+
var cacheEntries = Array.from(apiRequestCache.values());
|
|
3331
|
+
var stillRunning = cacheEntries.filter(function (cache) { return undefined === cache.response; });
|
|
3186
3332
|
if (stillRunning.length !== 0) {
|
|
3187
3333
|
if (document === null || document === undefined) {
|
|
3188
|
-
throw new Error('document is undefined while waiting for API requests to complete (' + JSON.stringify(
|
|
3334
|
+
throw new Error('document is undefined while waiting for API requests to complete (' + JSON.stringify(cacheEntries) + ')');
|
|
3189
3335
|
}
|
|
3190
3336
|
// when requests return emtpy sets in full renders, it may not be possible to track their progress.
|
|
3191
3337
|
console.warn('stillRunning...', stillRunning);
|
|
@@ -3227,6 +3373,7 @@ exports.SelectQueryBuilder = SelectQueryBuilder;
|
|
|
3227
3373
|
exports.SqlExecutor = SqlExecutor;
|
|
3228
3374
|
exports.TestRestfulResponse = TestRestfulResponse;
|
|
3229
3375
|
exports.UpdateQueryBuilder = UpdateQueryBuilder;
|
|
3376
|
+
exports.apiRequestCache = apiRequestCache;
|
|
3230
3377
|
exports.axiosInstance = axiosInstance;
|
|
3231
3378
|
exports.bbox = bbox;
|
|
3232
3379
|
exports.carbonNodeQsStringify = carbonNodeQsStringify;
|
|
@@ -3257,10 +3404,12 @@ exports.removePrefixIfExists = removePrefixIfExists;
|
|
|
3257
3404
|
exports.resolveDerivedTable = resolveDerivedTable;
|
|
3258
3405
|
exports.restOrm = restOrm;
|
|
3259
3406
|
exports.restRequest = restRequest;
|
|
3407
|
+
exports.setCache = setCache;
|
|
3260
3408
|
exports.sortAndSerializeQueryObject = sortAndSerializeQueryObject;
|
|
3261
3409
|
exports.stContains = stContains;
|
|
3262
3410
|
exports.timeout = timeout;
|
|
3263
3411
|
exports.toastOptions = toastOptions;
|
|
3264
3412
|
exports.toastOptionsDevs = toastOptionsDevs;
|
|
3413
|
+
exports.userCustomClearCache = userCustomClearCache;
|
|
3265
3414
|
exports.warn = warn;
|
|
3266
3415
|
//# sourceMappingURL=index.cjs.js.map
|