@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.esm.js
CHANGED
|
@@ -304,8 +304,30 @@ axiosInstance.interceptors.request.use(function (config) {
|
|
|
304
304
|
};
|
|
305
305
|
}
|
|
306
306
|
}
|
|
307
|
+
config.__carbonStart = performance.now();
|
|
307
308
|
return config;
|
|
308
309
|
});
|
|
310
|
+
axiosInstance.interceptors.response.use(function (response) {
|
|
311
|
+
var end = performance.now();
|
|
312
|
+
var start = response.config.__carbonStart;
|
|
313
|
+
response.__carbonTiming = {
|
|
314
|
+
start: start,
|
|
315
|
+
end: end,
|
|
316
|
+
duration: end - start,
|
|
317
|
+
};
|
|
318
|
+
return response;
|
|
319
|
+
}, function (error) {
|
|
320
|
+
if (error.config) {
|
|
321
|
+
var end = performance.now();
|
|
322
|
+
var start = error.config.__carbonStart;
|
|
323
|
+
error.__carbonTiming = {
|
|
324
|
+
start: start,
|
|
325
|
+
end: end,
|
|
326
|
+
duration: end - start,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
throw error;
|
|
330
|
+
});
|
|
309
331
|
|
|
310
332
|
function convertForRequestBody (restfulObject, tableName, C6, regexErrorHandler) {
|
|
311
333
|
if (regexErrorHandler === void 0) { regexErrorHandler = alert; }
|
|
@@ -407,10 +429,7 @@ function convertForRequestBody (restfulObject, tableName, C6, regexErrorHandler)
|
|
|
407
429
|
|
|
408
430
|
var isNode = function () {
|
|
409
431
|
var _a;
|
|
410
|
-
|
|
411
|
-
var isNodeEnv = typeof process !== 'undefined' && !!((_a = process.versions) === null || _a === void 0 ? void 0 : _a.node);
|
|
412
|
-
console.log("Is Node.js environment: ".concat(isNodeEnv));
|
|
413
|
-
return isNodeEnv;
|
|
432
|
+
return typeof process !== 'undefined' && !!((_a = process.versions) === null || _a === void 0 ? void 0 : _a.node);
|
|
414
433
|
};
|
|
415
434
|
|
|
416
435
|
/**
|
|
@@ -628,26 +647,64 @@ function removeInvalidKeys(request, c6Tables) {
|
|
|
628
647
|
return intersection;
|
|
629
648
|
}
|
|
630
649
|
|
|
631
|
-
//
|
|
632
|
-
//
|
|
633
|
-
|
|
650
|
+
// -----------------------------------------------------------------------------
|
|
651
|
+
// Cache Storage
|
|
652
|
+
// -----------------------------------------------------------------------------
|
|
653
|
+
var apiRequestCache = new Map();
|
|
634
654
|
var userCustomClearCache = [];
|
|
655
|
+
// -----------------------------------------------------------------------------
|
|
656
|
+
// Cache Key Generator (safe, fixed-size ~40 chars)
|
|
657
|
+
// -----------------------------------------------------------------------------
|
|
658
|
+
// -----------------------------------------------------------------------------
|
|
659
|
+
// Browser-safe deterministic hash (FNV-1a)
|
|
660
|
+
// -----------------------------------------------------------------------------
|
|
661
|
+
function fnv1a(str) {
|
|
662
|
+
var h = 0x811c9dc5;
|
|
663
|
+
for (var i = 0; i < str.length; i++) {
|
|
664
|
+
h ^= str.charCodeAt(i);
|
|
665
|
+
h = (h * 0x01000193) >>> 0;
|
|
666
|
+
}
|
|
667
|
+
return h.toString(16);
|
|
668
|
+
}
|
|
669
|
+
function makeCacheKey(method, tableName, requestData) {
|
|
670
|
+
var raw = JSON.stringify([method, tableName, requestData]);
|
|
671
|
+
return fnv1a(raw);
|
|
672
|
+
}
|
|
673
|
+
// -----------------------------------------------------------------------------
|
|
674
|
+
// Clear Cache (no shared-array bugs)
|
|
675
|
+
// -----------------------------------------------------------------------------
|
|
635
676
|
function clearCache(props) {
|
|
636
|
-
if (
|
|
637
|
-
console.warn(
|
|
677
|
+
if (!(props === null || props === void 0 ? void 0 : props.ignoreWarning)) {
|
|
678
|
+
console.warn("The REST API clearCache should only be used with extreme care!");
|
|
679
|
+
}
|
|
680
|
+
for (var _i = 0, userCustomClearCache_1 = userCustomClearCache; _i < userCustomClearCache_1.length; _i++) {
|
|
681
|
+
var fn = userCustomClearCache_1[_i];
|
|
682
|
+
try {
|
|
683
|
+
fn();
|
|
684
|
+
}
|
|
685
|
+
catch (_a) { }
|
|
638
686
|
}
|
|
639
|
-
|
|
640
|
-
userCustomClearCache = apiRequestCache = [];
|
|
687
|
+
apiRequestCache.clear();
|
|
641
688
|
}
|
|
642
|
-
|
|
643
|
-
|
|
689
|
+
// -----------------------------------------------------------------------------
|
|
690
|
+
// Check Cache (dedupe via hashed key)
|
|
691
|
+
// -----------------------------------------------------------------------------
|
|
692
|
+
function checkCache(method, tableName, requestData) {
|
|
693
|
+
var key = makeCacheKey(method, tableName, requestData);
|
|
694
|
+
var cached = apiRequestCache.get(key);
|
|
695
|
+
if (!cached)
|
|
644
696
|
return false;
|
|
645
|
-
|
|
646
|
-
console.
|
|
647
|
-
console.log('%c ' + requestMethod + ' ' + tableName, 'color: #0c0');
|
|
648
|
-
console.log('%c Request Data (note you may see the success and/or error prompt):', 'color: #0c0', request);
|
|
697
|
+
console.groupCollapsed("%c API cache hit for ".concat(method, " ").concat(tableName), "color:#0c0");
|
|
698
|
+
console.log("Request Data:", requestData);
|
|
649
699
|
console.groupEnd();
|
|
650
|
-
return
|
|
700
|
+
return cached.request;
|
|
701
|
+
}
|
|
702
|
+
// -----------------------------------------------------------------------------
|
|
703
|
+
// Store Cache Entry (drop-in compatible)
|
|
704
|
+
// -----------------------------------------------------------------------------
|
|
705
|
+
function setCache(method, tableName, requestData, cacheEntry) {
|
|
706
|
+
var key = makeCacheKey(method, tableName, requestData);
|
|
707
|
+
apiRequestCache.set(key, cacheEntry);
|
|
651
708
|
}
|
|
652
709
|
|
|
653
710
|
function sortAndSerializeQueryObject(tables, query) {
|
|
@@ -664,7 +721,10 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
664
721
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
665
722
|
}
|
|
666
723
|
HttpExecutor.prototype.isRestResponse = function (r) {
|
|
667
|
-
return !!r
|
|
724
|
+
return !!r
|
|
725
|
+
&& r.data != null
|
|
726
|
+
&& typeof r.data === 'object'
|
|
727
|
+
&& Array.isArray(r.data.rest);
|
|
668
728
|
};
|
|
669
729
|
HttpExecutor.prototype.stripTableNameFromKeys = function (obj) {
|
|
670
730
|
var _a;
|
|
@@ -767,19 +827,9 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
767
827
|
console.log('request', this.request);
|
|
768
828
|
console.groupEnd();
|
|
769
829
|
}
|
|
770
|
-
// an undefined query would indicate queryCallback returned undefined,
|
|
771
|
-
// thus the request shouldn't fire as is in custom cache
|
|
772
|
-
if (undefined === this.request || null === this.request) {
|
|
773
|
-
if (isLocal()) {
|
|
774
|
-
console.groupCollapsed("API: (".concat(requestMethod, ") (").concat(tableName, ") query undefined/null \u2192 returning null"));
|
|
775
|
-
console.log('request', this.request);
|
|
776
|
-
console.groupEnd();
|
|
777
|
-
}
|
|
778
|
-
return [2 /*return*/, null];
|
|
779
|
-
}
|
|
780
830
|
query = this.request;
|
|
781
831
|
apiRequest = function () { return __awaiter(_this, void 0, void 0, function () {
|
|
782
|
-
var _a, debug, _b, cacheResults, dataInsertMultipleRows, success, _c, fetchDependencies, _d, error,
|
|
832
|
+
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;
|
|
783
833
|
var _e;
|
|
784
834
|
var _this = this;
|
|
785
835
|
var _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
@@ -795,63 +845,37 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
795
845
|
console.log('request', this.request);
|
|
796
846
|
console.groupEnd();
|
|
797
847
|
}
|
|
798
|
-
querySerialized = sortAndSerializeQueryObject(tables, query !== null && query !== void 0 ? query : {});
|
|
799
|
-
cacheResult = apiRequestCache.find(function (cache) { return cache.requestArgumentsSerialized === querySerialized; });
|
|
800
848
|
cachingConfirmed = false;
|
|
801
|
-
|
|
802
|
-
if (
|
|
803
|
-
if (undefined === query
|
|
804
|
-
query
|
|
849
|
+
// determine if we need to paginate.
|
|
850
|
+
if (requestMethod === C6.GET) {
|
|
851
|
+
if (undefined === (query === null || query === void 0 ? void 0 : query[C6.PAGINATION])) {
|
|
852
|
+
if (undefined === query || null === query) {
|
|
853
|
+
query = {};
|
|
854
|
+
}
|
|
855
|
+
query[C6.PAGINATION] = {};
|
|
805
856
|
}
|
|
806
|
-
query[C6.PAGINATION] =
|
|
857
|
+
query[C6.PAGINATION][C6.PAGE] = query[C6.PAGINATION][C6.PAGE] || 1;
|
|
858
|
+
query[C6.PAGINATION][C6.LIMIT] = query[C6.PAGINATION][C6.LIMIT] || 100;
|
|
859
|
+
}
|
|
860
|
+
cacheRequestData = JSON.parse(JSON.stringify(query !== null && query !== void 0 ? query : {}));
|
|
861
|
+
querySerialized = sortAndSerializeQueryObject(tables, cacheRequestData !== null && cacheRequestData !== void 0 ? cacheRequestData : {});
|
|
862
|
+
cachedRequest = false;
|
|
863
|
+
if (cacheResults) {
|
|
864
|
+
cachedRequest = checkCache(requestMethod, tableName, cacheRequestData);
|
|
807
865
|
}
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
cacheCheck = checkCache(cacheResult, requestMethod, tableName, this.request);
|
|
815
|
-
if (!(false !== cacheCheck)) return [3 /*break*/, 3];
|
|
816
|
-
return [4 /*yield*/, cacheCheck];
|
|
817
|
-
case 2: return [2 /*return*/, (_r.sent()).data];
|
|
818
|
-
case 3:
|
|
819
|
-
++query[C6.PAGINATION][C6.PAGE];
|
|
820
|
-
querySerialized = sortAndSerializeQueryObject(tables, query !== null && query !== void 0 ? query : {});
|
|
821
|
-
cacheResult = apiRequestCache.find(function (cache) { return cache.requestArgumentsSerialized === querySerialized; });
|
|
822
|
-
_r.label = 4;
|
|
823
|
-
case 4:
|
|
824
|
-
if (undefined !== cacheResult) return [3 /*break*/, 1];
|
|
825
|
-
_r.label = 5;
|
|
826
|
-
case 5:
|
|
827
|
-
if (debug && isLocal()) {
|
|
828
|
-
toast.warning("DEVS: Request pages exhausted in cache; firing network.", toastOptionsDevs);
|
|
866
|
+
if (!cachedRequest) return [3 /*break*/, 2];
|
|
867
|
+
return [4 /*yield*/, cachedRequest];
|
|
868
|
+
case 1: return [2 /*return*/, (_r.sent()).data];
|
|
869
|
+
case 2:
|
|
870
|
+
if (cacheResults) {
|
|
871
|
+
cachingConfirmed = true;
|
|
829
872
|
}
|
|
830
|
-
|
|
831
|
-
case 6:
|
|
832
|
-
cachingConfirmed = true;
|
|
833
|
-
return [3 /*break*/, 8];
|
|
834
|
-
case 7:
|
|
835
|
-
if (debug && isLocal())
|
|
873
|
+
else if (debug && isLocal()) {
|
|
836
874
|
toast.info("DEVS: Ignore cache was set to true.", toastOptionsDevs);
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
if (debug && isLocal()) {
|
|
875
|
+
}
|
|
876
|
+
if (cacheResults && debug && isLocal()) {
|
|
840
877
|
toast.success("DEVS: Request not in cache." + (requestMethod === C6.GET ? " Page (" + query[C6.PAGINATION][C6.PAGE] + ")" : ''), toastOptionsDevs);
|
|
841
878
|
}
|
|
842
|
-
return [3 /*break*/, 12];
|
|
843
|
-
case 9:
|
|
844
|
-
if (!cacheResults) return [3 /*break*/, 12];
|
|
845
|
-
if (!cacheResult) return [3 /*break*/, 11];
|
|
846
|
-
cacheCheck = checkCache(cacheResult, requestMethod, tableName, this.request);
|
|
847
|
-
if (!(false !== cacheCheck)) return [3 /*break*/, 11];
|
|
848
|
-
return [4 /*yield*/, cacheCheck];
|
|
849
|
-
case 10: return [2 /*return*/, (_r.sent()).data];
|
|
850
|
-
case 11:
|
|
851
|
-
cachingConfirmed = true;
|
|
852
|
-
_r.label = 12;
|
|
853
|
-
case 12:
|
|
854
|
-
returnGetNextPageFunction = false;
|
|
855
879
|
restRequestUri = restURL + operatingTable + '/';
|
|
856
880
|
needsConditionOrPrimaryCheck = (PUT === requestMethod || DELETE === requestMethod)
|
|
857
881
|
&& false === skipPrimaryCheck;
|
|
@@ -921,7 +945,7 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
921
945
|
config: this.config,
|
|
922
946
|
request: this.request
|
|
923
947
|
});
|
|
924
|
-
|
|
948
|
+
axiosActiveRequest_1 = (_e = axios)[requestMethod.toLowerCase()].apply(_e, __spreadArray([restRequestUri], (function () {
|
|
925
949
|
var convert = function (data) {
|
|
926
950
|
return convertForRequestBody(data, fullTableList, C6, function (message) { return toast.error(message, toastOptions); });
|
|
927
951
|
};
|
|
@@ -948,23 +972,30 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
948
972
|
}
|
|
949
973
|
})(), false));
|
|
950
974
|
if (cachingConfirmed) {
|
|
951
|
-
|
|
952
|
-
apiRequestCache.push({
|
|
975
|
+
setCache(requestMethod, tableName, cacheRequestData, {
|
|
953
976
|
requestArgumentsSerialized: querySerialized,
|
|
954
|
-
request:
|
|
977
|
+
request: axiosActiveRequest_1,
|
|
955
978
|
});
|
|
956
979
|
}
|
|
957
980
|
// returning the promise with this then is important for tests. todo - we could make that optional.
|
|
958
981
|
// https://rapidapi.com/guides/axios-async-await
|
|
959
|
-
return [2 /*return*/,
|
|
960
|
-
var
|
|
982
|
+
return [2 /*return*/, axiosActiveRequest_1.then(function (response) { return __awaiter(_this, void 0, void 0, function () {
|
|
983
|
+
var hasNext, callback, responseData_1, pageLimit, got, dependencies_1, fetchReferences_1, apiRequestPromises, _loop_1, tableToFetch;
|
|
961
984
|
var _this = this;
|
|
962
|
-
var _a, _b, _c, _d;
|
|
963
|
-
return __generator(this, function (
|
|
964
|
-
switch (
|
|
985
|
+
var _a, _b, _c, _d, _e;
|
|
986
|
+
return __generator(this, function (_f) {
|
|
987
|
+
switch (_f.label) {
|
|
965
988
|
case 0:
|
|
966
989
|
// noinspection SuspiciousTypeOfGuard
|
|
967
990
|
if (typeof response.data === 'string') {
|
|
991
|
+
if (cachingConfirmed) {
|
|
992
|
+
setCache(requestMethod, tableName, cacheRequestData, {
|
|
993
|
+
requestArgumentsSerialized: querySerialized,
|
|
994
|
+
request: axiosActiveRequest_1,
|
|
995
|
+
response: response,
|
|
996
|
+
final: true,
|
|
997
|
+
});
|
|
998
|
+
}
|
|
968
999
|
if (isTest()) {
|
|
969
1000
|
console.trace();
|
|
970
1001
|
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 + ')');
|
|
@@ -972,11 +1003,11 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
972
1003
|
return [2 /*return*/, Promise.reject(response)];
|
|
973
1004
|
}
|
|
974
1005
|
if (cachingConfirmed) {
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
1006
|
+
setCache(requestMethod, tableName, cacheRequestData, {
|
|
1007
|
+
requestArgumentsSerialized: querySerialized,
|
|
1008
|
+
request: axiosActiveRequest_1,
|
|
1009
|
+
response: response,
|
|
1010
|
+
});
|
|
980
1011
|
}
|
|
981
1012
|
this.runLifecycleHooks("afterExecution", {
|
|
982
1013
|
config: this.config,
|
|
@@ -1027,17 +1058,18 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
1027
1058
|
got = responseData_1.rest.length;
|
|
1028
1059
|
hasNext = pageLimit !== 1 && got === pageLimit;
|
|
1029
1060
|
if (hasNext) {
|
|
1030
|
-
responseData_1.next = apiRequest;
|
|
1061
|
+
responseData_1.next = apiRequest;
|
|
1031
1062
|
}
|
|
1032
1063
|
else {
|
|
1033
1064
|
responseData_1.next = undefined; // short page => done
|
|
1034
1065
|
}
|
|
1035
|
-
// If you keep this flag, make it reflect reality:
|
|
1036
|
-
returnGetNextPageFunction = hasNext;
|
|
1037
|
-
// and fix cache ‘final’ flag to match:
|
|
1038
1066
|
if (cachingConfirmed) {
|
|
1039
|
-
|
|
1040
|
-
|
|
1067
|
+
setCache(requestMethod, tableName, cacheRequestData, {
|
|
1068
|
+
requestArgumentsSerialized: querySerialized,
|
|
1069
|
+
request: axiosActiveRequest_1,
|
|
1070
|
+
response: response,
|
|
1071
|
+
final: !hasNext,
|
|
1072
|
+
});
|
|
1041
1073
|
}
|
|
1042
1074
|
if ((this.config.verbose || debug) && isLocal()) {
|
|
1043
1075
|
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], ")"));
|
|
@@ -1047,7 +1079,7 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
1047
1079
|
}
|
|
1048
1080
|
if (!(fetchDependencies
|
|
1049
1081
|
&& 'number' === typeof fetchDependencies
|
|
1050
|
-
&& responseData_1.rest.length > 0)) return [3 /*break*/, 2];
|
|
1082
|
+
&& ((_d = responseData_1.rest) === null || _d === void 0 ? void 0 : _d.length) > 0)) return [3 /*break*/, 2];
|
|
1051
1083
|
console.groupCollapsed('%c API: Fetch Dependencies segment (' + requestMethod + ' ' + tableName + ')'
|
|
1052
1084
|
+ (fetchDependencies & eFetchDependencies.CHILDREN ? ' | (CHILDREN|REFERENCED) ' : '')
|
|
1053
1085
|
+ (fetchDependencies & eFetchDependencies.PARENTS ? ' | (PARENTS|REFERENCED_BY)' : '')
|
|
@@ -1118,7 +1150,7 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
1118
1150
|
}); });
|
|
1119
1151
|
console.log('fetchReferences', fetchReferences_1);
|
|
1120
1152
|
_loop_1 = function (tableToFetch) {
|
|
1121
|
-
var
|
|
1153
|
+
var _g;
|
|
1122
1154
|
if (fetchDependencies & eFetchDependencies.C6ENTITY
|
|
1123
1155
|
&& 'string' === typeof tableName
|
|
1124
1156
|
&& tableName.endsWith("carbon_carbons")) {
|
|
@@ -1141,7 +1173,7 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
1141
1173
|
.split('_')
|
|
1142
1174
|
.map(function (part) { return part.charAt(0).toUpperCase() + part.slice(1); })
|
|
1143
1175
|
.join('_');
|
|
1144
|
-
var RestApi = (
|
|
1176
|
+
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(', '), " ]"));
|
|
1145
1177
|
console.log('%c Fetch Dependencies will select (' + tableToFetch + ') using GET request', 'color: #33ccff');
|
|
1146
1178
|
var nextFetchDependencies = eFetchDependencies.NONE;
|
|
1147
1179
|
if (fetchDependencies & eFetchDependencies.RECURSIVE) {
|
|
@@ -1167,8 +1199,8 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
1167
1199
|
console.log('RestApi object', RestApi);
|
|
1168
1200
|
// this is a dynamic call to the rest api, any generated table may resolve with (RestApi)
|
|
1169
1201
|
// todo - using value to avoid joins.... but. maybe this should be a parameterizable option -- think race conditions; its safer to join
|
|
1170
|
-
apiRequestPromises.push(RestApi.Get((
|
|
1171
|
-
|
|
1202
|
+
apiRequestPromises.push(RestApi.Get((_g = {},
|
|
1203
|
+
_g[C6.WHERE] = Object.keys(fetchReferences_1[tableToFetch]).reduce(function (sum, column) {
|
|
1172
1204
|
fetchReferences_1[tableToFetch][column] = fetchReferences_1[tableToFetch][column].flat(Infinity);
|
|
1173
1205
|
if (0 === fetchReferences_1[tableToFetch][column].length) {
|
|
1174
1206
|
console.warn('The column (' + column + ') was not found in the response data. We will not fetch.', responseData_1);
|
|
@@ -1181,8 +1213,8 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
1181
1213
|
];
|
|
1182
1214
|
return sum;
|
|
1183
1215
|
}, {}),
|
|
1184
|
-
|
|
1185
|
-
|
|
1216
|
+
_g.fetchDependencies = nextFetchDependencies,
|
|
1217
|
+
_g)));
|
|
1186
1218
|
};
|
|
1187
1219
|
for (tableToFetch in fetchReferences_1) {
|
|
1188
1220
|
_loop_1(tableToFetch);
|
|
@@ -1190,7 +1222,7 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
1190
1222
|
console.groupEnd();
|
|
1191
1223
|
return [4 /*yield*/, Promise.all(apiRequestPromises)];
|
|
1192
1224
|
case 1:
|
|
1193
|
-
|
|
1225
|
+
_f.sent();
|
|
1194
1226
|
apiRequestPromises.map(function (promise) { return __awaiter(_this, void 0, void 0, function () {
|
|
1195
1227
|
var _a, _b;
|
|
1196
1228
|
return __generator(this, function (_c) {
|
|
@@ -1208,8 +1240,16 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
1208
1240
|
}
|
|
1209
1241
|
});
|
|
1210
1242
|
}); });
|
|
1211
|
-
|
|
1243
|
+
_f.label = 2;
|
|
1212
1244
|
case 2:
|
|
1245
|
+
if (cachingConfirmed && hasNext === undefined) {
|
|
1246
|
+
setCache(requestMethod, tableName, cacheRequestData, {
|
|
1247
|
+
requestArgumentsSerialized: querySerialized,
|
|
1248
|
+
request: axiosActiveRequest_1,
|
|
1249
|
+
response: response,
|
|
1250
|
+
final: true,
|
|
1251
|
+
});
|
|
1252
|
+
}
|
|
1213
1253
|
if (debug && isLocal()) {
|
|
1214
1254
|
toast.success("DEVS: (" + requestMethod + ") request complete.", toastOptionsDevs);
|
|
1215
1255
|
}
|
|
@@ -1220,16 +1260,12 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
1220
1260
|
}); }).then(function (response) { return response.data; })]; // this escapes from axios context
|
|
1221
1261
|
}
|
|
1222
1262
|
catch (throwableError) {
|
|
1223
|
-
if (isTest()) {
|
|
1224
|
-
throw new Error(JSON.stringify(throwableError));
|
|
1225
|
-
}
|
|
1226
1263
|
console.groupCollapsed('%c API: An error occurred in the try catch block. returning null!', 'color: #ff0000');
|
|
1227
1264
|
console.log('%c ' + requestMethod + ' ' + tableName, 'color: #A020F0');
|
|
1228
|
-
console.
|
|
1265
|
+
console.error(throwableError);
|
|
1229
1266
|
console.trace();
|
|
1230
1267
|
console.groupEnd();
|
|
1231
|
-
|
|
1232
|
-
return [2 /*return*/, null];
|
|
1268
|
+
throw new Error(JSON.stringify(throwableError));
|
|
1233
1269
|
}
|
|
1234
1270
|
return [2 /*return*/];
|
|
1235
1271
|
}
|
|
@@ -1788,6 +1824,62 @@ var ConditionBuilder = /** @class */ (function (_super) {
|
|
|
1788
1824
|
}
|
|
1789
1825
|
throw new Error('Unsupported operand type in SQL expression.');
|
|
1790
1826
|
};
|
|
1827
|
+
ConditionBuilder.prototype.isPlainArrayLiteral = function (value) {
|
|
1828
|
+
var _this = this;
|
|
1829
|
+
if (!Array.isArray(value))
|
|
1830
|
+
return false;
|
|
1831
|
+
return value.every(function (item) {
|
|
1832
|
+
if (item === null)
|
|
1833
|
+
return true;
|
|
1834
|
+
var type = typeof item;
|
|
1835
|
+
if (type === 'string' || type === 'number' || type === 'boolean')
|
|
1836
|
+
return true;
|
|
1837
|
+
if (Array.isArray(item))
|
|
1838
|
+
return _this.isPlainArrayLiteral(item);
|
|
1839
|
+
if (item && typeof item === 'object')
|
|
1840
|
+
return _this.isPlainObjectLiteral(item);
|
|
1841
|
+
return false;
|
|
1842
|
+
});
|
|
1843
|
+
};
|
|
1844
|
+
ConditionBuilder.prototype.isPlainObjectLiteral = function (value) {
|
|
1845
|
+
var _this = this;
|
|
1846
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
1847
|
+
return false;
|
|
1848
|
+
if (value instanceof Date)
|
|
1849
|
+
return false;
|
|
1850
|
+
if (typeof Buffer !== 'undefined' && Buffer.isBuffer && Buffer.isBuffer(value))
|
|
1851
|
+
return false;
|
|
1852
|
+
var normalized = value instanceof Map ? Object.fromEntries(value) : value;
|
|
1853
|
+
if (C6C.SUBSELECT in normalized)
|
|
1854
|
+
return false;
|
|
1855
|
+
var entries = Object.entries(normalized);
|
|
1856
|
+
if (entries.length === 0)
|
|
1857
|
+
return true;
|
|
1858
|
+
if (entries.some(function (_a) {
|
|
1859
|
+
var key = _a[0];
|
|
1860
|
+
return _this.isOperator(key) || _this.BOOLEAN_OPERATORS.has(key);
|
|
1861
|
+
})) {
|
|
1862
|
+
return false;
|
|
1863
|
+
}
|
|
1864
|
+
if (entries.some(function (_a) {
|
|
1865
|
+
var key = _a[0];
|
|
1866
|
+
return typeof key === 'string' && (_this.isColumnRef(key) || key.includes('.'));
|
|
1867
|
+
})) {
|
|
1868
|
+
return false;
|
|
1869
|
+
}
|
|
1870
|
+
return true;
|
|
1871
|
+
};
|
|
1872
|
+
ConditionBuilder.prototype.serializeUpdateValue = function (value, params, contextColumn) {
|
|
1873
|
+
var normalized = value instanceof Map ? Object.fromEntries(value) : value;
|
|
1874
|
+
if (this.isPlainArrayLiteral(normalized) || this.isPlainObjectLiteral(normalized)) {
|
|
1875
|
+
return this.addParam(params, contextColumn !== null && contextColumn !== void 0 ? contextColumn : '', JSON.stringify(normalized));
|
|
1876
|
+
}
|
|
1877
|
+
var _a = this.serializeOperand(normalized, params, contextColumn), sql = _a.sql, isReference = _a.isReference, isExpression = _a.isExpression, isSubSelect = _a.isSubSelect;
|
|
1878
|
+
if (!isReference && !isExpression && !isSubSelect && typeof normalized === 'object' && normalized !== null) {
|
|
1879
|
+
throw new Error('Unsupported operand type in SQL expression.');
|
|
1880
|
+
}
|
|
1881
|
+
return sql;
|
|
1882
|
+
};
|
|
1791
1883
|
ConditionBuilder.prototype.ensurePlainObject = function (value) {
|
|
1792
1884
|
if (value instanceof Map) {
|
|
1793
1885
|
return Object.fromEntries(value);
|
|
@@ -2644,12 +2736,14 @@ var PostQueryBuilder = /** @class */ (function (_super) {
|
|
|
2644
2736
|
var verb = C6C.REPLACE in this.request ? C6C.REPLACE : C6C.INSERT;
|
|
2645
2737
|
var body = verb in this.request ? this.request[verb] : this.request;
|
|
2646
2738
|
var keys = Object.keys(body);
|
|
2647
|
-
var params = [];
|
|
2739
|
+
var params = this.useNamedParams ? {} : [];
|
|
2648
2740
|
var placeholders = [];
|
|
2649
2741
|
for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
|
|
2650
2742
|
var key = keys_1[_i];
|
|
2651
2743
|
var value = body[key];
|
|
2652
|
-
var
|
|
2744
|
+
var trimmed = this.trimTablePrefix(table, key);
|
|
2745
|
+
var qualified = "".concat(table, ".").concat(trimmed);
|
|
2746
|
+
var placeholder = this.serializeUpdateValue(value, params, qualified);
|
|
2653
2747
|
placeholders.push(placeholder);
|
|
2654
2748
|
}
|
|
2655
2749
|
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 )");
|
|
@@ -2701,7 +2795,9 @@ var UpdateQueryBuilder = /** @class */ (function (_super) {
|
|
|
2701
2795
|
var col = _a[0], val = _a[1];
|
|
2702
2796
|
var trimmed = _this.trimTablePrefix(table, col);
|
|
2703
2797
|
var qualified = "".concat(table, ".").concat(trimmed);
|
|
2704
|
-
|
|
2798
|
+
_this.assertValidIdentifier(qualified, 'UPDATE SET');
|
|
2799
|
+
var rightSql = _this.serializeUpdateValue(val, params, qualified);
|
|
2800
|
+
return "`".concat(trimmed, "` = ").concat(rightSql);
|
|
2705
2801
|
});
|
|
2706
2802
|
sql += " SET ".concat(setClauses.join(', '));
|
|
2707
2803
|
if (args.WHERE) {
|
|
@@ -3029,12 +3125,12 @@ function ExpressHandler(_a) {
|
|
|
3029
3125
|
var _this = this;
|
|
3030
3126
|
var C6 = _a.C6, mysqlPool = _a.mysqlPool;
|
|
3031
3127
|
return function (req, res, next) { return __awaiter(_this, void 0, void 0, function () {
|
|
3032
|
-
var incomingMethod, table, primary, methodOverrideRaw, methodOverride, treatAsGet, method, payload,
|
|
3033
|
-
var _a, _b, _c, _d, _e;
|
|
3034
|
-
return __generator(this, function (
|
|
3035
|
-
switch (
|
|
3128
|
+
var incomingMethod, table, primary, methodOverrideRaw, methodOverride, treatAsGet, method, payload, restModel, primaryKeys_1, primaryShortKeys_1, columnMap_1, resolveShortKey_1, hasPrimaryKeyValues, primaryKeyName, response, err_1;
|
|
3129
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
3130
|
+
return __generator(this, function (_h) {
|
|
3131
|
+
switch (_h.label) {
|
|
3036
3132
|
case 0:
|
|
3037
|
-
|
|
3133
|
+
_h.trys.push([0, 2, , 3]);
|
|
3038
3134
|
incomingMethod = req.method.toUpperCase();
|
|
3039
3135
|
table = req.params.table;
|
|
3040
3136
|
primary = req.params.primary;
|
|
@@ -3048,7 +3144,7 @@ function ExpressHandler(_a) {
|
|
|
3048
3144
|
try {
|
|
3049
3145
|
delete payload.METHOD;
|
|
3050
3146
|
}
|
|
3051
|
-
catch ( /* noop */
|
|
3147
|
+
catch ( /* noop */_j) { /* noop */ }
|
|
3052
3148
|
}
|
|
3053
3149
|
// Warn for unsupported overrides but continue normally
|
|
3054
3150
|
if (incomingMethod !== 'GET' && methodOverride && methodOverride !== 'GET') {
|
|
@@ -3058,29 +3154,56 @@ function ExpressHandler(_a) {
|
|
|
3058
3154
|
res.status(400).json({ error: "Invalid table: ".concat(table) });
|
|
3059
3155
|
return [2 /*return*/];
|
|
3060
3156
|
}
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3157
|
+
restModel = C6.TABLES[table];
|
|
3158
|
+
primaryKeys_1 = restModel.PRIMARY;
|
|
3159
|
+
primaryShortKeys_1 = (_d = restModel.PRIMARY_SHORT) !== null && _d !== void 0 ? _d : [];
|
|
3160
|
+
columnMap_1 = (_e = restModel.COLUMNS) !== null && _e !== void 0 ? _e : {};
|
|
3161
|
+
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; };
|
|
3162
|
+
hasPrimaryKeyValues = function (data) {
|
|
3163
|
+
if (!data || typeof data !== 'object')
|
|
3164
|
+
return false;
|
|
3165
|
+
var whereClause = data[C6C.WHERE];
|
|
3166
|
+
var hasKeyValue = function (obj, fullKey, shortKey) {
|
|
3167
|
+
if (!obj || typeof obj !== 'object')
|
|
3168
|
+
return false;
|
|
3169
|
+
var fullValue = obj[fullKey];
|
|
3170
|
+
if (fullValue !== undefined && fullValue !== null)
|
|
3171
|
+
return true;
|
|
3172
|
+
var shortValue = shortKey ? obj[shortKey] : undefined;
|
|
3173
|
+
return shortValue !== undefined && shortValue !== null;
|
|
3174
|
+
};
|
|
3175
|
+
return primaryKeys_1.every(function (fullKey, index) {
|
|
3176
|
+
var shortKey = resolveShortKey_1(fullKey, index);
|
|
3177
|
+
return hasKeyValue(whereClause, fullKey, shortKey) || hasKeyValue(data, fullKey, shortKey);
|
|
3178
|
+
});
|
|
3179
|
+
};
|
|
3180
|
+
if (primary && primaryKeys_1.length !== 1) {
|
|
3181
|
+
if (primaryKeys_1.length > 1 && hasPrimaryKeyValues(payload)) {
|
|
3182
|
+
primary = undefined;
|
|
3183
|
+
}
|
|
3184
|
+
else if (primaryKeys_1.length > 1) {
|
|
3064
3185
|
res.status(400).json({ error: "Table ".concat(table, " has multiple primary keys. Cannot implicitly determine key.") });
|
|
3065
3186
|
return [2 /*return*/];
|
|
3066
3187
|
}
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3188
|
+
else {
|
|
3189
|
+
res.status(400).json({
|
|
3190
|
+
error: "Table ".concat(table, " has no primary keys. Please specify one.")
|
|
3191
|
+
});
|
|
3192
|
+
return [2 /*return*/];
|
|
3193
|
+
}
|
|
3071
3194
|
}
|
|
3072
|
-
primaryKeyName =
|
|
3195
|
+
primaryKeyName = primaryKeys_1[0];
|
|
3073
3196
|
// If a primary key was provided in the URL, merge it into the payload.
|
|
3074
3197
|
// Support both complex requests using WHERE and singular requests
|
|
3075
3198
|
// where the primary key lives at the root of the payload.
|
|
3076
3199
|
if (primary) {
|
|
3077
3200
|
if (payload[C6C.WHERE]) {
|
|
3078
3201
|
payload[C6C.WHERE][primaryKeyName] =
|
|
3079
|
-
(
|
|
3202
|
+
(_f = payload[C6C.WHERE][primaryKeyName]) !== null && _f !== void 0 ? _f : primary;
|
|
3080
3203
|
}
|
|
3081
3204
|
else {
|
|
3082
3205
|
payload[primaryKeyName] =
|
|
3083
|
-
(
|
|
3206
|
+
(_g = payload[primaryKeyName]) !== null && _g !== void 0 ? _g : primary;
|
|
3084
3207
|
}
|
|
3085
3208
|
}
|
|
3086
3209
|
return [4 /*yield*/, restRequest({
|
|
@@ -3090,11 +3213,11 @@ function ExpressHandler(_a) {
|
|
|
3090
3213
|
restModel: C6.TABLES[table]
|
|
3091
3214
|
})(payload)];
|
|
3092
3215
|
case 1:
|
|
3093
|
-
response =
|
|
3216
|
+
response = _h.sent();
|
|
3094
3217
|
res.status(200).json(__assign({ success: true }, response));
|
|
3095
3218
|
return [3 /*break*/, 3];
|
|
3096
3219
|
case 2:
|
|
3097
|
-
err_1 =
|
|
3220
|
+
err_1 = _h.sent();
|
|
3098
3221
|
res.status(500).json({ success: false, error: err_1 });
|
|
3099
3222
|
next(err_1);
|
|
3100
3223
|
return [3 /*break*/, 3];
|
|
@@ -3179,10 +3302,11 @@ function error(message) {
|
|
|
3179
3302
|
}
|
|
3180
3303
|
|
|
3181
3304
|
function checkAllRequestsComplete() {
|
|
3182
|
-
var
|
|
3305
|
+
var cacheEntries = Array.from(apiRequestCache.values());
|
|
3306
|
+
var stillRunning = cacheEntries.filter(function (cache) { return undefined === cache.response; });
|
|
3183
3307
|
if (stillRunning.length !== 0) {
|
|
3184
3308
|
if (document === null || document === undefined) {
|
|
3185
|
-
throw new Error('document is undefined while waiting for API requests to complete (' + JSON.stringify(
|
|
3309
|
+
throw new Error('document is undefined while waiting for API requests to complete (' + JSON.stringify(cacheEntries) + ')');
|
|
3186
3310
|
}
|
|
3187
3311
|
// when requests return emtpy sets in full renders, it may not be possible to track their progress.
|
|
3188
3312
|
console.warn('stillRunning...', stillRunning);
|
|
@@ -3203,5 +3327,5 @@ function isVerbose () {
|
|
|
3203
3327
|
return ['true', '1', 'yes', 'on'].includes(envVerbose.toLowerCase());
|
|
3204
3328
|
}
|
|
3205
3329
|
|
|
3206
|
-
export { A, AggregateBuilder, C6C, C6Constants, ConditionBuilder, DELETE, DeleteQueryBuilder, Executor, ExpressHandler, F, GET, HttpExecutor, JoinBuilder, POST, PUT, PaginationBuilder, PostQueryBuilder, SelectQueryBuilder, SqlExecutor, TestRestfulResponse, UpdateQueryBuilder, apiRequestCache, axiosInstance, bbox, carbonNodeQsStringify, checkAllRequestsComplete, checkCache, clearCache, convertForRequestBody, convertHexIfBinary, derivedTable, determineRuntimeJsType, distSphere, eFetchDependencies, error, fieldEq, getEnvVar, getPrimaryKeyTypes, group, info, isDerivedTableKey, isLocal, isNode, isTest, isVerbose, normalizeSingularRequest, onError, onSuccess, removeInvalidKeys, removePrefixIfExists, resolveDerivedTable, restOrm, restRequest, sortAndSerializeQueryObject, stContains, timeout, toastOptions, toastOptionsDevs, userCustomClearCache, warn };
|
|
3330
|
+
export { A, AggregateBuilder, C6C, C6Constants, ConditionBuilder, DELETE, DeleteQueryBuilder, Executor, ExpressHandler, F, GET, HttpExecutor, JoinBuilder, POST, PUT, PaginationBuilder, PostQueryBuilder, SelectQueryBuilder, SqlExecutor, TestRestfulResponse, UpdateQueryBuilder, apiRequestCache, axiosInstance, bbox, carbonNodeQsStringify, checkAllRequestsComplete, checkCache, clearCache, convertForRequestBody, convertHexIfBinary, derivedTable, determineRuntimeJsType, distSphere, eFetchDependencies, error, fieldEq, getEnvVar, getPrimaryKeyTypes, group, info, isDerivedTableKey, isLocal, isNode, isTest, isVerbose, normalizeSingularRequest, onError, onSuccess, removeInvalidKeys, removePrefixIfExists, resolveDerivedTable, restOrm, restRequest, setCache, sortAndSerializeQueryObject, stContains, timeout, toastOptions, toastOptionsDevs, userCustomClearCache, warn };
|
|
3207
3331
|
//# sourceMappingURL=index.esm.js.map
|