@utaba/deep-memory 0.17.0 → 0.19.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/{StorageProvider-DDTLUcuj.d.ts → StorageProvider-CgWRfvIZ.d.ts} +1 -1
- package/dist/{StorageProvider-DGH7bVuK.d.cts → StorageProvider-RPhT7vtH.d.cts} +1 -1
- package/dist/index.cjs +131 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +131 -45
- package/dist/index.js.map +1 -1
- package/dist/{portability-Dbm6vCdD.d.cts → portability-BHyXmv5-.d.cts} +21 -5
- package/dist/{portability-Dbm6vCdD.d.ts → portability-BHyXmv5-.d.ts} +21 -5
- package/dist/providers/index.d.cts +4 -4
- package/dist/providers/index.d.ts +4 -4
- package/dist/testing/conformance.cjs +30 -2
- package/dist/testing/conformance.cjs.map +1 -1
- package/dist/testing/conformance.d.cts +2 -2
- package/dist/testing/conformance.d.ts +2 -2
- package/dist/testing/conformance.js +30 -2
- package/dist/testing/conformance.js.map +1 -1
- package/dist/{traversal-OkXViSTI.d.ts → traversal-BK_3Cqj3.d.cts} +12 -7
- package/dist/{traversal-1f35drOx.d.cts → traversal-CIGJcdCb.d.ts} +12 -7
- package/dist/types/index.d.cts +3 -3
- package/dist/types/index.d.ts +3 -3
- package/package.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { au as StorageRepositoryConfig, aB as StoredRepository, ad as RepositoryFilter, T as PaginatedResult, aC as StoredRepositorySummary, ah as RepositoryUpdate, g as DeleteProgressCallback, af as RepositoryStats, O as MemoryVocabulary, U as PaginationOptions, aM as VocabularyChangeRecord, ay as StoredEntity, az as StoredEntityUpdate, an as StorageFindQuery, aA as StoredRelationship, a5 as RelationshipQueryOptions, am as StorageExploreOptions, ao as StorageNeighborhood, as as StoragePathOptions, at as StoragePathResult, aw as StorageTimelineOptions, ax as StorageTimelineResult, s as ExportChunk, J as ImportChunk, B as BulkImportOptions, d as BulkImportResult } from './portability-
|
|
1
|
+
import { au as StorageRepositoryConfig, aB as StoredRepository, ad as RepositoryFilter, T as PaginatedResult, aC as StoredRepositorySummary, ah as RepositoryUpdate, g as DeleteProgressCallback, af as RepositoryStats, O as MemoryVocabulary, U as PaginationOptions, aM as VocabularyChangeRecord, ay as StoredEntity, az as StoredEntityUpdate, an as StorageFindQuery, aA as StoredRelationship, a5 as RelationshipQueryOptions, am as StorageExploreOptions, ao as StorageNeighborhood, as as StoragePathOptions, at as StoragePathResult, aw as StorageTimelineOptions, ax as StorageTimelineResult, s as ExportChunk, J as ImportChunk, B as BulkImportOptions, d as BulkImportResult } from './portability-BHyXmv5-.js';
|
|
2
2
|
|
|
3
3
|
/** Result returned by ensureSchema describing what actions were taken. */
|
|
4
4
|
interface EnsureSchemaResult {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { au as StorageRepositoryConfig, aB as StoredRepository, ad as RepositoryFilter, T as PaginatedResult, aC as StoredRepositorySummary, ah as RepositoryUpdate, g as DeleteProgressCallback, af as RepositoryStats, O as MemoryVocabulary, U as PaginationOptions, aM as VocabularyChangeRecord, ay as StoredEntity, az as StoredEntityUpdate, an as StorageFindQuery, aA as StoredRelationship, a5 as RelationshipQueryOptions, am as StorageExploreOptions, ao as StorageNeighborhood, as as StoragePathOptions, at as StoragePathResult, aw as StorageTimelineOptions, ax as StorageTimelineResult, s as ExportChunk, J as ImportChunk, B as BulkImportOptions, d as BulkImportResult } from './portability-
|
|
1
|
+
import { au as StorageRepositoryConfig, aB as StoredRepository, ad as RepositoryFilter, T as PaginatedResult, aC as StoredRepositorySummary, ah as RepositoryUpdate, g as DeleteProgressCallback, af as RepositoryStats, O as MemoryVocabulary, U as PaginationOptions, aM as VocabularyChangeRecord, ay as StoredEntity, az as StoredEntityUpdate, an as StorageFindQuery, aA as StoredRelationship, a5 as RelationshipQueryOptions, am as StorageExploreOptions, ao as StorageNeighborhood, as as StoragePathOptions, at as StoragePathResult, aw as StorageTimelineOptions, ax as StorageTimelineResult, s as ExportChunk, J as ImportChunk, B as BulkImportOptions, d as BulkImportResult } from './portability-BHyXmv5-.cjs';
|
|
2
2
|
|
|
3
3
|
/** Result returned by ensureSchema describing what actions were taken. */
|
|
4
4
|
interface EnsureSchemaResult {
|
package/dist/index.cjs
CHANGED
|
@@ -1438,13 +1438,36 @@ async function executeFallbackTraversal(repositoryId, storage, spec) {
|
|
|
1438
1438
|
unionFullLength = unionElements.length;
|
|
1439
1439
|
const pageSlice = unionElements.slice(offset, offset + limit);
|
|
1440
1440
|
const pageEntries = [];
|
|
1441
|
+
const pageEntityIds = /* @__PURE__ */ new Set();
|
|
1441
1442
|
for (const element of pageSlice) {
|
|
1442
1443
|
if (element.kind === "entity") {
|
|
1443
|
-
|
|
1444
|
+
if (!pageEntityIds.has(element.entry.entity.id)) {
|
|
1445
|
+
pageEntityIds.add(element.entry.entity.id);
|
|
1446
|
+
pageEntries.push(element.entry);
|
|
1447
|
+
}
|
|
1444
1448
|
} else {
|
|
1445
1449
|
pagedAllRels.push(element.rel);
|
|
1446
1450
|
}
|
|
1447
1451
|
}
|
|
1452
|
+
if (pagedAllRels.length > 0) {
|
|
1453
|
+
const entityIndex = /* @__PURE__ */ new Map();
|
|
1454
|
+
for (const el of unionElements) {
|
|
1455
|
+
if (el.kind === "entity" && !entityIndex.has(el.entry.entity.id)) {
|
|
1456
|
+
entityIndex.set(el.entry.entity.id, el.entry);
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
for (const rel of pagedAllRels) {
|
|
1460
|
+
for (const endpointId of [rel.sourceEntityId, rel.targetEntityId]) {
|
|
1461
|
+
if (!pageEntityIds.has(endpointId)) {
|
|
1462
|
+
const entry = entityIndex.get(endpointId);
|
|
1463
|
+
if (entry) {
|
|
1464
|
+
pageEntityIds.add(endpointId);
|
|
1465
|
+
pageEntries.push(entry);
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1448
1471
|
paged = pageEntries;
|
|
1449
1472
|
total = pageEntries.length + pagedAllRels.length;
|
|
1450
1473
|
} else {
|
|
@@ -1472,13 +1495,13 @@ async function executeFallbackTraversal(repositoryId, storage, spec) {
|
|
|
1472
1495
|
direction: "both",
|
|
1473
1496
|
limit: 1e4
|
|
1474
1497
|
});
|
|
1475
|
-
const summary = {
|
|
1498
|
+
const summary = { out: {}, in: {} };
|
|
1476
1499
|
for (const rel of result.items) {
|
|
1477
1500
|
if (rel.sourceEntityId === entry.entity.id) {
|
|
1478
|
-
summary.
|
|
1501
|
+
summary.out[rel.relationshipType] = (summary.out[rel.relationshipType] ?? 0) + 1;
|
|
1479
1502
|
}
|
|
1480
1503
|
if (rel.targetEntityId === entry.entity.id) {
|
|
1481
|
-
summary.
|
|
1504
|
+
summary.in[rel.relationshipType] = (summary.in[rel.relationshipType] ?? 0) + 1;
|
|
1482
1505
|
}
|
|
1483
1506
|
}
|
|
1484
1507
|
return summary;
|
|
@@ -1541,7 +1564,7 @@ async function executeFallbackTraversal(repositoryId, storage, spec) {
|
|
|
1541
1564
|
type: rel.relationshipType,
|
|
1542
1565
|
sourceEntityId: rel.sourceEntityId,
|
|
1543
1566
|
targetEntityId: rel.targetEntityId,
|
|
1544
|
-
direction: "
|
|
1567
|
+
direction: "out",
|
|
1545
1568
|
properties: rel.properties
|
|
1546
1569
|
}));
|
|
1547
1570
|
} else if (!suppressEntities && spec.returnMode === "path") {
|
|
@@ -1556,7 +1579,7 @@ async function executeFallbackTraversal(repositoryId, storage, spec) {
|
|
|
1556
1579
|
type: rel.relationshipType,
|
|
1557
1580
|
sourceEntityId: rel.sourceEntityId,
|
|
1558
1581
|
targetEntityId: rel.targetEntityId,
|
|
1559
|
-
direction: fromId === rel.sourceEntityId ? "
|
|
1582
|
+
direction: fromId === rel.sourceEntityId ? "out" : "in",
|
|
1560
1583
|
properties: rel.properties
|
|
1561
1584
|
});
|
|
1562
1585
|
}
|
|
@@ -1595,7 +1618,7 @@ async function executeFallbackTraversal(repositoryId, storage, spec) {
|
|
|
1595
1618
|
type: rel.relationshipType,
|
|
1596
1619
|
sourceEntityId: rel.sourceEntityId,
|
|
1597
1620
|
targetEntityId: rel.targetEntityId,
|
|
1598
|
-
direction: fromId === rel.sourceEntityId ? "
|
|
1621
|
+
direction: fromId === rel.sourceEntityId ? "out" : "in",
|
|
1599
1622
|
properties: rel.properties
|
|
1600
1623
|
};
|
|
1601
1624
|
})
|
|
@@ -1624,7 +1647,7 @@ async function executeFallbackTraversal(repositoryId, storage, spec) {
|
|
|
1624
1647
|
};
|
|
1625
1648
|
}
|
|
1626
1649
|
async function executeSingleStep(repositoryId, storage, frontier, step, onStorageCall) {
|
|
1627
|
-
const direction =
|
|
1650
|
+
const direction = step.direction;
|
|
1628
1651
|
const pendingEdges = [];
|
|
1629
1652
|
for (const entry of frontier) {
|
|
1630
1653
|
const rels = await storage.getEntityRelationships(repositoryId, entry.entity.id, {
|
|
@@ -1719,16 +1742,6 @@ async function resolveEntity(repositoryId, storage, idOrSlug) {
|
|
|
1719
1742
|
if (byId) return byId;
|
|
1720
1743
|
return storage.getEntityBySlug(repositoryId, idOrSlug);
|
|
1721
1744
|
}
|
|
1722
|
-
function mapDirection(direction) {
|
|
1723
|
-
switch (direction) {
|
|
1724
|
-
case "out":
|
|
1725
|
-
return "outbound";
|
|
1726
|
-
case "in":
|
|
1727
|
-
return "inbound";
|
|
1728
|
-
case "both":
|
|
1729
|
-
return "both";
|
|
1730
|
-
}
|
|
1731
|
-
}
|
|
1732
1745
|
function getTargetId(rel, currentEntityId) {
|
|
1733
1746
|
if (rel.sourceEntityId === currentEntityId) {
|
|
1734
1747
|
return rel.targetEntityId;
|
|
@@ -1771,6 +1784,12 @@ function buildAllModeUnion(entries) {
|
|
|
1771
1784
|
}
|
|
1772
1785
|
for (let depth = 1; depth <= maxDepth; depth++) {
|
|
1773
1786
|
const bucket = byDepth.get(depth) ?? [];
|
|
1787
|
+
for (const entry of bucket) {
|
|
1788
|
+
if (!seenEntities.has(entry.entity.id)) {
|
|
1789
|
+
seenEntities.add(entry.entity.id);
|
|
1790
|
+
result.push({ kind: "entity", entry });
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1774
1793
|
for (const entry of bucket) {
|
|
1775
1794
|
const newRel = entry.relationshipPath[depth - 1];
|
|
1776
1795
|
if (newRel && !seenRels.has(newRel.id)) {
|
|
@@ -1778,12 +1797,6 @@ function buildAllModeUnion(entries) {
|
|
|
1778
1797
|
result.push({ kind: "relationship", rel: newRel });
|
|
1779
1798
|
}
|
|
1780
1799
|
}
|
|
1781
|
-
for (const entry of bucket) {
|
|
1782
|
-
if (!seenEntities.has(entry.entity.id)) {
|
|
1783
|
-
seenEntities.add(entry.entity.id);
|
|
1784
|
-
result.push({ kind: "entity", entry });
|
|
1785
|
-
}
|
|
1786
|
-
}
|
|
1787
1800
|
}
|
|
1788
1801
|
return result;
|
|
1789
1802
|
}
|
|
@@ -1923,7 +1936,7 @@ var GraphTraversal = class {
|
|
|
1923
1936
|
return {
|
|
1924
1937
|
id: rid,
|
|
1925
1938
|
type: r?.type ?? "unknown",
|
|
1926
|
-
direction: r?.sourceEntityId === currentEntityId ? "
|
|
1939
|
+
direction: r?.sourceEntityId === currentEntityId ? "out" : "in",
|
|
1927
1940
|
properties: r?.properties ?? {}
|
|
1928
1941
|
};
|
|
1929
1942
|
})
|
|
@@ -2550,7 +2563,7 @@ var MemoryRepository = class {
|
|
|
2550
2563
|
inbound[rel.relationshipType] = (inbound[rel.relationshipType] ?? 0) + 1;
|
|
2551
2564
|
}
|
|
2552
2565
|
}
|
|
2553
|
-
return { outbound, inbound };
|
|
2566
|
+
return { out: outbound, in: inbound };
|
|
2554
2567
|
}
|
|
2555
2568
|
async getRelationshipsForEntities(entityIds) {
|
|
2556
2569
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -2758,9 +2771,10 @@ var MemoryRepository = class {
|
|
|
2758
2771
|
### Step 1 \u2014 Discover before you traverse
|
|
2759
2772
|
|
|
2760
2773
|
Before following relationships from an entity, check that it actually has relationships.
|
|
2761
|
-
Graph queries include \`relationshipSummary\` on every returned entity by default
|
|
2762
|
-
(
|
|
2763
|
-
zero
|
|
2774
|
+
Graph queries include \`relationshipSummary\` on every returned entity by default \u2014
|
|
2775
|
+
\`out\` (entity is source) and \`in\` (entity is target) counts by relationship type.
|
|
2776
|
+
Inspect this before traversing: entities with zero counts for the relationship type
|
|
2777
|
+
you need have no connections to follow.
|
|
2764
2778
|
To skip summaries and reduce response size, set \`includeRelationshipSummary: false\`.
|
|
2765
2779
|
|
|
2766
2780
|
### Step 2 \u2014 Use projection for aggregation
|
|
@@ -3643,7 +3657,7 @@ var EventBus = class {
|
|
|
3643
3657
|
};
|
|
3644
3658
|
|
|
3645
3659
|
// src/portability/RepositoryExporter.ts
|
|
3646
|
-
var LIBRARY_VERSION = true ? "0.
|
|
3660
|
+
var LIBRARY_VERSION = true ? "0.19.0" : "0.1.0";
|
|
3647
3661
|
var RepositoryExporter = class {
|
|
3648
3662
|
storage;
|
|
3649
3663
|
provenance;
|
|
@@ -3675,6 +3689,9 @@ var RepositoryExporter = class {
|
|
|
3675
3689
|
type: repo.type,
|
|
3676
3690
|
label: repo.label,
|
|
3677
3691
|
description: repo.description,
|
|
3692
|
+
legal: repo.legal,
|
|
3693
|
+
owner: repo.owner,
|
|
3694
|
+
metadata: repo.metadata,
|
|
3678
3695
|
vocabularyVersion: vocabulary.version,
|
|
3679
3696
|
governanceMode: repo.governanceConfig.mode
|
|
3680
3697
|
},
|
|
@@ -4072,7 +4089,10 @@ var RepositoryImporter = class {
|
|
|
4072
4089
|
type: target.config.type,
|
|
4073
4090
|
label: target.config.label,
|
|
4074
4091
|
description: target.config.description,
|
|
4092
|
+
legal: target.config.legal,
|
|
4093
|
+
owner: target.config.owner,
|
|
4075
4094
|
governanceConfig: target.config.governance ?? { mode: "open" },
|
|
4095
|
+
metadata: target.config.metadata,
|
|
4076
4096
|
createdAt: now,
|
|
4077
4097
|
createdBy: this.actorId
|
|
4078
4098
|
});
|
|
@@ -4587,6 +4607,7 @@ var DeepMemory = class {
|
|
|
4587
4607
|
/** Import a repository from a portable archive */
|
|
4588
4608
|
async importRepository(archive, options) {
|
|
4589
4609
|
await this.ensureInitialized();
|
|
4610
|
+
this.validateRepositoryId(options.target.repositoryId);
|
|
4590
4611
|
await this.globalEventBus.emit("import:started", { repositoryId: options.target.repositoryId });
|
|
4591
4612
|
const importer = new RepositoryImporter({
|
|
4592
4613
|
storage: this.storage,
|
|
@@ -4687,6 +4708,7 @@ var DeepMemory = class {
|
|
|
4687
4708
|
*/
|
|
4688
4709
|
async importRepositoryStream(header, chunks, options) {
|
|
4689
4710
|
await this.ensureInitialized();
|
|
4711
|
+
this.validateRepositoryId(options.target.repositoryId);
|
|
4690
4712
|
const importer = new RepositoryImporter({
|
|
4691
4713
|
storage: this.storage,
|
|
4692
4714
|
actorId: this.provenance.getContext().actorId,
|
|
@@ -4921,8 +4943,8 @@ var GremlinCompiler = class {
|
|
|
4921
4943
|
const branches = [`__.identity().${VERTEX_PROJECT_EXPR}`];
|
|
4922
4944
|
let prefix = "";
|
|
4923
4945
|
for (const { edge, vertex, entityFilters } of compiledSteps) {
|
|
4924
|
-
branches.push(`__${prefix}${edge}.${EDGE_PROJECT_EXPR}`);
|
|
4925
4946
|
branches.push(`__${prefix}${edge}${vertex}${entityFilters}.${VERTEX_PROJECT_EXPR}`);
|
|
4947
|
+
branches.push(`__${prefix}${edge}.${EDGE_PROJECT_EXPR}`);
|
|
4926
4948
|
prefix = `${prefix}${edge}${vertex}`;
|
|
4927
4949
|
estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
|
|
4928
4950
|
}
|
|
@@ -4958,12 +4980,16 @@ var GremlinCompiler = class {
|
|
|
4958
4980
|
}
|
|
4959
4981
|
}
|
|
4960
4982
|
}
|
|
4961
|
-
|
|
4983
|
+
const emitProjection = spec.projection !== void 0 && returnMode === "terminal";
|
|
4984
|
+
if (returnMode === "terminal" && !emitProjection && spec.dedup !== false) {
|
|
4962
4985
|
parts.push(".dedup()");
|
|
4963
4986
|
}
|
|
4964
4987
|
if (returnMode === "path") {
|
|
4965
4988
|
parts.push(".simplePath()");
|
|
4966
4989
|
}
|
|
4990
|
+
if (emitProjection) {
|
|
4991
|
+
parts.push(emitProjectionTerminal(spec.projection));
|
|
4992
|
+
}
|
|
4967
4993
|
const limit = spec.limit ?? 50;
|
|
4968
4994
|
const offset = spec.offset ?? 0;
|
|
4969
4995
|
const pOffset = nextParam(offset);
|
|
@@ -4971,7 +4997,8 @@ var GremlinCompiler = class {
|
|
|
4971
4997
|
parts.push(`.range(${pOffset}, ${pEnd})`);
|
|
4972
4998
|
params["_limit"] = limit;
|
|
4973
4999
|
params["_offset"] = offset;
|
|
4974
|
-
if (
|
|
5000
|
+
if (emitProjection) {
|
|
5001
|
+
} else if (returnMode === "terminal") {
|
|
4975
5002
|
parts.push(`.${VERTEX_PROJECT_EXPR}`);
|
|
4976
5003
|
} else {
|
|
4977
5004
|
parts.push(`.path().by(${VERTEX_PROJECT_EXPR}).by(${EDGE_PROJECT_EXPR})`);
|
|
@@ -5067,6 +5094,31 @@ function compileRepeatStep(step, nextParam, useEdgeEmission) {
|
|
|
5067
5094
|
}
|
|
5068
5095
|
return parts.join("");
|
|
5069
5096
|
}
|
|
5097
|
+
var SAFE_PROJECTION_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
5098
|
+
function assertSafeProjectionKey(key) {
|
|
5099
|
+
if (!SAFE_PROJECTION_KEY_RE.test(key)) {
|
|
5100
|
+
throw new Error(
|
|
5101
|
+
`Unsafe projection property name: "${key}". Property names must match ${SAFE_PROJECTION_KEY_RE.source}.`
|
|
5102
|
+
);
|
|
5103
|
+
}
|
|
5104
|
+
}
|
|
5105
|
+
function emitProjectionTerminal(projection) {
|
|
5106
|
+
const properties = projection.properties;
|
|
5107
|
+
const mode = projection.mode ?? "values";
|
|
5108
|
+
const distinct = projection.distinct ?? false;
|
|
5109
|
+
for (const prop of properties) {
|
|
5110
|
+
assertSafeProjectionKey(prop);
|
|
5111
|
+
}
|
|
5112
|
+
const singleProperty = properties.length === 1;
|
|
5113
|
+
const keyExpr = singleProperty ? `values('${properties[0]}')` : `project(${properties.map((p) => `'${p}'`).join(",")})${properties.map((p) => `.by(values('${p}'))`).join("")}`;
|
|
5114
|
+
if (mode === "count") {
|
|
5115
|
+
return `.group().by(${keyExpr}).by(count()).unfold()`;
|
|
5116
|
+
}
|
|
5117
|
+
if (distinct) {
|
|
5118
|
+
return `.${keyExpr}.dedup()`;
|
|
5119
|
+
}
|
|
5120
|
+
return `.${keyExpr}`;
|
|
5121
|
+
}
|
|
5070
5122
|
function compilePropertyFilter(filter, nextParam) {
|
|
5071
5123
|
const key = nextParam(filter.key);
|
|
5072
5124
|
switch (filter.operator) {
|
|
@@ -5176,17 +5228,35 @@ var CypherCompiler = class {
|
|
|
5176
5228
|
}
|
|
5177
5229
|
lastNode = targetNode;
|
|
5178
5230
|
}
|
|
5179
|
-
const
|
|
5231
|
+
const bindPath = spec.returnMode === "path";
|
|
5232
|
+
const pathBinding = bindPath ? "p = " : "";
|
|
5233
|
+
const matchClause = `MATCH ${pathBinding}${matchParts[0]}${matchParts.slice(1).join("")}`;
|
|
5180
5234
|
const whereClause = whereClauses.length > 0 ? `
|
|
5181
5235
|
WHERE ${whereClauses.join(" AND ")}` : "";
|
|
5182
5236
|
let returnClause;
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
const
|
|
5186
|
-
|
|
5237
|
+
const emitProjection = spec.projection !== void 0 && spec.returnMode !== "path" && spec.returnMode !== "all";
|
|
5238
|
+
if (emitProjection) {
|
|
5239
|
+
const projection = spec.projection;
|
|
5240
|
+
const mode = projection.mode ?? "values";
|
|
5241
|
+
const distinct = projection.distinct ?? false;
|
|
5242
|
+
const projectionColumns = projection.properties.map((prop) => {
|
|
5243
|
+
assertSafeProjectionKey2(prop);
|
|
5244
|
+
return `${lastNode}.${prop} AS ${prop}`;
|
|
5245
|
+
});
|
|
5246
|
+
if (mode === "count") {
|
|
5247
|
+
returnClause = `RETURN ${projectionColumns.join(", ")}, count(*) AS count`;
|
|
5248
|
+
} else if (distinct) {
|
|
5249
|
+
returnClause = `RETURN DISTINCT ${projectionColumns.join(", ")}`;
|
|
5250
|
+
} else {
|
|
5251
|
+
returnClause = `RETURN ${projectionColumns.join(", ")}`;
|
|
5252
|
+
}
|
|
5253
|
+
} else if (spec.returnMode === "path") {
|
|
5254
|
+
returnClause = "RETURN nodes(p) AS pathNodes, relationships(p) AS pathRels, length(p) AS pathLength";
|
|
5187
5255
|
} else if (spec.returnMode === "all") {
|
|
5188
5256
|
const allNodes = Array.from({ length: nodeIndex }, (_, i) => `n${i}`);
|
|
5189
|
-
|
|
5257
|
+
const allRels = steps.map((_, i) => `r${i}`);
|
|
5258
|
+
const projection = [...allNodes, ...allRels].join(", ");
|
|
5259
|
+
returnClause = spec.dedup !== false ? `RETURN DISTINCT ${projection}` : `RETURN ${projection}`;
|
|
5190
5260
|
} else {
|
|
5191
5261
|
returnClause = spec.dedup !== false ? `RETURN DISTINCT ${lastNode}` : `RETURN ${lastNode}`;
|
|
5192
5262
|
}
|
|
@@ -5207,6 +5277,14 @@ ${returnClause}${skipClause}${limitClause}`;
|
|
|
5207
5277
|
};
|
|
5208
5278
|
}
|
|
5209
5279
|
};
|
|
5280
|
+
var SAFE_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
5281
|
+
function assertSafeProjectionKey2(key) {
|
|
5282
|
+
if (!SAFE_KEY_RE.test(key)) {
|
|
5283
|
+
throw new Error(
|
|
5284
|
+
`Unsafe projection property name: "${key}". Property names must match ${SAFE_KEY_RE.source}.`
|
|
5285
|
+
);
|
|
5286
|
+
}
|
|
5287
|
+
}
|
|
5210
5288
|
function compilePropertyFilterCypher(nodeAlias, filter, nextParam) {
|
|
5211
5289
|
const prop = `${nodeAlias}.${filter.key}`;
|
|
5212
5290
|
switch (filter.operator) {
|
|
@@ -5517,9 +5595,9 @@ var InMemoryStorageProvider = class {
|
|
|
5517
5595
|
const isTarget = rel.targetEntityId === entityId;
|
|
5518
5596
|
const isBidirectionalTarget = rel.bidirectional && isTarget;
|
|
5519
5597
|
switch (direction) {
|
|
5520
|
-
case "
|
|
5598
|
+
case "out":
|
|
5521
5599
|
return isSource || isBidirectionalTarget;
|
|
5522
|
-
case "
|
|
5600
|
+
case "in":
|
|
5523
5601
|
return isTarget || rel.bidirectional && isSource;
|
|
5524
5602
|
case "both":
|
|
5525
5603
|
default:
|
|
@@ -5611,23 +5689,24 @@ var InMemoryStorageProvider = class {
|
|
|
5611
5689
|
for (let depth = 0; depth < options.depth; depth++) {
|
|
5612
5690
|
const layer = {};
|
|
5613
5691
|
const nextFrontier = /* @__PURE__ */ new Set();
|
|
5692
|
+
const layerBucketSeen = /* @__PURE__ */ new Map();
|
|
5614
5693
|
for (const frontierEntityId of currentFrontier) {
|
|
5615
5694
|
for (const rel of store.relationships.values()) {
|
|
5616
5695
|
const isSource = rel.sourceEntityId === frontierEntityId;
|
|
5617
5696
|
const isTarget = rel.targetEntityId === frontierEntityId;
|
|
5618
5697
|
let matchesDirection = false;
|
|
5619
5698
|
let connectedEntityId;
|
|
5620
|
-
if (isSource && (options.direction === "
|
|
5699
|
+
if (isSource && (options.direction === "out" || options.direction === "both")) {
|
|
5621
5700
|
matchesDirection = true;
|
|
5622
5701
|
connectedEntityId = rel.targetEntityId;
|
|
5623
|
-
} else if (isTarget && (options.direction === "
|
|
5702
|
+
} else if (isTarget && (options.direction === "in" || options.direction === "both")) {
|
|
5624
5703
|
matchesDirection = true;
|
|
5625
5704
|
connectedEntityId = rel.sourceEntityId;
|
|
5626
5705
|
} else if (rel.bidirectional) {
|
|
5627
|
-
if (isSource && options.direction === "
|
|
5706
|
+
if (isSource && options.direction === "in") {
|
|
5628
5707
|
matchesDirection = true;
|
|
5629
5708
|
connectedEntityId = rel.targetEntityId;
|
|
5630
|
-
} else if (isTarget && options.direction === "
|
|
5709
|
+
} else if (isTarget && options.direction === "out") {
|
|
5631
5710
|
matchesDirection = true;
|
|
5632
5711
|
connectedEntityId = rel.sourceEntityId;
|
|
5633
5712
|
}
|
|
@@ -5648,6 +5727,13 @@ var InMemoryStorageProvider = class {
|
|
|
5648
5727
|
continue;
|
|
5649
5728
|
}
|
|
5650
5729
|
const relType = rel.relationshipType;
|
|
5730
|
+
let bucketSeen = layerBucketSeen.get(relType);
|
|
5731
|
+
if (!bucketSeen) {
|
|
5732
|
+
bucketSeen = /* @__PURE__ */ new Set();
|
|
5733
|
+
layerBucketSeen.set(relType, bucketSeen);
|
|
5734
|
+
}
|
|
5735
|
+
if (bucketSeen.has(connectedEntityId)) continue;
|
|
5736
|
+
bucketSeen.add(connectedEntityId);
|
|
5651
5737
|
if (!layer[relType]) {
|
|
5652
5738
|
layer[relType] = { total: 0, entities: [], relationships: [] };
|
|
5653
5739
|
}
|