reifydb_engine/expression/arith/
sub.rs1use reifydb_core::value::column::{Column, data::ColumnData, 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: &Column,
24 right: &Column,
25 fragment: impl LazyFragment + Copy,
26) -> Result<Column> {
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 (ColumnData::Duration(l), ColumnData::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(Column {
44 name: fragment.fragment(),
45 data: ColumnData::Duration(container),
46 })
47 }
48
49 _ => return Err(TypeError::BinaryOperatorNotApplicable {
50 operator: BinaryOp::Sub,
51 left: left.get_type(),
52 right: right.get_type(),
53 fragment: fragment.fragment(),
54 }.into()),
55 )
56 })
57}
58
59fn sub_numeric<'a, L, R>(
60 ctx: &EvalContext,
61 l: &NumberContainer<L>,
62 r: &NumberContainer<R>,
63 target: Type,
64 fragment: impl LazyFragment + Copy,
65) -> Result<Column>
66where
67 L: GetType + Promote<R> + IsNumber,
68 R: GetType + IsNumber,
69 <L as Promote<R>>::Output: IsNumber,
70 <L as Promote<R>>::Output: SafeSub,
71 ColumnData: Push<<L as Promote<R>>::Output>,
72{
73 debug_assert_eq!(l.len(), r.len());
74
75 let mut data = ColumnData::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(Column {
86 name: fragment.fragment(),
87 data,
88 })
89}
90
91fn sub_numeric_clone<'a, L, R>(
92 ctx: &EvalContext,
93 l: &NumberContainer<L>,
94 r: &NumberContainer<R>,
95 target: Type,
96 fragment: impl LazyFragment + Copy,
97) -> Result<Column>
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 ColumnData: Push<<L as Promote<R>>::Output>,
104{
105 debug_assert_eq!(l.len(), r.len());
106
107 let mut data = ColumnData::with_capacity(target, l.len());
108 let l_data = l.data();
109 let r_data = r.data();
110 for i in 0..l.len() {
111 let l_clone = l_data[i].clone();
112 let r_clone = r_data[i].clone();
113 if let Some(value) = ctx.sub(&l_clone, &r_clone, fragment)? {
114 data.push(value);
115 } else {
116 data.push_none()
117 }
118 }
119 Ok(Column {
120 name: fragment.fragment(),
121 data,
122 })
123}