@dbsp/adapter-pgsql 1.1.1 → 1.2.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/dist/index.js CHANGED
@@ -1074,6 +1074,19 @@ var init_param_ref = __esm({
1074
1074
  }
1075
1075
  });
1076
1076
 
1077
+ // src/handlers/expression/param-value.ts
1078
+ function bindParameter(value, state) {
1079
+ const idx = ++state.paramIndex;
1080
+ state.parameters.push(value);
1081
+ return createParamRef(idx);
1082
+ }
1083
+ var init_param_value = __esm({
1084
+ "src/handlers/expression/param-value.ts"() {
1085
+ "use strict";
1086
+ init_param_ref();
1087
+ }
1088
+ });
1089
+
1077
1090
  // src/handlers/expression/case-value.ts
1078
1091
  function resolveCaseValue(value, alias, schema, naming, state, nestedCaseHandler) {
1079
1092
  if (value === null || value === void 0) {
@@ -1083,12 +1096,12 @@ function resolveCaseValue(value, alias, schema, naming, state, nestedCaseHandler
1083
1096
  return columnRef(value, alias, schema, naming);
1084
1097
  }
1085
1098
  if (typeof value !== "object") {
1086
- const idx = ++state.paramIndex;
1087
- state.parameters.push(value);
1088
- return createParamRef(idx);
1099
+ return bindParameter(value, state);
1089
1100
  }
1090
1101
  const expr = value;
1091
1102
  switch (expr.kind) {
1103
+ case "param":
1104
+ return bindParameter(expr.value, state);
1092
1105
  case "literal":
1093
1106
  if (expr.value === null || expr.value === void 0)
1094
1107
  return nullConstNode();
@@ -1099,11 +1112,7 @@ function resolveCaseValue(value, alias, schema, naming, state, nestedCaseHandler
1099
1112
  return integerNode(expr.value);
1100
1113
  return floatNode(String(expr.value));
1101
1114
  }
1102
- {
1103
- const idx = ++state.paramIndex;
1104
- state.parameters.push(expr.value);
1105
- return createParamRef(idx);
1106
- }
1115
+ return bindParameter(expr.value, state);
1107
1116
  case "column":
1108
1117
  return columnRef(expr.column, alias, schema, naming);
1109
1118
  case "arithmetic": {
@@ -1139,9 +1148,7 @@ function resolveCaseValue(value, alias, schema, naming, state, nestedCaseHandler
1139
1148
  }
1140
1149
  // falls through
1141
1150
  default: {
1142
- const idx = ++state.paramIndex;
1143
- state.parameters.push(value);
1144
- return createParamRef(idx);
1151
+ return bindParameter(value, state);
1145
1152
  }
1146
1153
  }
1147
1154
  }
@@ -1149,7 +1156,7 @@ var init_case_value = __esm({
1149
1156
  "src/handlers/expression/case-value.ts"() {
1150
1157
  "use strict";
1151
1158
  init_ast_helpers();
1152
- init_param_ref();
1159
+ init_param_value();
1153
1160
  }
1154
1161
  });
1155
1162
 
@@ -1428,7 +1435,17 @@ function handleAggregateExpression(expr, rootTable, decisions, applyFilter) {
1428
1435
  const aggAs = expr.as;
1429
1436
  const aggDistinct = expr.distinct;
1430
1437
  const aggFilter = expr.filter;
1431
- if (aggFunc === "count" && !aggField) {
1438
+ const aggExtraArgs = Array.isArray(expr.extraArgs) ? expr.extraArgs : void 0;
1439
+ if (!aggField && aggExtraArgs?.length) {
1440
+ const decision = {
1441
+ type: "selectNqlFunction",
1442
+ function: aggFunc,
1443
+ args: aggExtraArgs,
1444
+ table: rootTable
1445
+ };
1446
+ if (aggAs) decision.alias = aggAs;
1447
+ decisions.push(decision);
1448
+ } else if (aggFunc === "count" && !aggField) {
1432
1449
  const decision = {
1433
1450
  type: "selectFunction",
1434
1451
  function: "count",
@@ -1480,6 +1497,16 @@ function handleRawExpression(expr, rootTable, decisions) {
1480
1497
  if (expr.as) decision.alias = expr.as;
1481
1498
  decisions.push(decision);
1482
1499
  }
1500
+ function handleFunctionExpression(expr, rootTable, decisions) {
1501
+ const decision = {
1502
+ type: "selectNqlFunction",
1503
+ function: expr.name,
1504
+ args: expr.args ?? [],
1505
+ table: rootTable
1506
+ };
1507
+ if (expr.as) decision.alias = expr.as;
1508
+ decisions.push(decision);
1509
+ }
1483
1510
  function handleWindowExpression(expr, rootTable, decisions) {
1484
1511
  const windowFunc = expr.function;
1485
1512
  const windowAlias = expr.alias;
@@ -1592,6 +1619,7 @@ var init_select_expression_handlers = __esm({
1592
1619
  aggregate: (expr, rootTable, decisions, applyFilter) => handleAggregateExpression(expr, rootTable, decisions, applyFilter),
1593
1620
  coalesce: (expr, rootTable, decisions) => handleCoalesceExpression(expr, rootTable, decisions),
1594
1621
  raw: (expr, rootTable, decisions) => handleRawExpression(expr, rootTable, decisions),
1622
+ function: (expr, rootTable, decisions) => handleFunctionExpression(expr, rootTable, decisions),
1595
1623
  window: (expr, rootTable, decisions) => handleWindowExpression(expr, rootTable, decisions),
1596
1624
  case: (expr, rootTable, decisions, applyFilter, convertCondition) => handleCaseExpression(
1597
1625
  expr,
@@ -1601,7 +1629,8 @@ var init_select_expression_handlers = __esm({
1601
1629
  convertCondition
1602
1630
  ),
1603
1631
  relationColumn: (expr, rootTable, decisions) => handleRelationColumnExpression(expr, rootTable, decisions),
1604
- // pseudoColumn: intentional no-op — planner hints, not SQL
1632
+ pseudoColumn: () => {
1633
+ },
1605
1634
  arithmetic: (expr, rootTable, decisions) => handleArithmeticExpression(expr, rootTable, decisions),
1606
1635
  jsonExtract: (expr, rootTable, decisions) => handleJsonExtractExpression(expr, rootTable, decisions),
1607
1636
  jsonPathExtract: (expr, rootTable, decisions) => handleJsonPathExtractExpression(expr, rootTable, decisions),
@@ -1612,12 +1641,17 @@ var init_select_expression_handlers = __esm({
1612
1641
  ref: (expr, rootTable, decisions) => handleCustomExpressionSelect(expr, rootTable, decisions),
1613
1642
  param: (expr, rootTable, decisions) => handleCustomExpressionSelect(expr, rootTable, decisions),
1614
1643
  cast: (expr, rootTable, decisions) => handleCustomExpressionSelect(expr, rootTable, decisions),
1615
- unary: (expr, rootTable, decisions) => handleCustomExpressionSelect(expr, rootTable, decisions)
1644
+ unary: (expr, rootTable, decisions) => handleCustomExpressionSelect(expr, rootTable, decisions),
1645
+ subquery: (expr, rootTable, decisions) => handleCustomExpressionSelect(expr, rootTable, decisions),
1646
+ namedArg: (expr, rootTable, decisions) => handleCustomExpressionSelect(expr, rootTable, decisions),
1647
+ star: (expr, rootTable, decisions) => handleCustomExpressionSelect(expr, rootTable, decisions),
1648
+ array: (expr, rootTable, decisions) => handleCustomExpressionSelect(expr, rootTable, decisions)
1616
1649
  };
1617
1650
  }
1618
1651
  });
1619
1652
 
1620
1653
  // src/intent-to-decisions.ts
1654
+ import { isParamIntent } from "@dbsp/types";
1621
1655
  function intentToDecisions(intent, rootTable) {
1622
1656
  const decisions = [];
1623
1657
  if (intent.select) {
@@ -1680,16 +1714,18 @@ function convertSelect(select, rootTable) {
1680
1714
  const columns = select.columns;
1681
1715
  for (const exprUnknown of columns) {
1682
1716
  const expr = exprUnknown;
1683
- const handler = EXPRESSION_HANDLERS[expr.kind];
1684
- if (handler) {
1685
- handler(
1686
- expr,
1687
- rootTable,
1688
- decisions,
1689
- applyFilterCondition,
1690
- convertWhereCondition
1691
- );
1717
+ const kind = typeof expr.kind === "string" ? expr.kind : String(expr.kind);
1718
+ const handler = EXPRESSION_HANDLERS[kind];
1719
+ if (!handler) {
1720
+ throw new UnknownSelectExpressionKindError(kind);
1692
1721
  }
1722
+ handler(
1723
+ expr,
1724
+ rootTable,
1725
+ decisions,
1726
+ (decision, filter, table) => applyFilterCondition(decision, filter, table),
1727
+ (condition, table) => convertWhereCondition(condition, table)
1728
+ );
1693
1729
  }
1694
1730
  return decisions;
1695
1731
  }
@@ -1822,10 +1858,12 @@ function isOuterRef(value) {
1822
1858
  function containsOuterRef(where) {
1823
1859
  if (!where || typeof where !== "object") return false;
1824
1860
  const w = where;
1861
+ if (isParamIntent(w)) return false;
1825
1862
  if (isOuterRef(w)) return true;
1826
1863
  for (const value of Object.values(w)) {
1827
1864
  if (Array.isArray(value)) {
1828
- for (const item of value) {
1865
+ for (let i = 0; i < value.length; i++) {
1866
+ const item = value[i];
1829
1867
  if (containsOuterRef(item)) return true;
1830
1868
  }
1831
1869
  } else if (typeof value === "object" && value !== null) {
@@ -2122,7 +2160,7 @@ function convertWhereCondition(condition, rootTable) {
2122
2160
  table: rootTable
2123
2161
  };
2124
2162
  }
2125
- case "jsonContains":
2163
+ case "jsonContains": {
2126
2164
  return {
2127
2165
  type: "where",
2128
2166
  column: cond.field,
@@ -2130,6 +2168,7 @@ function convertWhereCondition(condition, rootTable) {
2130
2168
  value: cond.value,
2131
2169
  table: rootTable
2132
2170
  };
2171
+ }
2133
2172
  case "any":
2134
2173
  return {
2135
2174
  type: "where",
@@ -2186,10 +2225,20 @@ function convertOrderBy(order, rootTable) {
2186
2225
  }
2187
2226
  return decision;
2188
2227
  }
2228
+ var UnknownSelectExpressionKindError;
2189
2229
  var init_intent_to_decisions = __esm({
2190
2230
  "src/intent-to-decisions.ts"() {
2191
2231
  "use strict";
2192
2232
  init_select_expression_handlers();
2233
+ UnknownSelectExpressionKindError = class extends Error {
2234
+ constructor(kind) {
2235
+ super(`Unknown SELECT expression kind: ${kind}`);
2236
+ this.kind = kind;
2237
+ this.name = "UnknownSelectExpressionKindError";
2238
+ }
2239
+ kind;
2240
+ code = "ERR_ADAPTER_UNKNOWN_SELECT_EXPRESSION_KIND";
2241
+ };
2193
2242
  }
2194
2243
  });
2195
2244
 
@@ -2750,8 +2799,19 @@ var init_compiler_utils = __esm({
2750
2799
  }
2751
2800
  });
2752
2801
 
2802
+ // src/param-intent.ts
2803
+ import { isParamIntent as isParamIntent2 } from "@dbsp/types";
2804
+ function unwrapParamIntent(value) {
2805
+ return isParamIntent2(value) ? value.value : value;
2806
+ }
2807
+ var init_param_intent = __esm({
2808
+ "src/param-intent.ts"() {
2809
+ "use strict";
2810
+ }
2811
+ });
2812
+
2753
2813
  // src/handlers/where/utils.ts
2754
- import { isFieldRef } from "@dbsp/types";
2814
+ import { isFieldRef, isParamIntent as isParamIntent3 } from "@dbsp/types";
2755
2815
  function buildColumnRef(column, ctx) {
2756
2816
  if (column.includes(".")) {
2757
2817
  const dotIndex = column.indexOf(".");
@@ -2763,15 +2823,27 @@ function buildColumnRef(column, ctx) {
2763
2823
  return columnRef(column, alias, void 0, ctx.naming);
2764
2824
  }
2765
2825
  function buildParamRef(value, state) {
2766
- if (isParamRef(value)) {
2767
- state.parameters.push(value.value);
2768
- return createParamRef(value.paramIndex);
2826
+ const boundValue = unwrapParamIntent(value);
2827
+ if (isParamRef(boundValue)) {
2828
+ state.parameters.push(boundValue.value);
2829
+ return createParamRef(boundValue.paramIndex);
2769
2830
  }
2770
2831
  state.paramIndex++;
2771
- state.parameters.push(value);
2832
+ state.parameters.push(boundValue);
2772
2833
  return createParamRef(state.paramIndex);
2773
2834
  }
2774
- function compileValue(value, state, columnType) {
2835
+ function compileValue(value, state, columnType, forceParam = false) {
2836
+ const boundValue = unwrapParamIntent(value);
2837
+ if (isParamIntent3(value)) {
2838
+ const idx2 = ++state.paramIndex;
2839
+ state.parameters.push(boundValue);
2840
+ return columnType ? createTypeCastParamRef(idx2, columnType) : createParamRef(idx2);
2841
+ }
2842
+ if (forceParam) {
2843
+ const idx2 = ++state.paramIndex;
2844
+ state.parameters.push(boundValue);
2845
+ return columnType ? createTypeCastParamRef(idx2, columnType) : createParamRef(idx2);
2846
+ }
2775
2847
  if (value === null || value === void 0) {
2776
2848
  return nullConstNode();
2777
2849
  }
@@ -2783,7 +2855,10 @@ function compileValue(value, state, columnType) {
2783
2855
  state.parameters.push(value);
2784
2856
  return columnType ? createTypeCastParamRef(idx, columnType) : createParamRef(idx);
2785
2857
  }
2786
- function compileValueOrFieldRef(value, ctx, state, columnType) {
2858
+ function compileValueOrFieldRef(value, ctx, state, columnType, forceParam = false) {
2859
+ if (forceParam || isParamIntent3(value)) {
2860
+ return compileValue(value, state, columnType, true);
2861
+ }
2787
2862
  if (isFieldRef(value)) {
2788
2863
  const alias = value.scope === "outer" ? ctx.outerAlias ?? ctx.rootTable : ctx.currentAlias ?? ctx.rootTable;
2789
2864
  return columnRef(value.column, alias, void 0, ctx.naming);
@@ -2803,9 +2878,11 @@ var init_utils = __esm({
2803
2878
  "src/handlers/where/utils.ts"() {
2804
2879
  "use strict";
2805
2880
  init_ast_helpers();
2881
+ init_param_intent();
2806
2882
  init_param_ref();
2807
2883
  init_validate();
2808
2884
  init_types();
2885
+ init_param_intent();
2809
2886
  }
2810
2887
  });
2811
2888
 
@@ -2835,6 +2912,7 @@ var init_any = __esm({
2835
2912
  "src/handlers/where/any.ts"() {
2836
2913
  "use strict";
2837
2914
  init_compiler_utils();
2915
+ init_param_intent();
2838
2916
  init_param_ref();
2839
2917
  init_types();
2840
2918
  init_utils();
@@ -2845,7 +2923,8 @@ var init_any = __esm({
2845
2923
  if (!column) {
2846
2924
  throw new Error("ANY handler requires a column");
2847
2925
  }
2848
- const values = Array.isArray(decision.values) ? decision.values : [];
2926
+ const rawValues = unwrapParamIntent(decision.values);
2927
+ const values = Array.isArray(rawValues) ? rawValues : [];
2849
2928
  const columnNode = buildColumnRef(column, ctx);
2850
2929
  let pgBaseType;
2851
2930
  if (decision.dataType) {
@@ -2875,6 +2954,7 @@ var betweenHandler;
2875
2954
  var init_between = __esm({
2876
2955
  "src/handlers/where/between.ts"() {
2877
2956
  "use strict";
2957
+ init_param_intent();
2878
2958
  init_param_ref();
2879
2959
  init_utils();
2880
2960
  betweenHandler = {
@@ -2884,16 +2964,18 @@ var init_between = __esm({
2884
2964
  if (!column) {
2885
2965
  throw new Error("BETWEEN handler requires a column");
2886
2966
  }
2887
- const range = decision.value;
2967
+ const range = unwrapParamIntent(decision.value);
2888
2968
  if (!Array.isArray(range) || range.length !== 2) {
2889
2969
  throw new Error("BETWEEN condition requires [min, max] array");
2890
2970
  }
2891
2971
  const columnNode = buildColumnRef(column, ctx);
2972
+ const minValue = unwrapParamIntent(range[0]);
2973
+ const maxValue = unwrapParamIntent(range[1]);
2892
2974
  const minIdx = ++state.paramIndex;
2893
- state.parameters.push(range[0]);
2975
+ state.parameters.push(minValue);
2894
2976
  const minNode = createParamRef(minIdx);
2895
2977
  const maxIdx = ++state.paramIndex;
2896
- state.parameters.push(range[1]);
2978
+ state.parameters.push(maxValue);
2897
2979
  const maxNode = createParamRef(maxIdx);
2898
2980
  return {
2899
2981
  A_Expr: {
@@ -2969,6 +3051,7 @@ var init_custom_expression = __esm({
2969
3051
  "src/handlers/where/custom-expression.ts"() {
2970
3052
  "use strict";
2971
3053
  init_ast_helpers();
3054
+ init_param_intent();
2972
3055
  init_param_ref();
2973
3056
  init_custom();
2974
3057
  OP_MAP = {
@@ -2994,7 +3077,7 @@ var init_custom_expression = __esm({
2994
3077
  return leftNode;
2995
3078
  }
2996
3079
  const idx = ++state.paramIndex;
2997
- state.parameters.push(decision.value);
3080
+ state.parameters.push(unwrapParamIntent(decision.value));
2998
3081
  const rightNode = createParamRef(idx);
2999
3082
  const rawOp = decision.subqueryOperator ?? decision.operator ?? "=";
3000
3083
  const sqlOp = OP_MAP[rawOp];
@@ -3202,6 +3285,7 @@ var init_exists = __esm({
3202
3285
  });
3203
3286
 
3204
3287
  // src/handlers/where/in.ts
3288
+ import { isParamIntent as isParamIntent4 } from "@dbsp/types";
3205
3289
  function createInExpr(columnNode, state, values, columnType) {
3206
3290
  state.paramIndex++;
3207
3291
  state.parameters.push(values);
@@ -3228,11 +3312,22 @@ function createNotInExpr(columnNode, state, values, columnType) {
3228
3312
  }
3229
3313
  };
3230
3314
  }
3315
+ function isWholeArrayParamList(value) {
3316
+ return value.length === 1 && isParamIntent4(value[0]) && Array.isArray(value[0].value);
3317
+ }
3318
+ function unwrapCompilerInListValues(value) {
3319
+ const values = [];
3320
+ for (const item of value) {
3321
+ values.push(unwrapParamIntent(item));
3322
+ }
3323
+ return values;
3324
+ }
3231
3325
  var inHandler;
3232
3326
  var init_in = __esm({
3233
3327
  "src/handlers/where/in.ts"() {
3234
3328
  "use strict";
3235
3329
  init_ast_helpers();
3330
+ init_param_intent();
3236
3331
  init_param_ref();
3237
3332
  init_types();
3238
3333
  init_utils();
@@ -3241,7 +3336,7 @@ var init_in = __esm({
3241
3336
  compile(decision, ctx, state) {
3242
3337
  const operator = decision.operator ?? "in";
3243
3338
  const column = decision.column;
3244
- const value = decision.value;
3339
+ const value = unwrapParamIntent(decision.value);
3245
3340
  if (!column) {
3246
3341
  throw new Error("In handler requires a column");
3247
3342
  }
@@ -3251,7 +3346,7 @@ var init_in = __esm({
3251
3346
  `[in handler] Received a non-array value for operator '${operator}' on column '${column}'. This is a compiler bug: ${hint}. File a bug report.`
3252
3347
  );
3253
3348
  }
3254
- const values = value;
3349
+ const values = isWholeArrayParamList(value) ? value[0].value : unwrapCompilerInListValues(value);
3255
3350
  if (values.length === 0) {
3256
3351
  if (operator === COLLECTION_OPERATORS.NOT_IN || operator === "notIn") {
3257
3352
  return booleanConstNode(true);
@@ -3494,6 +3589,7 @@ var RANGE_OP_MAP, rangeHandler;
3494
3589
  var init_range = __esm({
3495
3590
  "src/handlers/where/range.ts"() {
3496
3591
  "use strict";
3592
+ init_param_intent();
3497
3593
  init_param_ref();
3498
3594
  init_types();
3499
3595
  init_utils();
@@ -3511,11 +3607,14 @@ var init_range = __esm({
3511
3607
  }
3512
3608
  const operator = decision.operator ?? "contains";
3513
3609
  const pgOp = RANGE_OP_MAP[operator] ?? operator;
3514
- const value = decision.value;
3610
+ const rawValue = decision.value;
3611
+ const value = unwrapParamIntent(rawValue);
3515
3612
  const columnNode = buildColumnRef(column, ctx);
3516
3613
  let paramValue;
3517
3614
  let isScalar = false;
3518
- if (isRangeValue(value)) {
3615
+ if (value !== rawValue) {
3616
+ paramValue = value;
3617
+ } else if (isRangeValue(value)) {
3519
3618
  const lower = value.lower ?? "";
3520
3619
  const upper = value.upper ?? "";
3521
3620
  paramValue = `[${lower},${upper})`;
@@ -3699,7 +3798,7 @@ function handleExpressionIntent(intent, ctx, handlerCtx) {
3699
3798
  return leftNode;
3700
3799
  }
3701
3800
  const idx = ++ctx.paramState.paramIndex;
3702
- ctx.paramState.parameters.push(exprIntent.value);
3801
+ ctx.paramState.parameters.push(unwrapParamIntent(exprIntent.value));
3703
3802
  const rightNode = createParamRef(idx);
3704
3803
  const sqlOp = OP_MAP2[exprIntent.operator] ?? "=";
3705
3804
  return binaryExpr(sqlOp, leftNode, rightNode);
@@ -3981,9 +4080,13 @@ function compileWhereIntent(intent, ctx) {
3981
4080
  if (exprRefResult !== null) return exprRefResult;
3982
4081
  }
3983
4082
  const needsColumn = intent.kind === "comparison" || intent.kind === "null";
4083
+ const rawIntent = intent;
3984
4084
  const bridged = needsColumn ? {
3985
4085
  ...intent,
3986
- column: intent.field
4086
+ column: rawIntent.field,
4087
+ ..."value" in rawIntent && {
4088
+ value: rawIntent.value
4089
+ }
3987
4090
  } : intent;
3988
4091
  return dispatcher(bridged, handlerCtx, ctx.paramState);
3989
4092
  }
@@ -3999,6 +4102,7 @@ var init_compile_where = __esm({
3999
4102
  init_utils();
4000
4103
  init_intent_to_decisions();
4001
4104
  init_naming_plugin();
4105
+ init_param_intent();
4002
4106
  init_param_ref();
4003
4107
  registerWhereDispatcherFactory(createWhereDispatcher);
4004
4108
  OP_MAP2 = {
@@ -4037,7 +4141,8 @@ var init_raw_exists = __esm({
4037
4141
  subIntent,
4038
4142
  state.paramIndex,
4039
4143
  ctx.naming,
4040
- ctx.schema
4144
+ ctx.schema,
4145
+ "rawExists"
4041
4146
  );
4042
4147
  if (innerParams) {
4043
4148
  for (const p of innerParams) {
@@ -4169,6 +4274,7 @@ var init_relation_filter = __esm({
4169
4274
  });
4170
4275
 
4171
4276
  // src/subquery-emission.ts
4277
+ import { isParamIntent as isParamIntent5 } from "@dbsp/types";
4172
4278
  function assertNoDroppedDecisionModifiers(decision, use) {
4173
4279
  const d = decision;
4174
4280
  const unsupported = [];
@@ -4287,6 +4393,12 @@ function buildPredicateSubquerySelect(use, sourceIntent, decision, ctx, state, d
4287
4393
  if (decision.limit != null) {
4288
4394
  if (typeof decision.limit === "number") {
4289
4395
  stmt.limitCount = integerNode(decision.limit);
4396
+ } else if (isParamIntent5(decision.limit)) {
4397
+ state.parameters.push(unwrapParamIntent(decision.limit));
4398
+ state.paramIndex++;
4399
+ stmt.limitCount = {
4400
+ ParamRef: { number: state.paramIndex }
4401
+ };
4290
4402
  } else {
4291
4403
  const limitObj = decision.limit;
4292
4404
  if (typeof limitObj.paramIndex !== "number") {
@@ -4304,6 +4416,7 @@ var init_subquery_emission = __esm({
4304
4416
  "use strict";
4305
4417
  init_ast_helpers();
4306
4418
  init_intent_to_decisions();
4419
+ init_param_intent();
4307
4420
  }
4308
4421
  });
4309
4422
 
@@ -4714,12 +4827,13 @@ var init_join = __esm({
4714
4827
  const targets = [];
4715
4828
  const columns = decision.columns;
4716
4829
  const columnAliases = decision.columnAliases;
4830
+ const hydrationPrefix = decision.hydrationPrefix ?? relation ?? targetAlias;
4717
4831
  if (columns && columns.length > 0) {
4718
4832
  if (columns.length === 1 && columns[0] === "*") {
4719
4833
  targets.push(starTarget(targetAlias, ctx.naming));
4720
4834
  } else {
4721
4835
  for (const col of columns) {
4722
- const outputAlias = columnAliases?.[col] ?? `${relation}.${col}`;
4836
+ const outputAlias = columnAliases?.[col] ?? `${hydrationPrefix}.${col}`;
4723
4837
  targets.push(columnTarget(col, outputAlias, targetAlias, ctx.naming));
4724
4838
  }
4725
4839
  }
@@ -5048,6 +5162,7 @@ __export(handlers_exports, {
5048
5162
  genericWindowHandler: () => genericWindowHandler,
5049
5163
  getExpressionHandler: () => getExpressionHandler,
5050
5164
  getIncludeHandler: () => getIncludeHandler,
5165
+ getNqlSafeExpressionHandler: () => getNqlSafeExpressionHandler,
5051
5166
  getRegisteredOperators: () => getRegisteredOperators,
5052
5167
  getRegistryStats: () => getRegistryStats,
5053
5168
  getWhereHandler: () => getWhereHandler,
@@ -5158,6 +5273,10 @@ function getExpressionHandler(type) {
5158
5273
  }
5159
5274
  return handler;
5160
5275
  }
5276
+ function getNqlSafeExpressionHandler(type) {
5277
+ const handler = expressionHandlers.get(type);
5278
+ return handler?.nqlSafe === true ? handler : void 0;
5279
+ }
5161
5280
  function getIncludeHandler(strategy) {
5162
5281
  const handler = includeHandlers.get(strategy);
5163
5282
  if (!handler) {
@@ -5179,7 +5298,7 @@ function ensureHandlersRegistered() {
5179
5298
  handlersInitialized = true;
5180
5299
  registerAllWhereHandlers();
5181
5300
  }
5182
- function normalizeToDecision(input) {
5301
+ function normalizeToDecision(input, ctx) {
5183
5302
  if (input.column !== void 0) {
5184
5303
  const raw2 = input;
5185
5304
  if (raw2.jsonPath && raw2.jsonPath.length > 0) {
@@ -5202,7 +5321,7 @@ function normalizeToDecision(input) {
5202
5321
  type: op3,
5203
5322
  operator: op3,
5204
5323
  conditions: (raw.conditions ?? []).map(
5205
- (c) => normalizeToDecision(c)
5324
+ (c) => normalizeToDecision(c, ctx)
5206
5325
  )
5207
5326
  };
5208
5327
  }
@@ -5214,7 +5333,7 @@ function normalizeToDecision(input) {
5214
5333
  switch (kind) {
5215
5334
  case "comparison": {
5216
5335
  if (raw.jsonPath) {
5217
- return {
5336
+ const decision = {
5218
5337
  type: "where",
5219
5338
  column: raw.field,
5220
5339
  operator: "jsonComparison",
@@ -5222,6 +5341,7 @@ function normalizeToDecision(input) {
5222
5341
  jsonPath: raw.jsonPath,
5223
5342
  jsonMode: raw.jsonMode ?? "text"
5224
5343
  };
5344
+ return decision;
5225
5345
  }
5226
5346
  return {
5227
5347
  type: "where",
@@ -5235,7 +5355,7 @@ function normalizeToDecision(input) {
5235
5355
  type: "and",
5236
5356
  operator: "and",
5237
5357
  conditions: (raw.conditions ?? []).map(
5238
- (c) => normalizeToDecision(c)
5358
+ (c) => normalizeToDecision(c, ctx)
5239
5359
  )
5240
5360
  };
5241
5361
  case "or":
@@ -5243,14 +5363,14 @@ function normalizeToDecision(input) {
5243
5363
  type: "or",
5244
5364
  operator: "or",
5245
5365
  conditions: (raw.conditions ?? []).map(
5246
- (c) => normalizeToDecision(c)
5366
+ (c) => normalizeToDecision(c, ctx)
5247
5367
  )
5248
5368
  };
5249
5369
  case "not":
5250
5370
  return {
5251
5371
  type: "not",
5252
5372
  operator: "not",
5253
- conditions: [normalizeToDecision(raw.condition)]
5373
+ conditions: [normalizeToDecision(raw.condition, ctx)]
5254
5374
  };
5255
5375
  case "null":
5256
5376
  return {
@@ -5274,7 +5394,7 @@ function normalizeToDecision(input) {
5274
5394
  );
5275
5395
  const rawSelect = sub.select;
5276
5396
  const selectColumn = typeof rawSelect === "string" ? rawSelect : isSelectWithFields(rawSelect) ? rawSelect.fields?.[0] ?? "*" : "*";
5277
- const subConditions = sub.where ? [normalizeToDecision(sub.where)] : [];
5397
+ const subConditions = sub.where ? [normalizeToDecision(sub.where, ctx)] : [];
5278
5398
  const rawLimit = sub.limit;
5279
5399
  const rawOrderBy = sub.orderBy;
5280
5400
  return {
@@ -5309,13 +5429,14 @@ function normalizeToDecision(input) {
5309
5429
  operator: raw.caseInsensitive ? "ilike" : "like",
5310
5430
  value: raw.pattern
5311
5431
  };
5312
- case "jsonContains":
5432
+ case "jsonContains": {
5313
5433
  return {
5314
5434
  type: "where",
5315
5435
  column: raw.field,
5316
5436
  operator: raw.reversed ? "jsonContainedBy" : "jsonContains",
5317
5437
  value: raw.value
5318
5438
  };
5439
+ }
5319
5440
  case "jsonExists":
5320
5441
  return {
5321
5442
  type: "where",
@@ -5326,7 +5447,7 @@ function normalizeToDecision(input) {
5326
5447
  case "exists":
5327
5448
  case "notExists": {
5328
5449
  const relation = raw.relation;
5329
- const conditions = raw.where ? [normalizeToDecision(raw.where)] : void 0;
5450
+ const conditions = raw.where ? [normalizeToDecision(raw.where, ctx)] : void 0;
5330
5451
  const targetTable = raw.targetTable ?? relation;
5331
5452
  const sourceColumn = raw.sourceColumn;
5332
5453
  const targetColumn = raw.targetColumn;
@@ -5355,7 +5476,7 @@ function normalizeToDecision(input) {
5355
5476
  function createWhereDispatcher() {
5356
5477
  return (decision, ctx, state) => {
5357
5478
  ensureHandlersRegistered();
5358
- const normalized = normalizeToDecision(decision);
5479
+ const normalized = normalizeToDecision(decision, ctx);
5359
5480
  const rawOperator = normalized.operator ?? "=";
5360
5481
  const operator = OPERATOR_ALIASES[rawOperator] ?? rawOperator;
5361
5482
  const handler = getWhereHandler(operator);
@@ -5508,16 +5629,18 @@ function resolveOperand(operand, ctx, state) {
5508
5629
  const alias = ctx.currentAlias ?? ctx.rootTable;
5509
5630
  return columnRef(operand, alias, void 0, ctx.naming);
5510
5631
  }
5511
- const idx = ++state.paramIndex;
5512
- state.parameters.push(operand);
5513
- return createParamRef(idx);
5632
+ if (typeof operand === "object" && operand !== null && "kind" in operand && ctx.compileNqlSelectExpression) {
5633
+ return ctx.compileNqlSelectExpression(operand, ctx, state);
5634
+ }
5635
+ return bindParameter(unwrapParamIntent(operand), state);
5514
5636
  }
5515
5637
  var arithmeticHandler;
5516
5638
  var init_arithmetic = __esm({
5517
5639
  "src/handlers/expression/arithmetic.ts"() {
5518
5640
  "use strict";
5519
5641
  init_ast_helpers();
5520
- init_param_ref();
5642
+ init_param_intent();
5643
+ init_param_value();
5521
5644
  arithmeticHandler = {
5522
5645
  types: ["arithmetic", "math", "calc"],
5523
5646
  compile(decision, ctx, state) {
@@ -5552,8 +5675,9 @@ var init_case = __esm({
5552
5675
  "src/handlers/expression/case.ts"() {
5553
5676
  "use strict";
5554
5677
  init_ast_helpers();
5555
- init_param_ref();
5678
+ init_param_intent();
5556
5679
  init_case_value();
5680
+ init_param_value();
5557
5681
  caseHandler = {
5558
5682
  types: ["case", "CASE", "caseWhen"],
5559
5683
  compile(decision, ctx, state) {
@@ -5599,13 +5723,12 @@ var init_case = __esm({
5599
5723
  const tableAlias = ctx.currentAlias ?? ctx.rootTable;
5600
5724
  const testExpr = columnRef(column, tableAlias, void 0, ctx.naming);
5601
5725
  const args = conditions.map((cond) => {
5602
- const whenParamNumber = ++state.paramIndex;
5603
5726
  const whenDecision = cond.when;
5604
- state.parameters.push(whenDecision.value ?? cond.when);
5605
- const whenExpr = createParamRef(whenParamNumber);
5606
- const thenParamNumber = ++state.paramIndex;
5607
- state.parameters.push(cond.then);
5608
- const thenResult = createParamRef(thenParamNumber);
5727
+ const whenExpr = bindParameter(
5728
+ unwrapParamIntent(whenDecision.value ?? cond.when),
5729
+ state
5730
+ );
5731
+ const thenResult = bindParameter(unwrapParamIntent(cond.then), state);
5609
5732
  const caseWhen = {
5610
5733
  expr: whenExpr,
5611
5734
  result: thenResult
@@ -5614,9 +5737,7 @@ var init_case = __esm({
5614
5737
  });
5615
5738
  let defresult;
5616
5739
  if (elseValue !== void 0) {
5617
- const paramNumber = ++state.paramIndex;
5618
- state.parameters.push(elseValue);
5619
- defresult = createParamRef(paramNumber);
5740
+ defresult = bindParameter(unwrapParamIntent(elseValue), state);
5620
5741
  }
5621
5742
  const caseExpr = {
5622
5743
  arg: testExpr,
@@ -5642,18 +5763,21 @@ function buildValueNode(value, ctx, state) {
5642
5763
  return columnRef(decision.column, tableAlias, void 0, ctx.naming);
5643
5764
  }
5644
5765
  }
5645
- const paramNumber = ++state.paramIndex;
5646
- state.parameters.push(value);
5647
- return createParamRef(paramNumber);
5766
+ if (typeof value === "object" && value !== null && "kind" in value && ctx.compileNqlSelectExpression) {
5767
+ return ctx.compileNqlSelectExpression(value, ctx, state);
5768
+ }
5769
+ return bindParameter(unwrapParamIntent(value), state);
5648
5770
  }
5649
5771
  var coalesceHandler, nullIfHandler, greatestHandler, leastHandler;
5650
5772
  var init_coalesce = __esm({
5651
5773
  "src/handlers/expression/coalesce.ts"() {
5652
5774
  "use strict";
5653
5775
  init_ast_helpers();
5654
- init_param_ref();
5776
+ init_param_intent();
5777
+ init_param_value();
5655
5778
  coalesceHandler = {
5656
5779
  types: ["coalesce", "COALESCE", "ifNull", "nvl"],
5780
+ nqlSafe: true,
5657
5781
  compile(decision, ctx, state) {
5658
5782
  const args = decision.args;
5659
5783
  const column = decision.column;
@@ -5693,9 +5817,7 @@ var init_coalesce = __esm({
5693
5817
  }
5694
5818
  const tableAlias = ctx.currentAlias ?? ctx.rootTable;
5695
5819
  const colRef = columnRef(column, tableAlias, void 0, ctx.naming);
5696
- const paramNumber = ++state.paramIndex;
5697
- state.parameters.push(value);
5698
- const valueRef = createParamRef(paramNumber);
5820
+ const valueRef = bindParameter(unwrapParamIntent(value), state);
5699
5821
  return {
5700
5822
  NullIfExpr: {
5701
5823
  args: [colRef, valueRef]
@@ -5793,11 +5915,30 @@ var init_column = __esm({
5793
5915
  });
5794
5916
 
5795
5917
  // src/handlers/expression/json.ts
5918
+ function normalizeJsonPathArgs(args) {
5919
+ if (!args || args.length === 0) return [];
5920
+ if (args.length === 1) {
5921
+ const first = args[0];
5922
+ const unwrappedFirst = unwrapParamIntent(first);
5923
+ if (first !== unwrappedFirst) {
5924
+ return unwrappedFirst;
5925
+ }
5926
+ if (Array.isArray(first)) {
5927
+ return first.map(unwrapParamIntent);
5928
+ }
5929
+ if (typeof first === "string" && first.startsWith("{") && first.endsWith("}")) {
5930
+ const inner = first.slice(1, -1);
5931
+ return inner.length === 0 ? [] : inner.split(",");
5932
+ }
5933
+ }
5934
+ return args.map(unwrapParamIntent);
5935
+ }
5796
5936
  var jsonExtractHandler, jsonPathExtractHandler;
5797
5937
  var init_json2 = __esm({
5798
5938
  "src/handlers/expression/json.ts"() {
5799
5939
  "use strict";
5800
5940
  init_ast_helpers();
5941
+ init_param_intent();
5801
5942
  init_utils();
5802
5943
  jsonExtractHandler = {
5803
5944
  types: ["jsonExtract"],
@@ -5834,10 +5975,10 @@ var init_json2 = __esm({
5834
5975
  throw new Error("JSON path extract handler requires a column");
5835
5976
  }
5836
5977
  const mode = decision.jsonMode ?? "text";
5837
- const arrayLiteral = decision.args?.[0] ?? "{}";
5978
+ const path = normalizeJsonPathArgs(decision.args);
5838
5979
  const alias = ctx.currentAlias ?? ctx.rootTable;
5839
5980
  const left = columnRef(column, alias, void 0, ctx.naming);
5840
- const right = compileValue(arrayLiteral, state);
5981
+ const right = compileValue(path, state);
5841
5982
  const op3 = mode === "text" ? "#>>" : "#>";
5842
5983
  return {
5843
5984
  A_Expr: {
@@ -6432,6 +6573,8 @@ var rawHandler, sqlFunctionHandler, literalHandler;
6432
6573
  var init_raw = __esm({
6433
6574
  "src/handlers/expression/raw.ts"() {
6434
6575
  "use strict";
6576
+ init_param_intent();
6577
+ init_param_value();
6435
6578
  rawHandler = {
6436
6579
  types: ["raw", "RAW", "rawSql", "rawExpression"],
6437
6580
  compile(decision, ctx, _state) {
@@ -6466,17 +6609,9 @@ var init_raw = __esm({
6466
6609
  if (args && Array.isArray(args)) {
6467
6610
  for (const arg of args) {
6468
6611
  if (typeof arg === "object" && arg !== null && "type" in arg) {
6469
- const paramNumber = ++state.paramIndex;
6470
- state.parameters.push(arg);
6471
- argNodes.push({
6472
- ParamRef: { number: paramNumber }
6473
- });
6612
+ argNodes.push(bindParameter(unwrapParamIntent(arg), state));
6474
6613
  } else {
6475
- const paramNumber = ++state.paramIndex;
6476
- state.parameters.push(arg);
6477
- argNodes.push({
6478
- ParamRef: { number: paramNumber }
6479
- });
6614
+ argNodes.push(bindParameter(unwrapParamIntent(arg), state));
6480
6615
  }
6481
6616
  }
6482
6617
  }
@@ -6698,13 +6833,9 @@ function createLagLeadHandler(funcName, types) {
6698
6833
  const colRef = columnRef(column, tableAlias, void 0, ctx.naming);
6699
6834
  const args = [colRef];
6700
6835
  const offset = decision.args?.[0] ?? 1;
6701
- const offsetParamNumber = ++state.paramIndex;
6702
- state.parameters.push(offset);
6703
- args.push(createParamRef(offsetParamNumber));
6836
+ args.push(bindParameter(unwrapParamIntent(offset), state));
6704
6837
  if (decision.value !== void 0) {
6705
- const defaultParamNumber = ++state.paramIndex;
6706
- state.parameters.push(decision.value);
6707
- args.push(createParamRef(defaultParamNumber));
6838
+ args.push(bindParameter(unwrapParamIntent(decision.value), state));
6708
6839
  }
6709
6840
  return buildWindowFunction(funcName, args, decision, ctx);
6710
6841
  }
@@ -6730,7 +6861,8 @@ var init_window = __esm({
6730
6861
  "src/handlers/expression/window.ts"() {
6731
6862
  "use strict";
6732
6863
  init_ast_helpers();
6733
- init_param_ref();
6864
+ init_param_intent();
6865
+ init_param_value();
6734
6866
  WINDOW_FRAME_DEFAULT = 1034;
6735
6867
  rowNumberHandler = createNoArgWindowHandler("row_number", [
6736
6868
  "rowNumber",
@@ -6747,9 +6879,7 @@ var init_window = __esm({
6747
6879
  types: ["ntile", "NTILE"],
6748
6880
  compile(decision, ctx, state) {
6749
6881
  const n = decision.value ?? decision.args?.[0] ?? 4;
6750
- const paramNumber = ++state.paramIndex;
6751
- state.parameters.push(n);
6752
- const nRef = createParamRef(paramNumber);
6882
+ const nRef = bindParameter(unwrapParamIntent(n), state);
6753
6883
  return buildWindowFunction("ntile", [nRef], decision, ctx);
6754
6884
  }
6755
6885
  };
@@ -6790,15 +6920,11 @@ var init_window = __esm({
6790
6920
  }
6791
6921
  if (decision.args && Array.isArray(decision.args)) {
6792
6922
  for (const arg of decision.args) {
6793
- const paramNumber = ++state.paramIndex;
6794
- state.parameters.push(arg);
6795
- args.push(createParamRef(paramNumber));
6923
+ args.push(bindParameter(unwrapParamIntent(arg), state));
6796
6924
  }
6797
6925
  }
6798
6926
  if (decision.value !== void 0) {
6799
- const defaultParamNumber = ++state.paramIndex;
6800
- state.parameters.push(decision.value);
6801
- args.push(createParamRef(defaultParamNumber));
6927
+ args.push(bindParameter(unwrapParamIntent(decision.value), state));
6802
6928
  }
6803
6929
  return buildWindowFunction(funcName, args, decision, ctx);
6804
6930
  }
@@ -6915,6 +7041,12 @@ init_ast_helpers();
6915
7041
  // src/compiler.ts
6916
7042
  init_assert_field();
6917
7043
  init_ast_helpers();
7044
+ import { InvalidOperationError as InvalidOperationError2 } from "@dbsp/core";
7045
+ import {
7046
+ isParamIntent as isParamIntent6,
7047
+ NQL_SELECT_SCALAR_FUNCTION_ALLOWLIST,
7048
+ NQL_SELECT_WINDOW_FUNCTION_ALLOWLIST
7049
+ } from "@dbsp/types";
6918
7050
 
6919
7051
  // src/pgsql-deparser.ts
6920
7052
  function deparse(node) {
@@ -7972,6 +8104,7 @@ function deparseQuoted(ast) {
7972
8104
  init_case_value();
7973
8105
  init_custom();
7974
8106
  init_expression();
8107
+ init_param_value();
7975
8108
  init_window();
7976
8109
  init_include();
7977
8110
  init_shared();
@@ -7980,9 +8113,39 @@ init_types();
7980
8113
  init_utils();
7981
8114
  init_intent_to_decisions();
7982
8115
  init_naming_plugin();
8116
+ init_param_intent();
7983
8117
  init_param_ref();
7984
8118
  init_subquery_emission();
8119
+ init_validate();
7985
8120
  registerWhereDispatcherFactory(createWhereDispatcher);
8121
+ var UnhandledNqlSelectExpressionKindError = class extends Error {
8122
+ constructor(kind) {
8123
+ super(`Unhandled NQL SELECT expression intent kind: ${kind}`);
8124
+ this.kind = kind;
8125
+ this.name = "UnhandledNqlSelectExpressionKindError";
8126
+ }
8127
+ kind;
8128
+ code = "ERR_ADAPTER_UNHANDLED_NQL_SELECT_EXPRESSION_KIND";
8129
+ };
8130
+ var UnsupportedNqlSelectFunctionError = class extends Error {
8131
+ constructor(functionName) {
8132
+ super(`Unsupported function in SELECT context: ${functionName}()`);
8133
+ this.functionName = functionName;
8134
+ this.name = "UnsupportedNqlSelectFunctionError";
8135
+ }
8136
+ functionName;
8137
+ code = "ERR_ADAPTER_UNSUPPORTED_NQL_SELECT_FUNCTION";
8138
+ };
8139
+ function assertNqlSelectScalarFunctionAllowed(functionName) {
8140
+ if (!NQL_SELECT_SCALAR_FUNCTION_ALLOWLIST.has(functionName.toLowerCase())) {
8141
+ throw new UnsupportedNqlSelectFunctionError(functionName);
8142
+ }
8143
+ }
8144
+ function assertNqlSelectWindowFunctionAllowed(functionName) {
8145
+ if (!NQL_SELECT_WINDOW_FUNCTION_ALLOWLIST.has(functionName.toLowerCase())) {
8146
+ throw new UnsupportedNqlSelectFunctionError(functionName);
8147
+ }
8148
+ }
7986
8149
  function mapToHandlerDecision(pd, rootTable, defaultPk, deriveFk) {
7987
8150
  return {
7988
8151
  type: pd.type,
@@ -8006,6 +8169,8 @@ function mapToHandlerDecision(pd, rootTable, defaultPk, deriveFk) {
8006
8169
  strategy: pd.choice === "subquery" ? "json_agg" : pd.choice,
8007
8170
  relation: pd.relation ?? pd.relationName,
8008
8171
  relationName: pd.relationName,
8172
+ relationPath: pd.relationPath,
8173
+ hydrationPrefix: pd.hydrationPrefix,
8009
8174
  relationType: pd.relationType,
8010
8175
  foreignKey: pd.foreignKey,
8011
8176
  parentKey: pd.parentKey,
@@ -8058,6 +8223,77 @@ function isPrecompiledJoinDecision(d) {
8058
8223
  function isBatchValuesJoinDecision(d) {
8059
8224
  return isPrecompiledJoinDecision(d) && d.batchValuesParams !== void 0;
8060
8225
  }
8226
+ function getRelationIdentityPath(decision, rootTable) {
8227
+ if (decision.relationPath) return decision.relationPath;
8228
+ const relationName = decision.relationName ?? decision.relation;
8229
+ if (!relationName && !decision.targetTable) return void 0;
8230
+ const source = decision.sourceTable ?? rootTable;
8231
+ const target = decision.targetTable ?? "";
8232
+ const sourceColumn = decision.sourceColumn ?? decision.foreignKey ?? "";
8233
+ return `__legacy__:${source}:${relationName ?? target}:${sourceColumn}:${target}`;
8234
+ }
8235
+ function getParentRelationPath(relationPath) {
8236
+ if (!relationPath || relationPath.startsWith("__legacy__:")) return void 0;
8237
+ const lastDot = relationPath.lastIndexOf(".");
8238
+ return lastDot > 0 ? relationPath.slice(0, lastDot) : void 0;
8239
+ }
8240
+ function mergeColumnLists(current, next) {
8241
+ if (!current) return next ? [...next] : void 0;
8242
+ if (!next) return current;
8243
+ if (current.includes("*") || next.includes("*")) return ["*"];
8244
+ const merged = [...current];
8245
+ for (const column of next) {
8246
+ if (!merged.includes(column)) merged.push(column);
8247
+ }
8248
+ return merged;
8249
+ }
8250
+ function mergeDuplicateJoinIncludeDecisions(decisions, rootTable) {
8251
+ const merged = [];
8252
+ const seenByPath = /* @__PURE__ */ new Map();
8253
+ for (const decision of decisions) {
8254
+ const identityPath = decision.type === "includeStrategy" && decision.choice === "join" ? getRelationIdentityPath(decision, rootTable) : void 0;
8255
+ if (!identityPath) {
8256
+ merged.push(decision);
8257
+ continue;
8258
+ }
8259
+ const existing = seenByPath.get(identityPath);
8260
+ if (!existing) {
8261
+ const copy = {
8262
+ ...decision,
8263
+ ...decision.columns ? { columns: [...decision.columns] } : {},
8264
+ ...decision.columnAliases ? { columnAliases: { ...decision.columnAliases } } : {},
8265
+ ...decision.conditions ? { conditions: [...decision.conditions] } : {}
8266
+ };
8267
+ seenByPath.set(identityPath, copy);
8268
+ merged.push(copy);
8269
+ continue;
8270
+ }
8271
+ const existingJoinType = existing.joinType ?? "left";
8272
+ const nextJoinType = decision.joinType ?? "left";
8273
+ if (existingJoinType !== nextJoinType) {
8274
+ throw new InvalidOperationError2(
8275
+ "include",
8276
+ `Conflicting join options for relation path '${identityPath}'. Already registered as ${existingJoinType}, got ${nextJoinType}.`
8277
+ );
8278
+ }
8279
+ const mutable = existing;
8280
+ const columns = mergeColumnLists(existing.columns, decision.columns);
8281
+ if (columns) mutable.columns = columns;
8282
+ if (decision.columnAliases) {
8283
+ mutable.columnAliases = {
8284
+ ...decision.columnAliases,
8285
+ ...existing.columnAliases ?? {}
8286
+ };
8287
+ }
8288
+ if (decision.conditions && decision.conditions.length > 0) {
8289
+ mutable.conditions = [
8290
+ ...existing.conditions ?? [],
8291
+ ...decision.conditions
8292
+ ];
8293
+ }
8294
+ }
8295
+ return merged;
8296
+ }
8061
8297
  function renumberParamRefsInAst(node, offset) {
8062
8298
  if (offset === 0) return node;
8063
8299
  return renumberNode(node, offset);
@@ -8114,9 +8350,9 @@ var PlanCompiler = class _PlanCompiler {
8114
8350
  /** CTE nodes from include handlers (e.g., CTE strategy) */
8115
8351
  pendingCtes = [];
8116
8352
  /**
8117
- * Maps joined targetTable → alias for multi-hop FK resolution.
8118
- * Populated as join decisions are compiled so later hops can find
8119
- * the correct source alias (e.g., 'symbols' 'callee').
8353
+ * Maps relation-dotted include path JOIN alias for multi-hop FK resolution.
8354
+ * Populated as join decisions are compiled so later hops can find the
8355
+ * correct source alias (e.g., 'callee.file' reads parent path 'callee').
8120
8356
  */
8121
8357
  joinAliasMap = /* @__PURE__ */ new Map();
8122
8358
  /**
@@ -8143,6 +8379,13 @@ var PlanCompiler = class _PlanCompiler {
8143
8379
  ...this.model != null && { model: this.model }
8144
8380
  };
8145
8381
  }
8382
+ findAliasForLegacySourceTable(sourceTable) {
8383
+ let alias;
8384
+ for (const entry of this.joinAliasMap.values()) {
8385
+ if (entry.targetTable === sourceTable) alias = entry.alias;
8386
+ }
8387
+ return alias;
8388
+ }
8146
8389
  /**
8147
8390
  * Dispatch a PlanDecision through the unified WHERE handler system.
8148
8391
  * Bridges PlanCompiler's state to handler types, calls dispatcher, syncs back.
@@ -8293,7 +8536,21 @@ var PlanCompiler = class _PlanCompiler {
8293
8536
  const combined = condNodes.length === 1 ? condNodes[0] : andExpr(...condNodes);
8294
8537
  handlerDecision._compiledFilterWhere = combined;
8295
8538
  }
8296
- const sourceAlias = decision.sourceTable && decision.sourceTable !== plan.rootTable ? this.joinAliasMap.get(decision.sourceTable) ?? decision.sourceTable : plan.rootTable;
8539
+ const relationIdentityPath = decision.choice === "join" ? getRelationIdentityPath(decision, plan.rootTable) : void 0;
8540
+ const requestedJoinType = decision.joinType ?? "left";
8541
+ const existingJoin = relationIdentityPath ? this.joinAliasMap.get(relationIdentityPath) : void 0;
8542
+ if (existingJoin) {
8543
+ if (existingJoin.joinType !== requestedJoinType) {
8544
+ throw new InvalidOperationError2(
8545
+ "include",
8546
+ `Conflicting join options for relation path '${relationIdentityPath}'. Already registered as ${existingJoin.joinType}, got ${requestedJoinType}.`
8547
+ );
8548
+ }
8549
+ return {};
8550
+ }
8551
+ const parentRelationPath = getParentRelationPath(relationIdentityPath);
8552
+ const parentAlias = parentRelationPath ? this.joinAliasMap.get(parentRelationPath)?.alias : void 0;
8553
+ const sourceAlias = parentAlias ?? (decision.sourceTable && decision.sourceTable !== plan.rootTable ? this.findAliasForLegacySourceTable(decision.sourceTable) ?? decision.sourceTable : plan.rootTable);
8297
8554
  const ctx = {
8298
8555
  ...this.handlerCtx(),
8299
8556
  currentAlias: sourceAlias
@@ -8314,6 +8571,7 @@ var PlanCompiler = class _PlanCompiler {
8314
8571
  while (this.usedJoinAliases.has(alias)) {
8315
8572
  alias = `${candidateAlias}_${counter++}`;
8316
8573
  }
8574
+ validateIdentifier(alias, "alias");
8317
8575
  this.usedJoinAliases.add(alias);
8318
8576
  finalJoinAlias = alias;
8319
8577
  if (alias !== candidateAlias) {
@@ -8323,11 +8581,12 @@ var PlanCompiler = class _PlanCompiler {
8323
8581
  }
8324
8582
  const result = handler.compile(handlerDecision, ctx, handlerState);
8325
8583
  this.state.paramIndex = handlerState.paramIndex;
8326
- if (decision.choice === "join" && decision.targetTable && (finalJoinAlias ?? decision.relationName)) {
8327
- this.joinAliasMap.set(
8328
- decision.targetTable,
8329
- finalJoinAlias ?? decision.relationName
8330
- );
8584
+ if (decision.choice === "join" && relationIdentityPath && finalJoinAlias) {
8585
+ this.joinAliasMap.set(relationIdentityPath, {
8586
+ alias: finalJoinAlias,
8587
+ joinType: requestedJoinType,
8588
+ ...decision.targetTable && { targetTable: decision.targetTable }
8589
+ });
8331
8590
  }
8332
8591
  const out = {};
8333
8592
  if (result.targets) out.targets = result.targets;
@@ -8353,6 +8612,7 @@ var PlanCompiler = class _PlanCompiler {
8353
8612
  this.rawJoins = [];
8354
8613
  this.pendingCtes = [];
8355
8614
  this.joinAliasMap = /* @__PURE__ */ new Map();
8615
+ this.usedJoinAliases = /* @__PURE__ */ new Set();
8356
8616
  const queryType = this.detectQueryType(plan.decisions);
8357
8617
  let ast;
8358
8618
  switch (queryType) {
@@ -8402,7 +8662,9 @@ var PlanCompiler = class _PlanCompiler {
8402
8662
  defaultPkColumnName: this.defaultPk,
8403
8663
  deriveFkColumnName: this.deriveFk,
8404
8664
  ...plan.schema ?? this.schema ? { schema: plan.schema ?? this.schema } : {},
8405
- ...this.model != null && { model: this.model }
8665
+ ...this.model != null && { model: this.model },
8666
+ compileSubquery: (query, paramOffset) => this.compileExpressionSubquery(query, paramOffset),
8667
+ compileNqlSelectExpression: (value, handlerCtx, state) => this.compileNqlFunctionArg(value, handlerCtx, state)
8406
8668
  };
8407
8669
  }
8408
8670
  /** Build a fresh HandlerCompilerState sharing the current parameter array. */
@@ -8415,6 +8677,247 @@ var PlanCompiler = class _PlanCompiler {
8415
8677
  joins: []
8416
8678
  };
8417
8679
  }
8680
+ compileExpressionSubquery(query, paramOffset) {
8681
+ const innerCompiler = new _PlanCompiler({
8682
+ naming: this.naming,
8683
+ ...this.schema !== void 0 && {
8684
+ schema: this.schema
8685
+ },
8686
+ defaultPkColumnName: this.defaultPk,
8687
+ deriveFkColumnName: this.deriveFk
8688
+ });
8689
+ const innerPlan = {
8690
+ rootTable: query.from,
8691
+ decisions: intentToDecisions(query, query.from)
8692
+ };
8693
+ const innerResult = innerCompiler.compile(innerPlan);
8694
+ const renumbered = renumberParamRefsInAst(innerResult.ast, paramOffset);
8695
+ return { ast: renumbered, parameters: innerResult.parameters };
8696
+ }
8697
+ compileGenericNqlFunction(functionName, args, ctx, state) {
8698
+ assertNqlSelectScalarFunctionAllowed(functionName);
8699
+ validateIdentifier(functionName, "function");
8700
+ const argNodes = args.map(
8701
+ (arg) => this.compileNqlFunctionArg(arg, ctx, state)
8702
+ );
8703
+ return funcCall(functionName, argNodes);
8704
+ }
8705
+ compileNqlFunctionArg(arg, ctx, state) {
8706
+ if (typeof arg === "string") {
8707
+ return buildColumnRef(arg, ctx);
8708
+ }
8709
+ if (typeof arg === "object" && arg !== null) {
8710
+ const record = arg;
8711
+ if (typeof record.$ref === "string") {
8712
+ return buildColumnRef(record.$ref, ctx);
8713
+ }
8714
+ if (typeof record.kind !== "string") {
8715
+ const legacyKind = typeof record.$op === "string" ? `$op:${record.$op}` : typeof record.$fn === "string" ? `$fn:${record.$fn}` : "object";
8716
+ throw new UnhandledNqlSelectExpressionKindError(legacyKind);
8717
+ }
8718
+ switch (record.kind) {
8719
+ case "column":
8720
+ if (typeof record.column !== "string") {
8721
+ throw new Error("NQL column expression requires a column name");
8722
+ }
8723
+ return buildColumnRef(record.column, ctx);
8724
+ case "columnAlias":
8725
+ if (typeof record.column !== "string") {
8726
+ throw new Error(
8727
+ "NQL columnAlias expression requires a column name"
8728
+ );
8729
+ }
8730
+ return buildColumnRef(record.column, ctx);
8731
+ case "relationColumn": {
8732
+ const relation = record.relation;
8733
+ const column = record.column;
8734
+ if (typeof relation !== "string" || typeof column !== "string") {
8735
+ throw new Error(
8736
+ "NQL relationColumn expression requires relation and column"
8737
+ );
8738
+ }
8739
+ return buildColumnRef(`${relation}.${column}`, ctx);
8740
+ }
8741
+ case "param":
8742
+ if (!("value" in record)) {
8743
+ throw new Error("NQL param expression requires a value");
8744
+ }
8745
+ return bindParameter(record.value, state);
8746
+ case "literal":
8747
+ if (!("value" in record)) {
8748
+ throw new Error("NQL literal expression requires a value");
8749
+ }
8750
+ return compileValue(record.value, state);
8751
+ case "function": {
8752
+ const nestedName = record.name;
8753
+ const nestedArgs = record.args;
8754
+ if (typeof nestedName !== "string") {
8755
+ throw new Error("NQL function argument requires a function name");
8756
+ }
8757
+ return this.compileGenericNqlFunction(
8758
+ nestedName,
8759
+ Array.isArray(nestedArgs) ? nestedArgs : [],
8760
+ ctx,
8761
+ state
8762
+ );
8763
+ }
8764
+ case "coalesce": {
8765
+ const handler = getExpressionHandler("coalesce");
8766
+ return handler.compile(
8767
+ {
8768
+ type: "coalesce",
8769
+ args: Array.isArray(record.fields) ? record.fields : []
8770
+ },
8771
+ ctx,
8772
+ state
8773
+ );
8774
+ }
8775
+ case "aggregate": {
8776
+ const fn4 = record.function;
8777
+ if (typeof fn4 !== "string") {
8778
+ throw new Error(
8779
+ "NQL aggregate expression requires a function name"
8780
+ );
8781
+ }
8782
+ const aggregateArgs = [];
8783
+ if (record.field === "*") {
8784
+ aggregateArgs.push({ kind: "star" });
8785
+ } else if (typeof record.field === "string") {
8786
+ aggregateArgs.push(record.field);
8787
+ }
8788
+ if (Array.isArray(record.extraArgs)) {
8789
+ aggregateArgs.push(...record.extraArgs);
8790
+ }
8791
+ return this.compileGenericNqlFunction(fn4, aggregateArgs, ctx, state);
8792
+ }
8793
+ case "arithmetic": {
8794
+ const operator = record.operator;
8795
+ if (typeof operator !== "string") {
8796
+ throw new Error("NQL arithmetic expression requires an operator");
8797
+ }
8798
+ if (!("left" in record) || !("right" in record)) {
8799
+ throw new Error(
8800
+ "NQL arithmetic expression requires left and right operands"
8801
+ );
8802
+ }
8803
+ const handler = getExpressionHandler("arithmetic");
8804
+ return handler.compile(
8805
+ {
8806
+ type: "arithmetic",
8807
+ operator,
8808
+ args: [record.left, record.right]
8809
+ },
8810
+ ctx,
8811
+ state
8812
+ );
8813
+ }
8814
+ case "case":
8815
+ return this.compileNqlCaseExpressionArg(record, ctx, state);
8816
+ case "jsonExtract": {
8817
+ const handler = getExpressionHandler("jsonExtract");
8818
+ return handler.compile(
8819
+ {
8820
+ type: "jsonExtract",
8821
+ column: record.field,
8822
+ args: Array.isArray(record.path) ? record.path : [],
8823
+ jsonMode: record.mode
8824
+ },
8825
+ ctx,
8826
+ state
8827
+ );
8828
+ }
8829
+ case "jsonPathExtract": {
8830
+ const handler = getExpressionHandler("jsonPathExtract");
8831
+ return handler.compile(
8832
+ {
8833
+ type: "jsonPathExtract",
8834
+ column: record.field,
8835
+ args: Array.isArray(record.path) ? [record.path] : typeof record.path === "string" ? [record.path] : [],
8836
+ jsonMode: record.mode
8837
+ },
8838
+ ctx,
8839
+ state
8840
+ );
8841
+ }
8842
+ case "window":
8843
+ return genericWindowHandler.compile(
8844
+ {
8845
+ type: "window",
8846
+ function: record.function,
8847
+ column: record.field,
8848
+ args: typeof record.offset === "number" ? [record.offset] : void 0,
8849
+ value: record.defaultValue,
8850
+ partition: record.over?.partitionBy,
8851
+ orderBy: record.over?.orderBy?.map((item) => ({
8852
+ column: item.field,
8853
+ direction: item.direction?.toUpperCase()
8854
+ }))
8855
+ },
8856
+ ctx,
8857
+ state
8858
+ );
8859
+ case "customOp":
8860
+ case "customFn":
8861
+ case "ref":
8862
+ case "cast":
8863
+ case "unary":
8864
+ case "namedArg":
8865
+ case "star":
8866
+ case "array":
8867
+ case "subquery":
8868
+ return compileExpressionIntent(
8869
+ record,
8870
+ ctx,
8871
+ state
8872
+ );
8873
+ default:
8874
+ throw new UnhandledNqlSelectExpressionKindError(record.kind);
8875
+ }
8876
+ }
8877
+ return compileValue(arg, state);
8878
+ }
8879
+ compileNqlCaseExpressionArg(expr, ctx, state) {
8880
+ const whenClauses = expr.when;
8881
+ if (!Array.isArray(whenClauses) || whenClauses.length === 0) {
8882
+ throw new Error("NQL CASE expression requires at least one WHEN clause");
8883
+ }
8884
+ const dispatcher = createWhereDispatcher();
8885
+ const args = whenClauses.map((branch) => {
8886
+ const condition = branch.condition;
8887
+ const result = branch.result;
8888
+ const conditionDecision = convertWhereCondition(
8889
+ condition,
8890
+ ctx.rootTable
8891
+ );
8892
+ if (!conditionDecision) {
8893
+ throw new Error("NQL CASE WHEN condition could not be compiled");
8894
+ }
8895
+ const whenNode = dispatcher(
8896
+ mapToHandlerDecision(
8897
+ conditionDecision,
8898
+ ctx.rootTable,
8899
+ this.defaultPk,
8900
+ this.deriveFk
8901
+ ),
8902
+ ctx,
8903
+ state
8904
+ );
8905
+ const thenNode = this.compileNqlFunctionArg(result, ctx, state);
8906
+ return {
8907
+ CaseWhen: {
8908
+ expr: whenNode,
8909
+ result: thenNode
8910
+ }
8911
+ };
8912
+ });
8913
+ const defresult = expr.else !== void 0 ? this.compileNqlFunctionArg(expr.else, ctx, state) : void 0;
8914
+ return {
8915
+ CaseExpr: {
8916
+ args,
8917
+ ...defresult !== void 0 ? { defresult } : {}
8918
+ }
8919
+ };
8920
+ }
8418
8921
  /**
8419
8922
  * Compile a SELECT-list target via expression handler.
8420
8923
  * Wraps the node in a ResTarget and pushes it onto targetList.
@@ -8468,6 +8971,41 @@ var PlanCompiler = class _PlanCompiler {
8468
8971
  });
8469
8972
  break;
8470
8973
  }
8974
+ case "selectNqlFunction": {
8975
+ ensureExpressionHandlersRegistered();
8976
+ const funcType = decision.function;
8977
+ if (!funcType) break;
8978
+ assertNqlSelectScalarFunctionAllowed(funcType);
8979
+ const ctx = this.createHandlerContext(
8980
+ plan,
8981
+ decision.table ?? plan.rootTable
8982
+ );
8983
+ const state = this.createHandlerState();
8984
+ const safeHandler = getNqlSafeExpressionHandler(funcType);
8985
+ const node = safeHandler ? safeHandler.compile(
8986
+ mapToHandlerDecision(
8987
+ decision,
8988
+ plan.rootTable,
8989
+ this.defaultPk,
8990
+ this.deriveFk
8991
+ ),
8992
+ ctx,
8993
+ state
8994
+ ) : this.compileGenericNqlFunction(
8995
+ funcType,
8996
+ decision.args ?? [],
8997
+ ctx,
8998
+ state
8999
+ );
9000
+ this.state.paramIndex = state.paramIndex;
9001
+ targetList.push({
9002
+ ResTarget: {
9003
+ val: node,
9004
+ ...decision.alias ? { name: this.naming.toDatabase(decision.alias) } : {}
9005
+ }
9006
+ });
9007
+ break;
9008
+ }
8471
9009
  case "selectExpression": {
8472
9010
  if (decision.expressionType === "case") {
8473
9011
  const caseNode = this.compileCaseExpression(decision);
@@ -8564,6 +9102,7 @@ var PlanCompiler = class _PlanCompiler {
8564
9102
  case "selectWindow": {
8565
9103
  const winFuncName = decision.function;
8566
9104
  if (!winFuncName) break;
9105
+ assertNqlSelectWindowFunctionAllowed(winFuncName);
8567
9106
  const winHandler = genericWindowHandler;
8568
9107
  const ctx = this.createHandlerContext(
8569
9108
  plan,
@@ -8726,7 +9265,11 @@ var PlanCompiler = class _PlanCompiler {
8726
9265
  if (decision.choice !== "join" || !decision.conditions || decision.conditions.length === 0) {
8727
9266
  return where;
8728
9267
  }
8729
- const joinAlias = decision.relationName;
9268
+ const relationIdentityPath = getRelationIdentityPath(
9269
+ decision,
9270
+ this.currentRootTable
9271
+ );
9272
+ const joinAlias = (relationIdentityPath ? this.joinAliasMap.get(relationIdentityPath)?.alias : void 0) ?? decision.relationName;
8730
9273
  for (const cond of decision.conditions) {
8731
9274
  const condExpr = this.dispatchWhere(
8732
9275
  cond,
@@ -8853,6 +9396,10 @@ var PlanCompiler = class _PlanCompiler {
8853
9396
  return selectStmt(options);
8854
9397
  }
8855
9398
  compileSelect(plan) {
9399
+ const decisions = mergeDuplicateJoinIncludeDecisions(
9400
+ plan.decisions,
9401
+ plan.rootTable
9402
+ );
8856
9403
  const targetList = [];
8857
9404
  const from = this.compileFromClause(plan);
8858
9405
  let where;
@@ -8862,10 +9409,11 @@ var PlanCompiler = class _PlanCompiler {
8862
9409
  let limit;
8863
9410
  let offset;
8864
9411
  let distinct = false;
8865
- for (const decision of plan.decisions) {
9412
+ for (const decision of decisions) {
8866
9413
  switch (decision.type) {
8867
9414
  case "select":
8868
9415
  case "selectFunction":
9416
+ case "selectNqlFunction":
8869
9417
  case "selectExpression":
8870
9418
  case "selectRelationColumn":
8871
9419
  case "selectPseudoColumn":
@@ -8903,6 +9451,10 @@ var PlanCompiler = class _PlanCompiler {
8903
9451
  case "limit":
8904
9452
  if (typeof decision.limit === "number") {
8905
9453
  limit = integerNode(decision.limit);
9454
+ } else if (isParamIntent6(decision.limit)) {
9455
+ this.state.parameters.push(unwrapParamIntent(decision.limit));
9456
+ this.state.paramIndex++;
9457
+ limit = createParamRef(this.state.paramIndex);
8906
9458
  } else if (decision.limit?.paramIndex !== void 0) {
8907
9459
  limit = createParamRef(decision.limit.paramIndex);
8908
9460
  this.state.parameters.push(void 0);
@@ -8911,6 +9463,10 @@ var PlanCompiler = class _PlanCompiler {
8911
9463
  case "offset":
8912
9464
  if (typeof decision.offset === "number") {
8913
9465
  offset = integerNode(decision.offset);
9466
+ } else if (isParamIntent6(decision.offset)) {
9467
+ this.state.parameters.push(unwrapParamIntent(decision.offset));
9468
+ this.state.paramIndex++;
9469
+ offset = createParamRef(this.state.paramIndex);
8914
9470
  } else if (decision.offset?.paramIndex !== void 0) {
8915
9471
  offset = createParamRef(decision.offset.paramIndex);
8916
9472
  this.state.parameters.push(void 0);
@@ -12520,8 +13076,10 @@ function matchGlob(pattern, value) {
12520
13076
  init_ast_helpers();
12521
13077
  init_compiler_utils();
12522
13078
  init_handlers();
13079
+ init_param_intent();
12523
13080
  init_param_ref();
12524
13081
  import { isSqlRaw } from "@dbsp/core";
13082
+ import { isParamIntent as isParamIntent7 } from "@dbsp/types";
12525
13083
  function buildReturningList(columns, tableRef, ctx) {
12526
13084
  if (!columns || columns.length === 0) return void 0;
12527
13085
  const { naming } = ctx;
@@ -12779,7 +13337,7 @@ function compileInsertFrom(config, ctx, state) {
12779
13337
  }
12780
13338
  let limitCount;
12781
13339
  if (config.limit !== void 0) {
12782
- limitCount = { A_Const: { ival: { ival: config.limit } } };
13340
+ limitCount = limitToNode(config.limit, state);
12783
13341
  }
12784
13342
  const sourceRelation = {
12785
13343
  relname: dbSourceTable,
@@ -12854,7 +13412,7 @@ function compileUpsertFrom(config, ctx, state) {
12854
13412
  }
12855
13413
  let limitCount;
12856
13414
  if (config.limit !== void 0) {
12857
- limitCount = { A_Const: { ival: { ival: config.limit } } };
13415
+ limitCount = limitToNode(config.limit, state);
12858
13416
  }
12859
13417
  const sourceRelation = {
12860
13418
  relname: dbSourceTable,
@@ -12928,11 +13486,22 @@ var RANGE_TYPES = /* @__PURE__ */ new Set([
12928
13486
  "int8range",
12929
13487
  "numrange"
12930
13488
  ]);
12931
- function valueToNode(value, state, dbType) {
12932
- if (value === null || value === void 0) {
13489
+ function valueToNode(value, state, dbType, forceParam = false) {
13490
+ const isParam = isParamIntent7(value);
13491
+ const boundValue = unwrapParamIntent(value);
13492
+ if (boundValue === null || boundValue === void 0) {
13493
+ if (forceParam || isParam) {
13494
+ state.parameters.push(boundValue);
13495
+ state.paramIndex++;
13496
+ return dbType && RANGE_TYPES.has(dbType) ? createTypeCastParamRef(state.paramIndex, dbType) : {
13497
+ ParamRef: {
13498
+ number: state.paramIndex
13499
+ }
13500
+ };
13501
+ }
12933
13502
  return { A_Const: { isnull: true } };
12934
13503
  }
12935
- state.parameters.push(value);
13504
+ state.parameters.push(boundValue);
12936
13505
  state.paramIndex++;
12937
13506
  if (dbType && RANGE_TYPES.has(dbType)) {
12938
13507
  return createTypeCastParamRef(state.paramIndex, dbType);
@@ -12943,6 +13512,18 @@ function valueToNode(value, state, dbType) {
12943
13512
  }
12944
13513
  };
12945
13514
  }
13515
+ function limitToNode(limit, state) {
13516
+ if (isParamIntent7(limit)) {
13517
+ state.parameters.push(unwrapParamIntent(limit));
13518
+ state.paramIndex++;
13519
+ return {
13520
+ ParamRef: {
13521
+ number: state.paramIndex
13522
+ }
13523
+ };
13524
+ }
13525
+ return { A_Const: { ival: { ival: limit } } };
13526
+ }
12946
13527
  function compileMutation(decision, ctx, state) {
12947
13528
  const type = decision.type;
12948
13529
  const table = decision.table ?? ctx.rootTable;
@@ -12982,6 +13563,7 @@ function compileMutation(decision, ctx, state) {
12982
13563
  init_ast_helpers();
12983
13564
  init_compiler_utils();
12984
13565
  init_handlers();
13566
+ init_param_intent();
12985
13567
  init_param_ref();
12986
13568
  function buildOnConflictClause(config, ctx, state) {
12987
13569
  const naming = ctx.naming;
@@ -13141,7 +13723,7 @@ function compileUnnestUpsert(config, ctx, state) {
13141
13723
  }
13142
13724
  function valueToParam(state, value) {
13143
13725
  if (value !== void 0) {
13144
- state.parameters.push(value);
13726
+ state.parameters.push(unwrapParamIntent(value));
13145
13727
  }
13146
13728
  state.paramIndex++;
13147
13729
  return {
@@ -13382,7 +13964,7 @@ function compileSubqueryIncludeManyToMany(info, parentIds, schemaName, state, de
13382
13964
  // src/adapter-compiler-mutations.ts
13383
13965
  init_compile_where();
13384
13966
  init_compiler_utils();
13385
- import { InvalidOperationError as InvalidOperationError2, isSqlRaw as isSqlRaw2 } from "@dbsp/core";
13967
+ import { InvalidOperationError as InvalidOperationError3, isSqlRaw as isSqlRaw2 } from "@dbsp/core";
13386
13968
  init_handlers();
13387
13969
  function whereIntentAsDecision(where) {
13388
13970
  return where;
@@ -13460,9 +14042,8 @@ function compileInsert2(intent, options, deps) {
13460
14042
  const state = createCompilerState();
13461
14043
  const firstRow = intent.values?.[0] ?? {};
13462
14044
  const columns = Object.keys(firstRow);
13463
- const values = (intent.values ?? []).map(
13464
- (row) => columns.map((col) => row[col])
13465
- );
14045
+ const rows = intent.values ?? [];
14046
+ const values = rows.map((row) => columns.map((col) => row[col]));
13466
14047
  const columnTypes = getColumnTypes(intent.table, columns, deps);
13467
14048
  const config = {
13468
14049
  table: intent.table,
@@ -13473,7 +14054,7 @@ function compileInsert2(intent, options, deps) {
13473
14054
  };
13474
14055
  const maxBatchSize = options?.maxBatchSize;
13475
14056
  if (maxBatchSize !== void 0 && values.length > maxBatchSize) {
13476
- throw new InvalidOperationError2(
14057
+ throw new InvalidOperationError3(
13477
14058
  "insert",
13478
14059
  `Batch size ${values.length} exceeds maxBatchSize ${maxBatchSize}`
13479
14060
  );
@@ -13549,7 +14130,7 @@ function compileBatchUpdate(intent, _options, deps) {
13549
14130
  };
13550
14131
  const state = createCompilerState();
13551
14132
  if (intent.updates.length === 0) {
13552
- throw new InvalidOperationError2(
14133
+ throw new InvalidOperationError3(
13553
14134
  "update",
13554
14135
  "batchSet requires at least one row"
13555
14136
  );
@@ -13558,7 +14139,7 @@ function compileBatchUpdate(intent, _options, deps) {
13558
14139
  const matchColumns = [...intent.matchColumns];
13559
14140
  for (const mc of matchColumns) {
13560
14141
  if (!allColumns.includes(mc)) {
13561
- throw new InvalidOperationError2(
14142
+ throw new InvalidOperationError3(
13562
14143
  "update",
13563
14144
  `Match column "${mc}" not found in update data. Each row must include the match column(s).`
13564
14145
  );
@@ -13581,7 +14162,13 @@ function compileBatchUpdate(intent, _options, deps) {
13581
14162
  naming: deps.naming,
13582
14163
  ...schemaName !== void 0 && { schemaName },
13583
14164
  ...deps.model !== void 0 && { model: deps.model },
13584
- compileSubquery: (sqIntent, paramOffset) => buildSubqueryFromIntent(sqIntent, paramOffset, deps.naming, schemaName)
14165
+ compileSubquery: (sqIntent, paramOffset) => buildSubqueryFromIntent(
14166
+ sqIntent,
14167
+ paramOffset,
14168
+ deps.naming,
14169
+ schemaName,
14170
+ "rawExists"
14171
+ )
13585
14172
  };
13586
14173
  whereGuard = compileWhereIntent(intent.where, whereCtx);
13587
14174
  }
@@ -13685,7 +14272,7 @@ function compileUpsert2(intent, options, deps) {
13685
14272
  };
13686
14273
  const maxBatchSize = options?.maxBatchSize;
13687
14274
  if (maxBatchSize !== void 0 && values.length > maxBatchSize) {
13688
- throw new InvalidOperationError2(
14275
+ throw new InvalidOperationError3(
13689
14276
  "upsert",
13690
14277
  `Batch size ${values.length} exceeds maxBatchSize ${maxBatchSize}`
13691
14278
  );
@@ -13738,6 +14325,7 @@ function compileUpsertFrom2(intent, options, deps) {
13738
14325
  init_assert_field();
13739
14326
  init_ast_helpers();
13740
14327
  init_compile_where();
14328
+ import { countDistinctRelationPathsByName } from "@dbsp/core";
13741
14329
  init_compiler_utils();
13742
14330
  init_types();
13743
14331
  init_intent_to_decisions();
@@ -13746,6 +14334,7 @@ init_param_ref();
13746
14334
  // src/plan-decision-extractor.ts
13747
14335
  init_assert_field();
13748
14336
  init_intent_to_decisions();
14337
+ import { deriveRelationPathFromIntentPath } from "@dbsp/core";
13749
14338
  function findExistsIntents(where) {
13750
14339
  if (!where || typeof where !== "object") return [];
13751
14340
  const w = where;
@@ -13790,7 +14379,9 @@ function resolveIncludeByPath(includes, intentPath, relationName) {
13790
14379
  }
13791
14380
  if (resolved) return resolved;
13792
14381
  }
13793
- return includes.find((i) => i.relation === relationName);
14382
+ return includes.find(
14383
+ (i) => i.relation === relationName || i.via === relationName
14384
+ );
13794
14385
  }
13795
14386
  function deriveForeignKey(context, deriveFk = defaultFkDerivation, defaultPk = DEFAULT_PK_COLUMN) {
13796
14387
  const fk = context.foreignKey ?? context.sourceFK;
@@ -13815,24 +14406,6 @@ function mapComparisonOperator(op3) {
13815
14406
  };
13816
14407
  return map[op3] ?? "=";
13817
14408
  }
13818
- function valueToNode2(value) {
13819
- if (typeof value === "string") {
13820
- return { A_Const: { sval: { sval: value } } };
13821
- }
13822
- if (typeof value === "number") {
13823
- if (Number.isInteger(value)) {
13824
- return { A_Const: { ival: { ival: value } } };
13825
- }
13826
- return { A_Const: { fval: { fval: String(value) } } };
13827
- }
13828
- if (typeof value === "boolean") {
13829
- return { A_Const: { boolval: { boolval: value } } };
13830
- }
13831
- if (value === null) {
13832
- return { A_Const: { isnull: true } };
13833
- }
13834
- return { A_Const: { sval: { sval: String(value) } } };
13835
- }
13836
14409
  function convertWhereToDecisions(where, table) {
13837
14410
  if (!where || typeof where !== "object") return [];
13838
14411
  const w = where;
@@ -14499,6 +15072,11 @@ function toIncludeDecision(d, choice, plan, defaultPk = DEFAULT_PK_COLUMN, deriv
14499
15072
  type: "includeStrategy",
14500
15073
  choice: effectiveChoice,
14501
15074
  relationName,
15075
+ relationPath: deriveRelationPathFromIntentPath(
15076
+ Array.isArray(plan.intent?.include) ? plan.intent.include : void 0,
15077
+ context.intentPath,
15078
+ relationName
15079
+ ) ?? relationName,
14502
15080
  targetTable: context.target,
14503
15081
  ...context.sourceTable && { sourceTable: context.sourceTable },
14504
15082
  ...relationType && { relationType },
@@ -14513,6 +15091,11 @@ function toJoinIncludeDecision(d, plan, defaultPk = DEFAULT_PK_COLUMN, deriveFk
14513
15091
  const relationName = context.relation ?? context.includeAlias;
14514
15092
  if (!context.target || !relationName) return void 0;
14515
15093
  const intentPath = context?.intentPath;
15094
+ const relationPath = deriveRelationPathFromIntentPath(
15095
+ Array.isArray(plan.intent?.include) ? plan.intent.include : void 0,
15096
+ intentPath,
15097
+ relationName
15098
+ ) ?? relationName;
14516
15099
  const includeIntent = resolveIncludeByPath(
14517
15100
  plan.intent?.include,
14518
15101
  intentPath,
@@ -14540,6 +15123,7 @@ function toJoinIncludeDecision(d, plan, defaultPk = DEFAULT_PK_COLUMN, deriveFk
14540
15123
  type: "includeStrategy",
14541
15124
  choice: "join",
14542
15125
  relationName,
15126
+ relationPath,
14543
15127
  targetTable: context.target,
14544
15128
  ...context.sourceTable && { sourceTable: context.sourceTable },
14545
15129
  ...relationType && { relationType },
@@ -14585,6 +15169,7 @@ function synthesizeMissingJoinDecisions(plan, coveredRelations, model, defaultPk
14585
15169
  type: "includeStrategy",
14586
15170
  choice: "join",
14587
15171
  relationName: alias,
15172
+ relationPath: alias,
14588
15173
  targetTable: rel.target,
14589
15174
  sourceTable,
14590
15175
  ...rel.type && {
@@ -14881,22 +15466,11 @@ function buildRelationColumnsMap(decisions, includedRelations) {
14881
15466
  }
14882
15467
  return map;
14883
15468
  }
14884
- function findRelationMapKey(map, relationName) {
14885
- if (map.has(relationName)) return relationName;
14886
- const suffix = `.${relationName}`;
14887
- for (const key of map.keys()) {
14888
- if (key.endsWith(suffix)) return key;
14889
- }
14890
- return void 0;
14891
- }
14892
15469
  function injectAndValidateRelationColumns(enrichedUnifiedDecisions, relationColumnsMap, model) {
14893
15470
  if (relationColumnsMap.size === 0) return;
14894
15471
  for (const d of enrichedUnifiedDecisions) {
14895
15472
  if (d.type === "includeStrategy" && d.relationName) {
14896
- const mapKey = findRelationMapKey(
14897
- relationColumnsMap,
14898
- d.relationName
14899
- );
15473
+ const mapKey = d.relationPath ?? d.relationName;
14900
15474
  const entries = mapKey ? relationColumnsMap.get(mapKey) : void 0;
14901
15475
  if (entries) {
14902
15476
  const mut = d;
@@ -14931,6 +15505,27 @@ function injectAndValidateRelationColumns(enrichedUnifiedDecisions, relationColu
14931
15505
  }
14932
15506
  }
14933
15507
  }
15508
+ function applyJoinHydrationPrefixes(decisions) {
15509
+ const usages = [];
15510
+ for (const d of decisions) {
15511
+ if (d.type !== "includeStrategy" || d.choice !== "join" || !d.relationName) {
15512
+ continue;
15513
+ }
15514
+ const relationName = d.relationName;
15515
+ const relationPath = d.relationPath ?? relationName;
15516
+ usages.push({ relationName, relationPath });
15517
+ }
15518
+ const pathCountsByRelation = countDistinctRelationPathsByName(usages);
15519
+ for (const d of decisions) {
15520
+ if (d.type !== "includeStrategy" || d.choice !== "join" || !d.relationName) {
15521
+ continue;
15522
+ }
15523
+ const relationName = d.relationName;
15524
+ const relationPath = d.relationPath ?? relationName;
15525
+ const usesFullPath = (pathCountsByRelation.get(relationName) ?? 0) > 1;
15526
+ d.hydrationPrefix = usesFullPath ? relationPath : relationName;
15527
+ }
15528
+ }
14934
15529
  function enrichRangeDecisions(allDecisions, model, rootTable) {
14935
15530
  if (!model) return;
14936
15531
  for (let i = 0; i < allDecisions.length; i++) {
@@ -15019,6 +15614,7 @@ function compileSelect(plan, options, deps) {
15019
15614
  ...allUnifiedIncludeDecisions
15020
15615
  ];
15021
15616
  stripJoinColumnsForAggregation(enrichedUnifiedDecisions, execIntent);
15617
+ applyJoinHydrationPrefixes(enrichedUnifiedDecisions);
15022
15618
  const includedRelations = new Set(
15023
15619
  enrichedUnifiedDecisions.filter((d) => d.type === "includeStrategy").map((d) => d.relationName).filter(Boolean)
15024
15620
  );
@@ -15116,6 +15712,7 @@ function compileWithIncludes(plan, options, deps) {
15116
15712
  init_ast_helpers();
15117
15713
  init_compiler_utils();
15118
15714
  init_handlers();
15715
+ init_utils();
15119
15716
  init_param_ref();
15120
15717
 
15121
15718
  // src/recursive/cte-compiler.ts
@@ -15829,6 +16426,7 @@ function buildEdgeTableRecursiveCte(config) {
15829
16426
  // src/adapter-compiler-recursive.ts
15830
16427
  function compileRecursive(report, _model, _options, deps) {
15831
16428
  const schemaName = deps.schemaName;
16429
+ const state = createCompilerState();
15832
16430
  const intent = report.intent;
15833
16431
  const traversal = intent.traversal;
15834
16432
  const trackPath = intent.track?.path !== void 0;
@@ -15848,7 +16446,7 @@ function compileRecursive(report, _model, _options, deps) {
15848
16446
  const selectColumns = Array.from(/* @__PURE__ */ new Set([nodeIdColumn, ...startSelect]));
15849
16447
  const edgeFrom = traversal.direction === "in" ? traversal.edgeTo : traversal.edgeFrom;
15850
16448
  const edgeTo = traversal.direction === "in" ? traversal.edgeFrom : traversal.edgeTo;
15851
- const anchorWhere = intent.start.where ? buildRecursiveAnchorWhere(intent.start.where, "__n", deps) : void 0;
16449
+ const anchorWhere = intent.start.where ? buildRecursiveAnchorWhere(intent.start.where, "__n", deps, state) : void 0;
15852
16450
  const base = {
15853
16451
  cteAlias: intent.cteName,
15854
16452
  table,
@@ -15974,11 +16572,10 @@ function compileRecursive(report, _model, _options, deps) {
15974
16572
  const sql = deparseQuoted({ SelectStmt: selectStmt2 });
15975
16573
  return {
15976
16574
  sql,
15977
- parameters: []
16575
+ parameters: state.parameters
15978
16576
  };
15979
16577
  }
15980
- function compileCteQuery(intent, _options, deps) {
15981
- const schemaName = deps.schemaName;
16578
+ function compileCteQuery(intent, options, deps) {
15982
16579
  const state = createCompilerState();
15983
16580
  const allCteParams = [];
15984
16581
  const cteSqlFragments = [];
@@ -15992,8 +16589,8 @@ function compileCteQuery(intent, _options, deps) {
15992
16589
  isRecursive = true;
15993
16590
  const { sql: cteSql, params: cteParams } = buildRawCte(
15994
16591
  cte,
15995
- schemaName,
15996
- deps
16592
+ deps,
16593
+ options
15997
16594
  );
15998
16595
  allCteParams.push(...cteParams);
15999
16596
  cteSqlFragments.push(cteSql);
@@ -16011,12 +16608,7 @@ function compileCteQuery(intent, _options, deps) {
16011
16608
  isAmbiguous: false
16012
16609
  }
16013
16610
  };
16014
- const innerCompileOptions = schemaName !== void 0 ? { schemaName } : {};
16015
- const innerCompiled = compileSelect(
16016
- innerPlanReport,
16017
- innerCompileOptions,
16018
- deps
16019
- );
16611
+ const innerCompiled = compileSelect(innerPlanReport, options, deps);
16020
16612
  const currentParamOffset = allCteParams.length;
16021
16613
  const renumberedInnerSql = currentParamOffset > 0 ? innerCompiled.sql.replace(
16022
16614
  /\$([0-9]+)/g,
@@ -16031,7 +16623,6 @@ function compileCteQuery(intent, _options, deps) {
16031
16623
  );
16032
16624
  }
16033
16625
  }
16034
- const outerCompileOptions = schemaName !== void 0 ? { schemaName } : {};
16035
16626
  const outerPlanReport = {
16036
16627
  rootTable: intent.query.from,
16037
16628
  decisions: [],
@@ -16044,11 +16635,7 @@ function compileCteQuery(intent, _options, deps) {
16044
16635
  isAmbiguous: false
16045
16636
  }
16046
16637
  };
16047
- const outerCompiled = compileSelect(
16048
- outerPlanReport,
16049
- outerCompileOptions,
16050
- deps
16051
- );
16638
+ const outerCompiled = compileSelect(outerPlanReport, options, deps);
16052
16639
  const cteParamCount = allCteParams.length;
16053
16640
  const renumberedOuterSql = cteParamCount > 0 ? outerCompiled.sql.replace(
16054
16641
  /\$([0-9]+)/g,
@@ -16114,8 +16701,7 @@ function buildUnnestCte(cte, state, deps) {
16114
16701
  }
16115
16702
  };
16116
16703
  }
16117
- function buildRawCte(cte, schemaName, deps) {
16118
- const compileOptions = schemaName !== void 0 ? { schemaName } : {};
16704
+ function buildRawCte(cte, deps, options) {
16119
16705
  const basePlanReport = {
16120
16706
  rootTable: cte.base.from,
16121
16707
  decisions: [],
@@ -16124,7 +16710,7 @@ function buildRawCte(cte, schemaName, deps) {
16124
16710
  intent: cte.base,
16125
16711
  metadata: { planningTimeMs: 0, relationsAnalyzed: 0, isAmbiguous: false }
16126
16712
  };
16127
- const baseCompiled = compileSelect(basePlanReport, compileOptions, deps);
16713
+ const baseCompiled = compileSelect(basePlanReport, options, deps);
16128
16714
  const stepPlanReport = {
16129
16715
  rootTable: cte.step.from,
16130
16716
  decisions: [],
@@ -16133,7 +16719,7 @@ function buildRawCte(cte, schemaName, deps) {
16133
16719
  intent: cte.step,
16134
16720
  metadata: { planningTimeMs: 0, relationsAnalyzed: 0, isAmbiguous: false }
16135
16721
  };
16136
- const stepCompiled = compileSelect(stepPlanReport, compileOptions, deps);
16722
+ const stepCompiled = compileSelect(stepPlanReport, options, deps);
16137
16723
  const baseParamCount = baseCompiled.parameters.length;
16138
16724
  const renumberedStepSql = baseParamCount > 0 ? stepCompiled.sql.replace(
16139
16725
  /\$([0-9]+)/g,
@@ -16159,7 +16745,7 @@ function buildRawCte(cte, schemaName, deps) {
16159
16745
  params: allParams
16160
16746
  };
16161
16747
  }
16162
- function buildRecursiveAnchorWhere(where, tableAlias, deps) {
16748
+ function buildRecursiveAnchorWhere(where, tableAlias, deps, state) {
16163
16749
  if (!where || typeof where !== "object") {
16164
16750
  return { A_Const: { boolval: { boolval: true } } };
16165
16751
  }
@@ -16176,7 +16762,7 @@ function buildRecursiveAnchorWhere(where, tableAlias, deps) {
16176
16762
  }
16177
16763
  };
16178
16764
  const op3 = mapComparisonOperator(w.operator);
16179
- const right = valueToNode2(w.value);
16765
+ const right = compileValue(w.value, state, void 0, true);
16180
16766
  return {
16181
16767
  A_Expr: {
16182
16768
  kind: "AEXPR_OP",
@@ -16188,14 +16774,14 @@ function buildRecursiveAnchorWhere(where, tableAlias, deps) {
16188
16774
  }
16189
16775
  case "and": {
16190
16776
  const conditions = w.conditions.map(
16191
- (c) => buildRecursiveAnchorWhere(c, tableAlias, deps)
16777
+ (c) => buildRecursiveAnchorWhere(c, tableAlias, deps, state)
16192
16778
  );
16193
16779
  if (conditions.length === 1) return conditions[0];
16194
16780
  return { BoolExpr: { boolop: "AND_EXPR", args: conditions } };
16195
16781
  }
16196
16782
  case "or": {
16197
16783
  const conditions = w.conditions.map(
16198
- (c) => buildRecursiveAnchorWhere(c, tableAlias, deps)
16784
+ (c) => buildRecursiveAnchorWhere(c, tableAlias, deps, state)
16199
16785
  );
16200
16786
  if (conditions.length === 1) return conditions[0];
16201
16787
  return { BoolExpr: { boolop: "OR_EXPR", args: conditions } };
@@ -16374,12 +16960,12 @@ function compileLeafOrBranch(intent, compileFn) {
16374
16960
  const result = compileFn(intent);
16375
16961
  return { sql: result.sql, parameters: result.parameters };
16376
16962
  }
16377
- function createLeafCompileFn(adapter, model, planFn2) {
16963
+ function createLeafCompileFn(adapter, model, planFn2, options) {
16378
16964
  return (query) => {
16379
16965
  const planReport = planFn2(query, model, {
16380
16966
  dialectCapabilities: adapter.dialectCapabilities
16381
16967
  });
16382
- return adapter.compile(planReport, { model });
16968
+ return adapter.compile(planReport, { ...options, model });
16383
16969
  };
16384
16970
  }
16385
16971
 
@@ -16498,6 +17084,15 @@ function mapFetchDirection(direction) {
16498
17084
 
16499
17085
  // src/pgsql-adapter.ts
16500
17086
  init_validate();
17087
+ function renumberSqlParams(sql, offset) {
17088
+ if (offset === 0) return sql;
17089
+ return sql.replace(/\$(\d+)/g, (_match, num) => {
17090
+ return `$${Number.parseInt(num, 10) + offset}`;
17091
+ });
17092
+ }
17093
+ function isCompiledNqlQuery(input) {
17094
+ return !("intent" in input) && ("query" in input || "cteQuery" in input || "mutation" in input || "setOperation" in input || "bindings" in input || "mutationBindings" in input);
17095
+ }
16501
17096
  var PgsqlAdapter = class _PgsqlAdapter {
16502
17097
  pool;
16503
17098
  client;
@@ -16577,6 +17172,124 @@ var PgsqlAdapter = class _PgsqlAdapter {
16577
17172
  deriveFk: this.deriveFk
16578
17173
  };
16579
17174
  }
17175
+ requireNqlCompileModel(options) {
17176
+ const model = options?.model ?? this.model;
17177
+ if (model === void 0) {
17178
+ throw new Error(
17179
+ "Compiling an NQL bundle requires a model. Pass { model } to adapter.compile(compiledNql, { model }) or configure the adapter with a model."
17180
+ );
17181
+ }
17182
+ return model;
17183
+ }
17184
+ compileNqlMutation(bundle, options) {
17185
+ const mutation = bundle.mutation;
17186
+ if (mutation === void 0) {
17187
+ throw new Error("NQL bundle did not contain a mutation intent.");
17188
+ }
17189
+ switch (mutation.type) {
17190
+ case "insert":
17191
+ return compileInsert2(
17192
+ mutation,
17193
+ options,
17194
+ this.buildCompileDeps(options)
17195
+ );
17196
+ case "insert_from":
17197
+ return compileInsertFrom2(
17198
+ mutation,
17199
+ options,
17200
+ this.buildCompileDeps(options)
17201
+ );
17202
+ case "update":
17203
+ return compileUpdate2(
17204
+ mutation,
17205
+ options,
17206
+ this.buildCompileDeps(options)
17207
+ );
17208
+ case "delete":
17209
+ return compileDelete2(
17210
+ mutation,
17211
+ options,
17212
+ this.buildCompileDeps(options)
17213
+ );
17214
+ case "upsert":
17215
+ return compileUpsert2(
17216
+ mutation,
17217
+ options,
17218
+ this.buildCompileDeps(options)
17219
+ );
17220
+ case "upsert_from":
17221
+ return compileUpsertFrom2(
17222
+ mutation,
17223
+ options,
17224
+ this.buildCompileDeps(options)
17225
+ );
17226
+ }
17227
+ throw new Error(
17228
+ `Unsupported NQL mutation type: ${mutation.type}`
17229
+ );
17230
+ }
17231
+ compileNqlBundleLeaf(bundle, options) {
17232
+ if (bundle.query !== void 0) {
17233
+ const model = this.requireNqlCompileModel(options);
17234
+ const planReport = planFn(bundle.query, model, {
17235
+ dialectCapabilities: this.dialectCapabilities
17236
+ });
17237
+ return compileSelect(
17238
+ planReport,
17239
+ options,
17240
+ this.buildCompileDeps(options)
17241
+ );
17242
+ }
17243
+ if (bundle.cteQuery !== void 0) {
17244
+ return compileCteQuery(
17245
+ bundle.cteQuery,
17246
+ options,
17247
+ this.buildCompileDeps(options)
17248
+ );
17249
+ }
17250
+ if (bundle.setOperation !== void 0) {
17251
+ const model = this.requireNqlCompileModel(options);
17252
+ return this.compileSetOperation(
17253
+ bundle.setOperation,
17254
+ model,
17255
+ options
17256
+ );
17257
+ }
17258
+ if (bundle.mutation !== void 0) {
17259
+ return this.compileNqlMutation(bundle, options);
17260
+ }
17261
+ throw new Error("NQL bundle did not contain a compilable intent.");
17262
+ }
17263
+ compileNqlBundle(bundle, options) {
17264
+ const ctes = [];
17265
+ const parameters = [];
17266
+ for (const [name, queryIntent] of bundle.bindings ?? []) {
17267
+ const cteName = quoteIdent2(name, "alias");
17268
+ const bindingBundle = bundle.mutationBindings?.has(name) ? { mutation: bundle.mutationBindings.get(name) } : { query: queryIntent };
17269
+ const compiled2 = this.compileNqlBundleLeaf(bindingBundle, options);
17270
+ ctes.push(
17271
+ `${cteName} as (${renumberSqlParams(compiled2.sql, parameters.length)})`
17272
+ );
17273
+ parameters.push(...compiled2.parameters);
17274
+ }
17275
+ const leafBundle = {
17276
+ ...bundle.query !== void 0 && { query: bundle.query },
17277
+ ...bundle.cteQuery !== void 0 && { cteQuery: bundle.cteQuery },
17278
+ ...bundle.mutation !== void 0 && { mutation: bundle.mutation },
17279
+ ...bundle.returning !== void 0 && { returning: bundle.returning },
17280
+ ...bundle.setOperation !== void 0 && {
17281
+ setOperation: bundle.setOperation
17282
+ }
17283
+ };
17284
+ const compiled = this.compileNqlBundleLeaf(leafBundle, options);
17285
+ if (ctes.length === 0) {
17286
+ return compiled;
17287
+ }
17288
+ return {
17289
+ sql: `WITH ${ctes.join(", ")} ${renumberSqlParams(compiled.sql, parameters.length)}`,
17290
+ parameters: [...parameters, ...compiled.parameters]
17291
+ };
17292
+ }
16580
17293
  /**
16581
17294
  * Returns the pool/client executor, or throws if in compile-only mode.
16582
17295
  */
@@ -16616,6 +17329,9 @@ var PgsqlAdapter = class _PgsqlAdapter {
16616
17329
  * Compile a plan to executable SQL.
16617
17330
  */
16618
17331
  compile(plan, options) {
17332
+ if (isCompiledNqlQuery(plan)) {
17333
+ return this.compileNqlBundle(plan, options);
17334
+ }
16619
17335
  return compileSelect(plan, options, this.buildCompileDeps(options));
16620
17336
  }
16621
17337
  /**
@@ -16779,8 +17495,8 @@ var PgsqlAdapter = class _PgsqlAdapter {
16779
17495
  /**
16780
17496
  * Compile a set operation (UNION / INTERSECT / EXCEPT) to SQL.
16781
17497
  */
16782
- compileSetOperation(intent, model, _options) {
16783
- const compileFn = createLeafCompileFn(this, model, planFn);
17498
+ compileSetOperation(intent, model, options) {
17499
+ const compileFn = createLeafCompileFn(this, model, planFn, options);
16784
17500
  const result = compileSetOperation(intent, compileFn);
16785
17501
  return {
16786
17502
  sql: result.sql,