Compare commits

..

2 Commits

Author SHA1 Message Date
Hassan Abedi
751ef2e47e WIP 2026-06-05 13:06:06 +02:00
Hassan Abedi
07dab90bd6 WIP 2026-06-05 13:05:27 +02:00
17 changed files with 380 additions and 20 deletions

View File

@ -129,7 +129,7 @@ fn row_count(storage: &GeomergeStorage, table: &str) -> Result<usize, StorageErr
#[allow(clippy::expect_used, clippy::unwrap_used)] #[allow(clippy::expect_used, clippy::unwrap_used)]
mod tests { mod tests {
use super::{ use super::{
add_paths_data, load_paths_theory, row_count, run_demo, GeomergeStorage, Storage, Value, GeomergeStorage, Storage, Value, add_paths_data, load_paths_theory, row_count, run_demo,
}; };
#[test] #[test]

View File

@ -29,6 +29,14 @@ The exporter (`tools/exporter`) is the only producer of runner IR today;
it's where atoms are planned and rejected if they don't fit the supported subset. it's where atoms are planned and rejected if they don't fit the supported subset.
Fixtures are regenerated with `make export-fixtures`, and the full loop is `make examples`. Fixtures are regenerated with `make export-fixtures`, and the full loop is `make examples`.
What happens inside the runner once a JSON plan arrives:
<div align="center">
<picture>
<img alt="Workflow" src="docs/diagrams/workflow.svg" height="90%" width="90%">
</picture>
</div>
### Backends ### Backends
The CLI takes a `--backend` flag. The CLI takes a `--backend` flag.

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

View File

@ -35,12 +35,12 @@ use std::collections::HashMap;
use serde::Deserialize; use serde::Deserialize;
use query_ops::atom::{scan_atom, AtomPattern, Term}; use query_ops::atom::{AtomPattern, Term, scan_atom};
use query_ops::join::{natural_join, semijoin}; use query_ops::join::{natural_join, semijoin};
use query_ops::relation::Relation; use query_ops::relation::Relation;
use storage::table::Table; use storage::table::Table;
use storage::value::Value; use storage::value::Value;
use storage::{scan_as_table, Storage, StorageError}; use storage::{Storage, StorageError, scan_as_table};
/// A single fixture: schema, ground facts, and a query plan to execute. /// A single fixture: schema, ground facts, and a query plan to execute.
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]

View File

@ -19,7 +19,8 @@ use std::collections::HashMap;
use std::io::{self, Read}; use std::io::{self, Read};
use std::process::ExitCode; use std::process::ExitCode;
use plan_runner::{build_tables, build_tables_via_storage, execute, parse_plan, JsonValue, Plan}; use plan_runner::{JsonValue, Plan, build_tables, build_tables_via_storage, execute, parse_plan};
use storage::MemoryStorage;
use storage::adapters::fjall::FjallStorage; use storage::adapters::fjall::FjallStorage;
use storage::adapters::geomerge::{ColumnKind, GeomergeStorage}; use storage::adapters::geomerge::{ColumnKind, GeomergeStorage};
use storage::adapters::lmdb::LmdbStorage; use storage::adapters::lmdb::LmdbStorage;
@ -27,7 +28,6 @@ use storage::adapters::redb::RedbStorage;
use storage::adapters::sqlite::SqliteStorage; use storage::adapters::sqlite::SqliteStorage;
use storage::table::Table; use storage::table::Table;
use storage::value::Value; use storage::value::Value;
use storage::MemoryStorage;
use tempfile::TempDir; use tempfile::TempDir;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]

View File

@ -8,8 +8,8 @@
//! with a different `S`. //! with a different `S`.
use plan_runner::{build_tables, build_tables_via_storage, execute, parse_plan, run_json}; use plan_runner::{build_tables, build_tables_via_storage, execute, parse_plan, run_json};
use storage::value::Value;
use storage::MemoryStorage; use storage::MemoryStorage;
use storage::value::Value;
const FIXTURE: &str = include_str!("../fixtures/three_atom_chain.json"); const FIXTURE: &str = include_str!("../fixtures/three_atom_chain.json");

View File

@ -13,7 +13,7 @@
//! bestsellers via a semijoin against `bestseller`, then attaches each book's //! bestsellers via a semijoin against `bestseller`, then attaches each book's
//! price via a natural join against `price`. //! price via a natural join against `price`.
use query_ops::atom::{scan_atom, AtomPattern, Term}; use query_ops::atom::{AtomPattern, Term, scan_atom};
use query_ops::join::{natural_join, semijoin}; use query_ops::join::{natural_join, semijoin};
use storage::table::Table; use storage::table::Table;
use storage::value::Value; use storage::value::Value;

View File

