@dbsp/adapter-pgsql 1.3.0 → 1.5.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 +4 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +627 -121
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -949,6 +949,42 @@ var init_ast_helpers = __esm({
|
|
|
949
949
|
}
|
|
950
950
|
});
|
|
951
951
|
|
|
952
|
+
// src/binding-registry.ts
|
|
953
|
+
function emittedBindName(name, naming) {
|
|
954
|
+
return naming.toDatabase(name);
|
|
955
|
+
}
|
|
956
|
+
function hasBindingName(bindingNames, name, naming) {
|
|
957
|
+
return bindingNames?.has(emittedBindName(name, naming)) ?? false;
|
|
958
|
+
}
|
|
959
|
+
function schemaForFromName(schemaName, fromName, bindingNames, naming) {
|
|
960
|
+
return hasBindingName(bindingNames, fromName, naming) ? void 0 : schemaName;
|
|
961
|
+
}
|
|
962
|
+
function withBindingName(bindingNames, name, naming) {
|
|
963
|
+
const next = new Set(bindingNames ?? []);
|
|
964
|
+
next.add(emittedBindName(name, naming));
|
|
965
|
+
return next;
|
|
966
|
+
}
|
|
967
|
+
var init_binding_registry = __esm({
|
|
968
|
+
"src/binding-registry.ts"() {
|
|
969
|
+
"use strict";
|
|
970
|
+
}
|
|
971
|
+
});
|
|
972
|
+
|
|
973
|
+
// src/dialect-capabilities.ts
|
|
974
|
+
function supportsDialectCapability(capabilities, flag) {
|
|
975
|
+
return capabilities?.[flag] !== false;
|
|
976
|
+
}
|
|
977
|
+
function assertDialectCapability(capabilities, flag, feature) {
|
|
978
|
+
if (!supportsDialectCapability(capabilities, flag)) {
|
|
979
|
+
throw new Error(`${feature} not supported by this adapter`);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
var init_dialect_capabilities = __esm({
|
|
983
|
+
"src/dialect-capabilities.ts"() {
|
|
984
|
+
"use strict";
|
|
985
|
+
}
|
|
986
|
+
});
|
|
987
|
+
|
|
952
988
|
// src/param-ref.ts
|
|
953
989
|
function validateParamRef(paramRef) {
|
|
954
990
|
const errors = [];
|
|
@@ -1421,6 +1457,10 @@ var init_custom = __esm({
|
|
|
1421
1457
|
});
|
|
1422
1458
|
|
|
1423
1459
|
// src/select-expression-handlers.ts
|
|
1460
|
+
import {
|
|
1461
|
+
getTrustedNqlRelationFilterFields,
|
|
1462
|
+
markNqlTrustedRelationFilter
|
|
1463
|
+
} from "@dbsp/types/internal";
|
|
1424
1464
|
function handleColumnExpression(expr, rootTable, decisions) {
|
|
1425
1465
|
const decision = {
|
|
1426
1466
|
type: "select",
|
|
@@ -1549,14 +1589,18 @@ function handleCaseExpression(expr, rootTable, decisions, _applyFilter, convertC
|
|
|
1549
1589
|
decisions.push(decision);
|
|
1550
1590
|
}
|
|
1551
1591
|
function handleRelationColumnExpression(expr, rootTable, decisions) {
|
|
1592
|
+
const trusted = getTrustedNqlRelationFilterFields(expr);
|
|
1593
|
+
const trustedRelation = typeof trusted?.relation === "string" ? trusted.relation : trusted?.relation.join(".");
|
|
1552
1594
|
const decision = {
|
|
1553
1595
|
type: "selectRelationColumn",
|
|
1554
|
-
relation: expr.relation,
|
|
1555
|
-
column: expr.column ?? "*",
|
|
1596
|
+
relation: trustedRelation ?? expr.relation,
|
|
1597
|
+
column: trusted?.selectedColumn ?? (expr.column ?? "*"),
|
|
1556
1598
|
table: rootTable
|
|
1557
1599
|
};
|
|
1558
1600
|
if (expr.as) decision.alias = expr.as;
|
|
1559
|
-
decisions.push(
|
|
1601
|
+
decisions.push(
|
|
1602
|
+
trusted?.selectedColumn !== void 0 ? markNqlTrustedRelationFilter(decision, trusted) : decision
|
|
1603
|
+
);
|
|
1560
1604
|
}
|
|
1561
1605
|
function handleArithmeticExpression(expr, rootTable, decisions) {
|
|
1562
1606
|
const decision = {
|
|
@@ -1654,6 +1698,9 @@ var init_select_expression_handlers = __esm({
|
|
|
1654
1698
|
|
|
1655
1699
|
// src/intent-to-decisions.ts
|
|
1656
1700
|
import { isParamIntent } from "@dbsp/types";
|
|
1701
|
+
import {
|
|
1702
|
+
getTrustedNqlRelationFilterFields as getTrustedNqlRelationFilterFields2
|
|
1703
|
+
} from "@dbsp/types/internal";
|
|
1657
1704
|
function intentToDecisions(intent, rootTable) {
|
|
1658
1705
|
const decisions = [];
|
|
1659
1706
|
if (intent.select) {
|
|
@@ -2039,10 +2086,29 @@ function convertNot(cond, rootTable) {
|
|
|
2039
2086
|
if (!subDecision) return null;
|
|
2040
2087
|
return { type: "whereNot", conditions: [subDecision] };
|
|
2041
2088
|
}
|
|
2089
|
+
function formatRelationName(relation) {
|
|
2090
|
+
return typeof relation === "string" ? relation : relation.join(".");
|
|
2091
|
+
}
|
|
2042
2092
|
function convertExistsLike(cond, operator) {
|
|
2043
|
-
const
|
|
2093
|
+
const rawRelation = cond.relation;
|
|
2094
|
+
const preResolved = getTrustedNqlRelationFilterFields2(cond);
|
|
2095
|
+
const trustedRelation = preResolved?.relation;
|
|
2096
|
+
const relationName = trustedRelation !== void 0 ? formatRelationName(trustedRelation) : formatRelationName(rawRelation);
|
|
2097
|
+
const targetTable = preResolved?.targetTable ?? rawRelation;
|
|
2044
2098
|
const subDecisions = cond.where ? convertWhere(cond.where, targetTable) : [];
|
|
2045
|
-
const
|
|
2099
|
+
const isPreResolved = preResolved !== void 0;
|
|
2100
|
+
const base = {
|
|
2101
|
+
type: "where",
|
|
2102
|
+
operator,
|
|
2103
|
+
targetTable,
|
|
2104
|
+
...preResolved !== void 0 && {
|
|
2105
|
+
sourceColumn: preResolved.sourceColumn
|
|
2106
|
+
},
|
|
2107
|
+
...preResolved !== void 0 && {
|
|
2108
|
+
targetColumn: preResolved.targetColumn
|
|
2109
|
+
},
|
|
2110
|
+
...isPreResolved && { relationName }
|
|
2111
|
+
};
|
|
2046
2112
|
return subDecisions.length > 0 ? { ...base, conditions: subDecisions } : base;
|
|
2047
2113
|
}
|
|
2048
2114
|
function convertSubquery(cond) {
|
|
@@ -2813,6 +2879,7 @@ var init_param_intent = __esm({
|
|
|
2813
2879
|
});
|
|
2814
2880
|
|
|
2815
2881
|
// src/handlers/where/utils.ts
|
|
2882
|
+
import { validateTypeName as validateTypeName3 } from "@dbsp/core";
|
|
2816
2883
|
import { isFieldRef, isParamIntent as isParamIntent3 } from "@dbsp/types";
|
|
2817
2884
|
function buildColumnRef(column, ctx) {
|
|
2818
2885
|
if (column.includes(".")) {
|
|
@@ -2874,7 +2941,11 @@ function resolveColumnPgType(columnName, ctx) {
|
|
|
2874
2941
|
if (!table) return void 0;
|
|
2875
2942
|
const column = table.columns.find((c) => c.name === columnName);
|
|
2876
2943
|
if (!column) return void 0;
|
|
2877
|
-
if (column.originalDbType)
|
|
2944
|
+
if (column.originalDbType) {
|
|
2945
|
+
const typeName = column.originalDbType.trim();
|
|
2946
|
+
validateTypeName3(typeName);
|
|
2947
|
+
return typeName;
|
|
2948
|
+
}
|
|
2878
2949
|
return void 0;
|
|
2879
2950
|
}
|
|
2880
2951
|
var init_utils = __esm({
|
|
@@ -2883,7 +2954,6 @@ var init_utils = __esm({
|
|
|
2883
2954
|
init_ast_helpers();
|
|
2884
2955
|
init_param_intent();
|
|
2885
2956
|
init_param_ref();
|
|
2886
|
-
init_validate();
|
|
2887
2957
|
init_types();
|
|
2888
2958
|
init_param_intent();
|
|
2889
2959
|
}
|
|
@@ -2915,6 +2985,7 @@ var init_any = __esm({
|
|
|
2915
2985
|
"src/handlers/where/any.ts"() {
|
|
2916
2986
|
"use strict";
|
|
2917
2987
|
init_compiler_utils();
|
|
2988
|
+
init_dialect_capabilities();
|
|
2918
2989
|
init_param_intent();
|
|
2919
2990
|
init_param_ref();
|
|
2920
2991
|
init_types();
|
|
@@ -2922,6 +2993,11 @@ var init_any = __esm({
|
|
|
2922
2993
|
anyHandler = {
|
|
2923
2994
|
operators: [COLLECTION_OPERATORS.ANY],
|
|
2924
2995
|
compile(decision, ctx, state) {
|
|
2996
|
+
assertDialectCapability(
|
|
2997
|
+
ctx.dialectCapabilities,
|
|
2998
|
+
"supportsArrayType",
|
|
2999
|
+
"ANY array operator is"
|
|
3000
|
+
);
|
|
2925
3001
|
const column = decision.column;
|
|
2926
3002
|
if (!column) {
|
|
2927
3003
|
throw new Error("ANY handler requires a column");
|
|
@@ -3117,6 +3193,9 @@ function buildCorrelation(sourceAlias, sourceColumn, targetAlias, targetColumn,
|
|
|
3117
3193
|
const right = columnRef(targetColumn, targetAlias, void 0, ctx.naming);
|
|
3118
3194
|
return eqExpr(left, right);
|
|
3119
3195
|
}
|
|
3196
|
+
function schemaForExistsFromName(ctx, fromName) {
|
|
3197
|
+
return schemaForFromName(ctx.schema, fromName, ctx.bindingNames, ctx.naming);
|
|
3198
|
+
}
|
|
3120
3199
|
function buildExistsSubquery(decision, ctx, state, dispatch) {
|
|
3121
3200
|
const relation = decision.relation;
|
|
3122
3201
|
const targetTable = decision.targetTable ?? relation;
|
|
@@ -3160,7 +3239,7 @@ function buildExistsSubquery(decision, ctx, state, dispatch) {
|
|
|
3160
3239
|
let fromNode = rangeVar(
|
|
3161
3240
|
targetTable,
|
|
3162
3241
|
targetAlias,
|
|
3163
|
-
ctx
|
|
3242
|
+
schemaForExistsFromName(ctx, targetTable),
|
|
3164
3243
|
ctx.naming
|
|
3165
3244
|
);
|
|
3166
3245
|
const includeDecisions = decision.include;
|
|
@@ -3219,7 +3298,7 @@ function buildExistsSubquery(decision, ctx, state, dispatch) {
|
|
|
3219
3298
|
const joinRangeVar = rangeVar(
|
|
3220
3299
|
joinTargetTable,
|
|
3221
3300
|
joinAlias,
|
|
3222
|
-
ctx
|
|
3301
|
+
schemaForExistsFromName(ctx, joinTargetTable),
|
|
3223
3302
|
ctx.naming
|
|
3224
3303
|
);
|
|
3225
3304
|
fromNode = joinExpr(joinType, fromNode, joinRangeVar, joinQuals);
|
|
@@ -3245,6 +3324,7 @@ var init_exists = __esm({
|
|
|
3245
3324
|
"use strict";
|
|
3246
3325
|
init_assert_field();
|
|
3247
3326
|
init_ast_helpers();
|
|
3327
|
+
init_binding_registry();
|
|
3248
3328
|
existsHandler = {
|
|
3249
3329
|
operators: ["exists", "some"],
|
|
3250
3330
|
compile(decision, ctx, state, dispatch) {
|
|
@@ -3315,6 +3395,21 @@ function createNotInExpr(columnNode, state, values, columnType) {
|
|
|
3315
3395
|
}
|
|
3316
3396
|
};
|
|
3317
3397
|
}
|
|
3398
|
+
function createLiteralInListExpr(columnNode, state, values, negated) {
|
|
3399
|
+
const paramRefs = values.map((value) => {
|
|
3400
|
+
state.paramIndex++;
|
|
3401
|
+
state.parameters.push(value);
|
|
3402
|
+
return createParamRef(state.paramIndex);
|
|
3403
|
+
});
|
|
3404
|
+
return {
|
|
3405
|
+
A_Expr: {
|
|
3406
|
+
kind: "AEXPR_IN",
|
|
3407
|
+
name: [{ String: { sval: negated ? "<>" : "=" } }],
|
|
3408
|
+
lexpr: columnNode,
|
|
3409
|
+
rexpr: { List: { items: paramRefs } }
|
|
3410
|
+
}
|
|
3411
|
+
};
|
|
3412
|
+
}
|
|
3318
3413
|
function isWholeArrayParamList(value) {
|
|
3319
3414
|
return value.length === 1 && isParamIntent4(value[0]) && Array.isArray(value[0].value);
|
|
3320
3415
|
}
|
|
@@ -3330,6 +3425,7 @@ var init_in = __esm({
|
|
|
3330
3425
|
"src/handlers/where/in.ts"() {
|
|
3331
3426
|
"use strict";
|
|
3332
3427
|
init_ast_helpers();
|
|
3428
|
+
init_dialect_capabilities();
|
|
3333
3429
|
init_param_intent();
|
|
3334
3430
|
init_param_ref();
|
|
3335
3431
|
init_types();
|
|
@@ -3358,7 +3454,11 @@ var init_in = __esm({
|
|
|
3358
3454
|
}
|
|
3359
3455
|
const columnNode = buildColumnRef(column, ctx);
|
|
3360
3456
|
const columnType = resolveColumnPgType(column, ctx);
|
|
3361
|
-
|
|
3457
|
+
const isNotIn = operator === COLLECTION_OPERATORS.NOT_IN || operator === "notIn";
|
|
3458
|
+
if (!supportsDialectCapability(ctx.dialectCapabilities, "supportsArrayType")) {
|
|
3459
|
+
return createLiteralInListExpr(columnNode, state, values, isNotIn);
|
|
3460
|
+
}
|
|
3461
|
+
if (isNotIn) {
|
|
3362
3462
|
return createNotInExpr(columnNode, state, values, columnType);
|
|
3363
3463
|
}
|
|
3364
3464
|
return createInExpr(columnNode, state, values, columnType);
|
|
@@ -3372,10 +3472,16 @@ var jsonContainsHandler, jsonExistsHandler, jsonComparisonHandler;
|
|
|
3372
3472
|
var init_json = __esm({
|
|
3373
3473
|
"src/handlers/where/json.ts"() {
|
|
3374
3474
|
"use strict";
|
|
3475
|
+
init_dialect_capabilities();
|
|
3375
3476
|
init_utils();
|
|
3376
3477
|
jsonContainsHandler = {
|
|
3377
3478
|
operators: ["jsonContains", "jsonContainedBy"],
|
|
3378
3479
|
compile(decision, ctx, state) {
|
|
3480
|
+
assertDialectCapability(
|
|
3481
|
+
ctx.dialectCapabilities,
|
|
3482
|
+
"supportsJsonOperators",
|
|
3483
|
+
"JSON operators are"
|
|
3484
|
+
);
|
|
3379
3485
|
const column = decision.column;
|
|
3380
3486
|
if (!column) {
|
|
3381
3487
|
throw new Error("JSON contains handler requires a column");
|
|
@@ -3396,6 +3502,11 @@ var init_json = __esm({
|
|
|
3396
3502
|
jsonExistsHandler = {
|
|
3397
3503
|
operators: ["jsonExists"],
|
|
3398
3504
|
compile(decision, ctx, state) {
|
|
3505
|
+
assertDialectCapability(
|
|
3506
|
+
ctx.dialectCapabilities,
|
|
3507
|
+
"supportsJsonOperators",
|
|
3508
|
+
"JSON operators are"
|
|
3509
|
+
);
|
|
3399
3510
|
const column = decision.column;
|
|
3400
3511
|
if (!column) {
|
|
3401
3512
|
throw new Error("JSON exists handler requires a column");
|
|
@@ -3415,6 +3526,11 @@ var init_json = __esm({
|
|
|
3415
3526
|
jsonComparisonHandler = {
|
|
3416
3527
|
operators: ["jsonComparison"],
|
|
3417
3528
|
compile(decision, ctx, state) {
|
|
3529
|
+
assertDialectCapability(
|
|
3530
|
+
ctx.dialectCapabilities,
|
|
3531
|
+
"supportsJsonOperators",
|
|
3532
|
+
"JSON operators are"
|
|
3533
|
+
);
|
|
3418
3534
|
const column = decision.column;
|
|
3419
3535
|
if (!column) {
|
|
3420
3536
|
throw new Error("JSON comparison handler requires a column");
|
|
@@ -3592,6 +3708,7 @@ var RANGE_OP_MAP, rangeHandler;
|
|
|
3592
3708
|
var init_range = __esm({
|
|
3593
3709
|
"src/handlers/where/range.ts"() {
|
|
3594
3710
|
"use strict";
|
|
3711
|
+
init_dialect_capabilities();
|
|
3595
3712
|
init_param_intent();
|
|
3596
3713
|
init_param_ref();
|
|
3597
3714
|
init_types();
|
|
@@ -3604,6 +3721,11 @@ var init_range = __esm({
|
|
|
3604
3721
|
rangeHandler = {
|
|
3605
3722
|
operators: ["contains", "containedBy", "overlaps"],
|
|
3606
3723
|
compile(decision, ctx, state) {
|
|
3724
|
+
assertDialectCapability(
|
|
3725
|
+
ctx.dialectCapabilities,
|
|
3726
|
+
"supportsRangeTypes",
|
|
3727
|
+
"Range operators are"
|
|
3728
|
+
);
|
|
3607
3729
|
const column = decision.column;
|
|
3608
3730
|
if (!column) {
|
|
3609
3731
|
throw new Error("Range handler requires a column");
|
|
@@ -3651,28 +3773,8 @@ var init_range = __esm({
|
|
|
3651
3773
|
}
|
|
3652
3774
|
});
|
|
3653
3775
|
|
|
3654
|
-
// src/binding-registry.ts
|
|
3655
|
-
function emittedBindName(name, naming) {
|
|
3656
|
-
return naming.toDatabase(name);
|
|
3657
|
-
}
|
|
3658
|
-
function hasBindingName(bindingNames, name, naming) {
|
|
3659
|
-
return bindingNames?.has(emittedBindName(name, naming)) ?? false;
|
|
3660
|
-
}
|
|
3661
|
-
function schemaForFromName(schemaName, fromName, bindingNames, naming) {
|
|
3662
|
-
return hasBindingName(bindingNames, fromName, naming) ? void 0 : schemaName;
|
|
3663
|
-
}
|
|
3664
|
-
function withBindingName(bindingNames, name, naming) {
|
|
3665
|
-
const next = new Set(bindingNames ?? []);
|
|
3666
|
-
next.add(emittedBindName(name, naming));
|
|
3667
|
-
return next;
|
|
3668
|
-
}
|
|
3669
|
-
var init_binding_registry = __esm({
|
|
3670
|
-
"src/binding-registry.ts"() {
|
|
3671
|
-
"use strict";
|
|
3672
|
-
}
|
|
3673
|
-
});
|
|
3674
|
-
|
|
3675
3776
|
// src/compile-where.ts
|
|
3777
|
+
import { getTrustedNqlRelationFilterFields as getTrustedNqlRelationFilterFields3 } from "@dbsp/types/internal";
|
|
3676
3778
|
function toHandlerContext(ctx) {
|
|
3677
3779
|
return {
|
|
3678
3780
|
naming: ctx.naming,
|
|
@@ -3680,12 +3782,15 @@ function toHandlerContext(ctx) {
|
|
|
3680
3782
|
currentAlias: ctx.currentAlias ?? ctx.rootTable,
|
|
3681
3783
|
maxRecursiveDepth: 100,
|
|
3682
3784
|
...ctx.schemaName !== void 0 && { schema: ctx.schemaName },
|
|
3785
|
+
...ctx.dialectCapabilities !== void 0 && {
|
|
3786
|
+
dialectCapabilities: ctx.dialectCapabilities
|
|
3787
|
+
},
|
|
3683
3788
|
...ctx.bindingNames !== void 0 && { bindingNames: ctx.bindingNames },
|
|
3684
3789
|
...ctx.model !== void 0 && { model: ctx.model },
|
|
3685
3790
|
...ctx.outerTable !== void 0 && { outerAlias: ctx.outerTable }
|
|
3686
3791
|
};
|
|
3687
3792
|
}
|
|
3688
|
-
function buildSubqueryFromIntent(intent, paramOffset, naming = identityNaming, schemaName, use = "rawExists", bindingNames) {
|
|
3793
|
+
function buildSubqueryFromIntent(intent, paramOffset, naming = identityNaming, schemaName, use = "rawExists", bindingNames, dialectCapabilities) {
|
|
3689
3794
|
assertNoUnsupportedSubqueryModifiers(intent, use);
|
|
3690
3795
|
if (intent.where && containsOuterRef(intent.where)) {
|
|
3691
3796
|
throw new Error(
|
|
@@ -3751,6 +3856,8 @@ function buildSubqueryFromIntent(intent, paramOffset, naming = identityNaming, s
|
|
|
3751
3856
|
aliases: /* @__PURE__ */ new Map(),
|
|
3752
3857
|
paramState: innerState,
|
|
3753
3858
|
naming,
|
|
3859
|
+
...schemaName !== void 0 && { schemaName },
|
|
3860
|
+
...dialectCapabilities !== void 0 && { dialectCapabilities },
|
|
3754
3861
|
...bindingNames !== void 0 && { bindingNames },
|
|
3755
3862
|
compileSubquery: (_nestedIntent, _nestedOffset) => {
|
|
3756
3863
|
throw new Error(
|
|
@@ -3861,11 +3968,16 @@ function handleSubqueryIntent(intent, ctx, _handlerCtx) {
|
|
|
3861
3968
|
}
|
|
3862
3969
|
function handleRelationFilterIntent(intent, ctx) {
|
|
3863
3970
|
const rf = intent;
|
|
3864
|
-
const
|
|
3971
|
+
const preResolved = getTrustedNqlRelationFilterFields3(rf);
|
|
3972
|
+
const relationPath = preResolved?.relation ?? rf.relation;
|
|
3973
|
+
const hops = Array.isArray(relationPath) ? [...relationPath] : [relationPath];
|
|
3865
3974
|
const existsKind = rf.mode === "none" || rf.mode === "every" ? "notExists" : "exists";
|
|
3866
3975
|
const rfWhere = rf.where;
|
|
3867
3976
|
const isVacuousEvery = rf.mode === "every" && (!rfWhere || typeof rfWhere === "object" && rfWhere.kind === "and" && Array.isArray(rfWhere.conditions) && rfWhere.conditions.length === 0);
|
|
3868
3977
|
if (isVacuousEvery) {
|
|
3978
|
+
if (preResolved) {
|
|
3979
|
+
return { A_Const: { boolval: { boolval: true } } };
|
|
3980
|
+
}
|
|
3869
3981
|
if (hops.length <= 1) {
|
|
3870
3982
|
const relation = hops[0] ?? rf.relation;
|
|
3871
3983
|
if (!ctx.model) {
|
|
@@ -3901,6 +4013,19 @@ function handleRelationFilterIntent(intent, ctx) {
|
|
|
3901
4013
|
const innermostWhere = rf.mode === "every" ? { kind: "not", condition: rf.where } : rf.where;
|
|
3902
4014
|
if (hops.length <= 1) {
|
|
3903
4015
|
const relation = hops[0] ?? rf.relation;
|
|
4016
|
+
if (preResolved) {
|
|
4017
|
+
return compileWhereIntent(
|
|
4018
|
+
{
|
|
4019
|
+
kind: existsKind,
|
|
4020
|
+
relation,
|
|
4021
|
+
targetTable: preResolved.targetTable,
|
|
4022
|
+
sourceColumn: preResolved.sourceColumn,
|
|
4023
|
+
targetColumn: preResolved.targetColumn,
|
|
4024
|
+
where: innermostWhere
|
|
4025
|
+
},
|
|
4026
|
+
ctx
|
|
4027
|
+
);
|
|
4028
|
+
}
|
|
3904
4029
|
const resolvedRelation = ctx.model?.getRelation(
|
|
3905
4030
|
`${ctx.rootTable}.${relation}`
|
|
3906
4031
|
);
|
|
@@ -4175,7 +4300,8 @@ var init_raw_exists = __esm({
|
|
|
4175
4300
|
ctx.naming,
|
|
4176
4301
|
ctx.schema,
|
|
4177
4302
|
"rawExists",
|
|
4178
|
-
ctx.bindingNames
|
|
4303
|
+
ctx.bindingNames,
|
|
4304
|
+
ctx.dialectCapabilities
|
|
4179
4305
|
);
|
|
4180
4306
|
if (innerParams) {
|
|
4181
4307
|
for (const p of innerParams) {
|
|
@@ -5984,11 +6110,17 @@ var init_json2 = __esm({
|
|
|
5984
6110
|
"src/handlers/expression/json.ts"() {
|
|
5985
6111
|
"use strict";
|
|
5986
6112
|
init_ast_helpers();
|
|
6113
|
+
init_dialect_capabilities();
|
|
5987
6114
|
init_param_intent();
|
|
5988
6115
|
init_utils();
|
|
5989
6116
|
jsonExtractHandler = {
|
|
5990
6117
|
types: ["jsonExtract"],
|
|
5991
6118
|
compile(decision, ctx, state) {
|
|
6119
|
+
assertDialectCapability(
|
|
6120
|
+
ctx.dialectCapabilities,
|
|
6121
|
+
"supportsJsonOperators",
|
|
6122
|
+
"JSON operators are"
|
|
6123
|
+
);
|
|
5992
6124
|
const column = decision.column;
|
|
5993
6125
|
if (!column) {
|
|
5994
6126
|
throw new Error("JSON extract handler requires a column");
|
|
@@ -6016,6 +6148,11 @@ var init_json2 = __esm({
|
|
|
6016
6148
|
jsonPathExtractHandler = {
|
|
6017
6149
|
types: ["jsonPathExtract"],
|
|
6018
6150
|
compile(decision, ctx, state) {
|
|
6151
|
+
assertDialectCapability(
|
|
6152
|
+
ctx.dialectCapabilities,
|
|
6153
|
+
"supportsJsonOperators",
|
|
6154
|
+
"JSON operators are"
|
|
6155
|
+
);
|
|
6019
6156
|
const column = decision.column;
|
|
6020
6157
|
if (!column) {
|
|
6021
6158
|
throw new Error("JSON path extract handler requires a column");
|
|
@@ -7087,13 +7224,18 @@ init_ast_helpers();
|
|
|
7087
7224
|
// src/compiler.ts
|
|
7088
7225
|
init_assert_field();
|
|
7089
7226
|
init_ast_helpers();
|
|
7227
|
+
init_binding_registry();
|
|
7090
7228
|
import { InvalidOperationError as InvalidOperationError2 } from "@dbsp/core";
|
|
7091
7229
|
import {
|
|
7092
7230
|
isParamIntent as isParamIntent6,
|
|
7093
7231
|
NQL_SELECT_SCALAR_FUNCTION_ALLOWLIST,
|
|
7094
7232
|
NQL_SELECT_WINDOW_FUNCTION_ALLOWLIST
|
|
7095
7233
|
} from "@dbsp/types";
|
|
7096
|
-
import {
|
|
7234
|
+
import {
|
|
7235
|
+
getNqlBindingRefName,
|
|
7236
|
+
getTrustedNqlRelationFilterFields as getTrustedNqlRelationFilterFields4,
|
|
7237
|
+
isNqlBindingRef
|
|
7238
|
+
} from "@dbsp/types/internal";
|
|
7097
7239
|
|
|
7098
7240
|
// src/pgsql-deparser.ts
|
|
7099
7241
|
function deparse(node) {
|
|
@@ -8148,6 +8290,7 @@ function deparseQuoted(ast) {
|
|
|
8148
8290
|
}
|
|
8149
8291
|
|
|
8150
8292
|
// src/compiler.ts
|
|
8293
|
+
init_dialect_capabilities();
|
|
8151
8294
|
init_case_value();
|
|
8152
8295
|
init_custom();
|
|
8153
8296
|
init_expression();
|
|
@@ -8194,6 +8337,12 @@ function assertNqlSelectWindowFunctionAllowed(functionName) {
|
|
|
8194
8337
|
}
|
|
8195
8338
|
}
|
|
8196
8339
|
function mapToHandlerDecision(pd, rootTable, defaultPk, deriveFk) {
|
|
8340
|
+
const derivedFkColumns = deriveFkColumns(
|
|
8341
|
+
pd,
|
|
8342
|
+
pd.sourceTable ?? rootTable,
|
|
8343
|
+
defaultPk,
|
|
8344
|
+
deriveFk
|
|
8345
|
+
);
|
|
8197
8346
|
return {
|
|
8198
8347
|
type: pd.type,
|
|
8199
8348
|
table: pd.table,
|
|
@@ -8204,7 +8353,8 @@ function mapToHandlerDecision(pd, rootTable, defaultPk, deriveFk) {
|
|
|
8204
8353
|
paramIndex: pd.paramIndex,
|
|
8205
8354
|
direction: pd.direction,
|
|
8206
8355
|
joinType: pd.joinType,
|
|
8207
|
-
|
|
8356
|
+
sourceColumn: pd.sourceColumn ?? derivedFkColumns.sourceColumn,
|
|
8357
|
+
targetColumn: pd.targetColumn ?? derivedFkColumns.targetColumn,
|
|
8208
8358
|
targetTable: pd.targetTable,
|
|
8209
8359
|
function: pd.function,
|
|
8210
8360
|
args: pd.args,
|
|
@@ -8380,6 +8530,7 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
8380
8530
|
defaultPk;
|
|
8381
8531
|
deriveFk;
|
|
8382
8532
|
model;
|
|
8533
|
+
dialectCapabilities;
|
|
8383
8534
|
bindingNames;
|
|
8384
8535
|
/** Mutable state shared with extracted condition/value compilation functions */
|
|
8385
8536
|
state = {
|
|
@@ -8397,6 +8548,8 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
8397
8548
|
rawJoins = [];
|
|
8398
8549
|
/** CTE nodes from include handlers (e.g., CTE strategy) */
|
|
8399
8550
|
pendingCtes = [];
|
|
8551
|
+
/** Local aliases for binding relation-column scalar subqueries. */
|
|
8552
|
+
bindingRelationColumnSubqueryIndex = 0;
|
|
8400
8553
|
/**
|
|
8401
8554
|
* Maps relation-dotted include path → JOIN alias for multi-hop FK resolution.
|
|
8402
8555
|
* Populated as join decisions are compiled so later hops can find the
|
|
@@ -8415,8 +8568,25 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
8415
8568
|
this.defaultPk = options.defaultPkColumnName ?? DEFAULT_PK_COLUMN;
|
|
8416
8569
|
this.deriveFk = options.deriveFkColumnName ?? defaultFkDerivation;
|
|
8417
8570
|
this.model = options.model ?? void 0;
|
|
8571
|
+
this.dialectCapabilities = options.dialectCapabilities;
|
|
8418
8572
|
this.bindingNames = options.bindingNames;
|
|
8419
8573
|
}
|
|
8574
|
+
childCompilerOptions(overrides = {}) {
|
|
8575
|
+
return {
|
|
8576
|
+
naming: this.naming,
|
|
8577
|
+
...this.schema !== void 0 && { schema: this.schema },
|
|
8578
|
+
defaultPkColumnName: this.defaultPk,
|
|
8579
|
+
deriveFkColumnName: this.deriveFk,
|
|
8580
|
+
...this.model !== void 0 && { model: this.model },
|
|
8581
|
+
...this.dialectCapabilities !== void 0 && {
|
|
8582
|
+
dialectCapabilities: this.dialectCapabilities
|
|
8583
|
+
},
|
|
8584
|
+
...this.bindingNames !== void 0 && {
|
|
8585
|
+
bindingNames: this.bindingNames
|
|
8586
|
+
},
|
|
8587
|
+
...overrides
|
|
8588
|
+
};
|
|
8589
|
+
}
|
|
8420
8590
|
/** Build immutable context for handler-based WHERE compilation */
|
|
8421
8591
|
handlerCtx() {
|
|
8422
8592
|
return {
|
|
@@ -8427,6 +8597,9 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
8427
8597
|
defaultPkColumnName: this.defaultPk,
|
|
8428
8598
|
deriveFkColumnName: this.deriveFk,
|
|
8429
8599
|
...this.schema != null && { schema: this.schema },
|
|
8600
|
+
...this.dialectCapabilities != null && {
|
|
8601
|
+
dialectCapabilities: this.dialectCapabilities
|
|
8602
|
+
},
|
|
8430
8603
|
...this.bindingNames != null && { bindingNames: this.bindingNames },
|
|
8431
8604
|
...this.model != null && { model: this.model }
|
|
8432
8605
|
};
|
|
@@ -8737,6 +8910,9 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
8737
8910
|
defaultPkColumnName: this.defaultPk,
|
|
8738
8911
|
deriveFkColumnName: this.deriveFk,
|
|
8739
8912
|
...plan.schema ?? this.schema ? { schema: plan.schema ?? this.schema } : {},
|
|
8913
|
+
...this.dialectCapabilities != null && {
|
|
8914
|
+
dialectCapabilities: this.dialectCapabilities
|
|
8915
|
+
},
|
|
8740
8916
|
...this.bindingNames != null && { bindingNames: this.bindingNames },
|
|
8741
8917
|
...this.model != null && { model: this.model },
|
|
8742
8918
|
compileSubquery: (query, paramOffset) => this.compileExpressionSubquery(query, paramOffset),
|
|
@@ -8753,18 +8929,66 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
8753
8929
|
joins: []
|
|
8754
8930
|
};
|
|
8755
8931
|
}
|
|
8756
|
-
|
|
8757
|
-
|
|
8758
|
-
|
|
8759
|
-
|
|
8760
|
-
|
|
8761
|
-
|
|
8762
|
-
|
|
8763
|
-
|
|
8764
|
-
|
|
8765
|
-
|
|
8932
|
+
schemaForRangeVar(plan, table) {
|
|
8933
|
+
return schemaForFromName(
|
|
8934
|
+
plan.schema ?? this.schema,
|
|
8935
|
+
table,
|
|
8936
|
+
this.bindingNames,
|
|
8937
|
+
this.naming
|
|
8938
|
+
);
|
|
8939
|
+
}
|
|
8940
|
+
isNqlBindingRoot(plan) {
|
|
8941
|
+
return hasBindingName(this.bindingNames, plan.rootTable, this.naming);
|
|
8942
|
+
}
|
|
8943
|
+
compileBindingRelationColumnSubquery(fields, plan) {
|
|
8944
|
+
if (fields.selectedColumn === void 0) {
|
|
8945
|
+
throw new Error(
|
|
8946
|
+
`NQL binding relation-column proof for '${plan.rootTable}' is missing selectedColumn.`
|
|
8947
|
+
);
|
|
8948
|
+
}
|
|
8949
|
+
if (fields.cardinality !== "one") {
|
|
8950
|
+
throw new Error(
|
|
8951
|
+
`NQL binding relation-column proof for '${plan.rootTable}' is not scalar (cardinality: ${fields.cardinality ?? "unknown"}).`
|
|
8952
|
+
);
|
|
8953
|
+
}
|
|
8954
|
+
const relatedAlias = `rc_${this.bindingRelationColumnSubqueryIndex++}`;
|
|
8955
|
+
const relatedTable = rangeVar(
|
|
8956
|
+
fields.targetTable,
|
|
8957
|
+
relatedAlias,
|
|
8958
|
+
this.schemaForRangeVar(plan, fields.targetTable),
|
|
8959
|
+
this.naming
|
|
8960
|
+
);
|
|
8961
|
+
const relatedColumn = columnRef(
|
|
8962
|
+
fields.selectedColumn,
|
|
8963
|
+
relatedAlias,
|
|
8964
|
+
void 0,
|
|
8965
|
+
this.naming
|
|
8966
|
+
);
|
|
8967
|
+
const relatedJoinColumn = columnRef(
|
|
8968
|
+
fields.targetColumn,
|
|
8969
|
+
relatedAlias,
|
|
8970
|
+
void 0,
|
|
8971
|
+
this.naming
|
|
8972
|
+
);
|
|
8973
|
+
const bindingJoinColumn = columnRef(
|
|
8974
|
+
fields.sourceColumn,
|
|
8975
|
+
plan.rootTable,
|
|
8976
|
+
void 0,
|
|
8977
|
+
this.naming
|
|
8978
|
+
);
|
|
8979
|
+
return {
|
|
8980
|
+
SubLink: {
|
|
8981
|
+
subLinkType: "EXPR_SUBLINK",
|
|
8982
|
+
subselect: selectStmt({
|
|
8983
|
+
targetList: [{ ResTarget: { val: relatedColumn } }],
|
|
8984
|
+
from: [relatedTable],
|
|
8985
|
+
where: eqExpr(relatedJoinColumn, bindingJoinColumn)
|
|
8986
|
+
})
|
|
8766
8987
|
}
|
|
8767
|
-
}
|
|
8988
|
+
};
|
|
8989
|
+
}
|
|
8990
|
+
compileExpressionSubquery(query, paramOffset) {
|
|
8991
|
+
const innerCompiler = new _PlanCompiler(this.childCompilerOptions());
|
|
8768
8992
|
const innerPlan = {
|
|
8769
8993
|
rootTable: query.from,
|
|
8770
8994
|
decisions: intentToDecisions(query, query.from)
|
|
@@ -9104,24 +9328,7 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
9104
9328
|
const ctx = {
|
|
9105
9329
|
...this.createHandlerContext(plan, plan.rootTable),
|
|
9106
9330
|
compileSubquery(query, paramOffset) {
|
|
9107
|
-
|
|
9108
|
-
naming: outerThis.naming,
|
|
9109
|
-
...outerThis.schema !== void 0 && {
|
|
9110
|
-
schema: outerThis.schema
|
|
9111
|
-
},
|
|
9112
|
-
defaultPkColumnName: outerThis.defaultPk,
|
|
9113
|
-
deriveFkColumnName: outerThis.deriveFk
|
|
9114
|
-
});
|
|
9115
|
-
const innerPlan = {
|
|
9116
|
-
rootTable: query.from,
|
|
9117
|
-
decisions: intentToDecisions(query, query.from)
|
|
9118
|
-
};
|
|
9119
|
-
const innerResult = innerCompiler.compile(innerPlan);
|
|
9120
|
-
const renumbered = renumberParamRefsInAst(
|
|
9121
|
-
innerResult.ast,
|
|
9122
|
-
paramOffset
|
|
9123
|
-
);
|
|
9124
|
-
return { ast: renumbered, parameters: innerResult.parameters };
|
|
9331
|
+
return outerThis.compileExpressionSubquery(query, paramOffset);
|
|
9125
9332
|
}
|
|
9126
9333
|
};
|
|
9127
9334
|
const state = this.createHandlerState();
|
|
@@ -9157,6 +9364,27 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
9157
9364
|
case "selectRelationColumn":
|
|
9158
9365
|
case "selectPseudoColumn":
|
|
9159
9366
|
case "selectArithmetic": {
|
|
9367
|
+
if (decision.type === "selectRelationColumn") {
|
|
9368
|
+
const trusted = getTrustedNqlRelationFilterFields4(decision);
|
|
9369
|
+
if (trusted?.selectedColumn !== void 0) {
|
|
9370
|
+
const node2 = this.compileBindingRelationColumnSubquery(
|
|
9371
|
+
trusted,
|
|
9372
|
+
plan
|
|
9373
|
+
);
|
|
9374
|
+
targetList.push({
|
|
9375
|
+
ResTarget: {
|
|
9376
|
+
val: node2,
|
|
9377
|
+
...decision.alias ? { name: this.naming.toDatabase(decision.alias) } : {}
|
|
9378
|
+
}
|
|
9379
|
+
});
|
|
9380
|
+
break;
|
|
9381
|
+
}
|
|
9382
|
+
if (this.isNqlBindingRoot(plan)) {
|
|
9383
|
+
throw new Error(
|
|
9384
|
+
`NQL binding-final query '${plan.rootTable}' cannot select relation column '${decision.relation ?? "unknown"}.${decision.column ?? "unknown"}' without a trusted compiler proof.`
|
|
9385
|
+
);
|
|
9386
|
+
}
|
|
9387
|
+
}
|
|
9160
9388
|
ensureExpressionHandlersRegistered();
|
|
9161
9389
|
const exprType = decision.type === "selectRelationColumn" ? "relationColumn" : decision.type === "selectPseudoColumn" ? "pseudoColumn" : "arithmetic";
|
|
9162
9390
|
const handler = getExpressionHandler(exprType);
|
|
@@ -9307,13 +9535,13 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
9307
9535
|
const targetRV = rangeVar(
|
|
9308
9536
|
pj.table,
|
|
9309
9537
|
pj.alias,
|
|
9310
|
-
plan
|
|
9538
|
+
this.schemaForRangeVar(plan, pj.table),
|
|
9311
9539
|
this.naming
|
|
9312
9540
|
);
|
|
9313
9541
|
const base = from.length > 0 ? from[0] : rangeVar(
|
|
9314
9542
|
plan.rootTable,
|
|
9315
9543
|
void 0,
|
|
9316
|
-
plan
|
|
9544
|
+
this.schemaForRangeVar(plan, plan.rootTable),
|
|
9317
9545
|
this.naming
|
|
9318
9546
|
);
|
|
9319
9547
|
from[0] = pj.type === "LEFT JOIN" ? leftJoin(base, targetRV, pj.on) : innerJoin(base, targetRV, pj.on);
|
|
@@ -9322,7 +9550,7 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
9322
9550
|
const base = from.length > 0 ? from[0] : rangeVar(
|
|
9323
9551
|
plan.rootTable,
|
|
9324
9552
|
void 0,
|
|
9325
|
-
plan
|
|
9553
|
+
this.schemaForRangeVar(plan, plan.rootTable),
|
|
9326
9554
|
this.naming
|
|
9327
9555
|
);
|
|
9328
9556
|
const joinExpr2 = rawJoin;
|
|
@@ -9347,7 +9575,7 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
9347
9575
|
plan.batchValuesFromNode ? plan.batchValuesFromNode : rangeVar(
|
|
9348
9576
|
plan.rootTable,
|
|
9349
9577
|
void 0,
|
|
9350
|
-
plan
|
|
9578
|
+
this.schemaForRangeVar(plan, plan.rootTable),
|
|
9351
9579
|
this.naming
|
|
9352
9580
|
)
|
|
9353
9581
|
];
|
|
@@ -9494,6 +9722,18 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
9494
9722
|
options.withClause = { ctes: this.pendingCtes, recursive: false };
|
|
9495
9723
|
}
|
|
9496
9724
|
if (plan.lock) {
|
|
9725
|
+
assertDialectCapability(
|
|
9726
|
+
this.dialectCapabilities,
|
|
9727
|
+
"supportsRowLevelLocks",
|
|
9728
|
+
"Row-level locks are"
|
|
9729
|
+
);
|
|
9730
|
+
if (plan.lock.waitPolicy !== "block") {
|
|
9731
|
+
assertDialectCapability(
|
|
9732
|
+
this.dialectCapabilities,
|
|
9733
|
+
"supportsLockWaitPolicies",
|
|
9734
|
+
"Lock wait policies are"
|
|
9735
|
+
);
|
|
9736
|
+
}
|
|
9497
9737
|
const mapped = mapLockToAst(plan.lock);
|
|
9498
9738
|
const hasJoins = this.rawJoins.length > 0;
|
|
9499
9739
|
options.lockingClause = {
|
|
@@ -9503,7 +9743,7 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
9503
9743
|
rangeVar(
|
|
9504
9744
|
plan.rootTable,
|
|
9505
9745
|
void 0,
|
|
9506
|
-
plan
|
|
9746
|
+
this.schemaForRangeVar(plan, plan.rootTable),
|
|
9507
9747
|
this.naming
|
|
9508
9748
|
)
|
|
9509
9749
|
]
|
|
@@ -9883,13 +10123,13 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
9883
10123
|
const baseTable = larg ?? rangeVar(
|
|
9884
10124
|
plan.rootTable,
|
|
9885
10125
|
void 0,
|
|
9886
|
-
plan
|
|
10126
|
+
this.schemaForRangeVar(plan, plan.rootTable),
|
|
9887
10127
|
this.naming
|
|
9888
10128
|
);
|
|
9889
10129
|
const targetTable = rangeVar(
|
|
9890
10130
|
decision.targetTable ?? "",
|
|
9891
10131
|
decision.alias,
|
|
9892
|
-
plan.
|
|
10132
|
+
this.schemaForRangeVar(plan, decision.targetTable ?? ""),
|
|
9893
10133
|
this.naming
|
|
9894
10134
|
);
|
|
9895
10135
|
const onCondition = eqExpr(
|
|
@@ -13939,7 +14179,11 @@ init_naming_plugin();
|
|
|
13939
14179
|
init_param_ref();
|
|
13940
14180
|
|
|
13941
14181
|
// src/pgsql-adapter.ts
|
|
13942
|
-
import {
|
|
14182
|
+
import {
|
|
14183
|
+
POSTGRESQL_CAPABILITIES as POSTGRESQL_CAPABILITIES2,
|
|
14184
|
+
plan as planFn2,
|
|
14185
|
+
validateTypeName as validateTypeName4
|
|
14186
|
+
} from "@dbsp/core";
|
|
13943
14187
|
import { getNqlBindingRefName as getNqlBindingRefName2, isNqlBindingRef as isNqlBindingRef2 } from "@dbsp/types/internal";
|
|
13944
14188
|
|
|
13945
14189
|
// src/adapter-compiler-includes.ts
|
|
@@ -14136,6 +14380,7 @@ import {
|
|
|
14136
14380
|
// src/adapter-compiler-select.ts
|
|
14137
14381
|
init_assert_field();
|
|
14138
14382
|
init_ast_helpers();
|
|
14383
|
+
init_binding_registry();
|
|
14139
14384
|
init_compile_where();
|
|
14140
14385
|
import { countDistinctRelationPathsByName } from "@dbsp/core";
|
|
14141
14386
|
init_compiler_utils();
|
|
@@ -15174,7 +15419,13 @@ function compileJoinIntents(joins, rootTable, schemaName, deps) {
|
|
|
15174
15419
|
naming,
|
|
15175
15420
|
outerTable: alias,
|
|
15176
15421
|
...schemaName !== void 0 && { schemaName },
|
|
15422
|
+
...deps.bindingNames !== void 0 && {
|
|
15423
|
+
bindingNames: deps.bindingNames
|
|
15424
|
+
},
|
|
15177
15425
|
...model !== void 0 && { model },
|
|
15426
|
+
...deps.dialectCapabilities !== void 0 && {
|
|
15427
|
+
dialectCapabilities: deps.dialectCapabilities
|
|
15428
|
+
},
|
|
15178
15429
|
compileSubquery: () => {
|
|
15179
15430
|
throw new Error(
|
|
15180
15431
|
"Subquery in BatchValues JOIN ON condition is not supported."
|
|
@@ -15214,7 +15465,13 @@ function compileJoinIntents(joins, rootTable, schemaName, deps) {
|
|
|
15214
15465
|
// joined alias (e.g. 'e2' in self-join ON conditions).
|
|
15215
15466
|
outerTable: tableAlias,
|
|
15216
15467
|
...schemaName !== void 0 && { schemaName },
|
|
15468
|
+
...deps.bindingNames !== void 0 && {
|
|
15469
|
+
bindingNames: deps.bindingNames
|
|
15470
|
+
},
|
|
15217
15471
|
...model !== void 0 && { model },
|
|
15472
|
+
...deps.dialectCapabilities !== void 0 && {
|
|
15473
|
+
dialectCapabilities: deps.dialectCapabilities
|
|
15474
|
+
},
|
|
15218
15475
|
compileSubquery: () => {
|
|
15219
15476
|
throw new Error("Subquery in JOIN ON condition is not supported.");
|
|
15220
15477
|
}
|
|
@@ -15223,7 +15480,7 @@ function compileJoinIntents(joins, rootTable, schemaName, deps) {
|
|
|
15223
15480
|
const joinedRangeVar = rangeVar(
|
|
15224
15481
|
intent.table,
|
|
15225
15482
|
tableAlias,
|
|
15226
|
-
schemaName,
|
|
15483
|
+
schemaForFromName(schemaName, intent.table, deps.bindingNames, naming),
|
|
15227
15484
|
naming
|
|
15228
15485
|
);
|
|
15229
15486
|
results.push({
|
|
@@ -15386,6 +15643,9 @@ function compileSelect(plan, options, deps) {
|
|
|
15386
15643
|
...deps.bindingNames !== void 0 && {
|
|
15387
15644
|
bindingNames: deps.bindingNames
|
|
15388
15645
|
},
|
|
15646
|
+
...deps.dialectCapabilities !== void 0 && {
|
|
15647
|
+
dialectCapabilities: deps.dialectCapabilities
|
|
15648
|
+
},
|
|
15389
15649
|
...resolvedModelForCompiler != null && {
|
|
15390
15650
|
model: resolvedModelForCompiler
|
|
15391
15651
|
}
|
|
@@ -15545,7 +15805,7 @@ function compileSourceQueryCte(operation, sourceName, sourceQuery, options, deps
|
|
|
15545
15805
|
);
|
|
15546
15806
|
}
|
|
15547
15807
|
const sourcePlan = planFn(sourceQuery, model, {
|
|
15548
|
-
dialectCapabilities: POSTGRESQL_CAPABILITIES
|
|
15808
|
+
dialectCapabilities: deps.dialectCapabilities ?? POSTGRESQL_CAPABILITIES
|
|
15549
15809
|
});
|
|
15550
15810
|
return compileSelect(sourcePlan, options, deps);
|
|
15551
15811
|
}
|
|
@@ -15560,20 +15820,31 @@ function prependSourceCte(sql, parameters, sourceName, sourceCte, naming) {
|
|
|
15560
15820
|
parameters: [...sourceCte.parameters, ...parameters]
|
|
15561
15821
|
};
|
|
15562
15822
|
}
|
|
15823
|
+
function resolveMutationExistsForeignKey(foreignKey, relationName) {
|
|
15824
|
+
if (typeof foreignKey === "string") return foreignKey;
|
|
15825
|
+
if (!Array.isArray(foreignKey)) return void 0;
|
|
15826
|
+
if (foreignKey.length > 1) {
|
|
15827
|
+
throw new Error(
|
|
15828
|
+
`Mutation exists()/notExists() guards do not support composite foreignKey relations yet: relation '${relationName}' has foreignKey ${JSON.stringify(foreignKey)}. Composite FK correlation is tracked by #179.`
|
|
15829
|
+
);
|
|
15830
|
+
}
|
|
15831
|
+
return foreignKey[0];
|
|
15832
|
+
}
|
|
15563
15833
|
function resolveExistsRelation(sourceTable, relation, model) {
|
|
15564
15834
|
if (!model) return { targetTable: relation };
|
|
15565
|
-
const
|
|
15835
|
+
const relationName = `${sourceTable}.${relation}`;
|
|
15836
|
+
const rel = model.getRelation(relationName);
|
|
15566
15837
|
if (!rel) return { targetTable: relation };
|
|
15567
15838
|
const targetTable = rel.target;
|
|
15568
15839
|
if (rel.type === "belongsTo") {
|
|
15569
|
-
const fk2 =
|
|
15840
|
+
const fk2 = resolveMutationExistsForeignKey(rel.foreignKey, relationName);
|
|
15570
15841
|
return {
|
|
15571
15842
|
targetTable,
|
|
15572
15843
|
...fk2 !== void 0 && { sourceColumn: fk2 },
|
|
15573
15844
|
targetColumn: "id"
|
|
15574
15845
|
};
|
|
15575
15846
|
}
|
|
15576
|
-
const fk =
|
|
15847
|
+
const fk = resolveMutationExistsForeignKey(rel.foreignKey, relationName);
|
|
15577
15848
|
return {
|
|
15578
15849
|
targetTable,
|
|
15579
15850
|
sourceColumn: rel.sourceKey ?? "id",
|
|
@@ -15601,7 +15872,11 @@ function resolveExistsIntent(where, sourceTable, deps) {
|
|
|
15601
15872
|
if (kind !== "exists" && kind !== "notExists") return where;
|
|
15602
15873
|
const relation = w.relation;
|
|
15603
15874
|
const resolved = resolveExistsRelation(sourceTable, relation, deps.model);
|
|
15604
|
-
|
|
15875
|
+
const nestedWhere = w.where;
|
|
15876
|
+
const enrichedNestedWhere = nestedWhere !== void 0 ? resolveExistsIntent(nestedWhere, resolved.targetTable, deps) : void 0;
|
|
15877
|
+
if (resolved.targetTable === relation && !resolved.sourceColumn && !resolved.targetColumn && enrichedNestedWhere === nestedWhere) {
|
|
15878
|
+
return where;
|
|
15879
|
+
}
|
|
15605
15880
|
return {
|
|
15606
15881
|
...w,
|
|
15607
15882
|
targetTable: resolved.targetTable,
|
|
@@ -15610,7 +15885,8 @@ function resolveExistsIntent(where, sourceTable, deps) {
|
|
|
15610
15885
|
},
|
|
15611
15886
|
...resolved.targetColumn !== void 0 && {
|
|
15612
15887
|
targetColumn: resolved.targetColumn
|
|
15613
|
-
}
|
|
15888
|
+
},
|
|
15889
|
+
...enrichedNestedWhere !== void 0 && { where: enrichedNestedWhere }
|
|
15614
15890
|
};
|
|
15615
15891
|
}
|
|
15616
15892
|
function getColumnTypes(tableName, columns, deps) {
|
|
@@ -15636,13 +15912,17 @@ function compileUpsertActionWhere(where, table, state, deps, schemaName) {
|
|
|
15636
15912
|
...schemaName !== void 0 && { schemaName },
|
|
15637
15913
|
...deps.bindingNames !== void 0 && { bindingNames: deps.bindingNames },
|
|
15638
15914
|
...deps.model !== void 0 && { model: deps.model },
|
|
15915
|
+
...deps.dialectCapabilities !== void 0 && {
|
|
15916
|
+
dialectCapabilities: deps.dialectCapabilities
|
|
15917
|
+
},
|
|
15639
15918
|
compileSubquery: (sqIntent, paramOffset) => buildSubqueryFromIntent(
|
|
15640
15919
|
sqIntent,
|
|
15641
15920
|
paramOffset,
|
|
15642
15921
|
deps.naming,
|
|
15643
15922
|
schemaName,
|
|
15644
15923
|
"rawExists",
|
|
15645
|
-
deps.bindingNames
|
|
15924
|
+
deps.bindingNames,
|
|
15925
|
+
deps.dialectCapabilities
|
|
15646
15926
|
)
|
|
15647
15927
|
};
|
|
15648
15928
|
return compileWhereIntent(where, whereCtx);
|
|
@@ -15653,6 +15933,9 @@ function compileInsert2(intent, options, deps) {
|
|
|
15653
15933
|
naming: deps.naming,
|
|
15654
15934
|
rootTable: intent.table,
|
|
15655
15935
|
...schemaName !== void 0 && { schema: schemaName },
|
|
15936
|
+
...deps.dialectCapabilities !== void 0 && {
|
|
15937
|
+
dialectCapabilities: deps.dialectCapabilities
|
|
15938
|
+
},
|
|
15656
15939
|
...deps.bindingNames !== void 0 && { bindingNames: deps.bindingNames },
|
|
15657
15940
|
maxRecursiveDepth: 100
|
|
15658
15941
|
};
|
|
@@ -15699,15 +15982,19 @@ function compileInsertFrom2(intent, options, deps) {
|
|
|
15699
15982
|
naming: deps.naming,
|
|
15700
15983
|
rootTable: intent.source,
|
|
15701
15984
|
...schemaName !== void 0 && { schema: schemaName },
|
|
15985
|
+
...deps.dialectCapabilities !== void 0 && {
|
|
15986
|
+
dialectCapabilities: deps.dialectCapabilities
|
|
15987
|
+
},
|
|
15702
15988
|
...bindingNames !== void 0 && { bindingNames },
|
|
15703
15989
|
maxRecursiveDepth: 100
|
|
15704
15990
|
};
|
|
15705
15991
|
const state = createCompilerState();
|
|
15992
|
+
const resolvedWhere = intent.where ? resolveExistsIntent(intent.where, intent.source, deps) : void 0;
|
|
15706
15993
|
const config = {
|
|
15707
15994
|
targetTable: intent.table,
|
|
15708
15995
|
sourceTable: intent.source,
|
|
15709
15996
|
...intent.columns && { columns: [...intent.columns] },
|
|
15710
|
-
...
|
|
15997
|
+
...resolvedWhere && { where: [whereIntentAsDecision(resolvedWhere)] },
|
|
15711
15998
|
...intent.limit !== void 0 && { limit: intent.limit },
|
|
15712
15999
|
...intent.returning && { returning: [...intent.returning] }
|
|
15713
16000
|
};
|
|
@@ -15730,6 +16017,9 @@ function compileUpdate2(intent, options, deps) {
|
|
|
15730
16017
|
...schemaName !== void 0 && { schema: schemaName },
|
|
15731
16018
|
...deps.bindingNames !== void 0 && { bindingNames: deps.bindingNames },
|
|
15732
16019
|
...resolvedModel !== void 0 && { model: resolvedModel },
|
|
16020
|
+
...deps.dialectCapabilities !== void 0 && {
|
|
16021
|
+
dialectCapabilities: deps.dialectCapabilities
|
|
16022
|
+
},
|
|
15733
16023
|
maxRecursiveDepth: 100
|
|
15734
16024
|
};
|
|
15735
16025
|
const state = createCompilerState();
|
|
@@ -15759,6 +16049,9 @@ function compileBatchUpdate(intent, _options, deps) {
|
|
|
15759
16049
|
naming: deps.naming,
|
|
15760
16050
|
rootTable: intent.table,
|
|
15761
16051
|
...schemaName !== void 0 && { schema: schemaName },
|
|
16052
|
+
...deps.dialectCapabilities !== void 0 && {
|
|
16053
|
+
dialectCapabilities: deps.dialectCapabilities
|
|
16054
|
+
},
|
|
15762
16055
|
...deps.bindingNames !== void 0 && { bindingNames: deps.bindingNames },
|
|
15763
16056
|
maxRecursiveDepth: 100
|
|
15764
16057
|
};
|
|
@@ -15789,6 +16082,7 @@ function compileBatchUpdate(intent, _options, deps) {
|
|
|
15789
16082
|
})) : void 0;
|
|
15790
16083
|
let whereGuard;
|
|
15791
16084
|
if (intent.where) {
|
|
16085
|
+
const resolvedWhere = resolveExistsIntent(intent.where, intent.table, deps);
|
|
15792
16086
|
const whereCtx = {
|
|
15793
16087
|
rootTable: intent.table,
|
|
15794
16088
|
aliases: /* @__PURE__ */ new Map(),
|
|
@@ -15799,16 +16093,20 @@ function compileBatchUpdate(intent, _options, deps) {
|
|
|
15799
16093
|
bindingNames: deps.bindingNames
|
|
15800
16094
|
},
|
|
15801
16095
|
...deps.model !== void 0 && { model: deps.model },
|
|
16096
|
+
...deps.dialectCapabilities !== void 0 && {
|
|
16097
|
+
dialectCapabilities: deps.dialectCapabilities
|
|
16098
|
+
},
|
|
15802
16099
|
compileSubquery: (sqIntent, paramOffset) => buildSubqueryFromIntent(
|
|
15803
16100
|
sqIntent,
|
|
15804
16101
|
paramOffset,
|
|
15805
16102
|
deps.naming,
|
|
15806
16103
|
schemaName,
|
|
15807
16104
|
"rawExists",
|
|
15808
|
-
deps.bindingNames
|
|
16105
|
+
deps.bindingNames,
|
|
16106
|
+
deps.dialectCapabilities
|
|
15809
16107
|
)
|
|
15810
16108
|
};
|
|
15811
|
-
whereGuard = compileWhereIntent(
|
|
16109
|
+
whereGuard = compileWhereIntent(resolvedWhere, whereCtx);
|
|
15812
16110
|
}
|
|
15813
16111
|
const config = {
|
|
15814
16112
|
table: intent.table,
|
|
@@ -15835,6 +16133,9 @@ function compileDelete2(intent, options, deps) {
|
|
|
15835
16133
|
rootTable: intent.table,
|
|
15836
16134
|
...schemaName !== void 0 && { schema: schemaName },
|
|
15837
16135
|
...deps.bindingNames !== void 0 && { bindingNames: deps.bindingNames },
|
|
16136
|
+
...deps.dialectCapabilities !== void 0 && {
|
|
16137
|
+
dialectCapabilities: deps.dialectCapabilities
|
|
16138
|
+
},
|
|
15838
16139
|
maxRecursiveDepth: 100,
|
|
15839
16140
|
...resolvedModel !== void 0 && { model: resolvedModel }
|
|
15840
16141
|
};
|
|
@@ -15860,6 +16161,9 @@ function compileUpsert2(intent, options, deps) {
|
|
|
15860
16161
|
...schemaName !== void 0 && { schema: schemaName },
|
|
15861
16162
|
...deps.bindingNames !== void 0 && { bindingNames: deps.bindingNames },
|
|
15862
16163
|
...deps.model !== void 0 && { model: deps.model },
|
|
16164
|
+
...deps.dialectCapabilities !== void 0 && {
|
|
16165
|
+
dialectCapabilities: deps.dialectCapabilities
|
|
16166
|
+
},
|
|
15863
16167
|
maxRecursiveDepth: 100
|
|
15864
16168
|
};
|
|
15865
16169
|
const state = createCompilerState();
|
|
@@ -15953,10 +16257,14 @@ function compileUpsertFrom2(intent, options, deps) {
|
|
|
15953
16257
|
naming: deps.naming,
|
|
15954
16258
|
rootTable: intent.source,
|
|
15955
16259
|
...schemaName !== void 0 && { schema: schemaName },
|
|
16260
|
+
...deps.dialectCapabilities !== void 0 && {
|
|
16261
|
+
dialectCapabilities: deps.dialectCapabilities
|
|
16262
|
+
},
|
|
15956
16263
|
...bindingNames !== void 0 && { bindingNames },
|
|
15957
16264
|
maxRecursiveDepth: 100
|
|
15958
16265
|
};
|
|
15959
16266
|
const state = createCompilerState();
|
|
16267
|
+
const resolvedWhere = intent.where ? resolveExistsIntent(intent.where, intent.source, deps) : void 0;
|
|
15960
16268
|
let columns;
|
|
15961
16269
|
if (intent.columns) {
|
|
15962
16270
|
columns = [...intent.columns];
|
|
@@ -15971,7 +16279,7 @@ function compileUpsertFrom2(intent, options, deps) {
|
|
|
15971
16279
|
sourceTable: intent.source,
|
|
15972
16280
|
conflictColumns: [...intent.conflictColumns],
|
|
15973
16281
|
...columns && { columns },
|
|
15974
|
-
...
|
|
16282
|
+
...resolvedWhere && { where: [whereIntentAsDecision(resolvedWhere)] },
|
|
15975
16283
|
...intent.limit !== void 0 && { limit: intent.limit },
|
|
15976
16284
|
...intent.returning && { returning: [...intent.returning] }
|
|
15977
16285
|
};
|
|
@@ -17363,6 +17671,7 @@ function mapFetchDirection(direction) {
|
|
|
17363
17671
|
|
|
17364
17672
|
// src/pgsql-adapter.ts
|
|
17365
17673
|
init_validate();
|
|
17674
|
+
var MAX_NQL_RUNTIME_BINDING_VALUES_PARAMETERS = 32e3;
|
|
17366
17675
|
function renumberSqlParams2(sql, offset) {
|
|
17367
17676
|
if (offset === 0) return sql;
|
|
17368
17677
|
return sql.replace(/\$(\d+)/g, (_match, num) => {
|
|
@@ -17370,7 +17679,7 @@ function renumberSqlParams2(sql, offset) {
|
|
|
17370
17679
|
});
|
|
17371
17680
|
}
|
|
17372
17681
|
function isCompiledNqlQuery(input) {
|
|
17373
|
-
return !("intent" in input) && ("query" in input || "cteQuery" in input || "mutation" in input || "setOperation" in input || "bindings" in input || "mutationBindings" in input);
|
|
17682
|
+
return !("intent" in input) && ("query" in input || "cteQuery" in input || "mutation" in input || "setOperation" in input || "bindings" in input || "mutationBindings" in input || "runtimeBindings" in input);
|
|
17374
17683
|
}
|
|
17375
17684
|
function formatGuardPathSegment(key) {
|
|
17376
17685
|
return /^[A-Za-z_$][\w$]*$/.test(key) ? `.${key}` : `[${JSON.stringify(key)}]`;
|
|
@@ -17445,6 +17754,175 @@ function findDuplicateEmittedNqlBindingName(bindingNames, naming) {
|
|
|
17445
17754
|
}
|
|
17446
17755
|
return void 0;
|
|
17447
17756
|
}
|
|
17757
|
+
function orderedNqlBindingNames(bundle) {
|
|
17758
|
+
const names = [];
|
|
17759
|
+
const seen = /* @__PURE__ */ new Set();
|
|
17760
|
+
for (const name of bundle.bindings?.keys() ?? []) {
|
|
17761
|
+
names.push(name);
|
|
17762
|
+
seen.add(name);
|
|
17763
|
+
}
|
|
17764
|
+
for (const name of bundle.runtimeBindings?.keys() ?? []) {
|
|
17765
|
+
if (!seen.has(name)) {
|
|
17766
|
+
names.push(name);
|
|
17767
|
+
seen.add(name);
|
|
17768
|
+
}
|
|
17769
|
+
}
|
|
17770
|
+
return names;
|
|
17771
|
+
}
|
|
17772
|
+
function mapRuntimeBindingColumnType(type) {
|
|
17773
|
+
switch (type) {
|
|
17774
|
+
case "string":
|
|
17775
|
+
return "text";
|
|
17776
|
+
case "text":
|
|
17777
|
+
return "text";
|
|
17778
|
+
case "number":
|
|
17779
|
+
case "integer":
|
|
17780
|
+
return "integer";
|
|
17781
|
+
case "bigint":
|
|
17782
|
+
return "bigint";
|
|
17783
|
+
case "decimal":
|
|
17784
|
+
return "numeric";
|
|
17785
|
+
case "boolean":
|
|
17786
|
+
return "boolean";
|
|
17787
|
+
case "date":
|
|
17788
|
+
return "date";
|
|
17789
|
+
case "time":
|
|
17790
|
+
return "time";
|
|
17791
|
+
case "datetime":
|
|
17792
|
+
case "timestamp":
|
|
17793
|
+
return "timestamptz";
|
|
17794
|
+
case "json":
|
|
17795
|
+
case "jsonb":
|
|
17796
|
+
return "jsonb";
|
|
17797
|
+
case "uuid":
|
|
17798
|
+
return "uuid";
|
|
17799
|
+
case "daterange":
|
|
17800
|
+
return "daterange";
|
|
17801
|
+
case "tsrange":
|
|
17802
|
+
return "tsrange";
|
|
17803
|
+
case "tstzrange":
|
|
17804
|
+
return "tstzrange";
|
|
17805
|
+
case "int4range":
|
|
17806
|
+
return "int4range";
|
|
17807
|
+
case "int8range":
|
|
17808
|
+
return "int8range";
|
|
17809
|
+
case "numrange":
|
|
17810
|
+
return "numrange";
|
|
17811
|
+
default:
|
|
17812
|
+
return void 0;
|
|
17813
|
+
}
|
|
17814
|
+
}
|
|
17815
|
+
function findRuntimeBindingSourceTable(model, sourceTable) {
|
|
17816
|
+
return model.getTable(sourceTable) ?? [...model.tables.values()].find((table) => table.name === sourceTable);
|
|
17817
|
+
}
|
|
17818
|
+
function resolveRuntimeBindingColumnType(bindingName, sourceTable, columnName) {
|
|
17819
|
+
const column = sourceTable.columns.find(
|
|
17820
|
+
(candidate) => candidate.name === columnName
|
|
17821
|
+
);
|
|
17822
|
+
if (column === void 0) {
|
|
17823
|
+
throw new Error(
|
|
17824
|
+
`NQL runtime binding '${bindingName}' cannot resolve projected column '${columnName}' on source mutation table '${sourceTable.name}'.`
|
|
17825
|
+
);
|
|
17826
|
+
}
|
|
17827
|
+
const dbType = column.originalDbType?.trim() || mapRuntimeBindingColumnType(column.type);
|
|
17828
|
+
if (dbType === void 0 || dbType.trim() === "") {
|
|
17829
|
+
throw new Error(
|
|
17830
|
+
`NQL runtime binding '${bindingName}' cannot resolve a PostgreSQL type for projected column '${columnName}' on source mutation table '${sourceTable.name}'.`
|
|
17831
|
+
);
|
|
17832
|
+
}
|
|
17833
|
+
const typeName = dbType.trim();
|
|
17834
|
+
try {
|
|
17835
|
+
validateTypeName4(typeName);
|
|
17836
|
+
} catch (error) {
|
|
17837
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
17838
|
+
throw new Error(
|
|
17839
|
+
`NQL runtime binding '${bindingName}' cannot use PostgreSQL cast type for projected column '${columnName}': ${reason}`
|
|
17840
|
+
);
|
|
17841
|
+
}
|
|
17842
|
+
return typeName;
|
|
17843
|
+
}
|
|
17844
|
+
function resolveRuntimeBindingColumnTypes(name, binding, model, sourceTableName) {
|
|
17845
|
+
if (model === void 0) {
|
|
17846
|
+
throw new Error(
|
|
17847
|
+
`NQL runtime binding '${name}' cannot materialize non-empty rows because no model is available for source-table column type resolution.`
|
|
17848
|
+
);
|
|
17849
|
+
}
|
|
17850
|
+
const sourceTable = findRuntimeBindingSourceTable(model, sourceTableName);
|
|
17851
|
+
if (sourceTable === void 0) {
|
|
17852
|
+
throw new Error(
|
|
17853
|
+
`NQL runtime binding '${name}' cannot resolve source mutation table '${sourceTableName}' in the model.`
|
|
17854
|
+
);
|
|
17855
|
+
}
|
|
17856
|
+
return binding.columns.map(
|
|
17857
|
+
(column) => resolveRuntimeBindingColumnType(name, sourceTable, column)
|
|
17858
|
+
);
|
|
17859
|
+
}
|
|
17860
|
+
function assertRuntimeBindingValuesParameterCount(name, binding, parameterOffset) {
|
|
17861
|
+
const valueParameterCount = binding.rows.length * binding.columns.length;
|
|
17862
|
+
if (valueParameterCount <= MAX_NQL_RUNTIME_BINDING_VALUES_PARAMETERS && parameterOffset + valueParameterCount <= MAX_NQL_RUNTIME_BINDING_VALUES_PARAMETERS) {
|
|
17863
|
+
return;
|
|
17864
|
+
}
|
|
17865
|
+
const totalParameterCount = parameterOffset + valueParameterCount;
|
|
17866
|
+
throw new Error(
|
|
17867
|
+
`NQL runtime binding '${name}' would materialize ${valueParameterCount} VALUES parameters; limit is ${MAX_NQL_RUNTIME_BINDING_VALUES_PARAMETERS}. Current parameter offset is ${parameterOffset}, which would make ${totalParameterCount} total parameters before compiling the final statement.`
|
|
17868
|
+
);
|
|
17869
|
+
}
|
|
17870
|
+
function compileNqlRuntimeBindingCte(name, binding, naming, parameterOffset, sourceTable, schemaName, model) {
|
|
17871
|
+
if (binding.columns.length === 0) {
|
|
17872
|
+
throw new Error(
|
|
17873
|
+
`NQL runtime binding '${name}' cannot be materialized without projected columns.`
|
|
17874
|
+
);
|
|
17875
|
+
}
|
|
17876
|
+
const cteName = quoteIdent2(emittedBindName(name, naming), "alias");
|
|
17877
|
+
const columnSql = binding.columns.map((column) => quoteIdent2(naming.toDatabase(column), "column")).join(", ");
|
|
17878
|
+
if (sourceTable === void 0) {
|
|
17879
|
+
throw new Error(
|
|
17880
|
+
`NQL runtime binding '${name}' cannot materialize a typed relation because its source mutation table is unavailable.`
|
|
17881
|
+
);
|
|
17882
|
+
}
|
|
17883
|
+
const projectedColumns = binding.columns.map((column) => quoteIdent2(naming.toDatabase(column), "column")).join(", ");
|
|
17884
|
+
const sourceAnchorSql = `SELECT ${projectedColumns} FROM ${qualifyTableIdent(sourceTable, schemaName, naming)} WHERE false`;
|
|
17885
|
+
if (binding.rows.length === 0) {
|
|
17886
|
+
return {
|
|
17887
|
+
cte: `${cteName} (${columnSql}) as (${sourceAnchorSql})`,
|
|
17888
|
+
parameters: []
|
|
17889
|
+
};
|
|
17890
|
+
}
|
|
17891
|
+
assertRuntimeBindingValuesParameterCount(name, binding, parameterOffset);
|
|
17892
|
+
const columnTypes = resolveRuntimeBindingColumnTypes(
|
|
17893
|
+
name,
|
|
17894
|
+
binding,
|
|
17895
|
+
model,
|
|
17896
|
+
sourceTable
|
|
17897
|
+
);
|
|
17898
|
+
const parameters = [];
|
|
17899
|
+
let nextParam = parameterOffset + 1;
|
|
17900
|
+
const valuesSql = binding.rows.map((row) => {
|
|
17901
|
+
const placeholders = binding.columns.map((column, columnIndex) => {
|
|
17902
|
+
parameters.push(row[column]);
|
|
17903
|
+
return `$${nextParam++}::${columnTypes[columnIndex]}`;
|
|
17904
|
+
});
|
|
17905
|
+
return `(${placeholders.join(", ")})`;
|
|
17906
|
+
}).join(", ");
|
|
17907
|
+
return {
|
|
17908
|
+
cte: `${cteName} (${columnSql}) as (${sourceAnchorSql} UNION ALL VALUES ${valuesSql})`,
|
|
17909
|
+
parameters
|
|
17910
|
+
};
|
|
17911
|
+
}
|
|
17912
|
+
function createNqlBindingSelectPlan(query) {
|
|
17913
|
+
return {
|
|
17914
|
+
rootTable: query.from,
|
|
17915
|
+
decisions: [],
|
|
17916
|
+
warnings: [],
|
|
17917
|
+
ctes: [],
|
|
17918
|
+
intent: query,
|
|
17919
|
+
metadata: {
|
|
17920
|
+
planningTimeMs: 0,
|
|
17921
|
+
relationsAnalyzed: 0,
|
|
17922
|
+
isAmbiguous: false
|
|
17923
|
+
}
|
|
17924
|
+
};
|
|
17925
|
+
}
|
|
17448
17926
|
var PgsqlAdapter = class _PgsqlAdapter {
|
|
17449
17927
|
pool;
|
|
17450
17928
|
client;
|
|
@@ -17521,6 +17999,7 @@ var PgsqlAdapter = class _PgsqlAdapter {
|
|
|
17521
17999
|
// `||` (not `??`): empty string is treated as "no override" and falls back to this.schemaName (which may be a configured schema or undefined)
|
|
17522
18000
|
schemaName: options?.schemaName || this.schemaName,
|
|
17523
18001
|
model: options?.model ?? this.model,
|
|
18002
|
+
dialectCapabilities: options?.dialectCapabilities ?? this.dialectCapabilities,
|
|
17524
18003
|
defaultPk: this.defaultPk,
|
|
17525
18004
|
deriveFk: this.deriveFk,
|
|
17526
18005
|
...bindingNames !== void 0 && { bindingNames }
|
|
@@ -17601,22 +18080,17 @@ var PgsqlAdapter = class _PgsqlAdapter {
|
|
|
17601
18080
|
}
|
|
17602
18081
|
compileNqlBundleLeaf(bundle, options, bindingNames) {
|
|
17603
18082
|
if (bundle.query !== void 0) {
|
|
17604
|
-
const
|
|
17605
|
-
|
|
17606
|
-
|
|
17607
|
-
|
|
17608
|
-
|
|
17609
|
-
|
|
17610
|
-
const
|
|
17611
|
-
|
|
17612
|
-
dialectCapabilities: this.dialectCapabilities
|
|
18083
|
+
const deps = this.buildCompileDeps(options, bindingNames);
|
|
18084
|
+
const queryFromBinding = hasBindingName(
|
|
18085
|
+
bindingNames,
|
|
18086
|
+
bundle.query.from,
|
|
18087
|
+
deps.naming
|
|
18088
|
+
);
|
|
18089
|
+
const planReport = queryFromBinding ? createNqlBindingSelectPlan(bundle.query) : planFn2(bundle.query, this.requireNqlCompileModel(options), {
|
|
18090
|
+
dialectCapabilities: options?.dialectCapabilities ?? this.dialectCapabilities
|
|
17613
18091
|
});
|
|
17614
18092
|
return guardCompiledQuery(
|
|
17615
|
-
compileSelect(
|
|
17616
|
-
planReport,
|
|
17617
|
-
options,
|
|
17618
|
-
this.buildCompileDeps(options, bindingNames)
|
|
17619
|
-
),
|
|
18093
|
+
compileSelect(planReport, options, deps),
|
|
17620
18094
|
"NQL query"
|
|
17621
18095
|
);
|
|
17622
18096
|
}
|
|
@@ -17657,20 +18131,41 @@ var PgsqlAdapter = class _PgsqlAdapter {
|
|
|
17657
18131
|
compileNqlBundle(bundle, options) {
|
|
17658
18132
|
const ctes = [];
|
|
17659
18133
|
const parameters = [];
|
|
17660
|
-
const
|
|
17661
|
-
const
|
|
18134
|
+
const deps = this.buildCompileDeps(options);
|
|
18135
|
+
const { naming } = deps;
|
|
18136
|
+
const bindingNamesInOrder = orderedNqlBindingNames(bundle);
|
|
18137
|
+
const duplicateEmittedBinding = bindingNamesInOrder.length > 0 ? findDuplicateEmittedNqlBindingName(bindingNamesInOrder, naming) : void 0;
|
|
17662
18138
|
if (duplicateEmittedBinding !== void 0) {
|
|
17663
18139
|
throw new Error(
|
|
17664
18140
|
`NQL bindings '${duplicateEmittedBinding.originalName}' and '${duplicateEmittedBinding.duplicateName}' emit to duplicate CTE name '${duplicateEmittedBinding.emittedName}'. NQL binding names must be unique after database naming.`
|
|
17665
18141
|
);
|
|
17666
18142
|
}
|
|
17667
|
-
const bindingNames =
|
|
17668
|
-
|
|
17669
|
-
(name) => emittedBindName(name, naming)
|
|
17670
|
-
)
|
|
18143
|
+
const bindingNames = bindingNamesInOrder.length > 0 ? new Set(
|
|
18144
|
+
bindingNamesInOrder.map((name) => emittedBindName(name, naming))
|
|
17671
18145
|
) : void 0;
|
|
17672
18146
|
this.assertNqlBindingNamesDisjointFromTables(bindingNames, options);
|
|
17673
|
-
for (const
|
|
18147
|
+
for (const name of bindingNamesInOrder) {
|
|
18148
|
+
const runtimeBinding = bundle.runtimeBindings?.get(name);
|
|
18149
|
+
if (runtimeBinding !== void 0) {
|
|
18150
|
+
const compiledRuntimeBinding = compileNqlRuntimeBindingCte(
|
|
18151
|
+
name,
|
|
18152
|
+
runtimeBinding,
|
|
18153
|
+
naming,
|
|
18154
|
+
parameters.length,
|
|
18155
|
+
bundle.mutationBindings?.get(name)?.table,
|
|
18156
|
+
deps.schemaName,
|
|
18157
|
+
deps.model
|
|
18158
|
+
);
|
|
18159
|
+
ctes.push(compiledRuntimeBinding.cte);
|
|
18160
|
+
parameters.push(...compiledRuntimeBinding.parameters);
|
|
18161
|
+
continue;
|
|
18162
|
+
}
|
|
18163
|
+
const queryIntent = bundle.bindings?.get(name);
|
|
18164
|
+
if (queryIntent === void 0) {
|
|
18165
|
+
throw new Error(
|
|
18166
|
+
`NQL binding '${name}' has no query intent or runtime rows to materialize.`
|
|
18167
|
+
);
|
|
18168
|
+
}
|
|
17674
18169
|
const cteName = quoteIdent2(emittedBindName(name, naming), "alias");
|
|
17675
18170
|
const bindingBundle = bundle.mutationBindings?.has(name) ? { mutation: bundle.mutationBindings.get(name) } : { query: queryIntent };
|
|
17676
18171
|
const compiled2 = this.compileNqlBundleLeaf(
|
|
@@ -17745,6 +18240,11 @@ var PgsqlAdapter = class _PgsqlAdapter {
|
|
|
17745
18240
|
// =========================================================================
|
|
17746
18241
|
/**
|
|
17747
18242
|
* Compile a plan to executable SQL.
|
|
18243
|
+
*
|
|
18244
|
+
* When passed a direct `CompiledNqlQuery`, the adapter trusts that the bundle
|
|
18245
|
+
* has already been semantically validated by the NQL compiler. This method
|
|
18246
|
+
* still performs adapter-owned SQL safety checks for emitted binding names
|
|
18247
|
+
* before CTE emission.
|
|
17748
18248
|
*/
|
|
17749
18249
|
compile(plan, options) {
|
|
17750
18250
|
if (isCompiledNqlQuery(plan)) {
|
|
@@ -17796,10 +18296,12 @@ var PgsqlAdapter = class _PgsqlAdapter {
|
|
|
17796
18296
|
compileSelectExpression(expr) {
|
|
17797
18297
|
const naming = this.naming;
|
|
17798
18298
|
const schemaName = this.schemaName;
|
|
18299
|
+
const dialectCapabilities = this.dialectCapabilities;
|
|
17799
18300
|
const state = createCompilerState();
|
|
17800
18301
|
const ctx = {
|
|
17801
18302
|
naming,
|
|
17802
18303
|
...schemaName !== void 0 && { schema: schemaName },
|
|
18304
|
+
dialectCapabilities,
|
|
17803
18305
|
rootTable: "",
|
|
17804
18306
|
maxRecursiveDepth: 100,
|
|
17805
18307
|
// Wire compileSubquery so that SubqueryExpressionIntent nested inside
|
|
@@ -17809,7 +18311,8 @@ var PgsqlAdapter = class _PgsqlAdapter {
|
|
|
17809
18311
|
compileSubquery(query, paramOffset) {
|
|
17810
18312
|
const innerCompiler = new PlanCompiler({
|
|
17811
18313
|
naming,
|
|
17812
|
-
...schemaName !== void 0 && { schema: schemaName }
|
|
18314
|
+
...schemaName !== void 0 && { schema: schemaName },
|
|
18315
|
+
dialectCapabilities
|
|
17813
18316
|
});
|
|
17814
18317
|
const innerPlan = {
|
|
17815
18318
|
rootTable: query.from,
|
|
@@ -17943,19 +18446,22 @@ var PgsqlAdapter = class _PgsqlAdapter {
|
|
|
17943
18446
|
);
|
|
17944
18447
|
}
|
|
17945
18448
|
compileSetOperationWithBindings(intent, model, options, bindingNames) {
|
|
17946
|
-
const compileFn =
|
|
17947
|
-
{
|
|
17948
|
-
|
|
17949
|
-
|
|
17950
|
-
|
|
17951
|
-
|
|
17952
|
-
|
|
17953
|
-
|
|
17954
|
-
|
|
17955
|
-
|
|
17956
|
-
|
|
17957
|
-
|
|
17958
|
-
|
|
18449
|
+
const compileFn = (query) => {
|
|
18450
|
+
const leafOptions = {
|
|
18451
|
+
...options,
|
|
18452
|
+
model
|
|
18453
|
+
};
|
|
18454
|
+
const deps = this.buildCompileDeps(leafOptions, bindingNames);
|
|
18455
|
+
const queryFromBinding = hasBindingName(
|
|
18456
|
+
bindingNames,
|
|
18457
|
+
query.from,
|
|
18458
|
+
deps.naming
|
|
18459
|
+
);
|
|
18460
|
+
const planReport = queryFromBinding ? createNqlBindingSelectPlan(query) : planFn2(query, model, {
|
|
18461
|
+
dialectCapabilities: options?.dialectCapabilities ?? this.dialectCapabilities
|
|
18462
|
+
});
|
|
18463
|
+
return compileSelect(planReport, leafOptions, deps);
|
|
18464
|
+
};
|
|
17959
18465
|
const result = compileSetOperation(intent, compileFn);
|
|
17960
18466
|
return guardCompiledQuery(
|
|
17961
18467
|
{
|