dbgraph 0.1.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/LICENSE +21 -0
- package/README.md +347 -0
- package/dist/bin/dbgraph.d.ts +8 -0
- package/dist/bin/dbgraph.d.ts.map +1 -0
- package/dist/bin/dbgraph.js +382 -0
- package/dist/bin/dbgraph.js.map +1 -0
- package/dist/config.d.ts +25 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +158 -0
- package/dist/config.js.map +1 -0
- package/dist/context/formatter.d.ts +94 -0
- package/dist/context/formatter.d.ts.map +1 -0
- package/dist/context/formatter.js +288 -0
- package/dist/context/formatter.js.map +1 -0
- package/dist/context/index.d.ts +77 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +458 -0
- package/dist/context/index.js.map +1 -0
- package/dist/db/index.d.ts +26 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +127 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/migrations.d.ts +8 -0
- package/dist/db/migrations.d.ts.map +1 -0
- package/dist/db/migrations.js +39 -0
- package/dist/db/migrations.js.map +1 -0
- package/dist/db/queries.d.ts +46 -0
- package/dist/db/queries.d.ts.map +1 -0
- package/dist/db/queries.js +436 -0
- package/dist/db/queries.js.map +1 -0
- package/dist/db/schema.sql +113 -0
- package/dist/db/sqlite-adapter.d.ts +30 -0
- package/dist/db/sqlite-adapter.d.ts.map +1 -0
- package/dist/db/sqlite-adapter.js +78 -0
- package/dist/db/sqlite-adapter.js.map +1 -0
- package/dist/directory.d.ts +37 -0
- package/dist/directory.d.ts.map +1 -0
- package/dist/directory.js +160 -0
- package/dist/directory.js.map +1 -0
- package/dist/errors.d.ts +46 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +90 -0
- package/dist/errors.js.map +1 -0
- package/dist/graph/traversal.d.ts +157 -0
- package/dist/graph/traversal.d.ts.map +1 -0
- package/dist/graph/traversal.js +531 -0
- package/dist/graph/traversal.js.map +1 -0
- package/dist/index.d.ts +183 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +435 -0
- package/dist/index.js.map +1 -0
- package/dist/introspect/base.d.ts +62 -0
- package/dist/introspect/base.d.ts.map +1 -0
- package/dist/introspect/base.js +107 -0
- package/dist/introspect/base.js.map +1 -0
- package/dist/introspect/connection.d.ts +30 -0
- package/dist/introspect/connection.d.ts.map +1 -0
- package/dist/introspect/connection.js +232 -0
- package/dist/introspect/connection.js.map +1 -0
- package/dist/introspect/index.d.ts +23 -0
- package/dist/introspect/index.d.ts.map +1 -0
- package/dist/introspect/index.js +46 -0
- package/dist/introspect/index.js.map +1 -0
- package/dist/introspect/mysql.d.ts +64 -0
- package/dist/introspect/mysql.d.ts.map +1 -0
- package/dist/introspect/mysql.js +360 -0
- package/dist/introspect/mysql.js.map +1 -0
- package/dist/introspect/postgres.d.ts +55 -0
- package/dist/introspect/postgres.d.ts.map +1 -0
- package/dist/introspect/postgres.js +372 -0
- package/dist/introspect/postgres.js.map +1 -0
- package/dist/introspect/sqlite.d.ts +33 -0
- package/dist/introspect/sqlite.d.ts.map +1 -0
- package/dist/introspect/sqlite.js +207 -0
- package/dist/introspect/sqlite.js.map +1 -0
- package/dist/mcp/engine.d.ts +92 -0
- package/dist/mcp/engine.d.ts.map +1 -0
- package/dist/mcp/engine.js +261 -0
- package/dist/mcp/engine.js.map +1 -0
- package/dist/mcp/index.d.ts +33 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +119 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server-instructions.d.ts +9 -0
- package/dist/mcp/server-instructions.d.ts.map +1 -0
- package/dist/mcp/server-instructions.js +71 -0
- package/dist/mcp/server-instructions.js.map +1 -0
- package/dist/mcp/session.d.ts +35 -0
- package/dist/mcp/session.d.ts.map +1 -0
- package/dist/mcp/session.js +140 -0
- package/dist/mcp/session.js.map +1 -0
- package/dist/mcp/tools.d.ts +99 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +499 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/mcp/transport.d.ts +78 -0
- package/dist/mcp/transport.d.ts.map +1 -0
- package/dist/mcp/transport.js +182 -0
- package/dist/mcp/transport.js.map +1 -0
- package/dist/search/query-parser.d.ts +66 -0
- package/dist/search/query-parser.d.ts.map +1 -0
- package/dist/search/query-parser.js +163 -0
- package/dist/search/query-parser.js.map +1 -0
- package/dist/search/query-utils.d.ts +78 -0
- package/dist/search/query-utils.d.ts.map +1 -0
- package/dist/search/query-utils.js +203 -0
- package/dist/search/query-utils.js.map +1 -0
- package/dist/types.d.ts +279 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +47 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +40 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +190 -0
- package/dist/utils.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Graph Traversal Algorithms
|
|
4
|
+
*
|
|
5
|
+
* BFS and DFS traversal for the database schema knowledge graph.
|
|
6
|
+
* Operates on nodes/edges stored in SQLite via QueryBuilder.
|
|
7
|
+
*
|
|
8
|
+
* All traversal methods use batch node lookups (getNodesByIds) to avoid
|
|
9
|
+
* N+1 query patterns and maintain performance on large schemas.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.GraphTraverser = void 0;
|
|
13
|
+
/**
|
|
14
|
+
* Default traversal options
|
|
15
|
+
*/
|
|
16
|
+
const DEFAULT_OPTIONS = {
|
|
17
|
+
maxDepth: Infinity,
|
|
18
|
+
edgeKinds: [],
|
|
19
|
+
nodeKinds: [],
|
|
20
|
+
direction: 'outgoing',
|
|
21
|
+
limit: 1000,
|
|
22
|
+
includeStart: true,
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Graph traverser for BFS and DFS traversal of the database schema graph.
|
|
26
|
+
*
|
|
27
|
+
* Provides methods to navigate the graph structure — containment hierarchies,
|
|
28
|
+
* foreign-key references, and impact analysis — all with batched queries.
|
|
29
|
+
*/
|
|
30
|
+
class GraphTraverser {
|
|
31
|
+
queries;
|
|
32
|
+
constructor(queries) {
|
|
33
|
+
this.queries = queries;
|
|
34
|
+
}
|
|
35
|
+
// ===========================================================================
|
|
36
|
+
// Core Traversal
|
|
37
|
+
// ===========================================================================
|
|
38
|
+
/**
|
|
39
|
+
* Traverse the graph using breadth-first search.
|
|
40
|
+
*
|
|
41
|
+
* Structural edges (`contains`) are visited before reference edges so that
|
|
42
|
+
* BFS discovers internal structure first before fanning out.
|
|
43
|
+
*
|
|
44
|
+
* @param startId - Starting node ID
|
|
45
|
+
* @param options - Traversal options
|
|
46
|
+
* @returns Subgraph containing traversed nodes and edges
|
|
47
|
+
*/
|
|
48
|
+
traverseBFS(startId, options = {}) {
|
|
49
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
50
|
+
const startNode = this.queries.getNodeById(startId);
|
|
51
|
+
if (!startNode) {
|
|
52
|
+
return { nodes: new Map(), edges: [], roots: [] };
|
|
53
|
+
}
|
|
54
|
+
const nodes = new Map();
|
|
55
|
+
const edges = [];
|
|
56
|
+
const visited = new Set();
|
|
57
|
+
const queue = [{ node: startNode, edge: null, depth: 0 }];
|
|
58
|
+
if (opts.includeStart) {
|
|
59
|
+
nodes.set(startNode.id, startNode);
|
|
60
|
+
}
|
|
61
|
+
while (queue.length > 0 && nodes.size < opts.limit) {
|
|
62
|
+
const step = queue.shift();
|
|
63
|
+
const { node, edge, depth } = step;
|
|
64
|
+
if (visited.has(node.id)) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
visited.add(node.id);
|
|
68
|
+
// Add edge to result
|
|
69
|
+
if (edge) {
|
|
70
|
+
edges.push(edge);
|
|
71
|
+
}
|
|
72
|
+
// Check depth limit
|
|
73
|
+
if (depth >= opts.maxDepth) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
// Get adjacent edges, prioritizing containment edges
|
|
77
|
+
const adjacentEdges = this.getAdjacentEdges(node.id, opts.direction, opts.edgeKinds);
|
|
78
|
+
adjacentEdges.sort((a, b) => {
|
|
79
|
+
const priority = (e) => e.kind === 'contains' ? 0 : 1;
|
|
80
|
+
return priority(a) - priority(b);
|
|
81
|
+
});
|
|
82
|
+
// Batch-fetch the unvisited neighbors in one query
|
|
83
|
+
const wantIds = adjacentEdges
|
|
84
|
+
.map((e) => (e.source === node.id ? e.target : e.source))
|
|
85
|
+
.filter((id) => !visited.has(id));
|
|
86
|
+
const neighborNodes = wantIds.length > 0 ? this.queries.getNodesByIds(wantIds) : new Map();
|
|
87
|
+
for (const adjEdge of adjacentEdges) {
|
|
88
|
+
const nextNodeId = adjEdge.source === node.id ? adjEdge.target : adjEdge.source;
|
|
89
|
+
if (visited.has(nextNodeId))
|
|
90
|
+
continue;
|
|
91
|
+
const nextNode = neighborNodes.get(nextNodeId);
|
|
92
|
+
if (!nextNode)
|
|
93
|
+
continue;
|
|
94
|
+
if (opts.nodeKinds && opts.nodeKinds.length > 0 && !opts.nodeKinds.includes(nextNode.kind)) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
nodes.set(nextNode.id, nextNode);
|
|
98
|
+
queue.push({ node: nextNode, edge: adjEdge, depth: depth + 1 });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
nodes,
|
|
103
|
+
edges,
|
|
104
|
+
roots: [startId],
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Traverse the graph using depth-first search.
|
|
109
|
+
*
|
|
110
|
+
* @param startId - Starting node ID
|
|
111
|
+
* @param options - Traversal options
|
|
112
|
+
* @returns Subgraph containing traversed nodes and edges
|
|
113
|
+
*/
|
|
114
|
+
traverseDFS(startId, options = {}) {
|
|
115
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
116
|
+
const startNode = this.queries.getNodeById(startId);
|
|
117
|
+
if (!startNode) {
|
|
118
|
+
return { nodes: new Map(), edges: [], roots: [] };
|
|
119
|
+
}
|
|
120
|
+
const nodes = new Map();
|
|
121
|
+
const edges = [];
|
|
122
|
+
const visited = new Set();
|
|
123
|
+
if (opts.includeStart) {
|
|
124
|
+
nodes.set(startNode.id, startNode);
|
|
125
|
+
}
|
|
126
|
+
this.dfsRecursive(startNode, 0, opts, nodes, edges, visited);
|
|
127
|
+
return {
|
|
128
|
+
nodes,
|
|
129
|
+
edges,
|
|
130
|
+
roots: [startId],
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Recursive DFS helper with batch neighbor fetching.
|
|
135
|
+
*/
|
|
136
|
+
dfsRecursive(node, depth, opts, nodes, edges, visited) {
|
|
137
|
+
if (visited.has(node.id) || nodes.size >= opts.limit || depth >= opts.maxDepth) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
visited.add(node.id);
|
|
141
|
+
// Get adjacent edges
|
|
142
|
+
const adjacentEdges = this.getAdjacentEdges(node.id, opts.direction, opts.edgeKinds);
|
|
143
|
+
// Batch-fetch unvisited neighbors
|
|
144
|
+
const wantIds = adjacentEdges
|
|
145
|
+
.map((e) => (e.source === node.id ? e.target : e.source))
|
|
146
|
+
.filter((id) => !visited.has(id));
|
|
147
|
+
const neighborNodes = wantIds.length > 0 ? this.queries.getNodesByIds(wantIds) : new Map();
|
|
148
|
+
for (const adjEdge of adjacentEdges) {
|
|
149
|
+
const nextNodeId = adjEdge.source === node.id ? adjEdge.target : adjEdge.source;
|
|
150
|
+
if (visited.has(nextNodeId))
|
|
151
|
+
continue;
|
|
152
|
+
const nextNode = neighborNodes.get(nextNodeId);
|
|
153
|
+
if (!nextNode)
|
|
154
|
+
continue;
|
|
155
|
+
// Apply node kind filter
|
|
156
|
+
if (opts.nodeKinds && opts.nodeKinds.length > 0 && !opts.nodeKinds.includes(nextNode.kind)) {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
nodes.set(nextNode.id, nextNode);
|
|
160
|
+
edges.push(adjEdge);
|
|
161
|
+
this.dfsRecursive(nextNode, depth + 1, opts, nodes, edges, visited);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Get adjacent edges based on direction.
|
|
166
|
+
*/
|
|
167
|
+
getAdjacentEdges(nodeId, direction, edgeKinds) {
|
|
168
|
+
const kinds = edgeKinds && edgeKinds.length > 0 ? edgeKinds : undefined;
|
|
169
|
+
if (direction === 'outgoing') {
|
|
170
|
+
return this.queries.getOutgoingEdges(nodeId, kinds);
|
|
171
|
+
}
|
|
172
|
+
else if (direction === 'incoming') {
|
|
173
|
+
return this.queries.getIncomingEdges(nodeId, kinds);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
const outgoing = this.queries.getOutgoingEdges(nodeId, kinds);
|
|
177
|
+
const incoming = this.queries.getIncomingEdges(nodeId, kinds);
|
|
178
|
+
return [...outgoing, ...incoming];
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// ===========================================================================
|
|
182
|
+
// Reference Analysis
|
|
183
|
+
// ===========================================================================
|
|
184
|
+
/**
|
|
185
|
+
* Find all nodes that reference a given node (e.g., tables with foreign keys
|
|
186
|
+
* pointing to this table, or views referencing this table).
|
|
187
|
+
*
|
|
188
|
+
* Follows `references` edges incoming to the target.
|
|
189
|
+
*
|
|
190
|
+
* @param nodeId - ID of the node being referenced
|
|
191
|
+
* @param maxDepth - Maximum depth to traverse (default: 1)
|
|
192
|
+
* @returns Array of { caller node, edge } pairs
|
|
193
|
+
*/
|
|
194
|
+
getCallers(nodeId, maxDepth = 1) {
|
|
195
|
+
const result = [];
|
|
196
|
+
const visited = new Set();
|
|
197
|
+
this.getCallersRecursive(nodeId, maxDepth, 0, result, visited);
|
|
198
|
+
return result;
|
|
199
|
+
}
|
|
200
|
+
getCallersRecursive(nodeId, maxDepth, currentDepth, result, visited) {
|
|
201
|
+
if (currentDepth >= maxDepth || visited.has(nodeId)) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
visited.add(nodeId);
|
|
205
|
+
const incomingEdges = this.queries.getIncomingEdges(nodeId, ['references', 'foreign_key', 'depends_on', 'imports']);
|
|
206
|
+
if (incomingEdges.length === 0)
|
|
207
|
+
return;
|
|
208
|
+
// Batch-fetch all source nodes in one round-trip
|
|
209
|
+
const sourceIds = incomingEdges.map((e) => e.source);
|
|
210
|
+
const callerNodes = this.queries.getNodesByIds(sourceIds);
|
|
211
|
+
for (const edge of incomingEdges) {
|
|
212
|
+
const callerNode = callerNodes.get(edge.source);
|
|
213
|
+
if (callerNode && !visited.has(callerNode.id)) {
|
|
214
|
+
result.push({ node: callerNode, edge });
|
|
215
|
+
this.getCallersRecursive(callerNode.id, maxDepth, currentDepth + 1, result, visited);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Find all nodes referenced by a given node (e.g., tables this foreign key
|
|
221
|
+
* points to, tables this view depends on).
|
|
222
|
+
*
|
|
223
|
+
* Follows `references` edges outgoing from the source.
|
|
224
|
+
*
|
|
225
|
+
* @param nodeId - ID of the source node
|
|
226
|
+
* @param maxDepth - Maximum depth to traverse (default: 1)
|
|
227
|
+
* @returns Array of { callee node, edge } pairs
|
|
228
|
+
*/
|
|
229
|
+
getCallees(nodeId, maxDepth = 1) {
|
|
230
|
+
const result = [];
|
|
231
|
+
const visited = new Set();
|
|
232
|
+
this.getCalleesRecursive(nodeId, maxDepth, 0, result, visited);
|
|
233
|
+
return result;
|
|
234
|
+
}
|
|
235
|
+
getCalleesRecursive(nodeId, maxDepth, currentDepth, result, visited) {
|
|
236
|
+
if (currentDepth >= maxDepth || visited.has(nodeId)) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
visited.add(nodeId);
|
|
240
|
+
const outgoingEdges = this.queries.getOutgoingEdges(nodeId, ['references', 'foreign_key', 'depends_on', 'imports']);
|
|
241
|
+
if (outgoingEdges.length === 0)
|
|
242
|
+
return;
|
|
243
|
+
// Batch-fetch all target nodes
|
|
244
|
+
const targetIds = outgoingEdges.map((e) => e.target);
|
|
245
|
+
const calleeNodes = this.queries.getNodesByIds(targetIds);
|
|
246
|
+
for (const edge of outgoingEdges) {
|
|
247
|
+
const calleeNode = calleeNodes.get(edge.target);
|
|
248
|
+
if (calleeNode && !visited.has(calleeNode.id)) {
|
|
249
|
+
result.push({ node: calleeNode, edge });
|
|
250
|
+
this.getCalleesRecursive(calleeNode.id, maxDepth, currentDepth + 1, result, visited);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// ===========================================================================
|
|
255
|
+
// Usage & Impact
|
|
256
|
+
// ===========================================================================
|
|
257
|
+
/**
|
|
258
|
+
* Find all usages of a node — all incoming edges regardless of kind.
|
|
259
|
+
*
|
|
260
|
+
* This returns every node that has any edge pointing to the given node,
|
|
261
|
+
* including foreign key references, dependencies, and structural containment.
|
|
262
|
+
*
|
|
263
|
+
* @param nodeId - ID of the node being examined
|
|
264
|
+
* @returns Array of { using node, edge } pairs
|
|
265
|
+
*/
|
|
266
|
+
findUsages(nodeId) {
|
|
267
|
+
const result = [];
|
|
268
|
+
const incomingEdges = this.queries.getIncomingEdges(nodeId);
|
|
269
|
+
if (incomingEdges.length === 0)
|
|
270
|
+
return result;
|
|
271
|
+
// Batch-fetch all source nodes
|
|
272
|
+
const sources = this.queries.getNodesByIds(incomingEdges.map((e) => e.source));
|
|
273
|
+
for (const edge of incomingEdges) {
|
|
274
|
+
const sourceNode = sources.get(edge.source);
|
|
275
|
+
if (sourceNode)
|
|
276
|
+
result.push({ node: sourceNode, edge });
|
|
277
|
+
}
|
|
278
|
+
return result;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Compute the impact radius of a node — all nodes that could be affected
|
|
282
|
+
* if this schema object changes.
|
|
283
|
+
*
|
|
284
|
+
* Traverses incoming edges (dependents), including following `contains`
|
|
285
|
+
* edges into container children (e.g., a column change impacts the table's
|
|
286
|
+
* foreign-key dependents).
|
|
287
|
+
*
|
|
288
|
+
* @param nodeId - ID of the node being changed
|
|
289
|
+
* @param maxDepth - Maximum depth to traverse (default: 3)
|
|
290
|
+
* @returns Subgraph containing potentially impacted nodes
|
|
291
|
+
*/
|
|
292
|
+
getImpactRadius(nodeId, maxDepth = 3) {
|
|
293
|
+
const focalNode = this.queries.getNodeById(nodeId);
|
|
294
|
+
if (!focalNode) {
|
|
295
|
+
return { nodes: new Map(), edges: [], roots: [] };
|
|
296
|
+
}
|
|
297
|
+
const nodes = new Map();
|
|
298
|
+
const edges = [];
|
|
299
|
+
const visited = new Set();
|
|
300
|
+
nodes.set(focalNode.id, focalNode);
|
|
301
|
+
this.getImpactRecursive(nodeId, maxDepth, 0, nodes, edges, visited);
|
|
302
|
+
return {
|
|
303
|
+
nodes,
|
|
304
|
+
edges,
|
|
305
|
+
roots: [nodeId],
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Recursive impact traversal — follows incoming edges and also descends
|
|
310
|
+
* into container children (e.g., table → columns → FK references).
|
|
311
|
+
*/
|
|
312
|
+
getImpactRecursive(nodeId, maxDepth, currentDepth, nodes, edges, visited) {
|
|
313
|
+
if (currentDepth >= maxDepth || visited.has(nodeId)) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
visited.add(nodeId);
|
|
317
|
+
// For container nodes (tables, views, schemas), also traverse into their
|
|
318
|
+
// children so that dependents of contained members are discovered
|
|
319
|
+
const focalNode = this.queries.getNodeById(nodeId);
|
|
320
|
+
if (focalNode) {
|
|
321
|
+
const containerKinds = new Set(['table', 'view', 'schema', 'database']);
|
|
322
|
+
if (containerKinds.has(focalNode.kind)) {
|
|
323
|
+
const containsEdges = this.queries.getOutgoingEdges(nodeId, ['contains']);
|
|
324
|
+
if (containsEdges.length > 0) {
|
|
325
|
+
const children = this.queries.getNodesByIds(containsEdges.map((e) => e.target));
|
|
326
|
+
for (const edge of containsEdges) {
|
|
327
|
+
const childNode = children.get(edge.target);
|
|
328
|
+
if (childNode && !visited.has(childNode.id)) {
|
|
329
|
+
nodes.set(childNode.id, childNode);
|
|
330
|
+
edges.push(edge);
|
|
331
|
+
// Recurse into children at the same depth
|
|
332
|
+
this.getImpactRecursive(childNode.id, maxDepth, currentDepth, nodes, edges, visited);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
// Get all incoming edges (things that depend on this node)
|
|
339
|
+
const incomingEdges = this.queries.getIncomingEdges(nodeId);
|
|
340
|
+
if (incomingEdges.length === 0)
|
|
341
|
+
return;
|
|
342
|
+
const sources = this.queries.getNodesByIds(incomingEdges.map((e) => e.source));
|
|
343
|
+
for (const edge of incomingEdges) {
|
|
344
|
+
const sourceNode = sources.get(edge.source);
|
|
345
|
+
if (sourceNode && !nodes.has(sourceNode.id)) {
|
|
346
|
+
nodes.set(sourceNode.id, sourceNode);
|
|
347
|
+
edges.push(edge);
|
|
348
|
+
this.getImpactRecursive(sourceNode.id, maxDepth, currentDepth + 1, nodes, edges, visited);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
// ===========================================================================
|
|
353
|
+
// Path Finding
|
|
354
|
+
// ===========================================================================
|
|
355
|
+
/**
|
|
356
|
+
* Find the shortest path between two nodes using bidirectional BFS.
|
|
357
|
+
*
|
|
358
|
+
* Each step follows outgoing edges from the direction being expanded.
|
|
359
|
+
* Returns the path as an ordered array of { node, edge } steps, where
|
|
360
|
+
* the first entry's `edge` is null (the start node has no incoming edge).
|
|
361
|
+
*
|
|
362
|
+
* @param fromId - Starting node ID
|
|
363
|
+
* @param toId - Target node ID
|
|
364
|
+
* @param edgeKinds - Edge types to consider (all if empty array)
|
|
365
|
+
* @returns Ordered path, or null if no path exists
|
|
366
|
+
*/
|
|
367
|
+
findPath(fromId, toId, edgeKinds = []) {
|
|
368
|
+
const fromNode = this.queries.getNodeById(fromId);
|
|
369
|
+
const toNode = this.queries.getNodeById(toId);
|
|
370
|
+
if (!fromNode || !toNode) {
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
// Short-circuit: same node
|
|
374
|
+
if (fromId === toId) {
|
|
375
|
+
return [{ node: fromNode, edge: null }];
|
|
376
|
+
}
|
|
377
|
+
// Bidirectional BFS
|
|
378
|
+
const kinds = edgeKinds.length > 0 ? edgeKinds : undefined;
|
|
379
|
+
const forwardVisited = new Map();
|
|
380
|
+
const backwardVisited = new Map();
|
|
381
|
+
forwardVisited.set(fromId, [{ node: fromNode, edge: null }]);
|
|
382
|
+
backwardVisited.set(toId, [{ node: toNode, edge: null }]);
|
|
383
|
+
const forwardQueue = [fromId];
|
|
384
|
+
const backwardQueue = [toId];
|
|
385
|
+
while (forwardQueue.length > 0 && backwardQueue.length > 0) {
|
|
386
|
+
// Expand forward frontier
|
|
387
|
+
const meetPoint = this.expandPathFrontier(forwardQueue, forwardVisited, backwardVisited, 'outgoing', kinds);
|
|
388
|
+
if (meetPoint !== null) {
|
|
389
|
+
return this.mergePaths(forwardVisited, backwardVisited, meetPoint);
|
|
390
|
+
}
|
|
391
|
+
// Expand backward frontier
|
|
392
|
+
const meetPoint2 = this.expandPathFrontier(backwardQueue, backwardVisited, forwardVisited, 'incoming', kinds);
|
|
393
|
+
if (meetPoint2 !== null) {
|
|
394
|
+
return this.mergePaths(backwardVisited, forwardVisited, meetPoint2);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return null; // No path found
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Expand one frontier of the bidirectional BFS by one layer.
|
|
401
|
+
*
|
|
402
|
+
* Returns the meeting node ID if frontiers intersect, or null otherwise.
|
|
403
|
+
*/
|
|
404
|
+
expandPathFrontier(queue, currentVisited, otherVisited, direction, edgeKinds) {
|
|
405
|
+
const batch = [];
|
|
406
|
+
// Drain current queue into a batch so new pushes don't re-process
|
|
407
|
+
while (queue.length > 0) {
|
|
408
|
+
batch.push(queue.shift());
|
|
409
|
+
}
|
|
410
|
+
// Collect all edges and targets for the batch
|
|
411
|
+
const adjacencyMap = new Map();
|
|
412
|
+
for (const nodeId of batch) {
|
|
413
|
+
const edges = direction === 'outgoing'
|
|
414
|
+
? this.queries.getOutgoingEdges(nodeId, edgeKinds)
|
|
415
|
+
: this.queries.getIncomingEdges(nodeId, edgeKinds);
|
|
416
|
+
for (const edge of edges) {
|
|
417
|
+
const nextId = direction === 'outgoing' ? edge.target : edge.source;
|
|
418
|
+
if (!adjacencyMap.has(nodeId))
|
|
419
|
+
adjacencyMap.set(nodeId, []);
|
|
420
|
+
adjacencyMap.get(nodeId).push({ nextId, edge });
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
// Collect all candidate next IDs for batch fetch
|
|
424
|
+
const allCandidateIds = new Set();
|
|
425
|
+
for (const entries of adjacencyMap.values()) {
|
|
426
|
+
for (const { nextId } of entries) {
|
|
427
|
+
allCandidateIds.add(nextId);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
// Filter to unvisited and batch-fetch
|
|
431
|
+
const wantIds = [...allCandidateIds].filter((id) => !currentVisited.has(id));
|
|
432
|
+
const fetchedNodes = wantIds.length > 0 ? this.queries.getNodesByIds(wantIds) : new Map();
|
|
433
|
+
for (const nodeId of batch) {
|
|
434
|
+
const entries = adjacencyMap.get(nodeId);
|
|
435
|
+
if (!entries)
|
|
436
|
+
continue;
|
|
437
|
+
const currentPath = currentVisited.get(nodeId);
|
|
438
|
+
for (const { nextId, edge } of entries) {
|
|
439
|
+
if (currentVisited.has(nextId))
|
|
440
|
+
continue;
|
|
441
|
+
const nextNode = fetchedNodes.get(nextId);
|
|
442
|
+
if (!nextNode)
|
|
443
|
+
continue;
|
|
444
|
+
const newPath = [...currentPath, { node: nextNode, edge }];
|
|
445
|
+
currentVisited.set(nextId, newPath);
|
|
446
|
+
queue.push(nextId);
|
|
447
|
+
// Check for intersection
|
|
448
|
+
if (otherVisited.has(nextId)) {
|
|
449
|
+
return nextId;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Merge forward and backward path fragments at the meeting node.
|
|
457
|
+
*/
|
|
458
|
+
mergePaths(forward, backward, meetPoint) {
|
|
459
|
+
const forwardPath = forward.get(meetPoint);
|
|
460
|
+
const backwardPath = backward.get(meetPoint);
|
|
461
|
+
// Backward path is stored from meet → target; reverse and drop the
|
|
462
|
+
// duplicate meet-point node (keep only the forward copy's edge = null head)
|
|
463
|
+
const reversedBackward = backwardPath.slice(1).reverse();
|
|
464
|
+
return [...forwardPath, ...reversedBackward];
|
|
465
|
+
}
|
|
466
|
+
// ===========================================================================
|
|
467
|
+
// Hierarchy
|
|
468
|
+
// ===========================================================================
|
|
469
|
+
/**
|
|
470
|
+
* Walk up the containment hierarchy from a node to its ancestors.
|
|
471
|
+
*
|
|
472
|
+
* Follows `contains` edges in reverse (incoming edges of kind `contains`),
|
|
473
|
+
* which represent "parent → child" — so the incoming edge on this node
|
|
474
|
+
* points to its parent.
|
|
475
|
+
*
|
|
476
|
+
* @param nodeId - ID of the node to start from
|
|
477
|
+
* @returns Array of ancestor nodes from immediate parent to root
|
|
478
|
+
*/
|
|
479
|
+
getAncestors(nodeId) {
|
|
480
|
+
const ancestors = [];
|
|
481
|
+
const visited = new Set();
|
|
482
|
+
let currentId = nodeId;
|
|
483
|
+
while (true) {
|
|
484
|
+
if (visited.has(currentId)) {
|
|
485
|
+
break;
|
|
486
|
+
}
|
|
487
|
+
visited.add(currentId);
|
|
488
|
+
// Look for 'contains' edges pointing to this node (it's a child)
|
|
489
|
+
const containingEdges = this.queries.getIncomingEdges(currentId, ['contains']);
|
|
490
|
+
const firstEdge = containingEdges[0];
|
|
491
|
+
if (!firstEdge) {
|
|
492
|
+
break;
|
|
493
|
+
}
|
|
494
|
+
// A node typically has at most one containing parent
|
|
495
|
+
const parentNode = this.queries.getNodeById(firstEdge.source);
|
|
496
|
+
if (parentNode) {
|
|
497
|
+
ancestors.push(parentNode);
|
|
498
|
+
currentId = parentNode.id;
|
|
499
|
+
}
|
|
500
|
+
else {
|
|
501
|
+
break;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
return ancestors;
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Get immediate children of a node via `contains` outgoing edges.
|
|
508
|
+
*
|
|
509
|
+
* For a table, these would be its columns, indexes, constraints, etc.
|
|
510
|
+
* For a schema, these would be its tables and views.
|
|
511
|
+
*
|
|
512
|
+
* @param nodeId - ID of the parent node
|
|
513
|
+
* @returns Array of child nodes
|
|
514
|
+
*/
|
|
515
|
+
getChildren(nodeId) {
|
|
516
|
+
const containsEdges = this.queries.getOutgoingEdges(nodeId, ['contains']);
|
|
517
|
+
if (containsEdges.length === 0)
|
|
518
|
+
return [];
|
|
519
|
+
// Batch-fetch all children
|
|
520
|
+
const childNodes = this.queries.getNodesByIds(containsEdges.map((e) => e.target));
|
|
521
|
+
const children = [];
|
|
522
|
+
for (const edge of containsEdges) {
|
|
523
|
+
const childNode = childNodes.get(edge.target);
|
|
524
|
+
if (childNode)
|
|
525
|
+
children.push(childNode);
|
|
526
|
+
}
|
|
527
|
+
return children;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
exports.GraphTraverser = GraphTraverser;
|
|
531
|
+
//# sourceMappingURL=traversal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traversal.js","sourceRoot":"","sources":["../../src/graph/traversal.ts"],"names":[],"mappings":"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"}
|