@dbt-tools/core 0.3.2
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 +201 -0
- package/README.md +51 -0
- package/dist/analysis/analysis-snapshot.d.ts +145 -0
- package/dist/analysis/analysis-snapshot.js +615 -0
- package/dist/analysis/dependency-service.d.ts +56 -0
- package/dist/analysis/dependency-service.js +75 -0
- package/dist/analysis/execution-analyzer.d.ts +85 -0
- package/dist/analysis/execution-analyzer.js +245 -0
- package/dist/analysis/manifest-graph.d.ts +118 -0
- package/dist/analysis/manifest-graph.js +651 -0
- package/dist/analysis/run-results-search.d.ts +56 -0
- package/dist/analysis/run-results-search.js +127 -0
- package/dist/analysis/sql-analyzer.d.ts +30 -0
- package/dist/analysis/sql-analyzer.js +218 -0
- package/dist/browser.d.ts +11 -0
- package/dist/browser.js +17 -0
- package/dist/errors/error-handler.d.ts +26 -0
- package/dist/errors/error-handler.js +59 -0
- package/dist/formatting/field-filter.d.ts +29 -0
- package/dist/formatting/field-filter.js +112 -0
- package/dist/formatting/graph-export.d.ts +9 -0
- package/dist/formatting/graph-export.js +147 -0
- package/dist/formatting/output-formatter.d.ts +77 -0
- package/dist/formatting/output-formatter.js +160 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +38 -0
- package/dist/introspection/schema-generator.d.ts +29 -0
- package/dist/introspection/schema-generator.js +275 -0
- package/dist/io/artifact-loader.d.ts +27 -0
- package/dist/io/artifact-loader.js +142 -0
- package/dist/types.d.ts +43 -0
- package/dist/types.js +2 -0
- package/dist/validation/input-validator.d.ts +39 -0
- package/dist/validation/input-validator.js +167 -0
- package/dist/version.d.ts +28 -0
- package/dist/version.js +60 -0
- package/package.json +47 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DependencyService = void 0;
|
|
4
|
+
const field_filter_1 = require("../formatting/field-filter");
|
|
5
|
+
/**
|
|
6
|
+
* DependencyService wraps ManifestGraph dependency methods with formatting
|
|
7
|
+
* and field filtering capabilities.
|
|
8
|
+
*/
|
|
9
|
+
class DependencyService {
|
|
10
|
+
/**
|
|
11
|
+
* Get dependencies for a resource with optional field filtering, depth limit, output format, and build order.
|
|
12
|
+
* @param depth - Optional max traversal depth; 1 = immediate neighbors, undefined = all levels
|
|
13
|
+
* @param format - Output structure: flat list or nested tree
|
|
14
|
+
* @param buildOrder - When true and direction is upstream, return dependencies in topological build order
|
|
15
|
+
*/
|
|
16
|
+
static getDependencies(graph, resourceId, direction, fields, depth, format, buildOrder) {
|
|
17
|
+
if (format === "tree" && !(direction === "upstream" && buildOrder)) {
|
|
18
|
+
return this.getDependenciesTree(graph, resourceId, direction, fields, depth);
|
|
19
|
+
}
|
|
20
|
+
// Flat format (or tree with buildOrder: use flat + build order)
|
|
21
|
+
const dependencyEntries = direction === "upstream" && buildOrder
|
|
22
|
+
? graph.getUpstreamBuildOrder(resourceId, depth)
|
|
23
|
+
: direction === "upstream"
|
|
24
|
+
? graph.getUpstream(resourceId, depth)
|
|
25
|
+
: graph.getDownstream(resourceId, depth);
|
|
26
|
+
const graphologyGraph = graph.getGraph();
|
|
27
|
+
const dependencies = dependencyEntries.map(({ nodeId, depth: depDepth }) => {
|
|
28
|
+
const attributes = graphologyGraph.getNodeAttributes(nodeId);
|
|
29
|
+
return Object.assign(Object.assign({}, attributes), { unique_id: nodeId, resource_type: attributes.resource_type || "unknown", name: attributes.name || nodeId, package_name: attributes.package_name || "", depth: depDepth });
|
|
30
|
+
});
|
|
31
|
+
let filteredDependencies = dependencies;
|
|
32
|
+
if (fields) {
|
|
33
|
+
filteredDependencies = field_filter_1.FieldFilter.filterArrayFields(dependencies, fields);
|
|
34
|
+
}
|
|
35
|
+
return Object.assign(Object.assign({ resource_id: resourceId, direction }, (buildOrder && direction === "upstream" && { build_order: true })), { dependencies: filteredDependencies, count: filteredDependencies.length });
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Build nested tree from BFS entries with parent tracking
|
|
39
|
+
*/
|
|
40
|
+
static getDependenciesTree(graph, resourceId, direction, fields, depth) {
|
|
41
|
+
var _a, _b;
|
|
42
|
+
const entries = direction === "upstream"
|
|
43
|
+
? graph.getUpstreamWithParents(resourceId, depth)
|
|
44
|
+
: graph.getDownstreamWithParents(resourceId, depth);
|
|
45
|
+
const graphologyGraph = graph.getGraph();
|
|
46
|
+
// Build parent -> children map (parentId is the BFS predecessor)
|
|
47
|
+
const childrenByParent = new Map();
|
|
48
|
+
for (const { nodeId, depth: depDepth, parentId } of entries) {
|
|
49
|
+
const existing = (_a = childrenByParent.get(parentId)) !== null && _a !== void 0 ? _a : [];
|
|
50
|
+
existing.push({ nodeId, depth: depDepth });
|
|
51
|
+
childrenByParent.set(parentId, existing);
|
|
52
|
+
}
|
|
53
|
+
const buildNode = (nodeId, depDepth) => {
|
|
54
|
+
var _a;
|
|
55
|
+
const attributes = graphologyGraph.getNodeAttributes(nodeId);
|
|
56
|
+
const childEntries = (_a = childrenByParent.get(nodeId)) !== null && _a !== void 0 ? _a : [];
|
|
57
|
+
const childNodes = childEntries.map(({ nodeId: cId, depth: cDepth }) => buildNode(cId, cDepth));
|
|
58
|
+
const node = Object.assign(Object.assign({}, attributes), { unique_id: nodeId, resource_type: attributes.resource_type || "unknown", name: attributes.name || nodeId, package_name: attributes.package_name || "", depth: depDepth, dependencies: childNodes });
|
|
59
|
+
if (fields) {
|
|
60
|
+
const filtered = field_filter_1.FieldFilter.filterFields(node, fields);
|
|
61
|
+
return Object.assign(Object.assign({}, filtered), { dependencies: node.dependencies });
|
|
62
|
+
}
|
|
63
|
+
return node;
|
|
64
|
+
};
|
|
65
|
+
const rootChildren = (_b = childrenByParent.get(resourceId)) !== null && _b !== void 0 ? _b : [];
|
|
66
|
+
const dependencyTrees = rootChildren.map(({ nodeId, depth: d }) => buildNode(nodeId, d));
|
|
67
|
+
return {
|
|
68
|
+
resource_id: resourceId,
|
|
69
|
+
direction,
|
|
70
|
+
dependencies: dependencyTrees,
|
|
71
|
+
count: entries.length,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
exports.DependencyService = DependencyService;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { ParsedRunResults } from "dbt-artifacts-parser/run_results";
|
|
2
|
+
import type { ManifestGraph } from "./manifest-graph";
|
|
3
|
+
/**
|
|
4
|
+
* Execution timing information for a single node
|
|
5
|
+
*/
|
|
6
|
+
export interface NodeExecution {
|
|
7
|
+
unique_id: string;
|
|
8
|
+
status: string;
|
|
9
|
+
execution_time: number;
|
|
10
|
+
started_at?: string;
|
|
11
|
+
completed_at?: string;
|
|
12
|
+
thread_id?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Critical path analysis result
|
|
16
|
+
*/
|
|
17
|
+
export interface CriticalPath {
|
|
18
|
+
path: string[];
|
|
19
|
+
total_time: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Execution summary statistics
|
|
23
|
+
*/
|
|
24
|
+
export interface ExecutionSummary {
|
|
25
|
+
total_execution_time: number;
|
|
26
|
+
total_nodes: number;
|
|
27
|
+
nodes_by_status: Record<string, number>;
|
|
28
|
+
critical_path?: CriticalPath;
|
|
29
|
+
node_executions: NodeExecution[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* ExecutionAnalyzer processes run_results.json to extract timing information
|
|
33
|
+
* and correlate it with the dependency graph.
|
|
34
|
+
*/
|
|
35
|
+
export declare class ExecutionAnalyzer {
|
|
36
|
+
private runResults;
|
|
37
|
+
private graph;
|
|
38
|
+
constructor(runResults: ParsedRunResults, graph: ManifestGraph);
|
|
39
|
+
/**
|
|
40
|
+
* Get execution summary with statistics
|
|
41
|
+
*/
|
|
42
|
+
getSummary(): ExecutionSummary;
|
|
43
|
+
/**
|
|
44
|
+
* Extract execution information for each node
|
|
45
|
+
*/
|
|
46
|
+
getNodeExecutions(): NodeExecution[];
|
|
47
|
+
/**
|
|
48
|
+
* Calculate the critical path (longest path through the dependency graph)
|
|
49
|
+
*/
|
|
50
|
+
calculateCriticalPath(nodeExecutions: NodeExecution[]): CriticalPath | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* Find the longest path from a node to root (nodes with no dependencies)
|
|
53
|
+
*/
|
|
54
|
+
private findLongestPathToRoot;
|
|
55
|
+
/**
|
|
56
|
+
* Calculate total execution time for a path
|
|
57
|
+
*/
|
|
58
|
+
private calculatePathTime;
|
|
59
|
+
/**
|
|
60
|
+
* Returns the absolute epoch-ms timestamp of the earliest executed node,
|
|
61
|
+
* or null if no timing data is available. Useful for converting relative
|
|
62
|
+
* Gantt offsets to wall-clock timestamps.
|
|
63
|
+
*/
|
|
64
|
+
getRunStartedAt(): number | null;
|
|
65
|
+
private parseTimingInterval;
|
|
66
|
+
/**
|
|
67
|
+
* Wall-clock span and optional compile/execute intervals (epoch ms).
|
|
68
|
+
*/
|
|
69
|
+
private wallClockFromResult;
|
|
70
|
+
/**
|
|
71
|
+
* Get Gantt chart data for visualization
|
|
72
|
+
*/
|
|
73
|
+
getGanttData(): Array<{
|
|
74
|
+
unique_id: string;
|
|
75
|
+
name: string;
|
|
76
|
+
start: number;
|
|
77
|
+
end: number;
|
|
78
|
+
duration: number;
|
|
79
|
+
status: string;
|
|
80
|
+
compileStart: number | null;
|
|
81
|
+
compileEnd: number | null;
|
|
82
|
+
executeStart: number | null;
|
|
83
|
+
executeEnd: number | null;
|
|
84
|
+
}>;
|
|
85
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExecutionAnalyzer = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* ExecutionAnalyzer processes run_results.json to extract timing information
|
|
6
|
+
* and correlate it with the dependency graph.
|
|
7
|
+
*/
|
|
8
|
+
class ExecutionAnalyzer {
|
|
9
|
+
constructor(runResults, graph) {
|
|
10
|
+
this.runResults = runResults;
|
|
11
|
+
this.graph = graph;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Get execution summary with statistics
|
|
15
|
+
*/
|
|
16
|
+
getSummary() {
|
|
17
|
+
const nodeExecutions = this.getNodeExecutions();
|
|
18
|
+
const nodesByStatus = {};
|
|
19
|
+
let totalExecutionTime = 0;
|
|
20
|
+
for (const execution of nodeExecutions) {
|
|
21
|
+
// Count by status
|
|
22
|
+
const status = execution.status || "unknown";
|
|
23
|
+
nodesByStatus[status] = (nodesByStatus[status] || 0) + 1;
|
|
24
|
+
// Sum execution time
|
|
25
|
+
totalExecutionTime += execution.execution_time || 0;
|
|
26
|
+
}
|
|
27
|
+
// Calculate critical path
|
|
28
|
+
const criticalPath = this.calculateCriticalPath(nodeExecutions);
|
|
29
|
+
return {
|
|
30
|
+
total_execution_time: totalExecutionTime,
|
|
31
|
+
total_nodes: nodeExecutions.length,
|
|
32
|
+
nodes_by_status: nodesByStatus,
|
|
33
|
+
critical_path: criticalPath,
|
|
34
|
+
node_executions: nodeExecutions,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Extract execution information for each node
|
|
39
|
+
*/
|
|
40
|
+
getNodeExecutions() {
|
|
41
|
+
if (!this.runResults.results || !Array.isArray(this.runResults.results)) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
const results = this.runResults.results;
|
|
45
|
+
return results.map((result) => {
|
|
46
|
+
var _a, _b, _c;
|
|
47
|
+
// Find execute timing (most relevant for execution time)
|
|
48
|
+
const timingArray = result.timing || [];
|
|
49
|
+
const executeTiming = timingArray.find((t) => t.name === "execute");
|
|
50
|
+
const compileTiming = timingArray.find((t) => t.name === "compile");
|
|
51
|
+
// Use execute timing if available, otherwise fall back to compile
|
|
52
|
+
const timing = executeTiming || compileTiming || timingArray[0];
|
|
53
|
+
return {
|
|
54
|
+
unique_id: result.unique_id || "",
|
|
55
|
+
status: result.status || "unknown",
|
|
56
|
+
execution_time: result.execution_time || 0,
|
|
57
|
+
started_at: (_a = timing === null || timing === void 0 ? void 0 : timing.started_at) !== null && _a !== void 0 ? _a : undefined,
|
|
58
|
+
completed_at: (_b = timing === null || timing === void 0 ? void 0 : timing.completed_at) !== null && _b !== void 0 ? _b : undefined,
|
|
59
|
+
thread_id: (_c = result.thread_id) !== null && _c !== void 0 ? _c : undefined,
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Calculate the critical path (longest path through the dependency graph)
|
|
65
|
+
*/
|
|
66
|
+
calculateCriticalPath(nodeExecutions) {
|
|
67
|
+
// Create a map of node executions by unique_id
|
|
68
|
+
const executionMap = new Map();
|
|
69
|
+
for (const exec of nodeExecutions) {
|
|
70
|
+
executionMap.set(exec.unique_id, exec);
|
|
71
|
+
}
|
|
72
|
+
// Find all leaf nodes (nodes with no downstream dependents)
|
|
73
|
+
const leafNodes = [];
|
|
74
|
+
const graph = this.graph.getGraph();
|
|
75
|
+
graph.forEachNode((nodeId) => {
|
|
76
|
+
const outboundNeighbors = graph.outboundNeighbors(nodeId);
|
|
77
|
+
if (outboundNeighbors.length === 0 && executionMap.has(nodeId)) {
|
|
78
|
+
leafNodes.push(nodeId);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
if (leafNodes.length === 0) {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
// For each leaf node, find the longest path from root
|
|
85
|
+
let maxPath = [];
|
|
86
|
+
let maxTime = 0;
|
|
87
|
+
for (const leafNode of leafNodes) {
|
|
88
|
+
const path = this.findLongestPathToRoot(leafNode, executionMap);
|
|
89
|
+
const pathTime = this.calculatePathTime(path, executionMap);
|
|
90
|
+
if (pathTime > maxTime) {
|
|
91
|
+
maxTime = pathTime;
|
|
92
|
+
maxPath = path;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (maxPath.length === 0) {
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
path: maxPath,
|
|
100
|
+
total_time: maxTime,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Find the longest path from a node to root (nodes with no dependencies)
|
|
105
|
+
*/
|
|
106
|
+
findLongestPathToRoot(startNode, executionMap) {
|
|
107
|
+
const graph = this.graph.getGraph();
|
|
108
|
+
const visited = new Set();
|
|
109
|
+
let longestPath = [];
|
|
110
|
+
const dfs = (currentNode, currentPath) => {
|
|
111
|
+
if (visited.has(currentNode)) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
visited.add(currentNode);
|
|
115
|
+
const newPath = [...currentPath, currentNode];
|
|
116
|
+
// Update longest path if this is longer
|
|
117
|
+
if (newPath.length > longestPath.length) {
|
|
118
|
+
longestPath = newPath;
|
|
119
|
+
}
|
|
120
|
+
// Traverse upstream (inbound neighbors)
|
|
121
|
+
const inboundNeighbors = graph.inboundNeighbors(currentNode);
|
|
122
|
+
for (const neighbor of inboundNeighbors) {
|
|
123
|
+
if (executionMap.has(neighbor)) {
|
|
124
|
+
dfs(neighbor, newPath);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
visited.delete(currentNode);
|
|
128
|
+
};
|
|
129
|
+
dfs(startNode, []);
|
|
130
|
+
return longestPath.reverse(); // Reverse to get root-to-leaf order
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Calculate total execution time for a path
|
|
134
|
+
*/
|
|
135
|
+
calculatePathTime(path, executionMap) {
|
|
136
|
+
let totalTime = 0;
|
|
137
|
+
for (const nodeId of path) {
|
|
138
|
+
const exec = executionMap.get(nodeId);
|
|
139
|
+
if (exec) {
|
|
140
|
+
totalTime += exec.execution_time || 0;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return totalTime;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Returns the absolute epoch-ms timestamp of the earliest executed node,
|
|
147
|
+
* or null if no timing data is available. Useful for converting relative
|
|
148
|
+
* Gantt offsets to wall-clock timestamps.
|
|
149
|
+
*/
|
|
150
|
+
getRunStartedAt() {
|
|
151
|
+
const executions = this.getNodeExecutions();
|
|
152
|
+
const timestamps = executions
|
|
153
|
+
.map((exec) => exec.started_at ? new Date(exec.started_at).getTime() : null)
|
|
154
|
+
.filter((t) => t !== null);
|
|
155
|
+
if (timestamps.length === 0)
|
|
156
|
+
return null;
|
|
157
|
+
return Math.min(...timestamps);
|
|
158
|
+
}
|
|
159
|
+
parseTimingInterval(timing) {
|
|
160
|
+
if (!timing)
|
|
161
|
+
return null;
|
|
162
|
+
const started = timing.started_at;
|
|
163
|
+
const completed = timing.completed_at;
|
|
164
|
+
if (!started || !completed)
|
|
165
|
+
return null;
|
|
166
|
+
const startMs = new Date(started).getTime();
|
|
167
|
+
const endMs = new Date(completed).getTime();
|
|
168
|
+
if (Number.isNaN(startMs) || Number.isNaN(endMs))
|
|
169
|
+
return null;
|
|
170
|
+
return { start: startMs, end: endMs };
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Wall-clock span and optional compile/execute intervals (epoch ms).
|
|
174
|
+
*/
|
|
175
|
+
wallClockFromResult(result) {
|
|
176
|
+
const timingArray = result.timing || [];
|
|
177
|
+
const executeTiming = timingArray.find((t) => t.name === "execute");
|
|
178
|
+
const compileTiming = timingArray.find((t) => t.name === "compile");
|
|
179
|
+
const compile = this.parseTimingInterval(compileTiming);
|
|
180
|
+
const execute = this.parseTimingInterval(executeTiming);
|
|
181
|
+
const starts = [];
|
|
182
|
+
const ends = [];
|
|
183
|
+
if (compile) {
|
|
184
|
+
starts.push(compile.start);
|
|
185
|
+
ends.push(compile.end);
|
|
186
|
+
}
|
|
187
|
+
if (execute) {
|
|
188
|
+
starts.push(execute.start);
|
|
189
|
+
ends.push(execute.end);
|
|
190
|
+
}
|
|
191
|
+
if (starts.length === 0)
|
|
192
|
+
return null;
|
|
193
|
+
return {
|
|
194
|
+
wallStart: Math.min(...starts),
|
|
195
|
+
wallEnd: Math.max(...ends),
|
|
196
|
+
compile,
|
|
197
|
+
execute,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Get Gantt chart data for visualization
|
|
202
|
+
*/
|
|
203
|
+
getGanttData() {
|
|
204
|
+
if (!this.runResults.results || !Array.isArray(this.runResults.results)) {
|
|
205
|
+
return [];
|
|
206
|
+
}
|
|
207
|
+
const graphologyGraph = this.graph.getGraph();
|
|
208
|
+
const rows = [];
|
|
209
|
+
for (const result of this.runResults
|
|
210
|
+
.results) {
|
|
211
|
+
const uniqueId = result.unique_id || "";
|
|
212
|
+
if (!uniqueId)
|
|
213
|
+
continue;
|
|
214
|
+
const wall = this.wallClockFromResult(result);
|
|
215
|
+
if (!wall)
|
|
216
|
+
continue;
|
|
217
|
+
const nodeAttributes = graphologyGraph.hasNode(uniqueId)
|
|
218
|
+
? graphologyGraph.getNodeAttributes(uniqueId)
|
|
219
|
+
: undefined;
|
|
220
|
+
const name = (nodeAttributes === null || nodeAttributes === void 0 ? void 0 : nodeAttributes.name) || uniqueId;
|
|
221
|
+
const status = result.status || "unknown";
|
|
222
|
+
rows.push({ unique_id: uniqueId, name, status, wall });
|
|
223
|
+
}
|
|
224
|
+
if (rows.length === 0)
|
|
225
|
+
return [];
|
|
226
|
+
const minStart = Math.min(...rows.map((r) => r.wall.wallStart));
|
|
227
|
+
return rows.map((row) => {
|
|
228
|
+
const { wall } = row;
|
|
229
|
+
const rel = (t) => t - minStart;
|
|
230
|
+
return {
|
|
231
|
+
unique_id: row.unique_id,
|
|
232
|
+
name: row.name,
|
|
233
|
+
start: rel(wall.wallStart),
|
|
234
|
+
end: rel(wall.wallEnd),
|
|
235
|
+
duration: wall.wallEnd - wall.wallStart,
|
|
236
|
+
status: row.status,
|
|
237
|
+
compileStart: wall.compile ? rel(wall.compile.start) : null,
|
|
238
|
+
compileEnd: wall.compile ? rel(wall.compile.end) : null,
|
|
239
|
+
executeStart: wall.execute ? rel(wall.execute.start) : null,
|
|
240
|
+
executeEnd: wall.execute ? rel(wall.execute.end) : null,
|
|
241
|
+
};
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
exports.ExecutionAnalyzer = ExecutionAnalyzer;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { DirectedGraph } from "graphology";
|
|
2
|
+
import type { ParsedManifest } from "dbt-artifacts-parser/manifest";
|
|
3
|
+
import type { ParsedCatalog } from "dbt-artifacts-parser/catalog";
|
|
4
|
+
import type { GraphNodeAttributes, GraphEdgeAttributes, GraphSummary } from "../types";
|
|
5
|
+
import type { ColumnDependencyMap } from "./sql-analyzer";
|
|
6
|
+
/**
|
|
7
|
+
* ManifestGraph builds and manages a directed graph from a dbt manifest.
|
|
8
|
+
*
|
|
9
|
+
* This class transforms dbt artifacts into a graphology graph, enabling
|
|
10
|
+
* efficient graph operations like cycle detection, path finding, and traversal.
|
|
11
|
+
*/
|
|
12
|
+
export declare class ManifestGraph {
|
|
13
|
+
private graph;
|
|
14
|
+
private relationMap;
|
|
15
|
+
constructor(manifest: ParsedManifest);
|
|
16
|
+
/**
|
|
17
|
+
* Build the graph from manifest data
|
|
18
|
+
*/
|
|
19
|
+
private buildGraph;
|
|
20
|
+
/**
|
|
21
|
+
* Add nodes from manifest to the graph
|
|
22
|
+
*/
|
|
23
|
+
/** Map relation_name (lowercase) to unique_id when present on manifest entries. */
|
|
24
|
+
private registerRelationName;
|
|
25
|
+
private addNodes;
|
|
26
|
+
private addNodeEntries;
|
|
27
|
+
private addSourceEntries;
|
|
28
|
+
private addMacroEntries;
|
|
29
|
+
private addExposureEntries;
|
|
30
|
+
private addMetricEntries;
|
|
31
|
+
private addSemanticModelEntries;
|
|
32
|
+
private addUnitTestEntries;
|
|
33
|
+
/**
|
|
34
|
+
* Add edges based on dependencies
|
|
35
|
+
*/
|
|
36
|
+
private addEdges;
|
|
37
|
+
private addEdgesFromParentMap;
|
|
38
|
+
private addEdgesFromDependsOn;
|
|
39
|
+
private addEdgesFromNodeDependsOn;
|
|
40
|
+
private addEdgesFromExposureDependsOn;
|
|
41
|
+
private addEdgesFromMetricDependsOn;
|
|
42
|
+
/**
|
|
43
|
+
* Extract resource type from manifest node
|
|
44
|
+
*/
|
|
45
|
+
private extractResourceType;
|
|
46
|
+
/**
|
|
47
|
+
* Infer dependency type from node ID
|
|
48
|
+
*/
|
|
49
|
+
private inferDependencyType;
|
|
50
|
+
/**
|
|
51
|
+
* Get the underlying graphology graph
|
|
52
|
+
*/
|
|
53
|
+
getGraph(): DirectedGraph<GraphNodeAttributes, GraphEdgeAttributes>;
|
|
54
|
+
/**
|
|
55
|
+
* Get summary statistics about the graph
|
|
56
|
+
*/
|
|
57
|
+
getSummary(): GraphSummary;
|
|
58
|
+
/**
|
|
59
|
+
* Get all upstream dependencies of a node using BFS.
|
|
60
|
+
* @param nodeId - The node to find upstream dependencies for
|
|
61
|
+
* @param maxDepth - Optional limit; 1 = immediate neighbors only, undefined = all levels
|
|
62
|
+
* @returns Array of { nodeId, depth } where depth is the shortest distance from the node
|
|
63
|
+
*/
|
|
64
|
+
getUpstream(nodeId: string, maxDepth?: number): Array<{
|
|
65
|
+
nodeId: string;
|
|
66
|
+
depth: number;
|
|
67
|
+
}>;
|
|
68
|
+
/**
|
|
69
|
+
* Get all downstream dependents of a node using BFS.
|
|
70
|
+
* @param nodeId - The node to find downstream dependents for
|
|
71
|
+
* @param maxDepth - Optional limit; 1 = immediate neighbors only, undefined = all levels
|
|
72
|
+
* @returns Array of { nodeId, depth } where depth is the shortest distance from the node
|
|
73
|
+
*/
|
|
74
|
+
getDownstream(nodeId: string, maxDepth?: number): Array<{
|
|
75
|
+
nodeId: string;
|
|
76
|
+
depth: number;
|
|
77
|
+
}>;
|
|
78
|
+
/**
|
|
79
|
+
* Get upstream dependencies with parent info for tree construction.
|
|
80
|
+
* @returns Array of { nodeId, depth, parentId } where parentId is the BFS predecessor
|
|
81
|
+
*/
|
|
82
|
+
getUpstreamWithParents(nodeId: string, maxDepth?: number): Array<{
|
|
83
|
+
nodeId: string;
|
|
84
|
+
depth: number;
|
|
85
|
+
parentId: string;
|
|
86
|
+
}>;
|
|
87
|
+
/**
|
|
88
|
+
* Get upstream dependencies in build order (topological sort).
|
|
89
|
+
* Sources and root models first, then models that depend on them.
|
|
90
|
+
* @param nodeId - The node to find upstream dependencies for
|
|
91
|
+
* @param maxDepth - Optional limit; 1 = immediate neighbors only, undefined = all levels
|
|
92
|
+
* @returns Array of { nodeId, depth } in build order
|
|
93
|
+
*/
|
|
94
|
+
getUpstreamBuildOrder(nodeId: string, maxDepth?: number): Array<{
|
|
95
|
+
nodeId: string;
|
|
96
|
+
depth: number;
|
|
97
|
+
}>;
|
|
98
|
+
/**
|
|
99
|
+
* Get downstream dependents with parent info for tree construction.
|
|
100
|
+
* @returns Array of { nodeId, depth, parentId } where parentId is the BFS predecessor
|
|
101
|
+
*/
|
|
102
|
+
getDownstreamWithParents(nodeId: string, maxDepth?: number): Array<{
|
|
103
|
+
nodeId: string;
|
|
104
|
+
depth: number;
|
|
105
|
+
parentId: string;
|
|
106
|
+
}>;
|
|
107
|
+
/**
|
|
108
|
+
* Add field nodes from catalog metadata
|
|
109
|
+
*/
|
|
110
|
+
addFieldNodes(catalog: ParsedCatalog): void;
|
|
111
|
+
private processCatalogColumns;
|
|
112
|
+
/**
|
|
113
|
+
* Add field-to-field edges based on SQL analysis
|
|
114
|
+
*/
|
|
115
|
+
addFieldEdges(childNodeId: string, dependencies: ColumnDependencyMap): void;
|
|
116
|
+
private ensureFieldNode;
|
|
117
|
+
private resolveRelationToUniqueId;
|
|
118
|
+
}
|