@carbonorm/carbonnode 3.7.5 → 3.7.7
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 +1 -1
- package/dist/api/orm/builders/AggregateBuilder.d.ts +1 -0
- package/dist/api/types/dynamicFetching.d.ts +6 -6
- package/dist/api/types/ormInterfaces.d.ts +2 -2
- package/dist/api/utils/cacheManager.d.ts +1 -1
- package/dist/api/utils/normalizeSingularRequest.d.ts +10 -0
- package/dist/index.cjs.js +180 -34
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.esm.js +181 -36
- package/dist/index.esm.js.map +1 -1
- package/package.json +11 -6
- package/scripts/assets/handlebars/C6.test.ts.handlebars +55 -80
- package/scripts/assets/handlebars/C6.ts.handlebars +28 -2
- package/scripts/generateRestBindings.cjs +17 -6
- package/scripts/generateRestBindings.ts +22 -8
- package/src/__tests__/fixtures/c6.fixture.ts +74 -0
- package/src/__tests__/normalizeSingularRequest.test.ts +95 -0
- package/src/__tests__/sakila-db/C6.js +1487 -0
- package/src/__tests__/sakila-db/C6.test.ts +63 -0
- package/src/__tests__/sakila-db/C6.ts +2206 -0
- package/src/__tests__/sakila-db/sakila-data.sql +46444 -0
- package/src/__tests__/sakila-db/sakila-schema.sql +686 -0
- package/src/__tests__/sakila-db/sakila.mwb +0 -0
- package/src/__tests__/sakila.generated.test.ts +46 -0
- package/src/__tests__/sqlBuilders.complex.test.ts +134 -0
- package/src/__tests__/sqlBuilders.test.ts +121 -0
- package/src/api/convertForRequestBody.ts +1 -1
- package/src/api/executors/HttpExecutor.ts +23 -9
- package/src/api/executors/SqlExecutor.ts +14 -1
- package/src/api/orm/builders/AggregateBuilder.ts +3 -0
- package/src/api/orm/builders/ConditionBuilder.ts +34 -11
- package/src/api/orm/builders/PaginationBuilder.ts +10 -4
- package/src/api/orm/queries/SelectQueryBuilder.ts +3 -0
- package/src/api/orm/queries/UpdateQueryBuilder.ts +2 -1
- package/src/api/types/dynamicFetching.ts +8 -8
- package/src/api/types/ormInterfaces.ts +3 -4
- package/src/api/utils/cacheManager.ts +1 -1
- package/src/api/utils/normalizeSingularRequest.ts +138 -0
- package/src/index.ts +1 -0
package/README.md
CHANGED
|
@@ -566,7 +566,7 @@ export default Users;
|
|
|
566
566
|
|
|
567
567
|
This project uses Git hooks to automate certain tasks:
|
|
568
568
|
|
|
569
|
-
- **
|
|
569
|
+
- **post-commit**: Builds the project before pushing to ensure only working code is pushed
|
|
570
570
|
- **post-push**: Automatically publishes to npm when the version number changes
|
|
571
571
|
|
|
572
572
|
To set up the Git hooks, run:
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Executor } from "../../executors/Executor";
|
|
2
2
|
import { OrmGenerics } from "../../types/ormGenerics";
|
|
3
3
|
export declare abstract class AggregateBuilder<G extends OrmGenerics> extends Executor<G> {
|
|
4
|
+
protected selectAliases: Set<string>;
|
|
4
5
|
buildAggregateField(field: string | any[]): string;
|
|
5
6
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export declare enum eFetchDependencies {
|
|
2
2
|
NONE = 0,
|
|
3
|
-
REFERENCED = 1
|
|
4
|
-
CHILDREN = 1
|
|
5
|
-
REFERENCES = 2
|
|
6
|
-
PARENTS = 2
|
|
7
|
-
ALL = 3
|
|
8
|
-
C6ENTITY = 4
|
|
3
|
+
REFERENCED = 1,// alias of CHILDREN
|
|
4
|
+
CHILDREN = 1,// 0b0001
|
|
5
|
+
REFERENCES = 2,// alias of PARENTS
|
|
6
|
+
PARENTS = 2,// 0b0010
|
|
7
|
+
ALL = 3,// CHILDREN | PARENTS => 0b0011
|
|
8
|
+
C6ENTITY = 4,// 0b0100
|
|
9
9
|
RECURSIVE = 8
|
|
10
10
|
}
|
|
@@ -59,7 +59,7 @@ export type Pagination<T = any> = {
|
|
|
59
59
|
};
|
|
60
60
|
export type RequestGetPutDeleteBody<T extends {
|
|
61
61
|
[key: string]: any;
|
|
62
|
-
} = any> = {
|
|
62
|
+
} = any> = T | {
|
|
63
63
|
SELECT?: SelectField<T>[];
|
|
64
64
|
UPDATE?: Partial<T>;
|
|
65
65
|
DELETE?: boolean;
|
|
@@ -83,7 +83,7 @@ export type RequestQueryBody<Method extends iRestMethods, T extends {
|
|
|
83
83
|
[key: string]: any;
|
|
84
84
|
} = {}, Overrides extends {
|
|
85
85
|
[key: string]: any;
|
|
86
|
-
} = {}> = Method extends 'GET' | 'PUT' | 'DELETE' ? iAPI<RequestGetPutDeleteBody<Modify<T, Overrides> & Custom>> :
|
|
86
|
+
} = {}> = Method extends 'GET' | 'PUT' | 'DELETE' ? iAPI<RequestGetPutDeleteBody<Modify<T, Overrides> & Custom>> : iAPI<Modify<T, Overrides> & Custom>;
|
|
87
87
|
export interface iCacheAPI<ResponseDataType = any> {
|
|
88
88
|
requestArgumentsSerialized: string;
|
|
89
89
|
request: AxiosPromise<ResponseDataType>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AxiosPromise } from "axios";
|
|
2
|
-
import { iCacheAPI } from "
|
|
2
|
+
import { iCacheAPI } from "../types/ormInterfaces";
|
|
3
3
|
export declare let apiRequestCache: iCacheAPI[];
|
|
4
4
|
export declare let userCustomClearCache: (() => void)[];
|
|
5
5
|
interface iClearCache {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { C6RestfulModel, iRestMethods, RequestQueryBody } from "../types/ormInterfaces";
|
|
2
|
+
/**
|
|
3
|
+
* Converts a singular T-shaped request into complex ORM format for GET/PUT/DELETE
|
|
4
|
+
* Enforces that all primary keys are present for singular syntax and that the table has PKs.
|
|
5
|
+
* Optionally accepts a previously removed primary key (key/value) to reconstruct WHERE.
|
|
6
|
+
*/
|
|
7
|
+
export declare function normalizeSingularRequest<Method extends iRestMethods, T extends Record<string, any>, Custom extends Record<string, any> = {}, Overrides extends Record<string, any> = {}>(requestMethod: Method, request: RequestQueryBody<Method, T, Custom, Overrides>, restModel: C6RestfulModel<string, T, any>, removedPrimary?: {
|
|
8
|
+
key: string;
|
|
9
|
+
value: any;
|
|
10
|
+
}): RequestQueryBody<Method, T, Custom, Overrides>;
|
package/dist/index.cjs.js
CHANGED
|
@@ -593,6 +593,95 @@ function removeInvalidKeys(request, c6Tables) {
|
|
|
593
593
|
return intersection;
|
|
594
594
|
}
|
|
595
595
|
|
|
596
|
+
/**
|
|
597
|
+
* Converts a singular T-shaped request into complex ORM format for GET/PUT/DELETE
|
|
598
|
+
* Enforces that all primary keys are present for singular syntax and that the table has PKs.
|
|
599
|
+
* Optionally accepts a previously removed primary key (key/value) to reconstruct WHERE.
|
|
600
|
+
*/
|
|
601
|
+
function normalizeSingularRequest(requestMethod, request, restModel, removedPrimary) {
|
|
602
|
+
var _a, _b;
|
|
603
|
+
if (request == null || typeof request !== 'object')
|
|
604
|
+
return request;
|
|
605
|
+
var specialKeys = new Set([
|
|
606
|
+
C6Constants.SELECT,
|
|
607
|
+
C6Constants.UPDATE,
|
|
608
|
+
C6Constants.DELETE,
|
|
609
|
+
C6Constants.WHERE,
|
|
610
|
+
C6Constants.JOIN,
|
|
611
|
+
C6Constants.PAGINATION,
|
|
612
|
+
]);
|
|
613
|
+
// Determine if the request is already complex (has any special key besides PAGINATION)
|
|
614
|
+
var keys = Object.keys(request);
|
|
615
|
+
var hasComplexKeys = keys.some(function (k) { return k !== C6Constants.PAGINATION && specialKeys.has(k); });
|
|
616
|
+
if (hasComplexKeys)
|
|
617
|
+
return request; // already complex
|
|
618
|
+
// We treat it as singular when it's not complex.
|
|
619
|
+
// For GET, PUT, DELETE only
|
|
620
|
+
if (!(requestMethod === C6Constants.GET || requestMethod === C6Constants.PUT || requestMethod === C6Constants.DELETE)) {
|
|
621
|
+
return request;
|
|
622
|
+
}
|
|
623
|
+
var pkShorts = Array.isArray(restModel.PRIMARY_SHORT) ? tslib.__spreadArray([], restModel.PRIMARY_SHORT, true) : [];
|
|
624
|
+
if (!pkShorts.length) {
|
|
625
|
+
throw new Error("Table (".concat(restModel.TABLE_NAME, ") has no primary key; singular request syntax is not allowed."));
|
|
626
|
+
}
|
|
627
|
+
// Build pk map from request + possibly removed primary key
|
|
628
|
+
var pkValues = {};
|
|
629
|
+
for (var _i = 0, pkShorts_1 = pkShorts; _i < pkShorts_1.length; _i++) {
|
|
630
|
+
var pk = pkShorts_1[_i];
|
|
631
|
+
var fromRequest = request[pk];
|
|
632
|
+
if (fromRequest !== undefined && fromRequest !== null) {
|
|
633
|
+
pkValues[pk] = fromRequest;
|
|
634
|
+
continue;
|
|
635
|
+
}
|
|
636
|
+
if (removedPrimary && removedPrimary.key === pk) {
|
|
637
|
+
pkValues[pk] = removedPrimary.value;
|
|
638
|
+
continue;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
var missing = pkShorts.filter(function (pk) { return !(pk in pkValues); });
|
|
642
|
+
if (missing.length) {
|
|
643
|
+
throw new Error("Singular request requires all primary key(s) [".concat(pkShorts.join(', '), "] for table (").concat(restModel.TABLE_NAME, "). Missing: [").concat(missing.join(', '), "]"));
|
|
644
|
+
}
|
|
645
|
+
// Strip API metadata that should remain at root
|
|
646
|
+
var _c = request, dataInsertMultipleRows = _c.dataInsertMultipleRows, cacheResults = _c.cacheResults, fetchDependencies = _c.fetchDependencies, debug = _c.debug, success = _c.success, error = _c.error, rest = tslib.__rest(_c, ["dataInsertMultipleRows", "cacheResults", "fetchDependencies", "debug", "success", "error"]);
|
|
647
|
+
if (requestMethod === C6Constants.GET) {
|
|
648
|
+
var normalized_1 = {
|
|
649
|
+
WHERE: tslib.__assign({}, pkValues),
|
|
650
|
+
};
|
|
651
|
+
// Preserve pagination if any was added previously
|
|
652
|
+
if (request[C6Constants.PAGINATION]) {
|
|
653
|
+
normalized_1[C6Constants.PAGINATION] = request[C6Constants.PAGINATION];
|
|
654
|
+
}
|
|
655
|
+
return tslib.__assign(tslib.__assign({}, normalized_1), { dataInsertMultipleRows: dataInsertMultipleRows, cacheResults: cacheResults, fetchDependencies: fetchDependencies, debug: debug, success: success, error: error });
|
|
656
|
+
}
|
|
657
|
+
if (requestMethod === C6Constants.DELETE) {
|
|
658
|
+
var normalized_2 = (_a = {},
|
|
659
|
+
_a[C6Constants.DELETE] = true,
|
|
660
|
+
_a.WHERE = tslib.__assign({}, pkValues),
|
|
661
|
+
_a);
|
|
662
|
+
return tslib.__assign(tslib.__assign({}, normalized_2), { dataInsertMultipleRows: dataInsertMultipleRows, cacheResults: cacheResults, fetchDependencies: fetchDependencies, debug: debug, success: success, error: error });
|
|
663
|
+
}
|
|
664
|
+
// PUT
|
|
665
|
+
var updateBody = {};
|
|
666
|
+
for (var _d = 0, _e = Object.keys(rest); _d < _e.length; _d++) {
|
|
667
|
+
var k = _e[_d];
|
|
668
|
+
if (pkShorts.includes(k))
|
|
669
|
+
continue; // don't update PK columns
|
|
670
|
+
// Skip special request keys if any slipped through
|
|
671
|
+
if (specialKeys.has(k))
|
|
672
|
+
continue;
|
|
673
|
+
updateBody[k] = rest[k];
|
|
674
|
+
}
|
|
675
|
+
if (Object.keys(updateBody).length === 0) {
|
|
676
|
+
throw new Error("Singular PUT request for table (".concat(restModel.TABLE_NAME, ") must include at least one non-primary field to update."));
|
|
677
|
+
}
|
|
678
|
+
var normalized = (_b = {},
|
|
679
|
+
_b[C6Constants.UPDATE] = updateBody,
|
|
680
|
+
_b.WHERE = tslib.__assign({}, pkValues),
|
|
681
|
+
_b);
|
|
682
|
+
return tslib.__assign(tslib.__assign({}, normalized), { dataInsertMultipleRows: dataInsertMultipleRows, cacheResults: cacheResults, fetchDependencies: fetchDependencies, debug: debug, success: success, error: error });
|
|
683
|
+
}
|
|
684
|
+
|
|
596
685
|
// do not remove entries from this array. It is used to track the progress of API requests.
|
|
597
686
|
// position in array is important. Do not sort. To not add to begging.
|
|
598
687
|
exports.apiRequestCache = [];
|
|
@@ -730,7 +819,7 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
730
819
|
query[C6.PAGINATION][C6.LIMIT] = query[C6.PAGINATION][C6.LIMIT] || 100;
|
|
731
820
|
}
|
|
732
821
|
apiRequest = function () { return tslib.__awaiter(_this, void 0, void 0, function () {
|
|
733
|
-
var _a, debug, _b, cacheResults, dataInsertMultipleRows, success, _c, fetchDependencies, _d, error, querySerialized, cacheResult, cachingConfirmed, cacheCheck, cacheCheck, addBackPK, apiResponse, returnGetNextPageFunction, restRequestUri, needsConditionOrPrimaryCheck, TABLES, primaryKey, removedPkValue_1, axiosActiveRequest;
|
|
822
|
+
var _a, debug, _b, cacheResults, dataInsertMultipleRows, success, _c, fetchDependencies, _d, error, querySerialized, cacheResult, cachingConfirmed, cacheCheck, cacheCheck, addBackPK, removedPrimaryKV, apiResponse, returnGetNextPageFunction, restRequestUri, needsConditionOrPrimaryCheck, TABLES, primaryKey, removedPkValue_1, axiosActiveRequest;
|
|
734
823
|
var _e;
|
|
735
824
|
var _this = this;
|
|
736
825
|
var _f, _g, _h, _j, _k, _l;
|
|
@@ -850,6 +939,7 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
850
939
|
&& primaryKey in query) {
|
|
851
940
|
restRequestUri += query[primaryKey] + '/';
|
|
852
941
|
removedPkValue_1 = query[primaryKey];
|
|
942
|
+
removedPrimaryKV = { key: primaryKey, value: removedPkValue_1 };
|
|
853
943
|
addBackPK = function () {
|
|
854
944
|
query !== null && query !== void 0 ? query : (query = {});
|
|
855
945
|
query[primaryKey] = removedPkValue_1;
|
|
@@ -878,9 +968,11 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
878
968
|
var baseConfig = {
|
|
879
969
|
withCredentials: withCredentials,
|
|
880
970
|
};
|
|
971
|
+
// Normalize singular request (GET/PUT/DELETE) into complex ORM shape
|
|
972
|
+
var normalizedQuery = normalizeSingularRequest(requestMethod, query, restModel, removedPrimaryKV);
|
|
881
973
|
switch (requestMethod) {
|
|
882
974
|
case GET:
|
|
883
|
-
return [tslib.__assign(tslib.__assign({}, baseConfig), { params:
|
|
975
|
+
return [tslib.__assign(tslib.__assign({}, baseConfig), { params: normalizedQuery })];
|
|
884
976
|
case POST:
|
|
885
977
|
if (dataInsertMultipleRows !== undefined) {
|
|
886
978
|
return [
|
|
@@ -890,9 +982,9 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
890
982
|
}
|
|
891
983
|
return [convert(query), baseConfig];
|
|
892
984
|
case PUT:
|
|
893
|
-
return [convert(
|
|
985
|
+
return [convert(normalizedQuery), baseConfig];
|
|
894
986
|
case DELETE:
|
|
895
|
-
return [tslib.__assign(tslib.__assign({}, baseConfig), { data: convert(
|
|
987
|
+
return [tslib.__assign(tslib.__assign({}, baseConfig), { data: convert(normalizedQuery) })];
|
|
896
988
|
default:
|
|
897
989
|
throw new Error("The request method (".concat(requestMethod, ") was not recognized."));
|
|
898
990
|
}
|
|
@@ -1096,8 +1188,11 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
1096
1188
|
console.log('%c Fetch Dependencies will select (' + tableToFetch + ') using GET request', 'color: #33ccff');
|
|
1097
1189
|
var nextFetchDependencies = exports.eFetchDependencies.NONE;
|
|
1098
1190
|
if (fetchDependencies & exports.eFetchDependencies.RECURSIVE) {
|
|
1099
|
-
|
|
1100
|
-
|
|
1191
|
+
var hasParents = !!(fetchDependencies & exports.eFetchDependencies.PARENTS);
|
|
1192
|
+
var hasChildren = !!(fetchDependencies & exports.eFetchDependencies.CHILDREN);
|
|
1193
|
+
if (hasParents && hasChildren) {
|
|
1194
|
+
throw Error('Recursive fetch with both PARENT and CHILD references would loop forever. ' +
|
|
1195
|
+
'Use only one of PARENTS or CHILDREN when RECURSIVE is set.');
|
|
1101
1196
|
}
|
|
1102
1197
|
nextFetchDependencies = fetchDependencies;
|
|
1103
1198
|
}
|
|
@@ -1210,7 +1305,9 @@ function convertHexIfBinary(_col, val, columnDef) {
|
|
|
1210
1305
|
var AggregateBuilder = /** @class */ (function (_super) {
|
|
1211
1306
|
tslib.__extends(AggregateBuilder, _super);
|
|
1212
1307
|
function AggregateBuilder() {
|
|
1213
|
-
|
|
1308
|
+
var _this = _super !== null && _super.apply(this, arguments) || this;
|
|
1309
|
+
_this.selectAliases = new Set();
|
|
1310
|
+
return _this;
|
|
1214
1311
|
}
|
|
1215
1312
|
AggregateBuilder.prototype.buildAggregateField = function (field) {
|
|
1216
1313
|
var _this = this;
|
|
@@ -1238,6 +1335,7 @@ var AggregateBuilder = /** @class */ (function (_super) {
|
|
|
1238
1335
|
expr = "".concat(F, "(").concat(argList, ")");
|
|
1239
1336
|
}
|
|
1240
1337
|
if (alias) {
|
|
1338
|
+
this.selectAliases.add(alias);
|
|
1241
1339
|
expr += " AS ".concat(alias);
|
|
1242
1340
|
}
|
|
1243
1341
|
this.config.verbose && console.log("[SELECT] ".concat(expr));
|
|
@@ -1304,12 +1402,21 @@ var ConditionBuilder = /** @class */ (function (_super) {
|
|
|
1304
1402
|
throw new Error("Method not implemented.");
|
|
1305
1403
|
};
|
|
1306
1404
|
ConditionBuilder.prototype.isTableReference = function (val) {
|
|
1307
|
-
var _a, _b, _c;
|
|
1308
|
-
if (typeof val !== 'string'
|
|
1405
|
+
var _a, _b, _c, _d;
|
|
1406
|
+
if (typeof val !== 'string')
|
|
1407
|
+
return false;
|
|
1408
|
+
// Support aggregate aliases (e.g., SELECT COUNT(x) AS cnt ... HAVING cnt > 1)
|
|
1409
|
+
if (!val.includes('.')) {
|
|
1410
|
+
var isIdentifier = /^[A-Za-z_][A-Za-z0-9_]*$/.test(val);
|
|
1411
|
+
// selectAliases is defined in AggregateBuilder
|
|
1412
|
+
if (isIdentifier && ((_a = this.selectAliases) === null || _a === void 0 ? void 0 : _a.has(val))) {
|
|
1413
|
+
return true;
|
|
1414
|
+
}
|
|
1309
1415
|
return false;
|
|
1310
|
-
|
|
1311
|
-
var
|
|
1312
|
-
var
|
|
1416
|
+
}
|
|
1417
|
+
var _e = val.split('.'), prefix = _e[0], column = _e[1];
|
|
1418
|
+
var tableName = (_b = this.aliasMap[prefix]) !== null && _b !== void 0 ? _b : prefix;
|
|
1419
|
+
var table = (_d = (_c = this.config.C6) === null || _c === void 0 ? void 0 : _c.TABLES) === null || _d === void 0 ? void 0 : _d[tableName];
|
|
1313
1420
|
if (!table || !table.COLUMNS)
|
|
1314
1421
|
return false;
|
|
1315
1422
|
var fullKey = "".concat(tableName, ".").concat(column);
|
|
@@ -1322,8 +1429,14 @@ var ConditionBuilder = /** @class */ (function (_super) {
|
|
|
1322
1429
|
}
|
|
1323
1430
|
};
|
|
1324
1431
|
ConditionBuilder.prototype.addParam = function (params, column, value) {
|
|
1325
|
-
var _a, _b;
|
|
1326
|
-
|
|
1432
|
+
var _a, _b, _c;
|
|
1433
|
+
// Determine column definition from C6.TABLES to support type-aware conversions (e.g., BINARY hex -> Buffer)
|
|
1434
|
+
var columnDef;
|
|
1435
|
+
if (typeof column === 'string' && column.includes('.')) {
|
|
1436
|
+
var tableName = column.split('.', 2)[0];
|
|
1437
|
+
var table = (_b = (_a = this.config.C6) === null || _a === void 0 ? void 0 : _a.TABLES) === null || _b === void 0 ? void 0 : _b[tableName];
|
|
1438
|
+
columnDef = (_c = table === null || table === void 0 ? void 0 : table.TYPE_VALIDATION) === null || _c === void 0 ? void 0 : _c[column];
|
|
1439
|
+
}
|
|
1327
1440
|
var val = convertHexIfBinary(column, value, columnDef);
|
|
1328
1441
|
if (this.useNamedParams) {
|
|
1329
1442
|
var key = "param".concat(Object.keys(params).length);
|
|
@@ -1367,7 +1480,7 @@ var ConditionBuilder = /** @class */ (function (_super) {
|
|
|
1367
1480
|
var leftIsCol = _this.isColumnRef(column);
|
|
1368
1481
|
var leftIsRef = _this.isTableReference(column);
|
|
1369
1482
|
var rightIsCol = typeof value === 'string' && _this.isColumnRef(value);
|
|
1370
|
-
if (!leftIsCol && !rightIsCol) {
|
|
1483
|
+
if (!leftIsCol && !leftIsRef && !rightIsCol) {
|
|
1371
1484
|
throw new Error("Potential SQL injection detected: '".concat(column, " ").concat(op, " ").concat(value, "'"));
|
|
1372
1485
|
}
|
|
1373
1486
|
_this.validateOperator(op);
|
|
@@ -1434,21 +1547,22 @@ var ConditionBuilder = /** @class */ (function (_super) {
|
|
|
1434
1547
|
var parts = [];
|
|
1435
1548
|
var buildFromObject = function (obj, mode) {
|
|
1436
1549
|
var subParts = [];
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1550
|
+
var entries = Object.entries(obj);
|
|
1551
|
+
var nonNumeric = entries.filter(function (_a) {
|
|
1552
|
+
var k = _a[0];
|
|
1553
|
+
return isNaN(Number(k));
|
|
1554
|
+
});
|
|
1555
|
+
var numeric = entries.filter(function (_a) {
|
|
1556
|
+
var k = _a[0];
|
|
1557
|
+
return !isNaN(Number(k));
|
|
1558
|
+
});
|
|
1559
|
+
var processEntry = function (k, v) {
|
|
1446
1560
|
if (typeof v === 'object' && v !== null && Object.keys(v).length === 1) {
|
|
1447
|
-
var
|
|
1561
|
+
var _a = Object.entries(v)[0], op = _a[0], val = _a[1];
|
|
1448
1562
|
subParts.push(addCondition(k, op, val));
|
|
1449
1563
|
}
|
|
1450
1564
|
else if (Array.isArray(v) && v.length >= 2 && typeof v[0] === 'string') {
|
|
1451
|
-
var
|
|
1565
|
+
var _b = v, op = _b[0], val = _b[1];
|
|
1452
1566
|
subParts.push(addCondition(k, op, val));
|
|
1453
1567
|
}
|
|
1454
1568
|
else if (typeof v === 'object' && v !== null) {
|
|
@@ -1459,6 +1573,18 @@ var ConditionBuilder = /** @class */ (function (_super) {
|
|
|
1459
1573
|
else {
|
|
1460
1574
|
subParts.push(addCondition(k, '=', v));
|
|
1461
1575
|
}
|
|
1576
|
+
};
|
|
1577
|
+
// Process non-numeric keys first to preserve intuitive insertion order for params
|
|
1578
|
+
for (var _i = 0, nonNumeric_1 = nonNumeric; _i < nonNumeric_1.length; _i++) {
|
|
1579
|
+
var _a = nonNumeric_1[_i], k = _a[0], v = _a[1];
|
|
1580
|
+
processEntry(k, v);
|
|
1581
|
+
}
|
|
1582
|
+
// Then process numeric keys (treated as grouped OR conditions)
|
|
1583
|
+
for (var _b = 0, numeric_1 = numeric; _b < numeric_1.length; _b++) {
|
|
1584
|
+
var _c = numeric_1[_b]; _c[0]; var v = _c[1];
|
|
1585
|
+
var sub = _this.buildBooleanJoinedConditions(v, false, params);
|
|
1586
|
+
if (sub)
|
|
1587
|
+
subParts.push(sub);
|
|
1462
1588
|
}
|
|
1463
1589
|
return subParts.join(" ".concat(mode ? 'AND' : 'OR', " "));
|
|
1464
1590
|
};
|
|
@@ -1595,13 +1721,12 @@ var PaginationBuilder = /** @class */ (function (_super) {
|
|
|
1595
1721
|
*/
|
|
1596
1722
|
PaginationBuilder.prototype.buildPaginationClause = function (pagination) {
|
|
1597
1723
|
var _this = this;
|
|
1598
|
-
var _a;
|
|
1599
1724
|
var sql = "";
|
|
1600
1725
|
/* -------- ORDER BY -------- */
|
|
1601
1726
|
if (pagination === null || pagination === void 0 ? void 0 : pagination[C6Constants.ORDER]) {
|
|
1602
1727
|
var orderParts = [];
|
|
1603
|
-
for (var _i = 0,
|
|
1604
|
-
var
|
|
1728
|
+
for (var _i = 0, _a = Object.entries(pagination[C6Constants.ORDER]); _i < _a.length; _i++) {
|
|
1729
|
+
var _b = _a[_i], key = _b[0], val = _b[1];
|
|
1605
1730
|
// FUNCTION CALL: val is an array of args
|
|
1606
1731
|
if (Array.isArray(val)) {
|
|
1607
1732
|
var args = val
|
|
@@ -1620,9 +1745,16 @@ var PaginationBuilder = /** @class */ (function (_super) {
|
|
|
1620
1745
|
/* -------- LIMIT / OFFSET -------- */
|
|
1621
1746
|
if ((pagination === null || pagination === void 0 ? void 0 : pagination[C6Constants.LIMIT]) != null) {
|
|
1622
1747
|
var lim = parseInt(pagination[C6Constants.LIMIT], 10);
|
|
1623
|
-
var
|
|
1624
|
-
var
|
|
1625
|
-
|
|
1748
|
+
var pageRaw = pagination[C6Constants.PAGE];
|
|
1749
|
+
var pageParsed = parseInt(pageRaw !== null && pageRaw !== void 0 ? pageRaw : 1, 10);
|
|
1750
|
+
var page = isFinite(pageParsed) && pageParsed > 1 ? pageParsed : 1;
|
|
1751
|
+
if (page === 1) {
|
|
1752
|
+
sql += " LIMIT ".concat(lim);
|
|
1753
|
+
}
|
|
1754
|
+
else {
|
|
1755
|
+
var offset = (page - 1) * lim;
|
|
1756
|
+
sql += " LIMIT ".concat(offset, ", ").concat(lim);
|
|
1757
|
+
}
|
|
1626
1758
|
}
|
|
1627
1759
|
this.config.verbose && console.log("[PAGINATION] ".concat(sql.trim()));
|
|
1628
1760
|
return sql;
|
|
@@ -1640,6 +1772,10 @@ var SelectQueryBuilder = /** @class */ (function (_super) {
|
|
|
1640
1772
|
var _a;
|
|
1641
1773
|
if (isSubSelect === void 0) { isSubSelect = false; }
|
|
1642
1774
|
this.aliasMap = {};
|
|
1775
|
+
// reset any previously collected SELECT aliases (from AggregateBuilder)
|
|
1776
|
+
// @ts-ignore
|
|
1777
|
+
if (this.selectAliases && this.selectAliases.clear)
|
|
1778
|
+
this.selectAliases.clear();
|
|
1643
1779
|
var args = this.request;
|
|
1644
1780
|
this.initAlias(table, args.JOIN);
|
|
1645
1781
|
var params = this.useNamedParams ? {} : [];
|
|
@@ -1693,9 +1829,10 @@ var UpdateQueryBuilder = /** @class */ (function (_super) {
|
|
|
1693
1829
|
if (!(C6C.UPDATE in this.request)) {
|
|
1694
1830
|
throw new Error("No update data provided in the request.");
|
|
1695
1831
|
}
|
|
1696
|
-
var setClauses = Object.entries(this.request[C6C.UPDATE])
|
|
1832
|
+
var setClauses = Object.entries(this.request[C6C.UPDATE])
|
|
1833
|
+
.map(function (_a) {
|
|
1697
1834
|
var col = _a[0], val = _a[1];
|
|
1698
|
-
return _this.addParam(params, col, val);
|
|
1835
|
+
return "`".concat(col, "` = ").concat(_this.addParam(params, col, val));
|
|
1699
1836
|
});
|
|
1700
1837
|
sql += " SET ".concat(setClauses.join(', '));
|
|
1701
1838
|
if (args.WHERE) {
|
|
@@ -1727,6 +1864,14 @@ var SqlExecutor = /** @class */ (function (_super) {
|
|
|
1727
1864
|
case 0:
|
|
1728
1865
|
TABLE_NAME = this.config.restModel.TABLE_NAME;
|
|
1729
1866
|
method = this.config.requestMethod;
|
|
1867
|
+
// Normalize singular T-shaped requests into complex ORM shape (GET/PUT/DELETE)
|
|
1868
|
+
try {
|
|
1869
|
+
this.request = normalizeSingularRequest(method, this.request, this.config.restModel, undefined);
|
|
1870
|
+
}
|
|
1871
|
+
catch (e) {
|
|
1872
|
+
// Surface normalization errors early
|
|
1873
|
+
throw e;
|
|
1874
|
+
}
|
|
1730
1875
|
this.config.verbose && console.log("[SQL EXECUTOR] \u25B6\uFE0F Executing ".concat(method, " on table \"").concat(TABLE_NAME, "\""));
|
|
1731
1876
|
this.config.verbose && console.log("[SQL EXECUTOR] \uD83E\uDDE9 Request:", this.request);
|
|
1732
1877
|
_a = method;
|
|
@@ -2131,6 +2276,7 @@ exports.isLocal = isLocal;
|
|
|
2131
2276
|
exports.isNode = isNode;
|
|
2132
2277
|
exports.isTest = isTest;
|
|
2133
2278
|
exports.isVerbose = isVerbose;
|
|
2279
|
+
exports.normalizeSingularRequest = normalizeSingularRequest;
|
|
2134
2280
|
exports.onError = onError;
|
|
2135
2281
|
exports.onSuccess = onSuccess;
|
|
2136
2282
|
exports.removeInvalidKeys = removeInvalidKeys;
|