@dbsp/core 1.5.0 → 1.7.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 +15 -10
- package/dist/index.js +240 -157
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1665,7 +1665,7 @@ function isManyToMany(rel) {
|
|
|
1665
1665
|
}
|
|
1666
1666
|
|
|
1667
1667
|
// src/planner.ts
|
|
1668
|
-
import { toColumnList } from "@dbsp/types";
|
|
1668
|
+
import { resolveJsonAggOrderKey, toColumnList } from "@dbsp/types";
|
|
1669
1669
|
|
|
1670
1670
|
// src/dx/errors.ts
|
|
1671
1671
|
var ExecutionError = class _ExecutionError extends Error {
|
|
@@ -1803,31 +1803,14 @@ function levenshteinDistance(a, b) {
|
|
|
1803
1803
|
const lastRow = matrix[b.length];
|
|
1804
1804
|
return lastRow ? lastRow[a.length] ?? 0 : 0;
|
|
1805
1805
|
}
|
|
1806
|
-
var
|
|
1807
|
-
name = "RelationNotFoundError";
|
|
1808
|
-
/**
|
|
1809
|
-
* The table where the relation was requested.
|
|
1810
|
-
*/
|
|
1806
|
+
var TableScopedError = class extends Error {
|
|
1811
1807
|
table;
|
|
1812
|
-
/**
|
|
1813
|
-
* The relation name that was requested but not found.
|
|
1814
|
-
*/
|
|
1815
1808
|
requested;
|
|
1816
|
-
/**
|
|
1817
|
-
* Available relations on this table.
|
|
1818
|
-
*/
|
|
1819
1809
|
available;
|
|
1820
|
-
/**
|
|
1821
|
-
* Suggested relation name (fuzzy match), if any.
|
|
1822
|
-
*/
|
|
1823
1810
|
suggestion;
|
|
1824
|
-
/**
|
|
1825
|
-
* Public-safe message (no schema enumeration).
|
|
1826
|
-
*/
|
|
1827
1811
|
publicMessage;
|
|
1828
|
-
constructor(opts) {
|
|
1812
|
+
constructor(opts, genericMessage) {
|
|
1829
1813
|
const suggestion = findClosestMatch(opts.requested, opts.available);
|
|
1830
|
-
const genericMessage = "Relation not found";
|
|
1831
1814
|
super(genericMessage);
|
|
1832
1815
|
this.table = opts.table;
|
|
1833
1816
|
this.requested = opts.requested;
|
|
@@ -1836,6 +1819,12 @@ var RelationNotFoundError = class _RelationNotFoundError extends Error {
|
|
|
1836
1819
|
if (suggestion !== void 0) {
|
|
1837
1820
|
this.suggestion = suggestion;
|
|
1838
1821
|
}
|
|
1822
|
+
}
|
|
1823
|
+
};
|
|
1824
|
+
var RelationNotFoundError = class _RelationNotFoundError extends TableScopedError {
|
|
1825
|
+
name = "RelationNotFoundError";
|
|
1826
|
+
constructor(opts) {
|
|
1827
|
+
super(opts, "Relation not found");
|
|
1839
1828
|
Object.setPrototypeOf(this, _RelationNotFoundError.prototype);
|
|
1840
1829
|
}
|
|
1841
1830
|
};
|
|
@@ -1923,39 +1912,10 @@ var TableNotFoundError = class _TableNotFoundError extends Error {
|
|
|
1923
1912
|
Object.setPrototypeOf(this, _TableNotFoundError.prototype);
|
|
1924
1913
|
}
|
|
1925
1914
|
};
|
|
1926
|
-
var ColumnNotFoundError = class _ColumnNotFoundError extends
|
|
1915
|
+
var ColumnNotFoundError = class _ColumnNotFoundError extends TableScopedError {
|
|
1927
1916
|
name = "ColumnNotFoundError";
|
|
1928
|
-
/**
|
|
1929
|
-
* The table where the column was requested.
|
|
1930
|
-
*/
|
|
1931
|
-
table;
|
|
1932
|
-
/**
|
|
1933
|
-
* The column name that was requested but not found.
|
|
1934
|
-
*/
|
|
1935
|
-
requested;
|
|
1936
|
-
/**
|
|
1937
|
-
* Available columns on this table.
|
|
1938
|
-
*/
|
|
1939
|
-
available;
|
|
1940
|
-
/**
|
|
1941
|
-
* Suggested column name (fuzzy match), if any.
|
|
1942
|
-
*/
|
|
1943
|
-
suggestion;
|
|
1944
|
-
/**
|
|
1945
|
-
* Public-safe message (no schema enumeration).
|
|
1946
|
-
*/
|
|
1947
|
-
publicMessage;
|
|
1948
1917
|
constructor(opts) {
|
|
1949
|
-
|
|
1950
|
-
const genericMessage = "Column not found";
|
|
1951
|
-
super(genericMessage);
|
|
1952
|
-
this.table = opts.table;
|
|
1953
|
-
this.requested = opts.requested;
|
|
1954
|
-
this.available = opts.available;
|
|
1955
|
-
this.publicMessage = genericMessage;
|
|
1956
|
-
if (suggestion !== void 0) {
|
|
1957
|
-
this.suggestion = suggestion;
|
|
1958
|
-
}
|
|
1918
|
+
super(opts, "Column not found");
|
|
1959
1919
|
Object.setPrototypeOf(this, _ColumnNotFoundError.prototype);
|
|
1960
1920
|
}
|
|
1961
1921
|
};
|
|
@@ -2410,12 +2370,6 @@ function isSubquerySelectedColumnNonNullable(existsIntent, sourceTable, model) {
|
|
|
2410
2370
|
if (!column) return false;
|
|
2411
2371
|
return !column.nullable;
|
|
2412
2372
|
}
|
|
2413
|
-
function resolveTargetJsonAggOrderKey(model, targetTable) {
|
|
2414
|
-
const table = model.getTable(targetTable);
|
|
2415
|
-
if (!table) return { columns: [], fallback: false };
|
|
2416
|
-
const pkColumns = toColumnList(table.primaryKey);
|
|
2417
|
-
return pkColumns.length > 0 ? { columns: pkColumns, fallback: false } : { columns: table.columns.map((col2) => col2.name), fallback: true };
|
|
2418
|
-
}
|
|
2419
2373
|
function optimizeInToExists(where, sourceTable, model, negated = false) {
|
|
2420
2374
|
switch (where.kind) {
|
|
2421
2375
|
case "in": {
|
|
@@ -2744,7 +2698,8 @@ function processInclude(include, sourceTable, model, state, opts, intentPath, de
|
|
|
2744
2698
|
const explicitJoinType = includeStrategy === "join" ? include.join ?? cascadedJoinType : void 0;
|
|
2745
2699
|
const includeDecisionId = generateDecisionId(state, "include-strategy");
|
|
2746
2700
|
const parentKey = relation.type === "belongsTo" ? relation.targetKey : relation.sourceKey;
|
|
2747
|
-
const
|
|
2701
|
+
const targetTable = model.getTable(relation.target);
|
|
2702
|
+
const targetOrder = targetTable ? resolveJsonAggOrderKey(targetTable) : void 0;
|
|
2748
2703
|
state.decisions.push({
|
|
2749
2704
|
id: includeDecisionId,
|
|
2750
2705
|
type: "include-strategy",
|
|
@@ -2760,10 +2715,10 @@ function processInclude(include, sourceTable, model, state, opts, intentPath, de
|
|
|
2760
2715
|
foreignKey: relation.foreignKey
|
|
2761
2716
|
},
|
|
2762
2717
|
...parentKey !== void 0 && { parentKey },
|
|
2763
|
-
...targetOrder.columns.length > 0 && {
|
|
2764
|
-
|
|
2718
|
+
...targetOrder && targetOrder.columns.length > 0 && {
|
|
2719
|
+
targetOrderKey: targetOrder.columns
|
|
2765
2720
|
},
|
|
2766
|
-
...targetOrder
|
|
2721
|
+
...targetOrder?.fallback && { orderByFallback: true }
|
|
2767
2722
|
},
|
|
2768
2723
|
choice: includeStrategy,
|
|
2769
2724
|
// Embed joinType so the adapter's join handler can use it directly
|
|
@@ -4616,6 +4571,32 @@ function createHookManager() {
|
|
|
4616
4571
|
return new HookManagerImpl();
|
|
4617
4572
|
}
|
|
4618
4573
|
|
|
4574
|
+
// src/dx/include-hints.ts
|
|
4575
|
+
function applyHintToIncludeRecursive(inc, relationHints) {
|
|
4576
|
+
if (inc.via !== void 0) {
|
|
4577
|
+
if (inc.include && inc.include.length > 0) {
|
|
4578
|
+
return {
|
|
4579
|
+
...inc,
|
|
4580
|
+
include: inc.include.map(
|
|
4581
|
+
(nested) => applyHintToIncludeRecursive(nested, relationHints)
|
|
4582
|
+
)
|
|
4583
|
+
};
|
|
4584
|
+
}
|
|
4585
|
+
return inc;
|
|
4586
|
+
}
|
|
4587
|
+
const hint = relationHints[inc.relation];
|
|
4588
|
+
const result = hint ? { ...inc, via: hint } : inc;
|
|
4589
|
+
if (result.include && result.include.length > 0) {
|
|
4590
|
+
return {
|
|
4591
|
+
...result,
|
|
4592
|
+
include: result.include.map(
|
|
4593
|
+
(nested) => applyHintToIncludeRecursive(nested, relationHints)
|
|
4594
|
+
)
|
|
4595
|
+
};
|
|
4596
|
+
}
|
|
4597
|
+
return result;
|
|
4598
|
+
}
|
|
4599
|
+
|
|
4619
4600
|
// src/dx/subquery-builder.ts
|
|
4620
4601
|
var SubqueryBuilder = class _SubqueryBuilder {
|
|
4621
4602
|
_from;
|
|
@@ -5263,38 +5244,13 @@ var IntentBuilder = class _IntentBuilder {
|
|
|
5263
5244
|
return intent;
|
|
5264
5245
|
}
|
|
5265
5246
|
const updatedIncludes = intent.include.map(
|
|
5266
|
-
(inc) => this.
|
|
5247
|
+
(inc) => applyHintToIncludeRecursive(inc, this.relationHints)
|
|
5267
5248
|
);
|
|
5268
5249
|
return {
|
|
5269
5250
|
...intent,
|
|
5270
5251
|
include: updatedIncludes
|
|
5271
5252
|
};
|
|
5272
5253
|
}
|
|
5273
|
-
/**
|
|
5274
|
-
* Apply relation hint to a single include (recursively).
|
|
5275
|
-
*/
|
|
5276
|
-
applyHintToInclude(inc) {
|
|
5277
|
-
if (inc.via !== void 0) {
|
|
5278
|
-
if (inc.include && inc.include.length > 0) {
|
|
5279
|
-
return {
|
|
5280
|
-
...inc,
|
|
5281
|
-
include: inc.include.map((nested) => this.applyHintToInclude(nested))
|
|
5282
|
-
};
|
|
5283
|
-
}
|
|
5284
|
-
return inc;
|
|
5285
|
-
}
|
|
5286
|
-
const hint = this.relationHints[inc.relation];
|
|
5287
|
-
const result = hint ? { ...inc, via: hint } : inc;
|
|
5288
|
-
if (result.include && result.include.length > 0) {
|
|
5289
|
-
return {
|
|
5290
|
-
...result,
|
|
5291
|
-
include: result.include.map(
|
|
5292
|
-
(nested) => this.applyHintToInclude(nested)
|
|
5293
|
-
)
|
|
5294
|
-
};
|
|
5295
|
-
}
|
|
5296
|
-
return result;
|
|
5297
|
-
}
|
|
5298
5254
|
/**
|
|
5299
5255
|
* Clone the current state for immutable builder pattern.
|
|
5300
5256
|
*/
|
|
@@ -6257,7 +6213,7 @@ import {
|
|
|
6257
6213
|
NqlLexer,
|
|
6258
6214
|
compile as nqlCompile
|
|
6259
6215
|
} from "@dbsp/nql";
|
|
6260
|
-
import {
|
|
6216
|
+
import { resolveJsonAggOrderKey as resolveJsonAggOrderKey2 } from "@dbsp/types";
|
|
6261
6217
|
import {
|
|
6262
6218
|
explainUnsupportedNqlBindingIncludeHop,
|
|
6263
6219
|
getTrustedNqlRelationFilterFields,
|
|
@@ -6411,7 +6367,11 @@ function virtualRelationIncludeShape(relation) {
|
|
|
6411
6367
|
type: relationType,
|
|
6412
6368
|
foreignKey,
|
|
6413
6369
|
source: relation.sourceTable,
|
|
6414
|
-
target: relation.targetTable
|
|
6370
|
+
target: relation.targetTable,
|
|
6371
|
+
...relation.through !== void 0 && { through: relation.through },
|
|
6372
|
+
...relation.throughTargetColumn !== void 0 && {
|
|
6373
|
+
otherKey: relation.throughTargetColumn
|
|
6374
|
+
}
|
|
6415
6375
|
};
|
|
6416
6376
|
}
|
|
6417
6377
|
var BINDING_INCLUDE_NODE_ONLY_RELATION = {
|
|
@@ -6457,7 +6417,8 @@ function trustedBindingRelationColumnIsAdmitted(column) {
|
|
|
6457
6417
|
if (trusted.cardinality === "one") {
|
|
6458
6418
|
return !isDotted || trusted.hops.length > 0;
|
|
6459
6419
|
}
|
|
6460
|
-
|
|
6420
|
+
const hasCompleteManyToManyProof = (trusted.relationType === "manyToMany" || trusted.relationType === "belongsToMany") && trusted.through !== void 0 && trusted.throughSourceColumn !== void 0 && trusted.throughTargetColumn !== void 0;
|
|
6421
|
+
return trusted.cardinality === "many" && (trusted.relationType === "hasMany" || hasCompleteManyToManyProof) && !isDotted && trusted.hops.length === 0;
|
|
6461
6422
|
}
|
|
6462
6423
|
function assertProvenBindingInclude(bindingName, include, provenRelations) {
|
|
6463
6424
|
const proven = provenRelations.get(include.relation);
|
|
@@ -6519,7 +6480,8 @@ function createBindingIncludeDecision(intent, include, relation, index, model) {
|
|
|
6519
6480
|
const relationType = relation.relationType;
|
|
6520
6481
|
const foreignKey = relationType === "belongsTo" ? relation.sourceColumn : relation.targetColumn;
|
|
6521
6482
|
const parentKey = relationType === "belongsTo" ? relation.targetColumn : relation.sourceColumn;
|
|
6522
|
-
const
|
|
6483
|
+
const targetTable = model.getTable(relation.targetTable);
|
|
6484
|
+
const targetOrder = targetTable ? resolveJsonAggOrderKey2(targetTable) : void 0;
|
|
6523
6485
|
return {
|
|
6524
6486
|
id: `binding-include-${index}`,
|
|
6525
6487
|
type: "include-strategy",
|
|
@@ -6530,10 +6492,10 @@ function createBindingIncludeDecision(intent, include, relation, index, model) {
|
|
|
6530
6492
|
relationType,
|
|
6531
6493
|
foreignKey,
|
|
6532
6494
|
parentKey,
|
|
6533
|
-
...targetOrder.columns.length > 0 && {
|
|
6534
|
-
|
|
6495
|
+
...targetOrder && targetOrder.columns.length > 0 && {
|
|
6496
|
+
targetOrderKey: targetOrder.columns
|
|
6535
6497
|
},
|
|
6536
|
-
...targetOrder
|
|
6498
|
+
...targetOrder?.fallback && { orderByFallback: true },
|
|
6537
6499
|
includeAlias: include.relation,
|
|
6538
6500
|
intentPath: `include[${index}]`
|
|
6539
6501
|
},
|
|
@@ -6549,12 +6511,6 @@ function parentKeyForRelation(relation) {
|
|
|
6549
6511
|
if (relation.type === "belongsTo") return relation.targetKey;
|
|
6550
6512
|
return relation.sourceKey;
|
|
6551
6513
|
}
|
|
6552
|
-
function resolveTargetJsonAggOrderKey2(model, targetTable) {
|
|
6553
|
-
const table = model.getTable(targetTable);
|
|
6554
|
-
if (!table) return { columns: [], fallback: false };
|
|
6555
|
-
const pkColumns = toColumnList2(table.primaryKey);
|
|
6556
|
-
return pkColumns.length > 0 ? { columns: pkColumns, fallback: false } : { columns: table.columns.map((col2) => col2.name), fallback: true };
|
|
6557
|
-
}
|
|
6558
6514
|
function assertSupportedBindingIncludeHop(bindingName, rootIncludeRelation, relationName, relation, include, reasonPrefix = "") {
|
|
6559
6515
|
const unsupportedReason = explainUnsupportedNqlBindingIncludeHop(
|
|
6560
6516
|
relationName,
|
|
@@ -6653,10 +6609,11 @@ function createBindingTailIncludeDecisions(bindingName, include, firstHopRelatio
|
|
|
6653
6609
|
const baseContext = { ...decision.context };
|
|
6654
6610
|
delete baseContext.foreignKey;
|
|
6655
6611
|
delete baseContext.parentKey;
|
|
6656
|
-
delete baseContext.
|
|
6612
|
+
delete baseContext.targetOrderKey;
|
|
6657
6613
|
delete baseContext.orderByFallback;
|
|
6658
6614
|
const parentKey = parentKeyForRelation(relation);
|
|
6659
|
-
const
|
|
6615
|
+
const targetTable = model.getTable(relation.target);
|
|
6616
|
+
const targetOrder = targetTable ? resolveJsonAggOrderKey2(targetTable) : void 0;
|
|
6660
6617
|
return {
|
|
6661
6618
|
...decision,
|
|
6662
6619
|
id: `binding-include-${includeIndex}-tail-${tailIndex}`,
|
|
@@ -6674,10 +6631,10 @@ function createBindingTailIncludeDecisions(bindingName, include, firstHopRelatio
|
|
|
6674
6631
|
// Leave parentKey absent when RelationIR does not specify it so the
|
|
6675
6632
|
// adapter applies the same defaultPkColumnName fallback as real-table includes.
|
|
6676
6633
|
...parentKey !== void 0 && { parentKey },
|
|
6677
|
-
...targetOrder.columns.length > 0 && {
|
|
6678
|
-
|
|
6634
|
+
...targetOrder && targetOrder.columns.length > 0 && {
|
|
6635
|
+
targetOrderKey: targetOrder.columns
|
|
6679
6636
|
},
|
|
6680
|
-
...targetOrder
|
|
6637
|
+
...targetOrder?.fallback && { orderByFallback: true },
|
|
6681
6638
|
intentPath: rebaseBindingTailIntentPath(
|
|
6682
6639
|
decision.context.intentPath,
|
|
6683
6640
|
includeIndex
|
|
@@ -6698,6 +6655,13 @@ function createBindingFinalPlan(intent, bundle, model, dialectCapabilities) {
|
|
|
6698
6655
|
);
|
|
6699
6656
|
}
|
|
6700
6657
|
const proven = provenIncludes.get(include.relation);
|
|
6658
|
+
if (!proven) {
|
|
6659
|
+
throw bindingFinalIncludeError(
|
|
6660
|
+
intent.from,
|
|
6661
|
+
include.relation,
|
|
6662
|
+
"include relation proof was not emitted by the binding compiler"
|
|
6663
|
+
);
|
|
6664
|
+
}
|
|
6701
6665
|
const firstHopDecision = createBindingIncludeDecision(
|
|
6702
6666
|
intent,
|
|
6703
6667
|
include,
|
|
@@ -6848,6 +6812,14 @@ function assembleNqlTemplate(strings, values) {
|
|
|
6848
6812
|
function hasMutationBindingBodies(bundle) {
|
|
6849
6813
|
return (bundle.mutationBindings?.size ?? 0) > 0;
|
|
6850
6814
|
}
|
|
6815
|
+
function hasSnapshotReadBindingSteps(bundle) {
|
|
6816
|
+
return bundle.nqlProgramSequence?.some(
|
|
6817
|
+
(step) => step.kind === "query" && step.snapshot === true
|
|
6818
|
+
) ?? false;
|
|
6819
|
+
}
|
|
6820
|
+
function hasExecutableNqlProgramSequence(bundle) {
|
|
6821
|
+
return hasMutationBindingBodies(bundle) || hasSnapshotReadBindingSteps(bundle);
|
|
6822
|
+
}
|
|
6851
6823
|
function requireMutationBindingColumns(bundle, bindName) {
|
|
6852
6824
|
const columns = bundle.bindingOutputSchemas?.get(bindName)?.columns;
|
|
6853
6825
|
if (columns === void 0 || columns.length === 0) {
|
|
@@ -6890,11 +6862,13 @@ function toRuntimeBindingRow(bindName, row, columns, dbCasing) {
|
|
|
6890
6862
|
}
|
|
6891
6863
|
function createRuntimeBinding(bundle, bindName, rows, dbCasing) {
|
|
6892
6864
|
const columns = requireMutationBindingColumns(bundle, bindName);
|
|
6865
|
+
const columnTypes = bundle.bindingOutputSchemas?.get(bindName)?.columnTypes;
|
|
6893
6866
|
return {
|
|
6894
6867
|
columns,
|
|
6895
6868
|
rows: rows.map(
|
|
6896
6869
|
(row) => toRuntimeBindingRow(bindName, row, columns, dbCasing)
|
|
6897
|
-
)
|
|
6870
|
+
),
|
|
6871
|
+
...columnTypes !== void 0 && { columnTypes }
|
|
6898
6872
|
};
|
|
6899
6873
|
}
|
|
6900
6874
|
function bindingEntryIsFinal(compiledIntent, bindName, boundQuery, sourceBundle) {
|
|
@@ -6911,6 +6885,7 @@ function orderedSequenceStepToProgramStep(step) {
|
|
|
6911
6885
|
intent: step.query,
|
|
6912
6886
|
...step.bindName !== void 0 && { bindName: step.bindName },
|
|
6913
6887
|
final: step.final,
|
|
6888
|
+
...step.snapshot === true && { snapshot: true },
|
|
6914
6889
|
...dependencyStep.bindingDependencies !== void 0 && {
|
|
6915
6890
|
bindingDependencies: dependencyStep.bindingDependencies
|
|
6916
6891
|
}
|
|
@@ -6926,15 +6901,32 @@ function orderedSequenceStepToProgramStep(step) {
|
|
|
6926
6901
|
}
|
|
6927
6902
|
};
|
|
6928
6903
|
}
|
|
6904
|
+
var structuredCloneFn = globalThis.structuredClone;
|
|
6905
|
+
function hasCustomSnapshotPrototype(value) {
|
|
6906
|
+
if (value === null || typeof value !== "object") return false;
|
|
6907
|
+
const prototype = Object.getPrototypeOf(value);
|
|
6908
|
+
return prototype !== Object.prototype && prototype !== null && prototype !== Array.prototype && prototype !== Date.prototype && prototype !== Map.prototype && prototype !== Set.prototype;
|
|
6909
|
+
}
|
|
6910
|
+
function cloneMutationSnapshotColumnValue(value) {
|
|
6911
|
+
if (hasCustomSnapshotPrototype(value) || structuredCloneFn === void 0) {
|
|
6912
|
+
return value;
|
|
6913
|
+
}
|
|
6914
|
+
try {
|
|
6915
|
+
return structuredCloneFn(value);
|
|
6916
|
+
} catch {
|
|
6917
|
+
return value;
|
|
6918
|
+
}
|
|
6919
|
+
}
|
|
6929
6920
|
function snapshotMutationRows(rows) {
|
|
6930
6921
|
return rows.map((row) => {
|
|
6931
|
-
if (
|
|
6932
|
-
return
|
|
6922
|
+
if (row === null || typeof row !== "object") {
|
|
6923
|
+
return cloneMutationSnapshotColumnValue(row);
|
|
6933
6924
|
}
|
|
6934
|
-
|
|
6935
|
-
|
|
6925
|
+
const snapshot = { ...row };
|
|
6926
|
+
for (const key of Reflect.ownKeys(snapshot)) {
|
|
6927
|
+
snapshot[key] = cloneMutationSnapshotColumnValue(snapshot[key]);
|
|
6936
6928
|
}
|
|
6937
|
-
return
|
|
6929
|
+
return snapshot;
|
|
6938
6930
|
});
|
|
6939
6931
|
}
|
|
6940
6932
|
function assertNqlProgramSteps(compiledIntent, steps) {
|
|
@@ -6958,6 +6950,13 @@ function assertNqlProgramSteps(compiledIntent, steps) {
|
|
|
6958
6950
|
}
|
|
6959
6951
|
const seenBindNames = /* @__PURE__ */ new Set();
|
|
6960
6952
|
for (const step of steps) {
|
|
6953
|
+
if (step.kind === "query" && step.snapshot === true) {
|
|
6954
|
+
if (step.bindName === void 0 || step.final) {
|
|
6955
|
+
throw new Error(
|
|
6956
|
+
"NQL program sequence query snapshots must be named non-final statements."
|
|
6957
|
+
);
|
|
6958
|
+
}
|
|
6959
|
+
}
|
|
6961
6960
|
if (step.bindName === void 0) continue;
|
|
6962
6961
|
if (seenBindNames.has(step.bindName)) {
|
|
6963
6962
|
throw new Error(
|
|
@@ -7063,6 +7062,18 @@ function filterOptionalMapByBindingDependencies(source, bindingDependencies) {
|
|
|
7063
7062
|
const filtered = filterMapByBindingDependencies(source, bindingDependencies);
|
|
7064
7063
|
return filtered.size > 0 ? filtered : void 0;
|
|
7065
7064
|
}
|
|
7065
|
+
function runtimeSourceBindingNames(sourceBundle) {
|
|
7066
|
+
const names = /* @__PURE__ */ new Set();
|
|
7067
|
+
for (const name of sourceBundle.mutationBindings?.keys() ?? []) {
|
|
7068
|
+
names.add(name);
|
|
7069
|
+
}
|
|
7070
|
+
for (const step of sourceBundle.nqlProgramSequence ?? []) {
|
|
7071
|
+
if (step.kind === "query" && step.snapshot === true && step.bindName !== void 0) {
|
|
7072
|
+
names.add(step.bindName);
|
|
7073
|
+
}
|
|
7074
|
+
}
|
|
7075
|
+
return names.size > 0 ? names : void 0;
|
|
7076
|
+
}
|
|
7066
7077
|
function filterMapByRuntimeBindingDependencies(source, runtimeSourceBindings, bindingDependencies) {
|
|
7067
7078
|
if (source === void 0) return /* @__PURE__ */ new Map();
|
|
7068
7079
|
if (bindingDependencies === void 0 || runtimeSourceBindings === void 0 || runtimeSourceBindings.size === 0) {
|
|
@@ -7202,7 +7213,7 @@ var NqlBuilderImpl = class {
|
|
|
7202
7213
|
}
|
|
7203
7214
|
dump(meta) {
|
|
7204
7215
|
const compiledIntent = this.compile();
|
|
7205
|
-
if (
|
|
7216
|
+
if (hasExecutableNqlProgramSequence(compiledIntent.bundle)) {
|
|
7206
7217
|
return this.dumpNqlProgramSequence(compiledIntent, meta);
|
|
7207
7218
|
}
|
|
7208
7219
|
if (compiledIntent.kind === "mutation") {
|
|
@@ -7285,7 +7296,7 @@ var NqlBuilderImpl = class {
|
|
|
7285
7296
|
createNqlStatementBundle(statement, bindings, runtimeBindings, sourceBundle, bindingDependencies, planReport) {
|
|
7286
7297
|
const statementBindings = filterMapByRuntimeBindingDependencies(
|
|
7287
7298
|
bindings,
|
|
7288
|
-
sourceBundle
|
|
7299
|
+
runtimeSourceBindingNames(sourceBundle),
|
|
7289
7300
|
bindingDependencies
|
|
7290
7301
|
);
|
|
7291
7302
|
const statementRuntimeBindings = filterMapByBindingDependencies(
|
|
@@ -7425,6 +7436,28 @@ var NqlBuilderImpl = class {
|
|
|
7425
7436
|
if (step.final) {
|
|
7426
7437
|
finalRows = rows.transformedRows;
|
|
7427
7438
|
}
|
|
7439
|
+
} else if (step.snapshot === true && step.bindName !== void 0) {
|
|
7440
|
+
const statementBundle = this.createNqlStatementBundle(
|
|
7441
|
+
{ query: step.intent },
|
|
7442
|
+
priorBindings,
|
|
7443
|
+
runtimeBindings,
|
|
7444
|
+
sourceBundle,
|
|
7445
|
+
step.bindingDependencies
|
|
7446
|
+
);
|
|
7447
|
+
const compiled = txAdapter.compile(
|
|
7448
|
+
statementBundle,
|
|
7449
|
+
this.nqlBundleCompileOptions()
|
|
7450
|
+
);
|
|
7451
|
+
const rows = await txAdapter.execute(compiled);
|
|
7452
|
+
runtimeBindings.set(
|
|
7453
|
+
step.bindName,
|
|
7454
|
+
createRuntimeBinding(
|
|
7455
|
+
sourceBundle,
|
|
7456
|
+
step.bindName,
|
|
7457
|
+
snapshotMutationRows(rows),
|
|
7458
|
+
txAdapter.dbCasing
|
|
7459
|
+
)
|
|
7460
|
+
);
|
|
7428
7461
|
} else if (step.final) {
|
|
7429
7462
|
const planReport = isBindingFinalQuery(compiledIntent.bundle) && compiledIntent.kind === "query" ? createBindingFinalPlan(
|
|
7430
7463
|
step.intent,
|
|
@@ -7466,6 +7499,14 @@ var NqlBuilderImpl = class {
|
|
|
7466
7499
|
const runtimeBindings = /* @__PURE__ */ new Map();
|
|
7467
7500
|
const sequence = [];
|
|
7468
7501
|
const steps = createNqlProgramSteps(compiledIntent);
|
|
7502
|
+
const dumpRuntimeBindingPreview = (bindName) => {
|
|
7503
|
+
const columnTypes = sourceBundle.bindingOutputSchemas?.get(bindName)?.columnTypes;
|
|
7504
|
+
return {
|
|
7505
|
+
columns: requireMutationBindingColumns(sourceBundle, bindName),
|
|
7506
|
+
rows: [],
|
|
7507
|
+
...columnTypes !== void 0 && { columnTypes }
|
|
7508
|
+
};
|
|
7509
|
+
};
|
|
7469
7510
|
for (const step of steps) {
|
|
7470
7511
|
if (step.kind === "mutation") {
|
|
7471
7512
|
const statementBundle = this.createNqlStatementBundle(
|
|
@@ -7486,10 +7527,10 @@ var NqlBuilderImpl = class {
|
|
|
7486
7527
|
params: compiled.parameters
|
|
7487
7528
|
});
|
|
7488
7529
|
if (step.bindName !== void 0) {
|
|
7489
|
-
runtimeBindings.set(
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7530
|
+
runtimeBindings.set(
|
|
7531
|
+
step.bindName,
|
|
7532
|
+
dumpRuntimeBindingPreview(step.bindName)
|
|
7533
|
+
);
|
|
7493
7534
|
}
|
|
7494
7535
|
} else {
|
|
7495
7536
|
const planReport = step.final && isBindingFinalQuery(compiledIntent.bundle) && compiledIntent.kind === "query" ? createBindingFinalPlan(
|
|
@@ -7516,6 +7557,12 @@ var NqlBuilderImpl = class {
|
|
|
7516
7557
|
sql: compiled.sql,
|
|
7517
7558
|
params: compiled.parameters
|
|
7518
7559
|
});
|
|
7560
|
+
if (step.snapshot === true && step.bindName !== void 0) {
|
|
7561
|
+
runtimeBindings.set(
|
|
7562
|
+
step.bindName,
|
|
7563
|
+
dumpRuntimeBindingPreview(step.bindName)
|
|
7564
|
+
);
|
|
7565
|
+
}
|
|
7519
7566
|
}
|
|
7520
7567
|
if (step.bindName !== void 0) {
|
|
7521
7568
|
const boundQuery = sourceBundle.bindings?.get(step.bindName);
|
|
@@ -7595,7 +7642,7 @@ var NqlBuilderImpl = class {
|
|
|
7595
7642
|
);
|
|
7596
7643
|
}
|
|
7597
7644
|
const compiledIntent = this.compile();
|
|
7598
|
-
if (
|
|
7645
|
+
if (hasExecutableNqlProgramSequence(compiledIntent.bundle)) {
|
|
7599
7646
|
return this.executeNqlProgramSequence(compiledIntent, adapter);
|
|
7600
7647
|
}
|
|
7601
7648
|
if (compiledIntent.kind === "mutation") {
|
|
@@ -7940,7 +7987,7 @@ async function cursorPaginate(builder, options) {
|
|
|
7940
7987
|
}
|
|
7941
7988
|
|
|
7942
7989
|
// src/dx/result-hydrator.ts
|
|
7943
|
-
import { toColumnList as
|
|
7990
|
+
import { toColumnList as toColumnList2 } from "@dbsp/types";
|
|
7944
7991
|
|
|
7945
7992
|
// src/dx/relation-paths.ts
|
|
7946
7993
|
function nonEmptyString(value) {
|
|
@@ -8317,7 +8364,7 @@ var ResultHydrator = class {
|
|
|
8317
8364
|
* Get the foreign key column name from relation metadata.
|
|
8318
8365
|
*/
|
|
8319
8366
|
getForeignKeyColumn(foreignKey) {
|
|
8320
|
-
const columns =
|
|
8367
|
+
const columns = toColumnList2(foreignKey);
|
|
8321
8368
|
if (columns.length === 0) {
|
|
8322
8369
|
return "parent_id";
|
|
8323
8370
|
}
|
|
@@ -8418,7 +8465,7 @@ var ResultHydrator = class {
|
|
|
8418
8465
|
* case (slower but collision-safe for any value content).
|
|
8419
8466
|
*/
|
|
8420
8467
|
extractKeyValue(obj, key) {
|
|
8421
|
-
const columns =
|
|
8468
|
+
const columns = toColumnList2(key);
|
|
8422
8469
|
if (columns.length === 0) {
|
|
8423
8470
|
return void 0;
|
|
8424
8471
|
}
|
|
@@ -8436,7 +8483,7 @@ var ResultHydrator = class {
|
|
|
8436
8483
|
return parts.join(COMPOSITE_KEY_SEP);
|
|
8437
8484
|
}
|
|
8438
8485
|
extractQueryKeyValue(obj, key) {
|
|
8439
|
-
const columns =
|
|
8486
|
+
const columns = toColumnList2(key);
|
|
8440
8487
|
if (columns.length === 0) {
|
|
8441
8488
|
return void 0;
|
|
8442
8489
|
}
|
|
@@ -9466,38 +9513,13 @@ var QueryBuilderImpl = class _QueryBuilderImpl {
|
|
|
9466
9513
|
return intent;
|
|
9467
9514
|
}
|
|
9468
9515
|
const updatedIncludes = intent.include.map(
|
|
9469
|
-
(inc) => this.
|
|
9516
|
+
(inc) => applyHintToIncludeRecursive(inc, this.relationHints)
|
|
9470
9517
|
);
|
|
9471
9518
|
return {
|
|
9472
9519
|
...intent,
|
|
9473
9520
|
include: updatedIncludes
|
|
9474
9521
|
};
|
|
9475
9522
|
}
|
|
9476
|
-
/**
|
|
9477
|
-
* Apply relation hint to a single include (recursively).
|
|
9478
|
-
*/
|
|
9479
|
-
applyHintToInclude(inc) {
|
|
9480
|
-
if (inc.via !== void 0) {
|
|
9481
|
-
if (inc.include && inc.include.length > 0) {
|
|
9482
|
-
return {
|
|
9483
|
-
...inc,
|
|
9484
|
-
include: inc.include.map((nested) => this.applyHintToInclude(nested))
|
|
9485
|
-
};
|
|
9486
|
-
}
|
|
9487
|
-
return inc;
|
|
9488
|
-
}
|
|
9489
|
-
const hint = this.relationHints[inc.relation];
|
|
9490
|
-
const result = hint ? { ...inc, via: hint } : inc;
|
|
9491
|
-
if (result.include && result.include.length > 0) {
|
|
9492
|
-
return {
|
|
9493
|
-
...result,
|
|
9494
|
-
include: result.include.map(
|
|
9495
|
-
(nested) => this.applyHintToInclude(nested)
|
|
9496
|
-
)
|
|
9497
|
-
};
|
|
9498
|
-
}
|
|
9499
|
-
return result;
|
|
9500
|
-
}
|
|
9501
9523
|
/**
|
|
9502
9524
|
* Build the QueryIntent from current state.
|
|
9503
9525
|
* Handles exactOptionalPropertyTypes by only including defined properties.
|
|
@@ -10867,6 +10889,7 @@ function rangeContainedBy(fieldOrColumn, valueOrRange, rangeType = "daterange")
|
|
|
10867
10889
|
}
|
|
10868
10890
|
|
|
10869
10891
|
// src/dx/schema-bridge.ts
|
|
10892
|
+
import { buildRelationKeyFields, toColumnList as toColumnList3 } from "@dbsp/types";
|
|
10870
10893
|
import * as v from "valibot";
|
|
10871
10894
|
function generatedTypeToColumnType(genType) {
|
|
10872
10895
|
switch (genType) {
|
|
@@ -10919,6 +10942,37 @@ function mapRelationType2(kind) {
|
|
|
10919
10942
|
return "belongsToMany";
|
|
10920
10943
|
}
|
|
10921
10944
|
}
|
|
10945
|
+
function sourceTableFromQualifiedName(qualifiedName) {
|
|
10946
|
+
const dotIndex = qualifiedName.indexOf(".");
|
|
10947
|
+
return dotIndex > 0 ? qualifiedName.slice(0, dotIndex) : qualifiedName;
|
|
10948
|
+
}
|
|
10949
|
+
function relationNameFromQualifiedName(qualifiedName) {
|
|
10950
|
+
const dotIndex = qualifiedName.indexOf(".");
|
|
10951
|
+
return dotIndex > 0 ? qualifiedName.slice(dotIndex + 1) : qualifiedName;
|
|
10952
|
+
}
|
|
10953
|
+
function columnListsEqual(left, right) {
|
|
10954
|
+
const leftColumns = toColumnList3(left);
|
|
10955
|
+
const rightColumns = toColumnList3(right);
|
|
10956
|
+
return leftColumns.length === rightColumns.length && leftColumns.every((column, index) => column === rightColumns[index]);
|
|
10957
|
+
}
|
|
10958
|
+
function generatedReferencedColumns(key) {
|
|
10959
|
+
const columns = toColumnList3(key);
|
|
10960
|
+
return columns.length > 0 ? columns : ["id"];
|
|
10961
|
+
}
|
|
10962
|
+
function findRelationForeignKey(sourceTable, genRelation, tables) {
|
|
10963
|
+
switch (genRelation.kind) {
|
|
10964
|
+
case "belongsTo":
|
|
10965
|
+
return tables.get(sourceTable)?.foreignKeys.find(
|
|
10966
|
+
(fk) => fk.references.table === genRelation.target && columnListsEqual(fk.columns, genRelation.foreignKey)
|
|
10967
|
+
);
|
|
10968
|
+
case "hasMany":
|
|
10969
|
+
return tables.get(genRelation.target)?.foreignKeys.find(
|
|
10970
|
+
(fk) => fk.references.table === sourceTable && columnListsEqual(fk.columns, genRelation.foreignKey)
|
|
10971
|
+
);
|
|
10972
|
+
case "manyToMany":
|
|
10973
|
+
return void 0;
|
|
10974
|
+
}
|
|
10975
|
+
}
|
|
10922
10976
|
function isGeneratedTableWithConfig(table) {
|
|
10923
10977
|
const columns = table.columns;
|
|
10924
10978
|
return typeof columns === "object" && columns !== null && typeof columns.type !== "string";
|
|
@@ -11046,10 +11100,9 @@ function buildTableIRFromDefinition(tableName, genTable, fkAutoIndex) {
|
|
|
11046
11100
|
}
|
|
11047
11101
|
});
|
|
11048
11102
|
}
|
|
11049
|
-
function buildRelationIR(qualifiedName, genRelation, hints) {
|
|
11050
|
-
const
|
|
11051
|
-
const
|
|
11052
|
-
const relationName = dotIndex > 0 ? qualifiedName.slice(dotIndex + 1) : qualifiedName;
|
|
11103
|
+
function buildRelationIR(qualifiedName, genRelation, hints, relationFk) {
|
|
11104
|
+
const sourceTable = sourceTableFromQualifiedName(qualifiedName);
|
|
11105
|
+
const relationName = relationNameFromQualifiedName(qualifiedName);
|
|
11053
11106
|
const hint = hints[qualifiedName];
|
|
11054
11107
|
const relCardinality = genRelation.kind === "hasMany" ? genRelation.cardinality : void 0;
|
|
11055
11108
|
const cardinality = hint?.cardinality === "one" ? "one" : relCardinality === "one" ? "one" : genRelation.kind === "belongsTo" ? "one" : "many";
|
|
@@ -11073,14 +11126,38 @@ function buildRelationIR(qualifiedName, genRelation, hints) {
|
|
|
11073
11126
|
case "belongsTo":
|
|
11074
11127
|
return {
|
|
11075
11128
|
...baseRelation,
|
|
11076
|
-
|
|
11077
|
-
|
|
11129
|
+
...buildRelationKeyFields(
|
|
11130
|
+
relationFk ?? {
|
|
11131
|
+
columns: genRelation.foreignKey,
|
|
11132
|
+
references: {
|
|
11133
|
+
table: genRelation.target,
|
|
11134
|
+
columns: generatedReferencedColumns(genRelation.targetKey)
|
|
11135
|
+
}
|
|
11136
|
+
},
|
|
11137
|
+
"belongsTo",
|
|
11138
|
+
{
|
|
11139
|
+
foreignKeyShape: genRelation.foreignKey,
|
|
11140
|
+
...genRelation.targetKey !== void 0 ? { referencedKeyShape: genRelation.targetKey } : {}
|
|
11141
|
+
}
|
|
11142
|
+
)
|
|
11078
11143
|
};
|
|
11079
11144
|
case "hasMany":
|
|
11080
11145
|
return {
|
|
11081
11146
|
...baseRelation,
|
|
11082
|
-
|
|
11083
|
-
|
|
11147
|
+
...buildRelationKeyFields(
|
|
11148
|
+
relationFk ?? {
|
|
11149
|
+
columns: genRelation.foreignKey,
|
|
11150
|
+
references: {
|
|
11151
|
+
table: sourceTable,
|
|
11152
|
+
columns: generatedReferencedColumns(genRelation.sourceKey)
|
|
11153
|
+
}
|
|
11154
|
+
},
|
|
11155
|
+
"inverse",
|
|
11156
|
+
{
|
|
11157
|
+
foreignKeyShape: genRelation.foreignKey,
|
|
11158
|
+
...genRelation.sourceKey !== void 0 ? { referencedKeyShape: genRelation.sourceKey } : {}
|
|
11159
|
+
}
|
|
11160
|
+
)
|
|
11084
11161
|
};
|
|
11085
11162
|
case "manyToMany":
|
|
11086
11163
|
return {
|
|
@@ -11102,9 +11179,15 @@ function buildModelFromSchema(schema2) {
|
|
|
11102
11179
|
);
|
|
11103
11180
|
}
|
|
11104
11181
|
for (const [qualifiedName, genRelation] of Object.entries(schema2.relations)) {
|
|
11182
|
+
const sourceTable = sourceTableFromQualifiedName(qualifiedName);
|
|
11105
11183
|
relations.set(
|
|
11106
11184
|
qualifiedName,
|
|
11107
|
-
buildRelationIR(
|
|
11185
|
+
buildRelationIR(
|
|
11186
|
+
qualifiedName,
|
|
11187
|
+
genRelation,
|
|
11188
|
+
schema2.hints,
|
|
11189
|
+
findRelationForeignKey(sourceTable, genRelation, tables)
|
|
11190
|
+
)
|
|
11108
11191
|
);
|
|
11109
11192
|
}
|
|
11110
11193
|
return new ModelIRImpl(tables, relations);
|