Section 4.2Source:
server/src/analytics/traversal/GraphTraversal.tsGraph Traversal Primitive
The core Breadth-First Search (BFS) engine powering multi-hop reachability, shortest distance calculations, and bidirectional edge exploration.
Source:
server/src/analytics/traversal/GraphTraversal.tsIterative BFS with Queue Pointer Optimization
Standard JavaScript Array.shift() runs in $O(N)$ time because it shifts all elements in memory. GraphTraversal maintains an integer pointer (queueIndex++) to achieve true $O(1)$ dequeue performance across thousands of graph nodes:
server/src/analytics/traversal/GraphTraversal.ts
1234567891011121314151617181920212223242526272829303132333435363738394041export class GraphTraversal { traverse(startNodeId: string, options: TraversalOptions): TraversalResult { const visited = new Set<string>([startNodeId]); const queue: TraversalQueueItem[] = [{ nodeId: startNodeId, depth: 0 }]; const nodes: string[] = []; const depthByNode = new Map<string, number>(); let queueIndex = 0; while (queueIndex < queue.length) { const current = queue[queueIndex++]; // Depth cutoff guard if (options.maxDepth !== undefined && current.depth >= options.maxDepth) continue; const edgeIds = options.direction === "outgoing" ? this.graph.outgoingEdges.get(current.nodeId) : this.graph.incomingEdges.get(current.nodeId); for (const edgeId of edgeIds || []) { const edge = this.graph.edges.get(edgeId); if (!edge) continue; // Relationship filter if (options.relationshipKinds && !options.relationshipKinds.includes(edge.relationshipKind)) { continue; } const nextNodeId = options.direction === "outgoing" ? edge.targetId : edge.sourceId; if (!visited.has(nextNodeId)) { visited.add(nextNodeId); nodes.push(nextNodeId); depthByNode.set(nextNodeId, current.depth + 1); queue.push({ nodeId: nextNodeId, depth: current.depth + 1 }); } } } return { startNodeId, nodes, depthByNode }; } }
Start Node Exclusion
nodes: string[] explicitly excludes startNodeId itself, ensuring downstream analyzers only report affected or depended-upon nodes rather than the query root.