@dbsp/core 1.1.0 → 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 +14 -17
- package/dist/index.js +865 -155
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -5453,6 +5453,122 @@ var LightweightModelIR = class {
|
|
|
5453
5453
|
};
|
|
5454
5454
|
|
|
5455
5455
|
// src/dx/mutation-builders.ts
|
|
5456
|
+
function compileMutationIntent(adapter, intent, options) {
|
|
5457
|
+
switch (intent.type) {
|
|
5458
|
+
case "insert":
|
|
5459
|
+
return adapter.compileInsert(intent, options);
|
|
5460
|
+
case "insert_from":
|
|
5461
|
+
return adapter.compileInsertFrom(intent, options);
|
|
5462
|
+
case "update":
|
|
5463
|
+
return adapter.compileUpdate(intent, options);
|
|
5464
|
+
case "batchUpdate":
|
|
5465
|
+
return adapter.compileBatchUpdate(intent, options);
|
|
5466
|
+
case "delete":
|
|
5467
|
+
return adapter.compileDelete(intent, options);
|
|
5468
|
+
case "upsert":
|
|
5469
|
+
return adapter.compileUpsert(intent, options);
|
|
5470
|
+
case "upsert_from":
|
|
5471
|
+
return adapter.compileUpsertFrom(intent, options);
|
|
5472
|
+
}
|
|
5473
|
+
const _exhaustive = intent;
|
|
5474
|
+
throw new Error(
|
|
5475
|
+
`Unsupported mutation type: ${_exhaustive.type}`
|
|
5476
|
+
);
|
|
5477
|
+
}
|
|
5478
|
+
async function runMutationWithHooks(opts) {
|
|
5479
|
+
if (!opts.hookStore || !hasHooks(opts.hookStore)) {
|
|
5480
|
+
const prepared = opts.prepare(opts.intent);
|
|
5481
|
+
return prepared.execute();
|
|
5482
|
+
}
|
|
5483
|
+
return withReentrancyGuard(
|
|
5484
|
+
opts.hookStore,
|
|
5485
|
+
(store) => runMutationWithHooksInner(opts, store)
|
|
5486
|
+
);
|
|
5487
|
+
}
|
|
5488
|
+
async function runMutationWithHooksInner(opts, store) {
|
|
5489
|
+
const { intent } = opts;
|
|
5490
|
+
const operation = intent.type;
|
|
5491
|
+
const startTime = Date.now();
|
|
5492
|
+
const { cardinality, data } = extractMutationIntentData(intent);
|
|
5493
|
+
let ctx = Object.freeze({
|
|
5494
|
+
table: opts.table,
|
|
5495
|
+
operation,
|
|
5496
|
+
intent,
|
|
5497
|
+
cardinality,
|
|
5498
|
+
data,
|
|
5499
|
+
...opts.schemaName !== void 0 ? { schemaName: opts.schemaName } : {},
|
|
5500
|
+
...opts.inTransaction ? { inTransaction: true } : {}
|
|
5501
|
+
});
|
|
5502
|
+
try {
|
|
5503
|
+
if (store.beforeMutation.length > 0) {
|
|
5504
|
+
ctx = await runBeforeMutationHooks(
|
|
5505
|
+
store.beforeMutation,
|
|
5506
|
+
ctx,
|
|
5507
|
+
opts.onHookError
|
|
5508
|
+
);
|
|
5509
|
+
}
|
|
5510
|
+
const prepared = opts.prepare(intent);
|
|
5511
|
+
const duration = Date.now() - startTime;
|
|
5512
|
+
const result = await prepared.execute();
|
|
5513
|
+
if (store.afterMutation.length > 0) {
|
|
5514
|
+
const afterCtx = Object.freeze({
|
|
5515
|
+
...ctx,
|
|
5516
|
+
sql: prepared.sql,
|
|
5517
|
+
parameters: prepared.parameters,
|
|
5518
|
+
duration
|
|
5519
|
+
});
|
|
5520
|
+
const transformed = await runAfterMutationHooks(
|
|
5521
|
+
store.afterMutation,
|
|
5522
|
+
afterCtx,
|
|
5523
|
+
[...prepared.getAfterMutationResult?.(result) ?? []],
|
|
5524
|
+
opts.onHookError
|
|
5525
|
+
);
|
|
5526
|
+
if (prepared.returnAfterMutationResult) {
|
|
5527
|
+
return prepared.mapAfterMutationResult?.(result, transformed) ?? transformed;
|
|
5528
|
+
}
|
|
5529
|
+
}
|
|
5530
|
+
return result;
|
|
5531
|
+
} catch (error) {
|
|
5532
|
+
if (store.onError.length > 0) {
|
|
5533
|
+
const errorCtx = {
|
|
5534
|
+
table: opts.table,
|
|
5535
|
+
operation,
|
|
5536
|
+
error,
|
|
5537
|
+
intent,
|
|
5538
|
+
phase: "beforeMutation",
|
|
5539
|
+
...opts.schemaName !== void 0 ? { schemaName: opts.schemaName } : {}
|
|
5540
|
+
};
|
|
5541
|
+
const transformed = await runOnErrorHooks(store.onError, errorCtx);
|
|
5542
|
+
throw transformed;
|
|
5543
|
+
}
|
|
5544
|
+
throw error;
|
|
5545
|
+
}
|
|
5546
|
+
}
|
|
5547
|
+
function extractMutationIntentData(intent) {
|
|
5548
|
+
if (intent.type === "insert" || intent.type === "upsert") {
|
|
5549
|
+
const values = intent.values;
|
|
5550
|
+
return {
|
|
5551
|
+
cardinality: values.length > 1 ? "bulk" : "single",
|
|
5552
|
+
data: values.length > 1 ? values : values[0]
|
|
5553
|
+
};
|
|
5554
|
+
}
|
|
5555
|
+
if (intent.type === "update") {
|
|
5556
|
+
return {
|
|
5557
|
+
cardinality: "single",
|
|
5558
|
+
data: intent.set
|
|
5559
|
+
};
|
|
5560
|
+
}
|
|
5561
|
+
if (intent.type === "batchUpdate") {
|
|
5562
|
+
return {
|
|
5563
|
+
cardinality: "bulk",
|
|
5564
|
+
data: intent.updates
|
|
5565
|
+
};
|
|
5566
|
+
}
|
|
5567
|
+
if (intent.type === "insert_from" || intent.type === "upsert_from") {
|
|
5568
|
+
return { cardinality: "bulk", data: void 0 };
|
|
5569
|
+
}
|
|
5570
|
+
return { cardinality: "single", data: void 0 };
|
|
5571
|
+
}
|
|
5456
5572
|
var MutationBuilderBase = class {
|
|
5457
5573
|
table;
|
|
5458
5574
|
model;
|
|
@@ -5507,11 +5623,15 @@ var MutationBuilderBase = class {
|
|
|
5507
5623
|
Object.keys(compileOptions).length > 0 ? compileOptions : void 0
|
|
5508
5624
|
);
|
|
5509
5625
|
const meta = {
|
|
5510
|
-
compiledAt: /* @__PURE__ */ new Date()
|
|
5626
|
+
compiledAt: /* @__PURE__ */ new Date(),
|
|
5627
|
+
...this.schemaName !== void 0 && { schema: this.schemaName },
|
|
5628
|
+
...extraOptions?.queryName !== void 0 && {
|
|
5629
|
+
queryName: extraOptions.queryName
|
|
5630
|
+
},
|
|
5631
|
+
...extraOptions?.correlationId !== void 0 && {
|
|
5632
|
+
correlationId: extraOptions.correlationId
|
|
5633
|
+
}
|
|
5511
5634
|
};
|
|
5512
|
-
if (this.schemaName !== void 0) {
|
|
5513
|
-
meta.schema = this.schemaName;
|
|
5514
|
-
}
|
|
5515
5635
|
return {
|
|
5516
5636
|
sql: compiled.sql,
|
|
5517
5637
|
parameters: compiled.parameters,
|
|
@@ -5521,129 +5641,38 @@ var MutationBuilderBase = class {
|
|
|
5521
5641
|
}
|
|
5522
5642
|
async execute() {
|
|
5523
5643
|
const adapter = this.requireAdapter(this.operationName);
|
|
5524
|
-
if (!this.hookStore || !hasHooks(this.hookStore)) {
|
|
5525
|
-
return this.executeWithoutHooks(adapter);
|
|
5526
|
-
}
|
|
5527
|
-
return this.executeWithHooks(adapter);
|
|
5528
|
-
}
|
|
5529
|
-
async executeWithoutHooks(adapter) {
|
|
5530
|
-
const intent = this.buildIntent();
|
|
5531
|
-
const compileOptions = this.schemaName ? { schemaName: this.schemaName } : void 0;
|
|
5532
|
-
const compiled = this.compileIntent(adapter, intent, compileOptions);
|
|
5533
|
-
if (this.returningColumns && this.returningColumns.length > 0) {
|
|
5534
|
-
const result = await adapter.execute(compiled);
|
|
5535
|
-
return result;
|
|
5536
|
-
}
|
|
5537
|
-
await adapter.execute(compiled);
|
|
5538
|
-
return void 0;
|
|
5539
|
-
}
|
|
5540
|
-
async executeWithHooks(adapter) {
|
|
5541
|
-
const store = this.hookStore;
|
|
5542
|
-
if (!store) throw new Error("executeWithHooks called without hookStore");
|
|
5543
|
-
return withReentrancyGuard(
|
|
5544
|
-
store,
|
|
5545
|
-
(s) => this.executeWithHooksInner(adapter, s)
|
|
5546
|
-
);
|
|
5547
|
-
}
|
|
5548
|
-
async executeWithHooksInner(adapter, store) {
|
|
5549
5644
|
const intent = this.buildIntent();
|
|
5550
|
-
|
|
5551
|
-
const startTime = Date.now();
|
|
5552
|
-
const { cardinality, data } = this.extractIntentData(intent);
|
|
5553
|
-
let ctx = Object.freeze({
|
|
5645
|
+
return runMutationWithHooks({
|
|
5554
5646
|
table: this.table,
|
|
5555
|
-
operation,
|
|
5556
5647
|
intent,
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5648
|
+
hookStore: this.hookStore,
|
|
5649
|
+
onHookError: this.onHookError,
|
|
5650
|
+
schemaName: this.schemaName,
|
|
5651
|
+
inTransaction: this.inTransaction,
|
|
5652
|
+
prepare: (preparedIntent) => this.prepareMutationExecution(adapter, preparedIntent)
|
|
5561
5653
|
});
|
|
5562
|
-
try {
|
|
5563
|
-
if (store.beforeMutation.length > 0) {
|
|
5564
|
-
ctx = await runBeforeMutationHooks(
|
|
5565
|
-
store.beforeMutation,
|
|
5566
|
-
ctx,
|
|
5567
|
-
this.onHookError
|
|
5568
|
-
);
|
|
5569
|
-
}
|
|
5570
|
-
const compileOptions = this.schemaName ? { schemaName: this.schemaName } : void 0;
|
|
5571
|
-
const compiled = this.compileIntent(adapter, intent, compileOptions);
|
|
5572
|
-
const duration = Date.now() - startTime;
|
|
5573
|
-
if (this.returningColumns && this.returningColumns.length > 0) {
|
|
5574
|
-
const result = await adapter.execute(compiled);
|
|
5575
|
-
const afterCtx = Object.freeze({
|
|
5576
|
-
...ctx,
|
|
5577
|
-
sql: compiled.sql,
|
|
5578
|
-
parameters: compiled.parameters,
|
|
5579
|
-
duration
|
|
5580
|
-
});
|
|
5581
|
-
if (store.afterMutation.length > 0) {
|
|
5582
|
-
const transformed = await runAfterMutationHooks(
|
|
5583
|
-
store.afterMutation,
|
|
5584
|
-
afterCtx,
|
|
5585
|
-
result,
|
|
5586
|
-
this.onHookError
|
|
5587
|
-
);
|
|
5588
|
-
return transformed;
|
|
5589
|
-
}
|
|
5590
|
-
return result;
|
|
5591
|
-
}
|
|
5592
|
-
await adapter.execute(compiled);
|
|
5593
|
-
if (store.afterMutation.length > 0) {
|
|
5594
|
-
const afterCtx = Object.freeze({
|
|
5595
|
-
...ctx,
|
|
5596
|
-
sql: compiled.sql,
|
|
5597
|
-
parameters: compiled.parameters,
|
|
5598
|
-
duration
|
|
5599
|
-
});
|
|
5600
|
-
await runAfterMutationHooks(
|
|
5601
|
-
store.afterMutation,
|
|
5602
|
-
afterCtx,
|
|
5603
|
-
[],
|
|
5604
|
-
this.onHookError
|
|
5605
|
-
);
|
|
5606
|
-
}
|
|
5607
|
-
return void 0;
|
|
5608
|
-
} catch (error) {
|
|
5609
|
-
if (store.onError.length > 0) {
|
|
5610
|
-
const errorCtx = {
|
|
5611
|
-
table: this.table,
|
|
5612
|
-
operation,
|
|
5613
|
-
error,
|
|
5614
|
-
intent,
|
|
5615
|
-
phase: "beforeMutation",
|
|
5616
|
-
...this.schemaName !== void 0 ? { schemaName: this.schemaName } : {}
|
|
5617
|
-
};
|
|
5618
|
-
const transformed = await runOnErrorHooks(store.onError, errorCtx);
|
|
5619
|
-
throw transformed;
|
|
5620
|
-
}
|
|
5621
|
-
throw error;
|
|
5622
|
-
}
|
|
5623
5654
|
}
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
return {
|
|
5629
|
-
cardinality: values.length > 1 ? "bulk" : "single",
|
|
5630
|
-
data: values.length > 1 ? values : values[0]
|
|
5631
|
-
};
|
|
5632
|
-
}
|
|
5633
|
-
if (intent.type === "update") {
|
|
5634
|
-
return {
|
|
5635
|
-
cardinality: "single",
|
|
5636
|
-
data: intent.set
|
|
5637
|
-
};
|
|
5638
|
-
}
|
|
5639
|
-
if (intent.type === "batchUpdate") {
|
|
5640
|
-
const updates = intent.updates;
|
|
5655
|
+
prepareMutationExecution(adapter, intent) {
|
|
5656
|
+
const compileOptions = this.schemaName ? { schemaName: this.schemaName } : void 0;
|
|
5657
|
+
const compiled = this.compileIntent(adapter, intent, compileOptions);
|
|
5658
|
+
if (this.returningColumns && this.returningColumns.length > 0) {
|
|
5641
5659
|
return {
|
|
5642
|
-
|
|
5643
|
-
|
|
5660
|
+
sql: compiled.sql,
|
|
5661
|
+
parameters: compiled.parameters,
|
|
5662
|
+
execute: () => adapter.execute(compiled),
|
|
5663
|
+
getAfterMutationResult: (result) => result,
|
|
5664
|
+
returnAfterMutationResult: true
|
|
5644
5665
|
};
|
|
5645
5666
|
}
|
|
5646
|
-
return {
|
|
5667
|
+
return {
|
|
5668
|
+
sql: compiled.sql,
|
|
5669
|
+
parameters: compiled.parameters,
|
|
5670
|
+
execute: async () => {
|
|
5671
|
+
await adapter.execute(compiled);
|
|
5672
|
+
return void 0;
|
|
5673
|
+
},
|
|
5674
|
+
getAfterMutationResult: () => []
|
|
5675
|
+
};
|
|
5647
5676
|
}
|
|
5648
5677
|
};
|
|
5649
5678
|
var InsertBuilder = class _InsertBuilder extends MutationBuilderBase {
|
|
@@ -5703,7 +5732,7 @@ var InsertBuilder = class _InsertBuilder extends MutationBuilderBase {
|
|
|
5703
5732
|
return intent;
|
|
5704
5733
|
}
|
|
5705
5734
|
compileIntent(adapter, intent, options) {
|
|
5706
|
-
return adapter
|
|
5735
|
+
return compileMutationIntent(adapter, intent, options);
|
|
5707
5736
|
}
|
|
5708
5737
|
};
|
|
5709
5738
|
var UpdateBuilder = class _UpdateBuilder extends MutationBuilderBase {
|
|
@@ -5858,10 +5887,7 @@ var UpdateBuilder = class _UpdateBuilder extends MutationBuilderBase {
|
|
|
5858
5887
|
return intent;
|
|
5859
5888
|
}
|
|
5860
5889
|
compileIntent(adapter, intent, options) {
|
|
5861
|
-
|
|
5862
|
-
return adapter.compileBatchUpdate(intent, options);
|
|
5863
|
-
}
|
|
5864
|
-
return adapter.compileUpdate(intent, options);
|
|
5890
|
+
return compileMutationIntent(adapter, intent, options);
|
|
5865
5891
|
}
|
|
5866
5892
|
};
|
|
5867
5893
|
var DeleteBuilder = class _DeleteBuilder extends MutationBuilderBase {
|
|
@@ -5948,7 +5974,7 @@ var DeleteBuilder = class _DeleteBuilder extends MutationBuilderBase {
|
|
|
5948
5974
|
return intent;
|
|
5949
5975
|
}
|
|
5950
5976
|
compileIntent(adapter, intent, options) {
|
|
5951
|
-
return adapter
|
|
5977
|
+
return compileMutationIntent(adapter, intent, options);
|
|
5952
5978
|
}
|
|
5953
5979
|
};
|
|
5954
5980
|
var UpsertBuilder = class _UpsertBuilder extends MutationBuilderBase {
|
|
@@ -6080,7 +6106,7 @@ var UpsertBuilder = class _UpsertBuilder extends MutationBuilderBase {
|
|
|
6080
6106
|
return intent;
|
|
6081
6107
|
}
|
|
6082
6108
|
compileIntent(adapter, intent, options) {
|
|
6083
|
-
return adapter
|
|
6109
|
+
return compileMutationIntent(adapter, intent, options);
|
|
6084
6110
|
}
|
|
6085
6111
|
};
|
|
6086
6112
|
|
|
@@ -6139,6 +6165,63 @@ import {
|
|
|
6139
6165
|
} from "@dbsp/nql";
|
|
6140
6166
|
import { NQL_INTERNAL_COMPILER_OPTIONS } from "@dbsp/types/internal";
|
|
6141
6167
|
var NQL_RAW_FRAGMENT = /* @__PURE__ */ Symbol("NqlRawFragment");
|
|
6168
|
+
function hasNqlBindings(bundle) {
|
|
6169
|
+
return (bundle.bindings?.size ?? 0) > 0;
|
|
6170
|
+
}
|
|
6171
|
+
function isBindingFinalQuery(bundle) {
|
|
6172
|
+
return bundle.query !== void 0 && (bundle.bindings?.has(bundle.query.from) ?? false);
|
|
6173
|
+
}
|
|
6174
|
+
function formatBindingRelationPath(path) {
|
|
6175
|
+
return typeof path === "string" ? path : path.join(".");
|
|
6176
|
+
}
|
|
6177
|
+
function findBindingFinalRelationFilter(where) {
|
|
6178
|
+
switch (where.kind) {
|
|
6179
|
+
case "and":
|
|
6180
|
+
case "or":
|
|
6181
|
+
for (const condition of where.conditions) {
|
|
6182
|
+
const found = findBindingFinalRelationFilter(condition);
|
|
6183
|
+
if (found !== void 0) return found;
|
|
6184
|
+
}
|
|
6185
|
+
return void 0;
|
|
6186
|
+
case "not":
|
|
6187
|
+
return findBindingFinalRelationFilter(where.condition);
|
|
6188
|
+
case "relationFilter":
|
|
6189
|
+
return formatBindingRelationPath(where.relation);
|
|
6190
|
+
case "exists":
|
|
6191
|
+
case "notExists":
|
|
6192
|
+
return where.relation;
|
|
6193
|
+
case "rawExists":
|
|
6194
|
+
case "rawNotExists":
|
|
6195
|
+
return "raw EXISTS";
|
|
6196
|
+
default:
|
|
6197
|
+
return void 0;
|
|
6198
|
+
}
|
|
6199
|
+
}
|
|
6200
|
+
function assertBindingFinalQueryCanUseSyntheticPlan(intent) {
|
|
6201
|
+
const relationColumns = intent.select?.type === "expressions" ? intent.select.columns.filter((column) => column.kind === "relationColumn").map((column) => column.relation) : [];
|
|
6202
|
+
const relationFilter = intent.where ? findBindingFinalRelationFilter(intent.where) : void 0;
|
|
6203
|
+
const havingRelationFilter = intent.having ? findBindingFinalRelationFilter(intent.having) : void 0;
|
|
6204
|
+
if ((intent.include?.length ?? 0) > 0 || relationColumns.length > 0 || (intent.joins?.length ?? 0) > 0 || relationFilter !== void 0 || havingRelationFilter !== void 0) {
|
|
6205
|
+
throw new Error(
|
|
6206
|
+
`NQL binding-final query '${intent.from}' cannot select relation columns, use includes, joins, or relation filters. Relation planning requires a physical model table, not a CTE binding.`
|
|
6207
|
+
);
|
|
6208
|
+
}
|
|
6209
|
+
}
|
|
6210
|
+
function createBindingFinalPlan(intent) {
|
|
6211
|
+
assertBindingFinalQueryCanUseSyntheticPlan(intent);
|
|
6212
|
+
return {
|
|
6213
|
+
rootTable: intent.from,
|
|
6214
|
+
decisions: [],
|
|
6215
|
+
warnings: [],
|
|
6216
|
+
ctes: [],
|
|
6217
|
+
intent,
|
|
6218
|
+
metadata: {
|
|
6219
|
+
planningTimeMs: 0,
|
|
6220
|
+
relationsAnalyzed: 0,
|
|
6221
|
+
isAmbiguous: false
|
|
6222
|
+
}
|
|
6223
|
+
};
|
|
6224
|
+
}
|
|
6142
6225
|
function nqlRaw(fragment) {
|
|
6143
6226
|
if (typeof fragment !== "string") {
|
|
6144
6227
|
throw new TypeError("nqlRaw() expects a string fragment");
|
|
@@ -6250,7 +6333,250 @@ function assembleNqlTemplate(strings, values) {
|
|
|
6250
6333
|
sourceError: findInternalParamSourceError(query, generatedRanges)
|
|
6251
6334
|
};
|
|
6252
6335
|
}
|
|
6253
|
-
function
|
|
6336
|
+
function hasMutationBindingBodies(bundle) {
|
|
6337
|
+
return (bundle.mutationBindings?.size ?? 0) > 0;
|
|
6338
|
+
}
|
|
6339
|
+
function requireMutationBindingColumns(bundle, bindName) {
|
|
6340
|
+
const columns = bundle.bindingOutputSchemas?.get(bindName)?.columns;
|
|
6341
|
+
if (columns === void 0 || columns.length === 0) {
|
|
6342
|
+
throw new Error(
|
|
6343
|
+
`NQL mutation binding '${bindName}' cannot be materialized because its projected column schema is unavailable.`
|
|
6344
|
+
);
|
|
6345
|
+
}
|
|
6346
|
+
return columns;
|
|
6347
|
+
}
|
|
6348
|
+
function toSnakeCaseIdentifier(identifier) {
|
|
6349
|
+
if (!identifier) return identifier;
|
|
6350
|
+
const leadingUnderscores = identifier.match(/^_+/)?.[0] ?? "";
|
|
6351
|
+
const rest = identifier.slice(leadingUnderscores.length);
|
|
6352
|
+
if (!rest) return identifier;
|
|
6353
|
+
const snakeCase = rest.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").toLowerCase();
|
|
6354
|
+
return leadingUnderscores + snakeCase;
|
|
6355
|
+
}
|
|
6356
|
+
function toDatabaseColumnName(column, dbCasing) {
|
|
6357
|
+
return dbCasing === "snake_case" ? toSnakeCaseIdentifier(column) : column;
|
|
6358
|
+
}
|
|
6359
|
+
function toRuntimeBindingRow(bindName, row, columns, dbCasing) {
|
|
6360
|
+
if (typeof row !== "object" || row === null || Array.isArray(row)) {
|
|
6361
|
+
throw new Error(
|
|
6362
|
+
`NQL mutation binding '${bindName}' returned a non-object row; runtime VALUES materialization requires object rows keyed by projected column name.`
|
|
6363
|
+
);
|
|
6364
|
+
}
|
|
6365
|
+
const source = row;
|
|
6366
|
+
const materialized = {};
|
|
6367
|
+
for (const column of columns) {
|
|
6368
|
+
const dbColumn = toDatabaseColumnName(column, dbCasing);
|
|
6369
|
+
const sourceColumn = Object.hasOwn(source, column) ? column : dbColumn !== column && Object.hasOwn(source, dbColumn) ? dbColumn : void 0;
|
|
6370
|
+
if (sourceColumn === void 0) {
|
|
6371
|
+
throw new Error(
|
|
6372
|
+
`NQL mutation binding '${bindName}' returned a row without projected column '${column}'.`
|
|
6373
|
+
);
|
|
6374
|
+
}
|
|
6375
|
+
materialized[column] = source[sourceColumn];
|
|
6376
|
+
}
|
|
6377
|
+
return materialized;
|
|
6378
|
+
}
|
|
6379
|
+
function createRuntimeBinding(bundle, bindName, rows, dbCasing) {
|
|
6380
|
+
const columns = requireMutationBindingColumns(bundle, bindName);
|
|
6381
|
+
return {
|
|
6382
|
+
columns,
|
|
6383
|
+
rows: rows.map(
|
|
6384
|
+
(row) => toRuntimeBindingRow(bindName, row, columns, dbCasing)
|
|
6385
|
+
)
|
|
6386
|
+
};
|
|
6387
|
+
}
|
|
6388
|
+
function bindingEntryIsFinal(compiledIntent, bindName, boundQuery, sourceBundle) {
|
|
6389
|
+
if (compiledIntent.kind === "query") {
|
|
6390
|
+
return boundQuery === compiledIntent.intent;
|
|
6391
|
+
}
|
|
6392
|
+
return sourceBundle.mutationBindings?.get(bindName) === compiledIntent.intent;
|
|
6393
|
+
}
|
|
6394
|
+
function orderedSequenceStepToProgramStep(step) {
|
|
6395
|
+
const dependencyStep = step;
|
|
6396
|
+
if (step.kind === "query") {
|
|
6397
|
+
return {
|
|
6398
|
+
kind: "query",
|
|
6399
|
+
intent: step.query,
|
|
6400
|
+
...step.bindName !== void 0 && { bindName: step.bindName },
|
|
6401
|
+
final: step.final,
|
|
6402
|
+
...dependencyStep.bindingDependencies !== void 0 && {
|
|
6403
|
+
bindingDependencies: dependencyStep.bindingDependencies
|
|
6404
|
+
}
|
|
6405
|
+
};
|
|
6406
|
+
}
|
|
6407
|
+
return {
|
|
6408
|
+
kind: "mutation",
|
|
6409
|
+
intent: step.mutation,
|
|
6410
|
+
...step.bindName !== void 0 && { bindName: step.bindName },
|
|
6411
|
+
final: step.final,
|
|
6412
|
+
...dependencyStep.bindingDependencies !== void 0 && {
|
|
6413
|
+
bindingDependencies: dependencyStep.bindingDependencies
|
|
6414
|
+
}
|
|
6415
|
+
};
|
|
6416
|
+
}
|
|
6417
|
+
function snapshotMutationRows(rows) {
|
|
6418
|
+
return rows.map((row) => {
|
|
6419
|
+
if (Array.isArray(row)) {
|
|
6420
|
+
return [...row];
|
|
6421
|
+
}
|
|
6422
|
+
if (row !== null && typeof row === "object") {
|
|
6423
|
+
return { ...row };
|
|
6424
|
+
}
|
|
6425
|
+
return row;
|
|
6426
|
+
});
|
|
6427
|
+
}
|
|
6428
|
+
function assertNqlProgramSteps(compiledIntent, steps) {
|
|
6429
|
+
if (steps.length === 0) {
|
|
6430
|
+
throw new Error("NQL program sequence did not contain any statements.");
|
|
6431
|
+
}
|
|
6432
|
+
const finalIndexes = steps.map((step, index) => step.final ? index : -1).filter((index) => index !== -1);
|
|
6433
|
+
if (finalIndexes.length !== 1 || finalIndexes[0] !== steps.length - 1) {
|
|
6434
|
+
throw new Error(
|
|
6435
|
+
"NQL program sequence must contain exactly one final statement at the end."
|
|
6436
|
+
);
|
|
6437
|
+
}
|
|
6438
|
+
const finalStep = steps.at(-1);
|
|
6439
|
+
if (finalStep === void 0) {
|
|
6440
|
+
throw new Error("NQL program sequence did not contain a final statement.");
|
|
6441
|
+
}
|
|
6442
|
+
if (finalStep.kind !== compiledIntent.kind || finalStep.intent !== compiledIntent.intent) {
|
|
6443
|
+
throw new Error(
|
|
6444
|
+
"NQL program sequence final statement does not match the compiled NQL result."
|
|
6445
|
+
);
|
|
6446
|
+
}
|
|
6447
|
+
const seenBindNames = /* @__PURE__ */ new Set();
|
|
6448
|
+
for (const step of steps) {
|
|
6449
|
+
if (step.bindName === void 0) continue;
|
|
6450
|
+
if (seenBindNames.has(step.bindName)) {
|
|
6451
|
+
throw new Error(
|
|
6452
|
+
`NQL program sequence contains duplicate binding '${step.bindName}'.`
|
|
6453
|
+
);
|
|
6454
|
+
}
|
|
6455
|
+
seenBindNames.add(step.bindName);
|
|
6456
|
+
if (!(compiledIntent.bundle.bindings?.has(step.bindName) ?? false)) {
|
|
6457
|
+
throw new Error(
|
|
6458
|
+
`NQL program sequence references unknown binding '${step.bindName}'.`
|
|
6459
|
+
);
|
|
6460
|
+
}
|
|
6461
|
+
}
|
|
6462
|
+
}
|
|
6463
|
+
function createNqlProgramSteps(compiledIntent) {
|
|
6464
|
+
const sourceBundle = compiledIntent.bundle;
|
|
6465
|
+
if (sourceBundle.nqlProgramSequence !== void 0) {
|
|
6466
|
+
const steps2 = sourceBundle.nqlProgramSequence.map(
|
|
6467
|
+
orderedSequenceStepToProgramStep
|
|
6468
|
+
);
|
|
6469
|
+
assertNqlProgramSteps(compiledIntent, steps2);
|
|
6470
|
+
return steps2;
|
|
6471
|
+
}
|
|
6472
|
+
const bindingEntries = [...sourceBundle.bindings ?? /* @__PURE__ */ new Map()];
|
|
6473
|
+
const steps = bindingEntries.map(
|
|
6474
|
+
([bindName, boundQuery]) => {
|
|
6475
|
+
const boundMutation = sourceBundle.mutationBindings?.get(bindName);
|
|
6476
|
+
if (boundMutation !== void 0) {
|
|
6477
|
+
return {
|
|
6478
|
+
kind: "mutation",
|
|
6479
|
+
intent: boundMutation,
|
|
6480
|
+
bindName,
|
|
6481
|
+
final: false
|
|
6482
|
+
};
|
|
6483
|
+
}
|
|
6484
|
+
return {
|
|
6485
|
+
kind: "query",
|
|
6486
|
+
intent: boundQuery,
|
|
6487
|
+
bindName,
|
|
6488
|
+
final: false
|
|
6489
|
+
};
|
|
6490
|
+
}
|
|
6491
|
+
);
|
|
6492
|
+
const lastBindingEntry = bindingEntries.at(-1);
|
|
6493
|
+
const finalIsBound = lastBindingEntry !== void 0 && bindingEntryIsFinal(
|
|
6494
|
+
compiledIntent,
|
|
6495
|
+
lastBindingEntry[0],
|
|
6496
|
+
lastBindingEntry[1],
|
|
6497
|
+
sourceBundle
|
|
6498
|
+
);
|
|
6499
|
+
if (finalIsBound) {
|
|
6500
|
+
const lastStep = steps.at(-1);
|
|
6501
|
+
if (lastStep === void 0) return steps;
|
|
6502
|
+
steps[steps.length - 1] = { ...lastStep, final: true };
|
|
6503
|
+
return steps;
|
|
6504
|
+
}
|
|
6505
|
+
if (compiledIntent.kind === "query") {
|
|
6506
|
+
steps.push({
|
|
6507
|
+
kind: "query",
|
|
6508
|
+
intent: compiledIntent.intent,
|
|
6509
|
+
final: true
|
|
6510
|
+
});
|
|
6511
|
+
} else {
|
|
6512
|
+
steps.push({
|
|
6513
|
+
kind: "mutation",
|
|
6514
|
+
intent: compiledIntent.intent,
|
|
6515
|
+
final: true
|
|
6516
|
+
});
|
|
6517
|
+
}
|
|
6518
|
+
assertNqlProgramSteps(compiledIntent, steps);
|
|
6519
|
+
return steps;
|
|
6520
|
+
}
|
|
6521
|
+
function renumberDumpSqlParams(sql2, offset) {
|
|
6522
|
+
if (offset === 0) return sql2;
|
|
6523
|
+
return sql2.replace(/\$(\d+)/g, (_match, num) => {
|
|
6524
|
+
return `$${Number.parseInt(num, 10) + offset}`;
|
|
6525
|
+
});
|
|
6526
|
+
}
|
|
6527
|
+
function joinDumpSequenceSql(sequence) {
|
|
6528
|
+
let parameterOffset = 0;
|
|
6529
|
+
return sequence.map((step) => {
|
|
6530
|
+
const sql2 = renumberDumpSqlParams(step.sql, parameterOffset);
|
|
6531
|
+
parameterOffset += step.params.length;
|
|
6532
|
+
return sql2;
|
|
6533
|
+
}).join(";\n");
|
|
6534
|
+
}
|
|
6535
|
+
function flattenDumpSequenceParams(sequence) {
|
|
6536
|
+
return sequence.flatMap((step) => [...step.params]);
|
|
6537
|
+
}
|
|
6538
|
+
function filterMapByBindingDependencies(source, bindingDependencies) {
|
|
6539
|
+
if (source === void 0) return /* @__PURE__ */ new Map();
|
|
6540
|
+
if (bindingDependencies === void 0) return new Map(source);
|
|
6541
|
+
const filtered = /* @__PURE__ */ new Map();
|
|
6542
|
+
for (const bindName of bindingDependencies) {
|
|
6543
|
+
const value = source.get(bindName);
|
|
6544
|
+
if (value !== void 0) {
|
|
6545
|
+
filtered.set(bindName, value);
|
|
6546
|
+
}
|
|
6547
|
+
}
|
|
6548
|
+
return filtered;
|
|
6549
|
+
}
|
|
6550
|
+
function filterOptionalMapByBindingDependencies(source, bindingDependencies) {
|
|
6551
|
+
const filtered = filterMapByBindingDependencies(source, bindingDependencies);
|
|
6552
|
+
return filtered.size > 0 ? filtered : void 0;
|
|
6553
|
+
}
|
|
6554
|
+
function filterMapByRuntimeBindingDependencies(source, runtimeSourceBindings, bindingDependencies) {
|
|
6555
|
+
if (source === void 0) return /* @__PURE__ */ new Map();
|
|
6556
|
+
if (bindingDependencies === void 0 || runtimeSourceBindings === void 0 || runtimeSourceBindings.size === 0) {
|
|
6557
|
+
return new Map(source);
|
|
6558
|
+
}
|
|
6559
|
+
const dependencies = new Set(bindingDependencies);
|
|
6560
|
+
const filtered = /* @__PURE__ */ new Map();
|
|
6561
|
+
for (const [bindName, value] of source) {
|
|
6562
|
+
if (!runtimeSourceBindings.has(bindName) || dependencies.has(bindName)) {
|
|
6563
|
+
filtered.set(bindName, value);
|
|
6564
|
+
}
|
|
6565
|
+
}
|
|
6566
|
+
return filtered;
|
|
6567
|
+
}
|
|
6568
|
+
function filterOptionalMapByNames(source, names) {
|
|
6569
|
+
if (source === void 0) return void 0;
|
|
6570
|
+
const filtered = /* @__PURE__ */ new Map();
|
|
6571
|
+
for (const name of names) {
|
|
6572
|
+
const value = source.get(name);
|
|
6573
|
+
if (value !== void 0) {
|
|
6574
|
+
filtered.set(name, value);
|
|
6575
|
+
}
|
|
6576
|
+
}
|
|
6577
|
+
return filtered.size > 0 ? filtered : void 0;
|
|
6578
|
+
}
|
|
6579
|
+
function createNqlTag(_schemaDefinition, model, adapter, schemaName, hookStore, onHookError, inTransaction) {
|
|
6254
6580
|
return function nql(strings, ...values) {
|
|
6255
6581
|
const assembled = assembleNqlTemplate(strings, values);
|
|
6256
6582
|
return new NqlBuilderImpl(
|
|
@@ -6258,37 +6584,42 @@ function createNqlTag(schemaDefinition, model, adapter, schemaName) {
|
|
|
6258
6584
|
assembled.params,
|
|
6259
6585
|
assembled.hasBoundParams,
|
|
6260
6586
|
assembled.sourceError,
|
|
6261
|
-
schemaDefinition,
|
|
6262
6587
|
model,
|
|
6263
6588
|
adapter,
|
|
6264
|
-
schemaName
|
|
6589
|
+
schemaName,
|
|
6590
|
+
hookStore,
|
|
6591
|
+
onHookError,
|
|
6592
|
+
inTransaction
|
|
6265
6593
|
);
|
|
6266
6594
|
};
|
|
6267
6595
|
}
|
|
6268
6596
|
var NqlBuilderImpl = class {
|
|
6269
|
-
|
|
6597
|
+
_compiled;
|
|
6270
6598
|
query;
|
|
6271
6599
|
params;
|
|
6272
6600
|
hasBoundParams;
|
|
6273
6601
|
sourceError;
|
|
6274
|
-
schemaDefinition;
|
|
6275
6602
|
model;
|
|
6276
|
-
// biome-ignore lint/correctness/noUnusedPrivateClassMembers: Reserved for future schema-scoping support
|
|
6277
6603
|
_schemaName;
|
|
6278
6604
|
adapter;
|
|
6279
|
-
|
|
6605
|
+
hookStore;
|
|
6606
|
+
onHookError;
|
|
6607
|
+
inTransaction;
|
|
6608
|
+
constructor(query, params, hasBoundParams, sourceError, model, adapter, schemaName, hookStore, onHookError, inTransaction) {
|
|
6280
6609
|
this.query = query;
|
|
6281
6610
|
this.params = params;
|
|
6282
6611
|
this.hasBoundParams = hasBoundParams;
|
|
6283
6612
|
this.sourceError = sourceError;
|
|
6284
|
-
this.schemaDefinition = schemaDefinition;
|
|
6285
6613
|
this.model = model;
|
|
6286
6614
|
this.adapter = adapter;
|
|
6287
6615
|
this._schemaName = schemaName;
|
|
6616
|
+
this.hookStore = hookStore;
|
|
6617
|
+
this.onHookError = onHookError;
|
|
6618
|
+
this.inTransaction = inTransaction;
|
|
6288
6619
|
}
|
|
6289
6620
|
compile() {
|
|
6290
|
-
if (this.
|
|
6291
|
-
return this.
|
|
6621
|
+
if (this._compiled) {
|
|
6622
|
+
return this._compiled;
|
|
6292
6623
|
}
|
|
6293
6624
|
if (this.sourceError !== void 0) {
|
|
6294
6625
|
throw new Error(`NQL compilation failed: ${this.sourceError}`);
|
|
@@ -6300,7 +6631,7 @@ var NqlBuilderImpl = class {
|
|
|
6300
6631
|
};
|
|
6301
6632
|
const result = nqlCompile(
|
|
6302
6633
|
this.query,
|
|
6303
|
-
this.
|
|
6634
|
+
this.model,
|
|
6304
6635
|
void 0,
|
|
6305
6636
|
compilerOptions
|
|
6306
6637
|
);
|
|
@@ -6309,29 +6640,63 @@ var NqlBuilderImpl = class {
|
|
|
6309
6640
|
const rawHint = this.hasBoundParams ? " If an interpolation was intended as NQL structure, wrap a trusted fragment with nqlRaw()." : "";
|
|
6310
6641
|
throw new Error(`NQL compilation failed: ${errors}${rawHint}`);
|
|
6311
6642
|
}
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
"INSERT/UPDATE/DELETE/UPSERT not yet supported via the nql`...` tagged template. Use orm.insert(table, data) / orm.update(table, set) / orm.delete(table) / orm.upsert(table, data) instead. Tracking: https://github.com/oorabona/db-semantic-planner/issues/113"
|
|
6315
|
-
);
|
|
6316
|
-
}
|
|
6317
|
-
if (!result.ast?.query) {
|
|
6643
|
+
const bundle = result.ast;
|
|
6644
|
+
if (!bundle) {
|
|
6318
6645
|
throw new Error("NQL compilation failed: no query AST produced");
|
|
6319
6646
|
}
|
|
6320
|
-
|
|
6321
|
-
|
|
6647
|
+
if (bundle.query) {
|
|
6648
|
+
this._compiled = {
|
|
6649
|
+
kind: "query",
|
|
6650
|
+
bundle,
|
|
6651
|
+
intent: bundle.query
|
|
6652
|
+
};
|
|
6653
|
+
return this._compiled;
|
|
6654
|
+
}
|
|
6655
|
+
if (bundle.mutation) {
|
|
6656
|
+
this._compiled = {
|
|
6657
|
+
kind: "mutation",
|
|
6658
|
+
bundle,
|
|
6659
|
+
intent: bundle.mutation
|
|
6660
|
+
};
|
|
6661
|
+
return this._compiled;
|
|
6662
|
+
}
|
|
6663
|
+
throw new Error("NQL compilation failed: no query AST produced");
|
|
6322
6664
|
}
|
|
6323
6665
|
toIntentIR() {
|
|
6324
|
-
return this.compile();
|
|
6666
|
+
return this.compile().intent;
|
|
6325
6667
|
}
|
|
6326
6668
|
planInternal() {
|
|
6327
|
-
const
|
|
6328
|
-
|
|
6669
|
+
const compiled = this.compile();
|
|
6670
|
+
if (compiled.kind === "mutation") {
|
|
6671
|
+
throw new Error(
|
|
6672
|
+
"NQL mutations do not have execution plans; use dump() for SQL and parameters."
|
|
6673
|
+
);
|
|
6674
|
+
}
|
|
6675
|
+
return plan(compiled.intent, this.model);
|
|
6329
6676
|
}
|
|
6330
6677
|
plan() {
|
|
6331
|
-
|
|
6678
|
+
const compiled = this.compile();
|
|
6679
|
+
if (compiled.kind === "mutation") {
|
|
6680
|
+
throw new Error(
|
|
6681
|
+
"NQL mutations do not have execution plans; use dump() for SQL and parameters."
|
|
6682
|
+
);
|
|
6683
|
+
}
|
|
6684
|
+
return isBindingFinalQuery(compiled.bundle) ? createBindingFinalPlan(compiled.intent) : this.planInternal();
|
|
6332
6685
|
}
|
|
6333
6686
|
dump(meta) {
|
|
6334
|
-
const
|
|
6687
|
+
const compiledIntent = this.compile();
|
|
6688
|
+
if (hasMutationBindingBodies(compiledIntent.bundle)) {
|
|
6689
|
+
return this.dumpNqlProgramSequence(compiledIntent, meta);
|
|
6690
|
+
}
|
|
6691
|
+
if (compiledIntent.kind === "mutation") {
|
|
6692
|
+
return this.dumpMutation(
|
|
6693
|
+
this.createFinalNqlStatementBundle(compiledIntent),
|
|
6694
|
+
compiledIntent.intent,
|
|
6695
|
+
meta
|
|
6696
|
+
);
|
|
6697
|
+
}
|
|
6698
|
+
const bindingFinalQuery = isBindingFinalQuery(compiledIntent.bundle);
|
|
6699
|
+
const planReport = bindingFinalQuery ? createBindingFinalPlan(compiledIntent.intent) : this.planInternal();
|
|
6335
6700
|
if (!this.adapter) {
|
|
6336
6701
|
return {
|
|
6337
6702
|
plan: planReport,
|
|
@@ -6340,7 +6705,8 @@ var NqlBuilderImpl = class {
|
|
|
6340
6705
|
...meta !== void 0 && { meta }
|
|
6341
6706
|
};
|
|
6342
6707
|
}
|
|
6343
|
-
const
|
|
6708
|
+
const finalBundle = this.createFinalNqlStatementBundle(compiledIntent);
|
|
6709
|
+
const compiled = bindingFinalQuery || hasNqlBindings(finalBundle) ? this.adapter.compile(finalBundle, this.nqlBundleCompileOptions()) : this.adapter.compile(planReport);
|
|
6344
6710
|
try {
|
|
6345
6711
|
return this.adapter.createDump(planReport, compiled, meta);
|
|
6346
6712
|
} catch (err) {
|
|
@@ -6368,15 +6734,342 @@ var NqlBuilderImpl = class {
|
|
|
6368
6734
|
throw err;
|
|
6369
6735
|
}
|
|
6370
6736
|
}
|
|
6371
|
-
|
|
6737
|
+
requireAdapter(operation) {
|
|
6372
6738
|
if (!this.adapter) {
|
|
6739
|
+
throw new ExecutionError({
|
|
6740
|
+
operation,
|
|
6741
|
+
reason: "Adapter not configured",
|
|
6742
|
+
fix: "Pass adapter option when creating ORM: createOrm({ model, adapter })"
|
|
6743
|
+
});
|
|
6744
|
+
}
|
|
6745
|
+
return this.adapter;
|
|
6746
|
+
}
|
|
6747
|
+
mutationCompileOptions(extraOptions) {
|
|
6748
|
+
return {
|
|
6749
|
+
model: this.model,
|
|
6750
|
+
...this._schemaName !== void 0 && { schemaName: this._schemaName },
|
|
6751
|
+
...extraOptions
|
|
6752
|
+
};
|
|
6753
|
+
}
|
|
6754
|
+
nqlBundleCompileOptions() {
|
|
6755
|
+
return {
|
|
6756
|
+
model: this.model,
|
|
6757
|
+
...this._schemaName !== void 0 && { schemaName: this._schemaName }
|
|
6758
|
+
};
|
|
6759
|
+
}
|
|
6760
|
+
createNqlStatementBundle(statement, bindings, runtimeBindings, sourceBundle, bindingDependencies) {
|
|
6761
|
+
const statementBindings = filterMapByRuntimeBindingDependencies(
|
|
6762
|
+
bindings,
|
|
6763
|
+
sourceBundle.mutationBindings,
|
|
6764
|
+
bindingDependencies
|
|
6765
|
+
);
|
|
6766
|
+
const statementRuntimeBindings = filterMapByBindingDependencies(
|
|
6767
|
+
runtimeBindings,
|
|
6768
|
+
bindingDependencies
|
|
6769
|
+
);
|
|
6770
|
+
const emittedBindingNames = /* @__PURE__ */ new Set([
|
|
6771
|
+
...statementBindings.keys(),
|
|
6772
|
+
...statementRuntimeBindings.keys()
|
|
6773
|
+
]);
|
|
6774
|
+
const statementBindingOutputSchemas = filterOptionalMapByNames(
|
|
6775
|
+
sourceBundle.bindingOutputSchemas,
|
|
6776
|
+
emittedBindingNames
|
|
6777
|
+
);
|
|
6778
|
+
const statementMutationBindings = filterOptionalMapByBindingDependencies(
|
|
6779
|
+
sourceBundle.mutationBindings,
|
|
6780
|
+
bindingDependencies
|
|
6781
|
+
);
|
|
6782
|
+
return {
|
|
6783
|
+
...statement,
|
|
6784
|
+
...statementBindings.size > 0 && { bindings: statementBindings },
|
|
6785
|
+
...statementBindingOutputSchemas !== void 0 && {
|
|
6786
|
+
bindingOutputSchemas: statementBindingOutputSchemas
|
|
6787
|
+
},
|
|
6788
|
+
...statementMutationBindings !== void 0 && {
|
|
6789
|
+
mutationBindings: statementMutationBindings
|
|
6790
|
+
},
|
|
6791
|
+
...statementRuntimeBindings.size > 0 && {
|
|
6792
|
+
runtimeBindings: statementRuntimeBindings
|
|
6793
|
+
}
|
|
6794
|
+
};
|
|
6795
|
+
}
|
|
6796
|
+
createFinalNqlStatementBundle(compiledIntent) {
|
|
6797
|
+
const finalStep = createNqlProgramSteps(compiledIntent).at(-1);
|
|
6798
|
+
if (compiledIntent.kind === "query") {
|
|
6799
|
+
return this.createNqlStatementBundle(
|
|
6800
|
+
{ query: compiledIntent.intent },
|
|
6801
|
+
compiledIntent.bundle.bindings ?? /* @__PURE__ */ new Map(),
|
|
6802
|
+
compiledIntent.bundle.runtimeBindings ?? /* @__PURE__ */ new Map(),
|
|
6803
|
+
compiledIntent.bundle,
|
|
6804
|
+
finalStep?.bindingDependencies
|
|
6805
|
+
);
|
|
6806
|
+
}
|
|
6807
|
+
return this.createNqlStatementBundle(
|
|
6808
|
+
{ mutation: compiledIntent.intent },
|
|
6809
|
+
compiledIntent.bundle.bindings ?? /* @__PURE__ */ new Map(),
|
|
6810
|
+
compiledIntent.bundle.runtimeBindings ?? /* @__PURE__ */ new Map(),
|
|
6811
|
+
compiledIntent.bundle,
|
|
6812
|
+
finalStep?.bindingDependencies
|
|
6813
|
+
);
|
|
6814
|
+
}
|
|
6815
|
+
runMutationStatement(adapter, bundle, intent, inTransaction) {
|
|
6816
|
+
const hasReturning = (intent.returning?.length ?? 0) > 0;
|
|
6817
|
+
return runMutationWithHooks({
|
|
6818
|
+
table: intent.table,
|
|
6819
|
+
intent,
|
|
6820
|
+
hookStore: this.hookStore,
|
|
6821
|
+
onHookError: this.onHookError,
|
|
6822
|
+
schemaName: this._schemaName,
|
|
6823
|
+
inTransaction,
|
|
6824
|
+
prepare: () => {
|
|
6825
|
+
const compiled = adapter.compile(
|
|
6826
|
+
bundle,
|
|
6827
|
+
this.mutationCompileOptions()
|
|
6828
|
+
);
|
|
6829
|
+
return {
|
|
6830
|
+
sql: compiled.sql,
|
|
6831
|
+
parameters: compiled.parameters,
|
|
6832
|
+
execute: async () => {
|
|
6833
|
+
const hookRows = await adapter.execute(compiled);
|
|
6834
|
+
const rawRows = snapshotMutationRows(hookRows);
|
|
6835
|
+
return {
|
|
6836
|
+
rawRows,
|
|
6837
|
+
hookRows,
|
|
6838
|
+
transformedRows: hookRows
|
|
6839
|
+
};
|
|
6840
|
+
},
|
|
6841
|
+
getAfterMutationResult: (result) => hasReturning ? result.hookRows : [],
|
|
6842
|
+
mapAfterMutationResult: (result, transformedRows) => ({
|
|
6843
|
+
rawRows: result.rawRows,
|
|
6844
|
+
hookRows: result.hookRows,
|
|
6845
|
+
transformedRows: [...transformedRows]
|
|
6846
|
+
}),
|
|
6847
|
+
returnAfterMutationResult: hasReturning
|
|
6848
|
+
};
|
|
6849
|
+
}
|
|
6850
|
+
});
|
|
6851
|
+
}
|
|
6852
|
+
async executeNqlProgramSequence(compiledIntent, adapter) {
|
|
6853
|
+
if (!supportsTransactions(adapter)) {
|
|
6854
|
+
throw new ExecutionError({
|
|
6855
|
+
operation: "nql",
|
|
6856
|
+
reason: "NQL programs with mutation bindings require adapter transaction support",
|
|
6857
|
+
fix: "Use an adapter that implements transaction(fn), such as the PostgreSQL adapter."
|
|
6858
|
+
});
|
|
6859
|
+
}
|
|
6860
|
+
return adapter.transaction(async (txAdapter) => {
|
|
6861
|
+
const sourceBundle = compiledIntent.bundle;
|
|
6862
|
+
const priorBindings = /* @__PURE__ */ new Map();
|
|
6863
|
+
const runtimeBindings = /* @__PURE__ */ new Map();
|
|
6864
|
+
const steps = createNqlProgramSteps(compiledIntent);
|
|
6865
|
+
let finalRows = [];
|
|
6866
|
+
for (const step of steps) {
|
|
6867
|
+
if (step.kind === "mutation") {
|
|
6868
|
+
if ((step.intent.returning?.length ?? 0) === 0 && step.bindName) {
|
|
6869
|
+
throw new Error(
|
|
6870
|
+
`NQL mutation binding '${step.bindName}' cannot execute without a RETURNING projection.`
|
|
6871
|
+
);
|
|
6872
|
+
}
|
|
6873
|
+
const statementBundle = this.createNqlStatementBundle(
|
|
6874
|
+
{ mutation: step.intent },
|
|
6875
|
+
priorBindings,
|
|
6876
|
+
runtimeBindings,
|
|
6877
|
+
sourceBundle,
|
|
6878
|
+
step.bindingDependencies
|
|
6879
|
+
);
|
|
6880
|
+
const rows = await this.runMutationStatement(
|
|
6881
|
+
txAdapter,
|
|
6882
|
+
statementBundle,
|
|
6883
|
+
step.intent,
|
|
6884
|
+
true
|
|
6885
|
+
);
|
|
6886
|
+
if (step.bindName) {
|
|
6887
|
+
runtimeBindings.set(
|
|
6888
|
+
step.bindName,
|
|
6889
|
+
createRuntimeBinding(
|
|
6890
|
+
sourceBundle,
|
|
6891
|
+
step.bindName,
|
|
6892
|
+
rows.rawRows,
|
|
6893
|
+
txAdapter.dbCasing
|
|
6894
|
+
)
|
|
6895
|
+
);
|
|
6896
|
+
}
|
|
6897
|
+
if (step.final) {
|
|
6898
|
+
finalRows = rows.transformedRows;
|
|
6899
|
+
}
|
|
6900
|
+
} else if (step.final) {
|
|
6901
|
+
const statementBundle = this.createNqlStatementBundle(
|
|
6902
|
+
{ query: step.intent },
|
|
6903
|
+
priorBindings,
|
|
6904
|
+
runtimeBindings,
|
|
6905
|
+
sourceBundle,
|
|
6906
|
+
step.bindingDependencies
|
|
6907
|
+
);
|
|
6908
|
+
const compiled = txAdapter.compile(
|
|
6909
|
+
statementBundle,
|
|
6910
|
+
this.nqlBundleCompileOptions()
|
|
6911
|
+
);
|
|
6912
|
+
finalRows = await txAdapter.execute(compiled);
|
|
6913
|
+
}
|
|
6914
|
+
if (step.bindName) {
|
|
6915
|
+
const boundQuery = sourceBundle.bindings?.get(step.bindName);
|
|
6916
|
+
if (boundQuery !== void 0) {
|
|
6917
|
+
priorBindings.set(step.bindName, boundQuery);
|
|
6918
|
+
}
|
|
6919
|
+
}
|
|
6920
|
+
}
|
|
6921
|
+
return finalRows;
|
|
6922
|
+
});
|
|
6923
|
+
}
|
|
6924
|
+
dumpNqlProgramSequence(compiledIntent, meta) {
|
|
6925
|
+
const adapter = this.requireAdapter("dump");
|
|
6926
|
+
const sourceBundle = compiledIntent.bundle;
|
|
6927
|
+
const priorBindings = /* @__PURE__ */ new Map();
|
|
6928
|
+
const runtimeBindings = /* @__PURE__ */ new Map();
|
|
6929
|
+
const sequence = [];
|
|
6930
|
+
const steps = createNqlProgramSteps(compiledIntent);
|
|
6931
|
+
for (const step of steps) {
|
|
6932
|
+
if (step.kind === "mutation") {
|
|
6933
|
+
const statementBundle = this.createNqlStatementBundle(
|
|
6934
|
+
{ mutation: step.intent },
|
|
6935
|
+
priorBindings,
|
|
6936
|
+
runtimeBindings,
|
|
6937
|
+
sourceBundle,
|
|
6938
|
+
step.bindingDependencies
|
|
6939
|
+
);
|
|
6940
|
+
const compiled = adapter.compile(
|
|
6941
|
+
statementBundle,
|
|
6942
|
+
this.mutationCompileOptions()
|
|
6943
|
+
);
|
|
6944
|
+
sequence.push({
|
|
6945
|
+
kind: "mutation",
|
|
6946
|
+
...step.bindName !== void 0 && { bindName: step.bindName },
|
|
6947
|
+
sql: compiled.sql,
|
|
6948
|
+
params: compiled.parameters
|
|
6949
|
+
});
|
|
6950
|
+
if (step.bindName !== void 0) {
|
|
6951
|
+
runtimeBindings.set(step.bindName, {
|
|
6952
|
+
columns: requireMutationBindingColumns(sourceBundle, step.bindName),
|
|
6953
|
+
rows: []
|
|
6954
|
+
});
|
|
6955
|
+
}
|
|
6956
|
+
} else {
|
|
6957
|
+
const statementBundle = this.createNqlStatementBundle(
|
|
6958
|
+
{ query: step.intent },
|
|
6959
|
+
priorBindings,
|
|
6960
|
+
runtimeBindings,
|
|
6961
|
+
sourceBundle,
|
|
6962
|
+
step.bindingDependencies
|
|
6963
|
+
);
|
|
6964
|
+
const compiled = adapter.compile(
|
|
6965
|
+
statementBundle,
|
|
6966
|
+
this.nqlBundleCompileOptions()
|
|
6967
|
+
);
|
|
6968
|
+
sequence.push({
|
|
6969
|
+
kind: "query",
|
|
6970
|
+
...step.bindName !== void 0 && { bindName: step.bindName },
|
|
6971
|
+
sql: compiled.sql,
|
|
6972
|
+
params: compiled.parameters
|
|
6973
|
+
});
|
|
6974
|
+
}
|
|
6975
|
+
if (step.bindName !== void 0) {
|
|
6976
|
+
const boundQuery = sourceBundle.bindings?.get(step.bindName);
|
|
6977
|
+
if (boundQuery !== void 0) {
|
|
6978
|
+
priorBindings.set(step.bindName, boundQuery);
|
|
6979
|
+
}
|
|
6980
|
+
}
|
|
6981
|
+
}
|
|
6982
|
+
const finalStep = steps.at(-1);
|
|
6983
|
+
if (finalStep?.kind === "query") {
|
|
6984
|
+
const planReport = isBindingFinalQuery(compiledIntent.bundle) ? createBindingFinalPlan(finalStep.intent) : this.planInternal();
|
|
6985
|
+
const dumpMeta2 = {
|
|
6986
|
+
compiledAt: /* @__PURE__ */ new Date(),
|
|
6987
|
+
...this._schemaName !== void 0 && { schema: this._schemaName },
|
|
6988
|
+
...meta?.queryName !== void 0 && { queryName: meta.queryName },
|
|
6989
|
+
...meta?.correlationId !== void 0 && {
|
|
6990
|
+
correlationId: meta.correlationId
|
|
6991
|
+
}
|
|
6992
|
+
};
|
|
6993
|
+
return {
|
|
6994
|
+
plan: planReport,
|
|
6995
|
+
sql: joinDumpSequenceSql(sequence),
|
|
6996
|
+
params: flattenDumpSequenceParams(sequence),
|
|
6997
|
+
meta: dumpMeta2,
|
|
6998
|
+
sequence
|
|
6999
|
+
};
|
|
7000
|
+
}
|
|
7001
|
+
if (finalStep?.kind !== "mutation") {
|
|
7002
|
+
throw new Error(
|
|
7003
|
+
"NQL program sequence did not contain a final statement."
|
|
7004
|
+
);
|
|
7005
|
+
}
|
|
7006
|
+
const dumpMeta = {
|
|
7007
|
+
compiledAt: /* @__PURE__ */ new Date(),
|
|
7008
|
+
...this._schemaName !== void 0 && { schema: this._schemaName },
|
|
7009
|
+
...meta?.queryName !== void 0 && { queryName: meta.queryName },
|
|
7010
|
+
...meta?.correlationId !== void 0 && {
|
|
7011
|
+
correlationId: meta.correlationId
|
|
7012
|
+
}
|
|
7013
|
+
};
|
|
7014
|
+
return {
|
|
7015
|
+
sql: joinDumpSequenceSql(sequence),
|
|
7016
|
+
parameters: flattenDumpSequenceParams(sequence),
|
|
7017
|
+
intent: finalStep.intent,
|
|
7018
|
+
meta: dumpMeta,
|
|
7019
|
+
sequence
|
|
7020
|
+
};
|
|
7021
|
+
}
|
|
7022
|
+
dumpMutation(bundle, intent, meta) {
|
|
7023
|
+
const adapter = this.requireAdapter("dump");
|
|
7024
|
+
const compiled = adapter.compile(bundle, this.mutationCompileOptions(meta));
|
|
7025
|
+
const dumpMeta = {
|
|
7026
|
+
compiledAt: /* @__PURE__ */ new Date(),
|
|
7027
|
+
...this._schemaName !== void 0 && { schema: this._schemaName },
|
|
7028
|
+
...meta?.queryName !== void 0 && { queryName: meta.queryName },
|
|
7029
|
+
...meta?.correlationId !== void 0 && {
|
|
7030
|
+
correlationId: meta.correlationId
|
|
7031
|
+
}
|
|
7032
|
+
};
|
|
7033
|
+
return {
|
|
7034
|
+
sql: compiled.sql,
|
|
7035
|
+
parameters: compiled.parameters,
|
|
7036
|
+
intent,
|
|
7037
|
+
meta: dumpMeta
|
|
7038
|
+
};
|
|
7039
|
+
}
|
|
7040
|
+
async all() {
|
|
7041
|
+
const adapter = this.adapter;
|
|
7042
|
+
if (!adapter) {
|
|
6373
7043
|
throw new Error(
|
|
6374
7044
|
"Cannot execute query: no adapter configured. Pass an adapter to createOrm() or use .toIntentIR() / .plan() for debugging."
|
|
6375
7045
|
);
|
|
6376
7046
|
}
|
|
7047
|
+
const compiledIntent = this.compile();
|
|
7048
|
+
if (hasMutationBindingBodies(compiledIntent.bundle)) {
|
|
7049
|
+
return this.executeNqlProgramSequence(compiledIntent, adapter);
|
|
7050
|
+
}
|
|
7051
|
+
if (compiledIntent.kind === "mutation") {
|
|
7052
|
+
return (await this.runMutationStatement(
|
|
7053
|
+
adapter,
|
|
7054
|
+
this.createFinalNqlStatementBundle(compiledIntent),
|
|
7055
|
+
compiledIntent.intent,
|
|
7056
|
+
this.inTransaction
|
|
7057
|
+
)).transformedRows;
|
|
7058
|
+
}
|
|
7059
|
+
if (isBindingFinalQuery(compiledIntent.bundle)) {
|
|
7060
|
+
const compiled2 = adapter.compile(
|
|
7061
|
+
this.createFinalNqlStatementBundle(compiledIntent),
|
|
7062
|
+
this.nqlBundleCompileOptions()
|
|
7063
|
+
);
|
|
7064
|
+
return adapter.execute(compiled2);
|
|
7065
|
+
}
|
|
6377
7066
|
const planReport = this.planInternal();
|
|
6378
|
-
const
|
|
6379
|
-
|
|
7067
|
+
const finalBundle = this.createFinalNqlStatementBundle(compiledIntent);
|
|
7068
|
+
const compiled = hasNqlBindings(finalBundle) ? adapter.compile(finalBundle, this.nqlBundleCompileOptions()) : adapter.compile(planReport);
|
|
7069
|
+
return adapter.execute(compiled);
|
|
7070
|
+
}
|
|
7071
|
+
async run() {
|
|
7072
|
+
await this.all();
|
|
6380
7073
|
}
|
|
6381
7074
|
async first() {
|
|
6382
7075
|
const rows = await this.all();
|
|
@@ -9151,7 +9844,10 @@ function createOrmInstance(model, strictMode, relationHints, adapter, schemaName
|
|
|
9151
9844
|
schemaDefinition,
|
|
9152
9845
|
model,
|
|
9153
9846
|
adapter,
|
|
9154
|
-
schemaName
|
|
9847
|
+
schemaName,
|
|
9848
|
+
hookStore,
|
|
9849
|
+
onHookError,
|
|
9850
|
+
inTransaction
|
|
9155
9851
|
);
|
|
9156
9852
|
const mutationOpts = {
|
|
9157
9853
|
model,
|
|
@@ -10271,6 +10967,8 @@ var POSTGRESQL_CAPABILITIES = {
|
|
|
10271
10967
|
supportsJsonType: true,
|
|
10272
10968
|
supportsJsonOperators: true,
|
|
10273
10969
|
// PG: ->, ->>, @>, <@, ?, #>, #>>
|
|
10970
|
+
supportsRowLevelLocks: true,
|
|
10971
|
+
supportsLockWaitPolicies: true,
|
|
10274
10972
|
supportsSchemas: true,
|
|
10275
10973
|
// Include Strategy Capabilities (CORE-006)
|
|
10276
10974
|
supportsLateralJoin: true,
|
|
@@ -10315,6 +11013,9 @@ var MYSQL_CAPABILITIES = {
|
|
|
10315
11013
|
supportsJsonType: true,
|
|
10316
11014
|
supportsJsonOperators: false,
|
|
10317
11015
|
// MySQL uses JSON_EXTRACT() functions, not operators
|
|
11016
|
+
// Coarse PostgreSQL-shaped lock flags; revisit MySQL with per-strength caps.
|
|
11017
|
+
supportsRowLevelLocks: false,
|
|
11018
|
+
supportsLockWaitPolicies: false,
|
|
10318
11019
|
supportsSchemas: true,
|
|
10319
11020
|
// MySQL uses database as schema
|
|
10320
11021
|
// Include Strategy Capabilities (CORE-006)
|
|
@@ -10345,6 +11046,8 @@ var SQLITE_CAPABILITIES = {
|
|
|
10345
11046
|
// SQLite 3.38+ (JSON1 extension)
|
|
10346
11047
|
supportsJsonOperators: false,
|
|
10347
11048
|
// SQLite uses json_extract() functions
|
|
11049
|
+
supportsRowLevelLocks: false,
|
|
11050
|
+
supportsLockWaitPolicies: false,
|
|
10348
11051
|
supportsSchemas: false,
|
|
10349
11052
|
// SQLite uses ATTACH for multiple databases
|
|
10350
11053
|
// Include Strategy Capabilities (CORE-006)
|
|
@@ -10373,6 +11076,8 @@ var DUCKDB_CAPABILITIES = {
|
|
|
10373
11076
|
supportsJsonType: true,
|
|
10374
11077
|
supportsJsonOperators: false,
|
|
10375
11078
|
// DuckDB uses json_extract() style
|
|
11079
|
+
supportsRowLevelLocks: false,
|
|
11080
|
+
supportsLockWaitPolicies: false,
|
|
10376
11081
|
supportsSchemas: true,
|
|
10377
11082
|
// Include Strategy Capabilities (CORE-006)
|
|
10378
11083
|
supportsLateralJoin: true,
|
|
@@ -10402,6 +11107,9 @@ var MSSQL_CAPABILITIES = {
|
|
|
10402
11107
|
// SQL Server 2016+
|
|
10403
11108
|
supportsJsonOperators: false,
|
|
10404
11109
|
// MSSQL uses JSON_VALUE/JSON_QUERY functions
|
|
11110
|
+
// Coarse PostgreSQL-shaped lock flags; revisit MSSQL hints with per-strength caps.
|
|
11111
|
+
supportsRowLevelLocks: false,
|
|
11112
|
+
supportsLockWaitPolicies: false,
|
|
10405
11113
|
supportsSchemas: true,
|
|
10406
11114
|
// Include Strategy Capabilities (CORE-006)
|
|
10407
11115
|
supportsLateralJoin: true,
|
|
@@ -10459,6 +11167,8 @@ function createDialectCapabilities(overrides, options) {
|
|
|
10459
11167
|
supportsRangeTypes: false,
|
|
10460
11168
|
supportsJsonType: false,
|
|
10461
11169
|
supportsJsonOperators: false,
|
|
11170
|
+
supportsRowLevelLocks: false,
|
|
11171
|
+
supportsLockWaitPolicies: false,
|
|
10462
11172
|
supportsSchemas: false,
|
|
10463
11173
|
supportsLateralJoin: false,
|
|
10464
11174
|
supportsJsonAgg: false,
|