@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.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
- const operation = intent.type;
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
- cardinality,
5558
- data,
5559
- ...this.schemaName !== void 0 ? { schemaName: this.schemaName } : {},
5560
- ...this.inTransaction ? { inTransaction: true } : {}
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
- /** Extract cardinality and data from mutation intent */
5625
- extractIntentData(intent) {
5626
- if (intent.type === "insert" || intent.type === "upsert") {
5627
- const values = intent.values;
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
- cardinality: "bulk",
5643
- data: updates
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 { cardinality: "single", data: void 0 };
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.compileInsert(intent, options);
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
- if (intent.type === "batchUpdate") {
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.compileDelete(intent, options);
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.compileUpsert(intent, options);
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 createNqlTag(schemaDefinition, model, adapter, schemaName) {
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
- _intent;
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
- constructor(query, params, hasBoundParams, sourceError, schemaDefinition, model, adapter, schemaName) {
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._intent) {
6291
- return this._intent;
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.schemaDefinition,
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
- if (result.ast?.mutation && !result.ast?.query) {
6313
- throw new Error(
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
- this._intent = result.ast.query;
6321
- return this._intent;
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 intent = this.compile();
6328
- return plan(intent, this.model);
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
- return this.planInternal();
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 planReport = this.planInternal();
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 compiled = this.adapter.compile(planReport);
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
- async all() {
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 compiled = this.adapter.compile(planReport);
6379
- return this.adapter.execute(compiled);
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,