rindle/op/mod.rs
1//! Spec `06`/`07` operators implemented **outside `graph.rs`** — the operator
2//! **fan-out seam**.
3//!
4//! ## Why this module exists
5//!
6//! Operators are variants of the closed `graph::Operator` enum, and `Graph`
7//! dispatches `fetch`/`push`/`input_schema`/… over it. That enum + its match sites
8//! are a single file: if every operator's *logic* also lived in `graph.rs`, N
9//! agents each implementing one operator would all edit the same file and collide.
10//!
11//! The seam (the decision in the prep wave) keeps each operator's struct **and all
12//! its logic** in its own file here (`op/<name>.rs`), and leaves only **thin,
13//! stable wiring** in `graph.rs`:
14//!
15//! 1. one `Operator::<Name>(<Name>)` enum variant,
16//! 2. a **delegating** arm in each dispatch fn — `Op::<Name>(o) => o.fetch(self,
17//! req)` / `o.push(self, change)`,
18//! 3. a typed `input_schema` arm (pass-through for the non-reshaping operators),
19//! 4. an `add_<name>(<Name>) -> NodeId` builder that takes a **fully-constructed
20//! value** — so changing the struct's fields never changes `graph.rs`.
21//!
22//! The operator drives the graph through the `pub(crate)` Graph API:
23//! [`Graph::fetch`](crate::graph::Graph::fetch),
24//! `Graph::push`,
25//! `Graph::input_schema`, and [`Graph::storage`](crate::graph::Graph) (stateful
26//! operators get a [`StorageId`](crate::graph::StorageId) from
27//! `Graph::alloc_storage`).
28//!
29//! ## Adding an operator (the template)
30//!
31//! [`Skip`] is the worked example. To add `Take`/`Cap`/`Exists`/`FlippedJoin`/
32//! `UnionFanOut`/`UnionFanIn`:
33//!
34//! 1. Copy `skip.rs` → `op/<name>.rs`; define the struct (fields private to the
35//! module — grow them freely) and `impl` its `fetch`/`push` (+ the filter-chain
36//! methods if it's a chain link like `Exists`). Stateful operators store a
37//! `StorageId` and read state via `g.storage(id)`.
38//! 2. Add the four wiring lines to `graph.rs` (variant + the two delegating arms +
39//! the `input_schema` arm; plus the `set_output` arm and `add_<name>` builder).
40//! 3. `mod <name>; pub use <name>::<Name>;` here.
41//!
42//! Two agents adding two operators touch **disjoint files** plus a handful of
43//! distinct, auto-mergeable lines in `graph.rs` — not the same match arm. That is
44//! what makes the operator port fan out.
45
46pub(crate) mod join_util;
47pub(crate) use join_util::{is_join_match, row_equals_for_compound_key};
48
49mod merge;
50pub(crate) use merge::merge_node_streams;
51
52mod partition;
53
54mod skip;
55pub use skip::Skip;
56
57mod take;
58pub use take::Take;
59
60mod cap;
61pub use cap::Cap;
62
63mod exists;
64pub use exists::Exists;
65
66mod flipped_join;
67#[cfg(any(test, feature = "testkit"))]
68pub use flipped_join::set_multi_constraint_chunk_size_for_test;
69pub use flipped_join::FlippedJoin;
70
71mod union;
72pub use union::{UnionFanIn, UnionFanOut};
73
74mod reduce;
75pub use reduce::{AggSpec, Reduce};