@utaba/deep-memory 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -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.4.0" : "0.1.0";
3041
+ var LIBRARY_VERSION = true ? "0.6.0" : "0.1.0";
3356
3042
  var RepositoryExporter = class {
3357
3043
  storage;
3358
3044
  provenance;
@@ -4318,54 +4004,358 @@ var DeepMemory = class {
4318
4004
  relationshipCount
4319
4005
  });
4320
4006
  }
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
- });
4007
+ /**
4008
+ * Import a repository from a stream of chunks.
4009
+ * Use for large repositories to avoid loading everything into memory.
4010
+ */
4011
+ async importRepositoryStream(header, chunks, options) {
4012
+ await this.ensureInitialized();
4013
+ const importer = new RepositoryImporter({
4014
+ storage: this.storage,
4015
+ actorId: this.provenance.getContext().actorId,
4016
+ onProgress: (progress) => this.globalEventBus.emit("import:progress", progress)
4017
+ });
4018
+ await this.globalEventBus.emit("import:started", { repositoryId: options.target.repositoryId });
4019
+ const result = await importer.importStream(header, chunks, options);
4020
+ if (result.success) {
4021
+ await this.globalEventBus.emit("import:completed", {
4022
+ repositoryId: result.repositoryId,
4023
+ entitiesImported: result.statistics.entitiesImported,
4024
+ relationshipsImported: result.statistics.relationshipsImported
4025
+ });
4026
+ } else {
4027
+ await this.globalEventBus.emit("import:failed", {
4028
+ repositoryId: result.repositoryId,
4029
+ error: result.warnings.map((w) => w.message).join("; ")
4030
+ });
4031
+ }
4032
+ return result;
4033
+ }
4034
+ /** Subscribe to global events */
4035
+ on(event, handler) {
4036
+ return this.globalEventBus.on(event, handler);
4037
+ }
4038
+ /** Update the provenance context (e.g., new conversation) */
4039
+ updateProvenance(context) {
4040
+ this.provenance.updateContext(context);
4041
+ this.globalEventBus.updateProvenance(this.provenance.getContext());
4042
+ }
4043
+ /** Dispose of all resources */
4044
+ async dispose() {
4045
+ this.globalEventBus.removeAllListeners();
4046
+ if (this.graphTraversalProvider?.dispose) {
4047
+ await this.graphTraversalProvider.dispose();
4048
+ }
4049
+ if (this.storage.dispose) {
4050
+ await this.storage.dispose();
4051
+ }
4052
+ this.initialized = false;
4053
+ }
4054
+ };
4055
+
4056
+ // src/relationships/compilers/GremlinCompiler.ts
4057
+ var DEFAULT_ESTIMATED_FANOUT_PER_HOP = 10;
4058
+ var GremlinCompiler = class {
4059
+ language = "gremlin";
4060
+ compile(spec, _vocabulary) {
4061
+ const parts = [];
4062
+ const params = {};
4063
+ let paramIndex = 0;
4064
+ let estimatedFanOut = 1;
4065
+ const nextParam = (value) => {
4066
+ const name = `p${paramIndex++}`;
4067
+ params[name] = value;
4068
+ return name;
4069
+ };
4070
+ parts.push("g.V()");
4071
+ if (spec.start.entityId) {
4072
+ const p = nextParam(spec.start.entityId);
4073
+ parts.push(`.has('id', ${p})`);
4074
+ } else if (spec.start.entityType) {
4075
+ const p = nextParam(spec.start.entityType);
4076
+ parts.push(`.has('entityType', ${p})`);
4077
+ estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
4078
+ }
4079
+ if (spec.start.filter) {
4080
+ for (const f of spec.start.filter) {
4081
+ parts.push(compilePropertyFilter(f, nextParam));
4082
+ }
4083
+ }
4084
+ const steps = spec.steps ?? [];
4085
+ for (const step of steps) {
4086
+ if (step.repeat) {
4087
+ parts.push(compileRepeatStep(step, nextParam));
4088
+ estimatedFanOut *= step.repeat.maxDepth * DEFAULT_ESTIMATED_FANOUT_PER_HOP;
4089
+ } else if (step.relationshipFilter && step.relationshipFilter.length > 0) {
4090
+ parts.push(compileEdgeStep(step, nextParam));
4091
+ estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
4092
+ } else {
4093
+ parts.push(compileSimpleStep(step, nextParam));
4094
+ estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
4095
+ }
4096
+ if (step.entityTypes && step.entityTypes.length > 0) {
4097
+ const typeParams = step.entityTypes.map((t) => nextParam(t));
4098
+ parts.push(`.has('entityType', within(${typeParams.join(", ")}))`);
4099
+ }
4100
+ if (step.entityFilter) {
4101
+ for (const f of step.entityFilter) {
4102
+ parts.push(compilePropertyFilter(f, nextParam));
4103
+ }
4104
+ }
4105
+ }
4106
+ if (spec.returnMode === "all") {
4107
+ }
4108
+ if (spec.dedup !== false) {
4109
+ parts.push(".dedup()");
4110
+ }
4111
+ const limit = spec.limit ?? 50;
4112
+ const offset = spec.offset ?? 0;
4113
+ const pOffset = nextParam(offset);
4114
+ const pEnd = nextParam(offset + limit);
4115
+ parts.push(`.range(${pOffset}, ${pEnd})`);
4116
+ params["_limit"] = limit;
4117
+ params["_offset"] = offset;
4118
+ if (spec.returnMode === "path") {
4119
+ parts.push(".path()");
4120
+ }
4121
+ if (spec.returnMode !== "path") {
4122
+ parts.push(".valueMap(true)");
4123
+ }
4124
+ return {
4125
+ query: parts.join(""),
4126
+ params,
4127
+ estimatedFanOut: Math.min(estimatedFanOut, 1e4)
4128
+ };
4129
+ }
4130
+ };
4131
+ function compileSimpleStep(step, nextParam) {
4132
+ const types = step.relationshipTypes;
4133
+ const typeArgs = types ? types.map((t) => nextParam(t)).join(", ") : "";
4134
+ switch (step.direction) {
4135
+ case "out":
4136
+ return types ? `.out(${typeArgs})` : ".out()";
4137
+ case "in":
4138
+ return types ? `.in(${typeArgs})` : ".in()";
4139
+ case "both":
4140
+ return types ? `.both(${typeArgs})` : ".both()";
4141
+ }
4142
+ }
4143
+ function compileEdgeStep(step, nextParam) {
4144
+ const parts = [];
4145
+ const types = step.relationshipTypes;
4146
+ const typeArgs = types ? types.map((t) => nextParam(t)).join(", ") : "";
4147
+ switch (step.direction) {
4148
+ case "out":
4149
+ parts.push(types ? `.outE(${typeArgs})` : ".outE()");
4150
+ break;
4151
+ case "in":
4152
+ parts.push(types ? `.inE(${typeArgs})` : ".inE()");
4153
+ break;
4154
+ case "both":
4155
+ parts.push(types ? `.bothE(${typeArgs})` : ".bothE()");
4156
+ break;
4157
+ }
4158
+ if (step.relationshipFilter) {
4159
+ for (const f of step.relationshipFilter) {
4160
+ parts.push(compilePropertyFilter(f, nextParam));
4345
4161
  }
4346
- return result;
4347
4162
  }
4348
- /** Subscribe to global events */
4349
- on(event, handler) {
4350
- return this.globalEventBus.on(event, handler);
4163
+ switch (step.direction) {
4164
+ case "out":
4165
+ parts.push(".inV()");
4166
+ break;
4167
+ case "in":
4168
+ parts.push(".outV()");
4169
+ break;
4170
+ case "both":
4171
+ parts.push(".otherV()");
4172
+ break;
4351
4173
  }
4352
- /** Update the provenance context (e.g., new conversation) */
4353
- updateProvenance(context) {
4354
- this.provenance.updateContext(context);
4355
- this.globalEventBus.updateProvenance(this.provenance.getContext());
4174
+ return parts.join("");
4175
+ }
4176
+ function compileRepeatStep(step, nextParam) {
4177
+ const parts = [];
4178
+ const innerStep = step.relationshipFilter?.length ? compileEdgeStep({ ...step, repeat: void 0 }, nextParam) : compileSimpleStep(step, nextParam);
4179
+ if (step.repeat?.emitIntermediates !== false) {
4180
+ parts.push(".emit()");
4356
4181
  }
4357
- /** Dispose of all resources */
4358
- async dispose() {
4359
- this.globalEventBus.removeAllListeners();
4360
- if (this.graphTraversalProvider?.dispose) {
4361
- await this.graphTraversalProvider.dispose();
4182
+ parts.push(`.repeat(${innerStep.startsWith(".") ? `__${innerStep}` : innerStep})`);
4183
+ if (step.repeat?.until && step.repeat.until.length > 0) {
4184
+ const untilParts = step.repeat.until.map((f) => compilePropertyFilter(f, nextParam));
4185
+ parts.push(`.until(${untilParts.join("")})`);
4186
+ }
4187
+ if (step.repeat?.maxDepth) {
4188
+ const p = nextParam(step.repeat.maxDepth);
4189
+ parts.push(`.times(${p})`);
4190
+ }
4191
+ if (step.repeat?.emitIntermediates === false) {
4192
+ parts.push(".emit()");
4193
+ }
4194
+ return parts.join("");
4195
+ }
4196
+ function compilePropertyFilter(filter, nextParam) {
4197
+ const key = nextParam(filter.key);
4198
+ switch (filter.operator) {
4199
+ case "eq": {
4200
+ const val = nextParam(filter.value);
4201
+ return `.has(${key}, ${val})`;
4362
4202
  }
4363
- if (this.storage.dispose) {
4364
- await this.storage.dispose();
4203
+ case "neq": {
4204
+ const val = nextParam(filter.value);
4205
+ return `.has(${key}, neq(${val}))`;
4365
4206
  }
4366
- this.initialized = false;
4207
+ case "gt": {
4208
+ const val = nextParam(filter.value);
4209
+ return `.has(${key}, gt(${val}))`;
4210
+ }
4211
+ case "gte": {
4212
+ const val = nextParam(filter.value);
4213
+ return `.has(${key}, gte(${val}))`;
4214
+ }
4215
+ case "lt": {
4216
+ const val = nextParam(filter.value);
4217
+ return `.has(${key}, lt(${val}))`;
4218
+ }
4219
+ case "lte": {
4220
+ const val = nextParam(filter.value);
4221
+ return `.has(${key}, lte(${val}))`;
4222
+ }
4223
+ case "contains": {
4224
+ const val = nextParam(filter.value);
4225
+ return `.has(${key}, containing(${val}))`;
4226
+ }
4227
+ case "isNull":
4228
+ return `.hasNot(${key})`;
4229
+ case "isNotNull":
4230
+ return `.has(${key})`;
4231
+ }
4232
+ }
4233
+
4234
+ // src/relationships/compilers/CypherCompiler.ts
4235
+ var DEFAULT_ESTIMATED_FANOUT_PER_HOP2 = 10;
4236
+ var CypherCompiler = class {
4237
+ language = "cypher";
4238
+ compile(spec, _vocabulary) {
4239
+ const params = {};
4240
+ let paramIndex = 0;
4241
+ let estimatedFanOut = 1;
4242
+ const whereClauses = [];
4243
+ let nodeIndex = 0;
4244
+ const nextParam = (value) => {
4245
+ const name = `p${paramIndex++}`;
4246
+ params[name] = value;
4247
+ return `$${name}`;
4248
+ };
4249
+ const startNode = `n${nodeIndex++}`;
4250
+ let matchParts = [];
4251
+ if (spec.start.entityId) {
4252
+ matchParts.push(`(${startNode})`);
4253
+ whereClauses.push(`${startNode}.id = ${nextParam(spec.start.entityId)}`);
4254
+ } else if (spec.start.entityType) {
4255
+ matchParts.push(`(${startNode})`);
4256
+ whereClauses.push(`${startNode}.entityType = ${nextParam(spec.start.entityType)}`);
4257
+ estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP2;
4258
+ } else {
4259
+ matchParts.push(`(${startNode})`);
4260
+ }
4261
+ if (spec.start.filter) {
4262
+ for (const f of spec.start.filter) {
4263
+ whereClauses.push(compilePropertyFilterCypher(startNode, f, nextParam));
4264
+ }
4265
+ }
4266
+ let lastNode = startNode;
4267
+ const steps = spec.steps ?? [];
4268
+ for (let i = 0; i < steps.length; i++) {
4269
+ const step = steps[i];
4270
+ const targetNode = `n${nodeIndex++}`;
4271
+ const relAlias = `r${i}`;
4272
+ const relTypes = step.relationshipTypes?.length ? step.relationshipTypes.join("|") : "";
4273
+ const relTypePattern = relTypes ? `:${relTypes}` : "";
4274
+ const depthPattern = step.repeat ? `*1..${step.repeat.maxDepth}` : "";
4275
+ let pattern;
4276
+ switch (step.direction) {
4277
+ case "out":
4278
+ pattern = `-[${relAlias}${relTypePattern}${depthPattern}]->(${targetNode})`;
4279
+ break;
4280
+ case "in":
4281
+ pattern = `<-[${relAlias}${relTypePattern}${depthPattern}]-(${targetNode})`;
4282
+ break;
4283
+ case "both":
4284
+ pattern = `-[${relAlias}${relTypePattern}${depthPattern}]-(${targetNode})`;
4285
+ break;
4286
+ }
4287
+ matchParts.push(pattern);
4288
+ estimatedFanOut *= step.repeat ? step.repeat.maxDepth * DEFAULT_ESTIMATED_FANOUT_PER_HOP2 : DEFAULT_ESTIMATED_FANOUT_PER_HOP2;
4289
+ if (step.entityTypes && step.entityTypes.length > 0) {
4290
+ const typeParam = nextParam(step.entityTypes);
4291
+ whereClauses.push(`${targetNode}.entityType IN ${typeParam}`);
4292
+ }
4293
+ if (step.entityFilter) {
4294
+ for (const f of step.entityFilter) {
4295
+ whereClauses.push(compilePropertyFilterCypher(targetNode, f, nextParam));
4296
+ }
4297
+ }
4298
+ if (step.relationshipFilter) {
4299
+ for (const f of step.relationshipFilter) {
4300
+ whereClauses.push(compilePropertyFilterCypher(relAlias, f, nextParam));
4301
+ }
4302
+ }
4303
+ lastNode = targetNode;
4304
+ }
4305
+ const matchClause = `MATCH ${matchParts[0]}${matchParts.slice(1).join("")}`;
4306
+ const whereClause = whereClauses.length > 0 ? `
4307
+ WHERE ${whereClauses.join(" AND ")}` : "";
4308
+ let returnClause;
4309
+ if (spec.returnMode === "path") {
4310
+ const allNodes = Array.from({ length: nodeIndex }, (_, i) => `n${i}`);
4311
+ const allRels = steps.map((_, i) => `r${i}`);
4312
+ returnClause = `RETURN ${[...allNodes, ...allRels].join(", ")}`;
4313
+ } else if (spec.returnMode === "all") {
4314
+ const allNodes = Array.from({ length: nodeIndex }, (_, i) => `n${i}`);
4315
+ returnClause = spec.dedup !== false ? `RETURN DISTINCT ${allNodes.join(", ")}` : `RETURN ${allNodes.join(", ")}`;
4316
+ } else {
4317
+ returnClause = spec.dedup !== false ? `RETURN DISTINCT ${lastNode}` : `RETURN ${lastNode}`;
4318
+ }
4319
+ const offset = spec.offset ?? 0;
4320
+ const limit = spec.limit ?? 50;
4321
+ const skipClause = offset > 0 ? `
4322
+ SKIP ${nextParam(offset)}` : "";
4323
+ const limitClause = `
4324
+ LIMIT ${nextParam(limit)}`;
4325
+ params["_limit"] = limit;
4326
+ params["_offset"] = offset;
4327
+ const query = `${matchClause}${whereClause}
4328
+ ${returnClause}${skipClause}${limitClause}`;
4329
+ return {
4330
+ query,
4331
+ params,
4332
+ estimatedFanOut: Math.min(estimatedFanOut, 1e4)
4333
+ };
4367
4334
  }
4368
4335
  };
4336
+ function compilePropertyFilterCypher(nodeAlias, filter, nextParam) {
4337
+ const prop = `${nodeAlias}.${filter.key}`;
4338
+ switch (filter.operator) {
4339
+ case "eq":
4340
+ return `${prop} = ${nextParam(filter.value)}`;
4341
+ case "neq":
4342
+ return `${prop} <> ${nextParam(filter.value)}`;
4343
+ case "gt":
4344
+ return `${prop} > ${nextParam(filter.value)}`;
4345
+ case "gte":
4346
+ return `${prop} >= ${nextParam(filter.value)}`;
4347
+ case "lt":
4348
+ return `${prop} < ${nextParam(filter.value)}`;
4349
+ case "lte":
4350
+ return `${prop} <= ${nextParam(filter.value)}`;
4351
+ case "contains":
4352
+ return `${prop} CONTAINS ${nextParam(filter.value)}`;
4353
+ case "isNull":
4354
+ return `${prop} IS NULL`;
4355
+ case "isNotNull":
4356
+ return `${prop} IS NOT NULL`;
4357
+ }
4358
+ }
4369
4359
 
4370
4360
  // src/providers-builtin/InMemoryStorageProvider.ts
4371
4361
  var InMemoryStorageProvider = class {
@@ -5099,6 +5089,7 @@ export {
5099
5089
  VocabularyValidationError,
5100
5090
  generateId,
5101
5091
  isValidUuid,
5102
- matchesPropertyFilters
5092
+ matchesPropertyFilters,
5093
+ projectEntity
5103
5094
  };
5104
5095
  //# sourceMappingURL=index.js.map