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