@utaba/deep-memory 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -901,310 +901,6 @@ function validateTraversalSpec(spec, vocabulary, capabilities) {
901
901
  };
902
902
  }
903
903
 
904
- // src/relationships/compilers/GremlinCompiler.ts
905
- var DEFAULT_ESTIMATED_FANOUT_PER_HOP = 10;
906
- var GremlinCompiler = class {
907
- language = "gremlin";
908
- compile(spec, _vocabulary) {
909
- const parts = [];
910
- const params = {};
911
- let paramIndex = 0;
912
- let estimatedFanOut = 1;
913
- const nextParam = (value) => {
914
- const name = `p${paramIndex++}`;
915
- params[name] = value;
916
- return name;
917
- };
918
- parts.push("g.V()");
919
- if (spec.start.entityId) {
920
- const p = nextParam(spec.start.entityId);
921
- parts.push(`.has('id', ${p})`);
922
- } else if (spec.start.entityType) {
923
- const p = nextParam(spec.start.entityType);
924
- parts.push(`.has('entityType', ${p})`);
925
- estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
926
- }
927
- if (spec.start.filter) {
928
- for (const f of spec.start.filter) {
929
- parts.push(compilePropertyFilter(f, nextParam));
930
- }
931
- }
932
- const steps = spec.steps ?? [];
933
- for (const step of steps) {
934
- if (step.repeat) {
935
- parts.push(compileRepeatStep(step, nextParam));
936
- estimatedFanOut *= step.repeat.maxDepth * DEFAULT_ESTIMATED_FANOUT_PER_HOP;
937
- } else if (step.relationshipFilter && step.relationshipFilter.length > 0) {
938
- parts.push(compileEdgeStep(step, nextParam));
939
- estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
940
- } else {
941
- parts.push(compileSimpleStep(step, nextParam));
942
- estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
943
- }
944
- if (step.entityTypes && step.entityTypes.length > 0) {
945
- const typeParams = step.entityTypes.map((t) => nextParam(t));
946
- parts.push(`.has('entityType', within(${typeParams.join(", ")}))`);
947
- }
948
- if (step.entityFilter) {
949
- for (const f of step.entityFilter) {
950
- parts.push(compilePropertyFilter(f, nextParam));
951
- }
952
- }
953
- }
954
- if (spec.returnMode === "all") {
955
- }
956
- if (spec.dedup !== false) {
957
- parts.push(".dedup()");
958
- }
959
- const limit = spec.limit ?? 50;
960
- const offset = spec.offset ?? 0;
961
- const pOffset = nextParam(offset);
962
- const pEnd = nextParam(offset + limit);
963
- parts.push(`.range(${pOffset}, ${pEnd})`);
964
- params["_limit"] = limit;
965
- params["_offset"] = offset;
966
- if (spec.returnMode === "path") {
967
- parts.push(".path()");
968
- }
969
- if (spec.returnMode !== "path") {
970
- parts.push(".valueMap(true)");
971
- }
972
- return {
973
- query: parts.join(""),
974
- params,
975
- estimatedFanOut: Math.min(estimatedFanOut, 1e4)
976
- };
977
- }
978
- };
979
- function compileSimpleStep(step, nextParam) {
980
- const types = step.relationshipTypes;
981
- const typeArgs = types ? types.map((t) => nextParam(t)).join(", ") : "";
982
- switch (step.direction) {
983
- case "out":
984
- return types ? `.out(${typeArgs})` : ".out()";
985
- case "in":
986
- return types ? `.in(${typeArgs})` : ".in()";
987
- case "both":
988
- return types ? `.both(${typeArgs})` : ".both()";
989
- }
990
- }
991
- function compileEdgeStep(step, nextParam) {
992
- const parts = [];
993
- const types = step.relationshipTypes;
994
- const typeArgs = types ? types.map((t) => nextParam(t)).join(", ") : "";
995
- switch (step.direction) {
996
- case "out":
997
- parts.push(types ? `.outE(${typeArgs})` : ".outE()");
998
- break;
999
- case "in":
1000
- parts.push(types ? `.inE(${typeArgs})` : ".inE()");
1001
- break;
1002
- case "both":
1003
- parts.push(types ? `.bothE(${typeArgs})` : ".bothE()");
1004
- break;
1005
- }
1006
- if (step.relationshipFilter) {
1007
- for (const f of step.relationshipFilter) {
1008
- parts.push(compilePropertyFilter(f, nextParam));
1009
- }
1010
- }
1011
- switch (step.direction) {
1012
- case "out":
1013
- parts.push(".inV()");
1014
- break;
1015
- case "in":
1016
- parts.push(".outV()");
1017
- break;
1018
- case "both":
1019
- parts.push(".otherV()");
1020
- break;
1021
- }
1022
- return parts.join("");
1023
- }
1024
- function compileRepeatStep(step, nextParam) {
1025
- const parts = [];
1026
- const innerStep = step.relationshipFilter?.length ? compileEdgeStep({ ...step, repeat: void 0 }, nextParam) : compileSimpleStep(step, nextParam);
1027
- if (step.repeat?.emitIntermediates !== false) {
1028
- parts.push(".emit()");
1029
- }
1030
- parts.push(`.repeat(${innerStep.startsWith(".") ? `__${innerStep}` : innerStep})`);
1031
- if (step.repeat?.until && step.repeat.until.length > 0) {
1032
- const untilParts = step.repeat.until.map((f) => compilePropertyFilter(f, nextParam));
1033
- parts.push(`.until(${untilParts.join("")})`);
1034
- }
1035
- if (step.repeat?.maxDepth) {
1036
- const p = nextParam(step.repeat.maxDepth);
1037
- parts.push(`.times(${p})`);
1038
- }
1039
- if (step.repeat?.emitIntermediates === false) {
1040
- parts.push(".emit()");
1041
- }
1042
- return parts.join("");
1043
- }
1044
- function compilePropertyFilter(filter, nextParam) {
1045
- const key = nextParam(filter.key);
1046
- switch (filter.operator) {
1047
- case "eq": {
1048
- const val = nextParam(filter.value);
1049
- return `.has(${key}, ${val})`;
1050
- }
1051
- case "neq": {
1052
- const val = nextParam(filter.value);
1053
- return `.has(${key}, neq(${val}))`;
1054
- }
1055
- case "gt": {
1056
- const val = nextParam(filter.value);
1057
- return `.has(${key}, gt(${val}))`;
1058
- }
1059
- case "gte": {
1060
- const val = nextParam(filter.value);
1061
- return `.has(${key}, gte(${val}))`;
1062
- }
1063
- case "lt": {
1064
- const val = nextParam(filter.value);
1065
- return `.has(${key}, lt(${val}))`;
1066
- }
1067
- case "lte": {
1068
- const val = nextParam(filter.value);
1069
- return `.has(${key}, lte(${val}))`;
1070
- }
1071
- case "contains": {
1072
- const val = nextParam(filter.value);
1073
- return `.has(${key}, containing(${val}))`;
1074
- }
1075
- case "isNull":
1076
- return `.hasNot(${key})`;
1077
- case "isNotNull":
1078
- return `.has(${key})`;
1079
- }
1080
- }
1081
-
1082
- // src/relationships/compilers/CypherCompiler.ts
1083
- var DEFAULT_ESTIMATED_FANOUT_PER_HOP2 = 10;
1084
- var CypherCompiler = class {
1085
- language = "cypher";
1086
- compile(spec, _vocabulary) {
1087
- const params = {};
1088
- let paramIndex = 0;
1089
- let estimatedFanOut = 1;
1090
- const whereClauses = [];
1091
- let nodeIndex = 0;
1092
- const nextParam = (value) => {
1093
- const name = `p${paramIndex++}`;
1094
- params[name] = value;
1095
- return `$${name}`;
1096
- };
1097
- const startNode = `n${nodeIndex++}`;
1098
- let matchParts = [];
1099
- if (spec.start.entityId) {
1100
- matchParts.push(`(${startNode})`);
1101
- whereClauses.push(`${startNode}.id = ${nextParam(spec.start.entityId)}`);
1102
- } else if (spec.start.entityType) {
1103
- matchParts.push(`(${startNode})`);
1104
- whereClauses.push(`${startNode}.entityType = ${nextParam(spec.start.entityType)}`);
1105
- estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP2;
1106
- } else {
1107
- matchParts.push(`(${startNode})`);
1108
- }
1109
- if (spec.start.filter) {
1110
- for (const f of spec.start.filter) {
1111
- whereClauses.push(compilePropertyFilterCypher(startNode, f, nextParam));
1112
- }
1113
- }
1114
- let lastNode = startNode;
1115
- const steps = spec.steps ?? [];
1116
- for (let i = 0; i < steps.length; i++) {
1117
- const step = steps[i];
1118
- const targetNode = `n${nodeIndex++}`;
1119
- const relAlias = `r${i}`;
1120
- const relTypes = step.relationshipTypes?.length ? step.relationshipTypes.join("|") : "";
1121
- const relTypePattern = relTypes ? `:${relTypes}` : "";
1122
- const depthPattern = step.repeat ? `*1..${step.repeat.maxDepth}` : "";
1123
- let pattern;
1124
- switch (step.direction) {
1125
- case "out":
1126
- pattern = `-[${relAlias}${relTypePattern}${depthPattern}]->(${targetNode})`;
1127
- break;
1128
- case "in":
1129
- pattern = `<-[${relAlias}${relTypePattern}${depthPattern}]-(${targetNode})`;
1130
- break;
1131
- case "both":
1132
- pattern = `-[${relAlias}${relTypePattern}${depthPattern}]-(${targetNode})`;
1133
- break;
1134
- }
1135
- matchParts.push(pattern);
1136
- estimatedFanOut *= step.repeat ? step.repeat.maxDepth * DEFAULT_ESTIMATED_FANOUT_PER_HOP2 : DEFAULT_ESTIMATED_FANOUT_PER_HOP2;
1137
- if (step.entityTypes && step.entityTypes.length > 0) {
1138
- const typeParam = nextParam(step.entityTypes);
1139
- whereClauses.push(`${targetNode}.entityType IN ${typeParam}`);
1140
- }
1141
- if (step.entityFilter) {
1142
- for (const f of step.entityFilter) {
1143
- whereClauses.push(compilePropertyFilterCypher(targetNode, f, nextParam));
1144
- }
1145
- }
1146
- if (step.relationshipFilter) {
1147
- for (const f of step.relationshipFilter) {
1148
- whereClauses.push(compilePropertyFilterCypher(relAlias, f, nextParam));
1149
- }
1150
- }
1151
- lastNode = targetNode;
1152
- }
1153
- const matchClause = `MATCH ${matchParts[0]}${matchParts.slice(1).join("")}`;
1154
- const whereClause = whereClauses.length > 0 ? `
1155
- WHERE ${whereClauses.join(" AND ")}` : "";
1156
- let returnClause;
1157
- if (spec.returnMode === "path") {
1158
- const allNodes = Array.from({ length: nodeIndex }, (_, i) => `n${i}`);
1159
- const allRels = steps.map((_, i) => `r${i}`);
1160
- returnClause = `RETURN ${[...allNodes, ...allRels].join(", ")}`;
1161
- } else if (spec.returnMode === "all") {
1162
- const allNodes = Array.from({ length: nodeIndex }, (_, i) => `n${i}`);
1163
- returnClause = spec.dedup !== false ? `RETURN DISTINCT ${allNodes.join(", ")}` : `RETURN ${allNodes.join(", ")}`;
1164
- } else {
1165
- returnClause = spec.dedup !== false ? `RETURN DISTINCT ${lastNode}` : `RETURN ${lastNode}`;
1166
- }
1167
- const offset = spec.offset ?? 0;
1168
- const limit = spec.limit ?? 50;
1169
- const skipClause = offset > 0 ? `
1170
- SKIP ${nextParam(offset)}` : "";
1171
- const limitClause = `
1172
- LIMIT ${nextParam(limit)}`;
1173
- params["_limit"] = limit;
1174
- params["_offset"] = offset;
1175
- const query = `${matchClause}${whereClause}
1176
- ${returnClause}${skipClause}${limitClause}`;
1177
- return {
1178
- query,
1179
- params,
1180
- estimatedFanOut: Math.min(estimatedFanOut, 1e4)
1181
- };
1182
- }
1183
- };
1184
- function compilePropertyFilterCypher(nodeAlias, filter, nextParam) {
1185
- const prop = `${nodeAlias}.${filter.key}`;
1186
- switch (filter.operator) {
1187
- case "eq":
1188
- return `${prop} = ${nextParam(filter.value)}`;
1189
- case "neq":
1190
- return `${prop} <> ${nextParam(filter.value)}`;
1191
- case "gt":
1192
- return `${prop} > ${nextParam(filter.value)}`;
1193
- case "gte":
1194
- return `${prop} >= ${nextParam(filter.value)}`;
1195
- case "lt":
1196
- return `${prop} < ${nextParam(filter.value)}`;
1197
- case "lte":
1198
- return `${prop} <= ${nextParam(filter.value)}`;
1199
- case "contains":
1200
- return `${prop} CONTAINS ${nextParam(filter.value)}`;
1201
- case "isNull":
1202
- return `${prop} IS NULL`;
1203
- case "isNotNull":
1204
- return `${prop} IS NOT NULL`;
1205
- }
1206
- }
1207
-
1208
904
  // src/relationships/PropertyFilterMatcher.ts
