@dbsp/adapter-pgsql 1.2.1 → 1.3.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.d.ts +34 -1
- package/dist/index.js +1195 -798
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -3651,6 +3651,27 @@ var init_range = __esm({
|
|
|
3651
3651
|
}
|
|
3652
3652
|
});
|
|
3653
3653
|
|
|
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
|
+
|
|
3654
3675
|
// src/compile-where.ts
|
|
3655
3676
|
function toHandlerContext(ctx) {
|
|
3656
3677
|
return {
|
|
@@ -3659,11 +3680,12 @@ function toHandlerContext(ctx) {
|
|
|
3659
3680
|
currentAlias: ctx.currentAlias ?? ctx.rootTable,
|
|
3660
3681
|
maxRecursiveDepth: 100,
|
|
3661
3682
|
...ctx.schemaName !== void 0 && { schema: ctx.schemaName },
|
|
3683
|
+
...ctx.bindingNames !== void 0 && { bindingNames: ctx.bindingNames },
|
|
3662
3684
|
...ctx.model !== void 0 && { model: ctx.model },
|
|
3663
3685
|
...ctx.outerTable !== void 0 && { outerAlias: ctx.outerTable }
|
|
3664
3686
|
};
|
|
3665
3687
|
}
|
|
3666
|
-
function buildSubqueryFromIntent(intent, paramOffset, naming = identityNaming, schemaName, use = "rawExists") {
|
|
3688
|
+
function buildSubqueryFromIntent(intent, paramOffset, naming = identityNaming, schemaName, use = "rawExists", bindingNames) {
|
|
3667
3689
|
assertNoUnsupportedSubqueryModifiers(intent, use);
|
|
3668
3690
|
if (intent.where && containsOuterRef(intent.where)) {
|
|
3669
3691
|
throw new Error(
|
|
@@ -3708,9 +3730,14 @@ function buildSubqueryFromIntent(intent, paramOffset, naming = identityNaming, s
|
|
|
3708
3730
|
}
|
|
3709
3731
|
const stmt = {
|
|
3710
3732
|
targetList,
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3733
|
+
fromClause: [
|
|
3734
|
+
rangeVar(
|
|
3735
|
+
targetTable,
|
|
3736
|
+
innerAlias,
|
|
3737
|
+
schemaForFromName(schemaName, targetTable, bindingNames, naming),
|
|
3738
|
+
naming
|
|
3739
|
+
)
|
|
3740
|
+
]
|
|
3714
3741
|
};
|
|
3715
3742
|
let paramCount = 0;
|
|
3716
3743
|
let innerParameters = [];
|
|
@@ -3724,6 +3751,7 @@ function buildSubqueryFromIntent(intent, paramOffset, naming = identityNaming, s
|
|
|
3724
3751
|
aliases: /* @__PURE__ */ new Map(),
|
|
3725
3752
|
paramState: innerState,
|
|
3726
3753
|
naming,
|
|
3754
|
+
...bindingNames !== void 0 && { bindingNames },
|
|
3727
3755
|
compileSubquery: (_nestedIntent, _nestedOffset) => {
|
|
3728
3756
|
throw new Error(
|
|
3729
3757
|
"buildSubqueryFromIntent: nested subquery not supported"
|
|
@@ -4101,6 +4129,7 @@ var init_compile_where = __esm({
|
|
|
4101
4129
|
init_custom();
|
|
4102
4130
|
init_handlers();
|
|
4103
4131
|
init_assert_field();
|
|
4132
|
+
init_binding_registry();
|
|
4104
4133
|
init_types();
|
|
4105
4134
|
init_utils();
|
|
4106
4135
|
init_intent_to_decisions();
|
|
@@ -4145,7 +4174,8 @@ var init_raw_exists = __esm({
|
|
|
4145
4174
|
state.paramIndex,
|
|
4146
4175
|
ctx.naming,
|
|
4147
4176
|
ctx.schema,
|
|
4148
|
-
"rawExists"
|
|
4177
|
+
"rawExists",
|
|
4178
|
+
ctx.bindingNames
|
|
4149
4179
|
);
|
|
4150
4180
|
if (innerParams) {
|
|
4151
4181
|
for (const p of innerParams) {
|
|
@@ -4381,7 +4411,19 @@ function buildPredicateSubquerySelect(use, sourceIntent, decision, ctx, state, d
|
|
|
4381
4411
|
}
|
|
4382
4412
|
const stmt = {
|
|
4383
4413
|
targetList: [{ ResTarget: { val: targetVal } }],
|
|
4384
|
-
fromClause: [
|
|
4414
|
+
fromClause: [
|
|
4415
|
+
rangeVar(
|
|
4416
|
+
targetTable,
|
|
4417
|
+
targetAlias,
|
|
4418
|
+
schemaForFromName(
|
|
4419
|
+
ctx.schema,
|
|
4420
|
+
targetTable,
|
|
4421
|
+
ctx.bindingNames,
|
|
4422
|
+
ctx.naming
|
|
4423
|
+
),
|
|
4424
|
+
ctx.naming
|
|
4425
|
+
)
|
|
4426
|
+
],
|
|
4385
4427
|
...whereClause && { whereClause }
|
|
4386
4428
|
};
|
|
4387
4429
|
if (decision.orderBy && decision.orderBy.length > 0) {
|
|
@@ -4418,6 +4460,7 @@ var init_subquery_emission = __esm({
|
|
|
4418
4460
|
"src/subquery-emission.ts"() {
|
|
4419
4461
|
"use strict";
|
|
4420
4462
|
init_ast_helpers();
|
|
4463
|
+
init_binding_registry();
|
|
4421
4464
|
init_intent_to_decisions();
|
|
4422
4465
|
init_param_intent();
|
|
4423
4466
|
}
|
|
@@ -7050,6 +7093,7 @@ import {
|
|
|
7050
7093
|
NQL_SELECT_SCALAR_FUNCTION_ALLOWLIST,
|
|
7051
7094
|
NQL_SELECT_WINDOW_FUNCTION_ALLOWLIST
|
|
7052
7095
|
} from "@dbsp/types";
|
|
7096
|
+
import { getNqlBindingRefName, isNqlBindingRef } from "@dbsp/types/internal";
|
|
7053
7097
|
|
|
7054
7098
|
// src/pgsql-deparser.ts
|
|
7055
7099
|
function deparse(node) {
|
|
@@ -8336,6 +8380,7 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
8336
8380
|
defaultPk;
|
|
8337
8381
|
deriveFk;
|
|
8338
8382
|
model;
|
|
8383
|
+
bindingNames;
|
|
8339
8384
|
/** Mutable state shared with extracted condition/value compilation functions */
|
|
8340
8385
|
state = {
|
|
8341
8386
|
parameters: [],
|
|
@@ -8370,6 +8415,7 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
8370
8415
|
this.defaultPk = options.defaultPkColumnName ?? DEFAULT_PK_COLUMN;
|
|
8371
8416
|
this.deriveFk = options.deriveFkColumnName ?? defaultFkDerivation;
|
|
8372
8417
|
this.model = options.model ?? void 0;
|
|
8418
|
+
this.bindingNames = options.bindingNames;
|
|
8373
8419
|
}
|
|
8374
8420
|
/** Build immutable context for handler-based WHERE compilation */
|
|
8375
8421
|
handlerCtx() {
|
|
@@ -8381,6 +8427,7 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
8381
8427
|
defaultPkColumnName: this.defaultPk,
|
|
8382
8428
|
deriveFkColumnName: this.deriveFk,
|
|
8383
8429
|
...this.schema != null && { schema: this.schema },
|
|
8430
|
+
...this.bindingNames != null && { bindingNames: this.bindingNames },
|
|
8384
8431
|
...this.model != null && { model: this.model }
|
|
8385
8432
|
};
|
|
8386
8433
|
}
|
|
@@ -8690,6 +8737,7 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
8690
8737
|
defaultPkColumnName: this.defaultPk,
|
|
8691
8738
|
deriveFkColumnName: this.deriveFk,
|
|
8692
8739
|
...plan.schema ?? this.schema ? { schema: plan.schema ?? this.schema } : {},
|
|
8740
|
+
...this.bindingNames != null && { bindingNames: this.bindingNames },
|
|
8693
8741
|
...this.model != null && { model: this.model },
|
|
8694
8742
|
compileSubquery: (query, paramOffset) => this.compileExpressionSubquery(query, paramOffset),
|
|
8695
8743
|
compileNqlSelectExpression: (value, handlerCtx, state) => this.compileNqlFunctionArg(value, handlerCtx, state)
|
|
@@ -8712,7 +8760,10 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
8712
8760
|
schema: this.schema
|
|
8713
8761
|
},
|
|
8714
8762
|
defaultPkColumnName: this.defaultPk,
|
|
8715
|
-
deriveFkColumnName: this.deriveFk
|
|
8763
|
+
deriveFkColumnName: this.deriveFk,
|
|
8764
|
+
...this.bindingNames !== void 0 && {
|
|
8765
|
+
bindingNames: this.bindingNames
|
|
8766
|
+
}
|
|
8716
8767
|
});
|
|
8717
8768
|
const innerPlan = {
|
|
8718
8769
|
rootTable: query.from,
|
|
@@ -8731,14 +8782,14 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
8731
8782
|
return funcCall(functionName, argNodes);
|
|
8732
8783
|
}
|
|
8733
8784
|
compileNqlFunctionArg(arg, ctx, state) {
|
|
8785
|
+
if (isNqlBindingRef(arg)) {
|
|
8786
|
+
return buildColumnRef(getNqlBindingRefName(arg), ctx);
|
|
8787
|
+
}
|
|
8734
8788
|
if (typeof arg === "string") {
|
|
8735
8789
|
return buildColumnRef(arg, ctx);
|
|
8736
8790
|
}
|
|
8737
8791
|
if (typeof arg === "object" && arg !== null) {
|
|
8738
8792
|
const record = arg;
|
|
8739
|
-
if (typeof record.$ref === "string") {
|
|
8740
|
-
return buildColumnRef(record.$ref, ctx);
|
|
8741
|
-
}
|
|
8742
8793
|
if (typeof record.kind !== "string") {
|
|
8743
8794
|
const legacyKind = typeof record.$op === "string" ? `$op:${record.$op}` : typeof record.$fn === "string" ? `$fn:${record.$fn}` : "object";
|
|
8744
8795
|
throw new UnhandledNqlSelectExpressionKindError(legacyKind);
|
|
@@ -9390,19 +9441,35 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
9390
9441
|
}
|
|
9391
9442
|
return void 0;
|
|
9392
9443
|
}
|
|
9444
|
+
/**
|
|
9445
|
+
* Compile a column reference that may use dotted 'relation.column' notation.
|
|
9446
|
+
*/
|
|
9447
|
+
compileRelationAwareColumnRef(column, table) {
|
|
9448
|
+
const dot = column.lastIndexOf(".");
|
|
9449
|
+
if (dot !== -1) {
|
|
9450
|
+
const relation = column.slice(0, dot);
|
|
9451
|
+
const alias = this.resolvedJoinAliases().get(relation) ?? relation;
|
|
9452
|
+
return columnRef(column.slice(dot + 1), alias, void 0, this.naming);
|
|
9453
|
+
}
|
|
9454
|
+
return columnRef(column, table, void 0, this.naming);
|
|
9455
|
+
}
|
|
9393
9456
|
/**
|
|
9394
9457
|
* Compile a single groupBy decision into a ColumnRef AST node.
|
|
9395
9458
|
* Supports dotted 'relation.column' notation for joined tables.
|
|
9396
9459
|
*/
|
|
9397
9460
|
compileGroupByDecision(decision) {
|
|
9398
|
-
|
|
9399
|
-
|
|
9400
|
-
|
|
9401
|
-
|
|
9402
|
-
|
|
9403
|
-
|
|
9404
|
-
|
|
9405
|
-
|
|
9461
|
+
return this.compileRelationAwareColumnRef(
|
|
9462
|
+
decision.column,
|
|
9463
|
+
decision.table
|
|
9464
|
+
);
|
|
9465
|
+
}
|
|
9466
|
+
/**
|
|
9467
|
+
* Compile a DISTINCT ON column into a ColumnRef AST node.
|
|
9468
|
+
* Mirrors GROUP BY relation-alias resolution while preserving unqualified
|
|
9469
|
+
* DISTINCT ON columns as unqualified references.
|
|
9470
|
+
*/
|
|
9471
|
+
compileDistinctOnColumn(column) {
|
|
9472
|
+
return this.compileRelationAwareColumnRef(column, void 0);
|
|
9406
9473
|
}
|
|
9407
9474
|
/**
|
|
9408
9475
|
* Assemble the final SelectStmt from all accumulated clause nodes.
|
|
@@ -9539,7 +9606,7 @@ var PlanCompiler = class _PlanCompiler {
|
|
|
9539
9606
|
case "distinctOn":
|
|
9540
9607
|
if (decision.columns && decision.columns.length > 0) {
|
|
9541
9608
|
distinct = decision.columns.map(
|
|
9542
|
-
(col) =>
|
|
9609
|
+
(col) => this.compileDistinctOnColumn(col)
|
|
9543
9610
|
);
|
|
9544
9611
|
}
|
|
9545
9612
|
break;
|
|
@@ -13139,6 +13206,7 @@ function matchGlob(pattern, value) {
|
|
|
13139
13206
|
|
|
13140
13207
|
// src/mutations/mutation-compiler.ts
|
|
13141
13208
|
init_ast_helpers();
|
|
13209
|
+
init_binding_registry();
|
|
13142
13210
|
init_compiler_utils();
|
|
13143
13211
|
init_handlers();
|
|
13144
13212
|
init_param_intent();
|
|
@@ -13364,12 +13432,18 @@ function compileInsertFrom(config, ctx, state) {
|
|
|
13364
13432
|
const _dbTargetTable = naming.toDatabase(config.targetTable);
|
|
13365
13433
|
const dbSourceTable = naming.toDatabase(config.sourceTable);
|
|
13366
13434
|
const sourceAlias = config.sourceTable;
|
|
13435
|
+
const sourceSchema = schemaForFromName(
|
|
13436
|
+
ctx.schema,
|
|
13437
|
+
config.sourceTable,
|
|
13438
|
+
ctx.bindingNames,
|
|
13439
|
+
naming
|
|
13440
|
+
);
|
|
13367
13441
|
const dbColumns = config.columns?.map((c) => naming.toDatabase(c));
|
|
13368
13442
|
let targetList;
|
|
13369
13443
|
if (config.columns && config.columns.length > 0) {
|
|
13370
13444
|
targetList = config.columns.map(
|
|
13371
13445
|
(col) => resTarget(
|
|
13372
|
-
columnRef(col, sourceAlias,
|
|
13446
|
+
columnRef(col, sourceAlias, sourceSchema, naming),
|
|
13373
13447
|
naming.toDatabase(col)
|
|
13374
13448
|
)
|
|
13375
13449
|
);
|
|
@@ -13409,8 +13483,8 @@ function compileInsertFrom(config, ctx, state) {
|
|
|
13409
13483
|
inh: true,
|
|
13410
13484
|
relpersistence: "p"
|
|
13411
13485
|
};
|
|
13412
|
-
if (
|
|
13413
|
-
sourceRelation.schemaname = naming.toDatabase(
|
|
13486
|
+
if (sourceSchema) {
|
|
13487
|
+
sourceRelation.schemaname = naming.toDatabase(sourceSchema);
|
|
13414
13488
|
}
|
|
13415
13489
|
const selectQuery = {
|
|
13416
13490
|
SelectStmt: {
|
|
@@ -13439,12 +13513,18 @@ function compileUpsertFrom(config, ctx, state) {
|
|
|
13439
13513
|
const naming = ctx.naming;
|
|
13440
13514
|
const dbSourceTable = naming.toDatabase(config.sourceTable);
|
|
13441
13515
|
const sourceAlias = config.sourceTable;
|
|
13516
|
+
const sourceSchema = schemaForFromName(
|
|
13517
|
+
ctx.schema,
|
|
13518
|
+
config.sourceTable,
|
|
13519
|
+
ctx.bindingNames,
|
|
13520
|
+
naming
|
|
13521
|
+
);
|
|
13442
13522
|
const dbColumns = config.columns?.map((c) => naming.toDatabase(c));
|
|
13443
13523
|
let targetList;
|
|
13444
13524
|
if (config.columns && config.columns.length > 0) {
|
|
13445
13525
|
targetList = config.columns.map(
|
|
13446
13526
|
(col) => resTarget(
|
|
13447
|
-
columnRef(col, sourceAlias,
|
|
13527
|
+
columnRef(col, sourceAlias, sourceSchema, naming),
|
|
13448
13528
|
naming.toDatabase(col)
|
|
13449
13529
|
)
|
|
13450
13530
|
);
|
|
@@ -13484,8 +13564,8 @@ function compileUpsertFrom(config, ctx, state) {
|
|
|
13484
13564
|
inh: true,
|
|
13485
13565
|
relpersistence: "p"
|
|
13486
13566
|
};
|
|
13487
|
-
if (
|
|
13488
|
-
sourceRelation.schemaname = naming.toDatabase(
|
|
13567
|
+
if (sourceSchema) {
|
|
13568
|
+
sourceRelation.schemaname = naming.toDatabase(sourceSchema);
|
|
13489
13569
|
}
|
|
13490
13570
|
const selectQuery = {
|
|
13491
13571
|
SelectStmt: {
|
|
@@ -13630,6 +13710,28 @@ init_compiler_utils();
|
|
|
13630
13710
|
init_handlers();
|
|
13631
13711
|
init_param_intent();
|
|
13632
13712
|
init_param_ref();
|
|
13713
|
+
function buildWhereClause(conditions, ctx, state) {
|
|
13714
|
+
if (!conditions || conditions.length === 0) return void 0;
|
|
13715
|
+
const dispatch = createWhereDispatcher();
|
|
13716
|
+
if (conditions.length === 1) {
|
|
13717
|
+
return dispatch(conditions[0], ctx, state);
|
|
13718
|
+
}
|
|
13719
|
+
const nodes = conditions.map((condition) => dispatch(condition, ctx, state));
|
|
13720
|
+
return {
|
|
13721
|
+
BoolExpr: { boolop: "AND_EXPR", args: nodes }
|
|
13722
|
+
};
|
|
13723
|
+
}
|
|
13724
|
+
function buildActionWhereClause(config, ctx, state) {
|
|
13725
|
+
if (config.actionWhereIntent) {
|
|
13726
|
+
if (!config.compileActionWhere) {
|
|
13727
|
+
throw new Error(
|
|
13728
|
+
"Upsert actionWhereIntent requires compileActionWhere callback"
|
|
13729
|
+
);
|
|
13730
|
+
}
|
|
13731
|
+
return config.compileActionWhere(config.actionWhereIntent, state);
|
|
13732
|
+
}
|
|
13733
|
+
return buildWhereClause(config.actionWhere, ctx, state);
|
|
13734
|
+
}
|
|
13633
13735
|
function buildOnConflictClause(config, ctx, state) {
|
|
13634
13736
|
const naming = ctx.naming;
|
|
13635
13737
|
const action = config.conflictAction;
|
|
@@ -13643,18 +13745,12 @@ function buildOnConflictClause(config, ctx, state) {
|
|
|
13643
13745
|
}))
|
|
13644
13746
|
};
|
|
13645
13747
|
if (config.conflictTarget.where && config.conflictTarget.where.length > 0) {
|
|
13646
|
-
const
|
|
13647
|
-
|
|
13648
|
-
|
|
13649
|
-
|
|
13650
|
-
|
|
13651
|
-
|
|
13652
|
-
const nodes = conditions.map((c) => dispatch(c, ctx, state));
|
|
13653
|
-
whereClause = {
|
|
13654
|
-
BoolExpr: { boolop: "AND_EXPR", args: nodes }
|
|
13655
|
-
};
|
|
13656
|
-
}
|
|
13657
|
-
infer.whereClause = whereClause;
|
|
13748
|
+
const whereClause2 = buildWhereClause(
|
|
13749
|
+
config.conflictTarget.where,
|
|
13750
|
+
ctx,
|
|
13751
|
+
state
|
|
13752
|
+
);
|
|
13753
|
+
if (whereClause2) infer.whereClause = whereClause2;
|
|
13658
13754
|
}
|
|
13659
13755
|
} else if (config.conflictTarget.constraint) {
|
|
13660
13756
|
infer = {
|
|
@@ -13700,10 +13796,12 @@ function buildOnConflictClause(config, ctx, state) {
|
|
|
13700
13796
|
}
|
|
13701
13797
|
};
|
|
13702
13798
|
});
|
|
13799
|
+
const whereClause = buildActionWhereClause(config, ctx, state);
|
|
13703
13800
|
return {
|
|
13704
13801
|
action: "ONCONFLICT_UPDATE",
|
|
13705
13802
|
...infer && { infer },
|
|
13706
|
-
targetList
|
|
13803
|
+
targetList,
|
|
13804
|
+
...whereClause && { whereClause }
|
|
13707
13805
|
};
|
|
13708
13806
|
}
|
|
13709
13807
|
function compileUpsert(config, ctx, state) {
|
|
@@ -13841,7 +13939,8 @@ init_naming_plugin();
|
|
|
13841
13939
|
init_param_ref();
|
|
13842
13940
|
|
|
13843
13941
|
// src/pgsql-adapter.ts
|
|
13844
|
-
import { POSTGRESQL_CAPABILITIES, plan as
|
|
13942
|
+
import { POSTGRESQL_CAPABILITIES as POSTGRESQL_CAPABILITIES2, plan as planFn2 } from "@dbsp/core";
|
|
13943
|
+
import { getNqlBindingRefName as getNqlBindingRefName2, isNqlBindingRef as isNqlBindingRef2 } from "@dbsp/types/internal";
|
|
13845
13944
|
|
|
13846
13945
|
// src/adapter-compiler-includes.ts
|
|
13847
13946
|
init_ast_helpers();
|
|
@@ -14027,449 +14126,97 @@ function compileSubqueryIncludeManyToMany(info, parentIds, schemaName, state, de
|
|
|
14027
14126
|
}
|
|
14028
14127
|
|
|
14029
14128
|
// src/adapter-compiler-mutations.ts
|
|
14129
|
+
import {
|
|
14130
|
+
InvalidOperationError as InvalidOperationError3,
|
|
14131
|
+
isSqlRaw as isSqlRaw2,
|
|
14132
|
+
POSTGRESQL_CAPABILITIES,
|
|
14133
|
+
plan as planFn
|
|
14134
|
+
} from "@dbsp/core";
|
|
14135
|
+
|
|
14136
|
+
// src/adapter-compiler-select.ts
|
|
14137
|
+
init_assert_field();
|
|
14138
|
+
init_ast_helpers();
|
|
14030
14139
|
init_compile_where();
|
|
14140
|
+
import { countDistinctRelationPathsByName } from "@dbsp/core";
|
|
14031
14141
|
init_compiler_utils();
|
|
14032
|
-
|
|
14033
|
-
|
|
14034
|
-
|
|
14035
|
-
|
|
14036
|
-
|
|
14037
|
-
|
|
14038
|
-
|
|
14039
|
-
|
|
14040
|
-
|
|
14041
|
-
|
|
14042
|
-
if (rel.type === "belongsTo") {
|
|
14043
|
-
const fk = typeof rel.foreignKey === "string" ? rel.foreignKey : rel.foreignKey?.[0];
|
|
14044
|
-
return {
|
|
14045
|
-
targetTable,
|
|
14046
|
-
...fk !== void 0 && { sourceColumn: fk },
|
|
14047
|
-
targetColumn: "id"
|
|
14048
|
-
};
|
|
14049
|
-
}
|
|
14050
|
-
return { targetTable };
|
|
14051
|
-
}
|
|
14052
|
-
function resolveExistsIntent(where, sourceTable, deps) {
|
|
14142
|
+
init_types();
|
|
14143
|
+
init_intent_to_decisions();
|
|
14144
|
+
init_param_ref();
|
|
14145
|
+
|
|
14146
|
+
// src/plan-decision-extractor.ts
|
|
14147
|
+
init_assert_field();
|
|
14148
|
+
init_intent_to_decisions();
|
|
14149
|
+
import { deriveRelationPathFromIntentPath } from "@dbsp/core";
|
|
14150
|
+
function findExistsIntents(where) {
|
|
14151
|
+
if (!where || typeof where !== "object") return [];
|
|
14053
14152
|
const w = where;
|
|
14054
|
-
|
|
14055
|
-
|
|
14056
|
-
const conditions = w.conditions;
|
|
14057
|
-
if (!conditions) return where;
|
|
14058
|
-
const enriched = conditions.map(
|
|
14059
|
-
(c) => resolveExistsIntent(c, sourceTable, deps)
|
|
14060
|
-
);
|
|
14061
|
-
const changed = enriched.some((c, i) => c !== conditions[i]);
|
|
14062
|
-
return changed ? { ...w, conditions: enriched } : where;
|
|
14063
|
-
}
|
|
14064
|
-
if (kind === "not") {
|
|
14065
|
-
const condition = w.condition;
|
|
14066
|
-
if (!condition) return where;
|
|
14067
|
-
const enriched = resolveExistsIntent(condition, sourceTable, deps);
|
|
14068
|
-
return enriched !== condition ? { ...w, condition: enriched } : where;
|
|
14153
|
+
if (w.kind === "exists" || w.kind === "notExists" || w.kind === "relationFilter") {
|
|
14154
|
+
return [w];
|
|
14069
14155
|
}
|
|
14070
|
-
|
|
14071
|
-
|
|
14072
|
-
|
|
14073
|
-
|
|
14074
|
-
return {
|
|
14075
|
-
...w,
|
|
14076
|
-
targetTable: resolved.targetTable,
|
|
14077
|
-
...resolved.sourceColumn !== void 0 && {
|
|
14078
|
-
sourceColumn: resolved.sourceColumn
|
|
14079
|
-
},
|
|
14080
|
-
...resolved.targetColumn !== void 0 && {
|
|
14081
|
-
targetColumn: resolved.targetColumn
|
|
14156
|
+
const results = [];
|
|
14157
|
+
if (w.conditions && Array.isArray(w.conditions)) {
|
|
14158
|
+
for (const c of w.conditions) {
|
|
14159
|
+
results.push(...findExistsIntents(c));
|
|
14082
14160
|
}
|
|
14083
|
-
}
|
|
14161
|
+
}
|
|
14162
|
+
if (w.condition) {
|
|
14163
|
+
results.push(...findExistsIntents(w.condition));
|
|
14164
|
+
}
|
|
14165
|
+
return results;
|
|
14084
14166
|
}
|
|
14085
|
-
function
|
|
14086
|
-
|
|
14087
|
-
|
|
14088
|
-
|
|
14089
|
-
|
|
14090
|
-
|
|
14091
|
-
|
|
14092
|
-
|
|
14093
|
-
|
|
14094
|
-
|
|
14167
|
+
function resolveRelation(model, sourceTable, relationName) {
|
|
14168
|
+
const rel = model.getRelation(`${sourceTable}.${relationName}`);
|
|
14169
|
+
if (!rel) return void 0;
|
|
14170
|
+
const foreignKey = typeof rel.foreignKey === "string" ? rel.foreignKey : rel.foreignKey?.[0];
|
|
14171
|
+
const relationType = rel.type;
|
|
14172
|
+
return { target: rel.target, foreignKey, relationType };
|
|
14173
|
+
}
|
|
14174
|
+
function resolveIncludeAlias(context) {
|
|
14175
|
+
return context.relation ?? context.includeAlias;
|
|
14176
|
+
}
|
|
14177
|
+
function resolveIncludeByPath(includes, intentPath, relationName) {
|
|
14178
|
+
if (!includes) return void 0;
|
|
14179
|
+
if (intentPath) {
|
|
14180
|
+
const indexPattern = /include\[(\d+)\]/g;
|
|
14181
|
+
let current = includes;
|
|
14182
|
+
let resolved;
|
|
14183
|
+
let execResult = indexPattern.exec(intentPath);
|
|
14184
|
+
while (execResult !== null) {
|
|
14185
|
+
const idx = parseInt(execResult[1], 10);
|
|
14186
|
+
const item = current[idx];
|
|
14187
|
+
if (!item) break;
|
|
14188
|
+
resolved = item;
|
|
14189
|
+
current = item.include ?? [];
|
|
14190
|
+
execResult = indexPattern.exec(intentPath);
|
|
14095
14191
|
}
|
|
14192
|
+
if (resolved) return resolved;
|
|
14096
14193
|
}
|
|
14097
|
-
return
|
|
14194
|
+
return includes.find(
|
|
14195
|
+
(i) => i.relation === relationName || i.via === relationName
|
|
14196
|
+
);
|
|
14098
14197
|
}
|
|
14099
|
-
function
|
|
14100
|
-
const
|
|
14101
|
-
|
|
14102
|
-
|
|
14103
|
-
|
|
14104
|
-
|
|
14105
|
-
maxRecursiveDepth: 100
|
|
14106
|
-
};
|
|
14107
|
-
const state = createCompilerState();
|
|
14108
|
-
const firstRow = intent.values?.[0] ?? {};
|
|
14109
|
-
const columns = Object.keys(firstRow);
|
|
14110
|
-
const rows = intent.values ?? [];
|
|
14111
|
-
const values = rows.map((row) => columns.map((col) => row[col]));
|
|
14112
|
-
const columnTypes = getColumnTypes(intent.table, columns, deps);
|
|
14113
|
-
const config = {
|
|
14114
|
-
table: intent.table,
|
|
14115
|
-
columns,
|
|
14116
|
-
values,
|
|
14117
|
-
...intent.returning && { returning: [...intent.returning] },
|
|
14118
|
-
...columnTypes && { columnTypes }
|
|
14119
|
-
};
|
|
14120
|
-
const maxBatchSize = options?.maxBatchSize;
|
|
14121
|
-
if (maxBatchSize !== void 0 && values.length > maxBatchSize) {
|
|
14122
|
-
throw new InvalidOperationError3(
|
|
14123
|
-
"insert",
|
|
14124
|
-
`Batch size ${values.length} exceeds maxBatchSize ${maxBatchSize}`
|
|
14125
|
-
);
|
|
14198
|
+
function deriveForeignKey(context, deriveFk = defaultFkDerivation, defaultPk = DEFAULT_PK_COLUMN) {
|
|
14199
|
+
const fk = context.foreignKey ?? context.sourceFK;
|
|
14200
|
+
if (fk) return fk;
|
|
14201
|
+
if (!context.relationType) return void 0;
|
|
14202
|
+
if (context.relationType === "belongsTo") {
|
|
14203
|
+
return context.target ? deriveFk(context.target, defaultPk) : void 0;
|
|
14126
14204
|
}
|
|
14127
|
-
|
|
14128
|
-
const useUnnest = values.length > 0 && (batchThreshold === 0 || values.length > batchThreshold);
|
|
14129
|
-
const ast = useUnnest ? compileUnnestInsert(config, ctx, state) : compileInsert(config, ctx, state);
|
|
14130
|
-
const sql = deparseQuoted(ast);
|
|
14131
|
-
return {
|
|
14132
|
-
sql,
|
|
14133
|
-
parameters: state.parameters
|
|
14134
|
-
};
|
|
14205
|
+
return context.sourceTable ? deriveFk(context.sourceTable, defaultPk) : void 0;
|
|
14135
14206
|
}
|
|
14136
|
-
function
|
|
14137
|
-
const
|
|
14138
|
-
|
|
14139
|
-
|
|
14140
|
-
|
|
14141
|
-
|
|
14142
|
-
|
|
14143
|
-
|
|
14144
|
-
|
|
14145
|
-
|
|
14146
|
-
|
|
14147
|
-
sourceTable: intent.source,
|
|
14148
|
-
...intent.columns && { columns: [...intent.columns] },
|
|
14149
|
-
...intent.where && { where: [whereIntentAsDecision(intent.where)] },
|
|
14150
|
-
...intent.limit !== void 0 && { limit: intent.limit },
|
|
14151
|
-
...intent.returning && { returning: [...intent.returning] }
|
|
14152
|
-
};
|
|
14153
|
-
const ast = compileInsertFrom(config, ctx, state);
|
|
14154
|
-
const sql = deparseQuoted(ast);
|
|
14155
|
-
return {
|
|
14156
|
-
sql,
|
|
14157
|
-
parameters: state.parameters
|
|
14207
|
+
function mapComparisonOperator(op3) {
|
|
14208
|
+
const map = {
|
|
14209
|
+
eq: "=",
|
|
14210
|
+
neq: "!=",
|
|
14211
|
+
gt: ">",
|
|
14212
|
+
gte: ">=",
|
|
14213
|
+
lt: "<",
|
|
14214
|
+
lte: "<=",
|
|
14215
|
+
like: "LIKE",
|
|
14216
|
+
ilike: "ILIKE",
|
|
14217
|
+
isDistinctFrom: "IS DISTINCT FROM"
|
|
14158
14218
|
};
|
|
14159
|
-
|
|
14160
|
-
function compileUpdate2(intent, _options, deps) {
|
|
14161
|
-
const schemaName = deps.schemaName;
|
|
14162
|
-
const ctx = {
|
|
14163
|
-
naming: deps.naming,
|
|
14164
|
-
rootTable: intent.table,
|
|
14165
|
-
...schemaName !== void 0 && { schema: schemaName },
|
|
14166
|
-
maxRecursiveDepth: 100
|
|
14167
|
-
};
|
|
14168
|
-
const state = createCompilerState();
|
|
14169
|
-
const setColumns = Object.keys(intent.set ?? {});
|
|
14170
|
-
const columnTypes = getColumnTypes(intent.table, setColumns, deps);
|
|
14171
|
-
const config = {
|
|
14172
|
-
table: intent.table,
|
|
14173
|
-
set: Object.entries(intent.set ?? {}).map(([column, value]) => ({
|
|
14174
|
-
column,
|
|
14175
|
-
value
|
|
14176
|
-
})),
|
|
14177
|
-
...intent.where && { where: [whereIntentAsDecision(intent.where)] },
|
|
14178
|
-
...intent.returning && { returning: [...intent.returning] },
|
|
14179
|
-
...columnTypes && { columnTypes }
|
|
14180
|
-
};
|
|
14181
|
-
const ast = compileUpdate(config, ctx, state);
|
|
14182
|
-
const sql = deparseQuoted(ast);
|
|
14183
|
-
return {
|
|
14184
|
-
sql,
|
|
14185
|
-
parameters: state.parameters
|
|
14186
|
-
};
|
|
14187
|
-
}
|
|
14188
|
-
function compileBatchUpdate(intent, _options, deps) {
|
|
14189
|
-
const schemaName = deps.schemaName;
|
|
14190
|
-
const ctx = {
|
|
14191
|
-
naming: deps.naming,
|
|
14192
|
-
rootTable: intent.table,
|
|
14193
|
-
...schemaName !== void 0 && { schema: schemaName },
|
|
14194
|
-
maxRecursiveDepth: 100
|
|
14195
|
-
};
|
|
14196
|
-
const state = createCompilerState();
|
|
14197
|
-
if (intent.updates.length === 0) {
|
|
14198
|
-
throw new InvalidOperationError3(
|
|
14199
|
-
"update",
|
|
14200
|
-
"batchSet requires at least one row"
|
|
14201
|
-
);
|
|
14202
|
-
}
|
|
14203
|
-
const allColumns = Object.keys(intent.updates[0]);
|
|
14204
|
-
const matchColumns = [...intent.matchColumns];
|
|
14205
|
-
for (const mc of matchColumns) {
|
|
14206
|
-
if (!allColumns.includes(mc)) {
|
|
14207
|
-
throw new InvalidOperationError3(
|
|
14208
|
-
"update",
|
|
14209
|
-
`Match column "${mc}" not found in update data. Each row must include the match column(s).`
|
|
14210
|
-
);
|
|
14211
|
-
}
|
|
14212
|
-
}
|
|
14213
|
-
const values = intent.updates.map((row) => allColumns.map((col) => row[col]));
|
|
14214
|
-
validateBatchCardinality(allColumns, values);
|
|
14215
|
-
const columnArrays = transposeToColumnArrays(allColumns, values);
|
|
14216
|
-
const columnTypes = getColumnTypes(intent.table, allColumns, deps);
|
|
14217
|
-
const scalarSet = intent.scalarSet ? Object.entries(intent.scalarSet).map(([column, value]) => ({
|
|
14218
|
-
column,
|
|
14219
|
-
value
|
|
14220
|
-
})) : void 0;
|
|
14221
|
-
let whereGuard;
|
|
14222
|
-
if (intent.where) {
|
|
14223
|
-
const whereCtx = {
|
|
14224
|
-
rootTable: intent.table,
|
|
14225
|
-
aliases: /* @__PURE__ */ new Map(),
|
|
14226
|
-
paramState: state,
|
|
14227
|
-
naming: deps.naming,
|
|
14228
|
-
...schemaName !== void 0 && { schemaName },
|
|
14229
|
-
...deps.model !== void 0 && { model: deps.model },
|
|
14230
|
-
compileSubquery: (sqIntent, paramOffset) => buildSubqueryFromIntent(
|
|
14231
|
-
sqIntent,
|
|
14232
|
-
paramOffset,
|
|
14233
|
-
deps.naming,
|
|
14234
|
-
schemaName,
|
|
14235
|
-
"rawExists"
|
|
14236
|
-
)
|
|
14237
|
-
};
|
|
14238
|
-
whereGuard = compileWhereIntent(intent.where, whereCtx);
|
|
14239
|
-
}
|
|
14240
|
-
const config = {
|
|
14241
|
-
table: intent.table,
|
|
14242
|
-
matchColumns,
|
|
14243
|
-
allColumns,
|
|
14244
|
-
columnArrays,
|
|
14245
|
-
...scalarSet && { scalarSet },
|
|
14246
|
-
...intent.returning && { returning: [...intent.returning] },
|
|
14247
|
-
...columnTypes && { columnTypes },
|
|
14248
|
-
...whereGuard !== void 0 && { whereGuard }
|
|
14249
|
-
};
|
|
14250
|
-
const ast = compileUnnestUpdate(config, ctx, state);
|
|
14251
|
-
const sql = deparseQuoted(ast);
|
|
14252
|
-
return {
|
|
14253
|
-
sql,
|
|
14254
|
-
parameters: state.parameters
|
|
14255
|
-
};
|
|
14256
|
-
}
|
|
14257
|
-
function compileDelete2(intent, options, deps) {
|
|
14258
|
-
const schemaName = deps.schemaName;
|
|
14259
|
-
const resolvedModel = options?.model ?? deps.model;
|
|
14260
|
-
const ctx = {
|
|
14261
|
-
naming: deps.naming,
|
|
14262
|
-
rootTable: intent.table,
|
|
14263
|
-
...schemaName !== void 0 && { schema: schemaName },
|
|
14264
|
-
maxRecursiveDepth: 100,
|
|
14265
|
-
...resolvedModel !== void 0 && { model: resolvedModel }
|
|
14266
|
-
};
|
|
14267
|
-
const state = createCompilerState();
|
|
14268
|
-
const resolvedWhere = intent.where ? resolveExistsIntent(intent.where, intent.table, deps) : void 0;
|
|
14269
|
-
const config = {
|
|
14270
|
-
table: intent.table,
|
|
14271
|
-
...resolvedWhere && { where: [whereIntentAsDecision(resolvedWhere)] },
|
|
14272
|
-
...intent.returning && { returning: [...intent.returning] }
|
|
14273
|
-
};
|
|
14274
|
-
const ast = compileDelete(config, ctx, state);
|
|
14275
|
-
const sql = deparseQuoted(ast);
|
|
14276
|
-
return {
|
|
14277
|
-
sql,
|
|
14278
|
-
parameters: state.parameters
|
|
14279
|
-
};
|
|
14280
|
-
}
|
|
14281
|
-
function compileUpsert2(intent, options, deps) {
|
|
14282
|
-
const schemaName = deps.schemaName;
|
|
14283
|
-
const ctx = {
|
|
14284
|
-
naming: deps.naming,
|
|
14285
|
-
rootTable: intent.table,
|
|
14286
|
-
...schemaName !== void 0 && { schema: schemaName },
|
|
14287
|
-
maxRecursiveDepth: 100
|
|
14288
|
-
};
|
|
14289
|
-
const state = createCompilerState();
|
|
14290
|
-
const firstRow = intent.values?.[0] ?? {};
|
|
14291
|
-
const rawExprs = {};
|
|
14292
|
-
const scalarSet = {};
|
|
14293
|
-
if (intent.action.type === "doUpdate" && intent.action.set) {
|
|
14294
|
-
for (const [key, val] of Object.entries(intent.action.set)) {
|
|
14295
|
-
if (isSqlRaw2(val)) {
|
|
14296
|
-
rawExprs[key] = val.sql;
|
|
14297
|
-
} else {
|
|
14298
|
-
scalarSet[key] = val;
|
|
14299
|
-
}
|
|
14300
|
-
}
|
|
14301
|
-
}
|
|
14302
|
-
const hasScalarSet = Object.keys(scalarSet).length > 0;
|
|
14303
|
-
const mergedFirstRow = hasScalarSet ? { ...firstRow, ...scalarSet } : firstRow;
|
|
14304
|
-
const columns = Object.keys(mergedFirstRow);
|
|
14305
|
-
const values = (intent.values ?? []).map((row) => {
|
|
14306
|
-
const mergedRow = hasScalarSet ? { ...row, ...scalarSet } : row;
|
|
14307
|
-
return columns.map((col) => mergedRow[col]);
|
|
14308
|
-
});
|
|
14309
|
-
const conflictTarget = {};
|
|
14310
|
-
if ("columns" in intent.onConflict) {
|
|
14311
|
-
conflictTarget.columns = [...intent.onConflict.columns];
|
|
14312
|
-
} else if ("constraint" in intent.onConflict) {
|
|
14313
|
-
conflictTarget.constraint = intent.onConflict.constraint;
|
|
14314
|
-
}
|
|
14315
|
-
const conflictAction = intent.action.type === "doNothing" ? "nothing" : "update";
|
|
14316
|
-
let updateColumns;
|
|
14317
|
-
if (intent.action.type === "doUpdate") {
|
|
14318
|
-
if (intent.action.set) {
|
|
14319
|
-
updateColumns = Object.keys(intent.action.set);
|
|
14320
|
-
} else {
|
|
14321
|
-
const conflictCols = "columns" in intent.onConflict ? intent.onConflict.columns : [];
|
|
14322
|
-
updateColumns = columns.filter((col) => !conflictCols.includes(col));
|
|
14323
|
-
}
|
|
14324
|
-
}
|
|
14325
|
-
const columnTypes = getColumnTypes(intent.table, columns, deps);
|
|
14326
|
-
const hasRawExprs = Object.keys(rawExprs).length > 0;
|
|
14327
|
-
const config = {
|
|
14328
|
-
table: intent.table,
|
|
14329
|
-
columns,
|
|
14330
|
-
values,
|
|
14331
|
-
conflictTarget,
|
|
14332
|
-
conflictAction,
|
|
14333
|
-
...updateColumns && { updateColumns },
|
|
14334
|
-
...intent.returning && { returning: [...intent.returning] },
|
|
14335
|
-
...columnTypes && { columnTypes },
|
|
14336
|
-
...hasRawExprs && { updateExpressions: rawExprs }
|
|
14337
|
-
};
|
|
14338
|
-
const maxBatchSize = options?.maxBatchSize;
|
|
14339
|
-
if (maxBatchSize !== void 0 && values.length > maxBatchSize) {
|
|
14340
|
-
throw new InvalidOperationError3(
|
|
14341
|
-
"upsert",
|
|
14342
|
-
`Batch size ${values.length} exceeds maxBatchSize ${maxBatchSize}`
|
|
14343
|
-
);
|
|
14344
|
-
}
|
|
14345
|
-
const batchThreshold = options?.batchThreshold ?? 50;
|
|
14346
|
-
const useUnnest = values.length > 0 && (batchThreshold === 0 || values.length > batchThreshold);
|
|
14347
|
-
const ast = useUnnest ? compileUnnestUpsert(config, ctx, state) : compileUpsert(config, ctx, state);
|
|
14348
|
-
const sql = deparseQuoted(ast);
|
|
14349
|
-
return {
|
|
14350
|
-
sql,
|
|
14351
|
-
parameters: state.parameters
|
|
14352
|
-
};
|
|
14353
|
-
}
|
|
14354
|
-
function compileUpsertFrom2(intent, options, deps) {
|
|
14355
|
-
const schemaName = deps.schemaName;
|
|
14356
|
-
const ctx = {
|
|
14357
|
-
naming: deps.naming,
|
|
14358
|
-
rootTable: intent.source,
|
|
14359
|
-
...schemaName !== void 0 && { schema: schemaName },
|
|
14360
|
-
maxRecursiveDepth: 100
|
|
14361
|
-
};
|
|
14362
|
-
const state = createCompilerState();
|
|
14363
|
-
let columns;
|
|
14364
|
-
if (intent.columns) {
|
|
14365
|
-
columns = [...intent.columns];
|
|
14366
|
-
} else if (options?.model) {
|
|
14367
|
-
const targetTable = options.model.getTable(intent.table);
|
|
14368
|
-
if (targetTable) {
|
|
14369
|
-
columns = targetTable.columns.map((c) => c.name);
|
|
14370
|
-
}
|
|
14371
|
-
}
|
|
14372
|
-
const config = {
|
|
14373
|
-
targetTable: intent.table,
|
|
14374
|
-
sourceTable: intent.source,
|
|
14375
|
-
conflictColumns: [...intent.conflictColumns],
|
|
14376
|
-
...columns && { columns },
|
|
14377
|
-
...intent.where && { where: [whereIntentAsDecision(intent.where)] },
|
|
14378
|
-
...intent.limit !== void 0 && { limit: intent.limit },
|
|
14379
|
-
...intent.returning && { returning: [...intent.returning] }
|
|
14380
|
-
};
|
|
14381
|
-
const ast = compileUpsertFrom(config, ctx, state);
|
|
14382
|
-
const sql = deparseQuoted(ast);
|
|
14383
|
-
return {
|
|
14384
|
-
sql,
|
|
14385
|
-
parameters: state.parameters
|
|
14386
|
-
};
|
|
14387
|
-
}
|
|
14388
|
-
|
|
14389
|
-
// src/adapter-compiler-select.ts
|
|
14390
|
-
init_assert_field();
|
|
14391
|
-
init_ast_helpers();
|
|
14392
|
-
init_compile_where();
|
|
14393
|
-
import { countDistinctRelationPathsByName } from "@dbsp/core";
|
|
14394
|
-
init_compiler_utils();
|
|
14395
|
-
init_types();
|
|
14396
|
-
init_intent_to_decisions();
|
|
14397
|
-
init_param_ref();
|
|
14398
|
-
|
|
14399
|
-
// src/plan-decision-extractor.ts
|
|
14400
|
-
init_assert_field();
|
|
14401
|
-
init_intent_to_decisions();
|
|
14402
|
-
import { deriveRelationPathFromIntentPath } from "@dbsp/core";
|
|
14403
|
-
function findExistsIntents(where) {
|
|
14404
|
-
if (!where || typeof where !== "object") return [];
|
|
14405
|
-
const w = where;
|
|
14406
|
-
if (w.kind === "exists" || w.kind === "notExists" || w.kind === "relationFilter") {
|
|
14407
|
-
return [w];
|
|
14408
|
-
}
|
|
14409
|
-
const results = [];
|
|
14410
|
-
if (w.conditions && Array.isArray(w.conditions)) {
|
|
14411
|
-
for (const c of w.conditions) {
|
|
14412
|
-
results.push(...findExistsIntents(c));
|
|
14413
|
-
}
|
|
14414
|
-
}
|
|
14415
|
-
if (w.condition) {
|
|
14416
|
-
results.push(...findExistsIntents(w.condition));
|
|
14417
|
-
}
|
|
14418
|
-
return results;
|
|
14419
|
-
}
|
|
14420
|
-
function resolveRelation(model, sourceTable, relationName) {
|
|
14421
|
-
const rel = model.getRelation(`${sourceTable}.${relationName}`);
|
|
14422
|
-
if (!rel) return void 0;
|
|
14423
|
-
const foreignKey = typeof rel.foreignKey === "string" ? rel.foreignKey : rel.foreignKey?.[0];
|
|
14424
|
-
const relationType = rel.type;
|
|
14425
|
-
return { target: rel.target, foreignKey, relationType };
|
|
14426
|
-
}
|
|
14427
|
-
function resolveIncludeAlias(context) {
|
|
14428
|
-
return context.relation ?? context.includeAlias;
|
|
14429
|
-
}
|
|
14430
|
-
function resolveIncludeByPath(includes, intentPath, relationName) {
|
|
14431
|
-
if (!includes) return void 0;
|
|
14432
|
-
if (intentPath) {
|
|
14433
|
-
const indexPattern = /include\[(\d+)\]/g;
|
|
14434
|
-
let current = includes;
|
|
14435
|
-
let resolved;
|
|
14436
|
-
let execResult = indexPattern.exec(intentPath);
|
|
14437
|
-
while (execResult !== null) {
|
|
14438
|
-
const idx = parseInt(execResult[1], 10);
|
|
14439
|
-
const item = current[idx];
|
|
14440
|
-
if (!item) break;
|
|
14441
|
-
resolved = item;
|
|
14442
|
-
current = item.include ?? [];
|
|
14443
|
-
execResult = indexPattern.exec(intentPath);
|
|
14444
|
-
}
|
|
14445
|
-
if (resolved) return resolved;
|
|
14446
|
-
}
|
|
14447
|
-
return includes.find(
|
|
14448
|
-
(i) => i.relation === relationName || i.via === relationName
|
|
14449
|
-
);
|
|
14450
|
-
}
|
|
14451
|
-
function deriveForeignKey(context, deriveFk = defaultFkDerivation, defaultPk = DEFAULT_PK_COLUMN) {
|
|
14452
|
-
const fk = context.foreignKey ?? context.sourceFK;
|
|
14453
|
-
if (fk) return fk;
|
|
14454
|
-
if (!context.relationType) return void 0;
|
|
14455
|
-
if (context.relationType === "belongsTo") {
|
|
14456
|
-
return context.target ? deriveFk(context.target, defaultPk) : void 0;
|
|
14457
|
-
}
|
|
14458
|
-
return context.sourceTable ? deriveFk(context.sourceTable, defaultPk) : void 0;
|
|
14459
|
-
}
|
|
14460
|
-
function mapComparisonOperator(op3) {
|
|
14461
|
-
const map = {
|
|
14462
|
-
eq: "=",
|
|
14463
|
-
neq: "!=",
|
|
14464
|
-
gt: ">",
|
|
14465
|
-
gte: ">=",
|
|
14466
|
-
lt: "<",
|
|
14467
|
-
lte: "<=",
|
|
14468
|
-
like: "LIKE",
|
|
14469
|
-
ilike: "ILIKE",
|
|
14470
|
-
isDistinctFrom: "IS DISTINCT FROM"
|
|
14471
|
-
};
|
|
14472
|
-
return map[op3] ?? "=";
|
|
14219
|
+
return map[op3] ?? "=";
|
|
14473
14220
|
}
|
|
14474
14221
|
function convertWhereToDecisions(where, table) {
|
|
14475
14222
|
if (!where || typeof where !== "object") return [];
|
|
@@ -15489,288 +15236,754 @@ function compileJoinIntents(joins, rootTable, schemaName, deps) {
|
|
|
15489
15236
|
});
|
|
15490
15237
|
}
|
|
15491
15238
|
}
|
|
15492
|
-
return results;
|
|
15239
|
+
return results;
|
|
15240
|
+
}
|
|
15241
|
+
function stripJoinColumnsForAggregation(decisions, intent) {
|
|
15242
|
+
const isAggregateOnly = intent.select && "type" in intent.select && intent.select.type === "aggregate" && !("fields" in intent.select && intent.select.fields);
|
|
15243
|
+
const isDistinct = intent.distinct === true;
|
|
15244
|
+
const hasGroupBy = intent.groupBy && intent.groupBy.length > 0;
|
|
15245
|
+
const hasExplicitColumns = intent.select && "type" in intent.select && intent.select.type === "expressions";
|
|
15246
|
+
if (isAggregateOnly || isDistinct || hasGroupBy || hasExplicitColumns) {
|
|
15247
|
+
for (const d of decisions) {
|
|
15248
|
+
if (d.type === "includeStrategy" && d.choice === "join") {
|
|
15249
|
+
d.columns = [];
|
|
15250
|
+
}
|
|
15251
|
+
}
|
|
15252
|
+
}
|
|
15253
|
+
}
|
|
15254
|
+
function buildRelationColumnsMap(decisions, includedRelations) {
|
|
15255
|
+
const map = /* @__PURE__ */ new Map();
|
|
15256
|
+
for (const d of decisions) {
|
|
15257
|
+
if (!(d.type === "selectRelationColumn" && d.relation && d.column))
|
|
15258
|
+
continue;
|
|
15259
|
+
const col = d.column;
|
|
15260
|
+
const alias = d.alias;
|
|
15261
|
+
const fullRelation = d.relation;
|
|
15262
|
+
const rootRelation = fullRelation.split(".")[0] ?? "";
|
|
15263
|
+
if (!includedRelations.has(rootRelation)) continue;
|
|
15264
|
+
const mapKey = fullRelation;
|
|
15265
|
+
if (col === "*") {
|
|
15266
|
+
map.set(mapKey, [{ col: "*" }]);
|
|
15267
|
+
continue;
|
|
15268
|
+
}
|
|
15269
|
+
const existing = map.get(mapKey);
|
|
15270
|
+
if (existing) {
|
|
15271
|
+
if (existing.length === 1 && existing[0]?.col === "*") continue;
|
|
15272
|
+
if (!existing.some((e) => e.col === col)) {
|
|
15273
|
+
existing.push({ col, ...alias !== void 0 && { alias } });
|
|
15274
|
+
}
|
|
15275
|
+
} else {
|
|
15276
|
+
map.set(mapKey, [{ col, ...alias !== void 0 && { alias } }]);
|
|
15277
|
+
}
|
|
15278
|
+
}
|
|
15279
|
+
return map;
|
|
15280
|
+
}
|
|
15281
|
+
function injectAndValidateRelationColumns(enrichedUnifiedDecisions, relationColumnsMap, model) {
|
|
15282
|
+
if (relationColumnsMap.size === 0) return;
|
|
15283
|
+
for (const d of enrichedUnifiedDecisions) {
|
|
15284
|
+
if (d.type === "includeStrategy" && d.relationName) {
|
|
15285
|
+
const mapKey = d.relationPath ?? d.relationName;
|
|
15286
|
+
const entries = mapKey ? relationColumnsMap.get(mapKey) : void 0;
|
|
15287
|
+
if (entries) {
|
|
15288
|
+
const mut = d;
|
|
15289
|
+
mut.columns = entries.map((e) => e.col);
|
|
15290
|
+
const aliasMap = {};
|
|
15291
|
+
for (const { col, alias } of entries) {
|
|
15292
|
+
if (alias) aliasMap[col] = alias;
|
|
15293
|
+
}
|
|
15294
|
+
if (Object.keys(aliasMap).length > 0) {
|
|
15295
|
+
mut.columnAliases = aliasMap;
|
|
15296
|
+
}
|
|
15297
|
+
}
|
|
15298
|
+
}
|
|
15299
|
+
}
|
|
15300
|
+
if (!model) return;
|
|
15301
|
+
for (const d of enrichedUnifiedDecisions) {
|
|
15302
|
+
if (d.type === "includeStrategy" && d.columns && d.targetTable && !(d.columns.length === 1 && d.columns[0] === "*")) {
|
|
15303
|
+
const targetTable = model.getTable(d.targetTable);
|
|
15304
|
+
if (targetTable) {
|
|
15305
|
+
const validColumnNames = new Set(
|
|
15306
|
+
targetTable.columns.map((c) => c.name)
|
|
15307
|
+
);
|
|
15308
|
+
const invalid = d.columns.filter(
|
|
15309
|
+
(c) => !validColumnNames.has(c)
|
|
15310
|
+
);
|
|
15311
|
+
if (invalid.length > 0) {
|
|
15312
|
+
throw new Error(
|
|
15313
|
+
`Unknown column(s) ${invalid.map((c) => `'${c}'`).join(", ")} in relation '${d.relationName}' (table '${d.targetTable}'). Available: ${[...validColumnNames].join(", ")}`
|
|
15314
|
+
);
|
|
15315
|
+
}
|
|
15316
|
+
}
|
|
15317
|
+
}
|
|
15318
|
+
}
|
|
15319
|
+
}
|
|
15320
|
+
function applyJoinHydrationPrefixes(decisions) {
|
|
15321
|
+
const usages = [];
|
|
15322
|
+
for (const d of decisions) {
|
|
15323
|
+
if (d.type !== "includeStrategy" || d.choice !== "join" || !d.relationName) {
|
|
15324
|
+
continue;
|
|
15325
|
+
}
|
|
15326
|
+
const relationName = d.relationName;
|
|
15327
|
+
const relationPath = d.relationPath ?? relationName;
|
|
15328
|
+
usages.push({ relationName, relationPath });
|
|
15329
|
+
}
|
|
15330
|
+
const pathCountsByRelation = countDistinctRelationPathsByName(usages);
|
|
15331
|
+
for (const d of decisions) {
|
|
15332
|
+
if (d.type !== "includeStrategy" || d.choice !== "join" || !d.relationName) {
|
|
15333
|
+
continue;
|
|
15334
|
+
}
|
|
15335
|
+
const relationName = d.relationName;
|
|
15336
|
+
const relationPath = d.relationPath ?? relationName;
|
|
15337
|
+
const usesFullPath = (pathCountsByRelation.get(relationName) ?? 0) > 1;
|
|
15338
|
+
d.hydrationPrefix = usesFullPath ? relationPath : relationName;
|
|
15339
|
+
}
|
|
15340
|
+
}
|
|
15341
|
+
function enrichRangeDecisions(allDecisions, model, rootTable) {
|
|
15342
|
+
if (!model) return;
|
|
15343
|
+
for (let i = 0; i < allDecisions.length; i++) {
|
|
15344
|
+
const d = allDecisions[i];
|
|
15345
|
+
if (d && d.type === "where" && (d.operator === "contains" || d.operator === "containedBy" || d.operator === "overlaps")) {
|
|
15346
|
+
const tableName = d.table || rootTable;
|
|
15347
|
+
const table = model.getTable(tableName);
|
|
15348
|
+
if (table) {
|
|
15349
|
+
const col = table.columns.find((c) => c.name === d.column);
|
|
15350
|
+
if (col?.type.endsWith("range")) {
|
|
15351
|
+
allDecisions[i] = { ...d, dataType: col.type };
|
|
15352
|
+
}
|
|
15353
|
+
}
|
|
15354
|
+
}
|
|
15355
|
+
}
|
|
15356
|
+
}
|
|
15357
|
+
function buildSimplifiedPlanReport(plan, allDecisions, schemaName) {
|
|
15358
|
+
const bvFromSource = plan.intent?.batchValuesSource;
|
|
15359
|
+
const batchValuesFromFields = bvFromSource ? (() => {
|
|
15360
|
+
const { rangeFunction, params } = buildBatchValuesRangeFn(
|
|
15361
|
+
bvFromSource,
|
|
15362
|
+
1
|
|
15363
|
+
);
|
|
15364
|
+
return {
|
|
15365
|
+
batchValuesFromNode: rangeFunction,
|
|
15366
|
+
batchValuesFromParams: params
|
|
15367
|
+
};
|
|
15368
|
+
})() : {};
|
|
15369
|
+
return {
|
|
15370
|
+
rootTable: plan.rootTable,
|
|
15371
|
+
decisions: allDecisions,
|
|
15372
|
+
...schemaName ? { schema: schemaName } : {},
|
|
15373
|
+
...plan.intent?.existsWrap ? { existsWrap: true } : {},
|
|
15374
|
+
...plan.intent?.lock ? { lock: plan.intent.lock } : {},
|
|
15375
|
+
...batchValuesFromFields
|
|
15376
|
+
};
|
|
15377
|
+
}
|
|
15378
|
+
function compileSelect(plan, options, deps) {
|
|
15379
|
+
const schemaName = deps.schemaName;
|
|
15380
|
+
const resolvedModelForCompiler = options?.model ?? deps.model;
|
|
15381
|
+
const compilerOptions = {
|
|
15382
|
+
naming: deps.naming,
|
|
15383
|
+
...schemaName && { schema: schemaName },
|
|
15384
|
+
defaultPkColumnName: deps.defaultPk,
|
|
15385
|
+
deriveFkColumnName: deps.deriveFk,
|
|
15386
|
+
...deps.bindingNames !== void 0 && {
|
|
15387
|
+
bindingNames: deps.bindingNames
|
|
15388
|
+
},
|
|
15389
|
+
...resolvedModelForCompiler != null && {
|
|
15390
|
+
model: resolvedModelForCompiler
|
|
15391
|
+
}
|
|
15392
|
+
};
|
|
15393
|
+
const execIntent = plan.executableIntent ?? plan.intent;
|
|
15394
|
+
const planForCompilation = plan.executableIntent !== void 0 ? { ...plan, intent: plan.executableIntent } : plan;
|
|
15395
|
+
let simplifiedPlan;
|
|
15396
|
+
if (execIntent) {
|
|
15397
|
+
let decisions = intentToDecisions(execIntent, plan.rootTable);
|
|
15398
|
+
const resolvedModel = options?.model ?? deps.model;
|
|
15399
|
+
if (resolvedModel) {
|
|
15400
|
+
decisions = convertDottedFieldsToExists(
|
|
15401
|
+
decisions,
|
|
15402
|
+
plan.rootTable,
|
|
15403
|
+
resolvedModel
|
|
15404
|
+
);
|
|
15405
|
+
}
|
|
15406
|
+
enrichExistsDecisionsInPlace(
|
|
15407
|
+
decisions,
|
|
15408
|
+
planForCompilation,
|
|
15409
|
+
options?.model ?? deps.model
|
|
15410
|
+
);
|
|
15411
|
+
const unifiedIncludeDecisions = extractAllIncludeDecisions(
|
|
15412
|
+
planForCompilation,
|
|
15413
|
+
deps.defaultPk,
|
|
15414
|
+
deps.deriveFk
|
|
15415
|
+
);
|
|
15416
|
+
const coveredByPlanner = new Set(
|
|
15417
|
+
unifiedIncludeDecisions.filter((d) => d.type === "includeStrategy").map((d) => d.relationName).filter(Boolean)
|
|
15418
|
+
);
|
|
15419
|
+
const synthesizedModel = options?.model ?? deps.model;
|
|
15420
|
+
const synthesizedJoins = synthesizedModel ? synthesizeMissingJoinDecisions(
|
|
15421
|
+
planForCompilation,
|
|
15422
|
+
coveredByPlanner,
|
|
15423
|
+
synthesizedModel,
|
|
15424
|
+
deps.defaultPk,
|
|
15425
|
+
deps.deriveFk
|
|
15426
|
+
) : [];
|
|
15427
|
+
const allUnifiedIncludeDecisions = synthesizedJoins.length > 0 ? [...unifiedIncludeDecisions, ...synthesizedJoins] : unifiedIncludeDecisions;
|
|
15428
|
+
const enrichedUnifiedDecisions = [
|
|
15429
|
+
...allUnifiedIncludeDecisions
|
|
15430
|
+
];
|
|
15431
|
+
stripJoinColumnsForAggregation(enrichedUnifiedDecisions, execIntent);
|
|
15432
|
+
applyJoinHydrationPrefixes(enrichedUnifiedDecisions);
|
|
15433
|
+
const includedRelations = new Set(
|
|
15434
|
+
enrichedUnifiedDecisions.filter((d) => d.type === "includeStrategy").map((d) => d.relationName).filter(Boolean)
|
|
15435
|
+
);
|
|
15436
|
+
if (includedRelations.size > 0) {
|
|
15437
|
+
const relationColumnsMap = buildRelationColumnsMap(
|
|
15438
|
+
decisions,
|
|
15439
|
+
includedRelations
|
|
15440
|
+
);
|
|
15441
|
+
injectAndValidateRelationColumns(
|
|
15442
|
+
enrichedUnifiedDecisions,
|
|
15443
|
+
relationColumnsMap,
|
|
15444
|
+
options?.model ?? deps.model
|
|
15445
|
+
);
|
|
15446
|
+
}
|
|
15447
|
+
const deduplicatedDecisions = includedRelations.size > 0 ? decisions.filter((d) => {
|
|
15448
|
+
if (d.type === "selectRelationColumn" && d.relation) {
|
|
15449
|
+
const rel = d.relation;
|
|
15450
|
+
const rootRelation = rel.split(".")[0] ?? rel;
|
|
15451
|
+
if (includedRelations.has(rootRelation)) {
|
|
15452
|
+
return false;
|
|
15453
|
+
}
|
|
15454
|
+
}
|
|
15455
|
+
return true;
|
|
15456
|
+
}) : decisions;
|
|
15457
|
+
const joinIntentDecisions = execIntent?.joins && execIntent.joins.length > 0 ? compileJoinIntents(
|
|
15458
|
+
execIntent.joins,
|
|
15459
|
+
plan.rootTable,
|
|
15460
|
+
schemaName,
|
|
15461
|
+
deps
|
|
15462
|
+
) : [];
|
|
15463
|
+
const allDecisions = [
|
|
15464
|
+
...deduplicatedDecisions,
|
|
15465
|
+
...enrichedUnifiedDecisions,
|
|
15466
|
+
...joinIntentDecisions
|
|
15467
|
+
];
|
|
15468
|
+
const rangeModel = options?.model ?? deps.model;
|
|
15469
|
+
enrichRangeDecisions(allDecisions, rangeModel, plan.rootTable);
|
|
15470
|
+
simplifiedPlan = buildSimplifiedPlanReport(
|
|
15471
|
+
planForCompilation,
|
|
15472
|
+
allDecisions,
|
|
15473
|
+
schemaName
|
|
15474
|
+
);
|
|
15475
|
+
} else {
|
|
15476
|
+
simplifiedPlan = {
|
|
15477
|
+
rootTable: plan.rootTable,
|
|
15478
|
+
decisions: bridgeLegacyDecisions(plan.decisions),
|
|
15479
|
+
...schemaName ? { schema: schemaName } : {}
|
|
15480
|
+
};
|
|
15481
|
+
}
|
|
15482
|
+
const result = compilePlan(simplifiedPlan, compilerOptions);
|
|
15483
|
+
return {
|
|
15484
|
+
sql: result.sql,
|
|
15485
|
+
parameters: result.parameters
|
|
15486
|
+
};
|
|
15493
15487
|
}
|
|
15494
|
-
function
|
|
15495
|
-
const
|
|
15496
|
-
const
|
|
15497
|
-
const
|
|
15498
|
-
|
|
15499
|
-
|
|
15500
|
-
|
|
15501
|
-
|
|
15502
|
-
|
|
15503
|
-
|
|
15488
|
+
function compileWithIncludes(plan, options, deps) {
|
|
15489
|
+
const main = compileSelect(plan, options, deps);
|
|
15490
|
+
const subqueryIncludes = [];
|
|
15491
|
+
for (const d of plan.decisions) {
|
|
15492
|
+
if (d.type !== "include-strategy" || d.choice !== "subquery") continue;
|
|
15493
|
+
const ctx = d.context;
|
|
15494
|
+
if (!ctx.target) continue;
|
|
15495
|
+
const relationName = ctx.includeAlias ?? ctx.relation;
|
|
15496
|
+
if (!relationName) continue;
|
|
15497
|
+
const rawFk = deriveForeignKey(ctx, deps.deriveFk, deps.defaultPk) ?? deps.defaultPk;
|
|
15498
|
+
const fk = Array.isArray(rawFk) ? rawFk[0] : rawFk;
|
|
15499
|
+
const isBelongsTo = ctx.relationType === "belongsTo";
|
|
15500
|
+
const sourceKey = isBelongsTo ? fk : "id";
|
|
15501
|
+
const targetFk = isBelongsTo ? "id" : fk;
|
|
15502
|
+
const includeIntent = plan.intent?.include?.find(
|
|
15503
|
+
(i) => i.relation === relationName || i.relation === ctx.includeAlias
|
|
15504
|
+
);
|
|
15505
|
+
const entry = {
|
|
15506
|
+
relationName,
|
|
15507
|
+
targetTable: ctx.target,
|
|
15508
|
+
foreignKey: targetFk,
|
|
15509
|
+
sourceKey,
|
|
15510
|
+
sourceTable: ctx.sourceTable ?? plan.rootTable
|
|
15511
|
+
};
|
|
15512
|
+
if (typeof ctx.relationType === "string") {
|
|
15513
|
+
entry.relationType = ctx.relationType;
|
|
15504
15514
|
}
|
|
15505
|
-
|
|
15506
|
-
|
|
15507
|
-
function buildRelationColumnsMap(decisions, includedRelations) {
|
|
15508
|
-
const map = /* @__PURE__ */ new Map();
|
|
15509
|
-
for (const d of decisions) {
|
|
15510
|
-
if (!(d.type === "selectRelationColumn" && d.relation && d.column))
|
|
15511
|
-
continue;
|
|
15512
|
-
const col = d.column;
|
|
15513
|
-
const alias = d.alias;
|
|
15514
|
-
const fullRelation = d.relation;
|
|
15515
|
-
const rootRelation = fullRelation.split(".")[0] ?? "";
|
|
15516
|
-
if (!includedRelations.has(rootRelation)) continue;
|
|
15517
|
-
const mapKey = fullRelation;
|
|
15518
|
-
if (col === "*") {
|
|
15519
|
-
map.set(mapKey, [{ col: "*" }]);
|
|
15520
|
-
continue;
|
|
15515
|
+
if (includeIntent?.select != null) {
|
|
15516
|
+
entry.select = includeIntent.select;
|
|
15521
15517
|
}
|
|
15522
|
-
|
|
15523
|
-
|
|
15524
|
-
if (existing.length === 1 && existing[0]?.col === "*") continue;
|
|
15525
|
-
if (!existing.some((e) => e.col === col)) {
|
|
15526
|
-
existing.push({ col, ...alias !== void 0 && { alias } });
|
|
15527
|
-
}
|
|
15528
|
-
} else {
|
|
15529
|
-
map.set(mapKey, [{ col, ...alias !== void 0 && { alias } }]);
|
|
15518
|
+
if (includeIntent?.where != null) {
|
|
15519
|
+
entry.where = includeIntent.where;
|
|
15530
15520
|
}
|
|
15521
|
+
subqueryIncludes.push(entry);
|
|
15531
15522
|
}
|
|
15532
|
-
return
|
|
15523
|
+
return { main, subqueryIncludes };
|
|
15533
15524
|
}
|
|
15534
|
-
|
|
15535
|
-
|
|
15536
|
-
|
|
15537
|
-
|
|
15538
|
-
|
|
15539
|
-
|
|
15540
|
-
|
|
15541
|
-
|
|
15542
|
-
|
|
15543
|
-
|
|
15544
|
-
|
|
15545
|
-
|
|
15546
|
-
|
|
15547
|
-
|
|
15548
|
-
|
|
15549
|
-
|
|
15550
|
-
|
|
15551
|
-
|
|
15525
|
+
|
|
15526
|
+
// src/adapter-compiler-mutations.ts
|
|
15527
|
+
init_binding_registry();
|
|
15528
|
+
init_compile_where();
|
|
15529
|
+
init_compiler_utils();
|
|
15530
|
+
init_handlers();
|
|
15531
|
+
function whereIntentAsDecision(where) {
|
|
15532
|
+
return where;
|
|
15533
|
+
}
|
|
15534
|
+
function renumberSqlParams(sql, offset) {
|
|
15535
|
+
if (offset === 0) return sql;
|
|
15536
|
+
return sql.replace(/\$(\d+)/g, (_match, num) => {
|
|
15537
|
+
return `$${Number.parseInt(num, 10) + offset}`;
|
|
15538
|
+
});
|
|
15539
|
+
}
|
|
15540
|
+
function compileSourceQueryCte(operation, sourceName, sourceQuery, options, deps) {
|
|
15541
|
+
const model = deps.model;
|
|
15542
|
+
if (model === void 0) {
|
|
15543
|
+
throw new Error(
|
|
15544
|
+
`${operation} with sourceQuery requires a model to emit the source CTE for '${sourceName}'.`
|
|
15545
|
+
);
|
|
15552
15546
|
}
|
|
15553
|
-
|
|
15554
|
-
|
|
15555
|
-
|
|
15556
|
-
|
|
15557
|
-
|
|
15558
|
-
|
|
15559
|
-
|
|
15560
|
-
|
|
15561
|
-
|
|
15562
|
-
|
|
15563
|
-
|
|
15564
|
-
|
|
15565
|
-
|
|
15566
|
-
|
|
15567
|
-
|
|
15568
|
-
|
|
15569
|
-
|
|
15547
|
+
const sourcePlan = planFn(sourceQuery, model, {
|
|
15548
|
+
dialectCapabilities: POSTGRESQL_CAPABILITIES
|
|
15549
|
+
});
|
|
15550
|
+
return compileSelect(sourcePlan, options, deps);
|
|
15551
|
+
}
|
|
15552
|
+
function prependSourceCte(sql, parameters, sourceName, sourceCte, naming) {
|
|
15553
|
+
if (sourceCte === void 0) {
|
|
15554
|
+
return { sql, parameters };
|
|
15555
|
+
}
|
|
15556
|
+
const cteParamCount = sourceCte.parameters.length;
|
|
15557
|
+
const sourceCteName = emittedBindName(sourceName, naming);
|
|
15558
|
+
return {
|
|
15559
|
+
sql: `WITH ${quoteIdent2(sourceCteName, "alias")} as (${sourceCte.sql}) ${renumberSqlParams(sql, cteParamCount)}`,
|
|
15560
|
+
parameters: [...sourceCte.parameters, ...parameters]
|
|
15561
|
+
};
|
|
15562
|
+
}
|
|
15563
|
+
function resolveExistsRelation(sourceTable, relation, model) {
|
|
15564
|
+
if (!model) return { targetTable: relation };
|
|
15565
|
+
const rel = model.getRelation(`${sourceTable}.${relation}`);
|
|
15566
|
+
if (!rel) return { targetTable: relation };
|
|
15567
|
+
const targetTable = rel.target;
|
|
15568
|
+
if (rel.type === "belongsTo") {
|
|
15569
|
+
const fk2 = typeof rel.foreignKey === "string" ? rel.foreignKey : rel.foreignKey?.[0];
|
|
15570
|
+
return {
|
|
15571
|
+
targetTable,
|
|
15572
|
+
...fk2 !== void 0 && { sourceColumn: fk2 },
|
|
15573
|
+
targetColumn: "id"
|
|
15574
|
+
};
|
|
15575
|
+
}
|
|
15576
|
+
const fk = typeof rel.foreignKey === "string" ? rel.foreignKey : rel.foreignKey?.[0];
|
|
15577
|
+
return {
|
|
15578
|
+
targetTable,
|
|
15579
|
+
sourceColumn: rel.sourceKey ?? "id",
|
|
15580
|
+
...fk !== void 0 && { targetColumn: fk }
|
|
15581
|
+
};
|
|
15582
|
+
}
|
|
15583
|
+
function resolveExistsIntent(where, sourceTable, deps) {
|
|
15584
|
+
const w = where;
|
|
15585
|
+
const kind = w.kind;
|
|
15586
|
+
if (kind === "and" || kind === "or") {
|
|
15587
|
+
const conditions = w.conditions;
|
|
15588
|
+
if (!conditions) return where;
|
|
15589
|
+
const enriched = conditions.map(
|
|
15590
|
+
(c) => resolveExistsIntent(c, sourceTable, deps)
|
|
15591
|
+
);
|
|
15592
|
+
const changed = enriched.some((c, i) => c !== conditions[i]);
|
|
15593
|
+
return changed ? { ...w, conditions: enriched } : where;
|
|
15594
|
+
}
|
|
15595
|
+
if (kind === "not") {
|
|
15596
|
+
const condition = w.condition;
|
|
15597
|
+
if (!condition) return where;
|
|
15598
|
+
const enriched = resolveExistsIntent(condition, sourceTable, deps);
|
|
15599
|
+
return enriched !== condition ? { ...w, condition: enriched } : where;
|
|
15600
|
+
}
|
|
15601
|
+
if (kind !== "exists" && kind !== "notExists") return where;
|
|
15602
|
+
const relation = w.relation;
|
|
15603
|
+
const resolved = resolveExistsRelation(sourceTable, relation, deps.model);
|
|
15604
|
+
if (resolved.targetTable === relation && !resolved.sourceColumn) return where;
|
|
15605
|
+
return {
|
|
15606
|
+
...w,
|
|
15607
|
+
targetTable: resolved.targetTable,
|
|
15608
|
+
...resolved.sourceColumn !== void 0 && {
|
|
15609
|
+
sourceColumn: resolved.sourceColumn
|
|
15610
|
+
},
|
|
15611
|
+
...resolved.targetColumn !== void 0 && {
|
|
15612
|
+
targetColumn: resolved.targetColumn
|
|
15613
|
+
}
|
|
15614
|
+
};
|
|
15615
|
+
}
|
|
15616
|
+
function getColumnTypes(tableName, columns, deps) {
|
|
15617
|
+
if (!deps.model) return void 0;
|
|
15618
|
+
const table = deps.model.getTable(tableName);
|
|
15619
|
+
if (!table) return void 0;
|
|
15620
|
+
let result;
|
|
15621
|
+
for (const col of columns) {
|
|
15622
|
+
const columnIR = table.columns.find((c) => c.name === col);
|
|
15623
|
+
if (columnIR) {
|
|
15624
|
+
result ??= {};
|
|
15625
|
+
result[col] = columnIR.originalDbType ?? columnIR.type;
|
|
15570
15626
|
}
|
|
15571
15627
|
}
|
|
15628
|
+
return result;
|
|
15629
|
+
}
|
|
15630
|
+
function compileUpsertActionWhere(where, table, state, deps, schemaName) {
|
|
15631
|
+
const whereCtx = {
|
|
15632
|
+
rootTable: table,
|
|
15633
|
+
aliases: /* @__PURE__ */ new Map(),
|
|
15634
|
+
paramState: state,
|
|
15635
|
+
naming: deps.naming,
|
|
15636
|
+
...schemaName !== void 0 && { schemaName },
|
|
15637
|
+
...deps.bindingNames !== void 0 && { bindingNames: deps.bindingNames },
|
|
15638
|
+
...deps.model !== void 0 && { model: deps.model },
|
|
15639
|
+
compileSubquery: (sqIntent, paramOffset) => buildSubqueryFromIntent(
|
|
15640
|
+
sqIntent,
|
|
15641
|
+
paramOffset,
|
|
15642
|
+
deps.naming,
|
|
15643
|
+
schemaName,
|
|
15644
|
+
"rawExists",
|
|
15645
|
+
deps.bindingNames
|
|
15646
|
+
)
|
|
15647
|
+
};
|
|
15648
|
+
return compileWhereIntent(where, whereCtx);
|
|
15649
|
+
}
|
|
15650
|
+
function compileInsert2(intent, options, deps) {
|
|
15651
|
+
const schemaName = deps.schemaName;
|
|
15652
|
+
const ctx = {
|
|
15653
|
+
naming: deps.naming,
|
|
15654
|
+
rootTable: intent.table,
|
|
15655
|
+
...schemaName !== void 0 && { schema: schemaName },
|
|
15656
|
+
...deps.bindingNames !== void 0 && { bindingNames: deps.bindingNames },
|
|
15657
|
+
maxRecursiveDepth: 100
|
|
15658
|
+
};
|
|
15659
|
+
const state = createCompilerState();
|
|
15660
|
+
const firstRow = intent.values?.[0] ?? {};
|
|
15661
|
+
const columns = Object.keys(firstRow);
|
|
15662
|
+
const rows = intent.values ?? [];
|
|
15663
|
+
const values = rows.map((row) => columns.map((col) => row[col]));
|
|
15664
|
+
const columnTypes = getColumnTypes(intent.table, columns, deps);
|
|
15665
|
+
const config = {
|
|
15666
|
+
table: intent.table,
|
|
15667
|
+
columns,
|
|
15668
|
+
values,
|
|
15669
|
+
...intent.returning && { returning: [...intent.returning] },
|
|
15670
|
+
...columnTypes && { columnTypes }
|
|
15671
|
+
};
|
|
15672
|
+
const maxBatchSize = options?.maxBatchSize;
|
|
15673
|
+
if (maxBatchSize !== void 0 && values.length > maxBatchSize) {
|
|
15674
|
+
throw new InvalidOperationError3(
|
|
15675
|
+
"insert",
|
|
15676
|
+
`Batch size ${values.length} exceeds maxBatchSize ${maxBatchSize}`
|
|
15677
|
+
);
|
|
15678
|
+
}
|
|
15679
|
+
const batchThreshold = options?.batchThreshold ?? 50;
|
|
15680
|
+
const useUnnest = values.length > 0 && (batchThreshold === 0 || values.length > batchThreshold);
|
|
15681
|
+
const ast = useUnnest ? compileUnnestInsert(config, ctx, state) : compileInsert(config, ctx, state);
|
|
15682
|
+
const sql = deparseQuoted(ast);
|
|
15683
|
+
return {
|
|
15684
|
+
sql,
|
|
15685
|
+
parameters: state.parameters
|
|
15686
|
+
};
|
|
15687
|
+
}
|
|
15688
|
+
function compileInsertFrom2(intent, options, deps) {
|
|
15689
|
+
const schemaName = deps.schemaName;
|
|
15690
|
+
const sourceCte = intent.sourceQuery !== void 0 && !hasBindingName(deps.bindingNames, intent.source, deps.naming) ? compileSourceQueryCte(
|
|
15691
|
+
"compileInsertFrom",
|
|
15692
|
+
intent.source,
|
|
15693
|
+
intent.sourceQuery,
|
|
15694
|
+
options,
|
|
15695
|
+
deps
|
|
15696
|
+
) : void 0;
|
|
15697
|
+
const bindingNames = intent.sourceQuery !== void 0 ? withBindingName(deps.bindingNames, intent.source, deps.naming) : deps.bindingNames;
|
|
15698
|
+
const ctx = {
|
|
15699
|
+
naming: deps.naming,
|
|
15700
|
+
rootTable: intent.source,
|
|
15701
|
+
...schemaName !== void 0 && { schema: schemaName },
|
|
15702
|
+
...bindingNames !== void 0 && { bindingNames },
|
|
15703
|
+
maxRecursiveDepth: 100
|
|
15704
|
+
};
|
|
15705
|
+
const state = createCompilerState();
|
|
15706
|
+
const config = {
|
|
15707
|
+
targetTable: intent.table,
|
|
15708
|
+
sourceTable: intent.source,
|
|
15709
|
+
...intent.columns && { columns: [...intent.columns] },
|
|
15710
|
+
...intent.where && { where: [whereIntentAsDecision(intent.where)] },
|
|
15711
|
+
...intent.limit !== void 0 && { limit: intent.limit },
|
|
15712
|
+
...intent.returning && { returning: [...intent.returning] }
|
|
15713
|
+
};
|
|
15714
|
+
const ast = compileInsertFrom(config, ctx, state);
|
|
15715
|
+
const sql = deparseQuoted(ast);
|
|
15716
|
+
return prependSourceCte(
|
|
15717
|
+
sql,
|
|
15718
|
+
state.parameters,
|
|
15719
|
+
intent.source,
|
|
15720
|
+
sourceCte,
|
|
15721
|
+
deps.naming
|
|
15722
|
+
);
|
|
15572
15723
|
}
|
|
15573
|
-
function
|
|
15574
|
-
const
|
|
15575
|
-
|
|
15576
|
-
|
|
15577
|
-
|
|
15578
|
-
|
|
15579
|
-
|
|
15580
|
-
|
|
15581
|
-
|
|
15724
|
+
function compileUpdate2(intent, options, deps) {
|
|
15725
|
+
const schemaName = deps.schemaName;
|
|
15726
|
+
const resolvedModel = options?.model ?? deps.model;
|
|
15727
|
+
const ctx = {
|
|
15728
|
+
naming: deps.naming,
|
|
15729
|
+
rootTable: intent.table,
|
|
15730
|
+
...schemaName !== void 0 && { schema: schemaName },
|
|
15731
|
+
...deps.bindingNames !== void 0 && { bindingNames: deps.bindingNames },
|
|
15732
|
+
...resolvedModel !== void 0 && { model: resolvedModel },
|
|
15733
|
+
maxRecursiveDepth: 100
|
|
15734
|
+
};
|
|
15735
|
+
const state = createCompilerState();
|
|
15736
|
+
const setColumns = Object.keys(intent.set ?? {});
|
|
15737
|
+
const columnTypes = getColumnTypes(intent.table, setColumns, deps);
|
|
15738
|
+
const resolvedWhere = intent.where ? resolveExistsIntent(intent.where, intent.table, deps) : void 0;
|
|
15739
|
+
const config = {
|
|
15740
|
+
table: intent.table,
|
|
15741
|
+
set: Object.entries(intent.set ?? {}).map(([column, value]) => ({
|
|
15742
|
+
column,
|
|
15743
|
+
value
|
|
15744
|
+
})),
|
|
15745
|
+
...resolvedWhere && { where: [whereIntentAsDecision(resolvedWhere)] },
|
|
15746
|
+
...intent.returning && { returning: [...intent.returning] },
|
|
15747
|
+
...columnTypes && { columnTypes }
|
|
15748
|
+
};
|
|
15749
|
+
const ast = compileUpdate(config, ctx, state);
|
|
15750
|
+
const sql = deparseQuoted(ast);
|
|
15751
|
+
return {
|
|
15752
|
+
sql,
|
|
15753
|
+
parameters: state.parameters
|
|
15754
|
+
};
|
|
15755
|
+
}
|
|
15756
|
+
function compileBatchUpdate(intent, _options, deps) {
|
|
15757
|
+
const schemaName = deps.schemaName;
|
|
15758
|
+
const ctx = {
|
|
15759
|
+
naming: deps.naming,
|
|
15760
|
+
rootTable: intent.table,
|
|
15761
|
+
...schemaName !== void 0 && { schema: schemaName },
|
|
15762
|
+
...deps.bindingNames !== void 0 && { bindingNames: deps.bindingNames },
|
|
15763
|
+
maxRecursiveDepth: 100
|
|
15764
|
+
};
|
|
15765
|
+
const state = createCompilerState();
|
|
15766
|
+
if (intent.updates.length === 0) {
|
|
15767
|
+
throw new InvalidOperationError3(
|
|
15768
|
+
"update",
|
|
15769
|
+
"batchSet requires at least one row"
|
|
15770
|
+
);
|
|
15582
15771
|
}
|
|
15583
|
-
const
|
|
15584
|
-
|
|
15585
|
-
|
|
15586
|
-
|
|
15772
|
+
const allColumns = Object.keys(intent.updates[0]);
|
|
15773
|
+
const matchColumns = [...intent.matchColumns];
|
|
15774
|
+
for (const mc of matchColumns) {
|
|
15775
|
+
if (!allColumns.includes(mc)) {
|
|
15776
|
+
throw new InvalidOperationError3(
|
|
15777
|
+
"update",
|
|
15778
|
+
`Match column "${mc}" not found in update data. Each row must include the match column(s).`
|
|
15779
|
+
);
|
|
15587
15780
|
}
|
|
15588
|
-
const relationName = d.relationName;
|
|
15589
|
-
const relationPath = d.relationPath ?? relationName;
|
|
15590
|
-
const usesFullPath = (pathCountsByRelation.get(relationName) ?? 0) > 1;
|
|
15591
|
-
d.hydrationPrefix = usesFullPath ? relationPath : relationName;
|
|
15592
15781
|
}
|
|
15593
|
-
|
|
15594
|
-
|
|
15595
|
-
|
|
15596
|
-
|
|
15597
|
-
|
|
15598
|
-
|
|
15599
|
-
|
|
15600
|
-
|
|
15601
|
-
|
|
15602
|
-
|
|
15603
|
-
|
|
15604
|
-
|
|
15605
|
-
|
|
15606
|
-
|
|
15607
|
-
|
|
15782
|
+
const values = intent.updates.map((row) => allColumns.map((col) => row[col]));
|
|
15783
|
+
validateBatchCardinality(allColumns, values);
|
|
15784
|
+
const columnArrays = transposeToColumnArrays(allColumns, values);
|
|
15785
|
+
const columnTypes = getColumnTypes(intent.table, allColumns, deps);
|
|
15786
|
+
const scalarSet = intent.scalarSet ? Object.entries(intent.scalarSet).map(([column, value]) => ({
|
|
15787
|
+
column,
|
|
15788
|
+
value
|
|
15789
|
+
})) : void 0;
|
|
15790
|
+
let whereGuard;
|
|
15791
|
+
if (intent.where) {
|
|
15792
|
+
const whereCtx = {
|
|
15793
|
+
rootTable: intent.table,
|
|
15794
|
+
aliases: /* @__PURE__ */ new Map(),
|
|
15795
|
+
paramState: state,
|
|
15796
|
+
naming: deps.naming,
|
|
15797
|
+
...schemaName !== void 0 && { schemaName },
|
|
15798
|
+
...deps.bindingNames !== void 0 && {
|
|
15799
|
+
bindingNames: deps.bindingNames
|
|
15800
|
+
},
|
|
15801
|
+
...deps.model !== void 0 && { model: deps.model },
|
|
15802
|
+
compileSubquery: (sqIntent, paramOffset) => buildSubqueryFromIntent(
|
|
15803
|
+
sqIntent,
|
|
15804
|
+
paramOffset,
|
|
15805
|
+
deps.naming,
|
|
15806
|
+
schemaName,
|
|
15807
|
+
"rawExists",
|
|
15808
|
+
deps.bindingNames
|
|
15809
|
+
)
|
|
15810
|
+
};
|
|
15811
|
+
whereGuard = compileWhereIntent(intent.where, whereCtx);
|
|
15608
15812
|
}
|
|
15813
|
+
const config = {
|
|
15814
|
+
table: intent.table,
|
|
15815
|
+
matchColumns,
|
|
15816
|
+
allColumns,
|
|
15817
|
+
columnArrays,
|
|
15818
|
+
...scalarSet && { scalarSet },
|
|
15819
|
+
...intent.returning && { returning: [...intent.returning] },
|
|
15820
|
+
...columnTypes && { columnTypes },
|
|
15821
|
+
...whereGuard !== void 0 && { whereGuard }
|
|
15822
|
+
};
|
|
15823
|
+
const ast = compileUnnestUpdate(config, ctx, state);
|
|
15824
|
+
const sql = deparseQuoted(ast);
|
|
15825
|
+
return {
|
|
15826
|
+
sql,
|
|
15827
|
+
parameters: state.parameters
|
|
15828
|
+
};
|
|
15609
15829
|
}
|
|
15610
|
-
function
|
|
15611
|
-
const
|
|
15612
|
-
const
|
|
15613
|
-
|
|
15614
|
-
|
|
15615
|
-
|
|
15616
|
-
|
|
15617
|
-
|
|
15618
|
-
|
|
15619
|
-
|
|
15620
|
-
|
|
15621
|
-
|
|
15830
|
+
function compileDelete2(intent, options, deps) {
|
|
15831
|
+
const schemaName = deps.schemaName;
|
|
15832
|
+
const resolvedModel = options?.model ?? deps.model;
|
|
15833
|
+
const ctx = {
|
|
15834
|
+
naming: deps.naming,
|
|
15835
|
+
rootTable: intent.table,
|
|
15836
|
+
...schemaName !== void 0 && { schema: schemaName },
|
|
15837
|
+
...deps.bindingNames !== void 0 && { bindingNames: deps.bindingNames },
|
|
15838
|
+
maxRecursiveDepth: 100,
|
|
15839
|
+
...resolvedModel !== void 0 && { model: resolvedModel }
|
|
15840
|
+
};
|
|
15841
|
+
const state = createCompilerState();
|
|
15842
|
+
const resolvedWhere = intent.where ? resolveExistsIntent(intent.where, intent.table, deps) : void 0;
|
|
15843
|
+
const config = {
|
|
15844
|
+
table: intent.table,
|
|
15845
|
+
...resolvedWhere && { where: [whereIntentAsDecision(resolvedWhere)] },
|
|
15846
|
+
...intent.returning && { returning: [...intent.returning] }
|
|
15847
|
+
};
|
|
15848
|
+
const ast = compileDelete(config, ctx, state);
|
|
15849
|
+
const sql = deparseQuoted(ast);
|
|
15622
15850
|
return {
|
|
15623
|
-
|
|
15624
|
-
|
|
15625
|
-
...schemaName ? { schema: schemaName } : {},
|
|
15626
|
-
...plan.intent?.existsWrap ? { existsWrap: true } : {},
|
|
15627
|
-
...plan.intent?.lock ? { lock: plan.intent.lock } : {},
|
|
15628
|
-
...batchValuesFromFields
|
|
15851
|
+
sql,
|
|
15852
|
+
parameters: state.parameters
|
|
15629
15853
|
};
|
|
15630
15854
|
}
|
|
15631
|
-
function
|
|
15855
|
+
function compileUpsert2(intent, options, deps) {
|
|
15632
15856
|
const schemaName = deps.schemaName;
|
|
15633
|
-
const
|
|
15634
|
-
const compilerOptions = {
|
|
15857
|
+
const ctx = {
|
|
15635
15858
|
naming: deps.naming,
|
|
15636
|
-
|
|
15637
|
-
|
|
15638
|
-
|
|
15639
|
-
...
|
|
15640
|
-
|
|
15641
|
-
}
|
|
15859
|
+
rootTable: intent.table,
|
|
15860
|
+
...schemaName !== void 0 && { schema: schemaName },
|
|
15861
|
+
...deps.bindingNames !== void 0 && { bindingNames: deps.bindingNames },
|
|
15862
|
+
...deps.model !== void 0 && { model: deps.model },
|
|
15863
|
+
maxRecursiveDepth: 100
|
|
15642
15864
|
};
|
|
15643
|
-
const
|
|
15644
|
-
const
|
|
15645
|
-
|
|
15646
|
-
|
|
15647
|
-
|
|
15648
|
-
const
|
|
15649
|
-
|
|
15650
|
-
|
|
15651
|
-
|
|
15652
|
-
|
|
15653
|
-
|
|
15654
|
-
);
|
|
15865
|
+
const state = createCompilerState();
|
|
15866
|
+
const firstRow = intent.values?.[0] ?? {};
|
|
15867
|
+
const rawExprs = {};
|
|
15868
|
+
const scalarSet = {};
|
|
15869
|
+
if (intent.action.type === "doUpdate" && intent.action.set) {
|
|
15870
|
+
for (const [key, val] of Object.entries(intent.action.set)) {
|
|
15871
|
+
if (isSqlRaw2(val)) {
|
|
15872
|
+
rawExprs[key] = val.sql;
|
|
15873
|
+
} else {
|
|
15874
|
+
scalarSet[key] = val;
|
|
15875
|
+
}
|
|
15655
15876
|
}
|
|
15656
|
-
|
|
15657
|
-
|
|
15658
|
-
|
|
15659
|
-
|
|
15660
|
-
|
|
15661
|
-
const
|
|
15662
|
-
|
|
15663
|
-
|
|
15664
|
-
|
|
15665
|
-
|
|
15666
|
-
|
|
15667
|
-
|
|
15668
|
-
|
|
15669
|
-
|
|
15670
|
-
|
|
15671
|
-
|
|
15672
|
-
|
|
15673
|
-
|
|
15674
|
-
|
|
15675
|
-
|
|
15676
|
-
|
|
15677
|
-
|
|
15678
|
-
const enrichedUnifiedDecisions = [
|
|
15679
|
-
...allUnifiedIncludeDecisions
|
|
15680
|
-
];
|
|
15681
|
-
stripJoinColumnsForAggregation(enrichedUnifiedDecisions, execIntent);
|
|
15682
|
-
applyJoinHydrationPrefixes(enrichedUnifiedDecisions);
|
|
15683
|
-
const includedRelations = new Set(
|
|
15684
|
-
enrichedUnifiedDecisions.filter((d) => d.type === "includeStrategy").map((d) => d.relationName).filter(Boolean)
|
|
15685
|
-
);
|
|
15686
|
-
if (includedRelations.size > 0) {
|
|
15687
|
-
const relationColumnsMap = buildRelationColumnsMap(
|
|
15688
|
-
decisions,
|
|
15689
|
-
includedRelations
|
|
15690
|
-
);
|
|
15691
|
-
injectAndValidateRelationColumns(
|
|
15692
|
-
enrichedUnifiedDecisions,
|
|
15693
|
-
relationColumnsMap,
|
|
15694
|
-
options?.model ?? deps.model
|
|
15695
|
-
);
|
|
15877
|
+
}
|
|
15878
|
+
const hasScalarSet = Object.keys(scalarSet).length > 0;
|
|
15879
|
+
const mergedFirstRow = hasScalarSet ? { ...firstRow, ...scalarSet } : firstRow;
|
|
15880
|
+
const columns = Object.keys(mergedFirstRow);
|
|
15881
|
+
const values = (intent.values ?? []).map((row) => {
|
|
15882
|
+
const mergedRow = hasScalarSet ? { ...row, ...scalarSet } : row;
|
|
15883
|
+
return columns.map((col) => mergedRow[col]);
|
|
15884
|
+
});
|
|
15885
|
+
const conflictTarget = {};
|
|
15886
|
+
if ("columns" in intent.onConflict) {
|
|
15887
|
+
conflictTarget.columns = [...intent.onConflict.columns];
|
|
15888
|
+
} else if ("constraint" in intent.onConflict) {
|
|
15889
|
+
conflictTarget.constraint = intent.onConflict.constraint;
|
|
15890
|
+
}
|
|
15891
|
+
const conflictAction = intent.action.type === "doNothing" ? "nothing" : "update";
|
|
15892
|
+
let updateColumns;
|
|
15893
|
+
if (intent.action.type === "doUpdate") {
|
|
15894
|
+
if (intent.action.set) {
|
|
15895
|
+
updateColumns = Object.keys(intent.action.set);
|
|
15896
|
+
} else {
|
|
15897
|
+
const conflictCols = "columns" in intent.onConflict ? intent.onConflict.columns : [];
|
|
15898
|
+
updateColumns = columns.filter((col) => !conflictCols.includes(col));
|
|
15696
15899
|
}
|
|
15697
|
-
|
|
15698
|
-
|
|
15699
|
-
|
|
15700
|
-
|
|
15701
|
-
|
|
15702
|
-
|
|
15703
|
-
|
|
15704
|
-
|
|
15705
|
-
|
|
15706
|
-
|
|
15707
|
-
|
|
15708
|
-
|
|
15709
|
-
|
|
15710
|
-
|
|
15711
|
-
|
|
15712
|
-
|
|
15713
|
-
|
|
15714
|
-
|
|
15715
|
-
|
|
15716
|
-
|
|
15717
|
-
|
|
15718
|
-
|
|
15719
|
-
|
|
15720
|
-
|
|
15721
|
-
|
|
15722
|
-
|
|
15723
|
-
|
|
15900
|
+
}
|
|
15901
|
+
const columnTypes = getColumnTypes(intent.table, columns, deps);
|
|
15902
|
+
const hasRawExprs = Object.keys(rawExprs).length > 0;
|
|
15903
|
+
const actionWhere = intent.action.type === "doUpdate" && intent.action.where ? intent.action.where : void 0;
|
|
15904
|
+
const resolvedActionWhere = actionWhere ? resolveExistsIntent(actionWhere, intent.table, deps) : void 0;
|
|
15905
|
+
const config = {
|
|
15906
|
+
table: intent.table,
|
|
15907
|
+
columns,
|
|
15908
|
+
values,
|
|
15909
|
+
conflictTarget,
|
|
15910
|
+
conflictAction,
|
|
15911
|
+
...updateColumns && { updateColumns },
|
|
15912
|
+
...intent.returning && { returning: [...intent.returning] },
|
|
15913
|
+
...columnTypes && { columnTypes },
|
|
15914
|
+
...hasRawExprs && { updateExpressions: rawExprs },
|
|
15915
|
+
...resolvedActionWhere && {
|
|
15916
|
+
actionWhereIntent: resolvedActionWhere,
|
|
15917
|
+
compileActionWhere: (where, paramState) => compileUpsertActionWhere(
|
|
15918
|
+
where,
|
|
15919
|
+
intent.table,
|
|
15920
|
+
paramState,
|
|
15921
|
+
deps,
|
|
15922
|
+
schemaName
|
|
15923
|
+
)
|
|
15924
|
+
}
|
|
15925
|
+
};
|
|
15926
|
+
const maxBatchSize = options?.maxBatchSize;
|
|
15927
|
+
if (maxBatchSize !== void 0 && values.length > maxBatchSize) {
|
|
15928
|
+
throw new InvalidOperationError3(
|
|
15929
|
+
"upsert",
|
|
15930
|
+
`Batch size ${values.length} exceeds maxBatchSize ${maxBatchSize}`
|
|
15724
15931
|
);
|
|
15725
|
-
} else {
|
|
15726
|
-
simplifiedPlan = {
|
|
15727
|
-
rootTable: plan.rootTable,
|
|
15728
|
-
decisions: bridgeLegacyDecisions(plan.decisions),
|
|
15729
|
-
...schemaName ? { schema: schemaName } : {}
|
|
15730
|
-
};
|
|
15731
15932
|
}
|
|
15732
|
-
const
|
|
15933
|
+
const batchThreshold = options?.batchThreshold ?? 50;
|
|
15934
|
+
const useUnnest = values.length > 0 && (batchThreshold === 0 || values.length > batchThreshold);
|
|
15935
|
+
const ast = useUnnest ? compileUnnestUpsert(config, ctx, state) : compileUpsert(config, ctx, state);
|
|
15936
|
+
const sql = deparseQuoted(ast);
|
|
15733
15937
|
return {
|
|
15734
|
-
sql
|
|
15735
|
-
parameters:
|
|
15938
|
+
sql,
|
|
15939
|
+
parameters: state.parameters
|
|
15736
15940
|
};
|
|
15737
15941
|
}
|
|
15738
|
-
function
|
|
15739
|
-
const
|
|
15740
|
-
const
|
|
15741
|
-
|
|
15742
|
-
|
|
15743
|
-
|
|
15744
|
-
|
|
15745
|
-
|
|
15746
|
-
|
|
15747
|
-
|
|
15748
|
-
|
|
15749
|
-
|
|
15750
|
-
|
|
15751
|
-
|
|
15752
|
-
|
|
15753
|
-
|
|
15754
|
-
|
|
15755
|
-
|
|
15756
|
-
|
|
15757
|
-
|
|
15758
|
-
|
|
15759
|
-
|
|
15760
|
-
|
|
15761
|
-
|
|
15762
|
-
|
|
15763
|
-
entry.relationType = ctx.relationType;
|
|
15764
|
-
}
|
|
15765
|
-
if (includeIntent?.select != null) {
|
|
15766
|
-
entry.select = includeIntent.select;
|
|
15767
|
-
}
|
|
15768
|
-
if (includeIntent?.where != null) {
|
|
15769
|
-
entry.where = includeIntent.where;
|
|
15942
|
+
function compileUpsertFrom2(intent, options, deps) {
|
|
15943
|
+
const schemaName = deps.schemaName;
|
|
15944
|
+
const sourceCte = intent.sourceQuery !== void 0 && !hasBindingName(deps.bindingNames, intent.source, deps.naming) ? compileSourceQueryCte(
|
|
15945
|
+
"compileUpsertFrom",
|
|
15946
|
+
intent.source,
|
|
15947
|
+
intent.sourceQuery,
|
|
15948
|
+
options,
|
|
15949
|
+
deps
|
|
15950
|
+
) : void 0;
|
|
15951
|
+
const bindingNames = intent.sourceQuery !== void 0 ? withBindingName(deps.bindingNames, intent.source, deps.naming) : deps.bindingNames;
|
|
15952
|
+
const ctx = {
|
|
15953
|
+
naming: deps.naming,
|
|
15954
|
+
rootTable: intent.source,
|
|
15955
|
+
...schemaName !== void 0 && { schema: schemaName },
|
|
15956
|
+
...bindingNames !== void 0 && { bindingNames },
|
|
15957
|
+
maxRecursiveDepth: 100
|
|
15958
|
+
};
|
|
15959
|
+
const state = createCompilerState();
|
|
15960
|
+
let columns;
|
|
15961
|
+
if (intent.columns) {
|
|
15962
|
+
columns = [...intent.columns];
|
|
15963
|
+
} else if (options?.model) {
|
|
15964
|
+
const targetTable = options.model.getTable(intent.table);
|
|
15965
|
+
if (targetTable) {
|
|
15966
|
+
columns = targetTable.columns.map((c) => c.name);
|
|
15770
15967
|
}
|
|
15771
|
-
subqueryIncludes.push(entry);
|
|
15772
15968
|
}
|
|
15773
|
-
|
|
15969
|
+
const config = {
|
|
15970
|
+
targetTable: intent.table,
|
|
15971
|
+
sourceTable: intent.source,
|
|
15972
|
+
conflictColumns: [...intent.conflictColumns],
|
|
15973
|
+
...columns && { columns },
|
|
15974
|
+
...intent.where && { where: [whereIntentAsDecision(intent.where)] },
|
|
15975
|
+
...intent.limit !== void 0 && { limit: intent.limit },
|
|
15976
|
+
...intent.returning && { returning: [...intent.returning] }
|
|
15977
|
+
};
|
|
15978
|
+
const ast = compileUpsertFrom(config, ctx, state);
|
|
15979
|
+
const sql = deparseQuoted(ast);
|
|
15980
|
+
return prependSourceCte(
|
|
15981
|
+
sql,
|
|
15982
|
+
state.parameters,
|
|
15983
|
+
intent.source,
|
|
15984
|
+
sourceCte,
|
|
15985
|
+
deps.naming
|
|
15986
|
+
);
|
|
15774
15987
|
}
|
|
15775
15988
|
|
|
15776
15989
|
// src/adapter-compiler-recursive.ts
|
|
@@ -16859,6 +17072,7 @@ function buildRecursiveAnchorWhere(where, tableAlias, deps, state) {
|
|
|
16859
17072
|
// src/pgsql-adapter.ts
|
|
16860
17073
|
init_assert_field();
|
|
16861
17074
|
init_ast_helpers();
|
|
17075
|
+
init_binding_registry();
|
|
16862
17076
|
|
|
16863
17077
|
// src/ddl/index-operations.ts
|
|
16864
17078
|
init_validate();
|
|
@@ -17025,9 +17239,9 @@ function compileLeafOrBranch(intent, compileFn) {
|
|
|
17025
17239
|
const result = compileFn(intent);
|
|
17026
17240
|
return { sql: result.sql, parameters: result.parameters };
|
|
17027
17241
|
}
|
|
17028
|
-
function createLeafCompileFn(adapter, model,
|
|
17242
|
+
function createLeafCompileFn(adapter, model, planFn3, options) {
|
|
17029
17243
|
return (query) => {
|
|
17030
|
-
const planReport =
|
|
17244
|
+
const planReport = planFn3(query, model, {
|
|
17031
17245
|
dialectCapabilities: adapter.dialectCapabilities
|
|
17032
17246
|
});
|
|
17033
17247
|
return adapter.compile(planReport, { ...options, model });
|
|
@@ -17149,7 +17363,7 @@ function mapFetchDirection(direction) {
|
|
|
17149
17363
|
|
|
17150
17364
|
// src/pgsql-adapter.ts
|
|
17151
17365
|
init_validate();
|
|
17152
|
-
function
|
|
17366
|
+
function renumberSqlParams2(sql, offset) {
|
|
17153
17367
|
if (offset === 0) return sql;
|
|
17154
17368
|
return sql.replace(/\$(\d+)/g, (_match, num) => {
|
|
17155
17369
|
return `$${Number.parseInt(num, 10) + offset}`;
|
|
@@ -17158,6 +17372,79 @@ function renumberSqlParams(sql, offset) {
|
|
|
17158
17372
|
function isCompiledNqlQuery(input) {
|
|
17159
17373
|
return !("intent" in input) && ("query" in input || "cteQuery" in input || "mutation" in input || "setOperation" in input || "bindings" in input || "mutationBindings" in input);
|
|
17160
17374
|
}
|
|
17375
|
+
function formatGuardPathSegment(key) {
|
|
17376
|
+
return /^[A-Za-z_$][\w$]*$/.test(key) ? `.${key}` : `[${JSON.stringify(key)}]`;
|
|
17377
|
+
}
|
|
17378
|
+
function findNqlBindingRefMarker(value, path, seen = /* @__PURE__ */ new WeakSet()) {
|
|
17379
|
+
if (value === null || typeof value !== "object") {
|
|
17380
|
+
return void 0;
|
|
17381
|
+
}
|
|
17382
|
+
if (isNqlBindingRef2(value)) {
|
|
17383
|
+
return {
|
|
17384
|
+
ref: getNqlBindingRefName2(value),
|
|
17385
|
+
path
|
|
17386
|
+
};
|
|
17387
|
+
}
|
|
17388
|
+
if (seen.has(value)) {
|
|
17389
|
+
return void 0;
|
|
17390
|
+
}
|
|
17391
|
+
seen.add(value);
|
|
17392
|
+
if (Array.isArray(value)) {
|
|
17393
|
+
for (let i = 0; i < value.length; i++) {
|
|
17394
|
+
const found = findNqlBindingRefMarker(value[i], `${path}[${i}]`, seen);
|
|
17395
|
+
if (found) return found;
|
|
17396
|
+
}
|
|
17397
|
+
return void 0;
|
|
17398
|
+
}
|
|
17399
|
+
const record = value;
|
|
17400
|
+
for (const key of Object.keys(record)) {
|
|
17401
|
+
const found = findNqlBindingRefMarker(
|
|
17402
|
+
record[key],
|
|
17403
|
+
`${path}${formatGuardPathSegment(key)}`,
|
|
17404
|
+
seen
|
|
17405
|
+
);
|
|
17406
|
+
if (found) return found;
|
|
17407
|
+
}
|
|
17408
|
+
return void 0;
|
|
17409
|
+
}
|
|
17410
|
+
function guardCompiledQuery(query, context) {
|
|
17411
|
+
const found = findNqlBindingRefMarker(query.parameters, "parameters");
|
|
17412
|
+
if (found) {
|
|
17413
|
+
throw new Error(
|
|
17414
|
+
`NQL binding reference marker '${found.ref}' survived into emitted SQL parameters at ${found.path} while compiling ${context}. Binding references must resolve to CTE subqueries before SQL emission.`
|
|
17415
|
+
);
|
|
17416
|
+
}
|
|
17417
|
+
return query;
|
|
17418
|
+
}
|
|
17419
|
+
function guardCompileResultWithIncludes(result, context) {
|
|
17420
|
+
return {
|
|
17421
|
+
...result,
|
|
17422
|
+
main: guardCompiledQuery(result.main, context)
|
|
17423
|
+
};
|
|
17424
|
+
}
|
|
17425
|
+
function findPhysicalTableNameCollision(model, bindingName, naming) {
|
|
17426
|
+
for (const [modelTableName, table] of model.tables) {
|
|
17427
|
+
if (bindingName === table.name) return table.name;
|
|
17428
|
+
if (bindingName === modelTableName) return table.name;
|
|
17429
|
+
const emittedTableName = naming.toDatabase(table.name);
|
|
17430
|
+
if (bindingName === emittedTableName) return emittedTableName;
|
|
17431
|
+
const emittedModelTableName = naming.toDatabase(modelTableName);
|
|
17432
|
+
if (bindingName === emittedModelTableName) return emittedModelTableName;
|
|
17433
|
+
}
|
|
17434
|
+
return void 0;
|
|
17435
|
+
}
|
|
17436
|
+
function findDuplicateEmittedNqlBindingName(bindingNames, naming) {
|
|
17437
|
+
const seen = /* @__PURE__ */ new Map();
|
|
17438
|
+
for (const bindingName of bindingNames) {
|
|
17439
|
+
const emittedName = emittedBindName(bindingName, naming);
|
|
17440
|
+
const originalName = seen.get(emittedName);
|
|
17441
|
+
if (originalName !== void 0 && originalName !== bindingName) {
|
|
17442
|
+
return { originalName, duplicateName: bindingName, emittedName };
|
|
17443
|
+
}
|
|
17444
|
+
seen.set(emittedName, bindingName);
|
|
17445
|
+
}
|
|
17446
|
+
return void 0;
|
|
17447
|
+
}
|
|
17161
17448
|
var PgsqlAdapter = class _PgsqlAdapter {
|
|
17162
17449
|
pool;
|
|
17163
17450
|
client;
|
|
@@ -17224,17 +17511,19 @@ var PgsqlAdapter = class _PgsqlAdapter {
|
|
|
17224
17511
|
...overrides
|
|
17225
17512
|
};
|
|
17226
17513
|
}
|
|
17227
|
-
buildCompileDeps(options) {
|
|
17514
|
+
buildCompileDeps(options, bindingNames) {
|
|
17228
17515
|
if (options?.schemaName) {
|
|
17229
17516
|
validateIdentifier(options.schemaName, "schema");
|
|
17230
17517
|
}
|
|
17518
|
+
const naming = options?.naming ?? this.naming;
|
|
17231
17519
|
return {
|
|
17232
|
-
naming
|
|
17520
|
+
naming,
|
|
17233
17521
|
// `||` (not `??`): empty string is treated as "no override" and falls back to this.schemaName (which may be a configured schema or undefined)
|
|
17234
17522
|
schemaName: options?.schemaName || this.schemaName,
|
|
17235
17523
|
model: options?.model ?? this.model,
|
|
17236
17524
|
defaultPk: this.defaultPk,
|
|
17237
|
-
deriveFk: this.deriveFk
|
|
17525
|
+
deriveFk: this.deriveFk,
|
|
17526
|
+
...bindingNames !== void 0 && { bindingNames }
|
|
17238
17527
|
};
|
|
17239
17528
|
}
|
|
17240
17529
|
requireNqlCompileModel(options) {
|
|
@@ -17246,7 +17535,24 @@ var PgsqlAdapter = class _PgsqlAdapter {
|
|
|
17246
17535
|
}
|
|
17247
17536
|
return model;
|
|
17248
17537
|
}
|
|
17249
|
-
|
|
17538
|
+
assertNqlBindingNamesDisjointFromTables(bindingNames, options) {
|
|
17539
|
+
if (bindingNames === void 0 || bindingNames.size === 0) return;
|
|
17540
|
+
const model = this.requireNqlCompileModel(options);
|
|
17541
|
+
const naming = this.buildCompileDeps(options, bindingNames).naming;
|
|
17542
|
+
for (const bindingName of bindingNames) {
|
|
17543
|
+
const physicalTableName = findPhysicalTableNameCollision(
|
|
17544
|
+
model,
|
|
17545
|
+
bindingName,
|
|
17546
|
+
naming
|
|
17547
|
+
);
|
|
17548
|
+
if (physicalTableName !== void 0) {
|
|
17549
|
+
throw new Error(
|
|
17550
|
+
`NQL binding '${bindingName}' collides with physical table name '${physicalTableName}'. NQL binding names must be disjoint from model table names.`
|
|
17551
|
+
);
|
|
17552
|
+
}
|
|
17553
|
+
}
|
|
17554
|
+
}
|
|
17555
|
+
compileNqlMutation(bundle, options, bindingNames) {
|
|
17250
17556
|
const mutation = bundle.mutation;
|
|
17251
17557
|
if (mutation === void 0) {
|
|
17252
17558
|
throw new Error("NQL bundle did not contain a mutation intent.");
|
|
@@ -17256,84 +17562,124 @@ var PgsqlAdapter = class _PgsqlAdapter {
|
|
|
17256
17562
|
return compileInsert2(
|
|
17257
17563
|
mutation,
|
|
17258
17564
|
options,
|
|
17259
|
-
this.buildCompileDeps(options)
|
|
17565
|
+
this.buildCompileDeps(options, bindingNames)
|
|
17260
17566
|
);
|
|
17261
17567
|
case "insert_from":
|
|
17262
17568
|
return compileInsertFrom2(
|
|
17263
17569
|
mutation,
|
|
17264
17570
|
options,
|
|
17265
|
-
this.buildCompileDeps(options)
|
|
17571
|
+
this.buildCompileDeps(options, bindingNames)
|
|
17266
17572
|
);
|
|
17267
17573
|
case "update":
|
|
17268
17574
|
return compileUpdate2(
|
|
17269
17575
|
mutation,
|
|
17270
17576
|
options,
|
|
17271
|
-
this.buildCompileDeps(options)
|
|
17577
|
+
this.buildCompileDeps(options, bindingNames)
|
|
17272
17578
|
);
|
|
17273
17579
|
case "delete":
|
|
17274
17580
|
return compileDelete2(
|
|
17275
17581
|
mutation,
|
|
17276
17582
|
options,
|
|
17277
|
-
this.buildCompileDeps(options)
|
|
17583
|
+
this.buildCompileDeps(options, bindingNames)
|
|
17278
17584
|
);
|
|
17279
17585
|
case "upsert":
|
|
17280
17586
|
return compileUpsert2(
|
|
17281
17587
|
mutation,
|
|
17282
17588
|
options,
|
|
17283
|
-
this.buildCompileDeps(options)
|
|
17589
|
+
this.buildCompileDeps(options, bindingNames)
|
|
17284
17590
|
);
|
|
17285
17591
|
case "upsert_from":
|
|
17286
17592
|
return compileUpsertFrom2(
|
|
17287
17593
|
mutation,
|
|
17288
17594
|
options,
|
|
17289
|
-
this.buildCompileDeps(options)
|
|
17595
|
+
this.buildCompileDeps(options, bindingNames)
|
|
17290
17596
|
);
|
|
17291
17597
|
}
|
|
17292
17598
|
throw new Error(
|
|
17293
17599
|
`Unsupported NQL mutation type: ${mutation.type}`
|
|
17294
17600
|
);
|
|
17295
17601
|
}
|
|
17296
|
-
compileNqlBundleLeaf(bundle, options) {
|
|
17602
|
+
compileNqlBundleLeaf(bundle, options, bindingNames) {
|
|
17297
17603
|
if (bundle.query !== void 0) {
|
|
17604
|
+
const naming = this.buildCompileDeps(options, bindingNames).naming;
|
|
17605
|
+
if (hasBindingName(bindingNames, bundle.query.from, naming)) {
|
|
17606
|
+
throw new Error(
|
|
17607
|
+
`NQL binding '${bundle.query.from}' cannot be used as the final FROM source yet. Use the binding from a mutation source or WHERE IN predicate, or select from a real table.`
|
|
17608
|
+
);
|
|
17609
|
+
}
|
|
17298
17610
|
const model = this.requireNqlCompileModel(options);
|
|
17299
|
-
const planReport =
|
|
17611
|
+
const planReport = planFn2(bundle.query, model, {
|
|
17300
17612
|
dialectCapabilities: this.dialectCapabilities
|
|
17301
17613
|
});
|
|
17302
|
-
return
|
|
17303
|
-
|
|
17304
|
-
|
|
17305
|
-
|
|
17614
|
+
return guardCompiledQuery(
|
|
17615
|
+
compileSelect(
|
|
17616
|
+
planReport,
|
|
17617
|
+
options,
|
|
17618
|
+
this.buildCompileDeps(options, bindingNames)
|
|
17619
|
+
),
|
|
17620
|
+
"NQL query"
|
|
17306
17621
|
);
|
|
17307
17622
|
}
|
|
17308
17623
|
if (bundle.cteQuery !== void 0) {
|
|
17309
|
-
return
|
|
17310
|
-
|
|
17311
|
-
|
|
17312
|
-
|
|
17624
|
+
return guardCompiledQuery(
|
|
17625
|
+
compileCteQuery(
|
|
17626
|
+
bundle.cteQuery,
|
|
17627
|
+
options,
|
|
17628
|
+
this.buildCompileDeps(options, bindingNames)
|
|
17629
|
+
),
|
|
17630
|
+
"NQL CTE query"
|
|
17313
17631
|
);
|
|
17314
17632
|
}
|
|
17315
17633
|
if (bundle.setOperation !== void 0) {
|
|
17316
17634
|
const model = this.requireNqlCompileModel(options);
|
|
17317
|
-
return
|
|
17318
|
-
|
|
17319
|
-
|
|
17320
|
-
|
|
17635
|
+
return guardCompiledQuery(
|
|
17636
|
+
this.compileSetOperationWithBindings(
|
|
17637
|
+
bundle.setOperation,
|
|
17638
|
+
model,
|
|
17639
|
+
options,
|
|
17640
|
+
bindingNames
|
|
17641
|
+
),
|
|
17642
|
+
"NQL set operation"
|
|
17321
17643
|
);
|
|
17322
17644
|
}
|
|
17323
17645
|
if (bundle.mutation !== void 0) {
|
|
17324
|
-
return
|
|
17646
|
+
return guardCompiledQuery(
|
|
17647
|
+
this.compileNqlMutation(
|
|
17648
|
+
bundle,
|
|
17649
|
+
options,
|
|
17650
|
+
bindingNames
|
|
17651
|
+
),
|
|
17652
|
+
"NQL mutation"
|
|
17653
|
+
);
|
|
17325
17654
|
}
|
|
17326
17655
|
throw new Error("NQL bundle did not contain a compilable intent.");
|
|
17327
17656
|
}
|
|
17328
17657
|
compileNqlBundle(bundle, options) {
|
|
17329
17658
|
const ctes = [];
|
|
17330
17659
|
const parameters = [];
|
|
17660
|
+
const naming = this.buildCompileDeps(options).naming;
|
|
17661
|
+
const duplicateEmittedBinding = bundle.bindings !== void 0 ? findDuplicateEmittedNqlBindingName(bundle.bindings.keys(), naming) : void 0;
|
|
17662
|
+
if (duplicateEmittedBinding !== void 0) {
|
|
17663
|
+
throw new Error(
|
|
17664
|
+
`NQL bindings '${duplicateEmittedBinding.originalName}' and '${duplicateEmittedBinding.duplicateName}' emit to duplicate CTE name '${duplicateEmittedBinding.emittedName}'. NQL binding names must be unique after database naming.`
|
|
17665
|
+
);
|
|
17666
|
+
}
|
|
17667
|
+
const bindingNames = bundle.bindings !== void 0 ? new Set(
|
|
17668
|
+
[...bundle.bindings.keys()].map(
|
|
17669
|
+
(name) => emittedBindName(name, naming)
|
|
17670
|
+
)
|
|
17671
|
+
) : void 0;
|
|
17672
|
+
this.assertNqlBindingNamesDisjointFromTables(bindingNames, options);
|
|
17331
17673
|
for (const [name, queryIntent] of bundle.bindings ?? []) {
|
|
17332
|
-
const cteName = quoteIdent2(name, "alias");
|
|
17674
|
+
const cteName = quoteIdent2(emittedBindName(name, naming), "alias");
|
|
17333
17675
|
const bindingBundle = bundle.mutationBindings?.has(name) ? { mutation: bundle.mutationBindings.get(name) } : { query: queryIntent };
|
|
17334
|
-
const compiled2 = this.compileNqlBundleLeaf(
|
|
17676
|
+
const compiled2 = this.compileNqlBundleLeaf(
|
|
17677
|
+
bindingBundle,
|
|
17678
|
+
options,
|
|
17679
|
+
bindingNames
|
|
17680
|
+
);
|
|
17335
17681
|
ctes.push(
|
|
17336
|
-
`${cteName} as (${
|
|
17682
|
+
`${cteName} as (${renumberSqlParams2(compiled2.sql, parameters.length)})`
|
|
17337
17683
|
);
|
|
17338
17684
|
parameters.push(...compiled2.parameters);
|
|
17339
17685
|
}
|
|
@@ -17346,14 +17692,21 @@ var PgsqlAdapter = class _PgsqlAdapter {
|
|
|
17346
17692
|
setOperation: bundle.setOperation
|
|
17347
17693
|
}
|
|
17348
17694
|
};
|
|
17349
|
-
const compiled = this.compileNqlBundleLeaf(
|
|
17695
|
+
const compiled = this.compileNqlBundleLeaf(
|
|
17696
|
+
leafBundle,
|
|
17697
|
+
options,
|
|
17698
|
+
bindingNames
|
|
17699
|
+
);
|
|
17350
17700
|
if (ctes.length === 0) {
|
|
17351
|
-
return compiled;
|
|
17701
|
+
return guardCompiledQuery(compiled, "NQL bundle");
|
|
17352
17702
|
}
|
|
17353
|
-
return
|
|
17354
|
-
|
|
17355
|
-
|
|
17356
|
-
|
|
17703
|
+
return guardCompiledQuery(
|
|
17704
|
+
{
|
|
17705
|
+
sql: `WITH ${ctes.join(", ")} ${renumberSqlParams2(compiled.sql, parameters.length)}`,
|
|
17706
|
+
parameters: [...parameters, ...compiled.parameters]
|
|
17707
|
+
},
|
|
17708
|
+
"NQL bundle"
|
|
17709
|
+
);
|
|
17357
17710
|
}
|
|
17358
17711
|
/**
|
|
17359
17712
|
* Returns the pool/client executor, or throws if in compile-only mode.
|
|
@@ -17373,7 +17726,7 @@ var PgsqlAdapter = class _PgsqlAdapter {
|
|
|
17373
17726
|
}
|
|
17374
17727
|
/** PostgreSQL dialect capabilities for planner strategy selection */
|
|
17375
17728
|
get dialectCapabilities() {
|
|
17376
|
-
return
|
|
17729
|
+
return POSTGRESQL_CAPABILITIES2;
|
|
17377
17730
|
}
|
|
17378
17731
|
/**
|
|
17379
17732
|
* DB column casing convention used by this adapter.
|
|
@@ -17397,16 +17750,18 @@ var PgsqlAdapter = class _PgsqlAdapter {
|
|
|
17397
17750
|
if (isCompiledNqlQuery(plan)) {
|
|
17398
17751
|
return this.compileNqlBundle(plan, options);
|
|
17399
17752
|
}
|
|
17400
|
-
return
|
|
17753
|
+
return guardCompiledQuery(
|
|
17754
|
+
compileSelect(plan, options, this.buildCompileDeps(options)),
|
|
17755
|
+
"select plan"
|
|
17756
|
+
);
|
|
17401
17757
|
}
|
|
17402
17758
|
/**
|
|
17403
17759
|
* Compile a plan with includes, returning subquery include metadata (DX-033).
|
|
17404
17760
|
*/
|
|
17405
17761
|
compileWithIncludes(plan, options) {
|
|
17406
|
-
return
|
|
17407
|
-
plan,
|
|
17408
|
-
|
|
17409
|
-
this.buildCompileDeps(options)
|
|
17762
|
+
return guardCompileResultWithIncludes(
|
|
17763
|
+
compileWithIncludes(plan, options, this.buildCompileDeps(options)),
|
|
17764
|
+
"select plan with includes"
|
|
17410
17765
|
);
|
|
17411
17766
|
}
|
|
17412
17767
|
/**
|
|
@@ -17419,11 +17774,14 @@ var PgsqlAdapter = class _PgsqlAdapter {
|
|
|
17419
17774
|
* @returns Compiled query for fetching related records
|
|
17420
17775
|
*/
|
|
17421
17776
|
compileSubqueryInclude(info, parentIds, options) {
|
|
17422
|
-
return
|
|
17423
|
-
|
|
17424
|
-
|
|
17425
|
-
|
|
17426
|
-
|
|
17777
|
+
return guardCompiledQuery(
|
|
17778
|
+
compileSubqueryInclude(
|
|
17779
|
+
info,
|
|
17780
|
+
parentIds,
|
|
17781
|
+
options,
|
|
17782
|
+
this.buildCompileDeps(options)
|
|
17783
|
+
),
|
|
17784
|
+
"subquery include"
|
|
17427
17785
|
);
|
|
17428
17786
|
}
|
|
17429
17787
|
/**
|
|
@@ -17467,7 +17825,10 @@ var PgsqlAdapter = class _PgsqlAdapter {
|
|
|
17467
17825
|
targetList: [{ ResTarget: { val: node } }]
|
|
17468
17826
|
});
|
|
17469
17827
|
const sql = deparseQuoted(ast);
|
|
17470
|
-
return
|
|
17828
|
+
return guardCompiledQuery(
|
|
17829
|
+
{ sql, parameters: state.parameters },
|
|
17830
|
+
"select expression"
|
|
17831
|
+
);
|
|
17471
17832
|
}
|
|
17472
17833
|
/**
|
|
17473
17834
|
* Compile an insert intent to executable SQL.
|
|
@@ -17477,24 +17838,29 @@ var PgsqlAdapter = class _PgsqlAdapter {
|
|
|
17477
17838
|
* - rows > batchThreshold OR batchThreshold === 0: SELECT unnest($1::type[]),...
|
|
17478
17839
|
*/
|
|
17479
17840
|
compileInsert(intent, options) {
|
|
17480
|
-
return
|
|
17841
|
+
return guardCompiledQuery(
|
|
17842
|
+
compileInsert2(intent, options, this.buildCompileDeps(options)),
|
|
17843
|
+
"insert"
|
|
17844
|
+
);
|
|
17481
17845
|
}
|
|
17482
17846
|
/**
|
|
17483
17847
|
* Compile an insert-from intent to executable SQL (NQL-ALIGN).
|
|
17484
17848
|
* INSERT INTO target (cols) SELECT cols FROM source WHERE ... LIMIT ... RETURNING ...
|
|
17485
17849
|
*/
|
|
17486
17850
|
compileInsertFrom(intent, options) {
|
|
17487
|
-
return
|
|
17488
|
-
intent,
|
|
17489
|
-
|
|
17490
|
-
this.buildCompileDeps(options)
|
|
17851
|
+
return guardCompiledQuery(
|
|
17852
|
+
compileInsertFrom2(intent, options, this.buildCompileDeps(options)),
|
|
17853
|
+
"insert from"
|
|
17491
17854
|
);
|
|
17492
17855
|
}
|
|
17493
17856
|
/**
|
|
17494
17857
|
* Compile an update intent to executable SQL.
|
|
17495
17858
|
*/
|
|
17496
17859
|
compileUpdate(intent, options) {
|
|
17497
|
-
return
|
|
17860
|
+
return guardCompiledQuery(
|
|
17861
|
+
compileUpdate2(intent, options, this.buildCompileDeps(options)),
|
|
17862
|
+
"update"
|
|
17863
|
+
);
|
|
17498
17864
|
}
|
|
17499
17865
|
/**
|
|
17500
17866
|
* Compile a batch update intent to executable SQL using unnest FROM strategy (BATCH-001).
|
|
@@ -17506,33 +17872,37 @@ var PgsqlAdapter = class _PgsqlAdapter {
|
|
|
17506
17872
|
* [RETURNING ...]
|
|
17507
17873
|
*/
|
|
17508
17874
|
compileBatchUpdate(intent, options) {
|
|
17509
|
-
return
|
|
17510
|
-
intent,
|
|
17511
|
-
|
|
17512
|
-
this.buildCompileDeps(options)
|
|
17875
|
+
return guardCompiledQuery(
|
|
17876
|
+
compileBatchUpdate(intent, options, this.buildCompileDeps(options)),
|
|
17877
|
+
"batch update"
|
|
17513
17878
|
);
|
|
17514
17879
|
}
|
|
17515
17880
|
/**
|
|
17516
17881
|
* Compile a delete intent to executable SQL.
|
|
17517
17882
|
*/
|
|
17518
17883
|
compileDelete(intent, options) {
|
|
17519
|
-
return
|
|
17884
|
+
return guardCompiledQuery(
|
|
17885
|
+
compileDelete2(intent, options, this.buildCompileDeps(options)),
|
|
17886
|
+
"delete"
|
|
17887
|
+
);
|
|
17520
17888
|
}
|
|
17521
17889
|
/**
|
|
17522
17890
|
* Compile an upsert intent to executable SQL (DX-026).
|
|
17523
17891
|
*/
|
|
17524
17892
|
compileUpsert(intent, options) {
|
|
17525
|
-
return
|
|
17893
|
+
return guardCompiledQuery(
|
|
17894
|
+
compileUpsert2(intent, options, this.buildCompileDeps(options)),
|
|
17895
|
+
"upsert"
|
|
17896
|
+
);
|
|
17526
17897
|
}
|
|
17527
17898
|
/**
|
|
17528
17899
|
* Compile an upsert-from intent to executable SQL (NQL-BIND).
|
|
17529
17900
|
* INSERT INTO target SELECT ... FROM source ON CONFLICT (cols) DO UPDATE SET ...
|
|
17530
17901
|
*/
|
|
17531
17902
|
compileUpsertFrom(intent, options) {
|
|
17532
|
-
return
|
|
17533
|
-
intent,
|
|
17534
|
-
|
|
17535
|
-
this.buildCompileDeps(options)
|
|
17903
|
+
return guardCompiledQuery(
|
|
17904
|
+
compileUpsertFrom2(intent, options, this.buildCompileDeps(options)),
|
|
17905
|
+
"upsert from"
|
|
17536
17906
|
);
|
|
17537
17907
|
}
|
|
17538
17908
|
/**
|
|
@@ -17540,11 +17910,14 @@ var PgsqlAdapter = class _PgsqlAdapter {
|
|
|
17540
17910
|
* Supports adjacency-list and edge-table traversal modes.
|
|
17541
17911
|
*/
|
|
17542
17912
|
compileRecursive(report, model, options) {
|
|
17543
|
-
return
|
|
17544
|
-
|
|
17545
|
-
|
|
17546
|
-
|
|
17547
|
-
|
|
17913
|
+
return guardCompiledQuery(
|
|
17914
|
+
compileRecursive(
|
|
17915
|
+
report,
|
|
17916
|
+
model,
|
|
17917
|
+
options,
|
|
17918
|
+
this.buildCompileDeps(options)
|
|
17919
|
+
),
|
|
17920
|
+
"recursive query"
|
|
17548
17921
|
);
|
|
17549
17922
|
}
|
|
17550
17923
|
/**
|
|
@@ -17555,18 +17928,42 @@ var PgsqlAdapter = class _PgsqlAdapter {
|
|
|
17555
17928
|
* to start after CTE params and prepend WITH clause.
|
|
17556
17929
|
*/
|
|
17557
17930
|
compileCteQuery(intent, options) {
|
|
17558
|
-
return
|
|
17931
|
+
return guardCompiledQuery(
|
|
17932
|
+
compileCteQuery(intent, options, this.buildCompileDeps(options)),
|
|
17933
|
+
"CTE query"
|
|
17934
|
+
);
|
|
17559
17935
|
}
|
|
17560
17936
|
/**
|
|
17561
17937
|
* Compile a set operation (UNION / INTERSECT / EXCEPT) to SQL.
|
|
17562
17938
|
*/
|
|
17563
17939
|
compileSetOperation(intent, model, options) {
|
|
17564
|
-
|
|
17940
|
+
return guardCompiledQuery(
|
|
17941
|
+
this.compileSetOperationWithBindings(intent, model, options),
|
|
17942
|
+
"set operation"
|
|
17943
|
+
);
|
|
17944
|
+
}
|
|
17945
|
+
compileSetOperationWithBindings(intent, model, options, bindingNames) {
|
|
17946
|
+
const compileFn = createLeafCompileFn(
|
|
17947
|
+
{
|
|
17948
|
+
dialectCapabilities: this.dialectCapabilities,
|
|
17949
|
+
compile: (planReport, leafOptions) => compileSelect(
|
|
17950
|
+
planReport,
|
|
17951
|
+
leafOptions,
|
|
17952
|
+
this.buildCompileDeps(leafOptions, bindingNames)
|
|
17953
|
+
)
|
|
17954
|
+
},
|
|
17955
|
+
model,
|
|
17956
|
+
planFn2,
|
|
17957
|
+
options
|
|
17958
|
+
);
|
|
17565
17959
|
const result = compileSetOperation(intent, compileFn);
|
|
17566
|
-
return
|
|
17567
|
-
|
|
17568
|
-
|
|
17569
|
-
|
|
17960
|
+
return guardCompiledQuery(
|
|
17961
|
+
{
|
|
17962
|
+
sql: result.sql,
|
|
17963
|
+
parameters: result.parameters
|
|
17964
|
+
},
|
|
17965
|
+
"set operation"
|
|
17966
|
+
);
|
|
17570
17967
|
}
|
|
17571
17968
|
/**
|
|
17572
17969
|
* Create a dump for observability.
|