@nicia-ai/typegraph 0.11.0 → 0.12.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.cjs +1914 -1459
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1914 -1460
- package/dist/index.js.map +1 -1
- package/dist/interchange/index.d.cts +1 -1
- package/dist/interchange/index.d.ts +1 -1
- package/dist/profiler/index.d.cts +1 -1
- package/dist/profiler/index.d.ts +1 -1
- package/dist/{store-nQ1ATBlN.d.ts → store-BcnA11lH.d.ts} +154 -8
- package/dist/{store-DyGdpDFr.d.cts → store-NEa4EFFD.d.cts} +154 -8
- package/package.json +10 -10
package/dist/index.cjs
CHANGED
|
@@ -311,72 +311,6 @@ var core = {
|
|
|
311
311
|
implies
|
|
312
312
|
};
|
|
313
313
|
|
|
314
|
-
// src/query/compiler/passes/recursive.ts
|
|
315
|
-
function runRecursiveTraversalSelectionPass(ast) {
|
|
316
|
-
const variableLengthTraversal = ast.traversals.find(
|
|
317
|
-
(traversal) => traversal.variableLength !== void 0
|
|
318
|
-
);
|
|
319
|
-
if (variableLengthTraversal === void 0) {
|
|
320
|
-
throw new chunk44SXEVF4_cjs.CompilerInvariantError("No variable-length traversal found");
|
|
321
|
-
}
|
|
322
|
-
if (ast.traversals.length > 1) {
|
|
323
|
-
throw new chunk44SXEVF4_cjs.UnsupportedPredicateError(
|
|
324
|
-
"Variable-length traversals with multiple traversals are not yet supported. Please use a single variable-length traversal."
|
|
325
|
-
);
|
|
326
|
-
}
|
|
327
|
-
return variableLengthTraversal;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// src/query/compiler/passes/runner.ts
|
|
331
|
-
function runCompilerPass(state, pass) {
|
|
332
|
-
const output = pass.execute(state);
|
|
333
|
-
return {
|
|
334
|
-
state: pass.update(state, output)
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
function compileTemporalFilter(options) {
|
|
338
|
-
const { mode, asOf, tableAlias, currentTimestamp } = options;
|
|
339
|
-
const prefix = tableAlias ? drizzleOrm.sql.raw(`${tableAlias}.`) : drizzleOrm.sql.raw("");
|
|
340
|
-
const deletedAt = drizzleOrm.sql`${prefix}deleted_at`;
|
|
341
|
-
const validFrom = drizzleOrm.sql`${prefix}valid_from`;
|
|
342
|
-
const validTo = drizzleOrm.sql`${prefix}valid_to`;
|
|
343
|
-
switch (mode) {
|
|
344
|
-
case "current": {
|
|
345
|
-
const now = currentTimestamp ?? drizzleOrm.sql`CURRENT_TIMESTAMP`;
|
|
346
|
-
return drizzleOrm.sql`${deletedAt} IS NULL AND (${validFrom} IS NULL OR ${validFrom} <= ${now}) AND (${validTo} IS NULL OR ${validTo} > ${now})`;
|
|
347
|
-
}
|
|
348
|
-
case "asOf": {
|
|
349
|
-
const timestamp = asOf;
|
|
350
|
-
return drizzleOrm.sql`${deletedAt} IS NULL AND (${validFrom} IS NULL OR ${validFrom} <= ${timestamp}) AND (${validTo} IS NULL OR ${validTo} > ${timestamp})`;
|
|
351
|
-
}
|
|
352
|
-
case "includeEnded": {
|
|
353
|
-
return drizzleOrm.sql`${deletedAt} IS NULL`;
|
|
354
|
-
}
|
|
355
|
-
case "includeTombstones": {
|
|
356
|
-
return drizzleOrm.sql.raw("1=1");
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
function extractTemporalOptions(ast, tableAlias) {
|
|
361
|
-
return {
|
|
362
|
-
mode: ast.temporalMode.mode,
|
|
363
|
-
asOf: ast.temporalMode.asOf,
|
|
364
|
-
tableAlias
|
|
365
|
-
};
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
// src/query/compiler/passes/temporal.ts
|
|
369
|
-
function createTemporalFilterPass(ast, currentTimestamp) {
|
|
370
|
-
return {
|
|
371
|
-
forAlias(tableAlias) {
|
|
372
|
-
return compileTemporalFilter({
|
|
373
|
-
...extractTemporalOptions(ast, tableAlias),
|
|
374
|
-
currentTimestamp
|
|
375
|
-
});
|
|
376
|
-
}
|
|
377
|
-
};
|
|
378
|
-
}
|
|
379
|
-
|
|
380
314
|
// src/query/subquery-utils.ts
|
|
381
315
|
function normalizeValueType(valueType) {
|
|
382
316
|
if (valueType === void 0 || valueType === "unknown") {
|
|
@@ -579,6 +513,10 @@ function baseFieldBuilder(field2) {
|
|
|
579
513
|
function stringField(field2) {
|
|
580
514
|
return {
|
|
581
515
|
...baseFieldBuilder(field2),
|
|
516
|
+
gt: (value) => comparison("gt", field2, value),
|
|
517
|
+
gte: (value) => comparison("gte", field2, value),
|
|
518
|
+
lt: (value) => comparison("lt", field2, value),
|
|
519
|
+
lte: (value) => comparison("lte", field2, value),
|
|
582
520
|
contains: (pattern) => stringOp("contains", field2, pattern),
|
|
583
521
|
startsWith: (pattern) => stringOp("startsWith", field2, pattern),
|
|
584
522
|
endsWith: (pattern) => stringOp("endsWith", field2, pattern),
|
|
@@ -1459,627 +1397,310 @@ function extractVectorSimilarityPredicates(predicates) {
|
|
|
1459
1397
|
return results;
|
|
1460
1398
|
}
|
|
1461
1399
|
|
|
1462
|
-
// src/query/compiler/
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
throw new chunk44SXEVF4_cjs.UnsupportedPredicateError(
|
|
1477
|
-
`Vector similarity predicates are not supported for dialect "${dialect.name}"`
|
|
1478
|
-
);
|
|
1479
|
-
}
|
|
1480
|
-
if (!dialect.capabilities.vectorMetrics.includes(vectorPredicate.metric)) {
|
|
1481
|
-
throw new chunk44SXEVF4_cjs.UnsupportedPredicateError(
|
|
1482
|
-
`Vector metric "${vectorPredicate.metric}" is not supported for dialect "${dialect.name}"`
|
|
1400
|
+
// src/query/compiler/predicate-utils.ts
|
|
1401
|
+
var EMPTY_PREDICATES = [];
|
|
1402
|
+
function buildPredicateIndexKey(alias, targetType) {
|
|
1403
|
+
return `${alias}\0${targetType}`;
|
|
1404
|
+
}
|
|
1405
|
+
function resolvePredicateTargetType(predicate2) {
|
|
1406
|
+
return predicate2.targetType === "edge" ? "edge" : "node";
|
|
1407
|
+
}
|
|
1408
|
+
function buildPredicateIndex(ast) {
|
|
1409
|
+
const byAliasAndType = /* @__PURE__ */ new Map();
|
|
1410
|
+
for (const predicate2 of ast.predicates) {
|
|
1411
|
+
const key = buildPredicateIndexKey(
|
|
1412
|
+
predicate2.targetAlias,
|
|
1413
|
+
resolvePredicateTargetType(predicate2)
|
|
1483
1414
|
);
|
|
1415
|
+
const existing = byAliasAndType.get(key);
|
|
1416
|
+
if (existing === void 0) {
|
|
1417
|
+
byAliasAndType.set(key, [predicate2]);
|
|
1418
|
+
} else {
|
|
1419
|
+
existing.push(predicate2);
|
|
1420
|
+
}
|
|
1484
1421
|
}
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1422
|
+
return { byAliasAndType };
|
|
1423
|
+
}
|
|
1424
|
+
function getPredicatesForAlias(predicateIndex, alias, targetType) {
|
|
1425
|
+
return predicateIndex.byAliasAndType.get(
|
|
1426
|
+
buildPredicateIndexKey(alias, targetType)
|
|
1427
|
+
) ?? EMPTY_PREDICATES;
|
|
1428
|
+
}
|
|
1429
|
+
function compilePredicateClauses(predicates, predicateContext) {
|
|
1430
|
+
return predicates.map(
|
|
1431
|
+
(predicate2) => compilePredicateExpression(predicate2.expression, predicateContext)
|
|
1432
|
+
);
|
|
1433
|
+
}
|
|
1434
|
+
function compileKindFilter(column, kinds) {
|
|
1435
|
+
if (kinds.length === 0) {
|
|
1436
|
+
return drizzleOrm.sql`1 = 0`;
|
|
1489
1437
|
}
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
if (!Number.isFinite(minScore)) {
|
|
1493
|
-
throw new chunk44SXEVF4_cjs.UnsupportedPredicateError(
|
|
1494
|
-
`Vector minScore must be a finite number, got ${String(minScore)}`
|
|
1495
|
-
);
|
|
1496
|
-
}
|
|
1497
|
-
if (vectorPredicate.metric === "cosine" && (minScore < -1 || minScore > 1)) {
|
|
1498
|
-
throw new chunk44SXEVF4_cjs.UnsupportedPredicateError(
|
|
1499
|
-
`Cosine minScore must be between -1 and 1, got ${String(minScore)}`
|
|
1500
|
-
);
|
|
1501
|
-
}
|
|
1438
|
+
if (kinds.length === 1) {
|
|
1439
|
+
return drizzleOrm.sql`${column} = ${kinds[0]}`;
|
|
1502
1440
|
}
|
|
1503
|
-
return {
|
|
1441
|
+
return drizzleOrm.sql`${column} IN (${drizzleOrm.sql.join(
|
|
1442
|
+
kinds.map((kind) => drizzleOrm.sql`${kind}`),
|
|
1443
|
+
drizzleOrm.sql`, `
|
|
1444
|
+
)})`;
|
|
1504
1445
|
}
|
|
1505
|
-
function
|
|
1506
|
-
if (
|
|
1507
|
-
return
|
|
1446
|
+
function getNodeKindsForAlias(ast, alias) {
|
|
1447
|
+
if (alias === ast.start.alias) {
|
|
1448
|
+
return ast.start.kinds;
|
|
1508
1449
|
}
|
|
1509
|
-
|
|
1510
|
-
|
|
1450
|
+
for (const traversal of ast.traversals) {
|
|
1451
|
+
if (traversal.nodeAlias === alias) {
|
|
1452
|
+
return traversal.nodeKinds;
|
|
1453
|
+
}
|
|
1511
1454
|
}
|
|
1512
|
-
|
|
1455
|
+
throw new chunk44SXEVF4_cjs.CompilerInvariantError(`Unknown traversal source alias: ${alias}`);
|
|
1513
1456
|
}
|
|
1514
1457
|
|
|
1515
|
-
// src/query/compiler/plan
|
|
1516
|
-
function
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1458
|
+
// src/query/compiler/emitter/plan-inspector.ts
|
|
1459
|
+
function collectPlanOperations(node, ops) {
|
|
1460
|
+
ops.add(node.op);
|
|
1461
|
+
switch (node.op) {
|
|
1462
|
+
case "aggregate":
|
|
1463
|
+
case "filter":
|
|
1464
|
+
case "join":
|
|
1465
|
+
case "limit_offset":
|
|
1466
|
+
case "project":
|
|
1467
|
+
case "recursive_expand":
|
|
1468
|
+
case "sort":
|
|
1469
|
+
case "vector_knn": {
|
|
1470
|
+
collectPlanOperations(node.input, ops);
|
|
1471
|
+
return;
|
|
1472
|
+
}
|
|
1473
|
+
case "set_op": {
|
|
1474
|
+
collectPlanOperations(node.left, ops);
|
|
1475
|
+
collectPlanOperations(node.right, ops);
|
|
1476
|
+
return;
|
|
1477
|
+
}
|
|
1478
|
+
case "scan": {
|
|
1479
|
+
return;
|
|
1528
1480
|
}
|
|
1529
1481
|
}
|
|
1530
|
-
return aggregates;
|
|
1531
1482
|
}
|
|
1532
|
-
function
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1483
|
+
function findUnaryNodeInProjectChain(rootNode, op) {
|
|
1484
|
+
let currentNode = rootNode.input;
|
|
1485
|
+
for (; ; ) {
|
|
1486
|
+
if (currentNode.op === op) {
|
|
1487
|
+
return currentNode;
|
|
1488
|
+
}
|
|
1489
|
+
switch (currentNode.op) {
|
|
1490
|
+
case "aggregate":
|
|
1491
|
+
case "filter":
|
|
1492
|
+
case "join":
|
|
1493
|
+
case "limit_offset":
|
|
1494
|
+
case "recursive_expand":
|
|
1495
|
+
case "sort":
|
|
1496
|
+
case "vector_knn": {
|
|
1497
|
+
currentNode = currentNode.input;
|
|
1498
|
+
continue;
|
|
1499
|
+
}
|
|
1500
|
+
case "project":
|
|
1501
|
+
case "scan":
|
|
1502
|
+
case "set_op": {
|
|
1503
|
+
return void 0;
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1537
1507
|
}
|
|
1538
|
-
function
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1508
|
+
function inspectProjectPlan(logicalPlan) {
|
|
1509
|
+
if (logicalPlan.root.op !== "project") {
|
|
1510
|
+
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
1511
|
+
`SQL emitter expected logical plan root to be "project", got "${logicalPlan.root.op}"`,
|
|
1512
|
+
{ component: "plan-inspector" }
|
|
1513
|
+
);
|
|
1542
1514
|
}
|
|
1515
|
+
const operations = /* @__PURE__ */ new Set();
|
|
1516
|
+
collectPlanOperations(logicalPlan.root, operations);
|
|
1517
|
+
const limitOffsetNode = findUnaryNodeInProjectChain(
|
|
1518
|
+
logicalPlan.root,
|
|
1519
|
+
"limit_offset"
|
|
1520
|
+
);
|
|
1521
|
+
const sortNode = findUnaryNodeInProjectChain(
|
|
1522
|
+
logicalPlan.root,
|
|
1523
|
+
"sort"
|
|
1524
|
+
);
|
|
1543
1525
|
return {
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
};
|
|
1563
|
-
node = ast.having === void 0 ? aggregateNode : { ...aggregateNode, having: ast.having };
|
|
1564
|
-
}
|
|
1565
|
-
if (ast.orderBy !== void 0 && ast.orderBy.length > 0) {
|
|
1566
|
-
node = {
|
|
1567
|
-
id: nextPlanNodeId(),
|
|
1568
|
-
input: node,
|
|
1569
|
-
op: "sort",
|
|
1570
|
-
orderBy: ast.orderBy
|
|
1571
|
-
};
|
|
1526
|
+
hasAggregate: operations.has("aggregate"),
|
|
1527
|
+
hasLimitOffset: operations.has("limit_offset"),
|
|
1528
|
+
hasRecursiveExpand: operations.has("recursive_expand"),
|
|
1529
|
+
hasSetOperation: operations.has("set_op"),
|
|
1530
|
+
hasSort: operations.has("sort"),
|
|
1531
|
+
hasVectorKnn: operations.has("vector_knn"),
|
|
1532
|
+
limitOffsetNode,
|
|
1533
|
+
rootProjectNode: logicalPlan.root,
|
|
1534
|
+
sortNode
|
|
1535
|
+
};
|
|
1536
|
+
}
|
|
1537
|
+
function inspectStandardProjectPlan(logicalPlan) {
|
|
1538
|
+
const shape = inspectProjectPlan(logicalPlan);
|
|
1539
|
+
if (shape.hasSetOperation) {
|
|
1540
|
+
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
1541
|
+
'Standard SQL emitter does not support plans containing "set_op" nodes',
|
|
1542
|
+
{ component: "plan-inspector" }
|
|
1543
|
+
);
|
|
1572
1544
|
}
|
|
1573
|
-
if (
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
};
|
|
1579
|
-
const hasLimit = limit !== void 0;
|
|
1580
|
-
const hasOffset = ast.offset !== void 0;
|
|
1581
|
-
if (hasLimit && hasOffset) {
|
|
1582
|
-
node = {
|
|
1583
|
-
...limitOffsetNodeBase,
|
|
1584
|
-
limit,
|
|
1585
|
-
offset: ast.offset
|
|
1586
|
-
};
|
|
1587
|
-
} else if (hasLimit) {
|
|
1588
|
-
node = { ...limitOffsetNodeBase, limit };
|
|
1589
|
-
} else if (hasOffset) {
|
|
1590
|
-
node = { ...limitOffsetNodeBase, offset: ast.offset };
|
|
1591
|
-
} else {
|
|
1592
|
-
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
1593
|
-
"limit_offset node requires limit or offset to be present"
|
|
1594
|
-
);
|
|
1595
|
-
}
|
|
1545
|
+
if (shape.hasRecursiveExpand) {
|
|
1546
|
+
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
1547
|
+
'Standard SQL emitter does not support plans containing "recursive_expand" nodes',
|
|
1548
|
+
{ component: "plan-inspector" }
|
|
1549
|
+
);
|
|
1596
1550
|
}
|
|
1597
|
-
|
|
1598
|
-
fields: ast.projection.fields,
|
|
1599
|
-
id: nextPlanNodeId(),
|
|
1600
|
-
input: node,
|
|
1601
|
-
op: "project"
|
|
1602
|
-
};
|
|
1603
|
-
return collapsedTraversalCteAlias === void 0 ? projectNodeBase : {
|
|
1604
|
-
...projectNodeBase,
|
|
1605
|
-
collapsedTraversalAlias: collapsedTraversalCteAlias
|
|
1606
|
-
};
|
|
1551
|
+
return shape;
|
|
1607
1552
|
}
|
|
1608
|
-
function
|
|
1609
|
-
const
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
kinds: ast.start.kinds,
|
|
1615
|
-
op: "scan",
|
|
1616
|
-
source: "nodes"
|
|
1617
|
-
};
|
|
1618
|
-
currentNode = wrapWithAliasFilterNode(
|
|
1619
|
-
currentNode,
|
|
1620
|
-
ast,
|
|
1621
|
-
ast.start.alias,
|
|
1622
|
-
"node",
|
|
1623
|
-
nextPlanNodeId
|
|
1624
|
-
);
|
|
1625
|
-
for (const traversal of ast.traversals) {
|
|
1626
|
-
currentNode = {
|
|
1627
|
-
direction: traversal.direction,
|
|
1628
|
-
edgeAlias: traversal.edgeAlias,
|
|
1629
|
-
edgeKinds: traversal.edgeKinds,
|
|
1630
|
-
id: nextPlanNodeId(),
|
|
1631
|
-
input: currentNode,
|
|
1632
|
-
inverseEdgeKinds: traversal.inverseEdgeKinds ?? [],
|
|
1633
|
-
joinFromAlias: traversal.joinFromAlias,
|
|
1634
|
-
joinType: traversal.optional ? "left" : "inner",
|
|
1635
|
-
nodeAlias: traversal.nodeAlias,
|
|
1636
|
-
nodeKinds: traversal.nodeKinds,
|
|
1637
|
-
op: "join"
|
|
1638
|
-
};
|
|
1639
|
-
currentNode = wrapWithAliasFilterNode(
|
|
1640
|
-
currentNode,
|
|
1641
|
-
ast,
|
|
1642
|
-
traversal.edgeAlias,
|
|
1643
|
-
"edge",
|
|
1644
|
-
nextPlanNodeId
|
|
1553
|
+
function inspectRecursiveProjectPlan(logicalPlan) {
|
|
1554
|
+
const shape = inspectProjectPlan(logicalPlan);
|
|
1555
|
+
if (!shape.hasRecursiveExpand) {
|
|
1556
|
+
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
1557
|
+
'Recursive SQL emitter expected logical plan to contain a "recursive_expand" node',
|
|
1558
|
+
{ component: "plan-inspector" }
|
|
1645
1559
|
);
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
"
|
|
1651
|
-
nextPlanNodeId
|
|
1560
|
+
}
|
|
1561
|
+
if (shape.hasSetOperation) {
|
|
1562
|
+
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
1563
|
+
'Recursive SQL emitter does not support plans containing "set_op" nodes',
|
|
1564
|
+
{ component: "plan-inspector" }
|
|
1652
1565
|
);
|
|
1653
1566
|
}
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1567
|
+
return shape;
|
|
1568
|
+
}
|
|
1569
|
+
function findTopLevelLimitOffsetNode(rootNode) {
|
|
1570
|
+
let currentNode = rootNode;
|
|
1571
|
+
for (; ; ) {
|
|
1572
|
+
if (currentNode.op === "limit_offset") {
|
|
1573
|
+
return currentNode;
|
|
1574
|
+
}
|
|
1575
|
+
switch (currentNode.op) {
|
|
1576
|
+
case "aggregate":
|
|
1577
|
+
case "filter":
|
|
1578
|
+
case "join":
|
|
1579
|
+
case "project":
|
|
1580
|
+
case "recursive_expand":
|
|
1581
|
+
case "sort":
|
|
1582
|
+
case "vector_knn": {
|
|
1583
|
+
currentNode = currentNode.input;
|
|
1584
|
+
continue;
|
|
1585
|
+
}
|
|
1586
|
+
case "scan":
|
|
1587
|
+
case "set_op": {
|
|
1588
|
+
return void 0;
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1661
1591
|
}
|
|
1662
|
-
return appendAggregateSortLimitAndProjectNodes(
|
|
1663
|
-
currentNode,
|
|
1664
|
-
ast,
|
|
1665
|
-
nextPlanNodeId,
|
|
1666
|
-
input.effectiveLimit,
|
|
1667
|
-
input.collapsedTraversalCteAlias
|
|
1668
|
-
);
|
|
1669
1592
|
}
|
|
1670
|
-
function
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
inverseEdgeKinds: traversal.inverseEdgeKinds ?? [],
|
|
1694
|
-
nodeAlias: traversal.nodeAlias,
|
|
1695
|
-
nodeKinds: traversal.nodeKinds,
|
|
1696
|
-
op: "recursive_expand",
|
|
1697
|
-
traversal: traversal.variableLength
|
|
1698
|
-
};
|
|
1699
|
-
currentNode = wrapWithAliasFilterNode(
|
|
1700
|
-
currentNode,
|
|
1701
|
-
ast,
|
|
1702
|
-
traversal.edgeAlias,
|
|
1703
|
-
"edge",
|
|
1704
|
-
nextPlanNodeId
|
|
1705
|
-
);
|
|
1706
|
-
currentNode = wrapWithAliasFilterNode(
|
|
1707
|
-
currentNode,
|
|
1708
|
-
ast,
|
|
1709
|
-
traversal.nodeAlias,
|
|
1710
|
-
"node",
|
|
1711
|
-
nextPlanNodeId
|
|
1712
|
-
);
|
|
1713
|
-
return appendAggregateSortLimitAndProjectNodes(
|
|
1714
|
-
currentNode,
|
|
1715
|
-
ast,
|
|
1716
|
-
nextPlanNodeId,
|
|
1717
|
-
ast.limit
|
|
1718
|
-
);
|
|
1593
|
+
function findTopLevelSortNode(rootNode) {
|
|
1594
|
+
let currentNode = rootNode;
|
|
1595
|
+
for (; ; ) {
|
|
1596
|
+
if (currentNode.op === "sort") {
|
|
1597
|
+
return currentNode;
|
|
1598
|
+
}
|
|
1599
|
+
switch (currentNode.op) {
|
|
1600
|
+
case "aggregate":
|
|
1601
|
+
case "filter":
|
|
1602
|
+
case "join":
|
|
1603
|
+
case "limit_offset":
|
|
1604
|
+
case "project":
|
|
1605
|
+
case "recursive_expand":
|
|
1606
|
+
case "vector_knn": {
|
|
1607
|
+
currentNode = currentNode.input;
|
|
1608
|
+
continue;
|
|
1609
|
+
}
|
|
1610
|
+
case "scan":
|
|
1611
|
+
case "set_op": {
|
|
1612
|
+
return void 0;
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1719
1616
|
}
|
|
1720
|
-
function
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1617
|
+
function inspectSetOperationPlan(logicalPlan) {
|
|
1618
|
+
const operations = /* @__PURE__ */ new Set();
|
|
1619
|
+
collectPlanOperations(logicalPlan.root, operations);
|
|
1620
|
+
if (!operations.has("set_op")) {
|
|
1621
|
+
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
1622
|
+
'Set-operation SQL emitter expected logical plan to contain a "set_op" node',
|
|
1623
|
+
{ component: "plan-inspector" }
|
|
1727
1624
|
);
|
|
1728
1625
|
}
|
|
1729
|
-
const
|
|
1730
|
-
|
|
1731
|
-
);
|
|
1732
|
-
if (hasVariableLengthTraversal2) {
|
|
1733
|
-
return lowerRecursiveQueryToLogicalPlanNode({
|
|
1734
|
-
ast: query,
|
|
1735
|
-
graphId,
|
|
1736
|
-
nextPlanNodeId
|
|
1737
|
-
});
|
|
1738
|
-
}
|
|
1739
|
-
const vectorPredicate = runVectorPredicatePass(
|
|
1740
|
-
query,
|
|
1741
|
-
chunk2WVFEIHR_cjs.getDialect(dialect)
|
|
1742
|
-
).vectorPredicate;
|
|
1743
|
-
const effectiveLimit = resolveVectorAwareLimit(query.limit, vectorPredicate);
|
|
1744
|
-
const loweringInput = {
|
|
1745
|
-
ast: query,
|
|
1746
|
-
graphId,
|
|
1747
|
-
nextPlanNodeId,
|
|
1748
|
-
...effectiveLimit === void 0 ? {} : { effectiveLimit },
|
|
1749
|
-
...vectorPredicate === void 0 ? {} : { vectorPredicate }
|
|
1750
|
-
};
|
|
1751
|
-
return lowerStandardQueryToLogicalPlanNode(loweringInput);
|
|
1752
|
-
}
|
|
1753
|
-
function lowerSetOperationToLogicalPlanNode(op, graphId, dialect, nextPlanNodeId) {
|
|
1754
|
-
let currentNode = {
|
|
1755
|
-
id: nextPlanNodeId(),
|
|
1756
|
-
left: lowerComposableQueryToLogicalPlanNode(
|
|
1757
|
-
op.left,
|
|
1758
|
-
dialect,
|
|
1759
|
-
graphId,
|
|
1760
|
-
nextPlanNodeId
|
|
1761
|
-
),
|
|
1762
|
-
op: "set_op",
|
|
1763
|
-
operator: op.operator,
|
|
1764
|
-
right: lowerComposableQueryToLogicalPlanNode(
|
|
1765
|
-
op.right,
|
|
1766
|
-
dialect,
|
|
1767
|
-
graphId,
|
|
1768
|
-
nextPlanNodeId
|
|
1769
|
-
)
|
|
1770
|
-
};
|
|
1771
|
-
if (op.orderBy !== void 0 && op.orderBy.length > 0) {
|
|
1772
|
-
currentNode = {
|
|
1773
|
-
id: nextPlanNodeId(),
|
|
1774
|
-
input: currentNode,
|
|
1775
|
-
op: "sort",
|
|
1776
|
-
orderBy: op.orderBy
|
|
1777
|
-
};
|
|
1778
|
-
}
|
|
1779
|
-
if (op.limit !== void 0 || op.offset !== void 0) {
|
|
1780
|
-
const limitOffsetBase = {
|
|
1781
|
-
id: nextPlanNodeId(),
|
|
1782
|
-
input: currentNode,
|
|
1783
|
-
op: "limit_offset"
|
|
1784
|
-
};
|
|
1785
|
-
if (op.limit !== void 0 && op.offset !== void 0) {
|
|
1786
|
-
currentNode = { ...limitOffsetBase, limit: op.limit, offset: op.offset };
|
|
1787
|
-
} else if (op.limit === void 0) {
|
|
1788
|
-
currentNode = { ...limitOffsetBase, offset: op.offset };
|
|
1789
|
-
} else {
|
|
1790
|
-
currentNode = { ...limitOffsetBase, limit: op.limit };
|
|
1791
|
-
}
|
|
1792
|
-
}
|
|
1793
|
-
return currentNode;
|
|
1794
|
-
}
|
|
1795
|
-
function lowerStandardQueryToLogicalPlan(input) {
|
|
1796
|
-
const nextPlanNodeId = createPlanNodeIdFactory();
|
|
1797
|
-
return {
|
|
1798
|
-
metadata: {
|
|
1799
|
-
dialect: input.dialect,
|
|
1800
|
-
graphId: input.graphId
|
|
1801
|
-
},
|
|
1802
|
-
root: lowerStandardQueryToLogicalPlanNode({
|
|
1803
|
-
...input,
|
|
1804
|
-
nextPlanNodeId
|
|
1805
|
-
})
|
|
1806
|
-
};
|
|
1807
|
-
}
|
|
1808
|
-
function lowerRecursiveQueryToLogicalPlan(input) {
|
|
1809
|
-
const nextPlanNodeId = createPlanNodeIdFactory();
|
|
1810
|
-
return {
|
|
1811
|
-
metadata: {
|
|
1812
|
-
dialect: input.dialect,
|
|
1813
|
-
graphId: input.graphId
|
|
1814
|
-
},
|
|
1815
|
-
root: lowerRecursiveQueryToLogicalPlanNode({
|
|
1816
|
-
...input,
|
|
1817
|
-
nextPlanNodeId
|
|
1818
|
-
})
|
|
1819
|
-
};
|
|
1820
|
-
}
|
|
1821
|
-
function lowerSetOperationToLogicalPlan(input) {
|
|
1822
|
-
const nextPlanNodeId = createPlanNodeIdFactory();
|
|
1626
|
+
const limitOffsetNode = findTopLevelLimitOffsetNode(logicalPlan.root);
|
|
1627
|
+
const sortNode = findTopLevelSortNode(logicalPlan.root);
|
|
1823
1628
|
return {
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
input.op,
|
|
1830
|
-
input.graphId,
|
|
1831
|
-
input.dialect,
|
|
1832
|
-
nextPlanNodeId
|
|
1833
|
-
)
|
|
1629
|
+
hasLimitOffset: limitOffsetNode !== void 0,
|
|
1630
|
+
hasSetOperation: true,
|
|
1631
|
+
hasSort: sortNode !== void 0,
|
|
1632
|
+
limitOffsetNode,
|
|
1633
|
+
sortNode
|
|
1834
1634
|
};
|
|
1835
1635
|
}
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
case "join":
|
|
1844
|
-
case "limit_offset":
|
|
1845
|
-
case "project":
|
|
1846
|
-
case "recursive_expand":
|
|
1847
|
-
case "sort":
|
|
1848
|
-
case "vector_knn": {
|
|
1849
|
-
collectPlanOperations(node.input, ops);
|
|
1850
|
-
return;
|
|
1851
|
-
}
|
|
1852
|
-
case "set_op": {
|
|
1853
|
-
collectPlanOperations(node.left, ops);
|
|
1854
|
-
collectPlanOperations(node.right, ops);
|
|
1855
|
-
return;
|
|
1856
|
-
}
|
|
1857
|
-
case "scan": {
|
|
1858
|
-
return;
|
|
1859
|
-
}
|
|
1860
|
-
}
|
|
1861
|
-
}
|
|
1862
|
-
function findUnaryNodeInProjectChain(rootNode, op) {
|
|
1863
|
-
let currentNode = rootNode.input;
|
|
1864
|
-
for (; ; ) {
|
|
1865
|
-
if (currentNode.op === op) {
|
|
1866
|
-
return currentNode;
|
|
1867
|
-
}
|
|
1868
|
-
switch (currentNode.op) {
|
|
1869
|
-
case "aggregate":
|
|
1870
|
-
case "filter":
|
|
1871
|
-
case "join":
|
|
1872
|
-
case "limit_offset":
|
|
1873
|
-
case "recursive_expand":
|
|
1874
|
-
case "sort":
|
|
1875
|
-
case "vector_knn": {
|
|
1876
|
-
currentNode = currentNode.input;
|
|
1877
|
-
continue;
|
|
1878
|
-
}
|
|
1879
|
-
case "project":
|
|
1880
|
-
case "scan":
|
|
1881
|
-
case "set_op": {
|
|
1882
|
-
return void 0;
|
|
1883
|
-
}
|
|
1884
|
-
}
|
|
1636
|
+
function assertRecursiveEmitterClauseAlignment(logicalPlan, input) {
|
|
1637
|
+
const planShape = inspectRecursiveProjectPlan(logicalPlan);
|
|
1638
|
+
if (planShape.hasSort && input.orderBy === void 0) {
|
|
1639
|
+
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
1640
|
+
"Recursive SQL emitter expected ORDER BY clause for plan containing a sort node",
|
|
1641
|
+
{ component: "recursive-emitter" }
|
|
1642
|
+
);
|
|
1885
1643
|
}
|
|
1886
|
-
|
|
1887
|
-
function inspectProjectPlan(logicalPlan) {
|
|
1888
|
-
if (logicalPlan.root.op !== "project") {
|
|
1644
|
+
if (!planShape.hasSort && input.orderBy !== void 0) {
|
|
1889
1645
|
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
1890
|
-
|
|
1891
|
-
{ component: "
|
|
1646
|
+
"Recursive SQL emitter received ORDER BY clause for a plan without sort nodes",
|
|
1647
|
+
{ component: "recursive-emitter" }
|
|
1892
1648
|
);
|
|
1893
1649
|
}
|
|
1894
|
-
|
|
1895
|
-
collectPlanOperations(logicalPlan.root, operations);
|
|
1896
|
-
const limitOffsetNode = findUnaryNodeInProjectChain(
|
|
1897
|
-
logicalPlan.root,
|
|
1898
|
-
"limit_offset"
|
|
1899
|
-
);
|
|
1900
|
-
const sortNode = findUnaryNodeInProjectChain(
|
|
1901
|
-
logicalPlan.root,
|
|
1902
|
-
"sort"
|
|
1903
|
-
);
|
|
1904
|
-
return {
|
|
1905
|
-
hasAggregate: operations.has("aggregate"),
|
|
1906
|
-
hasLimitOffset: operations.has("limit_offset"),
|
|
1907
|
-
hasRecursiveExpand: operations.has("recursive_expand"),
|
|
1908
|
-
hasSetOperation: operations.has("set_op"),
|
|
1909
|
-
hasSort: operations.has("sort"),
|
|
1910
|
-
hasVectorKnn: operations.has("vector_knn"),
|
|
1911
|
-
limitOffsetNode,
|
|
1912
|
-
rootProjectNode: logicalPlan.root,
|
|
1913
|
-
sortNode
|
|
1914
|
-
};
|
|
1915
|
-
}
|
|
1916
|
-
function inspectStandardProjectPlan(logicalPlan) {
|
|
1917
|
-
const shape = inspectProjectPlan(logicalPlan);
|
|
1918
|
-
if (shape.hasSetOperation) {
|
|
1650
|
+
if (planShape.hasLimitOffset && input.limitOffset === void 0) {
|
|
1919
1651
|
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
1920
|
-
|
|
1921
|
-
{ component: "
|
|
1652
|
+
"Recursive SQL emitter expected LIMIT/OFFSET clause for plan containing a limit_offset node",
|
|
1653
|
+
{ component: "recursive-emitter" }
|
|
1922
1654
|
);
|
|
1923
1655
|
}
|
|
1924
|
-
if (
|
|
1656
|
+
if (!planShape.hasLimitOffset && input.limitOffset !== void 0) {
|
|
1925
1657
|
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
1926
|
-
|
|
1927
|
-
{ component: "
|
|
1658
|
+
"Recursive SQL emitter received LIMIT/OFFSET clause for a plan without limit_offset nodes",
|
|
1659
|
+
{ component: "recursive-emitter" }
|
|
1928
1660
|
);
|
|
1929
1661
|
}
|
|
1930
|
-
return shape;
|
|
1931
1662
|
}
|
|
1932
|
-
function
|
|
1933
|
-
|
|
1934
|
-
|
|
1663
|
+
function emitRecursiveQuerySql(input) {
|
|
1664
|
+
assertRecursiveEmitterClauseAlignment(input.logicalPlan, input);
|
|
1665
|
+
const parts = [
|
|
1666
|
+
drizzleOrm.sql`WITH RECURSIVE`,
|
|
1667
|
+
input.recursiveCte,
|
|
1668
|
+
drizzleOrm.sql`SELECT ${input.projection}`,
|
|
1669
|
+
drizzleOrm.sql`FROM recursive_cte`,
|
|
1670
|
+
input.depthFilter
|
|
1671
|
+
];
|
|
1672
|
+
if (input.orderBy !== void 0) {
|
|
1673
|
+
parts.push(input.orderBy);
|
|
1674
|
+
}
|
|
1675
|
+
if (input.limitOffset !== void 0) {
|
|
1676
|
+
parts.push(input.limitOffset);
|
|
1677
|
+
}
|
|
1678
|
+
return drizzleOrm.sql.join(parts, drizzleOrm.sql` `);
|
|
1679
|
+
}
|
|
1680
|
+
function assertSetOperationEmitterClauseAlignment(logicalPlan, suffixClauses) {
|
|
1681
|
+
const shape = inspectSetOperationPlan(logicalPlan);
|
|
1682
|
+
const hasSuffixClauses = suffixClauses !== void 0 && suffixClauses.length > 0;
|
|
1683
|
+
if (!shape.hasSort && !shape.hasLimitOffset && hasSuffixClauses) {
|
|
1935
1684
|
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
1936
|
-
|
|
1937
|
-
{ component: "
|
|
1685
|
+
"Set-operation SQL emitter received suffix clauses for a plan without top-level sort or limit_offset nodes",
|
|
1686
|
+
{ component: "set-operation-emitter" }
|
|
1938
1687
|
);
|
|
1939
1688
|
}
|
|
1940
|
-
if (
|
|
1689
|
+
if (!hasSuffixClauses) {
|
|
1690
|
+
if (shape.hasSort || shape.hasLimitOffset) {
|
|
1691
|
+
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
1692
|
+
"Set-operation SQL emitter expected suffix clauses for plan containing top-level sort or limit_offset nodes",
|
|
1693
|
+
{ component: "set-operation-emitter" }
|
|
1694
|
+
);
|
|
1695
|
+
}
|
|
1696
|
+
return;
|
|
1697
|
+
}
|
|
1698
|
+
const limitOffsetClauseCount = shape.limitOffsetNode === void 0 ? 0 : (shape.limitOffsetNode.limit === void 0 ? 0 : 1) + (shape.limitOffsetNode.offset === void 0 ? 0 : 1);
|
|
1699
|
+
const expectedClauseCount = (shape.sortNode === void 0 ? 0 : 1) + limitOffsetClauseCount;
|
|
1700
|
+
if (suffixClauses.length !== expectedClauseCount) {
|
|
1941
1701
|
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
1942
|
-
|
|
1943
|
-
{ component: "
|
|
1944
|
-
);
|
|
1945
|
-
}
|
|
1946
|
-
return shape;
|
|
1947
|
-
}
|
|
1948
|
-
function findTopLevelLimitOffsetNode(rootNode) {
|
|
1949
|
-
let currentNode = rootNode;
|
|
1950
|
-
for (; ; ) {
|
|
1951
|
-
if (currentNode.op === "limit_offset") {
|
|
1952
|
-
return currentNode;
|
|
1953
|
-
}
|
|
1954
|
-
switch (currentNode.op) {
|
|
1955
|
-
case "aggregate":
|
|
1956
|
-
case "filter":
|
|
1957
|
-
case "join":
|
|
1958
|
-
case "project":
|
|
1959
|
-
case "recursive_expand":
|
|
1960
|
-
case "sort":
|
|
1961
|
-
case "vector_knn": {
|
|
1962
|
-
currentNode = currentNode.input;
|
|
1963
|
-
continue;
|
|
1964
|
-
}
|
|
1965
|
-
case "scan":
|
|
1966
|
-
case "set_op": {
|
|
1967
|
-
return void 0;
|
|
1968
|
-
}
|
|
1969
|
-
}
|
|
1970
|
-
}
|
|
1971
|
-
}
|
|
1972
|
-
function findTopLevelSortNode(rootNode) {
|
|
1973
|
-
let currentNode = rootNode;
|
|
1974
|
-
for (; ; ) {
|
|
1975
|
-
if (currentNode.op === "sort") {
|
|
1976
|
-
return currentNode;
|
|
1977
|
-
}
|
|
1978
|
-
switch (currentNode.op) {
|
|
1979
|
-
case "aggregate":
|
|
1980
|
-
case "filter":
|
|
1981
|
-
case "join":
|
|
1982
|
-
case "limit_offset":
|
|
1983
|
-
case "project":
|
|
1984
|
-
case "recursive_expand":
|
|
1985
|
-
case "vector_knn": {
|
|
1986
|
-
currentNode = currentNode.input;
|
|
1987
|
-
continue;
|
|
1988
|
-
}
|
|
1989
|
-
case "scan":
|
|
1990
|
-
case "set_op": {
|
|
1991
|
-
return void 0;
|
|
1992
|
-
}
|
|
1993
|
-
}
|
|
1994
|
-
}
|
|
1995
|
-
}
|
|
1996
|
-
function inspectSetOperationPlan(logicalPlan) {
|
|
1997
|
-
const operations = /* @__PURE__ */ new Set();
|
|
1998
|
-
collectPlanOperations(logicalPlan.root, operations);
|
|
1999
|
-
if (!operations.has("set_op")) {
|
|
2000
|
-
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
2001
|
-
'Set-operation SQL emitter expected logical plan to contain a "set_op" node',
|
|
2002
|
-
{ component: "plan-inspector" }
|
|
2003
|
-
);
|
|
2004
|
-
}
|
|
2005
|
-
const limitOffsetNode = findTopLevelLimitOffsetNode(logicalPlan.root);
|
|
2006
|
-
const sortNode = findTopLevelSortNode(logicalPlan.root);
|
|
2007
|
-
return {
|
|
2008
|
-
hasLimitOffset: limitOffsetNode !== void 0,
|
|
2009
|
-
hasSetOperation: true,
|
|
2010
|
-
hasSort: sortNode !== void 0,
|
|
2011
|
-
limitOffsetNode,
|
|
2012
|
-
sortNode
|
|
2013
|
-
};
|
|
2014
|
-
}
|
|
2015
|
-
function assertRecursiveEmitterClauseAlignment(logicalPlan, input) {
|
|
2016
|
-
const planShape = inspectRecursiveProjectPlan(logicalPlan);
|
|
2017
|
-
if (planShape.hasSort && input.orderBy === void 0) {
|
|
2018
|
-
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
2019
|
-
"Recursive SQL emitter expected ORDER BY clause for plan containing a sort node",
|
|
2020
|
-
{ component: "recursive-emitter" }
|
|
2021
|
-
);
|
|
2022
|
-
}
|
|
2023
|
-
if (!planShape.hasSort && input.orderBy !== void 0) {
|
|
2024
|
-
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
2025
|
-
"Recursive SQL emitter received ORDER BY clause for a plan without sort nodes",
|
|
2026
|
-
{ component: "recursive-emitter" }
|
|
2027
|
-
);
|
|
2028
|
-
}
|
|
2029
|
-
if (planShape.hasLimitOffset && input.limitOffset === void 0) {
|
|
2030
|
-
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
2031
|
-
"Recursive SQL emitter expected LIMIT/OFFSET clause for plan containing a limit_offset node",
|
|
2032
|
-
{ component: "recursive-emitter" }
|
|
2033
|
-
);
|
|
2034
|
-
}
|
|
2035
|
-
if (!planShape.hasLimitOffset && input.limitOffset !== void 0) {
|
|
2036
|
-
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
2037
|
-
"Recursive SQL emitter received LIMIT/OFFSET clause for a plan without limit_offset nodes",
|
|
2038
|
-
{ component: "recursive-emitter" }
|
|
2039
|
-
);
|
|
2040
|
-
}
|
|
2041
|
-
}
|
|
2042
|
-
function emitRecursiveQuerySql(input) {
|
|
2043
|
-
assertRecursiveEmitterClauseAlignment(input.logicalPlan, input);
|
|
2044
|
-
const parts = [
|
|
2045
|
-
drizzleOrm.sql`WITH RECURSIVE`,
|
|
2046
|
-
input.recursiveCte,
|
|
2047
|
-
drizzleOrm.sql`SELECT ${input.projection}`,
|
|
2048
|
-
drizzleOrm.sql`FROM recursive_cte`,
|
|
2049
|
-
input.depthFilter
|
|
2050
|
-
];
|
|
2051
|
-
if (input.orderBy !== void 0) {
|
|
2052
|
-
parts.push(input.orderBy);
|
|
2053
|
-
}
|
|
2054
|
-
if (input.limitOffset !== void 0) {
|
|
2055
|
-
parts.push(input.limitOffset);
|
|
2056
|
-
}
|
|
2057
|
-
return drizzleOrm.sql.join(parts, drizzleOrm.sql` `);
|
|
2058
|
-
}
|
|
2059
|
-
function assertSetOperationEmitterClauseAlignment(logicalPlan, suffixClauses) {
|
|
2060
|
-
const shape = inspectSetOperationPlan(logicalPlan);
|
|
2061
|
-
const hasSuffixClauses = suffixClauses !== void 0 && suffixClauses.length > 0;
|
|
2062
|
-
if (!shape.hasSort && !shape.hasLimitOffset && hasSuffixClauses) {
|
|
2063
|
-
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
2064
|
-
"Set-operation SQL emitter received suffix clauses for a plan without top-level sort or limit_offset nodes",
|
|
2065
|
-
{ component: "set-operation-emitter" }
|
|
2066
|
-
);
|
|
2067
|
-
}
|
|
2068
|
-
if (!hasSuffixClauses) {
|
|
2069
|
-
if (shape.hasSort || shape.hasLimitOffset) {
|
|
2070
|
-
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
2071
|
-
"Set-operation SQL emitter expected suffix clauses for plan containing top-level sort or limit_offset nodes",
|
|
2072
|
-
{ component: "set-operation-emitter" }
|
|
2073
|
-
);
|
|
2074
|
-
}
|
|
2075
|
-
return;
|
|
2076
|
-
}
|
|
2077
|
-
const limitOffsetClauseCount = shape.limitOffsetNode === void 0 ? 0 : (shape.limitOffsetNode.limit === void 0 ? 0 : 1) + (shape.limitOffsetNode.offset === void 0 ? 0 : 1);
|
|
2078
|
-
const expectedClauseCount = (shape.sortNode === void 0 ? 0 : 1) + limitOffsetClauseCount;
|
|
2079
|
-
if (suffixClauses.length !== expectedClauseCount) {
|
|
2080
|
-
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
2081
|
-
`Set-operation SQL emitter expected ${String(expectedClauseCount)} top-level suffix clause(s) from logical plan, got ${String(suffixClauses.length)}`,
|
|
2082
|
-
{ component: "set-operation-emitter" }
|
|
1702
|
+
`Set-operation SQL emitter expected ${String(expectedClauseCount)} top-level suffix clause(s) from logical plan, got ${String(suffixClauses.length)}`,
|
|
1703
|
+
{ component: "set-operation-emitter" }
|
|
2083
1704
|
);
|
|
2084
1705
|
}
|
|
2085
1706
|
}
|
|
@@ -2159,62 +1780,6 @@ function emitStandardQuerySql(input) {
|
|
|
2159
1780
|
}
|
|
2160
1781
|
return drizzleOrm.sql.join(parts, drizzleOrm.sql` `);
|
|
2161
1782
|
}
|
|
2162
|
-
var EMPTY_PREDICATES = [];
|
|
2163
|
-
function buildPredicateIndexKey(alias, targetType) {
|
|
2164
|
-
return `${alias}\0${targetType}`;
|
|
2165
|
-
}
|
|
2166
|
-
function resolvePredicateTargetType(predicate2) {
|
|
2167
|
-
return predicate2.targetType === "edge" ? "edge" : "node";
|
|
2168
|
-
}
|
|
2169
|
-
function buildPredicateIndex(ast) {
|
|
2170
|
-
const byAliasAndType = /* @__PURE__ */ new Map();
|
|
2171
|
-
for (const predicate2 of ast.predicates) {
|
|
2172
|
-
const key = buildPredicateIndexKey(
|
|
2173
|
-
predicate2.targetAlias,
|
|
2174
|
-
resolvePredicateTargetType(predicate2)
|
|
2175
|
-
);
|
|
2176
|
-
const existing = byAliasAndType.get(key);
|
|
2177
|
-
if (existing === void 0) {
|
|
2178
|
-
byAliasAndType.set(key, [predicate2]);
|
|
2179
|
-
} else {
|
|
2180
|
-
existing.push(predicate2);
|
|
2181
|
-
}
|
|
2182
|
-
}
|
|
2183
|
-
return { byAliasAndType };
|
|
2184
|
-
}
|
|
2185
|
-
function getPredicatesForAlias(predicateIndex, alias, targetType) {
|
|
2186
|
-
return predicateIndex.byAliasAndType.get(
|
|
2187
|
-
buildPredicateIndexKey(alias, targetType)
|
|
2188
|
-
) ?? EMPTY_PREDICATES;
|
|
2189
|
-
}
|
|
2190
|
-
function compilePredicateClauses(predicates, predicateContext) {
|
|
2191
|
-
return predicates.map(
|
|
2192
|
-
(predicate2) => compilePredicateExpression(predicate2.expression, predicateContext)
|
|
2193
|
-
);
|
|
2194
|
-
}
|
|
2195
|
-
function compileKindFilter(column, kinds) {
|
|
2196
|
-
if (kinds.length === 0) {
|
|
2197
|
-
return drizzleOrm.sql`1 = 0`;
|
|
2198
|
-
}
|
|
2199
|
-
if (kinds.length === 1) {
|
|
2200
|
-
return drizzleOrm.sql`${column} = ${kinds[0]}`;
|
|
2201
|
-
}
|
|
2202
|
-
return drizzleOrm.sql`${column} IN (${drizzleOrm.sql.join(
|
|
2203
|
-
kinds.map((kind) => drizzleOrm.sql`${kind}`),
|
|
2204
|
-
drizzleOrm.sql`, `
|
|
2205
|
-
)})`;
|
|
2206
|
-
}
|
|
2207
|
-
function getNodeKindsForAlias(ast, alias) {
|
|
2208
|
-
if (alias === ast.start.alias) {
|
|
2209
|
-
return ast.start.kinds;
|
|
2210
|
-
}
|
|
2211
|
-
for (const traversal of ast.traversals) {
|
|
2212
|
-
if (traversal.nodeAlias === alias) {
|
|
2213
|
-
return traversal.nodeKinds;
|
|
2214
|
-
}
|
|
2215
|
-
}
|
|
2216
|
-
throw new chunk44SXEVF4_cjs.CompilerInvariantError(`Unknown traversal source alias: ${alias}`);
|
|
2217
|
-
}
|
|
2218
1783
|
|
|
2219
1784
|
// src/query/compiler/typed-json-extract.ts
|
|
2220
1785
|
function compileTypedJsonExtract(input) {
|
|
@@ -2804,254 +2369,695 @@ function buildLimitOffsetClause(input) {
|
|
|
2804
2369
|
return parts.length > 0 ? drizzleOrm.sql.join(parts, drizzleOrm.sql` `) : void 0;
|
|
2805
2370
|
}
|
|
2806
2371
|
|
|
2807
|
-
// src/query/compiler/recursive.ts
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2372
|
+
// src/query/compiler/passes/recursive.ts
|
|
2373
|
+
function runRecursiveTraversalSelectionPass(ast) {
|
|
2374
|
+
const variableLengthTraversal = ast.traversals.find(
|
|
2375
|
+
(traversal) => traversal.variableLength !== void 0
|
|
2376
|
+
);
|
|
2377
|
+
if (variableLengthTraversal === void 0) {
|
|
2378
|
+
throw new chunk44SXEVF4_cjs.CompilerInvariantError("No variable-length traversal found");
|
|
2379
|
+
}
|
|
2380
|
+
if (ast.traversals.length > 1) {
|
|
2381
|
+
throw new chunk44SXEVF4_cjs.UnsupportedPredicateError(
|
|
2382
|
+
"Variable-length traversals with multiple traversals are not yet supported. Please use a single variable-length traversal."
|
|
2383
|
+
);
|
|
2384
|
+
}
|
|
2385
|
+
return variableLengthTraversal;
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2388
|
+
// src/query/compiler/passes/runner.ts
|
|
2389
|
+
function runCompilerPass(state, pass) {
|
|
2390
|
+
const output = pass.execute(state);
|
|
2391
|
+
return {
|
|
2392
|
+
state: pass.update(state, output)
|
|
2820
2393
|
};
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2394
|
+
}
|
|
2395
|
+
function compileTemporalFilter(options) {
|
|
2396
|
+
const { mode, asOf, tableAlias, currentTimestamp } = options;
|
|
2397
|
+
const prefix = tableAlias ? drizzleOrm.sql.raw(`${tableAlias}.`) : drizzleOrm.sql.raw("");
|
|
2398
|
+
const deletedAt = drizzleOrm.sql`${prefix}deleted_at`;
|
|
2399
|
+
const validFrom = drizzleOrm.sql`${prefix}valid_from`;
|
|
2400
|
+
const validTo = drizzleOrm.sql`${prefix}valid_to`;
|
|
2401
|
+
switch (mode) {
|
|
2402
|
+
case "current": {
|
|
2403
|
+
const now = currentTimestamp ?? drizzleOrm.sql`CURRENT_TIMESTAMP`;
|
|
2404
|
+
return drizzleOrm.sql`${deletedAt} IS NULL AND (${validFrom} IS NULL OR ${validFrom} <= ${now}) AND (${validTo} IS NULL OR ${validTo} > ${now})`;
|
|
2831
2405
|
}
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
name: "temporal_filters",
|
|
2836
|
-
execute(currentState) {
|
|
2837
|
-
return createTemporalFilterPass(
|
|
2838
|
-
currentState.ast,
|
|
2839
|
-
currentState.ctx.dialect.currentTimestamp()
|
|
2840
|
-
);
|
|
2841
|
-
},
|
|
2842
|
-
update(currentState, temporalFilterPass) {
|
|
2843
|
-
return {
|
|
2844
|
-
...currentState,
|
|
2845
|
-
temporalFilterPass
|
|
2846
|
-
};
|
|
2406
|
+
case "asOf": {
|
|
2407
|
+
const timestamp = asOf;
|
|
2408
|
+
return drizzleOrm.sql`${deletedAt} IS NULL AND (${validFrom} IS NULL OR ${validFrom} <= ${timestamp}) AND (${validTo} IS NULL OR ${validTo} > ${timestamp})`;
|
|
2847
2409
|
}
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
const columnPruningPass = runCompilerPass(state, {
|
|
2851
|
-
name: "column_pruning",
|
|
2852
|
-
execute(currentState) {
|
|
2853
|
-
const traversal = currentState.traversal;
|
|
2854
|
-
if (traversal === void 0) {
|
|
2855
|
-
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
2856
|
-
"Recursive traversal pass did not select traversal"
|
|
2857
|
-
);
|
|
2858
|
-
}
|
|
2859
|
-
return collectRequiredColumnsByAlias(currentState.ast, traversal);
|
|
2860
|
-
},
|
|
2861
|
-
update(currentState, requiredColumnsByAlias) {
|
|
2862
|
-
return {
|
|
2863
|
-
...currentState,
|
|
2864
|
-
requiredColumnsByAlias
|
|
2865
|
-
};
|
|
2410
|
+
case "includeEnded": {
|
|
2411
|
+
return drizzleOrm.sql`${deletedAt} IS NULL`;
|
|
2866
2412
|
}
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
const logicalPlanPass = runCompilerPass(state, {
|
|
2870
|
-
name: "logical_plan",
|
|
2871
|
-
execute(currentState) {
|
|
2872
|
-
const loweringInput = {
|
|
2873
|
-
ast: currentState.ast,
|
|
2874
|
-
dialect: currentState.ctx.dialect.name,
|
|
2875
|
-
graphId: currentState.graphId,
|
|
2876
|
-
...currentState.traversal === void 0 ? {} : { traversal: currentState.traversal }
|
|
2877
|
-
};
|
|
2878
|
-
return lowerRecursiveQueryToLogicalPlan(loweringInput);
|
|
2879
|
-
},
|
|
2880
|
-
update(currentState, logicalPlan) {
|
|
2881
|
-
return {
|
|
2882
|
-
...currentState,
|
|
2883
|
-
logicalPlan
|
|
2884
|
-
};
|
|
2413
|
+
case "includeTombstones": {
|
|
2414
|
+
return drizzleOrm.sql.raw("1=1");
|
|
2885
2415
|
}
|
|
2886
|
-
}
|
|
2887
|
-
state = logicalPlanPass.state;
|
|
2888
|
-
return state;
|
|
2416
|
+
}
|
|
2889
2417
|
}
|
|
2890
|
-
function
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2418
|
+
function extractTemporalOptions(ast, tableAlias) {
|
|
2419
|
+
return {
|
|
2420
|
+
mode: ast.temporalMode.mode,
|
|
2421
|
+
asOf: ast.temporalMode.asOf,
|
|
2422
|
+
tableAlias
|
|
2423
|
+
};
|
|
2894
2424
|
}
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2425
|
+
|
|
2426
|
+
// src/query/compiler/passes/temporal.ts
|
|
2427
|
+
function createTemporalFilterPass(ast, currentTimestamp) {
|
|
2428
|
+
return {
|
|
2429
|
+
forAlias(tableAlias) {
|
|
2430
|
+
return compileTemporalFilter({
|
|
2431
|
+
...extractTemporalOptions(ast, tableAlias),
|
|
2432
|
+
currentTimestamp
|
|
2433
|
+
});
|
|
2434
|
+
}
|
|
2435
|
+
};
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2438
|
+
// src/query/compiler/passes/vector.ts
|
|
2439
|
+
function runVectorPredicatePass(ast, dialect) {
|
|
2440
|
+
const vectorPredicates = extractVectorSimilarityPredicates(ast.predicates);
|
|
2441
|
+
if (vectorPredicates.length > 1) {
|
|
2442
|
+
throw new chunk44SXEVF4_cjs.UnsupportedPredicateError(
|
|
2443
|
+
"Multiple vector similarity predicates in a single query are not supported"
|
|
2910
2444
|
);
|
|
2911
2445
|
}
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
);
|
|
2446
|
+
const vectorPredicate = vectorPredicates[0];
|
|
2447
|
+
if (vectorPredicate === void 0) {
|
|
2448
|
+
return { vectorPredicate: void 0 };
|
|
2916
2449
|
}
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2450
|
+
const vectorStrategy = dialect.capabilities.vectorPredicateStrategy;
|
|
2451
|
+
if (vectorStrategy === "unsupported" || !dialect.supportsVectors) {
|
|
2452
|
+
throw new chunk44SXEVF4_cjs.UnsupportedPredicateError(
|
|
2453
|
+
`Vector similarity predicates are not supported for dialect "${dialect.name}"`
|
|
2920
2454
|
);
|
|
2921
2455
|
}
|
|
2922
|
-
|
|
2923
|
-
ast,
|
|
2924
|
-
vlTraversal,
|
|
2925
|
-
graphId,
|
|
2926
|
-
ctx,
|
|
2927
|
-
requiredColumnsByAlias,
|
|
2928
|
-
temporalFilterPass
|
|
2929
|
-
);
|
|
2930
|
-
const projection = compileRecursiveProjection(ast, vlTraversal, dialect);
|
|
2931
|
-
const minDepth = vlTraversal.variableLength.minDepth;
|
|
2932
|
-
const depthFilter = minDepth > 0 ? drizzleOrm.sql`WHERE depth >= ${minDepth}` : drizzleOrm.sql.raw("");
|
|
2933
|
-
const orderBy = compileRecursiveOrderBy(ast, dialect);
|
|
2934
|
-
const limitOffset = compileLimitOffset(ast);
|
|
2935
|
-
return emitRecursiveQuerySql({
|
|
2936
|
-
depthFilter,
|
|
2937
|
-
...limitOffset === void 0 ? {} : { limitOffset },
|
|
2938
|
-
logicalPlan,
|
|
2939
|
-
...orderBy === void 0 ? {} : { orderBy },
|
|
2940
|
-
projection,
|
|
2941
|
-
recursiveCte
|
|
2942
|
-
});
|
|
2943
|
-
}
|
|
2944
|
-
function hasVariableLengthTraversal(ast) {
|
|
2945
|
-
return ast.traversals.some((t) => t.variableLength !== void 0);
|
|
2946
|
-
}
|
|
2947
|
-
function compileRecursiveCte(ast, traversal, graphId, ctx, requiredColumnsByAlias, temporalFilterPass) {
|
|
2948
|
-
const { dialect } = ctx;
|
|
2949
|
-
const startAlias = ast.start.alias;
|
|
2950
|
-
const startKinds = ast.start.kinds;
|
|
2951
|
-
const nodeAlias = traversal.nodeAlias;
|
|
2952
|
-
const directEdgeKinds = [...new Set(traversal.edgeKinds)];
|
|
2953
|
-
const inverseEdgeKinds = traversal.inverseEdgeKinds === void 0 ? [] : [...new Set(traversal.inverseEdgeKinds)];
|
|
2954
|
-
const forceWorktableOuterJoinOrder = dialect.capabilities.forceRecursiveWorktableOuterJoinOrder;
|
|
2955
|
-
const nodeKinds = traversal.nodeKinds;
|
|
2956
|
-
const previousNodeKinds = [.../* @__PURE__ */ new Set([...startKinds, ...nodeKinds])];
|
|
2957
|
-
const direction = traversal.direction;
|
|
2958
|
-
const vl = traversal.variableLength;
|
|
2959
|
-
const shouldEnforceCycleCheck = vl.cyclePolicy !== "allow";
|
|
2960
|
-
const shouldTrackPath = shouldEnforceCycleCheck || vl.pathAlias !== void 0;
|
|
2961
|
-
const recursiveJoinRequiredColumns = /* @__PURE__ */ new Set(["id"]);
|
|
2962
|
-
if (previousNodeKinds.length > 1) {
|
|
2963
|
-
recursiveJoinRequiredColumns.add("kind");
|
|
2964
|
-
}
|
|
2965
|
-
const requiredStartColumns = requiredColumnsByAlias ? requiredColumnsByAlias.get(startAlias) ?? EMPTY_REQUIRED_COLUMNS : void 0;
|
|
2966
|
-
const requiredNodeColumns = requiredColumnsByAlias ? requiredColumnsByAlias.get(nodeAlias) ?? EMPTY_REQUIRED_COLUMNS : void 0;
|
|
2967
|
-
const startColumnsFromBase = compileNodeSelectColumnsFromTable(
|
|
2968
|
-
"n0",
|
|
2969
|
-
startAlias,
|
|
2970
|
-
requiredStartColumns,
|
|
2971
|
-
NO_ALWAYS_REQUIRED_COLUMNS
|
|
2972
|
-
);
|
|
2973
|
-
const startColumnsFromRecursive = compileNodeSelectColumnsFromRecursiveRow(
|
|
2974
|
-
startAlias,
|
|
2975
|
-
requiredStartColumns,
|
|
2976
|
-
NO_ALWAYS_REQUIRED_COLUMNS
|
|
2977
|
-
);
|
|
2978
|
-
const nodeColumnsFromBase = compileNodeSelectColumnsFromTable(
|
|
2979
|
-
"n0",
|
|
2980
|
-
nodeAlias,
|
|
2981
|
-
requiredNodeColumns,
|
|
2982
|
-
recursiveJoinRequiredColumns
|
|
2983
|
-
);
|
|
2984
|
-
const nodeColumnsFromRecursive = compileNodeSelectColumnsFromTable(
|
|
2985
|
-
"n",
|
|
2986
|
-
nodeAlias,
|
|
2987
|
-
requiredNodeColumns,
|
|
2988
|
-
recursiveJoinRequiredColumns
|
|
2989
|
-
);
|
|
2990
|
-
const startKindFilter = compileKindFilter2(startKinds, "n0.kind");
|
|
2991
|
-
const nodeKindFilter = compileKindFilter2(nodeKinds, "n.kind");
|
|
2992
|
-
const startTemporalFilter = temporalFilterPass.forAlias("n0");
|
|
2993
|
-
const edgeTemporalFilter = temporalFilterPass.forAlias("e");
|
|
2994
|
-
const nodeTemporalFilter = temporalFilterPass.forAlias("n");
|
|
2995
|
-
const startContext = { ...ctx, cteColumnPrefix: "" };
|
|
2996
|
-
const startPredicates = compileNodePredicates(ast, startAlias, startContext);
|
|
2997
|
-
const edgeContext = { ...ctx, cteColumnPrefix: "e" };
|
|
2998
|
-
const edgePredicates = compileEdgePredicates(
|
|
2999
|
-
ast,
|
|
3000
|
-
traversal.edgeAlias,
|
|
3001
|
-
edgeContext
|
|
3002
|
-
);
|
|
3003
|
-
const targetContext = { ...ctx, cteColumnPrefix: "n" };
|
|
3004
|
-
const targetNodePredicates = compileNodePredicates(
|
|
3005
|
-
ast,
|
|
3006
|
-
nodeAlias,
|
|
3007
|
-
targetContext
|
|
3008
|
-
);
|
|
3009
|
-
if (vl.maxDepth > MAX_EXPLICIT_RECURSIVE_DEPTH) {
|
|
2456
|
+
if (!dialect.capabilities.vectorMetrics.includes(vectorPredicate.metric)) {
|
|
3010
2457
|
throw new chunk44SXEVF4_cjs.UnsupportedPredicateError(
|
|
3011
|
-
`
|
|
2458
|
+
`Vector metric "${vectorPredicate.metric}" is not supported for dialect "${dialect.name}"`
|
|
3012
2459
|
);
|
|
3013
2460
|
}
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
const pathExtension = shouldTrackPath ? dialect.extendPath(drizzleOrm.sql.raw("r.path"), drizzleOrm.sql.raw("n.id")) : void 0;
|
|
3019
|
-
const baseWhereClauses = [
|
|
3020
|
-
drizzleOrm.sql`n0.graph_id = ${graphId}`,
|
|
3021
|
-
startKindFilter,
|
|
3022
|
-
startTemporalFilter,
|
|
3023
|
-
...startPredicates
|
|
3024
|
-
];
|
|
3025
|
-
const recursiveBaseWhereClauses = [
|
|
3026
|
-
drizzleOrm.sql`e.graph_id = ${graphId}`,
|
|
3027
|
-
nodeKindFilter,
|
|
3028
|
-
edgeTemporalFilter,
|
|
3029
|
-
nodeTemporalFilter,
|
|
3030
|
-
maxDepthCondition
|
|
3031
|
-
];
|
|
3032
|
-
if (cycleCheck !== void 0) {
|
|
3033
|
-
recursiveBaseWhereClauses.push(cycleCheck);
|
|
2461
|
+
if (!Number.isFinite(vectorPredicate.limit) || vectorPredicate.limit <= 0) {
|
|
2462
|
+
throw new chunk44SXEVF4_cjs.UnsupportedPredicateError(
|
|
2463
|
+
`Vector predicate limit must be a positive finite number, got ${String(vectorPredicate.limit)}`
|
|
2464
|
+
);
|
|
3034
2465
|
}
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
compileKindFilter2(nodeKinds, `e.${branch.targetKindField}`)
|
|
3042
|
-
];
|
|
3043
|
-
if (branch.duplicateGuard !== void 0) {
|
|
3044
|
-
recursiveFilterClauses.push(branch.duplicateGuard);
|
|
2466
|
+
const { minScore } = vectorPredicate;
|
|
2467
|
+
if (minScore !== void 0) {
|
|
2468
|
+
if (!Number.isFinite(minScore)) {
|
|
2469
|
+
throw new chunk44SXEVF4_cjs.UnsupportedPredicateError(
|
|
2470
|
+
`Vector minScore must be a finite number, got ${String(minScore)}`
|
|
2471
|
+
);
|
|
3045
2472
|
}
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
];
|
|
3051
|
-
if (pathExtension !== void 0) {
|
|
3052
|
-
recursiveSelectColumns.push(drizzleOrm.sql`${pathExtension} AS path`);
|
|
2473
|
+
if (vectorPredicate.metric === "cosine" && (minScore < -1 || minScore > 1)) {
|
|
2474
|
+
throw new chunk44SXEVF4_cjs.UnsupportedPredicateError(
|
|
2475
|
+
`Cosine minScore must be between -1 and 1, got ${String(minScore)}`
|
|
2476
|
+
);
|
|
3053
2477
|
}
|
|
3054
|
-
|
|
2478
|
+
}
|
|
2479
|
+
return { vectorPredicate };
|
|
2480
|
+
}
|
|
2481
|
+
function resolveVectorAwareLimit(astLimit, vectorPredicate) {
|
|
2482
|
+
if (vectorPredicate === void 0) {
|
|
2483
|
+
return astLimit;
|
|
2484
|
+
}
|
|
2485
|
+
if (astLimit === void 0) {
|
|
2486
|
+
return vectorPredicate.limit;
|
|
2487
|
+
}
|
|
2488
|
+
return Math.min(astLimit, vectorPredicate.limit);
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2491
|
+
// src/query/compiler/plan/lowering.ts
|
|
2492
|
+
function createPlanNodeIdFactory() {
|
|
2493
|
+
let current = 0;
|
|
2494
|
+
return function nextPlanNodeId() {
|
|
2495
|
+
current += 1;
|
|
2496
|
+
return `plan_${current.toString(36)}`;
|
|
2497
|
+
};
|
|
2498
|
+
}
|
|
2499
|
+
function extractAggregateExpressions(ast) {
|
|
2500
|
+
const aggregates = [];
|
|
2501
|
+
for (const field2 of ast.projection.fields) {
|
|
2502
|
+
if ("__type" in field2.source && field2.source.__type === "aggregate") {
|
|
2503
|
+
aggregates.push(field2.source);
|
|
2504
|
+
}
|
|
2505
|
+
}
|
|
2506
|
+
return aggregates;
|
|
2507
|
+
}
|
|
2508
|
+
function getAliasPredicates(ast, alias, predicateTargetType) {
|
|
2509
|
+
return ast.predicates.filter((predicate2) => {
|
|
2510
|
+
const targetType = predicate2.targetType ?? "node";
|
|
2511
|
+
return predicate2.targetAlias === alias && targetType === predicateTargetType;
|
|
2512
|
+
});
|
|
2513
|
+
}
|
|
2514
|
+
function wrapWithAliasFilterNode(currentNode, ast, alias, predicateTargetType, nextPlanNodeId) {
|
|
2515
|
+
const aliasPredicates = getAliasPredicates(ast, alias, predicateTargetType);
|
|
2516
|
+
if (aliasPredicates.length === 0) {
|
|
2517
|
+
return currentNode;
|
|
2518
|
+
}
|
|
2519
|
+
return {
|
|
2520
|
+
alias,
|
|
2521
|
+
id: nextPlanNodeId(),
|
|
2522
|
+
input: currentNode,
|
|
2523
|
+
op: "filter",
|
|
2524
|
+
predicateTargetType,
|
|
2525
|
+
predicates: aliasPredicates.map((predicate2) => predicate2.expression)
|
|
2526
|
+
};
|
|
2527
|
+
}
|
|
2528
|
+
function appendAggregateSortLimitAndProjectNodes(currentNode, ast, nextPlanNodeId, limit, collapsedTraversalCteAlias) {
|
|
2529
|
+
let node = currentNode;
|
|
2530
|
+
const aggregateExpressions = extractAggregateExpressions(ast);
|
|
2531
|
+
if (aggregateExpressions.length > 0 || ast.groupBy !== void 0 || ast.having !== void 0) {
|
|
2532
|
+
const aggregateNode = {
|
|
2533
|
+
aggregates: aggregateExpressions,
|
|
2534
|
+
groupBy: ast.groupBy?.fields ?? [],
|
|
2535
|
+
id: nextPlanNodeId(),
|
|
2536
|
+
input: node,
|
|
2537
|
+
op: "aggregate"
|
|
2538
|
+
};
|
|
2539
|
+
node = ast.having === void 0 ? aggregateNode : { ...aggregateNode, having: ast.having };
|
|
2540
|
+
}
|
|
2541
|
+
if (ast.orderBy !== void 0 && ast.orderBy.length > 0) {
|
|
2542
|
+
node = {
|
|
2543
|
+
id: nextPlanNodeId(),
|
|
2544
|
+
input: node,
|
|
2545
|
+
op: "sort",
|
|
2546
|
+
orderBy: ast.orderBy
|
|
2547
|
+
};
|
|
2548
|
+
}
|
|
2549
|
+
if (limit !== void 0 || ast.offset !== void 0) {
|
|
2550
|
+
const limitOffsetNodeBase = {
|
|
2551
|
+
id: nextPlanNodeId(),
|
|
2552
|
+
input: node,
|
|
2553
|
+
op: "limit_offset"
|
|
2554
|
+
};
|
|
2555
|
+
const hasLimit = limit !== void 0;
|
|
2556
|
+
const hasOffset = ast.offset !== void 0;
|
|
2557
|
+
if (hasLimit && hasOffset) {
|
|
2558
|
+
node = {
|
|
2559
|
+
...limitOffsetNodeBase,
|
|
2560
|
+
limit,
|
|
2561
|
+
offset: ast.offset
|
|
2562
|
+
};
|
|
2563
|
+
} else if (hasLimit) {
|
|
2564
|
+
node = { ...limitOffsetNodeBase, limit };
|
|
2565
|
+
} else if (hasOffset) {
|
|
2566
|
+
node = { ...limitOffsetNodeBase, offset: ast.offset };
|
|
2567
|
+
} else {
|
|
2568
|
+
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
2569
|
+
"limit_offset node requires limit or offset to be present"
|
|
2570
|
+
);
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
const projectNodeBase = {
|
|
2574
|
+
fields: ast.projection.fields,
|
|
2575
|
+
id: nextPlanNodeId(),
|
|
2576
|
+
input: node,
|
|
2577
|
+
op: "project"
|
|
2578
|
+
};
|
|
2579
|
+
return collapsedTraversalCteAlias === void 0 ? projectNodeBase : {
|
|
2580
|
+
...projectNodeBase,
|
|
2581
|
+
collapsedTraversalAlias: collapsedTraversalCteAlias
|
|
2582
|
+
};
|
|
2583
|
+
}
|
|
2584
|
+
function lowerStandardQueryToLogicalPlanNode(input) {
|
|
2585
|
+
const { ast, nextPlanNodeId } = input;
|
|
2586
|
+
let currentNode = {
|
|
2587
|
+
alias: ast.start.alias,
|
|
2588
|
+
graphId: input.graphId,
|
|
2589
|
+
id: nextPlanNodeId(),
|
|
2590
|
+
kinds: ast.start.kinds,
|
|
2591
|
+
op: "scan",
|
|
2592
|
+
source: "nodes"
|
|
2593
|
+
};
|
|
2594
|
+
currentNode = wrapWithAliasFilterNode(
|
|
2595
|
+
currentNode,
|
|
2596
|
+
ast,
|
|
2597
|
+
ast.start.alias,
|
|
2598
|
+
"node",
|
|
2599
|
+
nextPlanNodeId
|
|
2600
|
+
);
|
|
2601
|
+
for (const traversal of ast.traversals) {
|
|
2602
|
+
currentNode = {
|
|
2603
|
+
direction: traversal.direction,
|
|
2604
|
+
edgeAlias: traversal.edgeAlias,
|
|
2605
|
+
edgeKinds: traversal.edgeKinds,
|
|
2606
|
+
id: nextPlanNodeId(),
|
|
2607
|
+
input: currentNode,
|
|
2608
|
+
inverseEdgeKinds: traversal.inverseEdgeKinds ?? [],
|
|
2609
|
+
joinFromAlias: traversal.joinFromAlias,
|
|
2610
|
+
joinType: traversal.optional ? "left" : "inner",
|
|
2611
|
+
nodeAlias: traversal.nodeAlias,
|
|
2612
|
+
nodeKinds: traversal.nodeKinds,
|
|
2613
|
+
op: "join"
|
|
2614
|
+
};
|
|
2615
|
+
currentNode = wrapWithAliasFilterNode(
|
|
2616
|
+
currentNode,
|
|
2617
|
+
ast,
|
|
2618
|
+
traversal.edgeAlias,
|
|
2619
|
+
"edge",
|
|
2620
|
+
nextPlanNodeId
|
|
2621
|
+
);
|
|
2622
|
+
currentNode = wrapWithAliasFilterNode(
|
|
2623
|
+
currentNode,
|
|
2624
|
+
ast,
|
|
2625
|
+
traversal.nodeAlias,
|
|
2626
|
+
"node",
|
|
2627
|
+
nextPlanNodeId
|
|
2628
|
+
);
|
|
2629
|
+
}
|
|
2630
|
+
if (input.vectorPredicate !== void 0) {
|
|
2631
|
+
currentNode = {
|
|
2632
|
+
id: nextPlanNodeId(),
|
|
2633
|
+
input: currentNode,
|
|
2634
|
+
op: "vector_knn",
|
|
2635
|
+
predicate: input.vectorPredicate
|
|
2636
|
+
};
|
|
2637
|
+
}
|
|
2638
|
+
return appendAggregateSortLimitAndProjectNodes(
|
|
2639
|
+
currentNode,
|
|
2640
|
+
ast,
|
|
2641
|
+
nextPlanNodeId,
|
|
2642
|
+
input.effectiveLimit,
|
|
2643
|
+
input.collapsedTraversalCteAlias
|
|
2644
|
+
);
|
|
2645
|
+
}
|
|
2646
|
+
function lowerRecursiveQueryToLogicalPlanNode(input) {
|
|
2647
|
+
const { ast, nextPlanNodeId } = input;
|
|
2648
|
+
const traversal = input.traversal ?? runRecursiveTraversalSelectionPass(input.ast);
|
|
2649
|
+
let currentNode = {
|
|
2650
|
+
alias: ast.start.alias,
|
|
2651
|
+
graphId: input.graphId,
|
|
2652
|
+
id: nextPlanNodeId(),
|
|
2653
|
+
kinds: ast.start.kinds,
|
|
2654
|
+
op: "scan",
|
|
2655
|
+
source: "nodes"
|
|
2656
|
+
};
|
|
2657
|
+
currentNode = wrapWithAliasFilterNode(
|
|
2658
|
+
currentNode,
|
|
2659
|
+
ast,
|
|
2660
|
+
ast.start.alias,
|
|
2661
|
+
"node",
|
|
2662
|
+
nextPlanNodeId
|
|
2663
|
+
);
|
|
2664
|
+
currentNode = {
|
|
2665
|
+
edgeAlias: traversal.edgeAlias,
|
|
2666
|
+
edgeKinds: traversal.edgeKinds,
|
|
2667
|
+
id: nextPlanNodeId(),
|
|
2668
|
+
input: currentNode,
|
|
2669
|
+
inverseEdgeKinds: traversal.inverseEdgeKinds ?? [],
|
|
2670
|
+
nodeAlias: traversal.nodeAlias,
|
|
2671
|
+
nodeKinds: traversal.nodeKinds,
|
|
2672
|
+
op: "recursive_expand",
|
|
2673
|
+
traversal: traversal.variableLength
|
|
2674
|
+
};
|
|
2675
|
+
currentNode = wrapWithAliasFilterNode(
|
|
2676
|
+
currentNode,
|
|
2677
|
+
ast,
|
|
2678
|
+
traversal.edgeAlias,
|
|
2679
|
+
"edge",
|
|
2680
|
+
nextPlanNodeId
|
|
2681
|
+
);
|
|
2682
|
+
currentNode = wrapWithAliasFilterNode(
|
|
2683
|
+
currentNode,
|
|
2684
|
+
ast,
|
|
2685
|
+
traversal.nodeAlias,
|
|
2686
|
+
"node",
|
|
2687
|
+
nextPlanNodeId
|
|
2688
|
+
);
|
|
2689
|
+
return appendAggregateSortLimitAndProjectNodes(
|
|
2690
|
+
currentNode,
|
|
2691
|
+
ast,
|
|
2692
|
+
nextPlanNodeId,
|
|
2693
|
+
ast.limit
|
|
2694
|
+
);
|
|
2695
|
+
}
|
|
2696
|
+
function lowerComposableQueryToLogicalPlanNode(query, dialect, graphId, nextPlanNodeId) {
|
|
2697
|
+
if ("__type" in query) {
|
|
2698
|
+
return lowerSetOperationToLogicalPlanNode(
|
|
2699
|
+
query,
|
|
2700
|
+
graphId,
|
|
2701
|
+
dialect,
|
|
2702
|
+
nextPlanNodeId
|
|
2703
|
+
);
|
|
2704
|
+
}
|
|
2705
|
+
const hasVariableLengthTraversal2 = query.traversals.some(
|
|
2706
|
+
(traversal) => traversal.variableLength !== void 0
|
|
2707
|
+
);
|
|
2708
|
+
if (hasVariableLengthTraversal2) {
|
|
2709
|
+
return lowerRecursiveQueryToLogicalPlanNode({
|
|
2710
|
+
ast: query,
|
|
2711
|
+
graphId,
|
|
2712
|
+
nextPlanNodeId
|
|
2713
|
+
});
|
|
2714
|
+
}
|
|
2715
|
+
const vectorPredicate = runVectorPredicatePass(
|
|
2716
|
+
query,
|
|
2717
|
+
chunk2WVFEIHR_cjs.getDialect(dialect)
|
|
2718
|
+
).vectorPredicate;
|
|
2719
|
+
const effectiveLimit = resolveVectorAwareLimit(query.limit, vectorPredicate);
|
|
2720
|
+
const loweringInput = {
|
|
2721
|
+
ast: query,
|
|
2722
|
+
graphId,
|
|
2723
|
+
nextPlanNodeId,
|
|
2724
|
+
...effectiveLimit === void 0 ? {} : { effectiveLimit },
|
|
2725
|
+
...vectorPredicate === void 0 ? {} : { vectorPredicate }
|
|
2726
|
+
};
|
|
2727
|
+
return lowerStandardQueryToLogicalPlanNode(loweringInput);
|
|
2728
|
+
}
|
|
2729
|
+
function lowerSetOperationToLogicalPlanNode(op, graphId, dialect, nextPlanNodeId) {
|
|
2730
|
+
let currentNode = {
|
|
2731
|
+
id: nextPlanNodeId(),
|
|
2732
|
+
left: lowerComposableQueryToLogicalPlanNode(
|
|
2733
|
+
op.left,
|
|
2734
|
+
dialect,
|
|
2735
|
+
graphId,
|
|
2736
|
+
nextPlanNodeId
|
|
2737
|
+
),
|
|
2738
|
+
op: "set_op",
|
|
2739
|
+
operator: op.operator,
|
|
2740
|
+
right: lowerComposableQueryToLogicalPlanNode(
|
|
2741
|
+
op.right,
|
|
2742
|
+
dialect,
|
|
2743
|
+
graphId,
|
|
2744
|
+
nextPlanNodeId
|
|
2745
|
+
)
|
|
2746
|
+
};
|
|
2747
|
+
if (op.orderBy !== void 0 && op.orderBy.length > 0) {
|
|
2748
|
+
currentNode = {
|
|
2749
|
+
id: nextPlanNodeId(),
|
|
2750
|
+
input: currentNode,
|
|
2751
|
+
op: "sort",
|
|
2752
|
+
orderBy: op.orderBy
|
|
2753
|
+
};
|
|
2754
|
+
}
|
|
2755
|
+
if (op.limit !== void 0 || op.offset !== void 0) {
|
|
2756
|
+
const limitOffsetBase = {
|
|
2757
|
+
id: nextPlanNodeId(),
|
|
2758
|
+
input: currentNode,
|
|
2759
|
+
op: "limit_offset"
|
|
2760
|
+
};
|
|
2761
|
+
if (op.limit !== void 0 && op.offset !== void 0) {
|
|
2762
|
+
currentNode = { ...limitOffsetBase, limit: op.limit, offset: op.offset };
|
|
2763
|
+
} else if (op.limit === void 0) {
|
|
2764
|
+
currentNode = { ...limitOffsetBase, offset: op.offset };
|
|
2765
|
+
} else {
|
|
2766
|
+
currentNode = { ...limitOffsetBase, limit: op.limit };
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
return currentNode;
|
|
2770
|
+
}
|
|
2771
|
+
function lowerStandardQueryToLogicalPlan(input) {
|
|
2772
|
+
const nextPlanNodeId = createPlanNodeIdFactory();
|
|
2773
|
+
return {
|
|
2774
|
+
metadata: {
|
|
2775
|
+
dialect: input.dialect,
|
|
2776
|
+
graphId: input.graphId
|
|
2777
|
+
},
|
|
2778
|
+
root: lowerStandardQueryToLogicalPlanNode({
|
|
2779
|
+
...input,
|
|
2780
|
+
nextPlanNodeId
|
|
2781
|
+
})
|
|
2782
|
+
};
|
|
2783
|
+
}
|
|
2784
|
+
function lowerRecursiveQueryToLogicalPlan(input) {
|
|
2785
|
+
const nextPlanNodeId = createPlanNodeIdFactory();
|
|
2786
|
+
return {
|
|
2787
|
+
metadata: {
|
|
2788
|
+
dialect: input.dialect,
|
|
2789
|
+
graphId: input.graphId
|
|
2790
|
+
},
|
|
2791
|
+
root: lowerRecursiveQueryToLogicalPlanNode({
|
|
2792
|
+
...input,
|
|
2793
|
+
nextPlanNodeId
|
|
2794
|
+
})
|
|
2795
|
+
};
|
|
2796
|
+
}
|
|
2797
|
+
function lowerSetOperationToLogicalPlan(input) {
|
|
2798
|
+
const nextPlanNodeId = createPlanNodeIdFactory();
|
|
2799
|
+
return {
|
|
2800
|
+
metadata: {
|
|
2801
|
+
dialect: input.dialect,
|
|
2802
|
+
graphId: input.graphId
|
|
2803
|
+
},
|
|
2804
|
+
root: lowerSetOperationToLogicalPlanNode(
|
|
2805
|
+
input.op,
|
|
2806
|
+
input.graphId,
|
|
2807
|
+
input.dialect,
|
|
2808
|
+
nextPlanNodeId
|
|
2809
|
+
)
|
|
2810
|
+
};
|
|
2811
|
+
}
|
|
2812
|
+
|
|
2813
|
+
// src/query/compiler/recursive.ts
|
|
2814
|
+
var MAX_RECURSIVE_DEPTH = 100;
|
|
2815
|
+
var MAX_EXPLICIT_RECURSIVE_DEPTH = 1e3;
|
|
2816
|
+
var NO_ALWAYS_REQUIRED_COLUMNS = /* @__PURE__ */ new Set();
|
|
2817
|
+
function runRecursiveQueryPassPipeline(ast, graphId, ctx) {
|
|
2818
|
+
let state = {
|
|
2819
|
+
ast,
|
|
2820
|
+
ctx,
|
|
2821
|
+
graphId,
|
|
2822
|
+
logicalPlan: void 0,
|
|
2823
|
+
requiredColumnsByAlias: void 0,
|
|
2824
|
+
temporalFilterPass: void 0,
|
|
2825
|
+
traversal: void 0
|
|
2826
|
+
};
|
|
2827
|
+
const recursiveTraversalPass = runCompilerPass(state, {
|
|
2828
|
+
name: "recursive_traversal",
|
|
2829
|
+
execute(currentState) {
|
|
2830
|
+
return runRecursiveTraversalSelectionPass(currentState.ast);
|
|
2831
|
+
},
|
|
2832
|
+
update(currentState, traversal) {
|
|
2833
|
+
return {
|
|
2834
|
+
...currentState,
|
|
2835
|
+
traversal
|
|
2836
|
+
};
|
|
2837
|
+
}
|
|
2838
|
+
});
|
|
2839
|
+
state = recursiveTraversalPass.state;
|
|
2840
|
+
const temporalPass = runCompilerPass(state, {
|
|
2841
|
+
name: "temporal_filters",
|
|
2842
|
+
execute(currentState) {
|
|
2843
|
+
return createTemporalFilterPass(
|
|
2844
|
+
currentState.ast,
|
|
2845
|
+
currentState.ctx.dialect.currentTimestamp()
|
|
2846
|
+
);
|
|
2847
|
+
},
|
|
2848
|
+
update(currentState, temporalFilterPass) {
|
|
2849
|
+
return {
|
|
2850
|
+
...currentState,
|
|
2851
|
+
temporalFilterPass
|
|
2852
|
+
};
|
|
2853
|
+
}
|
|
2854
|
+
});
|
|
2855
|
+
state = temporalPass.state;
|
|
2856
|
+
const columnPruningPass = runCompilerPass(state, {
|
|
2857
|
+
name: "column_pruning",
|
|
2858
|
+
execute(currentState) {
|
|
2859
|
+
const traversal = currentState.traversal;
|
|
2860
|
+
if (traversal === void 0) {
|
|
2861
|
+
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
2862
|
+
"Recursive traversal pass did not select traversal"
|
|
2863
|
+
);
|
|
2864
|
+
}
|
|
2865
|
+
return collectRequiredColumnsByAlias(currentState.ast, traversal);
|
|
2866
|
+
},
|
|
2867
|
+
update(currentState, requiredColumnsByAlias) {
|
|
2868
|
+
return {
|
|
2869
|
+
...currentState,
|
|
2870
|
+
requiredColumnsByAlias
|
|
2871
|
+
};
|
|
2872
|
+
}
|
|
2873
|
+
});
|
|
2874
|
+
state = columnPruningPass.state;
|
|
2875
|
+
const logicalPlanPass = runCompilerPass(state, {
|
|
2876
|
+
name: "logical_plan",
|
|
2877
|
+
execute(currentState) {
|
|
2878
|
+
const loweringInput = {
|
|
2879
|
+
ast: currentState.ast,
|
|
2880
|
+
dialect: currentState.ctx.dialect.name,
|
|
2881
|
+
graphId: currentState.graphId,
|
|
2882
|
+
...currentState.traversal === void 0 ? {} : { traversal: currentState.traversal }
|
|
2883
|
+
};
|
|
2884
|
+
return lowerRecursiveQueryToLogicalPlan(loweringInput);
|
|
2885
|
+
},
|
|
2886
|
+
update(currentState, logicalPlan) {
|
|
2887
|
+
return {
|
|
2888
|
+
...currentState,
|
|
2889
|
+
logicalPlan
|
|
2890
|
+
};
|
|
2891
|
+
}
|
|
2892
|
+
});
|
|
2893
|
+
state = logicalPlanPass.state;
|
|
2894
|
+
return state;
|
|
2895
|
+
}
|
|
2896
|
+
function compileVariableLengthQuery(ast, graphId, ctx) {
|
|
2897
|
+
const strategy = ctx.dialect.capabilities.recursiveQueryStrategy;
|
|
2898
|
+
const handler = RECURSIVE_QUERY_STRATEGY_HANDLERS[strategy];
|
|
2899
|
+
return handler(ast, graphId, ctx);
|
|
2900
|
+
}
|
|
2901
|
+
var RECURSIVE_QUERY_STRATEGY_HANDLERS = {
|
|
2902
|
+
recursive_cte: compileVariableLengthQueryWithRecursiveCteStrategy
|
|
2903
|
+
};
|
|
2904
|
+
function compileVariableLengthQueryWithRecursiveCteStrategy(ast, graphId, ctx) {
|
|
2905
|
+
const passState = runRecursiveQueryPassPipeline(ast, graphId, ctx);
|
|
2906
|
+
const { dialect } = ctx;
|
|
2907
|
+
const {
|
|
2908
|
+
logicalPlan,
|
|
2909
|
+
requiredColumnsByAlias,
|
|
2910
|
+
temporalFilterPass,
|
|
2911
|
+
traversal: vlTraversal
|
|
2912
|
+
} = passState;
|
|
2913
|
+
if (temporalFilterPass === void 0) {
|
|
2914
|
+
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
2915
|
+
"Temporal filter pass did not initialize temporal state"
|
|
2916
|
+
);
|
|
2917
|
+
}
|
|
2918
|
+
if (logicalPlan === void 0) {
|
|
2919
|
+
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
2920
|
+
"Logical plan pass did not initialize plan state"
|
|
2921
|
+
);
|
|
2922
|
+
}
|
|
2923
|
+
if (vlTraversal === void 0) {
|
|
2924
|
+
throw new chunk44SXEVF4_cjs.CompilerInvariantError(
|
|
2925
|
+
"Recursive traversal pass did not select traversal"
|
|
2926
|
+
);
|
|
2927
|
+
}
|
|
2928
|
+
const recursiveCte = compileRecursiveCte(
|
|
2929
|
+
ast,
|
|
2930
|
+
vlTraversal,
|
|
2931
|
+
graphId,
|
|
2932
|
+
ctx,
|
|
2933
|
+
requiredColumnsByAlias,
|
|
2934
|
+
temporalFilterPass
|
|
2935
|
+
);
|
|
2936
|
+
const projection = compileRecursiveProjection(ast, vlTraversal, dialect);
|
|
2937
|
+
const minDepth = vlTraversal.variableLength.minDepth;
|
|
2938
|
+
const depthFilter = minDepth > 0 ? drizzleOrm.sql`WHERE depth >= ${minDepth}` : drizzleOrm.sql.raw("");
|
|
2939
|
+
const orderBy = compileRecursiveOrderBy(ast, dialect);
|
|
2940
|
+
const limitOffset = compileLimitOffset(ast);
|
|
2941
|
+
return emitRecursiveQuerySql({
|
|
2942
|
+
depthFilter,
|
|
2943
|
+
...limitOffset === void 0 ? {} : { limitOffset },
|
|
2944
|
+
logicalPlan,
|
|
2945
|
+
...orderBy === void 0 ? {} : { orderBy },
|
|
2946
|
+
projection,
|
|
2947
|
+
recursiveCte
|
|
2948
|
+
});
|
|
2949
|
+
}
|
|
2950
|
+
function hasVariableLengthTraversal(ast) {
|
|
2951
|
+
return ast.traversals.some((t) => t.variableLength !== void 0);
|
|
2952
|
+
}
|
|
2953
|
+
function compileRecursiveCte(ast, traversal, graphId, ctx, requiredColumnsByAlias, temporalFilterPass) {
|
|
2954
|
+
const { dialect } = ctx;
|
|
2955
|
+
const startAlias = ast.start.alias;
|
|
2956
|
+
const startKinds = ast.start.kinds;
|
|
2957
|
+
const nodeAlias = traversal.nodeAlias;
|
|
2958
|
+
const directEdgeKinds = [...new Set(traversal.edgeKinds)];
|
|
2959
|
+
const inverseEdgeKinds = traversal.inverseEdgeKinds === void 0 ? [] : [...new Set(traversal.inverseEdgeKinds)];
|
|
2960
|
+
const forceWorktableOuterJoinOrder = dialect.capabilities.forceRecursiveWorktableOuterJoinOrder;
|
|
2961
|
+
const nodeKinds = traversal.nodeKinds;
|
|
2962
|
+
const previousNodeKinds = [.../* @__PURE__ */ new Set([...startKinds, ...nodeKinds])];
|
|
2963
|
+
const direction = traversal.direction;
|
|
2964
|
+
const vl = traversal.variableLength;
|
|
2965
|
+
const shouldEnforceCycleCheck = vl.cyclePolicy !== "allow";
|
|
2966
|
+
const shouldTrackPath = shouldEnforceCycleCheck || vl.pathAlias !== void 0;
|
|
2967
|
+
const recursiveJoinRequiredColumns = /* @__PURE__ */ new Set(["id"]);
|
|
2968
|
+
if (previousNodeKinds.length > 1) {
|
|
2969
|
+
recursiveJoinRequiredColumns.add("kind");
|
|
2970
|
+
}
|
|
2971
|
+
const requiredStartColumns = requiredColumnsByAlias ? requiredColumnsByAlias.get(startAlias) ?? EMPTY_REQUIRED_COLUMNS : void 0;
|
|
2972
|
+
const requiredNodeColumns = requiredColumnsByAlias ? requiredColumnsByAlias.get(nodeAlias) ?? EMPTY_REQUIRED_COLUMNS : void 0;
|
|
2973
|
+
const startColumnsFromBase = compileNodeSelectColumnsFromTable(
|
|
2974
|
+
"n0",
|
|
2975
|
+
startAlias,
|
|
2976
|
+
requiredStartColumns,
|
|
2977
|
+
NO_ALWAYS_REQUIRED_COLUMNS
|
|
2978
|
+
);
|
|
2979
|
+
const startColumnsFromRecursive = compileNodeSelectColumnsFromRecursiveRow(
|
|
2980
|
+
startAlias,
|
|
2981
|
+
requiredStartColumns,
|
|
2982
|
+
NO_ALWAYS_REQUIRED_COLUMNS
|
|
2983
|
+
);
|
|
2984
|
+
const nodeColumnsFromBase = compileNodeSelectColumnsFromTable(
|
|
2985
|
+
"n0",
|
|
2986
|
+
nodeAlias,
|
|
2987
|
+
requiredNodeColumns,
|
|
2988
|
+
recursiveJoinRequiredColumns
|
|
2989
|
+
);
|
|
2990
|
+
const nodeColumnsFromRecursive = compileNodeSelectColumnsFromTable(
|
|
2991
|
+
"n",
|
|
2992
|
+
nodeAlias,
|
|
2993
|
+
requiredNodeColumns,
|
|
2994
|
+
recursiveJoinRequiredColumns
|
|
2995
|
+
);
|
|
2996
|
+
const startKindFilter = compileKindFilter2(startKinds, "n0.kind");
|
|
2997
|
+
const nodeKindFilter = compileKindFilter2(nodeKinds, "n.kind");
|
|
2998
|
+
const startTemporalFilter = temporalFilterPass.forAlias("n0");
|
|
2999
|
+
const edgeTemporalFilter = temporalFilterPass.forAlias("e");
|
|
3000
|
+
const nodeTemporalFilter = temporalFilterPass.forAlias("n");
|
|
3001
|
+
const startContext = { ...ctx, cteColumnPrefix: "" };
|
|
3002
|
+
const startPredicates = compileNodePredicates(ast, startAlias, startContext);
|
|
3003
|
+
const edgeContext = { ...ctx, cteColumnPrefix: "e" };
|
|
3004
|
+
const edgePredicates = compileEdgePredicates(
|
|
3005
|
+
ast,
|
|
3006
|
+
traversal.edgeAlias,
|
|
3007
|
+
edgeContext
|
|
3008
|
+
);
|
|
3009
|
+
const targetContext = { ...ctx, cteColumnPrefix: "n" };
|
|
3010
|
+
const targetNodePredicates = compileNodePredicates(
|
|
3011
|
+
ast,
|
|
3012
|
+
nodeAlias,
|
|
3013
|
+
targetContext
|
|
3014
|
+
);
|
|
3015
|
+
if (vl.maxDepth > MAX_EXPLICIT_RECURSIVE_DEPTH) {
|
|
3016
|
+
throw new chunk44SXEVF4_cjs.UnsupportedPredicateError(
|
|
3017
|
+
`Recursive traversal maxHops(${vl.maxDepth}) exceeds maximum explicit depth of ${MAX_EXPLICIT_RECURSIVE_DEPTH}`
|
|
3018
|
+
);
|
|
3019
|
+
}
|
|
3020
|
+
const effectiveMaxDepth = vl.maxDepth > 0 ? vl.maxDepth : MAX_RECURSIVE_DEPTH;
|
|
3021
|
+
const maxDepthCondition = drizzleOrm.sql`r.depth < ${effectiveMaxDepth}`;
|
|
3022
|
+
const cycleCheck = shouldEnforceCycleCheck ? dialect.cycleCheck(drizzleOrm.sql.raw("n.id"), drizzleOrm.sql.raw("r.path")) : void 0;
|
|
3023
|
+
const initialPath = shouldTrackPath ? dialect.initializePath(drizzleOrm.sql.raw("n0.id")) : void 0;
|
|
3024
|
+
const pathExtension = shouldTrackPath ? dialect.extendPath(drizzleOrm.sql.raw("r.path"), drizzleOrm.sql.raw("n.id")) : void 0;
|
|
3025
|
+
const baseWhereClauses = [
|
|
3026
|
+
drizzleOrm.sql`n0.graph_id = ${graphId}`,
|
|
3027
|
+
startKindFilter,
|
|
3028
|
+
startTemporalFilter,
|
|
3029
|
+
...startPredicates
|
|
3030
|
+
];
|
|
3031
|
+
const recursiveBaseWhereClauses = [
|
|
3032
|
+
drizzleOrm.sql`e.graph_id = ${graphId}`,
|
|
3033
|
+
nodeKindFilter,
|
|
3034
|
+
edgeTemporalFilter,
|
|
3035
|
+
nodeTemporalFilter,
|
|
3036
|
+
maxDepthCondition
|
|
3037
|
+
];
|
|
3038
|
+
if (cycleCheck !== void 0) {
|
|
3039
|
+
recursiveBaseWhereClauses.push(cycleCheck);
|
|
3040
|
+
}
|
|
3041
|
+
recursiveBaseWhereClauses.push(...edgePredicates, ...targetNodePredicates);
|
|
3042
|
+
function compileRecursiveBranch2(branch) {
|
|
3043
|
+
const recursiveFilterClauses = [
|
|
3044
|
+
...recursiveBaseWhereClauses,
|
|
3045
|
+
compileKindFilter2(branch.edgeKinds, "e.kind"),
|
|
3046
|
+
compileKindFilter2(previousNodeKinds, `e.${branch.joinKindField}`),
|
|
3047
|
+
compileKindFilter2(nodeKinds, `e.${branch.targetKindField}`)
|
|
3048
|
+
];
|
|
3049
|
+
if (branch.duplicateGuard !== void 0) {
|
|
3050
|
+
recursiveFilterClauses.push(branch.duplicateGuard);
|
|
3051
|
+
}
|
|
3052
|
+
const recursiveSelectColumns = [
|
|
3053
|
+
...startColumnsFromRecursive,
|
|
3054
|
+
...nodeColumnsFromRecursive,
|
|
3055
|
+
drizzleOrm.sql`r.depth + 1 AS depth`
|
|
3056
|
+
];
|
|
3057
|
+
if (pathExtension !== void 0) {
|
|
3058
|
+
recursiveSelectColumns.push(drizzleOrm.sql`${pathExtension} AS path`);
|
|
3059
|
+
}
|
|
3060
|
+
const recursiveJoinClauses = [
|
|
3055
3061
|
drizzleOrm.sql`e.${drizzleOrm.sql.raw(branch.joinField)} = r.${drizzleOrm.sql.raw(nodeAlias)}_id`
|
|
3056
3062
|
];
|
|
3057
3063
|
if (previousNodeKinds.length > 1) {
|
|
@@ -3059,278 +3065,809 @@ function compileRecursiveCte(ast, traversal, graphId, ctx, requiredColumnsByAlia
|
|
|
3059
3065
|
drizzleOrm.sql`e.${drizzleOrm.sql.raw(branch.joinKindField)} = r.${drizzleOrm.sql.raw(nodeAlias)}_kind`
|
|
3060
3066
|
);
|
|
3061
3067
|
}
|
|
3062
|
-
if (forceWorktableOuterJoinOrder) {
|
|
3063
|
-
const recursiveWhereClauses = [
|
|
3064
|
-
...recursiveJoinClauses,
|
|
3065
|
-
...recursiveFilterClauses
|
|
3066
|
-
];
|
|
3067
|
-
return drizzleOrm.sql`
|
|
3068
|
-
SELECT ${drizzleOrm.sql.join(recursiveSelectColumns, drizzleOrm.sql`, `)}
|
|
3069
|
-
FROM recursive_cte r
|
|
3070
|
-
CROSS JOIN ${ctx.schema.edgesTable} e
|
|
3071
|
-
JOIN ${ctx.schema.nodesTable} n ON n.graph_id = e.graph_id
|
|
3072
|
-
AND n.id = e.${drizzleOrm.sql.raw(branch.targetField)}
|
|
3073
|
-
AND n.kind = e.${drizzleOrm.sql.raw(branch.targetKindField)}
|
|
3074
|
-
WHERE ${drizzleOrm.sql.join(recursiveWhereClauses, drizzleOrm.sql` AND `)}
|
|
3075
|
-
`;
|
|
3068
|
+
if (forceWorktableOuterJoinOrder) {
|
|
3069
|
+
const recursiveWhereClauses = [
|
|
3070
|
+
...recursiveJoinClauses,
|
|
3071
|
+
...recursiveFilterClauses
|
|
3072
|
+
];
|
|
3073
|
+
return drizzleOrm.sql`
|
|
3074
|
+
SELECT ${drizzleOrm.sql.join(recursiveSelectColumns, drizzleOrm.sql`, `)}
|
|
3075
|
+
FROM recursive_cte r
|
|
3076
|
+
CROSS JOIN ${ctx.schema.edgesTable} e
|
|
3077
|
+
JOIN ${ctx.schema.nodesTable} n ON n.graph_id = e.graph_id
|
|
3078
|
+
AND n.id = e.${drizzleOrm.sql.raw(branch.targetField)}
|
|
3079
|
+
AND n.kind = e.${drizzleOrm.sql.raw(branch.targetKindField)}
|
|
3080
|
+
WHERE ${drizzleOrm.sql.join(recursiveWhereClauses, drizzleOrm.sql` AND `)}
|
|
3081
|
+
`;
|
|
3082
|
+
}
|
|
3083
|
+
return drizzleOrm.sql`
|
|
3084
|
+
SELECT ${drizzleOrm.sql.join(recursiveSelectColumns, drizzleOrm.sql`, `)}
|
|
3085
|
+
FROM recursive_cte r
|
|
3086
|
+
JOIN ${ctx.schema.edgesTable} e ON ${drizzleOrm.sql.join(recursiveJoinClauses, drizzleOrm.sql` AND `)}
|
|
3087
|
+
JOIN ${ctx.schema.nodesTable} n ON n.graph_id = e.graph_id
|
|
3088
|
+
AND n.id = e.${drizzleOrm.sql.raw(branch.targetField)}
|
|
3089
|
+
AND n.kind = e.${drizzleOrm.sql.raw(branch.targetKindField)}
|
|
3090
|
+
WHERE ${drizzleOrm.sql.join(recursiveFilterClauses, drizzleOrm.sql` AND `)}
|
|
3091
|
+
`;
|
|
3092
|
+
}
|
|
3093
|
+
const directJoinField = direction === "out" ? "from_id" : "to_id";
|
|
3094
|
+
const directTargetField = direction === "out" ? "to_id" : "from_id";
|
|
3095
|
+
const directJoinKindField = direction === "out" ? "from_kind" : "to_kind";
|
|
3096
|
+
const directTargetKindField = direction === "out" ? "to_kind" : "from_kind";
|
|
3097
|
+
const directBranch = compileRecursiveBranch2({
|
|
3098
|
+
joinField: directJoinField,
|
|
3099
|
+
targetField: directTargetField,
|
|
3100
|
+
joinKindField: directJoinKindField,
|
|
3101
|
+
targetKindField: directTargetKindField,
|
|
3102
|
+
edgeKinds: directEdgeKinds
|
|
3103
|
+
});
|
|
3104
|
+
function compileInverseRecursiveBranch() {
|
|
3105
|
+
const inverseJoinField = direction === "out" ? "to_id" : "from_id";
|
|
3106
|
+
const inverseTargetField = direction === "out" ? "from_id" : "to_id";
|
|
3107
|
+
const inverseJoinKindField = direction === "out" ? "to_kind" : "from_kind";
|
|
3108
|
+
const inverseTargetKindField = direction === "out" ? "from_kind" : "to_kind";
|
|
3109
|
+
const overlappingKinds = inverseEdgeKinds.filter(
|
|
3110
|
+
(kind) => directEdgeKinds.includes(kind)
|
|
3111
|
+
);
|
|
3112
|
+
const duplicateGuard = overlappingKinds.length > 0 ? drizzleOrm.sql`NOT (e.from_id = e.to_id AND ${compileKindFilter2(overlappingKinds, "e.kind")})` : void 0;
|
|
3113
|
+
const inverseBranch = compileRecursiveBranch2({
|
|
3114
|
+
joinField: inverseJoinField,
|
|
3115
|
+
targetField: inverseTargetField,
|
|
3116
|
+
joinKindField: inverseJoinKindField,
|
|
3117
|
+
targetKindField: inverseTargetKindField,
|
|
3118
|
+
edgeKinds: inverseEdgeKinds,
|
|
3119
|
+
duplicateGuard
|
|
3120
|
+
});
|
|
3121
|
+
return drizzleOrm.sql`
|
|
3122
|
+
${directBranch}
|
|
3123
|
+
UNION ALL
|
|
3124
|
+
${inverseBranch}
|
|
3125
|
+
`;
|
|
3126
|
+
}
|
|
3127
|
+
const recursiveBranchSql = inverseEdgeKinds.length === 0 ? directBranch : compileInverseRecursiveBranch();
|
|
3128
|
+
const baseSelectColumns = [
|
|
3129
|
+
...startColumnsFromBase,
|
|
3130
|
+
...nodeColumnsFromBase,
|
|
3131
|
+
drizzleOrm.sql`0 AS depth`
|
|
3132
|
+
];
|
|
3133
|
+
if (initialPath !== void 0) {
|
|
3134
|
+
baseSelectColumns.push(drizzleOrm.sql`${initialPath} AS path`);
|
|
3135
|
+
}
|
|
3136
|
+
return drizzleOrm.sql`
|
|
3137
|
+
recursive_cte AS (
|
|
3138
|
+
-- Base case: starting nodes
|
|
3139
|
+
SELECT ${drizzleOrm.sql.join(baseSelectColumns, drizzleOrm.sql`, `)}
|
|
3140
|
+
FROM ${ctx.schema.nodesTable} n0
|
|
3141
|
+
WHERE ${drizzleOrm.sql.join(baseWhereClauses, drizzleOrm.sql` AND `)}
|
|
3142
|
+
|
|
3143
|
+
UNION ALL
|
|
3144
|
+
|
|
3145
|
+
-- Recursive case: follow edges
|
|
3146
|
+
${recursiveBranchSql}
|
|
3147
|
+
)
|
|
3148
|
+
`;
|
|
3149
|
+
}
|
|
3150
|
+
function compileKindFilter2(kinds, columnExpr) {
|
|
3151
|
+
return compileKindFilter(drizzleOrm.sql.raw(columnExpr), kinds);
|
|
3152
|
+
}
|
|
3153
|
+
function compileNodePredicates(ast, alias, ctx) {
|
|
3154
|
+
return ast.predicates.filter((p) => p.targetAlias === alias && p.targetType !== "edge").map((p) => compilePredicateExpression(p.expression, ctx));
|
|
3155
|
+
}
|
|
3156
|
+
function compileEdgePredicates(ast, edgeAlias, ctx) {
|
|
3157
|
+
return ast.predicates.filter((p) => p.targetAlias === edgeAlias && p.targetType === "edge").map((p) => compilePredicateExpression(p.expression, ctx));
|
|
3158
|
+
}
|
|
3159
|
+
function collectRequiredColumnsByAlias(ast, traversal) {
|
|
3160
|
+
const selectiveFields = ast.selectiveFields;
|
|
3161
|
+
if (selectiveFields === void 0 || selectiveFields.length === 0) {
|
|
3162
|
+
return void 0;
|
|
3163
|
+
}
|
|
3164
|
+
const requiredColumnsByAlias = /* @__PURE__ */ new Map();
|
|
3165
|
+
const previousNodeKinds = [
|
|
3166
|
+
.../* @__PURE__ */ new Set([...ast.start.kinds, ...traversal.nodeKinds])
|
|
3167
|
+
];
|
|
3168
|
+
addRequiredColumn(requiredColumnsByAlias, traversal.nodeAlias, "id");
|
|
3169
|
+
if (previousNodeKinds.length > 1) {
|
|
3170
|
+
addRequiredColumn(requiredColumnsByAlias, traversal.nodeAlias, "kind");
|
|
3171
|
+
}
|
|
3172
|
+
for (const field2 of selectiveFields) {
|
|
3173
|
+
markSelectiveFieldAsRequired(requiredColumnsByAlias, field2);
|
|
3174
|
+
}
|
|
3175
|
+
if (ast.orderBy) {
|
|
3176
|
+
for (const orderSpec of ast.orderBy) {
|
|
3177
|
+
markFieldRefAsRequired(requiredColumnsByAlias, orderSpec.field);
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
return requiredColumnsByAlias;
|
|
3181
|
+
}
|
|
3182
|
+
function compileNodeSelectColumnsFromTable(tableAlias, alias, requiredColumns, alwaysRequiredColumns) {
|
|
3183
|
+
return NODE_COLUMNS.filter(
|
|
3184
|
+
(column) => shouldProjectColumn(requiredColumns, column, alwaysRequiredColumns)
|
|
3185
|
+
).map(
|
|
3186
|
+
(column) => drizzleOrm.sql`${drizzleOrm.sql.raw(tableAlias)}.${drizzleOrm.sql.raw(column)} AS ${drizzleOrm.sql.raw(`${alias}_${column}`)}`
|
|
3187
|
+
);
|
|
3188
|
+
}
|
|
3189
|
+
function compileNodeSelectColumnsFromRecursiveRow(alias, requiredColumns, alwaysRequiredColumns) {
|
|
3190
|
+
return NODE_COLUMNS.filter(
|
|
3191
|
+
(column) => shouldProjectColumn(requiredColumns, column, alwaysRequiredColumns)
|
|
3192
|
+
).map((column) => {
|
|
3193
|
+
const projected = `${alias}_${column}`;
|
|
3194
|
+
return drizzleOrm.sql`r.${drizzleOrm.sql.raw(projected)} AS ${drizzleOrm.sql.raw(projected)}`;
|
|
3195
|
+
});
|
|
3196
|
+
}
|
|
3197
|
+
function compileRecursiveProjection(ast, traversal, dialect) {
|
|
3198
|
+
if (ast.selectiveFields && ast.selectiveFields.length > 0) {
|
|
3199
|
+
return compileRecursiveSelectiveProjection(
|
|
3200
|
+
ast.selectiveFields,
|
|
3201
|
+
ast,
|
|
3202
|
+
traversal,
|
|
3203
|
+
dialect
|
|
3204
|
+
);
|
|
3205
|
+
}
|
|
3206
|
+
const startAlias = ast.start.alias;
|
|
3207
|
+
const nodeAlias = traversal.nodeAlias;
|
|
3208
|
+
const vl = traversal.variableLength;
|
|
3209
|
+
const fields = [
|
|
3210
|
+
// Start alias fields with metadata
|
|
3211
|
+
drizzleOrm.sql`${drizzleOrm.sql.raw(startAlias)}_id`,
|
|
3212
|
+
drizzleOrm.sql`${drizzleOrm.sql.raw(startAlias)}_kind`,
|
|
3213
|
+
drizzleOrm.sql`${drizzleOrm.sql.raw(startAlias)}_props`,
|
|
3214
|
+
drizzleOrm.sql`${drizzleOrm.sql.raw(startAlias)}_version`,
|
|
3215
|
+
drizzleOrm.sql`${drizzleOrm.sql.raw(startAlias)}_valid_from`,
|
|
3216
|
+
drizzleOrm.sql`${drizzleOrm.sql.raw(startAlias)}_valid_to`,
|
|
3217
|
+
drizzleOrm.sql`${drizzleOrm.sql.raw(startAlias)}_created_at`,
|
|
3218
|
+
drizzleOrm.sql`${drizzleOrm.sql.raw(startAlias)}_updated_at`,
|
|
3219
|
+
drizzleOrm.sql`${drizzleOrm.sql.raw(startAlias)}_deleted_at`,
|
|
3220
|
+
// Node alias fields with metadata
|
|
3221
|
+
drizzleOrm.sql`${drizzleOrm.sql.raw(nodeAlias)}_id`,
|
|
3222
|
+
drizzleOrm.sql`${drizzleOrm.sql.raw(nodeAlias)}_kind`,
|
|
3223
|
+
drizzleOrm.sql`${drizzleOrm.sql.raw(nodeAlias)}_props`,
|
|
3224
|
+
drizzleOrm.sql`${drizzleOrm.sql.raw(nodeAlias)}_version`,
|
|
3225
|
+
drizzleOrm.sql`${drizzleOrm.sql.raw(nodeAlias)}_valid_from`,
|
|
3226
|
+
drizzleOrm.sql`${drizzleOrm.sql.raw(nodeAlias)}_valid_to`,
|
|
3227
|
+
drizzleOrm.sql`${drizzleOrm.sql.raw(nodeAlias)}_created_at`,
|
|
3228
|
+
drizzleOrm.sql`${drizzleOrm.sql.raw(nodeAlias)}_updated_at`,
|
|
3229
|
+
drizzleOrm.sql`${drizzleOrm.sql.raw(nodeAlias)}_deleted_at`
|
|
3230
|
+
];
|
|
3231
|
+
if (vl.depthAlias !== void 0) {
|
|
3232
|
+
fields.push(drizzleOrm.sql`depth AS ${quoteIdentifier(vl.depthAlias)}`);
|
|
3233
|
+
}
|
|
3234
|
+
if (vl.pathAlias !== void 0) {
|
|
3235
|
+
fields.push(drizzleOrm.sql`path AS ${quoteIdentifier(vl.pathAlias)}`);
|
|
3236
|
+
}
|
|
3237
|
+
return drizzleOrm.sql.join(fields, drizzleOrm.sql`, `);
|
|
3238
|
+
}
|
|
3239
|
+
function compileRecursiveSelectiveProjection(fields, ast, traversal, dialect) {
|
|
3240
|
+
const allowedAliases = /* @__PURE__ */ new Set([ast.start.alias, traversal.nodeAlias]);
|
|
3241
|
+
const columns = fields.map((field2) => {
|
|
3242
|
+
if (!allowedAliases.has(field2.alias)) {
|
|
3243
|
+
throw new chunk44SXEVF4_cjs.UnsupportedPredicateError(
|
|
3244
|
+
`Selective projection for recursive traversals does not support alias "${field2.alias}"`
|
|
3245
|
+
);
|
|
3246
|
+
}
|
|
3247
|
+
if (field2.isSystemField) {
|
|
3248
|
+
const dbColumn = mapSelectiveSystemFieldToColumn(field2.field);
|
|
3249
|
+
return drizzleOrm.sql`${drizzleOrm.sql.raw(`${field2.alias}_${dbColumn}`)} AS ${quoteIdentifier(field2.outputName)}`;
|
|
3076
3250
|
}
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
`;
|
|
3086
|
-
}
|
|
3087
|
-
const directJoinField = direction === "out" ? "from_id" : "to_id";
|
|
3088
|
-
const directTargetField = direction === "out" ? "to_id" : "from_id";
|
|
3089
|
-
const directJoinKindField = direction === "out" ? "from_kind" : "to_kind";
|
|
3090
|
-
const directTargetKindField = direction === "out" ? "to_kind" : "from_kind";
|
|
3091
|
-
const directBranch = compileRecursiveBranch2({
|
|
3092
|
-
joinField: directJoinField,
|
|
3093
|
-
targetField: directTargetField,
|
|
3094
|
-
joinKindField: directJoinKindField,
|
|
3095
|
-
targetKindField: directTargetKindField,
|
|
3096
|
-
edgeKinds: directEdgeKinds
|
|
3251
|
+
const column = drizzleOrm.sql.raw(`${field2.alias}_props`);
|
|
3252
|
+
const extracted = compileTypedJsonExtract({
|
|
3253
|
+
column,
|
|
3254
|
+
dialect,
|
|
3255
|
+
pointer: chunkP5CNM325_cjs.jsonPointer([field2.field]),
|
|
3256
|
+
valueType: field2.valueType
|
|
3257
|
+
});
|
|
3258
|
+
return drizzleOrm.sql`${extracted} AS ${quoteIdentifier(field2.outputName)}`;
|
|
3097
3259
|
});
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3260
|
+
const vl = traversal.variableLength;
|
|
3261
|
+
if (vl.depthAlias !== void 0) {
|
|
3262
|
+
columns.push(drizzleOrm.sql`depth AS ${quoteIdentifier(vl.depthAlias)}`);
|
|
3263
|
+
}
|
|
3264
|
+
if (vl.pathAlias !== void 0) {
|
|
3265
|
+
columns.push(drizzleOrm.sql`path AS ${quoteIdentifier(vl.pathAlias)}`);
|
|
3266
|
+
}
|
|
3267
|
+
return drizzleOrm.sql.join(columns, drizzleOrm.sql`, `);
|
|
3268
|
+
}
|
|
3269
|
+
function compileRecursiveOrderBy(ast, dialect) {
|
|
3270
|
+
if (!ast.orderBy || ast.orderBy.length === 0) {
|
|
3271
|
+
return void 0;
|
|
3272
|
+
}
|
|
3273
|
+
const parts = [];
|
|
3274
|
+
for (const orderSpec of ast.orderBy) {
|
|
3275
|
+
const valueType = orderSpec.field.valueType;
|
|
3276
|
+
if (valueType === "array" || valueType === "object") {
|
|
3277
|
+
throw new chunk44SXEVF4_cjs.UnsupportedPredicateError(
|
|
3278
|
+
"Ordering by JSON arrays or objects is not supported"
|
|
3279
|
+
);
|
|
3280
|
+
}
|
|
3281
|
+
const field2 = compileFieldValue(orderSpec.field, dialect, valueType);
|
|
3282
|
+
const direction = drizzleOrm.sql.raw(orderSpec.direction.toUpperCase());
|
|
3283
|
+
const nulls = orderSpec.nulls ?? (orderSpec.direction === "asc" ? "last" : "first");
|
|
3284
|
+
const nullsDirection = drizzleOrm.sql.raw(nulls === "first" ? "DESC" : "ASC");
|
|
3285
|
+
parts.push(
|
|
3286
|
+
drizzleOrm.sql`(${field2} IS NULL) ${nullsDirection}`,
|
|
3287
|
+
drizzleOrm.sql`${field2} ${direction}`
|
|
3288
|
+
);
|
|
3289
|
+
}
|
|
3290
|
+
return drizzleOrm.sql`ORDER BY ${drizzleOrm.sql.join(parts, drizzleOrm.sql`, `)}`;
|
|
3291
|
+
}
|
|
3292
|
+
function compileLimitOffset(ast) {
|
|
3293
|
+
const parts = [];
|
|
3294
|
+
if (ast.limit !== void 0) {
|
|
3295
|
+
parts.push(drizzleOrm.sql`LIMIT ${ast.limit}`);
|
|
3296
|
+
}
|
|
3297
|
+
if (ast.offset !== void 0) {
|
|
3298
|
+
parts.push(drizzleOrm.sql`OFFSET ${ast.offset}`);
|
|
3299
|
+
}
|
|
3300
|
+
return parts.length > 0 ? drizzleOrm.sql.join(parts, drizzleOrm.sql` `) : void 0;
|
|
3301
|
+
}
|
|
3302
|
+
var DEFAULT_TABLE_NAMES = {
|
|
3303
|
+
nodes: "typegraph_nodes",
|
|
3304
|
+
edges: "typegraph_edges",
|
|
3305
|
+
embeddings: "typegraph_node_embeddings"
|
|
3306
|
+
};
|
|
3307
|
+
var MAX_IDENTIFIER_LENGTH = 63;
|
|
3308
|
+
var VALID_IDENTIFIER_PATTERN = /^[a-z_][a-z0-9_$]*$/i;
|
|
3309
|
+
function validateTableName(name, label) {
|
|
3310
|
+
if (!name || name.length === 0) {
|
|
3311
|
+
throw new chunk44SXEVF4_cjs.ConfigurationError(`${label} table name cannot be empty`);
|
|
3312
|
+
}
|
|
3313
|
+
if (name.length > MAX_IDENTIFIER_LENGTH) {
|
|
3314
|
+
throw new chunk44SXEVF4_cjs.ConfigurationError(
|
|
3315
|
+
`${label} table name exceeds maximum length of ${MAX_IDENTIFIER_LENGTH} characters`
|
|
3316
|
+
);
|
|
3317
|
+
}
|
|
3318
|
+
if (!VALID_IDENTIFIER_PATTERN.test(name)) {
|
|
3319
|
+
throw new chunk44SXEVF4_cjs.ConfigurationError(
|
|
3320
|
+
`${label} table name "${name}" is not a valid SQL identifier. Table names must start with a letter or underscore and contain only letters, digits, underscores, or dollar signs.`
|
|
3321
|
+
);
|
|
3322
|
+
}
|
|
3323
|
+
}
|
|
3324
|
+
function quoteIdentifier2(name) {
|
|
3325
|
+
return `"${name.replaceAll('"', '""')}"`;
|
|
3326
|
+
}
|
|
3327
|
+
function createSqlSchema(names = {}) {
|
|
3328
|
+
const tables = { ...DEFAULT_TABLE_NAMES, ...names };
|
|
3329
|
+
validateTableName(tables.nodes, "nodes");
|
|
3330
|
+
validateTableName(tables.edges, "edges");
|
|
3331
|
+
validateTableName(tables.embeddings, "embeddings");
|
|
3332
|
+
return {
|
|
3333
|
+
tables,
|
|
3334
|
+
nodesTable: drizzleOrm.sql.raw(quoteIdentifier2(tables.nodes)),
|
|
3335
|
+
edgesTable: drizzleOrm.sql.raw(quoteIdentifier2(tables.edges)),
|
|
3336
|
+
embeddingsTable: drizzleOrm.sql.raw(quoteIdentifier2(tables.embeddings))
|
|
3337
|
+
};
|
|
3338
|
+
}
|
|
3339
|
+
var DEFAULT_SQL_SCHEMA = createSqlSchema();
|
|
3340
|
+
|
|
3341
|
+
// src/query/execution/value-decoder.ts
|
|
3342
|
+
function nullToUndefined(value) {
|
|
3343
|
+
return value === null ? void 0 : value;
|
|
3344
|
+
}
|
|
3345
|
+
function decodeSelectedValue(value, typeInfo) {
|
|
3346
|
+
const normalized = nullToUndefined(value);
|
|
3347
|
+
if (normalized === void 0) return void 0;
|
|
3348
|
+
if (typeInfo === void 0) {
|
|
3349
|
+
return normalized;
|
|
3350
|
+
}
|
|
3351
|
+
return decodeByValueType(normalized, typeInfo.valueType);
|
|
3352
|
+
}
|
|
3353
|
+
function decodeByValueType(value, valueType) {
|
|
3354
|
+
switch (valueType) {
|
|
3355
|
+
case "boolean": {
|
|
3356
|
+
if (typeof value === "boolean") return value;
|
|
3357
|
+
if (typeof value === "number") return value !== 0;
|
|
3358
|
+
if (typeof value === "string") {
|
|
3359
|
+
if (value === "0") return false;
|
|
3360
|
+
if (value === "1") return true;
|
|
3361
|
+
if (value.toLowerCase() === "true") return true;
|
|
3362
|
+
if (value.toLowerCase() === "false") return false;
|
|
3363
|
+
}
|
|
3364
|
+
return Boolean(value);
|
|
3365
|
+
}
|
|
3366
|
+
case "number": {
|
|
3367
|
+
if (typeof value === "number") return value;
|
|
3368
|
+
if (typeof value === "string") {
|
|
3369
|
+
const parsed = Number(value);
|
|
3370
|
+
return Number.isNaN(parsed) ? value : parsed;
|
|
3371
|
+
}
|
|
3372
|
+
return value;
|
|
3373
|
+
}
|
|
3374
|
+
case "array":
|
|
3375
|
+
case "object":
|
|
3376
|
+
case "embedding": {
|
|
3377
|
+
if (typeof value !== "string") return value;
|
|
3378
|
+
const trimmed = value.trim();
|
|
3379
|
+
const looksJson = trimmed.startsWith("[") || trimmed.startsWith("{");
|
|
3380
|
+
if (!looksJson) return value;
|
|
3381
|
+
try {
|
|
3382
|
+
return JSON.parse(trimmed);
|
|
3383
|
+
} catch {
|
|
3384
|
+
return value;
|
|
3385
|
+
}
|
|
3386
|
+
}
|
|
3387
|
+
case "string":
|
|
3388
|
+
case "date":
|
|
3389
|
+
case "unknown": {
|
|
3390
|
+
return value;
|
|
3391
|
+
}
|
|
3392
|
+
default: {
|
|
3393
|
+
return value;
|
|
3394
|
+
}
|
|
3395
|
+
}
|
|
3396
|
+
}
|
|
3397
|
+
|
|
3398
|
+
// src/store/reserved-keys.ts
|
|
3399
|
+
var RESERVED_NODE_KEYS2 = /* @__PURE__ */ new Set([
|
|
3400
|
+
"id",
|
|
3401
|
+
"kind",
|
|
3402
|
+
"meta"
|
|
3403
|
+
]);
|
|
3404
|
+
var RESERVED_EDGE_KEYS2 = /* @__PURE__ */ new Set([
|
|
3405
|
+
"id",
|
|
3406
|
+
"kind",
|
|
3407
|
+
"meta",
|
|
3408
|
+
"fromKind",
|
|
3409
|
+
"fromId",
|
|
3410
|
+
"toKind",
|
|
3411
|
+
"toId"
|
|
3412
|
+
]);
|
|
3413
|
+
var PROTOTYPE_POLLUTION_KEYS = /* @__PURE__ */ new Set([
|
|
3414
|
+
"__proto__",
|
|
3415
|
+
"constructor",
|
|
3416
|
+
"prototype"
|
|
3417
|
+
]);
|
|
3418
|
+
function validateProjectionField(field2, entityType, kind) {
|
|
3419
|
+
const reserved = entityType === "node" ? RESERVED_NODE_KEYS2 : RESERVED_EDGE_KEYS2;
|
|
3420
|
+
if (reserved.has(field2)) {
|
|
3421
|
+
throw new chunk44SXEVF4_cjs.ConfigurationError(
|
|
3422
|
+
`Projection field "${field2}" on ${entityType} kind "${kind}" conflicts with a reserved structural key`,
|
|
3423
|
+
{ field: field2, kind, entityType, reservedKeys: [...reserved] },
|
|
3424
|
+
{
|
|
3425
|
+
suggestion: `Remove "${field2}" from the projection. Structural fields (${[...reserved].join(", ")}) are included automatically when relevant.`
|
|
3426
|
+
}
|
|
3427
|
+
);
|
|
3428
|
+
}
|
|
3429
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(field2)) {
|
|
3430
|
+
throw new chunk44SXEVF4_cjs.ConfigurationError(
|
|
3431
|
+
`Projection field "${field2}" on ${entityType} kind "${kind}" is not allowed`,
|
|
3432
|
+
{ field: field2, kind, entityType },
|
|
3433
|
+
{
|
|
3434
|
+
suggestion: `"${field2}" cannot be used as a projection field name.`
|
|
3435
|
+
}
|
|
3105
3436
|
);
|
|
3106
|
-
const duplicateGuard = overlappingKinds.length > 0 ? drizzleOrm.sql`NOT (e.from_id = e.to_id AND ${compileKindFilter2(overlappingKinds, "e.kind")})` : void 0;
|
|
3107
|
-
const inverseBranch = compileRecursiveBranch2({
|
|
3108
|
-
joinField: inverseJoinField,
|
|
3109
|
-
targetField: inverseTargetField,
|
|
3110
|
-
joinKindField: inverseJoinKindField,
|
|
3111
|
-
targetKindField: inverseTargetKindField,
|
|
3112
|
-
edgeKinds: inverseEdgeKinds,
|
|
3113
|
-
duplicateGuard
|
|
3114
|
-
});
|
|
3115
|
-
return drizzleOrm.sql`
|
|
3116
|
-
${directBranch}
|
|
3117
|
-
UNION ALL
|
|
3118
|
-
${inverseBranch}
|
|
3119
|
-
`;
|
|
3120
3437
|
}
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
baseSelectColumns.push(drizzleOrm.sql`${initialPath} AS path`);
|
|
3438
|
+
}
|
|
3439
|
+
function filterReservedKeys(props, reservedKeys) {
|
|
3440
|
+
const filtered = {};
|
|
3441
|
+
for (const [key, value] of Object.entries(props)) {
|
|
3442
|
+
if (!reservedKeys.has(key)) {
|
|
3443
|
+
filtered[key] = value;
|
|
3444
|
+
}
|
|
3129
3445
|
}
|
|
3130
|
-
return
|
|
3131
|
-
|
|
3132
|
-
-- Base case: starting nodes
|
|
3133
|
-
SELECT ${drizzleOrm.sql.join(baseSelectColumns, drizzleOrm.sql`, `)}
|
|
3134
|
-
FROM ${ctx.schema.nodesTable} n0
|
|
3135
|
-
WHERE ${drizzleOrm.sql.join(baseWhereClauses, drizzleOrm.sql` AND `)}
|
|
3136
|
-
|
|
3137
|
-
UNION ALL
|
|
3446
|
+
return filtered;
|
|
3447
|
+
}
|
|
3138
3448
|
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
`;
|
|
3449
|
+
// src/store/row-mappers.ts
|
|
3450
|
+
function nullToUndefined2(value) {
|
|
3451
|
+
return value === null ? void 0 : value;
|
|
3143
3452
|
}
|
|
3144
|
-
function
|
|
3145
|
-
|
|
3453
|
+
function rowToNode(row) {
|
|
3454
|
+
const rawProps = JSON.parse(row.props);
|
|
3455
|
+
const props = filterReservedKeys(rawProps, RESERVED_NODE_KEYS2);
|
|
3456
|
+
return {
|
|
3457
|
+
kind: row.kind,
|
|
3458
|
+
id: row.id,
|
|
3459
|
+
meta: rowToNodeMeta(row),
|
|
3460
|
+
...props
|
|
3461
|
+
};
|
|
3146
3462
|
}
|
|
3147
|
-
function
|
|
3148
|
-
return
|
|
3463
|
+
function rowToNodeMeta(row) {
|
|
3464
|
+
return {
|
|
3465
|
+
version: row.version,
|
|
3466
|
+
validFrom: nullToUndefined2(row.valid_from),
|
|
3467
|
+
validTo: nullToUndefined2(row.valid_to),
|
|
3468
|
+
createdAt: row.created_at,
|
|
3469
|
+
updatedAt: row.updated_at,
|
|
3470
|
+
deletedAt: nullToUndefined2(row.deleted_at)
|
|
3471
|
+
};
|
|
3149
3472
|
}
|
|
3150
|
-
function
|
|
3151
|
-
|
|
3473
|
+
function rowToEdge(row) {
|
|
3474
|
+
const rawProps = JSON.parse(row.props);
|
|
3475
|
+
const props = filterReservedKeys(rawProps, RESERVED_EDGE_KEYS2);
|
|
3476
|
+
return {
|
|
3477
|
+
id: row.id,
|
|
3478
|
+
kind: row.kind,
|
|
3479
|
+
fromKind: row.from_kind,
|
|
3480
|
+
fromId: row.from_id,
|
|
3481
|
+
toKind: row.to_kind,
|
|
3482
|
+
toId: row.to_id,
|
|
3483
|
+
meta: rowToEdgeMeta(row),
|
|
3484
|
+
...props
|
|
3485
|
+
};
|
|
3152
3486
|
}
|
|
3153
|
-
function
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3487
|
+
function rowToEdgeMeta(row) {
|
|
3488
|
+
return {
|
|
3489
|
+
validFrom: nullToUndefined2(row.valid_from),
|
|
3490
|
+
validTo: nullToUndefined2(row.valid_to),
|
|
3491
|
+
createdAt: row.created_at,
|
|
3492
|
+
updatedAt: row.updated_at,
|
|
3493
|
+
deletedAt: nullToUndefined2(row.deleted_at)
|
|
3494
|
+
};
|
|
3495
|
+
}
|
|
3496
|
+
|
|
3497
|
+
// src/store/subgraph.ts
|
|
3498
|
+
var DEFAULT_SUBGRAPH_MAX_DEPTH = 10;
|
|
3499
|
+
var MAX_PG_IDENTIFIER_LENGTH = 63;
|
|
3500
|
+
function fnv1aBase36(input) {
|
|
3501
|
+
let hash = 2166136261;
|
|
3502
|
+
for (const character of input) {
|
|
3503
|
+
const codePoint = character.codePointAt(0);
|
|
3504
|
+
if (codePoint === void 0) continue;
|
|
3505
|
+
hash ^= codePoint;
|
|
3506
|
+
hash = Math.imul(hash, 16777619);
|
|
3507
|
+
}
|
|
3508
|
+
return (hash >>> 0).toString(36);
|
|
3509
|
+
}
|
|
3510
|
+
var TEXT_ENCODER = new TextEncoder();
|
|
3511
|
+
function truncateToBytes(value, maxBytes) {
|
|
3512
|
+
const encoded = TEXT_ENCODER.encode(value);
|
|
3513
|
+
if (encoded.byteLength <= maxBytes) return value;
|
|
3514
|
+
let end = maxBytes;
|
|
3515
|
+
while (end > 0 && encoded[end] >= 128 && encoded[end] < 192) {
|
|
3516
|
+
end--;
|
|
3517
|
+
}
|
|
3518
|
+
return new TextDecoder().decode(encoded.slice(0, end));
|
|
3519
|
+
}
|
|
3520
|
+
function projectionAlias(entityPrefix, kind, field2) {
|
|
3521
|
+
const prefix = entityPrefix === "node" ? "sg_n" : "sg_e";
|
|
3522
|
+
const hash = fnv1aBase36(`${kind}\0${field2}`);
|
|
3523
|
+
const fixedBytes = prefix.length + 1 + 1 + hash.length;
|
|
3524
|
+
const maxKindBytes = MAX_PG_IDENTIFIER_LENGTH - fixedBytes;
|
|
3525
|
+
const truncatedKind = truncateToBytes(kind, maxKindBytes);
|
|
3526
|
+
return `${prefix}_${truncatedKind}_${hash}`;
|
|
3527
|
+
}
|
|
3528
|
+
function normalizeProps(value) {
|
|
3529
|
+
return typeof value === "string" ? value : JSON.stringify(value ?? {});
|
|
3530
|
+
}
|
|
3531
|
+
function defineSubgraphProject(_graph) {
|
|
3532
|
+
return (project) => project;
|
|
3533
|
+
}
|
|
3534
|
+
async function executeSubgraph(params) {
|
|
3535
|
+
const { options } = params;
|
|
3536
|
+
if (options.edges.length === 0) {
|
|
3537
|
+
return { nodes: [], edges: [] };
|
|
3165
3538
|
}
|
|
3166
|
-
|
|
3167
|
-
|
|
3539
|
+
const maxDepth = Math.min(
|
|
3540
|
+
options.maxDepth ?? DEFAULT_SUBGRAPH_MAX_DEPTH,
|
|
3541
|
+
MAX_RECURSIVE_DEPTH
|
|
3542
|
+
);
|
|
3543
|
+
const ctx = {
|
|
3544
|
+
graphId: params.graphId,
|
|
3545
|
+
rootId: params.rootId,
|
|
3546
|
+
edgeKinds: options.edges,
|
|
3547
|
+
maxDepth,
|
|
3548
|
+
includeKinds: options.includeKinds,
|
|
3549
|
+
excludeRoot: options.excludeRoot ?? false,
|
|
3550
|
+
direction: options.direction ?? "out",
|
|
3551
|
+
cyclePolicy: options.cyclePolicy ?? "prevent",
|
|
3552
|
+
dialect: params.dialect,
|
|
3553
|
+
schema: params.schema ?? DEFAULT_SQL_SCHEMA,
|
|
3554
|
+
backend: params.backend
|
|
3555
|
+
};
|
|
3556
|
+
const schemaIntrospector = getSubgraphSchemaIntrospector(params.graph);
|
|
3557
|
+
const nodeProjectionPlan = buildProjectionPlan(
|
|
3558
|
+
getIncludedNodeKinds(params.graph, options.includeKinds),
|
|
3559
|
+
options.project?.nodes,
|
|
3560
|
+
(kind, field2) => schemaIntrospector.getFieldTypeInfo(kind, field2),
|
|
3561
|
+
"node"
|
|
3562
|
+
);
|
|
3563
|
+
const edgeProjectionPlan = buildProjectionPlan(
|
|
3564
|
+
dedupeStrings(options.edges),
|
|
3565
|
+
options.project?.edges,
|
|
3566
|
+
(kind, field2) => schemaIntrospector.getEdgeFieldTypeInfo(kind, field2),
|
|
3567
|
+
"edge"
|
|
3568
|
+
);
|
|
3569
|
+
const reachableCte = buildReachableCte(ctx);
|
|
3570
|
+
const includedIdsCte = buildIncludedIdsCte(ctx);
|
|
3571
|
+
const [nodeRows, edgeRows] = await Promise.all([
|
|
3572
|
+
fetchSubgraphNodes(ctx, reachableCte, includedIdsCte, nodeProjectionPlan),
|
|
3573
|
+
fetchSubgraphEdges(ctx, reachableCte, includedIdsCte, edgeProjectionPlan)
|
|
3574
|
+
]);
|
|
3575
|
+
const nodes = nodeRows.map(
|
|
3576
|
+
(row) => mapSubgraphNodeRow(row, nodeProjectionPlan)
|
|
3577
|
+
);
|
|
3578
|
+
const edges = edgeRows.map(
|
|
3579
|
+
(row) => mapSubgraphEdgeRow(row, edgeProjectionPlan)
|
|
3580
|
+
);
|
|
3581
|
+
return {
|
|
3582
|
+
nodes,
|
|
3583
|
+
edges
|
|
3584
|
+
};
|
|
3585
|
+
}
|
|
3586
|
+
var introspectorCache = /* @__PURE__ */ new WeakMap();
|
|
3587
|
+
function getSubgraphSchemaIntrospector(graph) {
|
|
3588
|
+
const cached = introspectorCache.get(graph);
|
|
3589
|
+
if (cached !== void 0) return cached;
|
|
3590
|
+
const nodeKinds = new Map(
|
|
3591
|
+
Object.entries(graph.nodes).map(([kind, definition]) => [
|
|
3592
|
+
kind,
|
|
3593
|
+
{ schema: definition.type.schema }
|
|
3594
|
+
])
|
|
3595
|
+
);
|
|
3596
|
+
const edgeKinds = new Map(
|
|
3597
|
+
Object.entries(graph.edges).map(([kind, definition]) => [
|
|
3598
|
+
kind,
|
|
3599
|
+
{ schema: definition.type.schema }
|
|
3600
|
+
])
|
|
3601
|
+
);
|
|
3602
|
+
const introspector = chunkP5CNM325_cjs.createSchemaIntrospector(nodeKinds, edgeKinds);
|
|
3603
|
+
introspectorCache.set(graph, introspector);
|
|
3604
|
+
return introspector;
|
|
3605
|
+
}
|
|
3606
|
+
function buildProjectionPlan(kinds, projectionMap, resolveFieldType, entityPrefix) {
|
|
3607
|
+
const projectedKinds = /* @__PURE__ */ new Map();
|
|
3608
|
+
const fullKinds = [];
|
|
3609
|
+
for (const kind of kinds) {
|
|
3610
|
+
const selection = projectionMap?.[kind];
|
|
3611
|
+
if (selection === void 0) {
|
|
3612
|
+
fullKinds.push(kind);
|
|
3613
|
+
continue;
|
|
3614
|
+
}
|
|
3615
|
+
projectedKinds.set(
|
|
3616
|
+
kind,
|
|
3617
|
+
buildKindProjectionPlan(kind, selection, resolveFieldType, entityPrefix)
|
|
3618
|
+
);
|
|
3168
3619
|
}
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3620
|
+
return { fullKinds, projectedKinds };
|
|
3621
|
+
}
|
|
3622
|
+
function buildKindProjectionPlan(kind, selection, resolveFieldType, entityPrefix) {
|
|
3623
|
+
const propertyFields = /* @__PURE__ */ new Map();
|
|
3624
|
+
let includeMeta = false;
|
|
3625
|
+
for (const field2 of selection) {
|
|
3626
|
+
if (field2 === "meta") {
|
|
3627
|
+
includeMeta = true;
|
|
3628
|
+
continue;
|
|
3629
|
+
}
|
|
3630
|
+
validateProjectionField(field2, entityPrefix, kind);
|
|
3631
|
+
if (!propertyFields.has(field2)) {
|
|
3632
|
+
propertyFields.set(field2, {
|
|
3633
|
+
field: field2,
|
|
3634
|
+
outputName: projectionAlias(entityPrefix, kind, field2),
|
|
3635
|
+
typeInfo: resolveFieldType(kind, field2)
|
|
3636
|
+
});
|
|
3172
3637
|
}
|
|
3173
3638
|
}
|
|
3174
|
-
return
|
|
3639
|
+
return {
|
|
3640
|
+
includeMeta,
|
|
3641
|
+
propertyFields: [...propertyFields.values()]
|
|
3642
|
+
};
|
|
3175
3643
|
}
|
|
3176
|
-
function
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
);
|
|
3644
|
+
function getIncludedNodeKinds(graph, includeKinds) {
|
|
3645
|
+
if (includeKinds === void 0 || includeKinds.length === 0) {
|
|
3646
|
+
return Object.keys(graph.nodes);
|
|
3647
|
+
}
|
|
3648
|
+
return dedupeStrings(includeKinds);
|
|
3182
3649
|
}
|
|
3183
|
-
function
|
|
3184
|
-
return
|
|
3185
|
-
(column) => shouldProjectColumn(requiredColumns, column, alwaysRequiredColumns)
|
|
3186
|
-
).map((column) => {
|
|
3187
|
-
const projected = `${alias}_${column}`;
|
|
3188
|
-
return drizzleOrm.sql`r.${drizzleOrm.sql.raw(projected)} AS ${drizzleOrm.sql.raw(projected)}`;
|
|
3189
|
-
});
|
|
3650
|
+
function dedupeStrings(values) {
|
|
3651
|
+
return [...new Set(values)];
|
|
3190
3652
|
}
|
|
3191
|
-
function
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3653
|
+
function buildReachableCte(ctx) {
|
|
3654
|
+
const shouldTrackPath = ctx.cyclePolicy === "prevent";
|
|
3655
|
+
const edgeKindFilter = compileKindFilter(drizzleOrm.sql.raw("e.kind"), ctx.edgeKinds);
|
|
3656
|
+
const initialPath = shouldTrackPath ? ctx.dialect.initializePath(drizzleOrm.sql.raw("n.id")) : void 0;
|
|
3657
|
+
const pathExtension = shouldTrackPath ? ctx.dialect.extendPath(drizzleOrm.sql.raw("r.path"), drizzleOrm.sql.raw("n.id")) : void 0;
|
|
3658
|
+
const cycleCheck = shouldTrackPath ? ctx.dialect.cycleCheck(drizzleOrm.sql.raw("n.id"), drizzleOrm.sql.raw("r.path")) : void 0;
|
|
3659
|
+
const baseColumns = [drizzleOrm.sql`n.id`, drizzleOrm.sql`n.kind`, drizzleOrm.sql`0 AS depth`];
|
|
3660
|
+
if (initialPath !== void 0) {
|
|
3661
|
+
baseColumns.push(drizzleOrm.sql`${initialPath} AS path`);
|
|
3199
3662
|
}
|
|
3200
|
-
const
|
|
3201
|
-
const
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
drizzleOrm.sql`${drizzleOrm.sql.raw(startAlias)}_id`,
|
|
3206
|
-
drizzleOrm.sql`${drizzleOrm.sql.raw(startAlias)}_kind`,
|
|
3207
|
-
drizzleOrm.sql`${drizzleOrm.sql.raw(startAlias)}_props`,
|
|
3208
|
-
drizzleOrm.sql`${drizzleOrm.sql.raw(startAlias)}_version`,
|
|
3209
|
-
drizzleOrm.sql`${drizzleOrm.sql.raw(startAlias)}_valid_from`,
|
|
3210
|
-
drizzleOrm.sql`${drizzleOrm.sql.raw(startAlias)}_valid_to`,
|
|
3211
|
-
drizzleOrm.sql`${drizzleOrm.sql.raw(startAlias)}_created_at`,
|
|
3212
|
-
drizzleOrm.sql`${drizzleOrm.sql.raw(startAlias)}_updated_at`,
|
|
3213
|
-
drizzleOrm.sql`${drizzleOrm.sql.raw(startAlias)}_deleted_at`,
|
|
3214
|
-
// Node alias fields with metadata
|
|
3215
|
-
drizzleOrm.sql`${drizzleOrm.sql.raw(nodeAlias)}_id`,
|
|
3216
|
-
drizzleOrm.sql`${drizzleOrm.sql.raw(nodeAlias)}_kind`,
|
|
3217
|
-
drizzleOrm.sql`${drizzleOrm.sql.raw(nodeAlias)}_props`,
|
|
3218
|
-
drizzleOrm.sql`${drizzleOrm.sql.raw(nodeAlias)}_version`,
|
|
3219
|
-
drizzleOrm.sql`${drizzleOrm.sql.raw(nodeAlias)}_valid_from`,
|
|
3220
|
-
drizzleOrm.sql`${drizzleOrm.sql.raw(nodeAlias)}_valid_to`,
|
|
3221
|
-
drizzleOrm.sql`${drizzleOrm.sql.raw(nodeAlias)}_created_at`,
|
|
3222
|
-
drizzleOrm.sql`${drizzleOrm.sql.raw(nodeAlias)}_updated_at`,
|
|
3223
|
-
drizzleOrm.sql`${drizzleOrm.sql.raw(nodeAlias)}_deleted_at`
|
|
3663
|
+
const baseCase = drizzleOrm.sql`SELECT ${drizzleOrm.sql.join(baseColumns, drizzleOrm.sql`, `)} FROM ${ctx.schema.nodesTable} n WHERE n.graph_id = ${ctx.graphId} AND n.id = ${ctx.rootId} AND n.deleted_at IS NULL`;
|
|
3664
|
+
const recursiveColumns = [
|
|
3665
|
+
drizzleOrm.sql`n.id`,
|
|
3666
|
+
drizzleOrm.sql`n.kind`,
|
|
3667
|
+
drizzleOrm.sql`r.depth + 1 AS depth`
|
|
3224
3668
|
];
|
|
3225
|
-
if (
|
|
3226
|
-
|
|
3669
|
+
if (pathExtension !== void 0) {
|
|
3670
|
+
recursiveColumns.push(drizzleOrm.sql`${pathExtension} AS path`);
|
|
3227
3671
|
}
|
|
3228
|
-
|
|
3229
|
-
|
|
3672
|
+
const recursiveWhereClauses = [
|
|
3673
|
+
drizzleOrm.sql`e.graph_id = ${ctx.graphId}`,
|
|
3674
|
+
edgeKindFilter,
|
|
3675
|
+
drizzleOrm.sql`e.deleted_at IS NULL`,
|
|
3676
|
+
drizzleOrm.sql`n.deleted_at IS NULL`,
|
|
3677
|
+
drizzleOrm.sql`r.depth < ${ctx.maxDepth}`
|
|
3678
|
+
];
|
|
3679
|
+
if (cycleCheck !== void 0) {
|
|
3680
|
+
recursiveWhereClauses.push(cycleCheck);
|
|
3681
|
+
}
|
|
3682
|
+
const forceWorktableOuterJoinOrder = ctx.dialect.capabilities.forceRecursiveWorktableOuterJoinOrder;
|
|
3683
|
+
const recursiveCase = ctx.direction === "both" ? compileBidirectionalBranch({
|
|
3684
|
+
recursiveColumns,
|
|
3685
|
+
whereClauses: recursiveWhereClauses,
|
|
3686
|
+
forceWorktableOuterJoinOrder,
|
|
3687
|
+
schema: ctx.schema
|
|
3688
|
+
}) : compileRecursiveBranch({
|
|
3689
|
+
recursiveColumns,
|
|
3690
|
+
whereClauses: recursiveWhereClauses,
|
|
3691
|
+
joinField: "from_id",
|
|
3692
|
+
targetField: "to_id",
|
|
3693
|
+
targetKindField: "to_kind",
|
|
3694
|
+
forceWorktableOuterJoinOrder,
|
|
3695
|
+
schema: ctx.schema
|
|
3696
|
+
});
|
|
3697
|
+
return drizzleOrm.sql`WITH RECURSIVE reachable AS (${baseCase} UNION ALL ${recursiveCase})`;
|
|
3698
|
+
}
|
|
3699
|
+
function compileRecursiveBranch(params) {
|
|
3700
|
+
const columns = [...params.recursiveColumns];
|
|
3701
|
+
const selectClause = drizzleOrm.sql`SELECT ${drizzleOrm.sql.join(columns, drizzleOrm.sql`, `)}`;
|
|
3702
|
+
const nodeJoin = drizzleOrm.sql`JOIN ${params.schema.nodesTable} n ON n.graph_id = e.graph_id AND n.id = e.${drizzleOrm.sql.raw(params.targetField)} AND n.kind = e.${drizzleOrm.sql.raw(params.targetKindField)}`;
|
|
3703
|
+
if (params.forceWorktableOuterJoinOrder) {
|
|
3704
|
+
const allWhere = [
|
|
3705
|
+
...params.whereClauses,
|
|
3706
|
+
drizzleOrm.sql`e.${drizzleOrm.sql.raw(params.joinField)} = r.id`
|
|
3707
|
+
];
|
|
3708
|
+
return drizzleOrm.sql`${selectClause} FROM reachable r CROSS JOIN ${params.schema.edgesTable} e ${nodeJoin} WHERE ${drizzleOrm.sql.join(allWhere, drizzleOrm.sql` AND `)}`;
|
|
3709
|
+
}
|
|
3710
|
+
const where = [...params.whereClauses];
|
|
3711
|
+
return drizzleOrm.sql`${selectClause} FROM reachable r JOIN ${params.schema.edgesTable} e ON e.${drizzleOrm.sql.raw(params.joinField)} = r.id ${nodeJoin} WHERE ${drizzleOrm.sql.join(where, drizzleOrm.sql` AND `)}`;
|
|
3712
|
+
}
|
|
3713
|
+
function compileBidirectionalBranch(params) {
|
|
3714
|
+
const columns = [...params.recursiveColumns];
|
|
3715
|
+
const selectClause = drizzleOrm.sql`SELECT ${drizzleOrm.sql.join(columns, drizzleOrm.sql`, `)}`;
|
|
3716
|
+
const nodeJoin = drizzleOrm.sql`JOIN ${params.schema.nodesTable} n ON n.graph_id = e.graph_id AND ((e.to_id = r.id AND n.id = e.from_id AND n.kind = e.from_kind) OR (e.from_id = r.id AND n.id = e.to_id AND n.kind = e.to_kind))`;
|
|
3717
|
+
if (params.forceWorktableOuterJoinOrder) {
|
|
3718
|
+
const allWhere = [
|
|
3719
|
+
...params.whereClauses,
|
|
3720
|
+
drizzleOrm.sql`(e.from_id = r.id OR e.to_id = r.id)`
|
|
3721
|
+
];
|
|
3722
|
+
return drizzleOrm.sql`${selectClause} FROM reachable r CROSS JOIN ${params.schema.edgesTable} e ${nodeJoin} WHERE ${drizzleOrm.sql.join(allWhere, drizzleOrm.sql` AND `)}`;
|
|
3230
3723
|
}
|
|
3231
|
-
return drizzleOrm.sql.join(
|
|
3724
|
+
return drizzleOrm.sql`${selectClause} FROM reachable r JOIN ${params.schema.edgesTable} e ON (e.from_id = r.id OR e.to_id = r.id) ${nodeJoin} WHERE ${drizzleOrm.sql.join([...params.whereClauses], drizzleOrm.sql` AND `)}`;
|
|
3232
3725
|
}
|
|
3233
|
-
function
|
|
3234
|
-
const
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
throw new chunk44SXEVF4_cjs.UnsupportedPredicateError(
|
|
3238
|
-
`Selective projection for recursive traversals does not support alias "${field2.alias}"`
|
|
3239
|
-
);
|
|
3240
|
-
}
|
|
3241
|
-
if (field2.isSystemField) {
|
|
3242
|
-
const dbColumn = mapSelectiveSystemFieldToColumn(field2.field);
|
|
3243
|
-
return drizzleOrm.sql`${drizzleOrm.sql.raw(`${field2.alias}_${dbColumn}`)} AS ${quoteIdentifier(field2.outputName)}`;
|
|
3244
|
-
}
|
|
3245
|
-
const column = drizzleOrm.sql.raw(`${field2.alias}_props`);
|
|
3246
|
-
const extracted = compileTypedJsonExtract({
|
|
3247
|
-
column,
|
|
3248
|
-
dialect,
|
|
3249
|
-
pointer: chunkP5CNM325_cjs.jsonPointer([field2.field]),
|
|
3250
|
-
valueType: field2.valueType
|
|
3251
|
-
});
|
|
3252
|
-
return drizzleOrm.sql`${extracted} AS ${quoteIdentifier(field2.outputName)}`;
|
|
3253
|
-
});
|
|
3254
|
-
const vl = traversal.variableLength;
|
|
3255
|
-
if (vl.depthAlias !== void 0) {
|
|
3256
|
-
columns.push(drizzleOrm.sql`depth AS ${quoteIdentifier(vl.depthAlias)}`);
|
|
3726
|
+
function buildIncludedIdsCte(ctx) {
|
|
3727
|
+
const filters = [];
|
|
3728
|
+
if (ctx.includeKinds !== void 0 && ctx.includeKinds.length > 0) {
|
|
3729
|
+
filters.push(compileKindFilter(drizzleOrm.sql.raw("kind"), ctx.includeKinds));
|
|
3257
3730
|
}
|
|
3258
|
-
if (
|
|
3259
|
-
|
|
3731
|
+
if (ctx.excludeRoot) {
|
|
3732
|
+
filters.push(drizzleOrm.sql`id != ${ctx.rootId}`);
|
|
3260
3733
|
}
|
|
3261
|
-
|
|
3734
|
+
const whereClause = filters.length > 0 ? drizzleOrm.sql` WHERE ${drizzleOrm.sql.join(filters, drizzleOrm.sql` AND `)}` : drizzleOrm.sql``;
|
|
3735
|
+
return drizzleOrm.sql`, included_ids AS (SELECT DISTINCT id FROM reachable${whereClause})`;
|
|
3262
3736
|
}
|
|
3263
|
-
function
|
|
3264
|
-
|
|
3265
|
-
|
|
3737
|
+
async function fetchSubgraphNodes(ctx, reachableCte, includedIdsCte, projectionPlan) {
|
|
3738
|
+
const columns = [
|
|
3739
|
+
drizzleOrm.sql`n.kind`,
|
|
3740
|
+
drizzleOrm.sql`n.id`,
|
|
3741
|
+
buildFullPropsColumn("n", projectionPlan),
|
|
3742
|
+
...buildMetadataColumns("n", projectionPlan, [
|
|
3743
|
+
"version",
|
|
3744
|
+
"valid_from",
|
|
3745
|
+
"valid_to",
|
|
3746
|
+
"created_at",
|
|
3747
|
+
"updated_at",
|
|
3748
|
+
"deleted_at"
|
|
3749
|
+
]),
|
|
3750
|
+
...buildProjectedPropertyColumns("n", projectionPlan, ctx.dialect)
|
|
3751
|
+
];
|
|
3752
|
+
const query = drizzleOrm.sql`${reachableCte}${includedIdsCte} SELECT ${drizzleOrm.sql.join(columns, drizzleOrm.sql`, `)} FROM ${ctx.schema.nodesTable} n WHERE n.graph_id = ${ctx.graphId} AND n.id IN (SELECT id FROM included_ids)`;
|
|
3753
|
+
return ctx.backend.execute(query);
|
|
3754
|
+
}
|
|
3755
|
+
async function fetchSubgraphEdges(ctx, reachableCte, includedIdsCte, projectionPlan) {
|
|
3756
|
+
const edgeKindFilter = compileKindFilter(drizzleOrm.sql.raw("e.kind"), ctx.edgeKinds);
|
|
3757
|
+
const columns = [
|
|
3758
|
+
drizzleOrm.sql`e.id`,
|
|
3759
|
+
drizzleOrm.sql`e.kind`,
|
|
3760
|
+
drizzleOrm.sql`e.from_kind`,
|
|
3761
|
+
drizzleOrm.sql`e.from_id`,
|
|
3762
|
+
drizzleOrm.sql`e.to_kind`,
|
|
3763
|
+
drizzleOrm.sql`e.to_id`,
|
|
3764
|
+
buildFullPropsColumn("e", projectionPlan),
|
|
3765
|
+
...buildMetadataColumns("e", projectionPlan, [
|
|
3766
|
+
"valid_from",
|
|
3767
|
+
"valid_to",
|
|
3768
|
+
"created_at",
|
|
3769
|
+
"updated_at",
|
|
3770
|
+
"deleted_at"
|
|
3771
|
+
]),
|
|
3772
|
+
...buildProjectedPropertyColumns("e", projectionPlan, ctx.dialect)
|
|
3773
|
+
];
|
|
3774
|
+
const query = drizzleOrm.sql`${reachableCte}${includedIdsCte} SELECT ${drizzleOrm.sql.join(columns, drizzleOrm.sql`, `)} FROM ${ctx.schema.edgesTable} e WHERE e.graph_id = ${ctx.graphId} AND ${edgeKindFilter} AND e.deleted_at IS NULL AND e.from_id IN (SELECT id FROM included_ids) AND e.to_id IN (SELECT id FROM included_ids)`;
|
|
3775
|
+
return ctx.backend.execute(query);
|
|
3776
|
+
}
|
|
3777
|
+
function buildMetadataColumns(alias, plan, columns) {
|
|
3778
|
+
if (plan.projectedKinds.size === 0) {
|
|
3779
|
+
return columns.map((col) => drizzleOrm.sql`${drizzleOrm.sql.raw(`${alias}.${col}`)}`);
|
|
3266
3780
|
}
|
|
3267
|
-
const
|
|
3268
|
-
for (const
|
|
3269
|
-
|
|
3270
|
-
if (valueType === "array" || valueType === "object") {
|
|
3271
|
-
throw new chunk44SXEVF4_cjs.UnsupportedPredicateError(
|
|
3272
|
-
"Ordering by JSON arrays or objects is not supported"
|
|
3273
|
-
);
|
|
3274
|
-
}
|
|
3275
|
-
const field2 = compileFieldValue(orderSpec.field, dialect, valueType);
|
|
3276
|
-
const direction = drizzleOrm.sql.raw(orderSpec.direction.toUpperCase());
|
|
3277
|
-
const nulls = orderSpec.nulls ?? (orderSpec.direction === "asc" ? "last" : "first");
|
|
3278
|
-
const nullsDirection = drizzleOrm.sql.raw(nulls === "first" ? "DESC" : "ASC");
|
|
3279
|
-
parts.push(
|
|
3280
|
-
drizzleOrm.sql`(${field2} IS NULL) ${nullsDirection}`,
|
|
3281
|
-
drizzleOrm.sql`${field2} ${direction}`
|
|
3282
|
-
);
|
|
3781
|
+
const metaKinds = [...plan.fullKinds];
|
|
3782
|
+
for (const [kind, kindPlan] of plan.projectedKinds) {
|
|
3783
|
+
if (kindPlan.includeMeta) metaKinds.push(kind);
|
|
3283
3784
|
}
|
|
3284
|
-
|
|
3285
|
-
}
|
|
3286
|
-
function compileLimitOffset(ast) {
|
|
3287
|
-
const parts = [];
|
|
3288
|
-
if (ast.limit !== void 0) {
|
|
3289
|
-
parts.push(drizzleOrm.sql`LIMIT ${ast.limit}`);
|
|
3785
|
+
if (metaKinds.length === 0) {
|
|
3786
|
+
return columns.map((col) => drizzleOrm.sql`NULL AS ${drizzleOrm.sql.raw(col)}`);
|
|
3290
3787
|
}
|
|
3291
|
-
if (
|
|
3292
|
-
|
|
3788
|
+
if (metaKinds.length === plan.fullKinds.length + plan.projectedKinds.size) {
|
|
3789
|
+
return columns.map((col) => drizzleOrm.sql`${drizzleOrm.sql.raw(`${alias}.${col}`)}`);
|
|
3293
3790
|
}
|
|
3294
|
-
|
|
3791
|
+
const filter = compileKindFilter(drizzleOrm.sql.raw(`${alias}.kind`), metaKinds);
|
|
3792
|
+
return columns.map(
|
|
3793
|
+
(col) => drizzleOrm.sql`CASE WHEN ${filter} THEN ${drizzleOrm.sql.raw(`${alias}.${col}`)} ELSE NULL END AS ${drizzleOrm.sql.raw(col)}`
|
|
3794
|
+
);
|
|
3295
3795
|
}
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
embeddings: "typegraph_node_embeddings"
|
|
3300
|
-
};
|
|
3301
|
-
var MAX_IDENTIFIER_LENGTH = 63;
|
|
3302
|
-
var VALID_IDENTIFIER_PATTERN = /^[a-z_][a-z0-9_$]*$/i;
|
|
3303
|
-
function validateTableName(name, label) {
|
|
3304
|
-
if (!name || name.length === 0) {
|
|
3305
|
-
throw new chunk44SXEVF4_cjs.ConfigurationError(`${label} table name cannot be empty`);
|
|
3796
|
+
function buildFullPropsColumn(alias, plan) {
|
|
3797
|
+
if (plan.projectedKinds.size === 0) {
|
|
3798
|
+
return drizzleOrm.sql`${drizzleOrm.sql.raw(`${alias}.props`)} AS props`;
|
|
3306
3799
|
}
|
|
3307
|
-
if (
|
|
3308
|
-
|
|
3309
|
-
`${label} table name exceeds maximum length of ${MAX_IDENTIFIER_LENGTH} characters`
|
|
3310
|
-
);
|
|
3800
|
+
if (plan.fullKinds.length === 0) {
|
|
3801
|
+
return drizzleOrm.sql`NULL AS props`;
|
|
3311
3802
|
}
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3803
|
+
const filter = compileKindFilter(drizzleOrm.sql.raw(`${alias}.kind`), plan.fullKinds);
|
|
3804
|
+
return drizzleOrm.sql`CASE WHEN ${filter} THEN ${drizzleOrm.sql.raw(`${alias}.props`)} ELSE NULL END AS props`;
|
|
3805
|
+
}
|
|
3806
|
+
function buildProjectedPropertyColumns(alias, plan, dialect) {
|
|
3807
|
+
const columns = [];
|
|
3808
|
+
for (const [kind, kindPlan] of plan.projectedKinds.entries()) {
|
|
3809
|
+
for (const fieldPlan of kindPlan.propertyFields) {
|
|
3810
|
+
const extracted = compileTypedJsonExtract({
|
|
3811
|
+
column: drizzleOrm.sql.raw(`${alias}.props`),
|
|
3812
|
+
dialect,
|
|
3813
|
+
pointer: chunkP5CNM325_cjs.jsonPointer([fieldPlan.field]),
|
|
3814
|
+
valueType: fieldPlan.typeInfo?.valueType
|
|
3815
|
+
});
|
|
3816
|
+
columns.push(
|
|
3817
|
+
drizzleOrm.sql`CASE WHEN ${drizzleOrm.sql.raw(alias)}.kind = ${kind} THEN ${extracted} ELSE NULL END AS ${quoteIdentifier(fieldPlan.outputName)}`
|
|
3818
|
+
);
|
|
3819
|
+
}
|
|
3316
3820
|
}
|
|
3821
|
+
return columns;
|
|
3317
3822
|
}
|
|
3318
|
-
function
|
|
3319
|
-
|
|
3823
|
+
function applyProjectedFields(target, row, kindPlan) {
|
|
3824
|
+
for (const fieldPlan of kindPlan.propertyFields) {
|
|
3825
|
+
target[fieldPlan.field] = decodeSelectedValue(
|
|
3826
|
+
row[fieldPlan.outputName],
|
|
3827
|
+
fieldPlan.typeInfo
|
|
3828
|
+
);
|
|
3829
|
+
}
|
|
3320
3830
|
}
|
|
3321
|
-
function
|
|
3322
|
-
const
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3831
|
+
function mapSubgraphNodeRow(row, projectionPlan) {
|
|
3832
|
+
const kindPlan = projectionPlan.projectedKinds.get(row.kind);
|
|
3833
|
+
if (kindPlan === void 0) {
|
|
3834
|
+
return rowToNode({
|
|
3835
|
+
...row,
|
|
3836
|
+
props: normalizeProps(row.props)
|
|
3837
|
+
});
|
|
3838
|
+
}
|
|
3839
|
+
const projectedNode = {
|
|
3840
|
+
kind: row.kind,
|
|
3841
|
+
id: row.id
|
|
3842
|
+
};
|
|
3843
|
+
if (kindPlan.includeMeta) {
|
|
3844
|
+
projectedNode.meta = rowToNodeMeta(row);
|
|
3845
|
+
}
|
|
3846
|
+
applyProjectedFields(projectedNode, row, kindPlan);
|
|
3847
|
+
return projectedNode;
|
|
3848
|
+
}
|
|
3849
|
+
function mapSubgraphEdgeRow(row, projectionPlan) {
|
|
3850
|
+
const kindPlan = projectionPlan.projectedKinds.get(row.kind);
|
|
3851
|
+
if (kindPlan === void 0) {
|
|
3852
|
+
return rowToEdge({
|
|
3853
|
+
...row,
|
|
3854
|
+
props: normalizeProps(row.props)
|
|
3855
|
+
});
|
|
3856
|
+
}
|
|
3857
|
+
const projectedEdge = {
|
|
3858
|
+
id: row.id,
|
|
3859
|
+
kind: row.kind,
|
|
3860
|
+
fromKind: row.from_kind,
|
|
3861
|
+
fromId: row.from_id,
|
|
3862
|
+
toKind: row.to_kind,
|
|
3863
|
+
toId: row.to_id
|
|
3331
3864
|
};
|
|
3865
|
+
if (kindPlan.includeMeta) {
|
|
3866
|
+
projectedEdge.meta = rowToEdgeMeta(row);
|
|
3867
|
+
}
|
|
3868
|
+
applyProjectedFields(projectedEdge, row, kindPlan);
|
|
3869
|
+
return projectedEdge;
|
|
3332
3870
|
}
|
|
3333
|
-
var DEFAULT_SQL_SCHEMA = createSqlSchema();
|
|
3334
3871
|
var OPERATOR_MAP = {
|
|
3335
3872
|
union: "UNION",
|
|
3336
3873
|
unionAll: "UNION ALL",
|
|
@@ -4699,9 +5236,9 @@ function transformPathColumns(rows, state, _dialect) {
|
|
|
4699
5236
|
}
|
|
4700
5237
|
return changed ? result : rows;
|
|
4701
5238
|
}
|
|
4702
|
-
var
|
|
4703
|
-
var
|
|
4704
|
-
function
|
|
5239
|
+
var RESERVED_NODE_KEYS3 = /* @__PURE__ */ new Set(["id", "kind", "meta"]);
|
|
5240
|
+
var RESERVED_EDGE_KEYS3 = /* @__PURE__ */ new Set(["id", "kind", "fromId", "toId", "meta"]);
|
|
5241
|
+
function nullToUndefined3(value) {
|
|
4705
5242
|
return value === null ? void 0 : value;
|
|
4706
5243
|
}
|
|
4707
5244
|
function assignPropsExcludingReserved(target, props, reservedKeys) {
|
|
@@ -4717,13 +5254,13 @@ function buildSelectableNode(row, alias) {
|
|
|
4717
5254
|
const propsRaw = row[`${alias}_props`];
|
|
4718
5255
|
const rawProps = typeof propsRaw === "string" ? JSON.parse(propsRaw) : propsRaw ?? {};
|
|
4719
5256
|
const version = row[`${alias}_version`];
|
|
4720
|
-
const validFrom =
|
|
5257
|
+
const validFrom = nullToUndefined3(
|
|
4721
5258
|
row[`${alias}_valid_from`]
|
|
4722
5259
|
);
|
|
4723
|
-
const validTo =
|
|
5260
|
+
const validTo = nullToUndefined3(row[`${alias}_valid_to`]);
|
|
4724
5261
|
const createdAt = row[`${alias}_created_at`];
|
|
4725
5262
|
const updatedAt = row[`${alias}_updated_at`];
|
|
4726
|
-
const deletedAt =
|
|
5263
|
+
const deletedAt = nullToUndefined3(
|
|
4727
5264
|
row[`${alias}_deleted_at`]
|
|
4728
5265
|
);
|
|
4729
5266
|
const result = {
|
|
@@ -4738,7 +5275,7 @@ function buildSelectableNode(row, alias) {
|
|
|
4738
5275
|
deletedAt
|
|
4739
5276
|
}
|
|
4740
5277
|
};
|
|
4741
|
-
assignPropsExcludingReserved(result, rawProps,
|
|
5278
|
+
assignPropsExcludingReserved(result, rawProps, RESERVED_NODE_KEYS3);
|
|
4742
5279
|
return result;
|
|
4743
5280
|
}
|
|
4744
5281
|
function buildSelectableNodeOrUndefined(row, alias) {
|
|
@@ -4758,13 +5295,13 @@ function buildSelectableEdge(row, alias) {
|
|
|
4758
5295
|
const toId = row[`${alias}_to_id`];
|
|
4759
5296
|
const propsRaw = row[`${alias}_props`];
|
|
4760
5297
|
const rawProps = typeof propsRaw === "string" ? JSON.parse(propsRaw) : propsRaw ?? {};
|
|
4761
|
-
const validFrom =
|
|
5298
|
+
const validFrom = nullToUndefined3(
|
|
4762
5299
|
row[`${alias}_valid_from`]
|
|
4763
5300
|
);
|
|
4764
|
-
const validTo =
|
|
5301
|
+
const validTo = nullToUndefined3(row[`${alias}_valid_to`]);
|
|
4765
5302
|
const createdAt = row[`${alias}_created_at`];
|
|
4766
5303
|
const updatedAt = row[`${alias}_updated_at`];
|
|
4767
|
-
const deletedAt =
|
|
5304
|
+
const deletedAt = nullToUndefined3(
|
|
4768
5305
|
row[`${alias}_deleted_at`]
|
|
4769
5306
|
);
|
|
4770
5307
|
const result = {
|
|
@@ -4780,7 +5317,7 @@ function buildSelectableEdge(row, alias) {
|
|
|
4780
5317
|
deletedAt
|
|
4781
5318
|
}
|
|
4782
5319
|
};
|
|
4783
|
-
assignPropsExcludingReserved(result, rawProps,
|
|
5320
|
+
assignPropsExcludingReserved(result, rawProps, RESERVED_EDGE_KEYS3);
|
|
4784
5321
|
return result;
|
|
4785
5322
|
}
|
|
4786
5323
|
function buildSelectContext(row, startAlias, traversals) {
|
|
@@ -4936,6 +5473,10 @@ var FieldAccessTracker = class {
|
|
|
4936
5473
|
#fields = /* @__PURE__ */ new Map();
|
|
4937
5474
|
record(alias, field2, isSystemField) {
|
|
4938
5475
|
const key = `${alias}\0${field2}`;
|
|
5476
|
+
const existing = this.#fields.get(key);
|
|
5477
|
+
if (existing !== void 0 && existing.isSystemField && !isSystemField) {
|
|
5478
|
+
return;
|
|
5479
|
+
}
|
|
4939
5480
|
this.#fields.set(key, { alias, field: field2, isSystemField });
|
|
4940
5481
|
}
|
|
4941
5482
|
getAccessedFields() {
|
|
@@ -5162,63 +5703,6 @@ function getPlaceholderForValueType(valueType, mode) {
|
|
|
5162
5703
|
}
|
|
5163
5704
|
}
|
|
5164
5705
|
|
|
5165
|
-
// src/query/execution/value-decoder.ts
|
|
5166
|
-
function nullToUndefined2(value) {
|
|
5167
|
-
return value === null ? void 0 : value;
|
|
5168
|
-
}
|
|
5169
|
-
function decodeSelectedValue(value, typeInfo) {
|
|
5170
|
-
const normalized = nullToUndefined2(value);
|
|
5171
|
-
if (normalized === void 0) return void 0;
|
|
5172
|
-
if (typeInfo === void 0) {
|
|
5173
|
-
return normalized;
|
|
5174
|
-
}
|
|
5175
|
-
return decodeByValueType(normalized, typeInfo.valueType);
|
|
5176
|
-
}
|
|
5177
|
-
function decodeByValueType(value, valueType) {
|
|
5178
|
-
switch (valueType) {
|
|
5179
|
-
case "boolean": {
|
|
5180
|
-
if (typeof value === "boolean") return value;
|
|
5181
|
-
if (typeof value === "number") return value !== 0;
|
|
5182
|
-
if (typeof value === "string") {
|
|
5183
|
-
if (value === "0") return false;
|
|
5184
|
-
if (value === "1") return true;
|
|
5185
|
-
if (value.toLowerCase() === "true") return true;
|
|
5186
|
-
if (value.toLowerCase() === "false") return false;
|
|
5187
|
-
}
|
|
5188
|
-
return Boolean(value);
|
|
5189
|
-
}
|
|
5190
|
-
case "number": {
|
|
5191
|
-
if (typeof value === "number") return value;
|
|
5192
|
-
if (typeof value === "string") {
|
|
5193
|
-
const parsed = Number(value);
|
|
5194
|
-
return Number.isNaN(parsed) ? value : parsed;
|
|
5195
|
-
}
|
|
5196
|
-
return value;
|
|
5197
|
-
}
|
|
5198
|
-
case "array":
|
|
5199
|
-
case "object":
|
|
5200
|
-
case "embedding": {
|
|
5201
|
-
if (typeof value !== "string") return value;
|
|
5202
|
-
const trimmed = value.trim();
|
|
5203
|
-
const looksJson = trimmed.startsWith("[") || trimmed.startsWith("{");
|
|
5204
|
-
if (!looksJson) return value;
|
|
5205
|
-
try {
|
|
5206
|
-
return JSON.parse(trimmed);
|
|
5207
|
-
} catch {
|
|
5208
|
-
return value;
|
|
5209
|
-
}
|
|
5210
|
-
}
|
|
5211
|
-
case "string":
|
|
5212
|
-
case "date":
|
|
5213
|
-
case "unknown": {
|
|
5214
|
-
return value;
|
|
5215
|
-
}
|
|
5216
|
-
default: {
|
|
5217
|
-
return value;
|
|
5218
|
-
}
|
|
5219
|
-
}
|
|
5220
|
-
}
|
|
5221
|
-
|
|
5222
5706
|
// src/query/execution/selective-result-mapper.ts
|
|
5223
5707
|
var MissingSelectiveFieldError = class extends Error {
|
|
5224
5708
|
alias;
|
|
@@ -5387,12 +5871,12 @@ function buildRequiredAliasValue(row, plan) {
|
|
|
5387
5871
|
}
|
|
5388
5872
|
};
|
|
5389
5873
|
for (const field2 of plan.systemFields) {
|
|
5390
|
-
base[field2.field] =
|
|
5874
|
+
base[field2.field] = nullToUndefined(row[field2.outputName]);
|
|
5391
5875
|
}
|
|
5392
5876
|
if (plan.metaFields.length > 0) {
|
|
5393
5877
|
const meta = {};
|
|
5394
5878
|
for (const field2 of plan.metaFields) {
|
|
5395
|
-
meta[field2.metaKey] =
|
|
5879
|
+
meta[field2.metaKey] = nullToUndefined(row[field2.outputName]);
|
|
5396
5880
|
}
|
|
5397
5881
|
base.meta = createGuardedProxy(meta, `${plan.alias}.meta`);
|
|
5398
5882
|
}
|
|
@@ -6359,24 +6843,102 @@ var ExecutableQuery = class _ExecutableQuery {
|
|
|
6359
6843
|
if (optimizedResult !== void 0) {
|
|
6360
6844
|
return optimizedResult;
|
|
6361
6845
|
}
|
|
6362
|
-
const compiled = this.compile();
|
|
6363
|
-
const rawRows = await this.#config.backend.execute(compiled);
|
|
6364
|
-
this.#config.dialect ?? "sqlite";
|
|
6365
|
-
const rows = transformPathColumns(rawRows, this.#state);
|
|
6366
|
-
return mapResults(
|
|
6367
|
-
rows,
|
|
6368
|
-
this.#state.startAlias,
|
|
6369
|
-
this.#state.traversals,
|
|
6370
|
-
this.#selectFn
|
|
6371
|
-
);
|
|
6846
|
+
const compiled = this.compile();
|
|
6847
|
+
const rawRows = await this.#config.backend.execute(compiled);
|
|
6848
|
+
this.#config.dialect ?? "sqlite";
|
|
6849
|
+
const rows = transformPathColumns(rawRows, this.#state);
|
|
6850
|
+
return mapResults(
|
|
6851
|
+
rows,
|
|
6852
|
+
this.#state.startAlias,
|
|
6853
|
+
this.#state.traversals,
|
|
6854
|
+
this.#selectFn
|
|
6855
|
+
);
|
|
6856
|
+
}
|
|
6857
|
+
/**
|
|
6858
|
+
* Executes the query against a provided backend.
|
|
6859
|
+
*
|
|
6860
|
+
* Used by `store.batch()` to run multiple queries over a single connection
|
|
6861
|
+
* (e.g., within a transaction). The full compile → execute → transform
|
|
6862
|
+
* pipeline runs identically to `execute()`, but against the given backend.
|
|
6863
|
+
*/
|
|
6864
|
+
async executeOn(backend) {
|
|
6865
|
+
if (hasParameterReferences(this.toAst())) {
|
|
6866
|
+
throw new Error(
|
|
6867
|
+
"Query contains param() references. Use .prepare().execute({...}) instead of .execute()."
|
|
6868
|
+
);
|
|
6869
|
+
}
|
|
6870
|
+
const optimizedResult = await this.#tryOptimizedExecutionOn(backend);
|
|
6871
|
+
if (optimizedResult !== void 0) {
|
|
6872
|
+
return optimizedResult;
|
|
6873
|
+
}
|
|
6874
|
+
const compiled = this.compile();
|
|
6875
|
+
const rawRows = await backend.execute(compiled);
|
|
6876
|
+
this.#config.dialect ?? "sqlite";
|
|
6877
|
+
const rows = transformPathColumns(rawRows, this.#state);
|
|
6878
|
+
return mapResults(
|
|
6879
|
+
rows,
|
|
6880
|
+
this.#state.startAlias,
|
|
6881
|
+
this.#state.traversals,
|
|
6882
|
+
this.#selectFn
|
|
6883
|
+
);
|
|
6884
|
+
}
|
|
6885
|
+
/**
|
|
6886
|
+
* Attempts optimized execution by tracking which fields the select callback accesses.
|
|
6887
|
+
*
|
|
6888
|
+
* Returns undefined if optimization is not possible (callback uses method calls,
|
|
6889
|
+
* computations, or returns whole nodes).
|
|
6890
|
+
*/
|
|
6891
|
+
async #tryOptimizedExecution() {
|
|
6892
|
+
const selectiveFields = this.#getSelectiveFieldsForExecute();
|
|
6893
|
+
if (selectiveFields === void 0) {
|
|
6894
|
+
return void 0;
|
|
6895
|
+
}
|
|
6896
|
+
let compiled;
|
|
6897
|
+
if (this.#cachedOptimizedCompiled === NOT_COMPUTED) {
|
|
6898
|
+
const baseAst = buildQueryAst(this.#config, this.#state);
|
|
6899
|
+
const selectiveAst = {
|
|
6900
|
+
...baseAst,
|
|
6901
|
+
selectiveFields
|
|
6902
|
+
};
|
|
6903
|
+
compiled = compileQuery(
|
|
6904
|
+
selectiveAst,
|
|
6905
|
+
this.#config.graphId,
|
|
6906
|
+
this.#compileOptions()
|
|
6907
|
+
);
|
|
6908
|
+
this.#cachedOptimizedCompiled = compiled;
|
|
6909
|
+
} else {
|
|
6910
|
+
compiled = this.#cachedOptimizedCompiled;
|
|
6911
|
+
}
|
|
6912
|
+
const rawSelectiveRows = await this.#requireBackend().execute(compiled);
|
|
6913
|
+
this.#config.dialect ?? "sqlite";
|
|
6914
|
+
const rows = transformPathColumns(rawSelectiveRows, this.#state);
|
|
6915
|
+
try {
|
|
6916
|
+
return mapSelectiveResults(
|
|
6917
|
+
rows,
|
|
6918
|
+
this.#state,
|
|
6919
|
+
selectiveFields,
|
|
6920
|
+
this.#config.schemaIntrospector,
|
|
6921
|
+
this.#selectFn
|
|
6922
|
+
);
|
|
6923
|
+
} catch (error) {
|
|
6924
|
+
if (error instanceof MissingSelectiveFieldError) {
|
|
6925
|
+
this.#cachedSelectiveFieldsForExecute = void 0;
|
|
6926
|
+
this.#cachedOptimizedCompiled = NOT_COMPUTED;
|
|
6927
|
+
return void 0;
|
|
6928
|
+
}
|
|
6929
|
+
if (error instanceof chunk44SXEVF4_cjs.UnsupportedPredicateError) {
|
|
6930
|
+
this.#cachedSelectiveFieldsForExecute = void 0;
|
|
6931
|
+
this.#cachedOptimizedCompiled = NOT_COMPUTED;
|
|
6932
|
+
return void 0;
|
|
6933
|
+
}
|
|
6934
|
+
throw error;
|
|
6935
|
+
}
|
|
6372
6936
|
}
|
|
6373
6937
|
/**
|
|
6374
|
-
* Attempts optimized execution
|
|
6375
|
-
*
|
|
6376
|
-
* Returns undefined if optimization is not possible (callback uses method calls,
|
|
6377
|
-
* computations, or returns whole nodes).
|
|
6938
|
+
* Attempts optimized execution against a provided backend.
|
|
6939
|
+
* Mirror of #tryOptimizedExecution but delegates to the given backend.
|
|
6378
6940
|
*/
|
|
6379
|
-
async #
|
|
6941
|
+
async #tryOptimizedExecutionOn(backend) {
|
|
6380
6942
|
const selectiveFields = this.#getSelectiveFieldsForExecute();
|
|
6381
6943
|
if (selectiveFields === void 0) {
|
|
6382
6944
|
return void 0;
|
|
@@ -6397,7 +6959,7 @@ var ExecutableQuery = class _ExecutableQuery {
|
|
|
6397
6959
|
} else {
|
|
6398
6960
|
compiled = this.#cachedOptimizedCompiled;
|
|
6399
6961
|
}
|
|
6400
|
-
const rawSelectiveRows = await
|
|
6962
|
+
const rawSelectiveRows = await backend.execute(compiled);
|
|
6401
6963
|
this.#config.dialect ?? "sqlite";
|
|
6402
6964
|
const rows = transformPathColumns(rawSelectiveRows, this.#state);
|
|
6403
6965
|
try {
|
|
@@ -6617,6 +7179,10 @@ var ExecutableQuery = class _ExecutableQuery {
|
|
|
6617
7179
|
#recordOrderByFieldsForPagination(tracker) {
|
|
6618
7180
|
for (const spec of this.#state.orderBy) {
|
|
6619
7181
|
const field2 = spec.field;
|
|
7182
|
+
if (field2.path.length === 1 && field2.path[0] !== "props" && field2.jsonPointer === void 0) {
|
|
7183
|
+
tracker.record(field2.alias, field2.path[0], true);
|
|
7184
|
+
continue;
|
|
7185
|
+
}
|
|
6620
7186
|
if (field2.path.length !== 1 || field2.path[0] !== "props") {
|
|
6621
7187
|
return false;
|
|
6622
7188
|
}
|
|
@@ -6657,7 +7223,19 @@ var ExecutableQuery = class _ExecutableQuery {
|
|
|
6657
7223
|
const alias = spec.field.alias;
|
|
6658
7224
|
const jsonPointer2 = spec.field.jsonPointer;
|
|
6659
7225
|
if (jsonPointer2 === void 0) {
|
|
6660
|
-
|
|
7226
|
+
if (spec.field.path.length !== 1) {
|
|
7227
|
+
throw new MissingSelectiveFieldError(alias, "orderBy");
|
|
7228
|
+
}
|
|
7229
|
+
const fieldName = spec.field.path[0];
|
|
7230
|
+
const outputName2 = outputNameByAliasField.get(
|
|
7231
|
+
`${alias}\0${fieldName}`
|
|
7232
|
+
);
|
|
7233
|
+
if (outputName2 === void 0) {
|
|
7234
|
+
throw new MissingSelectiveFieldError(alias, fieldName);
|
|
7235
|
+
}
|
|
7236
|
+
const aliasObject2 = this.#getOrCreateAliasObject(cursorContext, alias);
|
|
7237
|
+
aliasObject2[fieldName] = nullToUndefined(row[outputName2]);
|
|
7238
|
+
continue;
|
|
6661
7239
|
}
|
|
6662
7240
|
const segments = chunkP5CNM325_cjs.parseJsonPointer(jsonPointer2);
|
|
6663
7241
|
if (segments.length === 0) {
|
|
@@ -6680,14 +7258,7 @@ var ExecutableQuery = class _ExecutableQuery {
|
|
|
6680
7258
|
continue;
|
|
6681
7259
|
}
|
|
6682
7260
|
}
|
|
6683
|
-
|
|
6684
|
-
const existing = cursorContext[alias];
|
|
6685
|
-
if (typeof existing === "object" && existing !== null) {
|
|
6686
|
-
aliasObject = existing;
|
|
6687
|
-
} else {
|
|
6688
|
-
aliasObject = {};
|
|
6689
|
-
cursorContext[alias] = aliasObject;
|
|
6690
|
-
}
|
|
7261
|
+
const aliasObject = this.#getOrCreateAliasObject(cursorContext, alias);
|
|
6691
7262
|
const kindNames = this.#getNodeKindNamesForAlias(alias);
|
|
6692
7263
|
const typeInfo = kindNames ? this.#config.schemaIntrospector.getSharedFieldTypeInfo(
|
|
6693
7264
|
kindNames,
|
|
@@ -6714,6 +7285,15 @@ var ExecutableQuery = class _ExecutableQuery {
|
|
|
6714
7285
|
}
|
|
6715
7286
|
return cursorContext;
|
|
6716
7287
|
}
|
|
7288
|
+
#getOrCreateAliasObject(cursorContext, alias) {
|
|
7289
|
+
const existing = cursorContext[alias];
|
|
7290
|
+
if (typeof existing === "object" && existing !== null) {
|
|
7291
|
+
return existing;
|
|
7292
|
+
}
|
|
7293
|
+
const created = {};
|
|
7294
|
+
cursorContext[alias] = created;
|
|
7295
|
+
return created;
|
|
7296
|
+
}
|
|
6717
7297
|
#getNodeKindNamesForAlias(alias) {
|
|
6718
7298
|
if (alias === this.#state.startAlias) {
|
|
6719
7299
|
return this.#state.startKinds;
|
|
@@ -7541,9 +8121,12 @@ var QueryBuilder = class _QueryBuilder {
|
|
|
7541
8121
|
* Orders results.
|
|
7542
8122
|
*/
|
|
7543
8123
|
orderBy(alias, field2, direction = "asc") {
|
|
7544
|
-
const
|
|
7545
|
-
const typeInfo =
|
|
7546
|
-
const orderSpec = {
|
|
8124
|
+
const isSystem = field2 === "id" || field2 === "kind";
|
|
8125
|
+
const typeInfo = isSystem ? void 0 : this.#getOrderByTypeInfo(alias, field2);
|
|
8126
|
+
const orderSpec = isSystem ? {
|
|
8127
|
+
field: fieldRef(alias, [field2], { valueType: "string" }),
|
|
8128
|
+
direction
|
|
8129
|
+
} : {
|
|
7547
8130
|
field: fieldRef(alias, ["props"], {
|
|
7548
8131
|
jsonPointer: chunkP5CNM325_cjs.jsonPointer([field2]),
|
|
7549
8132
|
valueType: typeInfo?.valueType,
|
|
@@ -7557,6 +8140,10 @@ var QueryBuilder = class _QueryBuilder {
|
|
|
7557
8140
|
};
|
|
7558
8141
|
return new _QueryBuilder(this.#config, newState);
|
|
7559
8142
|
}
|
|
8143
|
+
#getOrderByTypeInfo(alias, field2) {
|
|
8144
|
+
const kindNames = this.#getKindNamesForAlias(alias);
|
|
8145
|
+
return kindNames ? this.#config.schemaIntrospector.getSharedFieldTypeInfo(kindNames, field2) : void 0;
|
|
8146
|
+
}
|
|
7560
8147
|
/**
|
|
7561
8148
|
* Limits the number of results.
|
|
7562
8149
|
*/
|
|
@@ -8030,6 +8617,29 @@ var UnionableQuery = class _UnionableQuery {
|
|
|
8030
8617
|
}
|
|
8031
8618
|
return rows;
|
|
8032
8619
|
}
|
|
8620
|
+
/**
|
|
8621
|
+
* Executes the combined query against a provided backend.
|
|
8622
|
+
*
|
|
8623
|
+
* Used by `store.batch()` to run multiple queries over a single connection.
|
|
8624
|
+
*/
|
|
8625
|
+
async executeOn(backend) {
|
|
8626
|
+
if (composableQueryHasParameterReferences(this.toAst())) {
|
|
8627
|
+
throw new Error(
|
|
8628
|
+
"Query contains param() references. Use .prepare().execute({...}) instead of .execute()."
|
|
8629
|
+
);
|
|
8630
|
+
}
|
|
8631
|
+
const compiled = this.compile();
|
|
8632
|
+
const rows = await backend.execute(compiled);
|
|
8633
|
+
if (this.#state.selectFn && this.#state.startAlias) {
|
|
8634
|
+
return mapResults(
|
|
8635
|
+
rows,
|
|
8636
|
+
this.#state.startAlias,
|
|
8637
|
+
this.#state.traversals ?? [],
|
|
8638
|
+
this.#state.selectFn
|
|
8639
|
+
);
|
|
8640
|
+
}
|
|
8641
|
+
return rows;
|
|
8642
|
+
}
|
|
8033
8643
|
};
|
|
8034
8644
|
|
|
8035
8645
|
// src/query/builder/aggregates.ts
|
|
@@ -9250,67 +9860,6 @@ async function checkCardinalityConstraint(ctx, edgeKind, cardinality, fromKind,
|
|
|
9250
9860
|
}
|
|
9251
9861
|
}
|
|
9252
9862
|
|
|
9253
|
-
// src/store/row-mappers.ts
|
|
9254
|
-
var RESERVED_NODE_KEYS3 = /* @__PURE__ */ new Set(["id", "kind", "meta"]);
|
|
9255
|
-
function nullToUndefined3(value) {
|
|
9256
|
-
return value === null ? void 0 : value;
|
|
9257
|
-
}
|
|
9258
|
-
function filterReservedKeys(props, reservedKeys) {
|
|
9259
|
-
const filtered = {};
|
|
9260
|
-
for (const [key, value] of Object.entries(props)) {
|
|
9261
|
-
if (!reservedKeys.has(key)) {
|
|
9262
|
-
filtered[key] = value;
|
|
9263
|
-
}
|
|
9264
|
-
}
|
|
9265
|
-
return filtered;
|
|
9266
|
-
}
|
|
9267
|
-
function rowToNode(row) {
|
|
9268
|
-
const rawProps = JSON.parse(row.props);
|
|
9269
|
-
const props = filterReservedKeys(rawProps, RESERVED_NODE_KEYS3);
|
|
9270
|
-
return {
|
|
9271
|
-
kind: row.kind,
|
|
9272
|
-
id: row.id,
|
|
9273
|
-
meta: {
|
|
9274
|
-
version: row.version,
|
|
9275
|
-
validFrom: nullToUndefined3(row.valid_from),
|
|
9276
|
-
validTo: nullToUndefined3(row.valid_to),
|
|
9277
|
-
createdAt: row.created_at,
|
|
9278
|
-
updatedAt: row.updated_at,
|
|
9279
|
-
deletedAt: nullToUndefined3(row.deleted_at)
|
|
9280
|
-
},
|
|
9281
|
-
...props
|
|
9282
|
-
};
|
|
9283
|
-
}
|
|
9284
|
-
var RESERVED_EDGE_KEYS3 = /* @__PURE__ */ new Set([
|
|
9285
|
-
"id",
|
|
9286
|
-
"kind",
|
|
9287
|
-
"meta",
|
|
9288
|
-
"fromKind",
|
|
9289
|
-
"fromId",
|
|
9290
|
-
"toKind",
|
|
9291
|
-
"toId"
|
|
9292
|
-
]);
|
|
9293
|
-
function rowToEdge(row) {
|
|
9294
|
-
const rawProps = JSON.parse(row.props);
|
|
9295
|
-
const props = filterReservedKeys(rawProps, RESERVED_EDGE_KEYS3);
|
|
9296
|
-
return {
|
|
9297
|
-
id: row.id,
|
|
9298
|
-
kind: row.kind,
|
|
9299
|
-
fromKind: row.from_kind,
|
|
9300
|
-
fromId: row.from_id,
|
|
9301
|
-
toKind: row.to_kind,
|
|
9302
|
-
toId: row.to_id,
|
|
9303
|
-
meta: {
|
|
9304
|
-
validFrom: nullToUndefined3(row.valid_from),
|
|
9305
|
-
validTo: nullToUndefined3(row.valid_to),
|
|
9306
|
-
createdAt: row.created_at,
|
|
9307
|
-
updatedAt: row.updated_at,
|
|
9308
|
-
deletedAt: nullToUndefined3(row.deleted_at)
|
|
9309
|
-
},
|
|
9310
|
-
...props
|
|
9311
|
-
};
|
|
9312
|
-
}
|
|
9313
|
-
|
|
9314
9863
|
// src/store/operations/edge-operations.ts
|
|
9315
9864
|
function getEdgeRegistration(graph, kind) {
|
|
9316
9865
|
const registration = graph.edges[kind];
|
|
@@ -11184,142 +11733,6 @@ async function executeNodeBulkGetOrCreateByConstraint(ctx, kind, constraintName,
|
|
|
11184
11733
|
}
|
|
11185
11734
|
return results;
|
|
11186
11735
|
}
|
|
11187
|
-
var DEFAULT_SUBGRAPH_MAX_DEPTH = 10;
|
|
11188
|
-
function normalizeProps(value) {
|
|
11189
|
-
return typeof value === "string" ? value : JSON.stringify(value ?? {});
|
|
11190
|
-
}
|
|
11191
|
-
async function executeSubgraph(params) {
|
|
11192
|
-
const { options } = params;
|
|
11193
|
-
if (options.edges.length === 0) {
|
|
11194
|
-
return { nodes: [], edges: [] };
|
|
11195
|
-
}
|
|
11196
|
-
const maxDepth = Math.min(
|
|
11197
|
-
options.maxDepth ?? DEFAULT_SUBGRAPH_MAX_DEPTH,
|
|
11198
|
-
MAX_RECURSIVE_DEPTH
|
|
11199
|
-
);
|
|
11200
|
-
const ctx = {
|
|
11201
|
-
graphId: params.graphId,
|
|
11202
|
-
rootId: params.rootId,
|
|
11203
|
-
edgeKinds: options.edges,
|
|
11204
|
-
maxDepth,
|
|
11205
|
-
includeKinds: options.includeKinds,
|
|
11206
|
-
excludeRoot: options.excludeRoot ?? false,
|
|
11207
|
-
direction: options.direction ?? "out",
|
|
11208
|
-
cyclePolicy: options.cyclePolicy ?? "prevent",
|
|
11209
|
-
dialect: params.dialect,
|
|
11210
|
-
schema: params.schema ?? DEFAULT_SQL_SCHEMA,
|
|
11211
|
-
backend: params.backend
|
|
11212
|
-
};
|
|
11213
|
-
const reachableCte = buildReachableCte(ctx);
|
|
11214
|
-
const includedIdsCte = buildIncludedIdsCte(ctx);
|
|
11215
|
-
const [nodeRows, edgeRows] = await Promise.all([
|
|
11216
|
-
fetchSubgraphNodes(ctx, reachableCte, includedIdsCte),
|
|
11217
|
-
fetchSubgraphEdges(ctx, reachableCte, includedIdsCte)
|
|
11218
|
-
]);
|
|
11219
|
-
const nodes = nodeRows.map(
|
|
11220
|
-
(row) => rowToNode({ ...row, props: normalizeProps(row.props) })
|
|
11221
|
-
);
|
|
11222
|
-
const edges = edgeRows.map(
|
|
11223
|
-
(row) => rowToEdge({ ...row, props: normalizeProps(row.props) })
|
|
11224
|
-
);
|
|
11225
|
-
return {
|
|
11226
|
-
nodes,
|
|
11227
|
-
edges
|
|
11228
|
-
};
|
|
11229
|
-
}
|
|
11230
|
-
function buildReachableCte(ctx) {
|
|
11231
|
-
const shouldTrackPath = ctx.cyclePolicy === "prevent";
|
|
11232
|
-
const edgeKindFilter = compileKindFilter(drizzleOrm.sql.raw("e.kind"), ctx.edgeKinds);
|
|
11233
|
-
const initialPath = shouldTrackPath ? ctx.dialect.initializePath(drizzleOrm.sql.raw("n.id")) : void 0;
|
|
11234
|
-
const pathExtension = shouldTrackPath ? ctx.dialect.extendPath(drizzleOrm.sql.raw("r.path"), drizzleOrm.sql.raw("n.id")) : void 0;
|
|
11235
|
-
const cycleCheck = shouldTrackPath ? ctx.dialect.cycleCheck(drizzleOrm.sql.raw("n.id"), drizzleOrm.sql.raw("r.path")) : void 0;
|
|
11236
|
-
const baseColumns = [drizzleOrm.sql`n.id`, drizzleOrm.sql`n.kind`, drizzleOrm.sql`0 AS depth`];
|
|
11237
|
-
if (initialPath !== void 0) {
|
|
11238
|
-
baseColumns.push(drizzleOrm.sql`${initialPath} AS path`);
|
|
11239
|
-
}
|
|
11240
|
-
const baseCase = drizzleOrm.sql`SELECT ${drizzleOrm.sql.join(baseColumns, drizzleOrm.sql`, `)} FROM ${ctx.schema.nodesTable} n WHERE n.graph_id = ${ctx.graphId} AND n.id = ${ctx.rootId} AND n.deleted_at IS NULL`;
|
|
11241
|
-
const recursiveColumns = [
|
|
11242
|
-
drizzleOrm.sql`n.id`,
|
|
11243
|
-
drizzleOrm.sql`n.kind`,
|
|
11244
|
-
drizzleOrm.sql`r.depth + 1 AS depth`
|
|
11245
|
-
];
|
|
11246
|
-
if (pathExtension !== void 0) {
|
|
11247
|
-
recursiveColumns.push(drizzleOrm.sql`${pathExtension} AS path`);
|
|
11248
|
-
}
|
|
11249
|
-
const recursiveWhereClauses = [
|
|
11250
|
-
drizzleOrm.sql`e.graph_id = ${ctx.graphId}`,
|
|
11251
|
-
edgeKindFilter,
|
|
11252
|
-
drizzleOrm.sql`e.deleted_at IS NULL`,
|
|
11253
|
-
drizzleOrm.sql`n.deleted_at IS NULL`,
|
|
11254
|
-
drizzleOrm.sql`r.depth < ${ctx.maxDepth}`
|
|
11255
|
-
];
|
|
11256
|
-
if (cycleCheck !== void 0) {
|
|
11257
|
-
recursiveWhereClauses.push(cycleCheck);
|
|
11258
|
-
}
|
|
11259
|
-
const forceWorktableOuterJoinOrder = ctx.dialect.capabilities.forceRecursiveWorktableOuterJoinOrder;
|
|
11260
|
-
const recursiveCase = ctx.direction === "both" ? compileBidirectionalBranch({
|
|
11261
|
-
recursiveColumns,
|
|
11262
|
-
whereClauses: recursiveWhereClauses,
|
|
11263
|
-
forceWorktableOuterJoinOrder,
|
|
11264
|
-
schema: ctx.schema
|
|
11265
|
-
}) : compileRecursiveBranch({
|
|
11266
|
-
recursiveColumns,
|
|
11267
|
-
whereClauses: recursiveWhereClauses,
|
|
11268
|
-
joinField: "from_id",
|
|
11269
|
-
targetField: "to_id",
|
|
11270
|
-
targetKindField: "to_kind",
|
|
11271
|
-
forceWorktableOuterJoinOrder,
|
|
11272
|
-
schema: ctx.schema
|
|
11273
|
-
});
|
|
11274
|
-
return drizzleOrm.sql`WITH RECURSIVE reachable AS (${baseCase} UNION ALL ${recursiveCase})`;
|
|
11275
|
-
}
|
|
11276
|
-
function compileRecursiveBranch(params) {
|
|
11277
|
-
const columns = [...params.recursiveColumns];
|
|
11278
|
-
const selectClause = drizzleOrm.sql`SELECT ${drizzleOrm.sql.join(columns, drizzleOrm.sql`, `)}`;
|
|
11279
|
-
const nodeJoin = drizzleOrm.sql`JOIN ${params.schema.nodesTable} n ON n.graph_id = e.graph_id AND n.id = e.${drizzleOrm.sql.raw(params.targetField)} AND n.kind = e.${drizzleOrm.sql.raw(params.targetKindField)}`;
|
|
11280
|
-
if (params.forceWorktableOuterJoinOrder) {
|
|
11281
|
-
const allWhere = [
|
|
11282
|
-
...params.whereClauses,
|
|
11283
|
-
drizzleOrm.sql`e.${drizzleOrm.sql.raw(params.joinField)} = r.id`
|
|
11284
|
-
];
|
|
11285
|
-
return drizzleOrm.sql`${selectClause} FROM reachable r CROSS JOIN ${params.schema.edgesTable} e ${nodeJoin} WHERE ${drizzleOrm.sql.join(allWhere, drizzleOrm.sql` AND `)}`;
|
|
11286
|
-
}
|
|
11287
|
-
const where = [...params.whereClauses];
|
|
11288
|
-
return drizzleOrm.sql`${selectClause} FROM reachable r JOIN ${params.schema.edgesTable} e ON e.${drizzleOrm.sql.raw(params.joinField)} = r.id ${nodeJoin} WHERE ${drizzleOrm.sql.join(where, drizzleOrm.sql` AND `)}`;
|
|
11289
|
-
}
|
|
11290
|
-
function compileBidirectionalBranch(params) {
|
|
11291
|
-
const columns = [...params.recursiveColumns];
|
|
11292
|
-
const selectClause = drizzleOrm.sql`SELECT ${drizzleOrm.sql.join(columns, drizzleOrm.sql`, `)}`;
|
|
11293
|
-
const nodeJoin = drizzleOrm.sql`JOIN ${params.schema.nodesTable} n ON n.graph_id = e.graph_id AND ((e.to_id = r.id AND n.id = e.from_id AND n.kind = e.from_kind) OR (e.from_id = r.id AND n.id = e.to_id AND n.kind = e.to_kind))`;
|
|
11294
|
-
if (params.forceWorktableOuterJoinOrder) {
|
|
11295
|
-
const allWhere = [
|
|
11296
|
-
...params.whereClauses,
|
|
11297
|
-
drizzleOrm.sql`(e.from_id = r.id OR e.to_id = r.id)`
|
|
11298
|
-
];
|
|
11299
|
-
return drizzleOrm.sql`${selectClause} FROM reachable r CROSS JOIN ${params.schema.edgesTable} e ${nodeJoin} WHERE ${drizzleOrm.sql.join(allWhere, drizzleOrm.sql` AND `)}`;
|
|
11300
|
-
}
|
|
11301
|
-
return drizzleOrm.sql`${selectClause} FROM reachable r JOIN ${params.schema.edgesTable} e ON (e.from_id = r.id OR e.to_id = r.id) ${nodeJoin} WHERE ${drizzleOrm.sql.join([...params.whereClauses], drizzleOrm.sql` AND `)}`;
|
|
11302
|
-
}
|
|
11303
|
-
function buildIncludedIdsCte(ctx) {
|
|
11304
|
-
const filters = [];
|
|
11305
|
-
if (ctx.includeKinds !== void 0 && ctx.includeKinds.length > 0) {
|
|
11306
|
-
filters.push(compileKindFilter(drizzleOrm.sql.raw("kind"), ctx.includeKinds));
|
|
11307
|
-
}
|
|
11308
|
-
if (ctx.excludeRoot) {
|
|
11309
|
-
filters.push(drizzleOrm.sql`id != ${ctx.rootId}`);
|
|
11310
|
-
}
|
|
11311
|
-
const whereClause = filters.length > 0 ? drizzleOrm.sql` WHERE ${drizzleOrm.sql.join(filters, drizzleOrm.sql` AND `)}` : drizzleOrm.sql``;
|
|
11312
|
-
return drizzleOrm.sql`, included_ids AS (SELECT DISTINCT id FROM reachable${whereClause})`;
|
|
11313
|
-
}
|
|
11314
|
-
async function fetchSubgraphNodes(ctx, reachableCte, includedIdsCte) {
|
|
11315
|
-
const query = drizzleOrm.sql`${reachableCte}${includedIdsCte} SELECT n.kind, n.id, n.props, n.version, n.valid_from, n.valid_to, n.created_at, n.updated_at, n.deleted_at FROM ${ctx.schema.nodesTable} n WHERE n.graph_id = ${ctx.graphId} AND n.id IN (SELECT id FROM included_ids)`;
|
|
11316
|
-
return ctx.backend.execute(query);
|
|
11317
|
-
}
|
|
11318
|
-
async function fetchSubgraphEdges(ctx, reachableCte, includedIdsCte) {
|
|
11319
|
-
const edgeKindFilter = compileKindFilter(drizzleOrm.sql.raw("e.kind"), ctx.edgeKinds);
|
|
11320
|
-
const query = drizzleOrm.sql`${reachableCte}${includedIdsCte} SELECT e.id, e.kind, e.from_kind, e.from_id, e.to_kind, e.to_id, e.props, e.valid_from, e.valid_to, e.created_at, e.updated_at, e.deleted_at FROM ${ctx.schema.edgesTable} e WHERE e.graph_id = ${ctx.graphId} AND ${edgeKindFilter} AND e.deleted_at IS NULL AND e.from_id IN (SELECT id FROM included_ids) AND e.to_id IN (SELECT id FROM included_ids)`;
|
|
11321
|
-
return ctx.backend.execute(query);
|
|
11322
|
-
}
|
|
11323
11736
|
|
|
11324
11737
|
// src/store/store.ts
|
|
11325
11738
|
var Store = class {
|
|
@@ -11523,6 +11936,46 @@ var Store = class {
|
|
|
11523
11936
|
query() {
|
|
11524
11937
|
return this.#createQueryForBackend(this.#backend);
|
|
11525
11938
|
}
|
|
11939
|
+
// === Batch Query Execution ===
|
|
11940
|
+
/**
|
|
11941
|
+
* Executes multiple queries over a single connection with snapshot consistency.
|
|
11942
|
+
*
|
|
11943
|
+
* Acquires one connection via an implicit transaction, executes each query
|
|
11944
|
+
* sequentially on that connection, and returns a typed tuple of results.
|
|
11945
|
+
* Each query preserves its own result type, projection, filtering,
|
|
11946
|
+
* sorting, and pagination.
|
|
11947
|
+
*
|
|
11948
|
+
* Read-only — use `bulkCreate`, `bulkInsert`, etc. for write batching.
|
|
11949
|
+
*
|
|
11950
|
+
* @example
|
|
11951
|
+
* ```typescript
|
|
11952
|
+
* const [people, companies] = await store.batch(
|
|
11953
|
+
* store.query()
|
|
11954
|
+
* .from("Person", "p")
|
|
11955
|
+
* .select((ctx) => ({ id: ctx.p.id, name: ctx.p.name })),
|
|
11956
|
+
* store.query()
|
|
11957
|
+
* .from("Company", "c")
|
|
11958
|
+
* .select((ctx) => ({ id: ctx.c.id, name: ctx.c.name }))
|
|
11959
|
+
* .orderBy("c", "name", "asc")
|
|
11960
|
+
* .limit(5),
|
|
11961
|
+
* );
|
|
11962
|
+
* // people: readonly { id: string; name: string }[]
|
|
11963
|
+
* // companies: readonly { id: string; name: string }[]
|
|
11964
|
+
* ```
|
|
11965
|
+
*
|
|
11966
|
+
* @param queries - Two or more executable queries (from `.select()` or set operations)
|
|
11967
|
+
* @returns A tuple with per-query typed results, preserving input order
|
|
11968
|
+
*/
|
|
11969
|
+
async batch(...queries) {
|
|
11970
|
+
return this.#backend.transaction(async (txBackend) => {
|
|
11971
|
+
const results = [];
|
|
11972
|
+
for (const query of queries) {
|
|
11973
|
+
const result = await query.executeOn(txBackend);
|
|
11974
|
+
results.push(result);
|
|
11975
|
+
}
|
|
11976
|
+
return results;
|
|
11977
|
+
});
|
|
11978
|
+
}
|
|
11526
11979
|
// === Subgraph Extraction ===
|
|
11527
11980
|
/**
|
|
11528
11981
|
* Extracts a typed subgraph by traversing from a root node.
|
|
@@ -11548,6 +12001,7 @@ var Store = class {
|
|
|
11548
12001
|
*/
|
|
11549
12002
|
async subgraph(rootId, options) {
|
|
11550
12003
|
return executeSubgraph({
|
|
12004
|
+
graph: this.#graph,
|
|
11551
12005
|
graphId: this.graphId,
|
|
11552
12006
|
rootId,
|
|
11553
12007
|
backend: this.#backend,
|
|
@@ -11909,6 +12363,7 @@ exports.createStore = createStore;
|
|
|
11909
12363
|
exports.createStoreWithSchema = createStoreWithSchema;
|
|
11910
12364
|
exports.defineEdge = defineEdge;
|
|
11911
12365
|
exports.defineNode = defineNode;
|
|
12366
|
+
exports.defineSubgraphProject = defineSubgraphProject;
|
|
11912
12367
|
exports.differentFrom = differentFrom;
|
|
11913
12368
|
exports.disjointWith = disjointWith;
|
|
11914
12369
|
exports.equivalentTo = equivalentTo;
|