Skip to content

Commit

Permalink
Engine: Handle nodes without calculate function #313
Browse files Browse the repository at this point in the history
  • Loading branch information
newcat committed Nov 1, 2023
1 parent bd9a997 commit 15a45c4
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 15 deletions.
46 changes: 31 additions & 15 deletions packages/engine/src/dependencyEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,23 @@ export class DependencyEngine<CalculationData = any> extends BaseEngine<Calculat

const result: CalculationResult = new Map();
for (const n of calculationOrder) {
if (!n.calculate) {
continue;
}

const inputsForNode: Record<string, any> = {};
Object.entries(n.inputs).forEach(([k, v]) => {
if (!inputs.has(v.id)) {
throw new Error(
`Could not find value for interface ${v.id}\n` +
"This is likely a Baklava internal issue. Please report it on GitHub.",
);
}
inputsForNode[k] = inputs.get(v.id);
inputsForNode[k] = this.getInterfaceValue(inputs, v.id);
});

this.events.beforeNodeCalculation.emit({ inputValues: inputsForNode, node: n });
const r = await n.calculate(inputsForNode, { globalValues: calculationData, engine: this });

let r: any;
if (n.calculate) {
r = await n.calculate(inputsForNode, { globalValues: calculationData, engine: this });
} else {
r = {};
for (const [k, intf] of Object.entries(n.outputs)) {
r[k] = this.getInterfaceValue(inputs, intf.id);
}
}

this.validateNodeCalculationOutput(n, r);
this.events.afterNodeCalculation.emit({ outputValues: r, node: n });

Expand Down Expand Up @@ -85,17 +85,23 @@ export class DependencyEngine<CalculationData = any> extends BaseEngine<Calculat
this.recalculateOrder = false;
}

// gather all values of the unconnected inputs
// Gather all values of the unconnected inputs.
// maps NodeInterface.id -> value
// the reason it is done here and not during calculation is that this
// way we prevent race conditions because calculations can be async
// The reason it is done here and not during calculation is
// that this way we prevent race conditions because calculations can be async.
// For the same reason, we need to gather all output values for nodes that do not have a calculate function.
const inputValues = new Map<string, any>();
for (const n of this.editor.graph.nodes) {
Object.values(n.inputs).forEach((ni) => {
if (ni.connectionCount === 0) {
inputValues.set(ni.id, ni.value);
}
});
if (!n.calculate) {
Object.values(n.outputs).forEach((ni) => {
inputValues.set(ni.id, ni.value);
});
}
}

return await this.runGraph(this.editor.graph, inputValues, calculationData);
Expand All @@ -105,4 +111,14 @@ export class DependencyEngine<CalculationData = any> extends BaseEngine<Calculat
this.recalculateOrder = recalculateOrder || this.recalculateOrder;
void this.calculateWithoutData();
}

private getInterfaceValue(values: Map<string, any>, id: string): any {
if (!values.has(id)) {
throw new Error(
`Could not find value for interface ${id}\n` +
"This is likely a Baklava internal issue. Please report it on GitHub.",
);
}
return values.get(id);
}
}
13 changes: 13 additions & 0 deletions packages/engine/test/__snapshots__/dependencyEngine.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`DependencyEngine handles nodes without calculate functions 1`] = `
Map {
"3595507a-28e8-4dac-a536-82f1cfb9b7cf" => Map {
"a" => 3,
},
"1ed1bcb1-6582-4606-9336-32c69330e8d1" => Map {
"c" => 4,
"d" => 2,
},
}
`;
18 changes: 18 additions & 0 deletions packages/engine/test/dependencyEngine.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,22 @@ describe("DependencyEngine", () => {

expect(spy).toHaveBeenCalledWith([2, 0]);
});

it("handles nodes without calculate functions", async () => {
const editor = new Editor();
const NoCalculateNode = defineNode({
type: "NoCalculateNode",
outputs: {
a: () => new NodeInterface("a", 3),
}
});
const n1 = editor.graph.addNode(new NoCalculateNode())!;
const n2 = editor.graph.addNode(new TestNode())!;
editor.graph.addConnection(n1.outputs.a, n2.inputs.a);

const engine = new DependencyEngine<void>(editor);
const result = await engine.runOnce();

expect(result).toMatchSnapshot();
});
});

0 comments on commit 15a45c4

Please sign in to comment.