reifydb_engine/expression/arith/
sub.rs1use reifydb_core::value::column::{ColumnWithName, buffer::ColumnBuffer, push::Push};
5use reifydb_type::{
6 error::{BinaryOp, TypeError},
7 fragment::LazyFragment,
8 value::{
9 container::{number::NumberContainer, temporal::TemporalContainer},
10 is::IsNumber,
11 number::{promote::Promote, safe::sub::SafeSub},
12 r#type::{Type, get::GetType},
13 },
14};
15
16use crate::{
17 Result,
18 expression::{context::EvalContext, option::binary_op_unwrap_option},
19};
20
21pub(crate) fn sub_columns(
22 ctx: &EvalContext,
23 left: &ColumnWithName,
24 right: &ColumnWithName,
25 fragment: impl LazyFragment + Copy,
26) -> Result<ColumnWithName> {
27 binary_op_unwrap_option(left, right, fragment.fragment(), |left, right| {
28 let target = Type::promote(left.get_type(), right.get_type());
29
30 dispatch_arith!(
31 &left.data(), &right.data();
32 fixed: sub_numeric, arb: sub_numeric_clone (ctx, target, fragment);
33
34
35 (ColumnBuffer::Duration(l), ColumnBuffer::Duration(r)) => {
36 let mut container = TemporalContainer::with_capacity(l.len());
37 for i in 0..l.len() {
38 match (l.get(i), r.get(i)) {
39 (Some(lv), Some(rv)) => container.push(*lv - *rv),
40 _ => container.push_default(),
41 }
42 }
43 Ok(ColumnWithName::new(fragment.fragment(), ColumnBuffer::Duration(container)))
44 }
45
46 _ => Err(TypeError::BinaryOperatorNotApplicable {
47 operator: BinaryOp::Sub,
48 left: left.get_type(),
49 right: right.get_type(),
50 fragment: fragment.fragment(),
51 }.into()),
52 )
53 })
54}
55
56fn sub_numeric<L, R>(
57 ctx: &EvalContext,
58 l: &NumberContainer<L>,
59 r: &NumberContainer<R>,
60 target: Type,
61 fragment: impl LazyFragment + Copy,
62) -> Result<ColumnWithName>
63where
64 L: GetType + Promote<R> + IsNumber,
65 R: GetType + IsNumber,
66 <L as Promote<R>>::Output: IsNumber,
67 <L as Promote<R>>::Output: SafeSub,
68 ColumnBuffer: Push<<L as Promote<R>>::Output>,
69{
70 debug_assert_eq!(l.len(), r.len());
71
72 let mut data = ColumnBuffer::with_capacity(target, l.len());
73 let l_data = l.data();
74 let r_data = r.data();
75 for i in 0..l.len() {
76 if let Some(value) = ctx.sub(&l_data[i], &r_data[i], fragment)? {
77 data.push(value);
78 } else {
79 data.push_none()
80 }
81 }
82 Ok(ColumnWithName {
83 name: fragment.fragment(),
84 data,
85 })
86}
87
88fn sub_numeric_clone<L, R>(
89 ctx: &EvalContext,
90 l: &NumberContainer<L>,
91 r: &NumberContainer<R>,
92 target: Type,
93 fragment: impl LazyFragment + Copy,
94) -> Result<ColumnWithName>
95where
96 L: Clone + GetType + Promote<R> + IsNumber,
97 R: Clone + GetType + IsNumber,
98 <L as Promote<R>>::Output: IsNumber,
99 <L as Promote<R>>::Output: SafeSub,
100 ColumnBuffer: Push<<L as Promote<R>>::Output>,
101{
102 debug_assert_eq!(l.len(), r.len());
103
104 let mut data = ColumnBuffer::with_capacity(target, l.len());
105 let l_data = l.data();
106 let r_data = r.data();
107 for i in 0..l.len() {
108 let l_clone = l_data[i].clone();
109 let r_clone = r_data[i].clone();
110 if let Some(value) = ctx.sub(&l_clone, &r_clone, fragment)? {
111 data.push(value);
112 } else {
113 data.push_none()
114 }
115 }
116 Ok(ColumnWithName {
117 name: fragment.fragment(),
118 data,
119 })
120}