@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.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,84 @@ 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, allowColumnRefs) {
|
|
1828
|
+
var _this = this;
|
|
1829
|
+
if (allowColumnRefs === void 0) { allowColumnRefs = false; }
|
|
1830
|
+
if (!Array.isArray(value))
|
|
1831
|
+
return false;
|
|
1832
|
+
return value.every(function (item) {
|
|
1833
|
+
if (item === null)
|
|
1834
|
+
return true;
|
|
1835
|
+
var type = typeof item;
|
|
1836
|
+
if (type === 'string' || type === 'number' || type === 'boolean')
|
|
1837
|
+
return true;
|
|
1838
|
+
if (Array.isArray(item))
|
|
1839
|
+
return _this.isPlainArrayLiteral(item, allowColumnRefs);
|
|
1840
|
+
if (item && typeof item === 'object')
|
|
1841
|
+
return _this.isPlainObjectLiteral(item, allowColumnRefs);
|
|
1842
|
+
return false;
|
|
1843
|
+
});
|
|
1844
|
+
};
|
|
1845
|
+
ConditionBuilder.prototype.isPlainObjectLiteral = function (value, allowColumnRefs) {
|
|
1846
|
+
var _this = this;
|
|
1847
|
+
if (allowColumnRefs === void 0) { allowColumnRefs = false; }
|
|
1848
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
1849
|
+
return false;
|
|
1850
|
+
if (value instanceof Date)
|
|
1851
|
+
return false;
|
|
1852
|
+
if (typeof Buffer !== 'undefined' && Buffer.isBuffer && Buffer.isBuffer(value))
|
|
1853
|
+
return false;
|
|
1854
|
+
var normalized = value instanceof Map ? Object.fromEntries(value) : value;
|
|
1855
|
+
if (C6C.SUBSELECT in normalized)
|
|
1856
|
+
return false;
|
|
1857
|
+
var entries = Object.entries(normalized);
|
|
1858
|
+
if (entries.length === 0)
|
|
1859
|
+
return true;
|
|
1860
|
+
if (entries.some(function (_a) {
|
|
1861
|
+
var key = _a[0];
|
|
1862
|
+
return _this.isOperator(key) || _this.BOOLEAN_OPERATORS.has(key);
|
|
1863
|
+
})) {
|
|
1864
|
+
return false;
|
|
1865
|
+
}
|
|
1866
|
+
if (!allowColumnRefs) {
|
|
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
|
+
}
|
|
1874
|
+
return true;
|
|
1875
|
+
};
|
|
1876
|
+
ConditionBuilder.prototype.resolveColumnDefinition = function (column) {
|
|
1877
|
+
var _a, _b, _c, _d;
|
|
1878
|
+
if (!column || typeof column !== 'string' || !column.includes('.'))
|
|
1879
|
+
return undefined;
|
|
1880
|
+
var _e = column.split('.', 2), prefix = _e[0], colName = _e[1];
|
|
1881
|
+
var tableName = (_a = this.aliasMap[prefix]) !== null && _a !== void 0 ? _a : prefix;
|
|
1882
|
+
var table = (_c = (_b = this.config.C6) === null || _b === void 0 ? void 0 : _b.TABLES) === null || _c === void 0 ? void 0 : _c[tableName];
|
|
1883
|
+
if (!(table === null || table === void 0 ? void 0 : table.TYPE_VALIDATION))
|
|
1884
|
+
return undefined;
|
|
1885
|
+
return (_d = table.TYPE_VALIDATION[colName]) !== null && _d !== void 0 ? _d : table.TYPE_VALIDATION["".concat(tableName, ".").concat(colName)];
|
|
1886
|
+
};
|
|
1887
|
+
ConditionBuilder.prototype.isJsonColumn = function (column) {
|
|
1888
|
+
var columnDef = this.resolveColumnDefinition(column);
|
|
1889
|
+
var mysqlType = columnDef === null || columnDef === void 0 ? void 0 : columnDef.MYSQL_TYPE;
|
|
1890
|
+
return typeof mysqlType === 'string' && mysqlType.toLowerCase().includes('json');
|
|
1891
|
+
};
|
|
1892
|
+
ConditionBuilder.prototype.serializeUpdateValue = function (value, params, contextColumn) {
|
|
1893
|
+
var normalized = value instanceof Map ? Object.fromEntries(value) : value;
|
|
1894
|
+
var allowColumnRefs = this.isJsonColumn(contextColumn);
|
|
1895
|
+
if (this.isPlainArrayLiteral(normalized, allowColumnRefs)
|
|
1896
|
+
|| this.isPlainObjectLiteral(normalized, allowColumnRefs)) {
|
|
1897
|
+
return this.addParam(params, contextColumn !== null && contextColumn !== void 0 ? contextColumn : '', JSON.stringify(normalized));
|
|
1898
|
+
}
|
|
1899
|
+
var _a = this.serializeOperand(normalized, params, contextColumn), sql = _a.sql, isReference = _a.isReference, isExpression = _a.isExpression, isSubSelect = _a.isSubSelect;
|
|
1900
|
+
if (!isReference && !isExpression && !isSubSelect && typeof normalized === 'object' && normalized !== null) {
|
|
1901
|
+
throw new Error('Unsupported operand type in SQL expression.');
|
|
1902
|
+
}
|
|
1903
|
+
return sql;
|
|
1904
|
+
};
|
|
1791
1905
|
ConditionBuilder.prototype.ensurePlainObject = function (value) {
|
|
1792
1906
|
if (value instanceof Map) {
|
|
1793
1907
|
return Object.fromEntries(value);
|
|
@@ -2644,12 +2758,14 @@ var PostQueryBuilder = /** @class */ (function (_super) {
|
|
|
2644
2758
|
var verb = C6C.REPLACE in this.request ? C6C.REPLACE : C6C.INSERT;
|
|
2645
2759
|
var body = verb in this.request ? this.request[verb] : this.request;
|
|
2646
2760
|
var keys = Object.keys(body);
|
|
2647
|
-
var params = [];
|
|
2761
|
+
var params = this.useNamedParams ? {} : [];
|
|
2648
2762
|
var placeholders = [];
|
|
2649
2763
|
for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
|
|
2650
2764
|
var key = keys_1[_i];
|
|
2651
2765
|
var value = body[key];
|
|
2652
|
-
var
|
|
2766
|
+
var trimmed = this.trimTablePrefix(table, key);
|
|
2767
|
+
var qualified = "".concat(table, ".").concat(trimmed);
|
|
2768
|
+
var placeholder = this.serializeUpdateValue(value, params, qualified);
|
|
2653
2769
|
placeholders.push(placeholder);
|
|
2654
2770
|
}
|
|
2655
2771
|
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 +2817,9 @@ var UpdateQueryBuilder = /** @class */ (function (_super) {
|
|
|
2701
2817
|
var col = _a[0], val = _a[1];
|
|
2702
2818
|
var trimmed = _this.trimTablePrefix(table, col);
|
|
2703
2819
|
var qualified = "".concat(table, ".").concat(trimmed);
|
|
2704
|
-
|
|
2820
|
+
_this.assertValidIdentifier(qualified, 'UPDATE SET');
|
|
2821
|
+
var rightSql = _this.serializeUpdateValue(val, params, qualified);
|
|
2822
|
+
return "`".concat(trimmed, "` = ").concat(rightSql);
|
|
2705
2823
|
});
|
|
2706
2824
|
sql += " SET ".concat(setClauses.join(', '));
|
|
2707
2825
|
if (args.WHERE) {
|
|
@@ -3029,12 +3147,12 @@ function ExpressHandler(_a) {
|
|
|
3029
3147
|
var _this = this;
|
|
3030
3148
|
var C6 = _a.C6, mysqlPool = _a.mysqlPool;
|
|
3031
3149
|
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 (
|
|
3150
|
+
var incomingMethod, table, primary, methodOverrideRaw, methodOverride, treatAsGet, method, payload, restModel, primaryKeys_1, primaryShortKeys_1, columnMap_1, resolveShortKey_1, hasPrimaryKeyValues, primaryKeyName, response, err_1;
|
|
3151
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
3152
|
+
return __generator(this, function (_h) {
|
|
3153
|
+
switch (_h.label) {
|
|
3036
3154
|
case 0:
|
|
3037
|
-
|
|
3155
|
+
_h.trys.push([0, 2, , 3]);
|
|
3038
3156
|
incomingMethod = req.method.toUpperCase();
|
|
3039
3157
|
table = req.params.table;
|
|
3040
3158
|
primary = req.params.primary;
|
|
@@ -3048,7 +3166,7 @@ function ExpressHandler(_a) {
|
|
|
3048
3166
|
try {
|
|
3049
3167
|
delete payload.METHOD;
|
|
3050
3168
|
}
|
|
3051
|
-
catch ( /* noop */
|
|
3169
|
+
catch ( /* noop */_j) { /* noop */ }
|
|
3052
3170
|
}
|
|
3053
3171
|
// Warn for unsupported overrides but continue normally
|
|
3054
3172
|
if (incomingMethod !== 'GET' && methodOverride && methodOverride !== 'GET') {
|
|
@@ -3058,29 +3176,56 @@ function ExpressHandler(_a) {
|
|
|
3058
3176
|
res.status(400).json({ error: "Invalid table: ".concat(table) });
|
|
3059
3177
|
return [2 /*return*/];
|
|
3060
3178
|
}
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3179
|
+
restModel = C6.TABLES[table];
|
|
3180
|
+
primaryKeys_1 = restModel.PRIMARY;
|
|
3181
|
+
primaryShortKeys_1 = (_d = restModel.PRIMARY_SHORT) !== null && _d !== void 0 ? _d : [];
|
|
3182
|
+
columnMap_1 = (_e = restModel.COLUMNS) !== null && _e !== void 0 ? _e : {};
|
|
3183
|
+
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; };
|
|
3184
|
+
hasPrimaryKeyValues = function (data) {
|
|
3185
|
+
if (!data || typeof data !== 'object')
|
|
3186
|
+
return false;
|
|
3187
|
+
var whereClause = data[C6C.WHERE];
|
|
3188
|
+
var hasKeyValue = function (obj, fullKey, shortKey) {
|
|
3189
|
+
if (!obj || typeof obj !== 'object')
|
|
3190
|
+
return false;
|
|
3191
|
+
var fullValue = obj[fullKey];
|
|
3192
|
+
if (fullValue !== undefined && fullValue !== null)
|
|
3193
|
+
return true;
|
|
3194
|
+
var shortValue = shortKey ? obj[shortKey] : undefined;
|
|
3195
|
+
return shortValue !== undefined && shortValue !== null;
|
|
3196
|
+
};
|
|
3197
|
+
return primaryKeys_1.every(function (fullKey, index) {
|
|
3198
|
+
var shortKey = resolveShortKey_1(fullKey, index);
|
|
3199
|
+
return hasKeyValue(whereClause, fullKey, shortKey) || hasKeyValue(data, fullKey, shortKey);
|
|
3200
|
+
});
|
|
3201
|
+
};
|
|
3202
|
+
if (primary && primaryKeys_1.length !== 1) {
|
|
3203
|
+
if (primaryKeys_1.length > 1 && hasPrimaryKeyValues(payload)) {
|
|
3204
|
+
primary = undefined;
|
|
3205
|
+
}
|
|
3206
|
+
else if (primaryKeys_1.length > 1) {
|
|
3064
3207
|
res.status(400).json({ error: "Table ".concat(table, " has multiple primary keys. Cannot implicitly determine key.") });
|
|
3065
3208
|
return [2 /*return*/];
|
|
3066
3209
|
}
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3210
|
+
else {
|
|
3211
|
+
res.status(400).json({
|
|
3212
|
+
error: "Table ".concat(table, " has no primary keys. Please specify one.")
|
|
3213
|
+
});
|
|
3214
|
+
return [2 /*return*/];
|
|
3215
|
+
}
|
|
3071
3216
|
}
|
|
3072
|
-
primaryKeyName =
|
|
3217
|
+
primaryKeyName = primaryKeys_1[0];
|
|
3073
3218
|
// If a primary key was provided in the URL, merge it into the payload.
|
|
3074
3219
|
// Support both complex requests using WHERE and singular requests
|
|
3075
3220
|
// where the primary key lives at the root of the payload.
|
|
3076
3221
|
if (primary) {
|
|
3077
3222
|
if (payload[C6C.WHERE]) {
|
|
3078
3223
|
payload[C6C.WHERE][primaryKeyName] =
|
|
3079
|
-
(
|
|
3224
|
+
(_f = payload[C6C.WHERE][primaryKeyName]) !== null && _f !== void 0 ? _f : primary;
|
|
3080
3225
|
}
|
|
3081
3226
|
else {
|
|
3082
3227
|
payload[primaryKeyName] =
|
|
3083
|
-
(
|
|
3228
|
+
(_g = payload[primaryKeyName]) !== null && _g !== void 0 ? _g : primary;
|
|
3084
3229
|
}
|
|
3085
3230
|
}
|
|
3086
3231
|
return [4 /*yield*/, restRequest({
|
|
@@ -3090,11 +3235,11 @@ function ExpressHandler(_a) {
|
|
|
3090
3235
|
restModel: C6.TABLES[table]
|
|
3091
3236
|
})(payload)];
|
|
3092
3237
|
case 1:
|
|
3093
|
-
response =
|
|
3238
|
+
response = _h.sent();
|
|
3094
3239
|
res.status(200).json(__assign({ success: true }, response));
|
|
3095
3240
|
return [3 /*break*/, 3];
|
|
3096
3241
|
case 2:
|
|
3097
|
-
err_1 =
|
|
3242
|
+
err_1 = _h.sent();
|
|
3098
3243
|
res.status(500).json({ success: false, error: err_1 });
|
|
3099
3244
|
next(err_1);
|
|
3100
3245
|
return [3 /*break*/, 3];
|
|
@@ -3179,10 +3324,11 @@ function error(message) {
|
|
|
3179
3324
|
}
|
|
3180
3325
|
|
|
3181
3326
|
function checkAllRequestsComplete() {
|
|
3182
|
-
var
|
|
3327
|
+
var cacheEntries = Array.from(apiRequestCache.values());
|
|
3328
|
+
var stillRunning = cacheEntries.filter(function (cache) { return undefined === cache.response; });
|
|
3183
3329
|
if (stillRunning.length !== 0) {
|
|
3184
3330
|
if (document === null || document === undefined) {
|
|
3185
|
-
throw new Error('document is undefined while waiting for API requests to complete (' + JSON.stringify(
|
|
3331
|
+
throw new Error('document is undefined while waiting for API requests to complete (' + JSON.stringify(cacheEntries) + ')');
|
|
3186
3332
|
}
|
|
3187
3333
|
// when requests return emtpy sets in full renders, it may not be possible to track their progress.
|
|
3188
3334
|
console.warn('stillRunning...', stillRunning);
|
|
@@ -3203,5 +3349,5 @@ function isVerbose () {
|
|
|
3203
3349
|
return ['true', '1', 'yes', 'on'].includes(envVerbose.toLowerCase());
|
|
3204
3350
|
}
|
|
3205
3351
|
|
|
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 };
|
|
3352
|
+
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
3353
|
//# sourceMappingURL=index.esm.js.map
|