@ -4,10 +4,10 @@
//! Demonstrates that `query-ops` operators can consume from a storage backend //! Demonstrates that `query-ops` operators can consume from a storage backend
//! through the [`scan_as_table`] bridge, with no changes to `query-ops` itself. //! through the [`scan_as_table`] bridge, with no changes to `query-ops` itself.
use query_ops::atom::{scan_atom, AtomPattern, Term}; use query_ops::atom::{AtomPattern, Term, scan_atom};
use storage::table::Table; use storage::table::Table;
use storage::value::Value; use storage::value::Value;
use storage::{scan_as_table, MemoryStorage, Storage, StorageError}; use storage::{MemoryStorage, Storage, StorageError, scan_as_table};
fn i(x: i64) -> Value { fn i(x: i64) -> Value {
Value::Int(x) Value::Int(x)

View File

@ -18,7 +18,7 @@
#![allow(clippy::unwrap_used, clippy::expect_used)] #![allow(clippy::unwrap_used, clippy::expect_used)]
use criterion::{black_box, criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion}; use criterion::{BatchSize, BenchmarkId, Criterion, black_box, criterion_group, criterion_main};
use storage::value::Value; use storage::value::Value;
use storage::{MemoryStorage, Storage}; use storage::{MemoryStorage, Storage};

View File

@ -19,7 +19,7 @@
#![allow(clippy::unwrap_used, clippy::expect_used)] #![allow(clippy::unwrap_used, clippy::expect_used)]
use criterion::{black_box, criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion}; use criterion::{BatchSize, BenchmarkId, Criterion, black_box, criterion_group, criterion_main};
use geomerge::ir::FlatTheory; use geomerge::ir::FlatTheory;
use storage::adapters::geomerge::GeomergeStorage; use storage::adapters::geomerge::GeomergeStorage;
use storage::id::RowId; use storage::id::RowId;

View File

@ -16,7 +16,7 @@ use fjall::{Keyspace, PartitionCreateOptions, PartitionHandle};
use crate::codec::{decode_meta, decode_row, encode_meta, encode_row}; use crate::codec::{decode_meta, decode_row, encode_meta, encode_row};
use crate::id::RowId; use crate::id::RowId;
use crate::value::Value; use crate::value::Value;
use crate::{backend, CommittedTx, RowStream, Storage, StorageError, Transaction}; use crate::{CommittedTx, RowStream, Storage, StorageError, Transaction, backend};
const META_PARTITION: &str = "__meta"; const META_PARTITION: &str = "__meta";
@ -176,7 +176,7 @@ impl Transaction for FjallTx<'_> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{backend, FjallStorage}; use super::{FjallStorage, backend};
use crate::value::Value; use crate::value::Value;
use crate::{Storage, StorageError}; use crate::{Storage, StorageError};

View File

@ -43,7 +43,7 @@ use geomerge::txn::ops::{RowRef, TempRowId, TxnCellValue};
use crate::id::RowId; use crate::id::RowId;
use crate::value::Value; use crate::value::Value;
use crate::{backend, CommittedTx, RowStream, Storage, StorageError, Transaction}; use crate::{CommittedTx, RowStream, Storage, StorageError, Transaction, backend};
const GM_ROW_ID_LEN: usize = 32 + 4; const GM_ROW_ID_LEN: usize = 32 + 4;
const PENDING_ROW_ID_LEN: usize = 4; const PENDING_ROW_ID_LEN: usize = 4;

View File

@ -16,7 +16,7 @@ use heed::{Database, Env, EnvOpenOptions, RwTxn};
use crate::codec::{decode_meta, decode_row, encode_meta, encode_row, row_key}; use crate::codec::{decode_meta, decode_row, encode_meta, encode_row, row_key};
use crate::id::RowId; use crate::id::RowId;
use crate::value::Value; use crate::value::Value;
use crate::{backend, CommittedTx, RowStream, Storage, StorageError, Transaction}; use crate::{CommittedTx, RowStream, Storage, StorageError, Transaction, backend};
const META_DB: &str = "__meta"; const META_DB: &str = "__meta";
const DEFAULT_MAX_DBS: u32 = 128; const DEFAULT_MAX_DBS: u32 = 128;
@ -245,7 +245,7 @@ impl Transaction for LmdbTx<'_> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{backend, LmdbStorage}; use super::{LmdbStorage, backend};
use crate::value::Value; use crate::value::Value;
use crate::{Storage, StorageError}; use crate::{Storage, StorageError};

View File

@ -15,7 +15,7 @@ use redb::{Database, ReadableTable, TableDefinition, WriteTransaction};
use crate::codec::{decode_meta, decode_row, encode_meta, encode_row}; use crate::codec::{decode_meta, decode_row, encode_meta, encode_row};
use crate::id::RowId; use crate::id::RowId;
use crate::value::Value; use crate::value::Value;
use crate::{backend, CommittedTx, RowStream, Storage, StorageError, Transaction}; use crate::{CommittedTx, RowStream, Storage, StorageError, Transaction, backend};
const META_TABLE: &str = "__meta"; const META_TABLE: &str = "__meta";
@ -199,7 +199,7 @@ impl Transaction for RedbTx {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{backend, RedbStorage}; use super::{RedbStorage, backend};
use crate::value::Value; use crate::value::Value;
use crate::{Storage, StorageError}; use crate::{Storage, StorageError};

View File

@ -14,12 +14,12 @@
use std::collections::HashMap; use std::collections::HashMap;
use rusqlite::{params, Connection, OptionalExtension}; use rusqlite::{Connection, OptionalExtension, params};
use crate::codec::{decode_row, encode_row}; use crate::codec::{decode_row, encode_row};
use crate::id::RowId; use crate::id::RowId;
use crate::value::Value; use crate::value::Value;
use crate::{backend, CommittedTx, RowStream, Storage, StorageError, Transaction}; use crate::{CommittedTx, RowStream, Storage, StorageError, Transaction, backend};
const SCHEMA_SQL: &str = " const SCHEMA_SQL: &str = "
CREATE TABLE IF NOT EXISTS __meta ( CREATE TABLE IF NOT EXISTS __meta (