1use reifydb_core::{
5 common::{JoinType, WindowKind},
6 interface::catalog::{
7 flow::{FlowEdgeId, FlowId, FlowNodeId},
8 id::{RingBufferId, SeriesId, SubscriptionId, TableId, ViewId},
9 series::SeriesKey,
10 shape::ShapeId,
11 },
12 sort::SortKey,
13};
14use reifydb_value::value::{dictionary::DictionaryId, duration::Duration};
15use serde::{Deserialize, Serialize};
16
17use crate::expression::Expression;
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub enum FlowNodeType {
21 SourceInlineData {},
22 SourceTable {
23 table: TableId,
24 },
25 SourceView {
26 view: ViewId,
27 },
28 SourceFlow {
29 flow: FlowId,
30 },
31 SourceRingBuffer {
32 ringbuffer: RingBufferId,
33 },
34 SourceSeries {
35 series: SeriesId,
36 },
37 Filter {
38 conditions: Vec<Expression>,
39 },
40 Gate {
41 conditions: Vec<Expression>,
42 },
43 Map {
44 expressions: Vec<Expression>,
45 },
46 Extend {
47 expressions: Vec<Expression>,
48 },
49 Join {
50 join_type: JoinType,
51 left: Vec<Expression>,
52 right: Vec<Expression>,
53 alias: Option<String>,
54 #[serde(default)]
55 snapshot: bool,
56 #[serde(default)]
57 natural: bool,
58 #[serde(default)]
59 latest: bool,
60 },
61 Aggregate {
62 by: Vec<Expression>,
63 map: Vec<Expression>,
64 },
65 Append {},
66 Sort {
67 by: Vec<SortKey>,
68 },
69 Take {
70 limit: usize,
71 },
72 Distinct {
73 expressions: Vec<Expression>,
74 },
75 Apply {
76 operator: String,
77 expressions: Vec<Expression>,
78 },
79 SinkTableView {
80 view: ViewId,
81 table: TableId,
82 },
83 SinkRingBufferView {
84 view: ViewId,
85 ringbuffer: RingBufferId,
86 capacity: u64,
87 propagate_evictions: bool,
88 },
89 SinkSeriesView {
90 view: ViewId,
91 series: SeriesId,
92 key: SeriesKey,
93 },
94 SinkSubscription {
95 subscription: SubscriptionId,
96 },
97 Window {
98 kind: WindowKind,
99 group_by: Vec<Expression>,
100 aggregations: Vec<Expression>,
101 ts: Option<String>,
102 lateness: Option<Duration>,
103 state_cache_size: Option<usize>,
104 internal_state_cache_size: Option<usize>,
105 },
106 SourceDictionary {
107 dictionary: DictionaryId,
108 },
109}
110
111impl FlowNodeType {
112 pub fn ticks(&self) -> bool {
113 matches!(
114 self,
115 FlowNodeType::Append { .. }
116 | FlowNodeType::Distinct { .. }
117 | FlowNodeType::Window { .. }
118 | FlowNodeType::Apply { .. } | FlowNodeType::Join { .. }
119 )
120 }
121
122 pub fn label(&self) -> String {
123 match self {
124 FlowNodeType::SourceInlineData {
125 ..
126 } => "SourceInlineData".into(),
127 FlowNodeType::SourceTable {
128 ..
129 } => "SourceTable".into(),
130 FlowNodeType::SourceView {
131 ..
132 } => "SourceView".into(),
133 FlowNodeType::SourceFlow {
134 ..
135 } => "SourceFlow".into(),
136 FlowNodeType::SourceRingBuffer {
137 ..
138 } => "SourceRingBuffer".into(),
139 FlowNodeType::SourceSeries {
140 ..
141 } => "SourceSeries".into(),
142 FlowNodeType::SourceDictionary {
143 ..
144 } => "SourceDictionary".into(),
145 FlowNodeType::Filter {
146 ..
147 } => "Filter".into(),
148 FlowNodeType::Gate {
149 ..
150 } => "Gate".into(),
151 FlowNodeType::Map {
152 ..
153 } => "Map".into(),
154 FlowNodeType::Extend {
155 ..
156 } => "Extend".into(),
157 FlowNodeType::Join {
158 ..
159 } => "Join".into(),
160 FlowNodeType::Aggregate {
161 ..
162 } => "Aggregate".into(),
163 FlowNodeType::Append {
164 ..
165 } => "Append".into(),
166 FlowNodeType::Sort {
167 ..
168 } => "Sort".into(),
169 FlowNodeType::Take {
170 ..
171 } => "Take".into(),
172 FlowNodeType::Distinct {
173 ..
174 } => "Distinct".into(),
175 FlowNodeType::Apply {
176 operator,
177 ..
178 } => format!("Apply({})", operator),
179 FlowNodeType::SinkTableView {
180 ..
181 } => "SinkTableView".into(),
182 FlowNodeType::SinkRingBufferView {
183 ..
184 } => "SinkRingBufferView".into(),
185 FlowNodeType::SinkSeriesView {
186 ..
187 } => "SinkSeriesView".into(),
188 FlowNodeType::SinkSubscription {
189 ..
190 } => "SinkSubscription".into(),
191 FlowNodeType::Window {
192 ..
193 } => "Window".into(),
194 }
195 }
196
197 pub fn discriminator(&self) -> u8 {
198 match self {
199 FlowNodeType::SourceInlineData {
200 ..
201 } => 0,
202 FlowNodeType::SourceTable {
203 ..
204 } => 1,
205 FlowNodeType::SourceView {
206 ..
207 } => 2,
208 FlowNodeType::SourceFlow {
209 ..
210 } => 3,
211 FlowNodeType::Filter {
212 ..
213 } => 4,
214 FlowNodeType::Map {
215 ..
216 } => 5,
217 FlowNodeType::Extend {
218 ..
219 } => 6,
220 FlowNodeType::Join {
221 ..
222 } => 7,
223 FlowNodeType::Aggregate {
224 ..
225 } => 8,
226 FlowNodeType::Append {
227 ..
228 } => 9,
229 FlowNodeType::Sort {
230 ..
231 } => 10,
232 FlowNodeType::Take {
233 ..
234 } => 11,
235 FlowNodeType::Distinct {
236 ..
237 } => 12,
238 FlowNodeType::Apply {
239 ..
240 } => 13,
241 FlowNodeType::SinkSubscription {
242 ..
243 } => 14,
244 FlowNodeType::Window {
245 ..
246 } => 15,
247 FlowNodeType::SourceRingBuffer {
248 ..
249 } => 16,
250 FlowNodeType::SourceSeries {
251 ..
252 } => 17,
253 FlowNodeType::Gate {
254 ..
255 } => 18,
256 FlowNodeType::SinkTableView {
257 ..
258 } => 19,
259 FlowNodeType::SinkRingBufferView {
260 ..
261 } => 20,
262 FlowNodeType::SinkSeriesView {
263 ..
264 } => 21,
265 FlowNodeType::SourceDictionary {
266 ..
267 } => 22,
268 }
269 }
270
271 pub fn primitive_source_shape_id(&self) -> Option<ShapeId> {
272 match self {
273 FlowNodeType::SourceTable {
274 table,
275 } => Some(ShapeId::table(*table)),
276 FlowNodeType::SourceRingBuffer {
277 ringbuffer,
278 } => Some(ShapeId::ringbuffer(*ringbuffer)),
279 FlowNodeType::SourceSeries {
280 series,
281 } => Some(ShapeId::series(*series)),
282 FlowNodeType::SourceDictionary {
283 dictionary,
284 } => Some(ShapeId::dictionary(*dictionary)),
285 FlowNodeType::SourceInlineData {
286 ..
287 }
288 | FlowNodeType::SourceView {
289 ..
290 }
291 | FlowNodeType::SourceFlow {
292 ..
293 }
294 | FlowNodeType::Filter {
295 ..
296 }
297 | FlowNodeType::Gate {
298 ..
299 }
300 | FlowNodeType::Map {
301 ..
302 }
303 | FlowNodeType::Extend {
304 ..
305 }
306 | FlowNodeType::Join {
307 ..
308 }
309 | FlowNodeType::Aggregate {
310 ..
311 }
312 | FlowNodeType::Append {
313 ..
314 }
315 | FlowNodeType::Sort {
316 ..
317 }
318 | FlowNodeType::Take {
319 ..
320 }
321 | FlowNodeType::Distinct {
322 ..
323 }
324 | FlowNodeType::Apply {
325 ..
326 }
327 | FlowNodeType::SinkTableView {
328 ..
329 }
330 | FlowNodeType::SinkRingBufferView {
331 ..
332 }
333 | FlowNodeType::SinkSeriesView {
334 ..
335 }
336 | FlowNodeType::SinkSubscription {
337 ..
338 }
339 | FlowNodeType::Window {
340 ..
341 } => None,
342 }
343 }
344}
345
346#[derive(Debug, Clone, Serialize, Deserialize)]
347pub struct FlowNode {
348 pub id: FlowNodeId,
349 pub ty: FlowNodeType,
350 pub inputs: Vec<FlowNodeId>,
351 pub outputs: Vec<FlowNodeId>,
352}
353
354impl FlowNode {
355 pub fn new(id: impl Into<FlowNodeId>, ty: FlowNodeType) -> Self {
356 Self {
357 id: id.into(),
358 ty,
359 inputs: Vec::new(),
360 outputs: Vec::new(),
361 }
362 }
363}
364
365#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
366pub struct FlowEdge {
367 pub id: FlowEdgeId,
368 pub source: FlowNodeId,
369 pub target: FlowNodeId,
370}
371
372impl FlowEdge {
373 pub fn new(id: impl Into<FlowEdgeId>, source: impl Into<FlowNodeId>, target: impl Into<FlowNodeId>) -> Self {
374 Self {
375 id: id.into(),
376 source: source.into(),
377 target: target.into(),
378 }
379 }
380}
381
382#[cfg(test)]
383mod tests {
384 use reifydb_core::common::JoinType;
385
386 use super::FlowNodeType;
387
388 fn join() -> FlowNodeType {
389 FlowNodeType::Join {
390 join_type: JoinType::Inner,
391 left: vec![],
392 right: vec![],
393 alias: None,
394 snapshot: false,
395 natural: false,
396 latest: false,
397 }
398 }
399
400 #[test]
401 fn join_always_requests_ticks() {
402 assert!(join().ticks());
405 }
406
407 #[test]
408 fn apply_always_requests_ticks() {
409 let apply = FlowNodeType::Apply {
415 operator: "compute_swap_volumes".to_string(),
416 expressions: vec![],
417 };
418 assert!(apply.ticks());
419 }
420
421 #[test]
422 fn append_and_distinct_always_request_ticks() {
423 assert!(FlowNodeType::Append {}.ticks());
427 assert!(FlowNodeType::Distinct {
428 expressions: vec![]
429 }
430 .ticks());
431 }
432
433 #[test]
434 fn stateless_nodes_do_not_request_ticks() {
435 assert!(!FlowNodeType::Map {
436 expressions: vec![]
437 }
438 .ticks());
439 assert!(!FlowNodeType::Filter {
440 conditions: vec![]
441 }
442 .ticks());
443 }
444}