@carbonorm/carbonnode 3.8.4 → 3.9.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/README.md +48 -1
- package/dist/api/C6Constants.d.ts +4 -0
- package/dist/api/orm/builders/AggregateBuilder.d.ts +2 -1
- package/dist/api/orm/builders/ConditionBuilder.d.ts +3 -0
- package/dist/api/orm/builders/JoinBuilder.d.ts +8 -0
- package/dist/api/orm/builders/PaginationBuilder.d.ts +1 -1
- package/dist/api/orm/queries/DeleteQueryBuilder.d.ts +2 -0
- package/dist/api/orm/queries/SelectQueryBuilder.d.ts +1 -0
- package/dist/api/orm/queries/UpdateQueryBuilder.d.ts +2 -0
- package/dist/api/orm/queryHelpers.d.ts +5 -0
- package/dist/index.cjs.js +364 -112
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +362 -113
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/fixtures/c6.fixture.ts +39 -0
- package/src/__tests__/fixtures/pu.fixture.ts +72 -0
- package/src/__tests__/sakila-db/C6.js +1 -1
- package/src/__tests__/sakila-db/C6.ts +1 -1
- package/src/__tests__/sqlBuilders.complex.test.ts +199 -1
- package/src/api/C6Constants.ts +2 -0
- package/src/api/orm/builders/AggregateBuilder.ts +39 -2
- package/src/api/orm/builders/ConditionBuilder.ts +66 -4
- package/src/api/orm/builders/JoinBuilder.ts +117 -6
- package/src/api/orm/builders/PaginationBuilder.ts +12 -2
- package/src/api/orm/queries/DeleteQueryBuilder.ts +5 -0
- package/src/api/orm/queries/SelectQueryBuilder.ts +6 -2
- package/src/api/orm/queries/UpdateQueryBuilder.ts +6 -1
- package/src/api/orm/queryHelpers.ts +59 -0
package/dist/index.cjs.js
CHANGED
|
@@ -61,6 +61,7 @@ var C6Constants = {
|
|
|
61
61
|
INNER: 'INNER',
|
|
62
62
|
INTERVAL: 'INTERVAL',
|
|
63
63
|
JOIN: 'JOIN',
|
|
64
|
+
FROM: 'FROM',
|
|
64
65
|
LEFT: 'LEFT',
|
|
65
66
|
LEFT_OUTER: 'LEFT_OUTER',
|
|
66
67
|
LESS_THAN: '<',
|
|
@@ -92,6 +93,7 @@ var C6Constants = {
|
|
|
92
93
|
SECOND: 'SECOND',
|
|
93
94
|
SECOND_MICROSECOND: 'SECOND_MICROSECOND',
|
|
94
95
|
SELECT: 'SELECT',
|
|
96
|
+
SUBSELECT: 'SUBSELECT',
|
|
95
97
|
// MySQL Spatial Functions
|
|
96
98
|
ST_AREA: 'ST_Area',
|
|
97
99
|
ST_ASBINARY: 'ST_AsBinary',
|
|
@@ -1254,9 +1256,16 @@ var AggregateBuilder = /** @class */ (function (_super) {
|
|
|
1254
1256
|
_this.selectAliases = new Set();
|
|
1255
1257
|
return _this;
|
|
1256
1258
|
}
|
|
1257
|
-
|
|
1259
|
+
// Overridden in ConditionBuilder where alias tracking is available.
|
|
1260
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1261
|
+
AggregateBuilder.prototype.assertValidIdentifier = function (_identifier, _context) {
|
|
1262
|
+
// no-op placeholder for subclasses that do not implement alias validation
|
|
1263
|
+
};
|
|
1264
|
+
AggregateBuilder.prototype.buildAggregateField = function (field, params) {
|
|
1258
1265
|
var _this = this;
|
|
1266
|
+
var _a, _b;
|
|
1259
1267
|
if (typeof field === 'string') {
|
|
1268
|
+
this.assertValidIdentifier(field, 'SELECT field');
|
|
1260
1269
|
return field;
|
|
1261
1270
|
}
|
|
1262
1271
|
if (!Array.isArray(field) || field.length === 0) {
|
|
@@ -1269,8 +1278,33 @@ var AggregateBuilder = /** @class */ (function (_super) {
|
|
|
1269
1278
|
args.pop();
|
|
1270
1279
|
}
|
|
1271
1280
|
var F = String(fn).toUpperCase();
|
|
1281
|
+
if (F === C6C.SUBSELECT) {
|
|
1282
|
+
if (!params) {
|
|
1283
|
+
throw new Error('Scalar subselects in SELECT require parameter tracking.');
|
|
1284
|
+
}
|
|
1285
|
+
var subRequest = args[0];
|
|
1286
|
+
var subSql = (_b = (_a = this).buildScalarSubSelect) === null || _b === void 0 ? void 0 : _b.call(_a, subRequest, params);
|
|
1287
|
+
if (!subSql) {
|
|
1288
|
+
throw new Error('Failed to build scalar subselect.');
|
|
1289
|
+
}
|
|
1290
|
+
var expr_1 = subSql;
|
|
1291
|
+
if (alias) {
|
|
1292
|
+
this.selectAliases.add(alias);
|
|
1293
|
+
expr_1 += " AS ".concat(alias);
|
|
1294
|
+
}
|
|
1295
|
+
this.config.verbose && console.log("[SELECT] ".concat(expr_1));
|
|
1296
|
+
return expr_1;
|
|
1297
|
+
}
|
|
1272
1298
|
var argList = args
|
|
1273
|
-
.map(function (arg) {
|
|
1299
|
+
.map(function (arg) {
|
|
1300
|
+
if (Array.isArray(arg))
|
|
1301
|
+
return _this.buildAggregateField(arg, params);
|
|
1302
|
+
if (typeof arg === 'string') {
|
|
1303
|
+
_this.assertValidIdentifier(arg, 'SELECT expression');
|
|
1304
|
+
return arg;
|
|
1305
|
+
}
|
|
1306
|
+
return String(arg);
|
|
1307
|
+
})
|
|
1274
1308
|
.join(', ');
|
|
1275
1309
|
var expr;
|
|
1276
1310
|
if (F === 'DISTINCT') {
|
|
@@ -1289,11 +1323,91 @@ var AggregateBuilder = /** @class */ (function (_super) {
|
|
|
1289
1323
|
return AggregateBuilder;
|
|
1290
1324
|
}(Executor));
|
|
1291
1325
|
|
|
1326
|
+
// Alias a table name with a given alias
|
|
1327
|
+
var DERIVED_TABLE_PREFIX = '__c6DerivedTable__';
|
|
1328
|
+
var DERIVED_ID_SYMBOL = Symbol('c6DerivedTableId');
|
|
1329
|
+
var derivedTableLookup = new Map();
|
|
1330
|
+
var derivedTableReverseLookup = new WeakMap();
|
|
1331
|
+
var derivedTableCounter = 0;
|
|
1332
|
+
var isDerivedTableKey = function (key) {
|
|
1333
|
+
return typeof key === 'string' && key.startsWith(DERIVED_TABLE_PREFIX);
|
|
1334
|
+
};
|
|
1335
|
+
var resolveDerivedTable = function (key) {
|
|
1336
|
+
return derivedTableLookup.get(key);
|
|
1337
|
+
};
|
|
1338
|
+
var derivedTable = function (spec) {
|
|
1339
|
+
if (!spec || typeof spec !== 'object') {
|
|
1340
|
+
throw new Error('Derived table definition must be an object.');
|
|
1341
|
+
}
|
|
1342
|
+
var aliasRaw = spec[C6C.AS];
|
|
1343
|
+
if (typeof aliasRaw !== 'string' || aliasRaw.trim() === '') {
|
|
1344
|
+
throw new Error('Derived tables require a non-empty alias via C6C.AS.');
|
|
1345
|
+
}
|
|
1346
|
+
if (!spec[C6C.SUBSELECT] || typeof spec[C6C.SUBSELECT] !== 'object') {
|
|
1347
|
+
throw new Error('Derived tables require a nested SELECT payload under C6C.SUBSELECT.');
|
|
1348
|
+
}
|
|
1349
|
+
var id = derivedTableReverseLookup.get(spec);
|
|
1350
|
+
if (!id) {
|
|
1351
|
+
id = "".concat(DERIVED_TABLE_PREFIX).concat(++derivedTableCounter);
|
|
1352
|
+
derivedTableReverseLookup.set(spec, id);
|
|
1353
|
+
derivedTableLookup.set(id, spec);
|
|
1354
|
+
Object.defineProperty(spec, DERIVED_ID_SYMBOL, {
|
|
1355
|
+
value: id,
|
|
1356
|
+
configurable: false,
|
|
1357
|
+
enumerable: false,
|
|
1358
|
+
writable: false
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
1361
|
+
var alias = aliasRaw.trim();
|
|
1362
|
+
derivedTableLookup.set(id, spec);
|
|
1363
|
+
Object.defineProperty(spec, 'toString', {
|
|
1364
|
+
value: function () { return "".concat(id, " ").concat(alias); },
|
|
1365
|
+
configurable: true,
|
|
1366
|
+
enumerable: false,
|
|
1367
|
+
writable: true
|
|
1368
|
+
});
|
|
1369
|
+
return spec;
|
|
1370
|
+
};
|
|
1371
|
+
var A = function (tableName, alias) {
|
|
1372
|
+
return "".concat(tableName, " ").concat(alias);
|
|
1373
|
+
};
|
|
1374
|
+
// Qualify a column constant (e.g. 'property_units.parcel_id') to an alias
|
|
1375
|
+
var F = function (qualifiedCol, alias) {
|
|
1376
|
+
return "".concat(alias, ".").concat(qualifiedCol.split('.').pop());
|
|
1377
|
+
};
|
|
1378
|
+
// Equal join condition using full-qualified column constants
|
|
1379
|
+
var fieldEq = function (leftCol, rightCol, leftAlias, rightAlias) {
|
|
1380
|
+
var _a;
|
|
1381
|
+
return (_a = {},
|
|
1382
|
+
_a[F(leftCol, leftAlias)] = F(rightCol, rightAlias),
|
|
1383
|
+
_a);
|
|
1384
|
+
};
|
|
1385
|
+
// ST_Distance_Sphere for aliased fields
|
|
1386
|
+
var distSphere = function (fromCol, toCol, fromAlias, toAlias) {
|
|
1387
|
+
return [C6C.ST_DISTANCE_SPHERE, F(fromCol, fromAlias), F(toCol, toAlias)];
|
|
1388
|
+
};
|
|
1389
|
+
// Build a bounding-box expression.
|
|
1390
|
+
//
|
|
1391
|
+
// Arguments must be provided in `(minLng, minLat, maxLng, maxLat)` order. The
|
|
1392
|
+
// helper does not attempt to swap or validate coordinates; if a minimum value
|
|
1393
|
+
// is greater than its corresponding maximum value, MySQL's `ST_MakeEnvelope`
|
|
1394
|
+
// returns `NULL`.
|
|
1395
|
+
var bbox = function (minLng, minLat, maxLng, maxLat) {
|
|
1396
|
+
return [C6C.ST_SRID, [C6C.ST_MAKEENVELOPE,
|
|
1397
|
+
[C6C.ST_POINT, minLng, minLat],
|
|
1398
|
+
[C6C.ST_POINT, maxLng, maxLat]], 4326];
|
|
1399
|
+
};
|
|
1400
|
+
// ST_Contains for map envelope/shape queries
|
|
1401
|
+
var stContains = function (envelope, shape) {
|
|
1402
|
+
return [C6C.ST_CONTAINS, envelope, shape];
|
|
1403
|
+
};
|
|
1404
|
+
|
|
1292
1405
|
var ConditionBuilder = /** @class */ (function (_super) {
|
|
1293
1406
|
tslib.__extends(ConditionBuilder, _super);
|
|
1294
1407
|
function ConditionBuilder() {
|
|
1295
1408
|
var _this = _super !== null && _super.apply(this, arguments) || this;
|
|
1296
1409
|
_this.aliasMap = {};
|
|
1410
|
+
_this.derivedAliases = new Set();
|
|
1297
1411
|
_this.OPERATORS = new Set([
|
|
1298
1412
|
C6C.EQUAL, C6C.NOT_EQUAL, C6C.LESS_THAN, C6C.LESS_THAN_OR_EQUAL_TO,
|
|
1299
1413
|
C6C.GREATER_THAN, C6C.GREATER_THAN_OR_EQUAL_TO,
|
|
@@ -1318,21 +1432,43 @@ var ConditionBuilder = /** @class */ (function (_super) {
|
|
|
1318
1432
|
ConditionBuilder.prototype.initAlias = function (baseTable, joins) {
|
|
1319
1433
|
var _a;
|
|
1320
1434
|
this.aliasMap = (_a = {}, _a[baseTable] = baseTable, _a);
|
|
1435
|
+
this.derivedAliases = new Set();
|
|
1321
1436
|
if (!joins)
|
|
1322
1437
|
return;
|
|
1323
1438
|
for (var joinType in joins) {
|
|
1324
1439
|
for (var raw in joins[joinType]) {
|
|
1325
|
-
var _b = raw.split(
|
|
1326
|
-
|
|
1440
|
+
var _b = raw.trim().split(/\s+/, 2), table = _b[0], alias = _b[1];
|
|
1441
|
+
if (!table)
|
|
1442
|
+
continue;
|
|
1443
|
+
this.registerAlias(alias || table, table);
|
|
1327
1444
|
}
|
|
1328
1445
|
}
|
|
1329
1446
|
};
|
|
1447
|
+
ConditionBuilder.prototype.registerAlias = function (alias, table) {
|
|
1448
|
+
this.aliasMap[alias] = table;
|
|
1449
|
+
if (isDerivedTableKey(table)) {
|
|
1450
|
+
this.derivedAliases.add(alias);
|
|
1451
|
+
}
|
|
1452
|
+
};
|
|
1453
|
+
ConditionBuilder.prototype.assertValidIdentifier = function (identifier, context) {
|
|
1454
|
+
if (typeof identifier !== 'string')
|
|
1455
|
+
return;
|
|
1456
|
+
if (!identifier.includes('.'))
|
|
1457
|
+
return;
|
|
1458
|
+
var alias = identifier.split('.', 2)[0];
|
|
1459
|
+
if (!(alias in this.aliasMap)) {
|
|
1460
|
+
throw new Error("Unknown table or alias '".concat(alias, "' referenced in ").concat(context, ": '").concat(identifier, "'."));
|
|
1461
|
+
}
|
|
1462
|
+
};
|
|
1330
1463
|
ConditionBuilder.prototype.isColumnRef = function (ref) {
|
|
1331
1464
|
var _a, _b;
|
|
1332
1465
|
if (typeof ref !== 'string' || !ref.includes('.'))
|
|
1333
1466
|
return false;
|
|
1334
1467
|
var _c = ref.split('.', 2), prefix = _c[0], column = _c[1];
|
|
1335
1468
|
var tableName = this.aliasMap[prefix] || prefix;
|
|
1469
|
+
if (isDerivedTableKey(tableName) || this.derivedAliases.has(prefix)) {
|
|
1470
|
+
return true;
|
|
1471
|
+
}
|
|
1336
1472
|
var table = (_b = (_a = this.config.C6) === null || _a === void 0 ? void 0 : _a.TABLES) === null || _b === void 0 ? void 0 : _b[tableName];
|
|
1337
1473
|
if (!table)
|
|
1338
1474
|
return false;
|
|
@@ -1361,6 +1497,9 @@ var ConditionBuilder = /** @class */ (function (_super) {
|
|
|
1361
1497
|
}
|
|
1362
1498
|
var _e = val.split('.'), prefix = _e[0], column = _e[1];
|
|
1363
1499
|
var tableName = (_b = this.aliasMap[prefix]) !== null && _b !== void 0 ? _b : prefix;
|
|
1500
|
+
if (isDerivedTableKey(tableName) || this.derivedAliases.has(prefix)) {
|
|
1501
|
+
return true;
|
|
1502
|
+
}
|
|
1364
1503
|
var table = (_d = (_c = this.config.C6) === null || _c === void 0 ? void 0 : _c.TABLES) === null || _d === void 0 ? void 0 : _d[tableName];
|
|
1365
1504
|
if (!table || !table.COLUMNS)
|
|
1366
1505
|
return false;
|
|
@@ -1403,6 +1542,26 @@ var ConditionBuilder = /** @class */ (function (_super) {
|
|
|
1403
1542
|
// Normalize common variants
|
|
1404
1543
|
var valueNorm = (value === C6C.NULL) ? null : value;
|
|
1405
1544
|
var displayOp = typeof op === 'string' ? op.replace('_', ' ') : op;
|
|
1545
|
+
var extractSubSelect = function (input) {
|
|
1546
|
+
if (Array.isArray(input) && input.length >= 2 && input[0] === C6C.SUBSELECT) {
|
|
1547
|
+
return input[1];
|
|
1548
|
+
}
|
|
1549
|
+
if (input && typeof input === 'object' && C6C.SUBSELECT in input) {
|
|
1550
|
+
return input[C6C.SUBSELECT];
|
|
1551
|
+
}
|
|
1552
|
+
return undefined;
|
|
1553
|
+
};
|
|
1554
|
+
var rightSubSelectPayload = extractSubSelect(valueNorm);
|
|
1555
|
+
var buildSubSelect = function (payload) {
|
|
1556
|
+
if (!payload)
|
|
1557
|
+
return undefined;
|
|
1558
|
+
var builder = _this.buildScalarSubSelect;
|
|
1559
|
+
if (typeof builder !== 'function') {
|
|
1560
|
+
throw new Error('Scalar subselect handling requires JoinBuilder context.');
|
|
1561
|
+
}
|
|
1562
|
+
return builder.call(_this, payload, params);
|
|
1563
|
+
};
|
|
1564
|
+
var rightSubSelectSql = buildSubSelect(rightSubSelectPayload);
|
|
1406
1565
|
// Support function-based expressions like [C6C.ST_DISTANCE_SPHERE, col1, col2]
|
|
1407
1566
|
if (typeof column === 'string' &&
|
|
1408
1567
|
_this.OPERATORS.has(column) &&
|
|
@@ -1429,7 +1588,7 @@ var ConditionBuilder = /** @class */ (function (_super) {
|
|
|
1429
1588
|
var leftIsCol = _this.isColumnRef(column);
|
|
1430
1589
|
var leftIsRef = _this.isTableReference(column);
|
|
1431
1590
|
var rightIsCol = typeof value === 'string' && _this.isColumnRef(value);
|
|
1432
|
-
if (!leftIsCol && !leftIsRef && !rightIsCol) {
|
|
1591
|
+
if (!leftIsCol && !leftIsRef && !rightIsCol && !rightSubSelectSql) {
|
|
1433
1592
|
throw new Error("Potential SQL injection detected: '".concat(column, " ").concat(op, " ").concat(value, "'"));
|
|
1434
1593
|
}
|
|
1435
1594
|
_this.validateOperator(op);
|
|
@@ -1462,6 +1621,13 @@ var ConditionBuilder = /** @class */ (function (_super) {
|
|
|
1462
1621
|
return matchClause;
|
|
1463
1622
|
}
|
|
1464
1623
|
if ((op === C6C.IN || op === C6C.NOT_IN) && Array.isArray(value)) {
|
|
1624
|
+
if (rightSubSelectSql) {
|
|
1625
|
+
if (!leftIsRef) {
|
|
1626
|
+
throw new Error("IN operator requires a table reference as the left operand. Column '".concat(column, "' is not a valid table reference."));
|
|
1627
|
+
}
|
|
1628
|
+
var normalized_1 = op.replace('_', ' ');
|
|
1629
|
+
return "( ".concat(column, " ").concat(normalized_1, " ").concat(rightSubSelectSql, " )");
|
|
1630
|
+
}
|
|
1465
1631
|
var placeholders = value.map(function (v) {
|
|
1466
1632
|
return _this.isColumnRef(v) ? v : _this.addParam(params, column, v);
|
|
1467
1633
|
}).join(', ');
|
|
@@ -1481,10 +1647,13 @@ var ConditionBuilder = /** @class */ (function (_super) {
|
|
|
1481
1647
|
}
|
|
1482
1648
|
return "(".concat(column, ") ").concat(op.replace('_', ' '), " ").concat(_this.addParam(params, column, start), " AND ").concat(_this.addParam(params, column, end));
|
|
1483
1649
|
}
|
|
1484
|
-
var rightIsRef = _this.isTableReference(value);
|
|
1650
|
+
var rightIsRef = rightSubSelectSql ? false : _this.isTableReference(value);
|
|
1485
1651
|
if (leftIsRef && rightIsRef) {
|
|
1486
1652
|
return "(".concat(column, ") ").concat(displayOp, " ").concat(value);
|
|
1487
1653
|
}
|
|
1654
|
+
if (leftIsRef && rightSubSelectSql) {
|
|
1655
|
+
return "(".concat(column, ") ").concat(displayOp, " ").concat(rightSubSelectSql);
|
|
1656
|
+
}
|
|
1488
1657
|
if (leftIsRef && !rightIsRef) {
|
|
1489
1658
|
return "(".concat(column, ") ").concat(displayOp, " ").concat(_this.addParam(params, column, valueNorm));
|
|
1490
1659
|
}
|
|
@@ -1580,85 +1749,117 @@ var JoinBuilder = /** @class */ (function (_super) {
|
|
|
1580
1749
|
function JoinBuilder() {
|
|
1581
1750
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
1582
1751
|
}
|
|
1752
|
+
JoinBuilder.prototype.createSelectBuilder = function (_request) {
|
|
1753
|
+
throw new Error('Subclasses must implement createSelectBuilder to support derived table serialization.');
|
|
1754
|
+
};
|
|
1583
1755
|
JoinBuilder.prototype.buildJoinClauses = function (joinArgs, params) {
|
|
1584
1756
|
var sql = '';
|
|
1585
|
-
|
|
1757
|
+
var _loop_1 = function (joinType) {
|
|
1586
1758
|
var joinKind = joinType.replace('_', ' ').toUpperCase();
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1759
|
+
var entries = [];
|
|
1760
|
+
var joinSection = joinArgs[joinType];
|
|
1761
|
+
if (joinSection instanceof Map) {
|
|
1762
|
+
joinSection.forEach(function (value, key) {
|
|
1763
|
+
entries.push([key, value]);
|
|
1764
|
+
});
|
|
1765
|
+
}
|
|
1766
|
+
else {
|
|
1767
|
+
for (var raw in joinSection) {
|
|
1768
|
+
entries.push([raw, joinSection[raw]]);
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
|
|
1772
|
+
var _a = entries_1[_i], rawKey = _a[0], conditions = _a[1];
|
|
1773
|
+
var raw = typeof rawKey === 'string' ? rawKey : String(rawKey);
|
|
1774
|
+
var _b = raw.trim().split(/\s+/, 2), table = _b[0], aliasCandidate = _b[1];
|
|
1775
|
+
if (!table)
|
|
1776
|
+
continue;
|
|
1777
|
+
if (isDerivedTableKey(table)) {
|
|
1778
|
+
var derived = resolveDerivedTable(table);
|
|
1779
|
+
if (!derived) {
|
|
1780
|
+
throw new Error("Derived table '".concat(table, "' was not registered. Wrap the object with derivedTable(...) before using it in JOIN."));
|
|
1781
|
+
}
|
|
1782
|
+
var configuredAliasRaw = derived[C6C.AS];
|
|
1783
|
+
var configuredAlias = typeof configuredAliasRaw === 'string' ? configuredAliasRaw.trim() : '';
|
|
1784
|
+
var alias = (aliasCandidate !== null && aliasCandidate !== void 0 ? aliasCandidate : configuredAlias).trim();
|
|
1785
|
+
if (!alias) {
|
|
1786
|
+
throw new Error('Derived tables require an alias via C6C.AS.');
|
|
1787
|
+
}
|
|
1788
|
+
this_1.registerAlias(alias, table);
|
|
1789
|
+
var subRequest = derived[C6C.SUBSELECT];
|
|
1790
|
+
if (!subRequest || typeof subRequest !== 'object') {
|
|
1791
|
+
throw new Error('Derived tables must include a C6C.SUBSELECT payload.');
|
|
1792
|
+
}
|
|
1793
|
+
var fromTable = subRequest[C6C.FROM];
|
|
1794
|
+
if (typeof fromTable !== 'string' || fromTable.trim() === '') {
|
|
1795
|
+
throw new Error('Derived table subselects require a base table defined with C6C.FROM.');
|
|
1796
|
+
}
|
|
1797
|
+
var subBuilder = this_1.createSelectBuilder(subRequest);
|
|
1798
|
+
var _c = subBuilder.build(fromTable, true), subSql = _c.sql, subParams = _c.params;
|
|
1799
|
+
var normalizedSql = this_1.integrateSubSelectParams(subSql, subParams, params);
|
|
1800
|
+
var formatted = normalizedSql.trim().split('\n').map(function (line) { return " ".concat(line); }).join('\n');
|
|
1801
|
+
var joinSql = "(\n".concat(formatted, "\n) AS `").concat(alias, "`");
|
|
1802
|
+
var onClause = this_1.buildBooleanJoinedConditions(conditions, true, params);
|
|
1803
|
+
sql += " ".concat(joinKind, " JOIN ").concat(joinSql);
|
|
1804
|
+
if (onClause) {
|
|
1805
|
+
sql += " ON ".concat(onClause);
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
else {
|
|
1809
|
+
var alias = aliasCandidate;
|
|
1810
|
+
if (alias) {
|
|
1811
|
+
this_1.registerAlias(alias, table);
|
|
1812
|
+
}
|
|
1813
|
+
var joinSql = alias ? "`".concat(table, "` AS `").concat(alias, "`") : "`".concat(table, "`");
|
|
1814
|
+
var onClause = this_1.buildBooleanJoinedConditions(conditions, true, params);
|
|
1815
|
+
sql += " ".concat(joinKind, " JOIN ").concat(joinSql);
|
|
1816
|
+
if (onClause) {
|
|
1817
|
+
sql += " ON ".concat(onClause);
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1593
1820
|
}
|
|
1821
|
+
};
|
|
1822
|
+
var this_1 = this;
|
|
1823
|
+
for (var joinType in joinArgs) {
|
|
1824
|
+
_loop_1(joinType);
|
|
1594
1825
|
}
|
|
1595
1826
|
this.config.verbose && console.log("[JOIN] ".concat(sql.trim()));
|
|
1596
1827
|
return sql;
|
|
1597
1828
|
};
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
if (this.request.WHERE) {
|
|
1615
|
-
sql += this.buildWhereClause(this.request.WHERE, params);
|
|
1616
|
-
}
|
|
1617
|
-
return { sql: sql, params: params };
|
|
1618
|
-
};
|
|
1619
|
-
return DeleteQueryBuilder;
|
|
1620
|
-
}(JoinBuilder));
|
|
1621
|
-
|
|
1622
|
-
var PostQueryBuilder = /** @class */ (function (_super) {
|
|
1623
|
-
tslib.__extends(PostQueryBuilder, _super);
|
|
1624
|
-
function PostQueryBuilder() {
|
|
1625
|
-
return _super !== null && _super.apply(this, arguments) || this;
|
|
1626
|
-
}
|
|
1627
|
-
PostQueryBuilder.prototype.trimTablePrefix = function (table, column) {
|
|
1628
|
-
if (!column.includes('.'))
|
|
1629
|
-
return column;
|
|
1630
|
-
var _a = column.split('.', 2), prefix = _a[0], col = _a[1];
|
|
1631
|
-
if (prefix !== table) {
|
|
1632
|
-
throw new Error("Invalid prefixed column: '".concat(column, "'. Expected prefix '").concat(table, ".'"));
|
|
1829
|
+
JoinBuilder.prototype.integrateSubSelectParams = function (subSql, subParams, target) {
|
|
1830
|
+
var _a;
|
|
1831
|
+
if (!subParams)
|
|
1832
|
+
return subSql;
|
|
1833
|
+
if (this.useNamedParams) {
|
|
1834
|
+
var normalized = subSql;
|
|
1835
|
+
var extras = subParams;
|
|
1836
|
+
for (var _i = 0, _b = Object.keys(extras); _i < _b.length; _i++) {
|
|
1837
|
+
var key = _b[_i];
|
|
1838
|
+
var placeholder = this.addParam(target, '', extras[key]);
|
|
1839
|
+
var original = ":".concat(key);
|
|
1840
|
+
if (original !== placeholder) {
|
|
1841
|
+
normalized = normalized.split(original).join(placeholder);
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
return normalized;
|
|
1633
1845
|
}
|
|
1634
|
-
|
|
1846
|
+
(_a = target).push.apply(_a, subParams);
|
|
1847
|
+
return subSql;
|
|
1635
1848
|
};
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
var verb = C6C.REPLACE in this.request ? C6C.REPLACE : C6C.INSERT;
|
|
1640
|
-
var body = verb in this.request ? this.request[verb] : this.request;
|
|
1641
|
-
var keys = Object.keys(body);
|
|
1642
|
-
var params = [];
|
|
1643
|
-
var placeholders = [];
|
|
1644
|
-
for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
|
|
1645
|
-
var key = keys_1[_i];
|
|
1646
|
-
var value = body[key];
|
|
1647
|
-
var placeholder = this.addParam(params, key, value);
|
|
1648
|
-
placeholders.push(placeholder);
|
|
1849
|
+
JoinBuilder.prototype.buildScalarSubSelect = function (subRequest, params) {
|
|
1850
|
+
if (!subRequest || typeof subRequest !== 'object') {
|
|
1851
|
+
throw new Error('Scalar subselect requires a C6C.SUBSELECT object payload.');
|
|
1649
1852
|
}
|
|
1650
|
-
var
|
|
1651
|
-
if (
|
|
1652
|
-
|
|
1653
|
-
if (!Array.isArray(updateData)) {
|
|
1654
|
-
throw new Error("Update data must be an array of keys to update, got: ".concat(JSON.stringify(updateData)));
|
|
1655
|
-
}
|
|
1656
|
-
var updateClause = updateData.map(function (k) { return "`".concat(k, "` = VALUES(`").concat(k, "`)"); }).join(', ');
|
|
1657
|
-
sql += " ON DUPLICATE KEY UPDATE ".concat(updateClause);
|
|
1853
|
+
var fromTable = subRequest[C6C.FROM];
|
|
1854
|
+
if (typeof fromTable !== 'string' || fromTable.trim() === '') {
|
|
1855
|
+
throw new Error('Scalar subselects require a base table specified with C6C.FROM.');
|
|
1658
1856
|
}
|
|
1659
|
-
|
|
1857
|
+
var subBuilder = this.createSelectBuilder(subRequest);
|
|
1858
|
+
var _a = subBuilder.build(fromTable, true), subSql = _a.sql, subParams = _a.params;
|
|
1859
|
+
var normalized = this.integrateSubSelectParams(subSql, subParams, params).trim();
|
|
1860
|
+
return "(".concat(normalized, ")");
|
|
1660
1861
|
};
|
|
1661
|
-
return
|
|
1862
|
+
return JoinBuilder;
|
|
1662
1863
|
}(ConditionBuilder));
|
|
1663
1864
|
|
|
1664
1865
|
var PaginationBuilder = /** @class */ (function (_super) {
|
|
@@ -1679,7 +1880,7 @@ var PaginationBuilder = /** @class */ (function (_super) {
|
|
|
1679
1880
|
* }
|
|
1680
1881
|
* ```
|
|
1681
1882
|
*/
|
|
1682
|
-
PaginationBuilder.prototype.buildPaginationClause = function (pagination) {
|
|
1883
|
+
PaginationBuilder.prototype.buildPaginationClause = function (pagination, params) {
|
|
1683
1884
|
var _this = this;
|
|
1684
1885
|
var sql = "";
|
|
1685
1886
|
/* -------- ORDER BY -------- */
|
|
@@ -1687,10 +1888,21 @@ var PaginationBuilder = /** @class */ (function (_super) {
|
|
|
1687
1888
|
var orderParts = [];
|
|
1688
1889
|
for (var _i = 0, _a = Object.entries(pagination[C6Constants.ORDER]); _i < _a.length; _i++) {
|
|
1689
1890
|
var _b = _a[_i], key = _b[0], val = _b[1];
|
|
1891
|
+
if (typeof key === 'string' && key.includes('.')) {
|
|
1892
|
+
this.assertValidIdentifier(key, 'ORDER BY');
|
|
1893
|
+
}
|
|
1690
1894
|
// FUNCTION CALL: val is an array of args
|
|
1691
1895
|
if (Array.isArray(val)) {
|
|
1692
1896
|
var args = val
|
|
1693
|
-
.map(function (arg) {
|
|
1897
|
+
.map(function (arg) {
|
|
1898
|
+
if (Array.isArray(arg))
|
|
1899
|
+
return _this.buildAggregateField(arg, params);
|
|
1900
|
+
if (typeof arg === 'string' && arg.includes('.')) {
|
|
1901
|
+
_this.assertValidIdentifier(arg, 'ORDER BY argument');
|
|
1902
|
+
return arg;
|
|
1903
|
+
}
|
|
1904
|
+
return String(arg);
|
|
1905
|
+
})
|
|
1694
1906
|
.join(", ");
|
|
1695
1907
|
orderParts.push("".concat(key, "(").concat(args, ")"));
|
|
1696
1908
|
}
|
|
@@ -1727,6 +1939,9 @@ var SelectQueryBuilder = /** @class */ (function (_super) {
|
|
|
1727
1939
|
function SelectQueryBuilder() {
|
|
1728
1940
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
1729
1941
|
}
|
|
1942
|
+
SelectQueryBuilder.prototype.createSelectBuilder = function (request) {
|
|
1943
|
+
return new SelectQueryBuilder(this.config, request, this.useNamedParams);
|
|
1944
|
+
};
|
|
1730
1945
|
SelectQueryBuilder.prototype.build = function (table, isSubSelect) {
|
|
1731
1946
|
var _this = this;
|
|
1732
1947
|
var _a;
|
|
@@ -1741,7 +1956,7 @@ var SelectQueryBuilder = /** @class */ (function (_super) {
|
|
|
1741
1956
|
var params = this.useNamedParams ? {} : [];
|
|
1742
1957
|
var selectList = (_a = args.SELECT) !== null && _a !== void 0 ? _a : ['*'];
|
|
1743
1958
|
var selectFields = selectList
|
|
1744
|
-
.map(function (f) { return _this.buildAggregateField(f); })
|
|
1959
|
+
.map(function (f) { return _this.buildAggregateField(f, params); })
|
|
1745
1960
|
.join(', ');
|
|
1746
1961
|
var sql = "SELECT ".concat(selectFields, " FROM `").concat(table, "`");
|
|
1747
1962
|
if (args.JOIN) {
|
|
@@ -1760,7 +1975,7 @@ var SelectQueryBuilder = /** @class */ (function (_super) {
|
|
|
1760
1975
|
sql += " HAVING ".concat(this.buildBooleanJoinedConditions(args.HAVING, true, params));
|
|
1761
1976
|
}
|
|
1762
1977
|
if (args.PAGINATION) {
|
|
1763
|
-
sql += this.buildPaginationClause(args.PAGINATION);
|
|
1978
|
+
sql += this.buildPaginationClause(args.PAGINATION, params);
|
|
1764
1979
|
}
|
|
1765
1980
|
else if (!isSubSelect) {
|
|
1766
1981
|
sql += " LIMIT 100";
|
|
@@ -1771,11 +1986,80 @@ var SelectQueryBuilder = /** @class */ (function (_super) {
|
|
|
1771
1986
|
return SelectQueryBuilder;
|
|
1772
1987
|
}(PaginationBuilder));
|
|
1773
1988
|
|
|
1989
|
+
var DeleteQueryBuilder = /** @class */ (function (_super) {
|
|
1990
|
+
tslib.__extends(DeleteQueryBuilder, _super);
|
|
1991
|
+
function DeleteQueryBuilder() {
|
|
1992
|
+
return _super !== null && _super.apply(this, arguments) || this;
|
|
1993
|
+
}
|
|
1994
|
+
DeleteQueryBuilder.prototype.createSelectBuilder = function (request) {
|
|
1995
|
+
return new SelectQueryBuilder(this.config, request, this.useNamedParams);
|
|
1996
|
+
};
|
|
1997
|
+
DeleteQueryBuilder.prototype.build = function (table) {
|
|
1998
|
+
this.aliasMap = {};
|
|
1999
|
+
var params = this.useNamedParams ? {} : [];
|
|
2000
|
+
this.initAlias(table, this.request.JOIN);
|
|
2001
|
+
var sql = "DELETE `".concat(table, "` FROM `").concat(table, "`");
|
|
2002
|
+
if (this.request.JOIN) {
|
|
2003
|
+
sql += this.buildJoinClauses(this.request.JOIN, params);
|
|
2004
|
+
}
|
|
2005
|
+
if (this.request.WHERE) {
|
|
2006
|
+
sql += this.buildWhereClause(this.request.WHERE, params);
|
|
2007
|
+
}
|
|
2008
|
+
return { sql: sql, params: params };
|
|
2009
|
+
};
|
|
2010
|
+
return DeleteQueryBuilder;
|
|
2011
|
+
}(JoinBuilder));
|
|
2012
|
+
|
|
2013
|
+
var PostQueryBuilder = /** @class */ (function (_super) {
|
|
2014
|
+
tslib.__extends(PostQueryBuilder, _super);
|
|
2015
|
+
function PostQueryBuilder() {
|
|
2016
|
+
return _super !== null && _super.apply(this, arguments) || this;
|
|
2017
|
+
}
|
|
2018
|
+
PostQueryBuilder.prototype.trimTablePrefix = function (table, column) {
|
|
2019
|
+
if (!column.includes('.'))
|
|
2020
|
+
return column;
|
|
2021
|
+
var _a = column.split('.', 2), prefix = _a[0], col = _a[1];
|
|
2022
|
+
if (prefix !== table) {
|
|
2023
|
+
throw new Error("Invalid prefixed column: '".concat(column, "'. Expected prefix '").concat(table, ".'"));
|
|
2024
|
+
}
|
|
2025
|
+
return col;
|
|
2026
|
+
};
|
|
2027
|
+
PostQueryBuilder.prototype.build = function (table) {
|
|
2028
|
+
var _this = this;
|
|
2029
|
+
this.aliasMap = {};
|
|
2030
|
+
var verb = C6C.REPLACE in this.request ? C6C.REPLACE : C6C.INSERT;
|
|
2031
|
+
var body = verb in this.request ? this.request[verb] : this.request;
|
|
2032
|
+
var keys = Object.keys(body);
|
|
2033
|
+
var params = [];
|
|
2034
|
+
var placeholders = [];
|
|
2035
|
+
for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
|
|
2036
|
+
var key = keys_1[_i];
|
|
2037
|
+
var value = body[key];
|
|
2038
|
+
var placeholder = this.addParam(params, key, value);
|
|
2039
|
+
placeholders.push(placeholder);
|
|
2040
|
+
}
|
|
2041
|
+
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 )");
|
|
2042
|
+
if (C6C.UPDATE in this.request) {
|
|
2043
|
+
var updateData = this.request[C6C.UPDATE];
|
|
2044
|
+
if (!Array.isArray(updateData)) {
|
|
2045
|
+
throw new Error("Update data must be an array of keys to update, got: ".concat(JSON.stringify(updateData)));
|
|
2046
|
+
}
|
|
2047
|
+
var updateClause = updateData.map(function (k) { return "`".concat(k, "` = VALUES(`").concat(k, "`)"); }).join(', ');
|
|
2048
|
+
sql += " ON DUPLICATE KEY UPDATE ".concat(updateClause);
|
|
2049
|
+
}
|
|
2050
|
+
return { sql: sql, params: params };
|
|
2051
|
+
};
|
|
2052
|
+
return PostQueryBuilder;
|
|
2053
|
+
}(ConditionBuilder));
|
|
2054
|
+
|
|
1774
2055
|
var UpdateQueryBuilder = /** @class */ (function (_super) {
|
|
1775
2056
|
tslib.__extends(UpdateQueryBuilder, _super);
|
|
1776
2057
|
function UpdateQueryBuilder() {
|
|
1777
2058
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
1778
2059
|
}
|
|
2060
|
+
UpdateQueryBuilder.prototype.createSelectBuilder = function (request) {
|
|
2061
|
+
return new SelectQueryBuilder(this.config, request, this.useNamedParams);
|
|
2062
|
+
};
|
|
1779
2063
|
UpdateQueryBuilder.prototype.trimTablePrefix = function (table, column) {
|
|
1780
2064
|
if (!column.includes('.'))
|
|
1781
2065
|
return column;
|
|
@@ -1810,7 +2094,7 @@ var UpdateQueryBuilder = /** @class */ (function (_super) {
|
|
|
1810
2094
|
sql += this.buildWhereClause(args.WHERE, params);
|
|
1811
2095
|
}
|
|
1812
2096
|
if (args.PAGINATION) {
|
|
1813
|
-
sql += this.buildPaginationClause(args.PAGINATION);
|
|
2097
|
+
sql += this.buildPaginationClause(args.PAGINATION, params);
|
|
1814
2098
|
}
|
|
1815
2099
|
return { sql: sql, params: params };
|
|
1816
2100
|
};
|
|
@@ -2206,41 +2490,6 @@ function ExpressHandler(_a) {
|
|
|
2206
2490
|
}); };
|
|
2207
2491
|
}
|
|
2208
2492
|
|
|
2209
|
-
// Alias a table name with a given alias
|
|
2210
|
-
var A = function (tableName, alias) {
|
|
2211
|
-
return "".concat(tableName, " ").concat(alias);
|
|
2212
|
-
};
|
|
2213
|
-
// Qualify a column constant (e.g. 'property_units.parcel_id') to an alias
|
|
2214
|
-
var F = function (qualifiedCol, alias) {
|
|
2215
|
-
return "".concat(alias, ".").concat(qualifiedCol.split('.').pop());
|
|
2216
|
-
};
|
|
2217
|
-
// Equal join condition using full-qualified column constants
|
|
2218
|
-
var fieldEq = function (leftCol, rightCol, leftAlias, rightAlias) {
|
|
2219
|
-
var _a;
|
|
2220
|
-
return (_a = {},
|
|
2221
|
-
_a[F(leftCol, leftAlias)] = F(rightCol, rightAlias),
|
|
2222
|
-
_a);
|
|
2223
|
-
};
|
|
2224
|
-
// ST_Distance_Sphere for aliased fields
|
|
2225
|
-
var distSphere = function (fromCol, toCol, fromAlias, toAlias) {
|
|
2226
|
-
return [C6C.ST_DISTANCE_SPHERE, F(fromCol, fromAlias), F(toCol, toAlias)];
|
|
2227
|
-
};
|
|
2228
|
-
// Build a bounding-box expression.
|
|
2229
|
-
//
|
|
2230
|
-
// Arguments must be provided in `(minLng, minLat, maxLng, maxLat)` order. The
|
|
2231
|
-
// helper does not attempt to swap or validate coordinates; if a minimum value
|
|
2232
|
-
// is greater than its corresponding maximum value, MySQL's `ST_MakeEnvelope`
|
|
2233
|
-
// returns `NULL`.
|
|
2234
|
-
var bbox = function (minLng, minLat, maxLng, maxLat) {
|
|
2235
|
-
return [C6C.ST_SRID, [C6C.ST_MAKEENVELOPE,
|
|
2236
|
-
[C6C.ST_POINT, minLng, minLat],
|
|
2237
|
-
[C6C.ST_POINT, maxLng, maxLat]], 4326];
|
|
2238
|
-
};
|
|
2239
|
-
// ST_Contains for map envelope/shape queries
|
|
2240
|
-
var stContains = function (envelope, shape) {
|
|
2241
|
-
return [C6C.ST_CONTAINS, envelope, shape];
|
|
2242
|
-
};
|
|
2243
|
-
|
|
2244
2493
|
function determineRuntimeJsType(mysqlType) {
|
|
2245
2494
|
var base = mysqlType.toLowerCase().split('(')[0];
|
|
2246
2495
|
if ([
|
|
@@ -2369,6 +2618,7 @@ exports.checkCache = checkCache;
|
|
|
2369
2618
|
exports.clearCache = clearCache;
|
|
2370
2619
|
exports.convertForRequestBody = convertForRequestBody;
|
|
2371
2620
|
exports.convertHexIfBinary = convertHexIfBinary;
|
|
2621
|
+
exports.derivedTable = derivedTable;
|
|
2372
2622
|
exports.determineRuntimeJsType = determineRuntimeJsType;
|
|
2373
2623
|
exports.distSphere = distSphere;
|
|
2374
2624
|
exports.error = error;
|
|
@@ -2377,6 +2627,7 @@ exports.getEnvVar = getEnvVar;
|
|
|
2377
2627
|
exports.getPrimaryKeyTypes = getPrimaryKeyTypes;
|
|
2378
2628
|
exports.group = group;
|
|
2379
2629
|
exports.info = info;
|
|
2630
|
+
exports.isDerivedTableKey = isDerivedTableKey;
|
|
2380
2631
|
exports.isLocal = isLocal;
|
|
2381
2632
|
exports.isNode = isNode;
|
|
2382
2633
|
exports.isTest = isTest;
|
|
@@ -2386,6 +2637,7 @@ exports.onError = onError;
|
|
|
2386
2637
|
exports.onSuccess = onSuccess;
|
|
2387
2638
|
exports.removeInvalidKeys = removeInvalidKeys;
|
|
2388
2639
|
exports.removePrefixIfExists = removePrefixIfExists;
|
|
2640
|
+
exports.resolveDerivedTable = resolveDerivedTable;
|
|
2389
2641
|
exports.restOrm = restOrm;
|
|
2390
2642
|
exports.restRequest = restRequest;
|
|
2391
2643
|
exports.sortAndSerializeQueryObject = sortAndSerializeQueryObject;
|