flowquery 1.0.66 → 1.0.68

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.
@@ -0,0 +1,730 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const database_1 = __importDefault(require("../graph/database"));
7
+ const node_1 = __importDefault(require("../graph/node"));
8
+ const relationship_1 = __importDefault(require("../graph/relationship"));
9
+ const ast_node_1 = __importDefault(require("./ast_node"));
10
+ const lookup_1 = __importDefault(require("./data_structures/lookup"));
11
+ const f_string_1 = __importDefault(require("./expressions/f_string"));
12
+ const identifier_1 = __importDefault(require("./expressions/identifier"));
13
+ const operator_1 = require("./expressions/operator");
14
+ const parameter_reference_1 = __importDefault(require("./expressions/parameter_reference"));
15
+ const reference_1 = __importDefault(require("./expressions/reference"));
16
+ const subquery_expression_1 = __importDefault(require("./expressions/subquery_expression"));
17
+ const aggregated_return_1 = __importDefault(require("./operations/aggregated_return"));
18
+ const aggregated_with_1 = __importDefault(require("./operations/aggregated_with"));
19
+ const create_node_1 = __importDefault(require("./operations/create_node"));
20
+ const create_relationship_1 = __importDefault(require("./operations/create_relationship"));
21
+ const delete_node_1 = __importDefault(require("./operations/delete_node"));
22
+ const delete_relationship_1 = __importDefault(require("./operations/delete_relationship"));
23
+ const load_1 = __importDefault(require("./operations/load"));
24
+ const match_1 = __importDefault(require("./operations/match"));
25
+ const order_by_1 = __importDefault(require("./operations/order_by"));
26
+ const return_1 = __importDefault(require("./operations/return"));
27
+ const with_1 = __importDefault(require("./operations/with"));
28
+ /**
29
+ * Walks one or more parsed FlowQuery statement ASTs and extracts a
30
+ * `StatementInfo` describing the labels, relationship types, sources, and
31
+ * properties they reference.
32
+ *
33
+ * The crawler does not execute the statement. It only inspects the AST
34
+ * structure plus the live `Database` registry (to resolve sources for
35
+ * virtuals that are referenced but not (re-)declared in the AST).
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * const crawler = new StatementInfoCrawler();
40
+ * const info = crawler.crawl(ast);
41
+ * console.log(info.node_labels);
42
+ * ```
43
+ */
44
+ class StatementInfoCrawler {
45
+ constructor() {
46
+ this._nodeLabels = new Set();
47
+ this._relTypes = new Set();
48
+ this._nodeProps = new Map();
49
+ this._relProps = new Map();
50
+ this._nodeSources = new Map();
51
+ this._relSources = new Map();
52
+ this._nodeLiterals = new Map();
53
+ this._relLiterals = new Map();
54
+ this._nodeDeclaredProps = new Map();
55
+ this._relDeclaredProps = new Map();
56
+ this._nodeDeclaredSources = new Map();
57
+ this._relDeclaredSources = new Map();
58
+ this._ownCreatedNodeLabels = new Set();
59
+ this._ownCreatedRelTypes = new Set();
60
+ /**
61
+ * For each inline CREATE VIRTUAL clause, the (label or type) it
62
+ * declares and its inner statement AST. The label key receives the
63
+ * sources collected from the statement during {@link resolveRegisteredDefinitions}.
64
+ */
65
+ this._ownNodeCreates = [];
66
+ this._ownRelCreates = [];
67
+ }
68
+ /**
69
+ * Walks one or more statement ASTs and returns the merged structural info.
70
+ *
71
+ * @param statements - A single statement root, or an iterable of roots
72
+ * (for multi-statement queries).
73
+ */
74
+ crawl(statements) {
75
+ this.reset();
76
+ const roots = this.toIterable(statements);
77
+ for (const root of roots) {
78
+ this.crawlStatement(root);
79
+ }
80
+ this.resolveRegisteredDefinitions();
81
+ return this.snapshot();
82
+ }
83
+ toIterable(statements) {
84
+ if (statements instanceof ast_node_1.default) {
85
+ return [statements];
86
+ }
87
+ return statements;
88
+ }
89
+ reset() {
90
+ this._nodeLabels = new Set();
91
+ this._relTypes = new Set();
92
+ this._nodeProps = new Map();
93
+ this._relProps = new Map();
94
+ this._nodeSources = new Map();
95
+ this._relSources = new Map();
96
+ this._nodeLiterals = new Map();
97
+ this._relLiterals = new Map();
98
+ this._nodeDeclaredProps = new Map();
99
+ this._relDeclaredProps = new Map();
100
+ this._nodeDeclaredSources = new Map();
101
+ this._relDeclaredSources = new Map();
102
+ this._ownCreatedNodeLabels = new Set();
103
+ this._ownCreatedRelTypes = new Set();
104
+ this._ownNodeCreates = [];
105
+ this._ownRelCreates = [];
106
+ }
107
+ crawlStatement(root) {
108
+ let op = null;
109
+ try {
110
+ op = root.firstChild();
111
+ }
112
+ catch (_a) {
113
+ return;
114
+ }
115
+ while (op !== null) {
116
+ this.visitOperation(op);
117
+ op = op.next;
118
+ }
119
+ }
120
+ visitOperation(op) {
121
+ var _a, _b, _c, _d, _e;
122
+ if (op instanceof create_node_1.default) {
123
+ const node = op.node;
124
+ if (node === null || node === void 0 ? void 0 : node.label) {
125
+ this._nodeLabels.add(node.label);
126
+ this._ownCreatedNodeLabels.add(node.label);
127
+ if (op.statement) {
128
+ this._ownNodeCreates.push({ label: node.label, statement: op.statement });
129
+ }
130
+ }
131
+ }
132
+ else if (op instanceof create_relationship_1.default) {
133
+ const rel = op.relationship;
134
+ if (rel === null || rel === void 0 ? void 0 : rel.type) {
135
+ this._relTypes.add(rel.type);
136
+ this._ownCreatedRelTypes.add(rel.type);
137
+ if (op.statement) {
138
+ this._ownRelCreates.push({ type: rel.type, statement: op.statement });
139
+ }
140
+ }
141
+ if ((_a = rel === null || rel === void 0 ? void 0 : rel.source) === null || _a === void 0 ? void 0 : _a.label)
142
+ this._nodeLabels.add(rel.source.label);
143
+ if ((_b = rel === null || rel === void 0 ? void 0 : rel.target) === null || _b === void 0 ? void 0 : _b.label)
144
+ this._nodeLabels.add(rel.target.label);
145
+ }
146
+ else if (op instanceof delete_node_1.default) {
147
+ if ((_c = op.node) === null || _c === void 0 ? void 0 : _c.label)
148
+ this._nodeLabels.add(op.node.label);
149
+ }
150
+ else if (op instanceof delete_relationship_1.default) {
151
+ const rel = op.relationship;
152
+ if (rel === null || rel === void 0 ? void 0 : rel.type)
153
+ this._relTypes.add(rel.type);
154
+ if ((_d = rel === null || rel === void 0 ? void 0 : rel.source) === null || _d === void 0 ? void 0 : _d.label)
155
+ this._nodeLabels.add(rel.source.label);
156
+ if ((_e = rel === null || rel === void 0 ? void 0 : rel.target) === null || _e === void 0 ? void 0 : _e.label)
157
+ this._nodeLabels.add(rel.target.label);
158
+ }
159
+ else if (op instanceof match_1.default) {
160
+ for (const pattern of op.patterns) {
161
+ for (const element of pattern.chain) {
162
+ if (element instanceof node_1.default) {
163
+ for (const lbl of element.labels)
164
+ this._nodeLabels.add(lbl);
165
+ for (const [propKey, expr] of element.properties) {
166
+ this.addNodeProp(element.labels, propKey);
167
+ this.tryAddNodeLiteral(element.labels, propKey, expr);
168
+ }
169
+ }
170
+ else if (element instanceof relationship_1.default) {
171
+ for (const t of element.types)
172
+ this._relTypes.add(t);
173
+ for (const [propKey, expr] of element.properties) {
174
+ this.addRelProp(element.types, propKey);
175
+ this.tryAddRelLiteral(element.types, propKey, expr);
176
+ }
177
+ }
178
+ }
179
+ }
180
+ }
181
+ // CREATE/DELETE VIRTUAL operations describe registry mutations rather
182
+ // than query-side property accesses; their inner ASTs are crawled
183
+ // separately for sources, but we don't surface their property usage.
184
+ if (!(op instanceof create_node_1.default) &&
185
+ !(op instanceof create_relationship_1.default) &&
186
+ !(op instanceof delete_node_1.default) &&
187
+ !(op instanceof delete_relationship_1.default)) {
188
+ this.collectPropertyAccesses(op);
189
+ }
190
+ }
191
+ resolveRegisteredDefinitions() {
192
+ // Sources and declared properties from inline CREATE VIRTUAL clauses
193
+ // in the crawled statements.
194
+ for (const { label, statement } of this._ownNodeCreates) {
195
+ this.collectSources(statement, this.getOrCreate(this._nodeSources, label));
196
+ this.collectSources(statement, this.getOrCreate(this._nodeDeclaredSources, label));
197
+ this.collectDeclaredProps(statement, this.getOrCreate(this._nodeDeclaredProps, label));
198
+ }
199
+ for (const { type, statement } of this._ownRelCreates) {
200
+ this.collectSources(statement, this.getOrCreate(this._relSources, type));
201
+ this.collectSources(statement, this.getOrCreate(this._relDeclaredSources, type));
202
+ this.collectDeclaredProps(statement, this.getOrCreate(this._relDeclaredProps, type));
203
+ }
204
+ // Sources / declared properties from already-registered virtuals
205
+ // that the crawled statements reference (e.g. MATCH/DELETE against
206
+ // a virtual registered earlier).
207
+ const db = database_1.default.getInstance();
208
+ for (const label of this._nodeLabels) {
209
+ if (this._ownCreatedNodeLabels.has(label))
210
+ continue;
211
+ const physical = db.nodes.get(label);
212
+ if (physical === null || physical === void 0 ? void 0 : physical.statement) {
213
+ this.collectSources(physical.statement, this.getOrCreate(this._nodeSources, label));
214
+ this.collectSources(physical.statement, this.getOrCreate(this._nodeDeclaredSources, label));
215
+ this.collectDeclaredProps(physical.statement, this.getOrCreate(this._nodeDeclaredProps, label));
216
+ }
217
+ }
218
+ for (const type of this._relTypes) {
219
+ if (this._ownCreatedRelTypes.has(type))
220
+ continue;
221
+ const typeMap = db.relationships.get(type);
222
+ if (typeMap === undefined)
223
+ continue;
224
+ for (const physical of typeMap.values()) {
225
+ if (physical.statement) {
226
+ this.collectSources(physical.statement, this.getOrCreate(this._relSources, type));
227
+ this.collectSources(physical.statement, this.getOrCreate(this._relDeclaredSources, type));
228
+ this.collectDeclaredProps(physical.statement, this.getOrCreate(this._relDeclaredProps, type));
229
+ }
230
+ }
231
+ }
232
+ }
233
+ getOrCreate(map, key) {
234
+ let set = map.get(key);
235
+ if (set === undefined) {
236
+ set = new Set();
237
+ map.set(key, set);
238
+ }
239
+ return set;
240
+ }
241
+ /**
242
+ * Walks the AST rooted at `root` and records every property access
243
+ * (via `Lookup`) on a known node/relationship binding, every literal
244
+ * value supplied via equality / `IN` predicates, and descends into
245
+ * subqueries plus the privately-held WHERE / ORDER BY ASTs of
246
+ * RETURN-style operations.
247
+ */
248
+ collectPropertyAccesses(root) {
249
+ const visited = new Set();
250
+ const stack = [root];
251
+ while (stack.length > 0) {
252
+ const node = stack.pop();
253
+ if (visited.has(node))
254
+ continue;
255
+ visited.add(node);
256
+ if (node instanceof lookup_1.default) {
257
+ this.handleLookupAccess(node);
258
+ }
259
+ if (node instanceof operator_1.Equals) {
260
+ this.handleEqualityLiteral(node);
261
+ }
262
+ else if (node instanceof operator_1.In) {
263
+ this.handleInLiteral(node);
264
+ }
265
+ for (const child of node.getChildren()) {
266
+ stack.push(child);
267
+ }
268
+ // Subquery expressions hold their inner AST in a private field
269
+ // rather than as a child; descend into it explicitly.
270
+ if (node instanceof subquery_expression_1.default) {
271
+ const inner = node._subqueryAST;
272
+ if (inner !== undefined)
273
+ stack.push(inner);
274
+ }
275
+ // RETURN / AggregatedReturn hold WHERE and ORDER BY clauses in
276
+ // private fields; descend into the ones with expression trees.
277
+ if (node instanceof return_1.default) {
278
+ const w = node._where;
279
+ const o = node._orderBy;
280
+ if (w)
281
+ stack.push(w);
282
+ if (o)
283
+ stack.push(o);
284
+ }
285
+ // OrderBy stores its sort expressions in a private array of
286
+ // SortField objects rather than as AST children; descend
287
+ // explicitly.
288
+ if (node instanceof order_by_1.default) {
289
+ for (const field of node.fields) {
290
+ stack.push(field.expression);
291
+ }
292
+ }
293
+ }
294
+ }
295
+ handleLookupAccess(node) {
296
+ const target = this.resolveLookupTarget(node);
297
+ if (target === null)
298
+ return;
299
+ if (target.kind === "node") {
300
+ this.addNodeProp(target.labels, target.prop);
301
+ }
302
+ else {
303
+ this.addRelProp(target.types, target.prop);
304
+ }
305
+ }
306
+ /**
307
+ * Resolves a `Lookup` of the shape `alias.prop` to the labels/types
308
+ * of the bound entity and the property name. Returns `null` if the
309
+ * lookup isn't of that shape or its variable doesn't resolve to a
310
+ * Node/Relationship.
311
+ */
312
+ resolveLookupTarget(lookup) {
313
+ const variable = lookup.variable;
314
+ const index = lookup.index;
315
+ if (!(variable instanceof reference_1.default) || !(index instanceof identifier_1.default))
316
+ return null;
317
+ const propName = index.value();
318
+ if (typeof propName !== "string" || propName.length === 0)
319
+ return null;
320
+ const referred = variable.referred;
321
+ if (referred instanceof node_1.default) {
322
+ return { kind: "node", labels: referred.labels, prop: propName };
323
+ }
324
+ if (referred instanceof relationship_1.default) {
325
+ return { kind: "rel", types: referred.types, prop: propName };
326
+ }
327
+ return null;
328
+ }
329
+ handleEqualityLiteral(op) {
330
+ const lhs = op.lhs;
331
+ const rhs = op.rhs;
332
+ // Try both orientations: `alias.prop = literal` and `literal = alias.prop`.
333
+ this.tryRecordPropEquality(lhs, rhs);
334
+ this.tryRecordPropEquality(rhs, lhs);
335
+ }
336
+ tryRecordPropEquality(side, other) {
337
+ if (!(side instanceof lookup_1.default))
338
+ return;
339
+ if (!this.isLiteralAst(other))
340
+ return;
341
+ const target = this.resolveLookupTarget(side);
342
+ if (target === null)
343
+ return;
344
+ const value = this.safeEvaluate(other);
345
+ if (value === undefined)
346
+ return;
347
+ if (target.kind === "node") {
348
+ this.addNodeLiteralValue(target.labels, target.prop, value);
349
+ }
350
+ else {
351
+ this.addRelLiteralValue(target.types, target.prop, value);
352
+ }
353
+ }
354
+ handleInLiteral(op) {
355
+ const lhs = op.lhs;
356
+ const rhs = op.rhs;
357
+ if (!(lhs instanceof lookup_1.default))
358
+ return;
359
+ if (!this.isLiteralAst(rhs))
360
+ return;
361
+ const target = this.resolveLookupTarget(lhs);
362
+ if (target === null)
363
+ return;
364
+ const value = this.safeEvaluate(rhs);
365
+ if (!Array.isArray(value))
366
+ return;
367
+ for (const item of value) {
368
+ if (target.kind === "node") {
369
+ this.addNodeLiteralValue(target.labels, target.prop, item);
370
+ }
371
+ else {
372
+ this.addRelLiteralValue(target.types, target.prop, item);
373
+ }
374
+ }
375
+ }
376
+ /**
377
+ * Returns true iff the AST subtree contains only literal nodes (no
378
+ * References, ParameterReferences, Lookups, FStrings, or
379
+ * SubqueryExpressions). Used to guard literal-value extraction
380
+ * against runtime-dependent expressions.
381
+ */
382
+ isLiteralAst(node) {
383
+ if (node instanceof reference_1.default ||
384
+ node instanceof parameter_reference_1.default ||
385
+ node instanceof lookup_1.default ||
386
+ node instanceof f_string_1.default ||
387
+ node instanceof subquery_expression_1.default) {
388
+ return false;
389
+ }
390
+ for (const child of node.getChildren()) {
391
+ if (!this.isLiteralAst(child))
392
+ return false;
393
+ }
394
+ return true;
395
+ }
396
+ safeEvaluate(node) {
397
+ try {
398
+ return node.value();
399
+ }
400
+ catch (_a) {
401
+ return undefined;
402
+ }
403
+ }
404
+ tryAddNodeLiteral(labels, prop, expr) {
405
+ if (!this.isLiteralAst(expr))
406
+ return;
407
+ const value = this.safeEvaluate(expr);
408
+ if (value === undefined)
409
+ return;
410
+ this.addNodeLiteralValue(labels, prop, value);
411
+ }
412
+ tryAddRelLiteral(types, prop, expr) {
413
+ if (!this.isLiteralAst(expr))
414
+ return;
415
+ const value = this.safeEvaluate(expr);
416
+ if (value === undefined)
417
+ return;
418
+ this.addRelLiteralValue(types, prop, value);
419
+ }
420
+ /**
421
+ * Walks a virtual definition's inner statement to find the final
422
+ * RETURN-style projection and records its aliases as the declared
423
+ * property set. Falls back to the last WITH if no RETURN exists.
424
+ */
425
+ collectDeclaredProps(statement, target) {
426
+ let op = null;
427
+ try {
428
+ op = statement.firstChild();
429
+ }
430
+ catch (_a) {
431
+ return;
432
+ }
433
+ let lastReturn = null;
434
+ let lastWith = null;
435
+ while (op !== null) {
436
+ if (op instanceof return_1.default || op instanceof aggregated_return_1.default) {
437
+ lastReturn = op;
438
+ }
439
+ else if (op instanceof with_1.default || op instanceof aggregated_with_1.default) {
440
+ lastWith = op;
441
+ }
442
+ op = op.next;
443
+ }
444
+ const projection = lastReturn !== null && lastReturn !== void 0 ? lastReturn : lastWith;
445
+ if (projection === null)
446
+ return;
447
+ for (const alias of this.projectionAliases(projection)) {
448
+ target.add(alias);
449
+ }
450
+ }
451
+ /**
452
+ * Yields the alias of every projected expression in a Projection.
453
+ * Mirrors the alias-resolution logic of `Projection.expressions()`
454
+ * (which is protected).
455
+ */
456
+ *projectionAliases(projection) {
457
+ var _a;
458
+ const children = projection.getChildren();
459
+ for (let i = 0; i < children.length; i++) {
460
+ const expr = children[i];
461
+ const alias = (_a = expr.alias) !== null && _a !== void 0 ? _a : `expr${i}`;
462
+ if (typeof alias === "string" && alias.length > 0) {
463
+ yield alias;
464
+ }
465
+ }
466
+ }
467
+ collectSources(statement, target) {
468
+ var _a;
469
+ let op = null;
470
+ try {
471
+ op = statement.firstChild();
472
+ }
473
+ catch (_b) {
474
+ return;
475
+ }
476
+ while (op !== null) {
477
+ if (op instanceof load_1.default) {
478
+ if (op.isAsyncFunction) {
479
+ const name = (_a = op.asyncFunction) === null || _a === void 0 ? void 0 : _a.name;
480
+ if (typeof name === "string" && name.length > 0)
481
+ target.add(name);
482
+ }
483
+ else {
484
+ try {
485
+ const from = op.from;
486
+ if (typeof from === "string" && from.length > 0)
487
+ target.add(from);
488
+ }
489
+ catch (_c) {
490
+ // Dynamic source (e.g. f-string with unresolved refs);
491
+ // skip rather than fail metadata extraction.
492
+ }
493
+ }
494
+ }
495
+ op = op.next;
496
+ }
497
+ }
498
+ addNodeProp(labels, prop) {
499
+ for (const label of labels) {
500
+ if (!label)
501
+ continue;
502
+ let set = this._nodeProps.get(label);
503
+ if (set === undefined) {
504
+ set = new Set();
505
+ this._nodeProps.set(label, set);
506
+ }
507
+ set.add(prop);
508
+ }
509
+ }
510
+ addRelProp(types, prop) {
511
+ for (const type of types) {
512
+ if (!type)
513
+ continue;
514
+ let set = this._relProps.get(type);
515
+ if (set === undefined) {
516
+ set = new Set();
517
+ this._relProps.set(type, set);
518
+ }
519
+ set.add(prop);
520
+ }
521
+ }
522
+ addNodeLiteralValue(labels, prop, value) {
523
+ for (const label of labels) {
524
+ if (!label)
525
+ continue;
526
+ let propMap = this._nodeLiterals.get(label);
527
+ if (propMap === undefined) {
528
+ propMap = new Map();
529
+ this._nodeLiterals.set(label, propMap);
530
+ }
531
+ this.appendUniqueLiteral(propMap, prop, value);
532
+ }
533
+ }
534
+ addRelLiteralValue(types, prop, value) {
535
+ for (const type of types) {
536
+ if (!type)
537
+ continue;
538
+ let propMap = this._relLiterals.get(type);
539
+ if (propMap === undefined) {
540
+ propMap = new Map();
541
+ this._relLiterals.set(type, propMap);
542
+ }
543
+ this.appendUniqueLiteral(propMap, prop, value);
544
+ }
545
+ }
546
+ appendUniqueLiteral(propMap, prop, value) {
547
+ let arr = propMap.get(prop);
548
+ if (arr === undefined) {
549
+ arr = [];
550
+ propMap.set(prop, arr);
551
+ }
552
+ for (const existing of arr) {
553
+ if (this.literalsEqual(existing, value))
554
+ return;
555
+ }
556
+ arr.push(value);
557
+ }
558
+ literalsEqual(a, b) {
559
+ if (a === b)
560
+ return true;
561
+ if (a === null || b === null || a === undefined || b === undefined)
562
+ return false;
563
+ if (typeof a !== typeof b)
564
+ return false;
565
+ if (typeof a !== "object")
566
+ return false;
567
+ if (Array.isArray(a) !== Array.isArray(b))
568
+ return false;
569
+ if (Array.isArray(a)) {
570
+ if (a.length !== b.length)
571
+ return false;
572
+ for (let i = 0; i < a.length; i++) {
573
+ if (!this.literalsEqual(a[i], b[i]))
574
+ return false;
575
+ }
576
+ return true;
577
+ }
578
+ const ka = Object.keys(a);
579
+ const kb = Object.keys(b);
580
+ if (ka.length !== kb.length)
581
+ return false;
582
+ for (const k of ka) {
583
+ if (!Object.prototype.hasOwnProperty.call(b, k))
584
+ return false;
585
+ if (!this.literalsEqual(a[k], b[k]))
586
+ return false;
587
+ }
588
+ return true;
589
+ }
590
+ literalsSnapshot(map, key) {
591
+ const propMap = map.get(key);
592
+ if (propMap === undefined || propMap.size === 0)
593
+ return {};
594
+ const out = {};
595
+ const sortedKeys = Array.from(propMap.keys()).sort();
596
+ for (const propKey of sortedKeys) {
597
+ out[propKey] = [...propMap.get(propKey)];
598
+ }
599
+ return out;
600
+ }
601
+ snapshot() {
602
+ const allSources = new Set();
603
+ const nodes = {};
604
+ for (const label of this._nodeLabels) {
605
+ const props = this._nodeProps.get(label);
606
+ const sources = this._nodeSources.get(label);
607
+ if (sources !== undefined) {
608
+ for (const s of sources)
609
+ allSources.add(s);
610
+ }
611
+ nodes[label] = {
612
+ properties: props ? Array.from(props).sort() : [],
613
+ sources: sources ? Array.from(sources).sort() : [],
614
+ literal_values: this.literalsSnapshot(this._nodeLiterals, label),
615
+ };
616
+ }
617
+ const relationships = {};
618
+ for (const type of this._relTypes) {
619
+ const props = this._relProps.get(type);
620
+ const sources = this._relSources.get(type);
621
+ if (sources !== undefined) {
622
+ for (const s of sources)
623
+ allSources.add(s);
624
+ }
625
+ relationships[type] = {
626
+ properties: props ? Array.from(props).sort() : [],
627
+ sources: sources ? Array.from(sources).sort() : [],
628
+ literal_values: this.literalsSnapshot(this._relLiterals, type),
629
+ };
630
+ }
631
+ const declaredNodes = {};
632
+ for (const label of this._nodeLabels) {
633
+ const props = this._nodeDeclaredProps.get(label);
634
+ const sources = this._nodeDeclaredSources.get(label);
635
+ if ((props && props.size > 0) || (sources && sources.size > 0)) {
636
+ declaredNodes[label] = {
637
+ properties: props ? Array.from(props).sort() : [],
638
+ sources: sources ? Array.from(sources).sort() : [],
639
+ };
640
+ }
641
+ }
642
+ const declaredRelationships = {};
643
+ for (const type of this._relTypes) {
644
+ const props = this._relDeclaredProps.get(type);
645
+ const sources = this._relDeclaredSources.get(type);
646
+ if ((props && props.size > 0) || (sources && sources.size > 0)) {
647
+ declaredRelationships[type] = {
648
+ properties: props ? Array.from(props).sort() : [],
649
+ sources: sources ? Array.from(sources).sort() : [],
650
+ };
651
+ }
652
+ }
653
+ const info = {
654
+ node_labels: Array.from(this._nodeLabels).sort(),
655
+ relationship_types: Array.from(this._relTypes).sort(),
656
+ sources: Array.from(allSources).sort(),
657
+ node_properties: {},
658
+ relationship_properties: {},
659
+ nodes,
660
+ relationships,
661
+ declared: {
662
+ nodes: declaredNodes,
663
+ relationships: declaredRelationships,
664
+ },
665
+ };
666
+ for (const [label, props] of this._nodeProps) {
667
+ info.node_properties[label] = Array.from(props).sort();
668
+ }
669
+ for (const [type, props] of this._relProps) {
670
+ info.relationship_properties[type] = Array.from(props).sort();
671
+ }
672
+ return info;
673
+ }
674
+ /**
675
+ * Returns a deep copy of a StatementInfo so callers can mutate it freely.
676
+ */
677
+ static clone(info) {
678
+ var _a, _b, _c, _d;
679
+ const cloneProps = (props) => {
680
+ const out = {};
681
+ for (const [k, v] of Object.entries(props))
682
+ out[k] = [...v];
683
+ return out;
684
+ };
685
+ const cloneLiterals = (literals) => {
686
+ const out = {};
687
+ for (const [k, v] of Object.entries(literals)) {
688
+ out[k] = v.map((item) => typeof item === "object" && item !== null ? structuredClone(item) : item);
689
+ }
690
+ return out;
691
+ };
692
+ const cloneEntities = (entities) => {
693
+ var _a;
694
+ const out = {};
695
+ for (const [k, v] of Object.entries(entities)) {
696
+ out[k] = {
697
+ properties: [...v.properties],
698
+ sources: [...v.sources],
699
+ literal_values: cloneLiterals((_a = v.literal_values) !== null && _a !== void 0 ? _a : {}),
700
+ };
701
+ }
702
+ return out;
703
+ };
704
+ const cloneDeclared = (entities) => {
705
+ const out = {};
706
+ for (const [k, v] of Object.entries(entities)) {
707
+ out[k] = {
708
+ properties: [...v.properties],
709
+ sources: [...v.sources],
710
+ };
711
+ }
712
+ return out;
713
+ };
714
+ return {
715
+ node_labels: [...info.node_labels],
716
+ relationship_types: [...info.relationship_types],
717
+ sources: [...info.sources],
718
+ node_properties: cloneProps(info.node_properties),
719
+ relationship_properties: cloneProps(info.relationship_properties),
720
+ nodes: cloneEntities(info.nodes),
721
+ relationships: cloneEntities(info.relationships),
722
+ declared: {
723
+ nodes: cloneDeclared((_b = (_a = info.declared) === null || _a === void 0 ? void 0 : _a.nodes) !== null && _b !== void 0 ? _b : {}),
724
+ relationships: cloneDeclared((_d = (_c = info.declared) === null || _c === void 0 ? void 0 : _c.relationships) !== null && _d !== void 0 ? _d : {}),
725
+ },
726
+ };
727
+ }
728
+ }
729
+ exports.default = StatementInfoCrawler;
730
+ //# sourceMappingURL=statement_info_crawler.js.map