@carbonorm/carbonnode 3.7.6 → 3.7.8
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 +2 -1
- package/dist/api/orm/builders/AggregateBuilder.d.ts +1 -0
- 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 +182 -32
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.esm.js +183 -34
- 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 +105 -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 +14 -3
- 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/ormInterfaces.ts +3 -4
- package/src/api/utils/cacheManager.ts +1 -1
- package/src/api/utils/normalizeSingularRequest.ts +144 -0
- package/src/index.ts +1 -0
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|

|
|
6
6
|

|
|
7
7
|

|
|
8
|
+
[](https://github.com/CarbonORM/CarbonNode/actions/workflows/npm-publish-on-bump.yml)
|
|
8
9
|
|
|
9
10
|
# CarbonNode (Alpha Release)
|
|
10
11
|
|
|
@@ -566,7 +567,7 @@ export default Users;
|
|
|
566
567
|
|
|
567
568
|
This project uses Git hooks to automate certain tasks:
|
|
568
569
|
|
|
569
|
-
- **
|
|
570
|
+
- **post-commit**: Builds the project before pushing to ensure only working code is pushed
|
|
570
571
|
- **post-push**: Automatically publishes to npm when the version number changes
|
|
571
572
|
|
|
572
573
|
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
|
}
|
|
@@ -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,102 @@ 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
|
+
// For GET requests, do not enforce primary key presence; treat as a collection query.
|
|
626
|
+
if (requestMethod === C6Constants.GET)
|
|
627
|
+
return request;
|
|
628
|
+
throw new Error("Table (".concat(restModel.TABLE_NAME, ") has no primary key; singular request syntax is not allowed."));
|
|
629
|
+
}
|
|
630
|
+
// Build pk map from request + possibly removed primary key
|
|
631
|
+
var pkValues = {};
|
|
632
|
+
for (var _i = 0, pkShorts_1 = pkShorts; _i < pkShorts_1.length; _i++) {
|
|
633
|
+
var pk = pkShorts_1[_i];
|
|
634
|
+
var fromRequest = request[pk];
|
|
635
|
+
if (fromRequest !== undefined && fromRequest !== null) {
|
|
636
|
+
pkValues[pk] = fromRequest;
|
|
637
|
+
continue;
|
|
638
|
+
}
|
|
639
|
+
if (removedPrimary && removedPrimary.key === pk) {
|
|
640
|
+
pkValues[pk] = removedPrimary.value;
|
|
641
|
+
continue;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
var missing = pkShorts.filter(function (pk) { return !(pk in pkValues); });
|
|
645
|
+
if (missing.length) {
|
|
646
|
+
// For GET requests, if not all PKs are provided, treat as a collection query and leave as-is.
|
|
647
|
+
if (requestMethod === C6Constants.GET) {
|
|
648
|
+
return request;
|
|
649
|
+
}
|
|
650
|
+
throw new Error("Singular request requires all primary key(s) [".concat(pkShorts.join(', '), "] for table (").concat(restModel.TABLE_NAME, "). Missing: [").concat(missing.join(', '), "]"));
|
|
651
|
+
}
|
|
652
|
+
// Strip API metadata that should remain at root
|
|
653
|
+
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"]);
|
|
654
|
+
if (requestMethod === C6Constants.GET) {
|
|
655
|
+
var normalized_1 = {
|
|
656
|
+
WHERE: tslib.__assign({}, pkValues),
|
|
657
|
+
};
|
|
658
|
+
// Preserve pagination if any was added previously
|
|
659
|
+
if (request[C6Constants.PAGINATION]) {
|
|
660
|
+
normalized_1[C6Constants.PAGINATION] = request[C6Constants.PAGINATION];
|
|
661
|
+
}
|
|
662
|
+
return tslib.__assign(tslib.__assign({}, normalized_1), { dataInsertMultipleRows: dataInsertMultipleRows, cacheResults: cacheResults, fetchDependencies: fetchDependencies, debug: debug, success: success, error: error });
|
|
663
|
+
}
|
|
664
|
+
if (requestMethod === C6Constants.DELETE) {
|
|
665
|
+
var normalized_2 = (_a = {},
|
|
666
|
+
_a[C6Constants.DELETE] = true,
|
|
667
|
+
_a.WHERE = tslib.__assign({}, pkValues),
|
|
668
|
+
_a);
|
|
669
|
+
return tslib.__assign(tslib.__assign({}, normalized_2), { dataInsertMultipleRows: dataInsertMultipleRows, cacheResults: cacheResults, fetchDependencies: fetchDependencies, debug: debug, success: success, error: error });
|
|
670
|
+
}
|
|
671
|
+
// PUT
|
|
672
|
+
var updateBody = {};
|
|
673
|
+
for (var _d = 0, _e = Object.keys(rest); _d < _e.length; _d++) {
|
|
674
|
+
var k = _e[_d];
|
|
675
|
+
if (pkShorts.includes(k))
|
|
676
|
+
continue; // don't update PK columns
|
|
677
|
+
// Skip special request keys if any slipped through
|
|
678
|
+
if (specialKeys.has(k))
|
|
679
|
+
continue;
|
|
680
|
+
updateBody[k] = rest[k];
|
|
681
|
+
}
|
|
682
|
+
if (Object.keys(updateBody).length === 0) {
|
|
683
|
+
throw new Error("Singular PUT request for table (".concat(restModel.TABLE_NAME, ") must include at least one non-primary field to update."));
|
|
684
|
+
}
|
|
685
|
+
var normalized = (_b = {},
|
|
686
|
+
_b[C6Constants.UPDATE] = updateBody,
|
|
687
|
+
_b.WHERE = tslib.__assign({}, pkValues),
|
|
688
|
+
_b);
|
|
689
|
+
return tslib.__assign(tslib.__assign({}, normalized), { dataInsertMultipleRows: dataInsertMultipleRows, cacheResults: cacheResults, fetchDependencies: fetchDependencies, debug: debug, success: success, error: error });
|
|
690
|
+
}
|
|
691
|
+
|
|
596
692
|
// do not remove entries from this array. It is used to track the progress of API requests.
|
|
597
693
|
// position in array is important. Do not sort. To not add to begging.
|
|
598
694
|
exports.apiRequestCache = [];
|
|
@@ -730,7 +826,7 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
730
826
|
query[C6.PAGINATION][C6.LIMIT] = query[C6.PAGINATION][C6.LIMIT] || 100;
|
|
731
827
|
}
|
|
732
828
|
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;
|
|
829
|
+
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
830
|
var _e;
|
|
735
831
|
var _this = this;
|
|
736
832
|
var _f, _g, _h, _j, _k, _l;
|
|
@@ -850,6 +946,7 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
850
946
|
&& primaryKey in query) {
|
|
851
947
|
restRequestUri += query[primaryKey] + '/';
|
|
852
948
|
removedPkValue_1 = query[primaryKey];
|
|
949
|
+
removedPrimaryKV = { key: primaryKey, value: removedPkValue_1 };
|
|
853
950
|
addBackPK = function () {
|
|
854
951
|
query !== null && query !== void 0 ? query : (query = {});
|
|
855
952
|
query[primaryKey] = removedPkValue_1;
|
|
@@ -878,9 +975,11 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
878
975
|
var baseConfig = {
|
|
879
976
|
withCredentials: withCredentials,
|
|
880
977
|
};
|
|
978
|
+
// Normalize singular request (GET/PUT/DELETE) into complex ORM shape
|
|
979
|
+
var normalizedQuery = normalizeSingularRequest(requestMethod, query, restModel, removedPrimaryKV);
|
|
881
980
|
switch (requestMethod) {
|
|
882
981
|
case GET:
|
|
883
|
-
return [tslib.__assign(tslib.__assign({}, baseConfig), { params:
|
|
982
|
+
return [tslib.__assign(tslib.__assign({}, baseConfig), { params: normalizedQuery })];
|
|
884
983
|
case POST:
|
|
885
984
|
if (dataInsertMultipleRows !== undefined) {
|
|
886
985
|
return [
|
|
@@ -890,9 +989,9 @@ var HttpExecutor = /** @class */ (function (_super) {
|
|
|
890
989
|
}
|
|
891
990
|
return [convert(query), baseConfig];
|
|
892
991
|
case PUT:
|
|
893
|
-
return [convert(
|
|
992
|
+
return [convert(normalizedQuery), baseConfig];
|
|
894
993
|
case DELETE:
|
|
895
|
-
return [tslib.__assign(tslib.__assign({}, baseConfig), { data: convert(
|
|
994
|
+
return [tslib.__assign(tslib.__assign({}, baseConfig), { data: convert(normalizedQuery) })];
|
|
896
995
|
default:
|
|
897
996
|
throw new Error("The request method (".concat(requestMethod, ") was not recognized."));
|
|
898
997
|
}
|
|
@@ -1213,7 +1312,9 @@ function convertHexIfBinary(_col, val, columnDef) {
|
|
|
1213
1312
|
var AggregateBuilder = /** @class */ (function (_super) {
|
|
1214
1313
|
tslib.__extends(AggregateBuilder, _super);
|
|
1215
1314
|
function AggregateBuilder() {
|
|
1216
|
-
|
|
1315
|
+
var _this = _super !== null && _super.apply(this, arguments) || this;
|
|
1316
|
+
_this.selectAliases = new Set();
|
|
1317
|
+
return _this;
|
|
1217
1318
|
}
|
|
1218
1319
|
AggregateBuilder.prototype.buildAggregateField = function (field) {
|
|
1219
1320
|
var _this = this;
|
|
@@ -1241,6 +1342,7 @@ var AggregateBuilder = /** @class */ (function (_super) {
|
|
|
1241
1342
|
expr = "".concat(F, "(").concat(argList, ")");
|
|
1242
1343
|
}
|
|
1243
1344
|
if (alias) {
|
|
1345
|
+
this.selectAliases.add(alias);
|
|
1244
1346
|
expr += " AS ".concat(alias);
|
|
1245
1347
|
}
|
|
1246
1348
|
this.config.verbose && console.log("[SELECT] ".concat(expr));
|
|
@@ -1307,12 +1409,21 @@ var ConditionBuilder = /** @class */ (function (_super) {
|
|
|
1307
1409
|
throw new Error("Method not implemented.");
|
|
1308
1410
|
};
|
|
1309
1411
|
ConditionBuilder.prototype.isTableReference = function (val) {
|
|
1310
|
-
var _a, _b, _c;
|
|
1311
|
-
if (typeof val !== 'string'
|
|
1412
|
+
var _a, _b, _c, _d;
|
|
1413
|
+
if (typeof val !== 'string')
|
|
1414
|
+
return false;
|
|
1415
|
+
// Support aggregate aliases (e.g., SELECT COUNT(x) AS cnt ... HAVING cnt > 1)
|
|
1416
|
+
if (!val.includes('.')) {
|
|
1417
|
+
var isIdentifier = /^[A-Za-z_][A-Za-z0-9_]*$/.test(val);
|
|
1418
|
+
// selectAliases is defined in AggregateBuilder
|
|
1419
|
+
if (isIdentifier && ((_a = this.selectAliases) === null || _a === void 0 ? void 0 : _a.has(val))) {
|
|
1420
|
+
return true;
|
|
1421
|
+
}
|
|
1312
1422
|
return false;
|
|
1313
|
-
|
|
1314
|
-
var
|
|
1315
|
-
var
|
|
1423
|
+
}
|
|
1424
|
+
var _e = val.split('.'), prefix = _e[0], column = _e[1];
|
|
1425
|
+
var tableName = (_b = this.aliasMap[prefix]) !== null && _b !== void 0 ? _b : prefix;
|
|
1426
|
+
var table = (_d = (_c = this.config.C6) === null || _c === void 0 ? void 0 : _c.TABLES) === null || _d === void 0 ? void 0 : _d[tableName];
|
|
1316
1427
|
if (!table || !table.COLUMNS)
|
|
1317
1428
|
return false;
|
|
1318
1429
|
var fullKey = "".concat(tableName, ".").concat(column);
|
|
@@ -1325,8 +1436,14 @@ var ConditionBuilder = /** @class */ (function (_super) {
|
|
|
1325
1436
|
}
|
|
1326
1437
|
};
|
|
1327
1438
|
ConditionBuilder.prototype.addParam = function (params, column, value) {
|
|
1328
|
-
var _a, _b;
|
|
1329
|
-
|
|
1439
|
+
var _a, _b, _c;
|
|
1440
|
+
// Determine column definition from C6.TABLES to support type-aware conversions (e.g., BINARY hex -> Buffer)
|
|
1441
|
+
var columnDef;
|
|
1442
|
+
if (typeof column === 'string' && column.includes('.')) {
|
|
1443
|
+
var tableName = column.split('.', 2)[0];
|
|
1444
|
+
var table = (_b = (_a = this.config.C6) === null || _a === void 0 ? void 0 : _a.TABLES) === null || _b === void 0 ? void 0 : _b[tableName];
|
|
1445
|
+
columnDef = (_c = table === null || table === void 0 ? void 0 : table.TYPE_VALIDATION) === null || _c === void 0 ? void 0 : _c[column];
|
|
1446
|
+
}
|
|
1330
1447
|
var val = convertHexIfBinary(column, value, columnDef);
|
|
1331
1448
|
if (this.useNamedParams) {
|
|
1332
1449
|
var key = "param".concat(Object.keys(params).length);
|
|
@@ -1370,7 +1487,7 @@ var ConditionBuilder = /** @class */ (function (_super) {
|
|
|
1370
1487
|
var leftIsCol = _this.isColumnRef(column);
|
|
1371
1488
|
var leftIsRef = _this.isTableReference(column);
|
|
1372
1489
|
var rightIsCol = typeof value === 'string' && _this.isColumnRef(value);
|
|
1373
|
-
if (!leftIsCol && !rightIsCol) {
|
|
1490
|
+
if (!leftIsCol && !leftIsRef && !rightIsCol) {
|
|
1374
1491
|
throw new Error("Potential SQL injection detected: '".concat(column, " ").concat(op, " ").concat(value, "'"));
|
|
1375
1492
|
}
|
|
1376
1493
|
_this.validateOperator(op);
|
|
@@ -1437,21 +1554,22 @@ var ConditionBuilder = /** @class */ (function (_super) {
|
|
|
1437
1554
|
var parts = [];
|
|
1438
1555
|
var buildFromObject = function (obj, mode) {
|
|
1439
1556
|
var subParts = [];
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1557
|
+
var entries = Object.entries(obj);
|
|
1558
|
+
var nonNumeric = entries.filter(function (_a) {
|
|
1559
|
+
var k = _a[0];
|
|
1560
|
+
return isNaN(Number(k));
|
|
1561
|
+
});
|
|
1562
|
+
var numeric = entries.filter(function (_a) {
|
|
1563
|
+
var k = _a[0];
|
|
1564
|
+
return !isNaN(Number(k));
|
|
1565
|
+
});
|
|
1566
|
+
var processEntry = function (k, v) {
|
|
1449
1567
|
if (typeof v === 'object' && v !== null && Object.keys(v).length === 1) {
|
|
1450
|
-
var
|
|
1568
|
+
var _a = Object.entries(v)[0], op = _a[0], val = _a[1];
|
|
1451
1569
|
subParts.push(addCondition(k, op, val));
|
|
1452
1570
|
}
|
|
1453
1571
|
else if (Array.isArray(v) && v.length >= 2 && typeof v[0] === 'string') {
|
|
1454
|
-
var
|
|
1572
|
+
var _b = v, op = _b[0], val = _b[1];
|
|
1455
1573
|
subParts.push(addCondition(k, op, val));
|
|
1456
1574
|
}
|
|
1457
1575
|
else if (typeof v === 'object' && v !== null) {
|
|
@@ -1462,6 +1580,18 @@ var ConditionBuilder = /** @class */ (function (_super) {
|
|
|
1462
1580
|
else {
|
|
1463
1581
|
subParts.push(addCondition(k, '=', v));
|
|
1464
1582
|
}
|
|
1583
|
+
};
|
|
1584
|
+
// Process non-numeric keys first to preserve intuitive insertion order for params
|
|
1585
|
+
for (var _i = 0, nonNumeric_1 = nonNumeric; _i < nonNumeric_1.length; _i++) {
|
|
1586
|
+
var _a = nonNumeric_1[_i], k = _a[0], v = _a[1];
|
|
1587
|
+
processEntry(k, v);
|
|
1588
|
+
}
|
|
1589
|
+
// Then process numeric keys (treated as grouped OR conditions)
|
|
1590
|
+
for (var _b = 0, numeric_1 = numeric; _b < numeric_1.length; _b++) {
|
|
1591
|
+
var _c = numeric_1[_b]; _c[0]; var v = _c[1];
|
|
1592
|
+
var sub = _this.buildBooleanJoinedConditions(v, false, params);
|
|
1593
|
+
if (sub)
|
|
1594
|
+
subParts.push(sub);
|
|
1465
1595
|
}
|
|
1466
1596
|
return subParts.join(" ".concat(mode ? 'AND' : 'OR', " "));
|
|
1467
1597
|
};
|
|
@@ -1598,13 +1728,12 @@ var PaginationBuilder = /** @class */ (function (_super) {
|
|
|
1598
1728
|
*/
|
|
1599
1729
|
PaginationBuilder.prototype.buildPaginationClause = function (pagination) {
|
|
1600
1730
|
var _this = this;
|
|
1601
|
-
var _a;
|
|
1602
1731
|
var sql = "";
|
|
1603
1732
|
/* -------- ORDER BY -------- */
|
|
1604
1733
|
if (pagination === null || pagination === void 0 ? void 0 : pagination[C6Constants.ORDER]) {
|
|
1605
1734
|
var orderParts = [];
|
|
1606
|
-
for (var _i = 0,
|
|
1607
|
-
var
|
|
1735
|
+
for (var _i = 0, _a = Object.entries(pagination[C6Constants.ORDER]); _i < _a.length; _i++) {
|
|
1736
|
+
var _b = _a[_i], key = _b[0], val = _b[1];
|
|
1608
1737
|
// FUNCTION CALL: val is an array of args
|
|
1609
1738
|
if (Array.isArray(val)) {
|
|
1610
1739
|
var args = val
|
|
@@ -1623,9 +1752,16 @@ var PaginationBuilder = /** @class */ (function (_super) {
|
|
|
1623
1752
|
/* -------- LIMIT / OFFSET -------- */
|
|
1624
1753
|
if ((pagination === null || pagination === void 0 ? void 0 : pagination[C6Constants.LIMIT]) != null) {
|
|
1625
1754
|
var lim = parseInt(pagination[C6Constants.LIMIT], 10);
|
|
1626
|
-
var
|
|
1627
|
-
var
|
|
1628
|
-
|
|
1755
|
+
var pageRaw = pagination[C6Constants.PAGE];
|
|
1756
|
+
var pageParsed = parseInt(pageRaw !== null && pageRaw !== void 0 ? pageRaw : 1, 10);
|
|
1757
|
+
var page = isFinite(pageParsed) && pageParsed > 1 ? pageParsed : 1;
|
|
1758
|
+
if (page === 1) {
|
|
1759
|
+
sql += " LIMIT ".concat(lim);
|
|
1760
|
+
}
|
|
1761
|
+
else {
|
|
1762
|
+
var offset = (page - 1) * lim;
|
|
1763
|
+
sql += " LIMIT ".concat(offset, ", ").concat(lim);
|
|
1764
|
+
}
|
|
1629
1765
|
}
|
|
1630
1766
|
this.config.verbose && console.log("[PAGINATION] ".concat(sql.trim()));
|
|
1631
1767
|
return sql;
|
|
@@ -1643,6 +1779,10 @@ var SelectQueryBuilder = /** @class */ (function (_super) {
|
|
|
1643
1779
|
var _a;
|
|
1644
1780
|
if (isSubSelect === void 0) { isSubSelect = false; }
|
|
1645
1781
|
this.aliasMap = {};
|
|
1782
|
+
// reset any previously collected SELECT aliases (from AggregateBuilder)
|
|
1783
|
+
// @ts-ignore
|
|
1784
|
+
if (this.selectAliases && this.selectAliases.clear)
|
|
1785
|
+
this.selectAliases.clear();
|
|
1646
1786
|
var args = this.request;
|
|
1647
1787
|
this.initAlias(table, args.JOIN);
|
|
1648
1788
|
var params = this.useNamedParams ? {} : [];
|
|
@@ -1696,9 +1836,10 @@ var UpdateQueryBuilder = /** @class */ (function (_super) {
|
|
|
1696
1836
|
if (!(C6C.UPDATE in this.request)) {
|
|
1697
1837
|
throw new Error("No update data provided in the request.");
|
|
1698
1838
|
}
|
|
1699
|
-
var setClauses = Object.entries(this.request[C6C.UPDATE])
|
|
1839
|
+
var setClauses = Object.entries(this.request[C6C.UPDATE])
|
|
1840
|
+
.map(function (_a) {
|
|
1700
1841
|
var col = _a[0], val = _a[1];
|
|
1701
|
-
return _this.addParam(params, col, val);
|
|
1842
|
+
return "`".concat(col, "` = ").concat(_this.addParam(params, col, val));
|
|
1702
1843
|
});
|
|
1703
1844
|
sql += " SET ".concat(setClauses.join(', '));
|
|
1704
1845
|
if (args.WHERE) {
|
|
@@ -1730,6 +1871,14 @@ var SqlExecutor = /** @class */ (function (_super) {
|
|
|
1730
1871
|
case 0:
|
|
1731
1872
|
TABLE_NAME = this.config.restModel.TABLE_NAME;
|
|
1732
1873
|
method = this.config.requestMethod;
|
|
1874
|
+
// Normalize singular T-shaped requests into complex ORM shape (GET/PUT/DELETE)
|
|
1875
|
+
try {
|
|
1876
|
+
this.request = normalizeSingularRequest(method, this.request, this.config.restModel, undefined);
|
|
1877
|
+
}
|
|
1878
|
+
catch (e) {
|
|
1879
|
+
// Surface normalization errors early
|
|
1880
|
+
throw e;
|
|
1881
|
+
}
|
|
1733
1882
|
this.config.verbose && console.log("[SQL EXECUTOR] \u25B6\uFE0F Executing ".concat(method, " on table \"").concat(TABLE_NAME, "\""));
|
|
1734
1883
|
this.config.verbose && console.log("[SQL EXECUTOR] \uD83E\uDDE9 Request:", this.request);
|
|
1735
1884
|
_a = method;
|
|
@@ -2134,6 +2283,7 @@ exports.isLocal = isLocal;
|
|
|
2134
2283
|
exports.isNode = isNode;
|
|
2135
2284
|
exports.isTest = isTest;
|
|
2136
2285
|
exports.isVerbose = isVerbose;
|
|
2286
|
+
exports.normalizeSingularRequest = normalizeSingularRequest;
|
|
2137
2287
|
exports.onError = onError;
|
|
2138
2288
|
exports.onSuccess = onSuccess;
|
|
2139
2289
|
exports.removeInvalidKeys = removeInvalidKeys;
|