1209
905
  function matchesPropertyFilters(properties, filters) {
1210
906
  return filters.every((filter) => matchesSingleFilter(properties, filter));
@@ -1737,8 +1433,9 @@ var GraphTraversal = class {
1737
1433
  }
1738
1434
  /**
1739
1435
  * Execute a structured traversal.
1740
- * Validates the spec, compiles to native query if a provider exists,
1741
- * falls back to application-level BFS otherwise.
1436
+ * Validates the spec, delegates to the GraphTraversalProvider if one is
1437
+ * registered (the provider owns native compilation), or falls back to
1438
+ * application-level BFS over StorageProvider.
1742
1439
  */
1743
1440
  async traverse(spec) {
1744
1441
  const capabilities = this.graphTraversalProvider?.getCapabilities();
@@ -1753,19 +1450,8 @@ var GraphTraversal = class {
1753
1450
  }
1754
1451
  throw new TraversalValidationError(structErrors.length > 0 ? structErrors : validation.errors);
1755
1452
  }
1756
- if (this.graphTraversalProvider && vocabulary) {
1757
- const language = capabilities.nativeQueryLanguage;
1758
- let compiledQuery;
1759
- if (language === "gremlin") {
1760
- const compiler = new GremlinCompiler();
1761
- const compiled = compiler.compile(spec, vocabulary);
1762
- compiledQuery = compiled.query;
1763
- } else if (language === "cypher") {
1764
- const compiler = new CypherCompiler();
1765
- const compiled = compiler.compile(spec, vocabulary);
1766
- compiledQuery = compiled.query;
1767
- }
1768
- return this.graphTraversalProvider.traverse(this.repositoryId, spec, compiledQuery);
1453
+ if (this.graphTraversalProvider) {
1454
+ return this.graphTraversalProvider.traverse(this.repositoryId, spec);
1769
1455
  }
1770
1456
  return executeFallbackTraversal(this.repositoryId, this.storage, spec);
1771
1457
  }
@@ -3352,7 +3038,7 @@ var EventBus = class {
3352
3038
  };
3353
3039
 
3354
3040
  // src/portability/RepositoryExporter.ts
3355
- var LIBRARY_VERSION = true ? "0.5.0" : "0.1.0";
3041
+ var LIBRARY_VERSION = true ? "0.6.1" : "0.1.0";
3356
3042
  var RepositoryExporter = class {
3357
3043
  storage;
3358
3044
  provenance;
@@ -4146,6 +3832,16 @@ var DeepMemory = class {
4146
3832
  await this.globalEventBus.emit("repository:opened", { repositoryId });
4147
3833
  return repo;
4148
3834
  }
3835
+ /** Get the full stored record for a single repository (including legal, owner, metadata, governance) */
3836
+ async getRepository(repositoryId) {
3837
+ await this.ensureInitialized();
3838
+ this.validateRepositoryId(repositoryId);
3839
+ const storedRepo = await this.storage.getRepository(repositoryId);
3840
+ if (!storedRepo) {
3841
+ throw new RepositoryNotFoundError(repositoryId);
3842
+ }
3843
+ return storedRepo;
3844
+ }
4149
3845
  /** List all repositories */
4150
3846
  async listRepositories(filter) {
4151
3847
  await this.ensureInitialized();
@@ -4318,54 +4014,358 @@ var DeepMemory = class {
4318
4014
  relationshipCount
4319
4015
  });
4320
4016
  }
4321
- /**
4322
- * Import a repository from a stream of chunks.
4323
- * Use for large repositories to avoid loading everything into memory.
4324
- */
4325
- async importRepositoryStream(header, chunks, options) {
4326
- await this.ensureInitialized();
4327
- const importer = new RepositoryImporter({
4328
- storage: this.storage,
4329
- actorId: this.provenance.getContext().actorId,
4330
- onProgress: (progress) => this.globalEventBus.emit("import:progress", progress)
4331
- });
4332
- await this.globalEventBus.emit("import:started", { repositoryId: options.target.repositoryId });
4333
- const result = await importer.importStream(header, chunks, options);
4334
- if (result.success) {
4335
- await this.globalEventBus.emit("import:completed", {
4336
- repositoryId: result.repositoryId,
4337
- entitiesImported: result.statistics.entitiesImported,
4338
- relationshipsImported: result.statistics.relationshipsImported
4339
- });
4340
- } else {
4341
- await this.globalEventBus.emit("import:failed", {
4342
- repositoryId: result.repositoryId,
4343
- error: result.warnings.map((w) => w.message).join("; ")
4344
- });
4017
+ /**
4018
+ * Import a repository from a stream of chunks.
4019
+ * Use for large repositories to avoid loading everything into memory.
4020
+ */
4021
+ async importRepositoryStream(header, chunks, options) {
4022
+ await this.ensureInitialized();
4023
+ const importer = new RepositoryImporter({
4024
+ storage: this.storage,
4025
+ actorId: this.provenance.getContext().actorId,
4026
+ onProgress: (progress) => this.globalEventBus.emit("import:progress", progress)
4027
+ });
4028
+ await this.globalEventBus.emit("import:started", { repositoryId: options.target.repositoryId });
4029
+ const result = await importer.importStream(header, chunks, options);
4030
+ if (result.success) {
4031
+ await this.globalEventBus.emit("import:completed", {
4032
+ repositoryId: result.repositoryId,
4033
+ entitiesImported: result.statistics.entitiesImported,
4034
+ relationshipsImported: result.statistics.relationshipsImported
4035
+ });
4036
+ } else {
4037
+ await this.globalEventBus.emit("import:failed", {
4038
+ repositoryId: result.repositoryId,
4039
+ error: result.warnings.map((w) => w.message).join("; ")
4040
+ });
4041
+ }
4042
+ return result;
4043
+ }
4044
+ /** Subscribe to global events */
4045
+ on(event, handler) {
4046
+ return this.globalEventBus.on(event, handler);
4047
+ }
4048
+ /** Update the provenance context (e.g., new conversation) */
4049
+ updateProvenance(context) {
4050
+ this.provenance.updateContext(context);
4051
+ this.globalEventBus.updateProvenance(this.provenance.getContext());
4052
+ }
4053
+ /** Dispose of all resources */
4054
+ async dispose() {
4055
+ this.globalEventBus.removeAllListeners();
4056
+ if (this.graphTraversalProvider?.dispose) {
4057
+ await this.graphTraversalProvider.dispose();
4058
+ }
4059
+ if (this.storage.dispose) {
4060
+ await this.storage.dispose();
4061
+ }
4062
+ this.initialized = false;
4063
+ }
4064
+ };
4065
+
4066
+ // src/relationships/compilers/GremlinCompiler.ts
4067
+ var DEFAULT_ESTIMATED_FANOUT_PER_HOP = 10;
4068
+ var GremlinCompiler = class {
4069
+ language = "gremlin";
4070
+ compile(spec, _vocabulary) {
4071
+ const parts = [];
4072
+ const params = {};
4073
+ let paramIndex = 0;
4074
+ let estimatedFanOut = 1;
4075
+ const nextParam = (value) => {
4076
+ const name = `p${paramIndex++}`;
4077
+ params[name] = value;
4078
+ return name;
4079
+ };
4080
+ parts.push("g.V()");
4081
+ if (spec.start.entityId) {
4082
+ const p = nextParam(spec.start.entityId);
4083
+ parts.push(`.has('id', ${p})`);
4084
+ } else if (spec.start.entityType) {
4085
+ const p = nextParam(spec.start.entityType);
4086
+ parts.push(`.has('entityType', ${p})`);
4087
+ estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
4088
+ }
4089
+ if (spec.start.filter) {
4090
+ for (const f of spec.start.filter) {
4091
+ parts.push(compilePropertyFilter(f, nextParam));
4092
+ }
4093
+ }
4094
+ const steps = spec.steps ?? [];
4095
+ for (const step of steps) {
4096
+ if (step.repeat) {
4097
+ parts.push(compileRepeatStep(step, nextParam));
4098
+ estimatedFanOut *= step.repeat.maxDepth * DEFAULT_ESTIMATED_FANOUT_PER_HOP;
4099
+ } else if (step.relationshipFilter && step.relationshipFilter.length > 0) {
4100
+ parts.push(compileEdgeStep(step, nextParam));
4101
+ estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
4102
+ } else {
4103
+ parts.push(compileSimpleStep(step, nextParam));
4104
+ estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
4105
+ }
4106
+ if (step.entityTypes && step.entityTypes.length > 0) {
4107
+ const typeParams = step.entityTypes.map((t) => nextParam(t));
4108
+ parts.push(`.has('entityType', within(${typeParams.join(", ")}))`);
4109
+ }
4110
+ if (step.entityFilter) {
4111
+ for (const f of step.entityFilter) {
4112
+ parts.push(compilePropertyFilter(f, nextParam));
4113
+ }
4114
+ }
4115
+ }
4116
+ if (spec.returnMode === "all") {
4117
+ }
4118
+ if (spec.dedup !== false) {
4119
+ parts.push(".dedup()");
4120
+ }
4121
+ const limit = spec.limit ?? 50;
4122
+ const offset = spec.offset ?? 0;
4123
+ const pOffset = nextParam(offset);
4124
+ const pEnd = nextParam(offset + limit);
4125
+ parts.push(`.range(${pOffset}, ${pEnd})`);
4126
+ params["_limit"] = limit;
4127
+ params["_offset"] = offset;
4128
+ if (spec.returnMode === "path") {
4129
+ parts.push(".path()");
4130
+ }
4131
+ if (spec.returnMode !== "path") {
4132
+ parts.push(".valueMap(true)");
4133
+ }
4134
+ return {
4135
+ query: parts.join(""),
4136
+ params,
4137
+ estimatedFanOut: Math.min(estimatedFanOut, 1e4)
4138
+ };
4139
+ }
4140
+ };
4141
+ function compileSimpleStep(step, nextParam) {
4142
+ const types = step.relationshipTypes;
4143
+ const typeArgs = types ? types.map((t) => nextParam(t)).join(", ") : "";
4144
+ switch (step.direction) {
4145
+ case "out":
4146
+ return types ? `.out(${typeArgs})` : ".out()";
4147
+ case "in":
4148
+ return types ? `.in(${typeArgs})` : ".in()";
4149
+ case "both":
4150
+ return types ? `.both(${typeArgs})` : ".both()";
4151
+ }
4152
+ }
4153
+ function compileEdgeStep(step, nextParam) {
4154
+ const parts = [];
4155
+ const types = step.relationshipTypes;
4156
+ const typeArgs = types ? types.map((t) => nextParam(t)).join(", ") : "";
4157
+ switch (step.direction) {
4158
+ case "out":
4159
+ parts.push(types ? `.outE(${typeArgs})` : ".outE()");
4160
+ break;
4161
+ case "in":
4162
+ parts.push(types ? `.inE(${typeArgs})` : ".inE()");
4163
+ break;
4164
+ case "both":
4165
+ parts.push(types ? `.bothE(${typeArgs})` : ".bothE()");
4166
+ break;
4167
+ }
4168
+ if (step.relationshipFilter) {
4169
+ for (const f of step.relationshipFilter) {
4170
+ parts.push(compilePropertyFilter(f, nextParam));
4345
4171
  }
4346
- return result;
4347
4172
  }
4348
- /** Subscribe to global events */
4349
- on(event, handler) {
4350
- return this.globalEventBus.on(event, handler);
4173
+ switch (step.direction) {
4174
+ case "out":
4175
+ parts.push(".inV()");
4176
+ break;
4177
+ case "in":
4178
+ parts.push(".outV()");
4179
+ break;
4180
+ case "both":
4181
+ parts.push(".otherV()");
4182
+ break;
4351
4183
  }
4352
- /** Update the provenance context (e.g., new conversation) */
4353
- updateProvenance(context) {
4354
- this.provenance.updateContext(context);
4355
- this.globalEventBus.updateProvenance(this.provenance.getContext());
4184
+ return parts.join("");
4185
+ }
4186
+ function compileRepeatStep(step, nextParam) {
4187
+ const parts = [];
4188
+ const innerStep = step.relationshipFilter?.length ? compileEdgeStep({ ...step, repeat: void 0 }, nextParam) : compileSimpleStep(step, nextParam);
4189
+ if (step.repeat?.emitIntermediates !== false) {
4190
+ parts.push(".emit()");
4356
4191
  }
4357
- /** Dispose of all resources */
4358
- async dispose() {
4359
- this.globalEventBus.removeAllListeners();
4360
- if (this.graphTraversalProvider?.dispose) {
4361
- await this.graphTraversalProvider.dispose();
4192
+ parts.push(`.repeat(${innerStep.startsWith(".") ? `__${innerStep}` : innerStep})`);
4193
+ if (step.repeat?.until && step.repeat.until.length > 0) {
4194
+ const untilParts = step.repeat.until.map((f) => compilePropertyFilter(f, nextParam));
4195
+ parts.push(`.until(${untilParts.join("")})`);
4196
+ }
4197
+ if (step.repeat?.maxDepth) {
4198
+ const p = nextParam(step.repeat.maxDepth);
4199
+ parts.push(`.times(${p})`);
4200
+ }
4201
+ if (step.repeat?.emitIntermediates === false) {
4202
+ parts.push(".emit()");
4203
+ }
4204
+ return parts.join("");
4205
+ }
4206
+ function compilePropertyFilter(filter, nextParam) {
4207
+ const key = nextParam(filter.key);
4208
+ switch (filter.operator) {
4209
+ case "eq": {
4210
+ const val = nextParam(filter.value);
4211
+ return `.has(${key}, ${val})`;
4362
4212
  }
4363
- if (this.storage.dispose) {
4364
- await this.storage.dispose();
4213
+ case "neq": {
4214
+ const val = nextParam(filter.value);
4215
+ return `.has(${key}, neq(${val}))`;
4365
4216
  }
4366
- this.initialized = false;
4217
+ case "gt": {
4218
+ const val = nextParam(filter.value);
4219
+ return `.has(${key}, gt(${val}))`;
4220
+ }
4221
+ case "gte": {
4222
+ const val = nextParam(filter.value);
4223
+ return `.has(${key}, gte(${val}))`;
4224
+ }
4225
+ case "lt": {
4226
+ const val = nextParam(filter.value);
4227
+ return `.has(${key}, lt(${val}))`;
4228
+ }
4229
+ case "lte": {
4230
+ const val = nextParam(filter.value);
4231
+ return `.has(${key}, lte(${val}))`;
4232
+ }
4233
+ case "contains": {
4234
+ const val = nextParam(filter.value);
4235
+ return `.has(${key}, containing(${val}))`;
4236
+ }
4237
+ case "isNull":
4238
+ return `.hasNot(${key})`;
4239
+ case "isNotNull":
4240
+ return `.has(${key})`;
4241
+ }
4242
+ }
4243
+
4244
+ // src/relationships/compilers/CypherCompiler.ts
4245
+ var DEFAULT_ESTIMATED_FANOUT_PER_HOP2 = 10;
4246
+ var CypherCompiler = class {
4247
+ language = "cypher";
4248
+ compile(spec, _vocabulary) {
4249
+ const params = {};
4250
+ let paramIndex = 0;
4251
+ let estimatedFanOut = 1;
4252
+ const whereClauses = [];
4253
+ let nodeIndex = 0;
4254
+ const nextParam = (value) => {
4255
+ const name = `p${paramIndex++}`;
4256
+ params[name] = value;
4257
+ return `$${name}`;
4258
+ };
4259
+ const startNode = `n${nodeIndex++}`;
4260
+ let matchParts = [];
4261
+ if (spec.start.entityId) {
4262
+ matchParts.push(`(${startNode})`);
4263
+ whereClauses.push(`${startNode}.id = ${nextParam(spec.start.entityId)}`);
4264
+ } else if (spec.start.entityType) {
4265
+ matchParts.push(`(${startNode})`);
4266
+ whereClauses.push(`${startNode}.entityType = ${nextParam(spec.start.entityType)}`);
4267
+ estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP2;
4268
+ } else {
4269
+ matchParts.push(`(${startNode})`);
4270
+ }
4271
+ if (spec.start.filter) {
4272
+ for (const f of spec.start.filter) {
4273
+ whereClauses.push(compilePropertyFilterCypher(startNode, f, nextParam));
4274
+ }
4275
+ }
4276
+ let lastNode = startNode;
4277
+ const steps = spec.steps ?? [];
4278
+ for (let i = 0; i < steps.length; i++) {
4279
+ const step = steps[i];
4280
+ const targetNode = `n${nodeIndex++}`;
4281
+ const relAlias = `r${i}`;
4282
+ const relTypes = step.relationshipTypes?.length ? step.relationshipTypes.join("|") : "";
4283
+ const relTypePattern = relTypes ? `:${relTypes}` : "";
4284
+ const depthPattern = step.repeat ? `*1..${step.repeat.maxDepth}` : "";
4285
+ let pattern;
4286
+ switch (step.direction) {
4287
+ case "out":
4288
+ pattern = `-[${relAlias}${relTypePattern}${depthPattern}]->(${targetNode})`;
4289
+ break;
4290
+ case "in":
4291
+ pattern = `<-[${relAlias}${relTypePattern}${depthPattern}]-(${targetNode})`;
4292
+ break;
4293
+ case "both":
4294
+ pattern = `-[${relAlias}${relTypePattern}${depthPattern}]-(${targetNode})`;
4295
+ break;
4296
+ }
4297
+ matchParts.push(pattern);
4298
+ estimatedFanOut *= step.repeat ? step.repeat.maxDepth * DEFAULT_ESTIMATED_FANOUT_PER_HOP2 : DEFAULT_ESTIMATED_FANOUT_PER_HOP2;
4299
+ if (step.entityTypes && step.entityTypes.length > 0) {
4300
+ const typeParam = nextParam(step.entityTypes);
4301
+ whereClauses.push(`${targetNode}.entityType IN ${typeParam}`);
4302
+ }
4303
+ if (step.entityFilter) {
4304
+ for (const f of step.entityFilter) {
4305
+ whereClauses.push(compilePropertyFilterCypher(targetNode, f, nextParam));
4306
+ }
4307
+ }
4308
+ if (step.relationshipFilter) {
4309
+ for (const f of step.relationshipFilter) {
4310
+ whereClauses.push(compilePropertyFilterCypher(relAlias, f, nextParam));
4311
+ }
4312
+ }
4313
+ lastNode = targetNode;
4314
+ }
4315
+ const matchClause = `MATCH ${matchParts[0]}${matchParts.slice(1).join("")}`;
4316
+ const whereClause = whereClauses.length > 0 ? `
4317
+ WHERE ${whereClauses.join(" AND ")}` : "";
4318
+ let returnClause;
4319
+ if (spec.returnMode === "path") {
4320
+ const allNodes = Array.from({ length: nodeIndex }, (_, i) => `n${i}`);
4321
+ const allRels = steps.map((_, i) => `r${i}`);
4322
+ returnClause = `RETURN ${[...allNodes, ...allRels].join(", ")}`;
4323
+ } else if (spec.returnMode === "all") {
4324
+ const allNodes = Array.from({ length: nodeIndex }, (_, i) => `n${i}`);
4325
+ returnClause = spec.dedup !== false ? `RETURN DISTINCT ${allNodes.join(", ")}` : `RETURN ${allNodes.join(", ")}`;
4326
+ } else {
4327
+ returnClause = spec.dedup !== false ? `RETURN DISTINCT ${lastNode}` : `RETURN ${lastNode}`;
4328
+ }
4329
+ const offset = spec.offset ?? 0;
4330
+ const limit = spec.limit ?? 50;
4331
+ const skipClause = offset > 0 ? `
4332
+ SKIP ${nextParam(offset)}` : "";
4333
+ const limitClause = `
4334
+ LIMIT ${nextParam(limit)}`;
4335
+ params["_limit"] = limit;
4336
+ params["_offset"] = offset;
4337
+ const query = `${matchClause}${whereClause}
4338
+ ${returnClause}${skipClause}${limitClause}`;
4339
+ return {
4340
+ query,
4341
+ params,
4342
+ estimatedFanOut: Math.min(estimatedFanOut, 1e4)
4343
+ };
4367
4344
  }
4368
4345
  };
4346
+ function compilePropertyFilterCypher(nodeAlias, filter, nextParam) {
4347
+ const prop = `${nodeAlias}.${filter.key}`;
4348
+ switch (filter.operator) {
4349
+ case "eq":
4350
+ return `${prop} = ${nextParam(filter.value)}`;
4351
+ case "neq":
4352
+ return `${prop} <> ${nextParam(filter.value)}`;
4353
+ case "gt":
4354
+ return `${prop} > ${nextParam(filter.value)}`;
4355
+ case "gte":
4356
+ return `${prop} >= ${nextParam(filter.value)}`;
4357
+ case "lt":
4358
+ return `${prop} < ${nextParam(filter.value)}`;
4359
+ case "lte":
4360
+ return `${prop} <= ${nextParam(filter.value)}`;
4361
+ case "contains":
4362
+ return `${prop} CONTAINS ${nextParam(filter.value)}`;
4363
+ case "isNull":
4364
+ return `${prop} IS NULL`;
4365
+ case "isNotNull":
4366
+ return `${prop} IS NOT NULL`;
4367
+ }
4368
+ }
4369
4369
 
4370
4370
  // src/providers-builtin/InMemoryStorageProvider.ts
4371
4371
  var InMemoryStorageProvider = class {
@@ -5099,6 +5099,7 @@ export {
5099
5099
  VocabularyValidationError,
5100
5100
  generateId,
5101
5101
  isValidUuid,
5102
- matchesPropertyFilters
5102
+ matchesPropertyFilters,
5103
+ projectEntity
5103
5104
  };
5104
5105
  //# sourceMappingURL=index.js.map