1use std::mem;
5
6use reifydb_core::{
7 common::{JoinType, WindowKind},
8 interface::{
9 catalog::{
10 flow::{FlowId, FlowNodeId},
11 id::{RingBufferId, SeriesId, TableId, ViewId},
12 series::SeriesKey,
13 shape::ShapeId,
14 },
15 identifier::{ColumnIdentifier, ColumnShape},
16 },
17 value::column::columns::Columns,
18 window::engine::LatePolicy,
19};
20use reifydb_rql::{
21 expression::{ColumnExpression, Expression},
22 flow::{
23 flow::FlowDag,
24 node::{
25 FlowNode,
26 FlowNodeType::{
27 Aggregate, Append, Apply, Distinct, Extend, Filter, Gate, Join, Map,
28 SinkRingBufferView, SinkSeriesView, SinkSubscription, SinkTableView, Sort,
29 SourceDictionary, SourceFlow, SourceInlineData, SourceRingBuffer, SourceSeries,
30 SourceTable, SourceView, Take, Window,
31 },
32 },
33 },
34};
35use reifydb_sdk::config::Config;
36use reifydb_transaction::transaction::{Transaction, command::CommandTransaction};
37use reifydb_value::{
38 Result,
39 error::Error,
40 fragment::Fragment,
41 reifydb_assertions,
42 value::{dictionary::DictionaryId, duration::Duration},
43};
44use tracing::instrument;
45
46use super::eval::evaluate_operator_config;
47#[cfg(reifydb_target = "native")]
48use crate::operator::apply::ApplyOperator;
49use crate::{
50 engine::FlowEngineInner,
51 error::FlowGraphError,
52 operator::{
53 OperatorCell, Operators,
54 append::AppendOperator,
55 distinct::operator::DistinctOperator,
56 extend::ExtendOperator,
57 filter::FilterOperator,
58 gate::GateOperator,
59 join::operator::{JoinOperator, JoinSideConfig},
60 map::MapOperator,
61 scan::{
62 dictionary::PrimitiveDictionaryOperator, flow::PrimitiveFlowOperator,
63 ringbuffer::PrimitiveRingBufferOperator, series::PrimitiveSeriesOperator,
64 table::PrimitiveTableOperator, view::PrimitiveViewOperator,
65 },
66 sink::{
67 ringbuffer_view::SinkRingBufferViewOperator, series_view::SinkSeriesViewOperator,
68 view::SinkTableViewOperator,
69 },
70 sort::SortOperator,
71 take::TakeOperator,
72 window::{
73 aggregate::AggregateOperator,
74 operator::{WindowConfig, WindowOperator},
75 },
76 },
77};
78
79impl FlowEngineInner {
80 #[instrument(name = "flow::register", level = "info", skip(self, txn), fields(flow_id = ?flow.id))]
81 pub fn register(&mut self, txn: &mut CommandTransaction, flow: FlowDag) -> Result<()> {
82 self.register_with_transaction(&mut Transaction::Command(txn), flow)
83 }
84
85 #[instrument(name = "flow::register_with_transaction", level = "info", skip(self, txn), fields(flow_id = ?flow.id))]
86 pub fn register_with_transaction(&mut self, txn: &mut Transaction<'_>, flow: FlowDag) -> Result<()> {
87 reifydb_assertions! {
88 assert!(!self.flows.contains_key(&flow.id), "Flow already registered");
89 }
90
91 let mut added: Vec<FlowNodeId> = Vec::new();
92 for node_id in flow.topological_order()? {
93 let node = flow.get_node(&node_id).unwrap();
94 if let Err(err) = self.add(txn, &flow, node) {
95 for id in &added {
96 self.operators.remove(id);
97 }
98 for entries in self.sources.values_mut() {
99 entries.retain(|(fid, _)| *fid != flow.id);
100 }
101 self.sources.retain(|_, v| !v.is_empty());
102 for entries in self.sinks.values_mut() {
103 entries.retain(|(fid, _)| *fid != flow.id);
104 }
105 self.sinks.retain(|_, v| !v.is_empty());
106 return Err(err);
107 }
108 added.push(node_id);
109 }
110
111 self.analyzer.add(flow.clone());
112 self.flows.insert(flow.id, flow.clone());
113 self.execution_level_cache.invalidate();
114 self.schedule_cache.invalidate();
115
116 Ok(())
117 }
118
119 #[instrument(name = "flow::add", level = "debug", skip(self, txn, flow), fields(flow_id = ?flow.id, node_id = ?node.id, node_type = ?mem::discriminant(&node.ty)))]
120 pub fn add(&mut self, txn: &mut Transaction<'_>, flow: &FlowDag, node: &FlowNode) -> Result<()> {
121 reifydb_assertions! {
122 assert!(!self.operators.contains_key(&node.id), "Operator already registered");
123 }
124 let node = node.clone();
125 let node_id = node.id;
126 let inputs = node.inputs;
127
128 match node.ty {
129 SourceInlineData {
130 ..
131 } => unimplemented!(),
132 SourceTable {
133 table,
134 } => self.add_source_table(txn, flow, node_id, table)?,
135 SourceView {
136 view,
137 } => self.register_source_view(txn, flow, node_id, view)?,
138 SourceFlow {
139 flow: source_flow,
140 } => self.add_source_flow(txn, node_id, source_flow)?,
141 SourceRingBuffer {
142 ringbuffer,
143 } => self.add_source_ringbuffer(txn, flow, node_id, ringbuffer)?,
144 SourceSeries {
145 series,
146 } => self.add_source_series(txn, flow, node_id, series)?,
147 SourceDictionary {
148 dictionary,
149 } => self.add_source_dictionary(flow, node_id, dictionary),
150 SinkTableView {
151 view,
152 table,
153 } => self.add_sink_table_view(txn, flow, node_id, &inputs, view, table)?,
154 SinkRingBufferView {
155 view,
156 ringbuffer,
157 capacity,
158 propagate_evictions,
159 } => self.add_sink_ringbuffer_view(
160 txn,
161 flow,
162 node_id,
163 &inputs,
164 view,
165 ringbuffer,
166 capacity,
167 propagate_evictions,
168 )?,
169 SinkSeriesView {
170 view,
171 series,
172 key,
173 } => self.add_sink_series_view(txn, flow, node_id, &inputs, view, series, key)?,
174 SinkSubscription {
175 ..
176 } => {
177 return Err(Error::from(FlowGraphError::UnsupportedNode {
178 kind: "SinkSubscription",
179 }));
180 }
181 Filter {
182 conditions,
183 } => self.add_filter(node_id, &inputs, conditions)?,
184 Gate {
185 conditions,
186 } => self.add_gate(node_id, &inputs, conditions)?,
187 Map {
188 expressions,
189 } => self.add_map(node_id, &inputs, expressions)?,
190 Extend {
191 expressions,
192 } => self.add_extend(node_id, &inputs, expressions)?,
193 Sort {
194 by: _,
195 } => self.add_sort(node_id, &inputs)?,
196 Take {
197 limit,
198 } => self.add_take(node_id, &inputs, limit)?,
199 Join {
200 join_type,
201 left,
202 right,
203 alias,
204 snapshot,
205 natural,
206 latest,
207 } => self.add_join(
208 txn, node_id, &inputs, join_type, left, right, alias, snapshot, natural, latest,
209 )?,
210 Distinct {
211 expressions,
212 } => self.add_distinct(txn, node_id, &inputs, expressions)?,
213 Append {} => self.add_append(txn, node_id, &inputs)?,
214 Apply {
215 operator,
216 expressions,
217 } => self.add_apply(node_id, &inputs, operator, expressions)?,
218 Aggregate {
219 by,
220 map,
221 } => self.add_aggregate(node_id, &inputs, by, map)?,
222 Window {
223 kind,
224 group_by,
225 aggregations,
226 ts,
227 lateness,
228 state_cache_size,
229 internal_state_cache_size,
230 } => self.add_window(
231 node_id,
232 &inputs,
233 kind,
234 group_by,
235 aggregations,
236 ts,
237 lateness,
238 state_cache_size,
239 internal_state_cache_size,
240 )?,
241 }
242
243 Ok(())
244 }
245
246 #[inline]
247 fn add_source_table(
248 &mut self,
249 txn: &mut Transaction<'_>,
250 flow: &FlowDag,
251 node_id: FlowNodeId,
252 table: TableId,
253 ) -> Result<()> {
254 let table = self.catalog.get_table(&mut txn.reborrow(), table)?;
255
256 self.add_source(flow.id, node_id, ShapeId::table(table.id));
257 self.operators.insert(
258 node_id,
259 OperatorCell::new(Operators::SourceTable(PrimitiveTableOperator::new(node_id, table))),
260 );
261 Ok(())
262 }
263
264 #[inline]
265 fn add_source_flow(
266 &mut self,
267 txn: &mut Transaction<'_>,
268 node_id: FlowNodeId,
269 source_flow: FlowId,
270 ) -> Result<()> {
271 let source_flow = self.catalog.get_flow(&mut txn.reborrow(), source_flow)?;
272 self.operators.insert(
273 node_id,
274 OperatorCell::new(Operators::SourceFlow(PrimitiveFlowOperator::new(node_id, source_flow))),
275 );
276 Ok(())
277 }
278
279 #[inline]
280 fn add_source_ringbuffer(
281 &mut self,
282 txn: &mut Transaction<'_>,
283 flow: &FlowDag,
284 node_id: FlowNodeId,
285 ringbuffer: RingBufferId,
286 ) -> Result<()> {
287 let rb = self.catalog.get_ringbuffer(&mut txn.reborrow(), ringbuffer)?;
288 self.add_source(flow.id, node_id, ShapeId::ringbuffer(rb.id));
289 self.operators.insert(
290 node_id,
291 OperatorCell::new(Operators::SourceRingBuffer(PrimitiveRingBufferOperator::new(node_id, rb))),
292 );
293 Ok(())
294 }
295
296 #[inline]
297 fn add_source_series(
298 &mut self,
299 txn: &mut Transaction<'_>,
300 flow: &FlowDag,
301 node_id: FlowNodeId,
302 series: SeriesId,
303 ) -> Result<()> {
304 let s = self.catalog.get_series(&mut txn.reborrow(), series)?;
305 self.add_source(flow.id, node_id, ShapeId::series(s.id));
306 self.operators.insert(
307 node_id,
308 OperatorCell::new(Operators::SourceSeries(PrimitiveSeriesOperator::new(node_id))),
309 );
310 Ok(())
311 }
312
313 #[inline]
314 fn add_source_dictionary(&mut self, flow: &FlowDag, node_id: FlowNodeId, dictionary: DictionaryId) {
315 self.add_source(flow.id, node_id, ShapeId::dictionary(dictionary));
316 self.operators.insert(
317 node_id,
318 OperatorCell::new(Operators::SourceDictionary(PrimitiveDictionaryOperator::new(node_id))),
319 );
320 }
321
322 #[inline]
323 fn add_sink_table_view(
324 &mut self,
325 txn: &mut Transaction<'_>,
326 flow: &FlowDag,
327 node_id: FlowNodeId,
328 inputs: &[FlowNodeId],
329 view: ViewId,
330 table: TableId,
331 ) -> Result<()> {
332 let parent = self.parent(first_input(inputs)?)?;
333
334 self.add_sink(flow.id, node_id, ShapeId::view(*view));
335 let resolved = self.catalog.resolve_view(&mut txn.reborrow(), view)?;
336 self.operators.insert(
337 node_id,
338 OperatorCell::new(Operators::SinkTableView(SinkTableViewOperator::new(
339 parent, node_id, resolved, table,
340 ))),
341 );
342 Ok(())
343 }
344
345 #[inline]
346 #[allow(clippy::too_many_arguments)]
347 fn add_sink_ringbuffer_view(
348 &mut self,
349 txn: &mut Transaction<'_>,
350 flow: &FlowDag,
351 node_id: FlowNodeId,
352 inputs: &[FlowNodeId],
353 view: ViewId,
354 ringbuffer: RingBufferId,
355 capacity: u64,
356 propagate_evictions: bool,
357 ) -> Result<()> {
358 let parent = self.parent(first_input(inputs)?)?;
359 self.add_sink(flow.id, node_id, ShapeId::view(*view));
360 let resolved = self.catalog.resolve_view(&mut txn.reborrow(), view)?;
361 self.operators.insert(
362 node_id,
363 OperatorCell::new(Operators::SinkRingBufferView(SinkRingBufferViewOperator::new(
364 parent,
365 node_id,
366 resolved,
367 ringbuffer,
368 capacity,
369 propagate_evictions,
370 ))),
371 );
372 Ok(())
373 }
374
375 #[inline]
376 #[allow(clippy::too_many_arguments)]
377 fn add_sink_series_view(
378 &mut self,
379 txn: &mut Transaction<'_>,
380 flow: &FlowDag,
381 node_id: FlowNodeId,
382 inputs: &[FlowNodeId],
383 view: ViewId,
384 series: SeriesId,
385 key: SeriesKey,
386 ) -> Result<()> {
387 let parent = self.parent(first_input(inputs)?)?;
388 self.add_sink(flow.id, node_id, ShapeId::view(*view));
389 let resolved = self.catalog.resolve_view(&mut txn.reborrow(), view)?;
390 self.operators.insert(
391 node_id,
392 OperatorCell::new(Operators::SinkSeriesView(SinkSeriesViewOperator::new(
393 parent,
394 node_id,
395 resolved,
396 series,
397 key.clone(),
398 ))),
399 );
400 Ok(())
401 }
402
403 #[inline]
404 fn add_filter(
405 &mut self,
406 node_id: FlowNodeId,
407 inputs: &[FlowNodeId],
408 conditions: Vec<Expression>,
409 ) -> Result<()> {
410 let parent = self.parent(first_input(inputs)?)?;
411 self.operators.insert(
412 node_id,
413 OperatorCell::new(Operators::Filter(FilterOperator::new(
414 parent,
415 node_id,
416 conditions,
417 self.executor.routines.clone(),
418 self.runtime_context.clone(),
419 ))),
420 );
421 Ok(())
422 }
423
424 #[inline]
425 fn add_gate(&mut self, node_id: FlowNodeId, inputs: &[FlowNodeId], conditions: Vec<Expression>) -> Result<()> {
426 let parent = self.parent(first_input(inputs)?)?;
427 self.operators.insert(
428 node_id,
429 OperatorCell::new(Operators::Gate(GateOperator::new(
430 parent,
431 node_id,
432 conditions,
433 self.executor.routines.clone(),
434 self.runtime_context.clone(),
435 ))),
436 );
437 Ok(())
438 }
439
440 #[inline]
441 fn add_map(&mut self, node_id: FlowNodeId, inputs: &[FlowNodeId], expressions: Vec<Expression>) -> Result<()> {
442 let parent = self.parent(first_input(inputs)?)?;
443 self.operators.insert(
444 node_id,
445 OperatorCell::new(Operators::Map(MapOperator::new(
446 parent,
447 node_id,
448 expressions,
449 self.executor.routines.clone(),
450 self.runtime_context.clone(),
451 ))),
452 );
453 Ok(())
454 }
455
456 #[inline]
457 fn add_extend(
458 &mut self,
459 node_id: FlowNodeId,
460 inputs: &[FlowNodeId],
461 expressions: Vec<Expression>,
462 ) -> Result<()> {
463 let parent = self.parent(first_input(inputs)?)?;
464 self.operators.insert(
465 node_id,
466 OperatorCell::new(Operators::Extend(ExtendOperator::new(
467 parent,
468 node_id,
469 expressions,
470 self.executor.routines.clone(),
471 self.runtime_context.clone(),
472 ))),
473 );
474 Ok(())
475 }
476
477 #[inline]
478 fn add_sort(&mut self, node_id: FlowNodeId, inputs: &[FlowNodeId]) -> Result<()> {
479 let parent = self.parent(first_input(inputs)?)?;
480 self.operators.insert(
481 node_id,
482 OperatorCell::new(Operators::Sort(SortOperator::new(parent, node_id, Vec::new()))),
483 );
484 Ok(())
485 }
486
487 #[inline]
488 fn add_take(&mut self, node_id: FlowNodeId, inputs: &[FlowNodeId], limit: usize) -> Result<()> {
489 let parent = self.parent(first_input(inputs)?)?;
490 self.operators
491 .insert(node_id, OperatorCell::new(Operators::Take(TakeOperator::new(parent, node_id, limit))));
492 Ok(())
493 }
494
495 #[inline]
496 #[allow(clippy::too_many_arguments)]
497 fn add_join(
498 &mut self,
499 txn: &mut Transaction<'_>,
500 node_id: FlowNodeId,
501 inputs: &[FlowNodeId],
502 join_type: JoinType,
503 left: Vec<Expression>,
504 right: Vec<Expression>,
505 alias: Option<String>,
506 snapshot: bool,
507 natural: bool,
508 latest: bool,
509 ) -> Result<()> {
510 if inputs.len() != 2 {
511 return Err(Error::from(FlowGraphError::NodeInputArity {
512 node: "Join",
513 expected: "exactly 2",
514 found: inputs.len(),
515 }));
516 }
517
518 let left_node = inputs[0];
519 let right_node = inputs[1];
520
521 let left_parent = self
522 .operators
523 .get(&left_node)
524 .ok_or_else(|| {
525 Error::from(FlowGraphError::ParentOperatorNotFound {
526 input: "left parent".to_string(),
527 })
528 })?
529 .clone();
530
531 let right_parent = self
532 .operators
533 .get(&right_node)
534 .ok_or_else(|| {
535 Error::from(FlowGraphError::ParentOperatorNotFound {
536 input: "right parent".to_string(),
537 })
538 })?
539 .clone();
540
541 let left_schema = left_parent.output_schema().unwrap_or_default();
542 let right_schema =
543 right_parent.output_schema().expect("right side of join must have a statically known schema");
544
545 let (left_exprs, right_exprs) = if natural {
546 let common = common_column_names(&left_schema, &right_schema);
547 let keys: Vec<Expression> = common.iter().map(|name| natural_key_expr(name)).collect();
548 (keys.clone(), keys)
549 } else {
550 (left, right)
551 };
552
553 let join_ttl = self.catalog.find_operator_settings(txn, node_id)?.and_then(|s| s.join);
554 let left = join_ttl.as_ref().and_then(|j| j.left.as_ref());
555 let left_ttl = left.map(|t| t.duration);
556 let right = join_ttl.as_ref().and_then(|j| j.right.as_ref());
557 let right_ttl = right.map(|t| t.duration);
558
559 self.operators.insert(
560 node_id,
561 OperatorCell::new(Operators::Join(JoinOperator::new(
562 JoinSideConfig {
563 schema: left_schema,
564 node: left_node,
565 exprs: left_exprs,
566 },
567 JoinSideConfig {
568 schema: right_schema,
569 node: right_node,
570 exprs: right_exprs,
571 },
572 node_id,
573 join_type,
574 alias,
575 self.executor.clone(),
576 snapshot,
577 natural,
578 latest,
579 left_ttl,
580 right_ttl,
581 ))),
582 );
583 Ok(())
584 }
585
586 #[inline]
587 fn add_distinct(
588 &mut self,
589 txn: &mut Transaction<'_>,
590 node_id: FlowNodeId,
591 inputs: &[FlowNodeId],
592 expressions: Vec<Expression>,
593 ) -> Result<()> {
594 let parent = self.parent(first_input(inputs)?)?;
595 let ttl = self.catalog.find_operator_settings(txn, node_id)?.and_then(|s| s.ttl);
596 self.operators.insert(
597 node_id,
598 OperatorCell::new(Operators::Distinct(DistinctOperator::new(
599 parent,
600 node_id,
601 expressions,
602 self.executor.routines.clone(),
603 self.runtime_context.clone(),
604 ttl.map(|t| {
605 t.duration.as_nanos().expect("operator ttl duration fits in i64 nanoseconds")
606 as u64
607 }),
608 ))),
609 );
610 Ok(())
611 }
612
613 #[inline]
614 fn add_append(&mut self, txn: &mut Transaction<'_>, node_id: FlowNodeId, inputs: &[FlowNodeId]) -> Result<()> {
615 if inputs.len() < 2 {
616 return Err(Error::from(FlowGraphError::NodeInputArity {
617 node: "Append",
618 expected: "at least 2",
619 found: inputs.len(),
620 }));
621 }
622
623 let mut parents = Vec::with_capacity(inputs.len());
624
625 for input_node_id in inputs {
626 let parent = self
627 .operators
628 .get(input_node_id)
629 .ok_or_else(|| {
630 Error::from(FlowGraphError::ParentOperatorNotFound {
631 input: format!("{:?}", input_node_id),
632 })
633 })?
634 .clone();
635 parents.push(parent);
636 }
637
638 let ttl = self.catalog.find_operator_settings(txn, node_id)?.and_then(|s| s.ttl);
639 let ttl_nanos = ttl
640 .as_ref()
641 .map(|t| t.duration.as_nanos().expect("operator ttl duration fits in i64 nanoseconds") as u64);
642
643 self.operators.insert(
644 node_id,
645 OperatorCell::new(Operators::Append(AppendOperator::new(
646 node_id,
647 parents,
648 inputs.to_vec(),
649 ttl_nanos,
650 self.executor.runtime_context.version_epoch.clone(),
651 ))),
652 );
653 Ok(())
654 }
655
656 #[inline]
657 fn add_apply(
658 &mut self,
659 node_id: FlowNodeId,
660 inputs: &[FlowNodeId],
661 operator: String,
662 expressions: Vec<Expression>,
663 ) -> Result<()> {
664 let config = evaluate_operator_config(
665 expressions.as_slice(),
666 &self.executor.routines,
667 &self.runtime_context,
668 )?;
669 let cfg = Config::new(operator.as_str(), config.clone());
670
671 if let Some(factory) = self.custom_operators.get(operator.as_str()) {
672 let op = factory(node_id, &cfg)?;
673 self.operators.insert(node_id, OperatorCell::new(Operators::Custom(op)));
674 } else {
675 #[cfg(reifydb_target = "native")]
676 {
677 let parent = self.parent(first_input(inputs)?)?;
678
679 let inner = if self.is_native_operator(operator.as_str()) {
680 self.create_native_operator(operator.as_str(), node_id, &cfg)?
681 } else if self.is_ffi_operator(operator.as_str()) {
682 self.create_ffi_operator(operator.as_str(), node_id, &config)?
683 } else {
684 return Err(Error::from(FlowGraphError::UnknownOperator {
685 operator: operator.to_string(),
686 }));
687 };
688
689 self.operators.insert(
690 node_id,
691 OperatorCell::new(Operators::Apply(ApplyOperator::new(parent, node_id, inner))),
692 );
693 }
694 #[cfg(not(reifydb_target = "native"))]
695 {
696 let _ = (operator, inputs);
697
698 return Err(Error::from(FlowGraphError::FfiUnsupportedOnWasm));
699 }
700 }
701 Ok(())
702 }
703
704 #[inline]
705 #[allow(clippy::too_many_arguments)]
706 fn add_window(
707 &mut self,
708 node_id: FlowNodeId,
709 inputs: &[FlowNodeId],
710 kind: WindowKind,
711 group_by: Vec<Expression>,
712 aggregations: Vec<Expression>,
713 ts: Option<String>,
714 lateness: Option<Duration>,
715 state_cache_size: Option<usize>,
716 internal_state_cache_size: Option<usize>,
717 ) -> Result<()> {
718 let parent = self.parent(first_input(inputs)?)?;
719 let operator = WindowOperator::new(WindowConfig {
720 parent,
721 node: node_id,
722 kind: kind.clone(),
723 group_by: group_by.clone(),
724 aggregations: aggregations.clone(),
725 ts: ts.clone(),
726 runtime_context: self.runtime_context.clone(),
727 routines: self.executor.routines.clone(),
728 late_policy: LatePolicy::Process,
729 lateness,
730 state_cache_size,
731 internal_state_cache_size,
732 });
733 self.operators.insert(node_id, OperatorCell::new(Operators::Window(operator)));
734 Ok(())
735 }
736
737 #[inline]
738 fn add_aggregate(
739 &mut self,
740 node_id: FlowNodeId,
741 inputs: &[FlowNodeId],
742 by: Vec<Expression>,
743 map: Vec<Expression>,
744 ) -> Result<()> {
745 let parent = self.parent(first_input(inputs)?)?;
746 self.operators.insert(
747 node_id,
748 OperatorCell::new(Operators::Aggregate(AggregateOperator::new(
749 parent,
750 node_id,
751 by,
752 map,
753 self.executor.routines.clone(),
754 self.runtime_context.clone(),
755 ))),
756 );
757 Ok(())
758 }
759
760 fn parent(&self, input: FlowNodeId) -> Result<OperatorCell> {
761 Ok(self.operators
762 .get(&input)
763 .ok_or_else(|| {
764 Error::from(FlowGraphError::ParentOperatorNotFound {
765 input: format!("{:?}", input),
766 })
767 })?
768 .clone())
769 }
770
771 #[inline]
772 fn register_source_view(
773 &mut self,
774 txn: &mut Transaction<'_>,
775 flow: &FlowDag,
776 node_id: FlowNodeId,
777 view: ViewId,
778 ) -> Result<()> {
779 let view = self.catalog.get_view(&mut txn.reborrow(), view)?;
780 self.add_source(flow.id, node_id, ShapeId::view(view.id()));
781
782 self.add_source(flow.id, node_id, view.underlying_id());
783
784 self.operators.insert(
785 node_id,
786 OperatorCell::new(Operators::SourceView(PrimitiveViewOperator::new(node_id, view))),
787 );
788 Ok(())
789 }
790
791 pub fn add_source(&mut self, flow: FlowId, node: FlowNodeId, shape: ShapeId) {
792 let nodes = self.sources.entry(shape).or_default();
793
794 let entry = (flow, node);
795 if !nodes.contains(&entry) {
796 nodes.push(entry);
797 }
798 }
799
800 pub fn add_sink(&mut self, flow: FlowId, node: FlowNodeId, sink: ShapeId) {
801 let nodes = self.sinks.entry(sink).or_default();
802
803 let entry = (flow, node);
804 if !nodes.contains(&entry) {
805 nodes.push(entry);
806 }
807 }
808}
809
810fn first_input(inputs: &[FlowNodeId]) -> Result<FlowNodeId> {
811 inputs.first().copied().ok_or_else(|| Error::from(FlowGraphError::MissingInputEdge))
812}
813
814fn common_column_names(left: &Columns, right: &Columns) -> Vec<String> {
815 let right_names: Vec<String> = right.names.iter().map(|n| n.text().to_string()).collect();
816 left.names.iter().map(|n| n.text().to_string()).filter(|name| right_names.contains(name)).collect()
817}
818
819fn natural_key_expr(name: &str) -> Expression {
820 Expression::Column(ColumnExpression(ColumnIdentifier {
821 shape: ColumnShape::Qualified {
822 namespace: Fragment::internal("_context"),
823 name: Fragment::internal("_context"),
824 },
825 name: Fragment::internal(name),
826 }))
827}