This commit is contained in:
Hassan Abedi 2026-06-05 13:05:27 +02:00
parent fa9f2ce50e
commit 07dab90bd6
3 changed files with 352 additions and 0 deletions

View File

@ -0,0 +1,14 @@
#!/usr/bin/env bash
# You need to have Graphviz installed to run this script
# On Debian-based OSes, you can install it using: sudo apt-get install graphviz
# Directory containing .dot files. Defaults to the script's own directory so the
# script works regardless of the caller's working directory.
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
ASSET_DIR=${1:-"${SCRIPT_DIR}"}
# Make figures from .dot files
for f in "${ASSET_DIR}"/*.dot; do
dot -Tsvg "$f" -o "${f%.dot}.svg"
done

View File

@ -0,0 +1,136 @@
digraph PlanRunnerWorkflow {
fontname = "Helvetica,Arial,sans-serif"
layout = dot
rankdir = LR
ranksep = 0.9;
nodesep = 0.7;
splines = true;
compound = true;
bgcolor = "white"
node [
fontname = "Helvetica,Arial,sans-serif",
shape = box,
style = "filled,rounded",
color = "#555555",
fillcolor = "white",
penwidth = 1.5
]
edge [
fontname = "Helvetica,Arial,sans-serif",
color = "#333333",
fontsize = 9,
fontcolor = "#555555",
labeldistance = 2.0,
penwidth = 1.2
]
subgraph cluster_input {
label = "Input"
style = "dashed"
color = "#888888"
fontcolor = "#555555"
margin = 18
json_plan [label = <<table border="0" cellborder="0" cellspacing="0" cellpadding="4">
<tr><td align="center"><b>JSON Plan</b></td></tr>
<tr><td align="left" balign="left">• schema: name -&gt; arity</td></tr>
<tr><td align="left" balign="left">• facts: name -&gt; rows</td></tr>
<tr><td align="left" balign="left">• query: { root, nodes }</td></tr>
<tr><td align="left" balign="left">• expected_bindings (optional oracle)</td></tr>
</table>>, fillcolor = "#E8F4FD", color = "#2196F3"]
}
subgraph cluster_parse {
label = "Parse"
style = "dashed"
color = "#9C27B0"
fontcolor = "#7B1FA2"
margin = 14
parse_plan [label = "parse_plan(json)\n-&gt; Plan", fillcolor = "#F3E5F5", color = "#9C27B0"]
}
subgraph cluster_load {
label = "Load Tables (--backend selects the path)"
style = "dashed"
color = "#4CAF50"
fontcolor = "#388E3C"
margin = 14
build_pure [label = <<table border="0" cellborder="0" cellspacing="0" cellpadding="4">
<tr><td align="center"><b>build_tables(plan)</b></td></tr>
<tr><td align="left" balign="left">--backend memory</td></tr>
<tr><td align="left" balign="left">direct from plan.facts</td></tr>
</table>>, fillcolor = "#E8F5E9", color = "#4CAF50"]
build_storage [label = <<table border="0" cellborder="0" cellspacing="0" cellpadding="4">
<tr><td align="center"><b>build_tables_via_storage&lt;S: Storage&gt;</b></td></tr>
<tr><td align="left" balign="left">--backend memory-storage</td></tr>
<tr><td align="left" balign="left">--backend lmdb / redb / fjall</td></tr>
<tr><td align="left" balign="left">--backend sqlite / geomerge</td></tr>
<tr><td align="left" balign="left">create_relation → tx.insert → scan_as_table</td></tr>
</table>>, fillcolor = "#E8F5E9", color = "#4CAF50"]
tables_map [label = <<table border="0" cellborder="0" cellspacing="0" cellpadding="4">
<tr><td align="center"><b>HashMap&lt;String, Table&gt;</b></td></tr>
<tr><td align="left" balign="left">positional rows per relation</td></tr>
</table>>, fillcolor = "#E8F4FD", color = "#2196F3"]
}
subgraph cluster_execute {
label = "Execute (walk node DAG in id order)"
style = "dashed"
color = "#FF9800"
fontcolor = "#F57C00"
margin = 14
execute_node [label = <<table border="0" cellborder="0" cellspacing="0" cellpadding="4">
<tr><td align="center"><b>execute(tables, query)</b></td></tr>
<tr><td align="left" balign="left">Action::Scan → scan_atom</td></tr>
<tr><td align="left" balign="left">Action::Join Left → semijoin(l, r)</td></tr>
<tr><td align="left" balign="left">Action::Join Right → semijoin(r, l)</td></tr>
<tr><td align="left" balign="left">Action::Join Natural → natural_join(l, r)</td></tr>
<tr><td align="left" balign="left">cache per-node Relation; return root</td></tr>
</table>>, fillcolor = "#FFF3E0", color = "#FF9800"]
relation_out [label = <<table border="0" cellborder="0" cellspacing="0" cellpadding="4">
<tr><td align="center"><b>Relation</b></td></tr>
<tr><td align="left" balign="left">columns: variables + wildcards</td></tr>
<tr><td align="left" balign="left">rows: bindings</td></tr>
</table>>, fillcolor = "#FFF3E0", color = "#FF9800"]
}
subgraph cluster_verify {
label = "Verify (when expected_bindings is present)"
style = "dashed"
color = "#9C27B0"
fontcolor = "#7B1FA2"
margin = 14
verify_node [label = <<table border="0" cellborder="0" cellspacing="0" cellpadding="4">
<tr><td align="center"><b>verify(plan, relation)</b></td></tr>
<tr><td align="left" balign="left">project to expected.columns</td></tr>
<tr><td align="left" balign="left">multiset compare against expected.rows</td></tr>
</table>>, fillcolor = "#F3E5F5", color = "#9C27B0"]
}
subgraph cluster_output {
label = "Output"
style = "dashed"
color = "#888888"
fontcolor = "#555555"
margin = 18
stdout_json [label = <<table border="0" cellborder="0" cellspacing="0" cellpadding="4">
<tr><td align="center"><b>stdout JSON</b></td></tr>
<tr><td align="left" balign="left">{ columns, rows }</td></tr>
</table>>, fillcolor = "#ECEFF1", color = "#607D8B"]
oracle_pass [label = "Ok(true) / VerifyError\n(used by tests/examples.rs)", fillcolor = "#ECEFF1", color = "#607D8B"]
}
// Pipeline edges
json_plan -> parse_plan [color = "#2196F3"]
parse_plan -> build_pure [label = "Backend::Memory", color = "#9C27B0"]
parse_plan -> build_storage [label = "Backend::*Storage", color = "#9C27B0"]
build_pure -> tables_map [color = "#4CAF50"]
build_storage -> tables_map [color = "#4CAF50"]
tables_map -> execute_node [color = "#2196F3"]
parse_plan -> execute_node [style = "dashed", label = "plan.query", color = "#9C27B0"]
execute_node -> relation_out [color = "#FF9800"]
relation_out -> stdout_json [color = "#607D8B"]
relation_out -> verify_node [style = "dashed", color = "#FF9800"]
parse_plan -> verify_node [style = "dashed", label = "plan.expected_bindings", color = "#9C27B0"]
verify_node -> oracle_pass [color = "#9C27B0"]
}

View File

@ -0,0 +1,202 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 12.2.1 (0)
-->
<!-- Title: PlanRunnerWorkflow Pages: 1 -->
<svg width="2495pt" height="593pt"
viewBox="0.00 0.00 2495.25 593.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 589)">
<title>PlanRunnerWorkflow</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-589 2491.25,-589 2491.25,4 -4,4"/>
<g id="clust1" class="cluster">
<title>cluster_input</title>
<polygon fill="white" stroke="#888888" stroke-dasharray="5,2" points="8,-126 8,-343 290,-343 290,-126 8,-126"/>
<text text-anchor="middle" x="149" y="-325.7" font-family="Helvetica,Arial,sans-serif" font-size="14.00" fill="#555555">Input</text>
</g>
<g id="clust2" class="cluster">
<title>cluster_parse</title>
<polygon fill="white" stroke="#9c27b0" stroke-dasharray="5,2" points="325,-181 325,-288 469.5,-288 469.5,-181 325,-181"/>
<text text-anchor="middle" x="397.25" y="-270.7" font-family="Helvetica,Arial,sans-serif" font-size="14.00" fill="#7b1fa2">Parse</text>
</g>
<g id="clust3" class="cluster">
<title>cluster_load</title>
<polygon fill="white" stroke="#4caf50" stroke-dasharray="5,2" points="584,-224 584,-577 1197.75,-577 1197.75,-224 584,-224"/>
<text text-anchor="middle" x="890.88" y="-559.7" font-family="Helvetica,Arial,sans-serif" font-size="14.00" fill="#388e3c">Load Tables &#160;(&#45;&#45;backend selects the path)</text>
</g>
<g id="clust4" class="cluster">
<title>cluster_execute</title>
<polygon fill="white" stroke="#ff9800" stroke-dasharray="5,2" points="1333.25,-122 1333.25,-361 1893.25,-361 1893.25,-122 1333.25,-122"/>
<text text-anchor="middle" x="1613.25" y="-343.7" font-family="Helvetica,Arial,sans-serif" font-size="14.00" fill="#f57c00">Execute &#160;(walk node DAG in id order)</text>
</g>
<g id="clust5" class="cluster">
<title>cluster_verify</title>
<polygon fill="white" stroke="#9c27b0" stroke-dasharray="5,2" points="1932.25,-8 1932.25,-159 2226.5,-159 2226.5,-8 1932.25,-8"/>
<text text-anchor="middle" x="2079.38" y="-141.7" font-family="Helvetica,Arial,sans-serif" font-size="14.00" fill="#7b1fa2">Verify &#160;(when expected_bindings is present)</text>
</g>
<g id="clust6" class="cluster">
<title>cluster_output</title>
<polygon fill="white" stroke="#888888" stroke-dasharray="5,2" points="2261.5,-37 2261.5,-268 2479.25,-268 2479.25,-37 2261.5,-37"/>
<text text-anchor="middle" x="2370.38" y="-250.7" font-family="Helvetica,Arial,sans-serif" font-size="14.00" fill="#555555">Output</text>
</g>
<!-- json_plan -->
<g id="node1" class="node">
<title>json_plan</title>
<path fill="#e8f4fd" stroke="#2196f3" stroke-width="1.5" d="M260,-296.12C260,-296.12 38,-296.12 38,-296.12 32,-296.12 26,-290.12 26,-284.12 26,-284.12 26,-155.88 26,-155.88 26,-149.88 32,-143.88 38,-143.88 38,-143.88 260,-143.88 260,-143.88 266,-143.88 272,-149.88 272,-155.88 272,-155.88 272,-284.12 272,-284.12 272,-290.12 266,-296.12 260,-296.12"/>
<text text-anchor="start" x="114.12" y="-275.82" font-family="Helvetica,Arial,sans-serif" font-weight="bold" font-size="14.00">JSON Plan</text>
<text text-anchor="start" x="38" y="-246.57" font-family="Helvetica,Arial,sans-serif" font-size="14.00">• schema: name &#45;&gt; arity</text>
<text text-anchor="start" x="38" y="-217.57" font-family="Helvetica,Arial,sans-serif" font-size="14.00">• facts: name &#45;&gt; rows</text>
<text text-anchor="start" x="38" y="-188.57" font-family="Helvetica,Arial,sans-serif" font-size="14.00">• query: { root, nodes }</text>
<text text-anchor="start" x="38" y="-159.57" font-family="Helvetica,Arial,sans-serif" font-size="14.00">• expected_bindings (optional oracle)</text>
</g>
<!-- parse_plan -->
<g id="node2" class="node">
<title>parse_plan</title>
<path fill="#f3e5f5" stroke="#9c27b0" stroke-width="1.5" d="M443.5,-245C443.5,-245 351,-245 351,-245 345,-245 339,-239 339,-233 339,-233 339,-207 339,-207 339,-201 345,-195 351,-195 351,-195 443.5,-195 443.5,-195 449.5,-195 455.5,-201 455.5,-207 455.5,-207 455.5,-233 455.5,-233 455.5,-239 449.5,-245 443.5,-245"/>
<text text-anchor="middle" x="397.25" y="-227.7" font-family="Helvetica,Arial,sans-serif" font-size="14.00">parse_plan(json)</text>
<text text-anchor="middle" x="397.25" y="-206.7" font-family="Helvetica,Arial,sans-serif" font-size="14.00">&#45;&gt; Plan</text>
</g>
<!-- json_plan&#45;&gt;parse_plan -->
<g id="edge1" class="edge">
<title>json_plan&#45;&gt;parse_plan</title>
<path fill="none" stroke="#2196f3" stroke-width="1.2" d="M272.4,-220C291.23,-220 310.09,-220 327.2,-220"/>
<polygon fill="#2196f3" stroke="#2196f3" stroke-width="1.2" points="326.93,-223.5 336.93,-220 326.93,-216.5 326.93,-223.5"/>
</g>
<!-- build_pure -->
<g id="node3" class="node">
<title>build_pure</title>
<path fill="#e8f5e9" stroke="#4caf50" stroke-width="1.5" d="M806.88,-534.12C806.88,-534.12 680.88,-534.12 680.88,-534.12 674.88,-534.12 668.88,-528.12 668.88,-522.12 668.88,-522.12 668.88,-451.88 668.88,-451.88 668.88,-445.88 674.88,-439.88 680.88,-439.88 680.88,-439.88 806.88,-439.88 806.88,-439.88 812.88,-439.88 818.88,-445.88 818.88,-451.88 818.88,-451.88 818.88,-522.12 818.88,-522.12 818.88,-528.12 812.88,-534.12 806.88,-534.12"/>
<text text-anchor="start" x="686.12" y="-513.83" font-family="Helvetica,Arial,sans-serif" font-weight="bold" font-size="14.00">build_tables(plan)</text>
<text text-anchor="start" x="680.88" y="-484.57" font-family="Helvetica,Arial,sans-serif" font-size="14.00">&#45;&#45;backend memory</text>
<text text-anchor="start" x="680.88" y="-455.57" font-family="Helvetica,Arial,sans-serif" font-size="14.00">direct from plan.facts</text>
</g>
<!-- parse_plan&#45;&gt;build_pure -->
<g id="edge2" class="edge">
<title>parse_plan&#45;&gt;build_pure</title>
<path fill="none" stroke="#9c27b0" stroke-width="1.2" d="M417.17,-245.45C448.23,-285.81 513.67,-365.05 584,-415 606.47,-430.96 633.04,-444.67 657.95,-455.71"/>
<polygon fill="#9c27b0" stroke="#9c27b0" stroke-width="1.2" points="656.28,-458.8 666.85,-459.56 659.06,-452.38 656.28,-458.8"/>
<text text-anchor="middle" x="526.75" y="-402.33" font-family="Helvetica,Arial,sans-serif" font-size="9.00" fill="#555555">Backend::Memory</text>
</g>
<!-- build_storage -->
<g id="node4" class="node">
<title>build_storage</title>
<path fill="#e8f5e9" stroke="#4caf50" stroke-width="1.5" d="M877.75,-390.12C877.75,-390.12 610,-390.12 610,-390.12 604,-390.12 598,-384.12 598,-378.12 598,-378.12 598,-249.88 598,-249.88 598,-243.88 604,-237.88 610,-237.88 610,-237.88 877.75,-237.88 877.75,-237.88 883.75,-237.88 889.75,-243.88 889.75,-249.88 889.75,-249.88 889.75,-378.12 889.75,-378.12 889.75,-384.12 883.75,-390.12 877.75,-390.12"/>
<text text-anchor="start" x="620.5" y="-369.82" font-family="Helvetica,Arial,sans-serif" font-weight="bold" font-size="14.00">build_tables_via_storage&lt;S: Storage&gt;</text>
<text text-anchor="start" x="610" y="-340.57" font-family="Helvetica,Arial,sans-serif" font-size="14.00">&#45;&#45;backend memory&#45;storage</text>
<text text-anchor="start" x="610" y="-311.57" font-family="Helvetica,Arial,sans-serif" font-size="14.00">&#45;&#45;backend lmdb / redb / fjall</text>
<text text-anchor="start" x="610" y="-282.57" font-family="Helvetica,Arial,sans-serif" font-size="14.00">&#45;&#45;backend sqlite / geomerge</text>
<text text-anchor="start" x="610" y="-253.57" font-family="Helvetica,Arial,sans-serif" font-size="14.00">create_relation → tx.insert → scan_as_table</text>
</g>
<!-- parse_plan&#45;&gt;build_storage -->
<g id="edge3" class="edge">
<title>parse_plan&#45;&gt;build_storage</title>
<path fill="none" stroke="#9c27b0" stroke-width="1.2" d="M455.93,-235.73C491.85,-245.53 539.94,-258.65 586.47,-271.34"/>
<polygon fill="#9c27b0" stroke="#9c27b0" stroke-width="1.2" points="585.3,-274.65 595.87,-273.9 587.14,-267.89 585.3,-274.65"/>
<text text-anchor="middle" x="526.75" y="-269.13" font-family="Helvetica,Arial,sans-serif" font-size="9.00" fill="#555555">Backend::*Storage</text>
</g>
<!-- execute_node -->
<g id="node6" class="node">
<title>execute_node</title>
<path fill="#fff3e0" stroke="#ff9800" stroke-width="1.5" d="M1591.75,-317.62C1591.75,-317.62 1359.25,-317.62 1359.25,-317.62 1353.25,-317.62 1347.25,-311.62 1347.25,-305.62 1347.25,-305.62 1347.25,-148.38 1347.25,-148.38 1347.25,-142.38 1353.25,-136.38 1359.25,-136.38 1359.25,-136.38 1591.75,-136.38 1591.75,-136.38 1597.75,-136.38 1603.75,-142.38 1603.75,-148.38 1603.75,-148.38 1603.75,-305.62 1603.75,-305.62 1603.75,-311.62 1597.75,-317.62 1591.75,-317.62"/>
<text text-anchor="start" x="1403.88" y="-297.32" font-family="Helvetica,Arial,sans-serif" font-weight="bold" font-size="14.00">execute(tables, query)</text>
<text text-anchor="start" x="1359.25" y="-268.07" font-family="Helvetica,Arial,sans-serif" font-size="14.00">Action::Scan &#160;→ scan_atom</text>
<text text-anchor="start" x="1359.25" y="-239.07" font-family="Helvetica,Arial,sans-serif" font-size="14.00">Action::Join Left &#160;→ semijoin(l, r)</text>
<text text-anchor="start" x="1359.25" y="-210.07" font-family="Helvetica,Arial,sans-serif" font-size="14.00">Action::Join Right → semijoin(r, l)</text>
<text text-anchor="start" x="1359.25" y="-181.07" font-family="Helvetica,Arial,sans-serif" font-size="14.00">Action::Join Natural → natural_join(l, r)</text>
<text text-anchor="start" x="1359.25" y="-152.07" font-family="Helvetica,Arial,sans-serif" font-size="14.00">cache per&#45;node Relation; return root</text>
</g>
<!-- parse_plan&#45;&gt;execute_node -->
<g id="edge7" class="edge">
<title>parse_plan&#45;&gt;execute_node</title>
<path fill="none" stroke="#9c27b0" stroke-width="1.2" stroke-dasharray="5,2" d="M455.98,-217.47C492.65,-215.87 541.11,-213.78 584,-212 753.85,-204.96 796.32,-193.74 966.25,-198.5 1091.19,-202 1233.2,-210.33 1335.29,-217.09"/>
<polygon fill="#9c27b0" stroke="#9c27b0" stroke-width="1.2" points="1334.89,-220.57 1345.1,-217.74 1335.35,-213.58 1334.89,-220.57"/>
<text text-anchor="middle" x="944.5" y="-203.45" font-family="Helvetica,Arial,sans-serif" font-size="9.00" fill="#555555">plan.query</text>
</g>
<!-- verify_node -->
<g id="node8" class="node">
<title>verify_node</title>
<path fill="#f3e5f5" stroke="#9c27b0" stroke-width="1.5" d="M2200.5,-116.12C2200.5,-116.12 1958.25,-116.12 1958.25,-116.12 1952.25,-116.12 1946.25,-110.12 1946.25,-104.12 1946.25,-104.12 1946.25,-33.88 1946.25,-33.88 1946.25,-27.88 1952.25,-21.88 1958.25,-21.88 1958.25,-21.88 2200.5,-21.88 2200.5,-21.88 2206.5,-21.88 2212.5,-27.88 2212.5,-33.88 2212.5,-33.88 2212.5,-104.12 2212.5,-104.12 2212.5,-110.12 2206.5,-116.12 2200.5,-116.12"/>
<text text-anchor="start" x="2014.88" y="-95.83" font-family="Helvetica,Arial,sans-serif" font-weight="bold" font-size="14.00">verify(plan, relation)</text>
<text text-anchor="start" x="1958.25" y="-66.58" font-family="Helvetica,Arial,sans-serif" font-size="14.00">project to expected.columns</text>
<text text-anchor="start" x="1958.25" y="-37.58" font-family="Helvetica,Arial,sans-serif" font-size="14.00">multiset compare against expected.rows</text>
</g>
<!-- parse_plan&#45;&gt;verify_node -->
<g id="edge11" class="edge">
<title>parse_plan&#45;&gt;verify_node</title>
<path fill="none" stroke="#9c27b0" stroke-width="1.2" stroke-dasharray="5,2" d="M428.8,-194.65C486.38,-149.53 616.55,-60 742.88,-60 742.88,-60 742.88,-60 1776,-60 1827.65,-60 1884.23,-61.33 1934.34,-62.96"/>
<polygon fill="#9c27b0" stroke="#9c27b0" stroke-width="1.2" points="1934.01,-66.45 1944.12,-63.29 1934.24,-59.46 1934.01,-66.45"/>
<text text-anchor="middle" x="1265.5" y="-64.95" font-family="Helvetica,Arial,sans-serif" font-size="9.00" fill="#555555">plan.expected_bindings</text>
</g>
<!-- tables_map -->
<g id="node5" class="node">
<title>tables_map</title>
<path fill="#e8f4fd" stroke="#2196f3" stroke-width="1.5" d="M1171.75,-346.62C1171.75,-346.62 1011.25,-346.62 1011.25,-346.62 1005.25,-346.62 999.25,-340.62 999.25,-334.62 999.25,-334.62 999.25,-293.38 999.25,-293.38 999.25,-287.38 1005.25,-281.38 1011.25,-281.38 1011.25,-281.38 1171.75,-281.38 1171.75,-281.38 1177.75,-281.38 1183.75,-287.38 1183.75,-293.38 1183.75,-293.38 1183.75,-334.62 1183.75,-334.62 1183.75,-340.62 1177.75,-346.62 1171.75,-346.62"/>
<text text-anchor="start" x="1012.38" y="-326.32" font-family="Helvetica,Arial,sans-serif" font-weight="bold" font-size="14.00">HashMap&lt;String, Table&gt;</text>
<text text-anchor="start" x="1011.25" y="-297.07" font-family="Helvetica,Arial,sans-serif" font-size="14.00">positional rows per relation</text>
</g>
<!-- build_pure&#45;&gt;tables_map -->
<g id="edge4" class="edge">
<title>build_pure&#45;&gt;tables_map</title>
<path fill="none" stroke="#4caf50" stroke-width="1.2" d="M819.36,-450.07C841.98,-438.83 866.89,-426.43 889.75,-415 931.06,-394.35 977.08,-371.2 1014.64,-352.28"/>
<polygon fill="#4caf50" stroke="#4caf50" stroke-width="1.2" points="1016.01,-355.5 1023.37,-347.88 1012.86,-349.25 1016.01,-355.5"/>
</g>
<!-- build_storage&#45;&gt;tables_map -->
<g id="edge5" class="edge">
<title>build_storage&#45;&gt;tables_map</title>
<path fill="none" stroke="#4caf50" stroke-width="1.2" d="M890.2,-314C922.86,-314 956.86,-314 987.38,-314"/>
<polygon fill="#4caf50" stroke="#4caf50" stroke-width="1.2" points="987.08,-317.5 997.08,-314 987.08,-310.5 987.08,-317.5"/>
</g>
<!-- tables_map&#45;&gt;execute_node -->
<g id="edge6" class="edge">
<title>tables_map&#45;&gt;execute_node</title>
<path fill="none" stroke="#2196f3" stroke-width="1.2" d="M1184,-293.16C1229.35,-282.83 1285.08,-270.14 1335.56,-258.64"/>
<polygon fill="#2196f3" stroke="#2196f3" stroke-width="1.2" points="1336.18,-262.09 1345.15,-256.46 1334.62,-255.27 1336.18,-262.09"/>
</g>
<!-- relation_out -->
<g id="node7" class="node">
<title>relation_out</title>
<path fill="#fff3e0" stroke="#ff9800" stroke-width="1.5" d="M1867.25,-246.12C1867.25,-246.12 1682.75,-246.12 1682.75,-246.12 1676.75,-246.12 1670.75,-240.12 1670.75,-234.12 1670.75,-234.12 1670.75,-163.88 1670.75,-163.88 1670.75,-157.88 1676.75,-151.88 1682.75,-151.88 1682.75,-151.88 1867.25,-151.88 1867.25,-151.88 1873.25,-151.88 1879.25,-157.88 1879.25,-163.88 1879.25,-163.88 1879.25,-234.12 1879.25,-234.12 1879.25,-240.12 1873.25,-246.12 1867.25,-246.12"/>
<text text-anchor="start" x="1748.38" y="-225.82" font-family="Helvetica,Arial,sans-serif" font-weight="bold" font-size="14.00">Relation</text>
<text text-anchor="start" x="1682.75" y="-196.57" font-family="Helvetica,Arial,sans-serif" font-size="14.00">columns: variables + wildcards</text>
<text text-anchor="start" x="1682.75" y="-167.57" font-family="Helvetica,Arial,sans-serif" font-size="14.00">rows: bindings</text>
</g>
<!-- execute_node&#45;&gt;relation_out -->
<g id="edge8" class="edge">
<title>execute_node&#45;&gt;relation_out</title>
<path fill="none" stroke="#ff9800" stroke-width="1.2" d="M1603.96,-215C1622.2,-213.29 1640.88,-211.53 1658.87,-209.84"/>
<polygon fill="#ff9800" stroke="#ff9800" stroke-width="1.2" points="1659.14,-213.33 1668.76,-208.9 1658.48,-206.36 1659.14,-213.33"/>
</g>
<!-- relation_out&#45;&gt;verify_node -->
<g id="edge10" class="edge">
<title>relation_out&#45;&gt;verify_node</title>
<path fill="none" stroke="#ff9800" stroke-width="1.2" stroke-dasharray="5,2" d="M1879.64,-154.44C1904.58,-143.72 1931.45,-132.17 1957.11,-121.13"/>
<polygon fill="#ff9800" stroke="#ff9800" stroke-width="1.2" points="1958.17,-124.49 1965.98,-117.32 1955.41,-118.06 1958.17,-124.49"/>
</g>
<!-- stdout_json -->
<g id="node9" class="node">
<title>stdout_json</title>
<path fill="#eceff1" stroke="#607d8b" stroke-width="1.5" d="M2422.12,-220.62C2422.12,-220.62 2318.62,-220.62 2318.62,-220.62 2312.62,-220.62 2306.62,-214.62 2306.62,-208.62 2306.62,-208.62 2306.62,-167.38 2306.62,-167.38 2306.62,-161.38 2312.62,-155.38 2318.62,-155.38 2318.62,-155.38 2422.12,-155.38 2422.12,-155.38 2428.12,-155.38 2434.12,-161.38 2434.12,-167.38 2434.12,-167.38 2434.12,-208.62 2434.12,-208.62 2434.12,-214.62 2428.12,-220.62 2422.12,-220.62"/>
<text text-anchor="start" x="2329.12" y="-200.32" font-family="Helvetica,Arial,sans-serif" font-weight="bold" font-size="14.00">stdout JSON</text>
<text text-anchor="start" x="2318.62" y="-171.07" font-family="Helvetica,Arial,sans-serif" font-size="14.00">{ columns, rows }</text>
</g>
<!-- relation_out&#45;&gt;stdout_json -->
<g id="edge9" class="edge">
<title>relation_out&#45;&gt;stdout_json</title>
<path fill="none" stroke="#607d8b" stroke-width="1.2" d="M1879.7,-197.08C1998.37,-194.88 2189.83,-191.33 2294.73,-189.38"/>
<polygon fill="#607d8b" stroke="#607d8b" stroke-width="1.2" points="2294.71,-192.88 2304.64,-189.2 2294.58,-185.89 2294.71,-192.88"/>
</g>
<!-- oracle_pass -->
<g id="node10" class="node">
<title>oracle_pass</title>
<path fill="#eceff1" stroke="#607d8b" stroke-width="1.5" d="M2449.25,-105C2449.25,-105 2291.5,-105 2291.5,-105 2285.5,-105 2279.5,-99 2279.5,-93 2279.5,-93 2279.5,-67 2279.5,-67 2279.5,-61 2285.5,-55 2291.5,-55 2291.5,-55 2449.25,-55 2449.25,-55 2455.25,-55 2461.25,-61 2461.25,-67 2461.25,-67 2461.25,-93 2461.25,-93 2461.25,-99 2455.25,-105 2449.25,-105"/>
<text text-anchor="middle" x="2370.38" y="-87.7" font-family="Helvetica,Arial,sans-serif" font-size="14.00">Ok(true) &#160;/ &#160;VerifyError</text>
<text text-anchor="middle" x="2370.38" y="-66.7" font-family="Helvetica,Arial,sans-serif" font-size="14.00">(used by tests/examples.rs)</text>
</g>
<!-- verify_node&#45;&gt;oracle_pass -->
<g id="edge12" class="edge">
<title>verify_node&#45;&gt;oracle_pass</title>
<path fill="none" stroke="#9c27b0" stroke-width="1.2" d="M2212.61,-74.03C2231.14,-74.74 2249.95,-75.45 2267.79,-76.13"/>
<polygon fill="#9c27b0" stroke="#9c27b0" stroke-width="1.2" points="2267.42,-79.62 2277.55,-76.5 2267.69,-72.63 2267.42,-79.62"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 18 KiB