Skip to content

Commit bdd76f7

Browse files
committed
refactor: replace Node class hierarchy with NodeData interface
1 parent fb85e14 commit bdd76f7

File tree

3 files changed

+156
-95
lines changed

3 files changed

+156
-95
lines changed

src/dbt_integration/domain.ts

Lines changed: 9 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,16 @@ export interface ExposureMetaData {
170170
meta?: Record<string, unknown>;
171171
}
172172

173+
export interface NodeData {
174+
label: string;
175+
key: string;
176+
url?: string;
177+
resourceType: string;
178+
}
179+
173180
interface NodeGraphMetaData {
174-
currentNode: Node;
175-
nodes: Node[];
181+
currentNode: NodeData;
182+
nodes: NodeData[];
176183
}
177184

178185
interface ModelGraphMetaData {
@@ -191,64 +198,6 @@ export interface GraphMetaMap {
191198
metrics: NodeGraphMap;
192199
}
193200

194-
interface IconPath {
195-
light: string;
196-
dark: string;
197-
}
198-
199-
export abstract class Node {
200-
label: string;
201-
key: string;
202-
url: string | undefined;
203-
iconPath: IconPath = {
204-
light: path.join(
205-
path.resolve(__dirname),
206-
"../media/images/model_light.svg",
207-
),
208-
dark: path.join(path.resolve(__dirname), "../media/images/model_dark.svg"),
209-
};
210-
displayInModelTree: boolean = true;
211-
212-
constructor(label: string, key: string, url?: string) {
213-
this.label = label;
214-
this.key = key;
215-
this.url = url;
216-
}
217-
}
218-
219-
export class Model extends Node {}
220-
221-
export class Seed extends Node {}
222-
export class Test extends Node {
223-
// displayInModelTree = false;
224-
iconPath = {
225-
light: path.join(
226-
path.resolve(__dirname),
227-
"../media/images/source_light.svg",
228-
),
229-
dark: path.join(path.resolve(__dirname), "../media/images/source_dark.svg"),
230-
};
231-
}
232-
export class Analysis extends Node {
233-
displayInModelTree = true;
234-
}
235-
export class Exposure extends Node {
236-
displayInModelTree = true;
237-
}
238-
export class Metric extends Node {
239-
displayInModelTree = false;
240-
}
241-
export class Snapshot extends Node {}
242-
export class Source extends Node {
243-
iconPath = {
244-
light: path.join(
245-
path.resolve(__dirname),
246-
"../media/images/source_light.svg",
247-
),
248-
dark: path.join(path.resolve(__dirname), "../media/images/source_dark.svg"),
249-
};
250-
}
251-
252201
export enum RunModelType {
253202
RUN_PARENTS,
254203
RUN_CHILDREN,

src/dbt_integration/parsers/graphParser.ts

Lines changed: 53 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,15 @@
11
import {
2-
Analysis,
3-
Exposure,
42
GraphMetaMap,
5-
Metric,
63
MetricMetaMap,
7-
Model,
8-
Node,
4+
NodeData,
95
NodeGraphMap,
106
NodeMetaMap,
11-
Seed,
12-
Snapshot,
13-
Source,
147
SourceMetaMap,
15-
Test,
168
TestMetaMap,
179
} from "../domain";
1810
import { DBTTerminal } from "../terminal";
1911
import { DBTIntegrationAdapter } from "../dbtIntegrationAdapter";
12+
import { RESOURCE_TYPE_METRIC, RESOURCE_TYPE_TEST } from "../dbtIntegration";
2013

2114
const notEmpty = <T>(value: T | null | undefined): value is T => {
2215
return value !== null && value !== undefined;
@@ -73,7 +66,7 @@ export class GraphParser {
7366
metricMetaMap,
7467
),
7568
)
76-
.filter((n) => !(n instanceof Test))
69+
.filter((n) => n?.resourceType !== RESOURCE_TYPE_TEST)
7770
.filter(notEmpty);
7871
map.set(nodeName, { nodes: currentNodes });
7972
return map;
@@ -92,7 +85,7 @@ export class GraphParser {
9285
metricMetaMap,
9386
),
9487
)
95-
.filter((n) => n instanceof Test)
88+
.filter((n) => n?.resourceType === RESOURCE_TYPE_TEST)
9689
.filter(notEmpty);
9790
map.set(nodeName, { nodes: currentNodes });
9891
return map;
@@ -111,7 +104,7 @@ export class GraphParser {
111104
metricMetaMap,
112105
),
113106
)
114-
.filter((n) => n instanceof Metric)
107+
.filter((n) => n?.resourceType === RESOURCE_TYPE_METRIC)
115108
.filter(notEmpty);
116109
map.set(nodeName, { nodes: currentNodes });
117110
return map;
@@ -138,7 +131,7 @@ export class GraphParser {
138131
nodeMetaMap: NodeMetaMap,
139132
testMetaMap: TestMetaMap,
140133
metricMetaMap: MetricMetaMap,
141-
): (parentNodeName: string) => Node | undefined {
134+
): (parentNodeName: string) => NodeData | undefined {
142135
return (parentNodeName) => {
143136
// Support dots in model names
144137
const [nodeType, nodePackage, ...restNodeName] =
@@ -150,11 +143,12 @@ export class GraphParser {
150143
const url = sourceMetaMap
151144
.get(sourceName)
152145
?.tables.find((table) => table.name === tableName)?.path!;
153-
return new Source(
154-
`${tableName} (${sourceName})`,
155-
parentNodeName,
156-
url,
157-
);
146+
return {
147+
label: `${tableName} (${sourceName})`,
148+
key: parentNodeName,
149+
url: url,
150+
resourceType: "source",
151+
};
158152
}
159153
case "model": {
160154
// can this ever be not there?
@@ -163,7 +157,12 @@ export class GraphParser {
163157
return;
164158
}
165159
const url = model?.path!;
166-
return new Model(model.alias, parentNodeName, url);
160+
return {
161+
label: model.alias,
162+
key: parentNodeName,
163+
url: url,
164+
resourceType: "model",
165+
};
167166
}
168167
case "seed": {
169168
// can this ever be not there?
@@ -172,28 +171,57 @@ export class GraphParser {
172171
return;
173172
}
174173
const url = model?.path!;
175-
return new Seed(model.alias, parentNodeName, url);
174+
return {
175+
label: model.alias,
176+
key: parentNodeName,
177+
url: url,
178+
resourceType: "seed",
179+
};
176180
}
177181
case "test": {
178182
// nodeName => more interesting label possibilities?
179183
// console.log(`${nodeName} => (parent: ${parentNodeName})`);
180184
const url = testMetaMap.get(nodeName.split(".")[0])?.path;
181-
return new Test(nodeName, parentNodeName, url ?? "");
185+
return {
186+
label: nodeName,
187+
key: parentNodeName,
188+
url: url,
189+
resourceType: "test",
190+
};
182191
}
183192
case "analysis": {
184193
const url = nodeMetaMap.lookupByBaseName(nodeName)?.path!;
185-
return new Analysis(nodeName, parentNodeName, url);
194+
return {
195+
label: nodeName,
196+
key: parentNodeName,
197+
url: url,
198+
resourceType: "analysis",
199+
};
186200
}
187201
case "snapshot": {
188202
const url = nodeMetaMap.lookupByBaseName(nodeName)?.path!;
189-
return new Snapshot(nodeName, parentNodeName, url);
203+
return {
204+
label: nodeName,
205+
key: parentNodeName,
206+
url: url,
207+
resourceType: "snapshot",
208+
};
190209
}
191210
case "exposure": {
192211
const url = nodeMetaMap.lookupByBaseName(nodeName)?.path!;
193-
return new Exposure(nodeName, parentNodeName, url);
212+
return {
213+
label: nodeName,
214+
key: parentNodeName,
215+
url: url,
216+
resourceType: "exposure",
217+
};
194218
}
195219
case "semantic_model": {
196-
return new Metric(nodeName, parentNodeName);
220+
return {
221+
label: nodeName,
222+
key: parentNodeName,
223+
resourceType: "semantic_model",
224+
};
197225
}
198226
default:
199227
console.log(`Node Type '${nodeType}' not implemented!`);

src/treeview_provider/modelTreeviewProvider.ts

Lines changed: 94 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,12 @@ import {
1616
TreeItemCollapsibleState,
1717
Uri,
1818
window,
19-
workspace,
2019
} from "vscode";
2120
import {
22-
Analysis,
23-
Exposure,
2421
GraphMetaMap,
25-
Node,
22+
NodeData,
2623
NodeMetaData,
2724
NodeMetaMap,
28-
Seed,
29-
Snapshot,
30-
Source,
31-
Test,
3225
} from "../dbt_integration/domain";
3326
import { DBTProjectContainer } from "../manifest/dbtProjectContainer";
3427
import {
@@ -42,6 +35,66 @@ import {
4235
getDepthColor,
4336
} from "../utils";
4437

38+
interface IconPath {
39+
light: string;
40+
dark: string;
41+
}
42+
43+
abstract class Node {
44+
label: string;
45+
key: string;
46+
url: string | undefined;
47+
iconPath: IconPath = {
48+
light: path.join(
49+
path.resolve(__dirname),
50+
"../media/images/model_light.svg",
51+
),
52+
dark: path.join(path.resolve(__dirname), "../media/images/model_dark.svg"),
53+
};
54+
displayInModelTree: boolean = true;
55+
56+
constructor(label: string, key: string, url?: string) {
57+
this.label = label;
58+
this.key = key;
59+
this.url = url;
60+
}
61+
}
62+
63+
class Model extends Node {}
64+
65+
class Seed extends Node {}
66+
class Test extends Node {
67+
// displayInModelTree = false;
68+
iconPath = {
69+
light: path.join(
70+
path.resolve(__dirname),
71+
"../media/images/source_light.svg",
72+
),
73+
dark: path.join(path.resolve(__dirname), "../media/images/source_dark.svg"),
74+
};
75+
}
76+
class Analysis extends Node {
77+
displayInModelTree = true;
78+
}
79+
class Exposure extends Node {
80+
displayInModelTree = true;
81+
}
82+
class Metric extends Node {
83+
displayInModelTree = false;
84+
}
85+
86+
class Snapshot extends Node {}
87+
88+
class Source extends Node {
89+
iconPath = {
90+
light: path.join(
91+
path.resolve(__dirname),
92+
"../media/images/source_light.svg",
93+
),
94+
dark: path.join(path.resolve(__dirname), "../media/images/source_dark.svg"),
95+
};
96+
}
97+
4598
@provide(ModelTreeviewProvider)
4699
abstract class ModelTreeviewProvider
47100
implements TreeDataProvider<NodeTreeItem>, Disposable
@@ -129,6 +182,33 @@ abstract class ModelTreeviewProvider
129182
return Promise.resolve(this.getTreeItems(model.uniqueId, event));
130183
}
131184

185+
private nodeDataToNode(nodeData: NodeData): Node | undefined {
186+
const resourceType = nodeData.resourceType;
187+
switch (resourceType) {
188+
case "snapshot":
189+
return new Snapshot(nodeData.label, nodeData.key, nodeData.url);
190+
case "exposure":
191+
return new Exposure(nodeData.label, nodeData.key, nodeData.url);
192+
case "analysis":
193+
return new Analysis(nodeData.label, nodeData.key, nodeData.url);
194+
case "test":
195+
return new Test(nodeData.label, nodeData.key, nodeData.url);
196+
case "source":
197+
return new Source(nodeData.label, nodeData.key, nodeData.url);
198+
case "seed":
199+
return new Seed(nodeData.label, nodeData.key, nodeData.url);
200+
case "semantic_model":
201+
return new Metric(nodeData.label, nodeData.key, nodeData.url);
202+
case "model":
203+
return new Model(nodeData.label, nodeData.key, nodeData.url);
204+
default:
205+
console.log(
206+
`Resource Type '${resourceType}' not implemented in ModelTreeviewProvider.nodeDataToNode`,
207+
);
208+
return undefined;
209+
}
210+
}
211+
132212
private getNodeTreeItem(node: Node): NodeTreeItem {
133213
if (node instanceof Snapshot) {
134214
return new SnapshotTreeItem(node);
@@ -161,11 +241,15 @@ abstract class ModelTreeviewProvider
161241
return [];
162242
}
163243
return parentModels.nodes
164-
.filter((node) => node.displayInModelTree)
244+
.flatMap((nodeData) => {
245+
const node = this.nodeDataToNode(nodeData);
246+
return node && node.displayInModelTree ? [node] : [];
247+
})
165248
.map((node) => {
166249
const childNodes = graphMetaMap[this.treeType]
167250
.get(node.key)
168-
?.nodes.filter((node) => node.displayInModelTree);
251+
?.nodes.map((nodeData) => this.nodeDataToNode(nodeData))
252+
.filter((node) => node && node.displayInModelTree);
169253

170254
const treeItem = this.getNodeTreeItem(node);
171255
treeItem.collapsibleState =

0 commit comments

Comments
 (0)