Skip to main content

drizzle_core/expr/
column_ops.rs

1//! Internal wrapper types for column arithmetic operations.
2//!
3//! These types are implementation details that allow `column + 5` syntax
4//! to work seamlessly. Users don't interact with these directly.
5
6use core::marker::PhantomData;
7
8use crate::sql::{SQL, Token};
9use crate::traits::{SQLParam, ToSQL};
10use crate::types::{ArithmeticOutput, Numeric};
11
12use super::{AggOr, AggregateKind, Expr, NullOr, Nullability};
13
14/// Binary operation result for column arithmetic.
15///
16/// This is an implementation detail - users see `column + 5` and it "just works".
17#[derive(Debug, Clone, Copy)]
18pub struct ColumnBinOp<Lhs, Rhs, Op> {
19    lhs: Lhs,
20    rhs: Rhs,
21    _op: PhantomData<Op>,
22}
23
24impl<Lhs, Rhs, Op> ColumnBinOp<Lhs, Rhs, Op> {
25    #[inline]
26    pub const fn new(lhs: Lhs, rhs: Rhs) -> Self {
27        Self {
28            lhs,
29            rhs,
30            _op: PhantomData,
31        }
32    }
33}
34
35/// Marker for addition
36#[derive(Debug, Clone, Copy)]
37pub struct OpAdd;
38
39/// Marker for subtraction
40#[derive(Debug, Clone, Copy)]
41pub struct OpSub;
42
43/// Marker for multiplication
44#[derive(Debug, Clone, Copy)]
45pub struct OpMul;
46
47/// Marker for division
48#[derive(Debug, Clone, Copy)]
49pub struct OpDiv;
50
51/// Marker for remainder/modulo
52#[derive(Debug, Clone, Copy)]
53pub struct OpRem;
54
55/// Trait to get the token for an operation
56pub trait BinOpToken {
57    const TOKEN: Token;
58}
59
60impl BinOpToken for OpAdd {
61    const TOKEN: Token = Token::PLUS;
62}
63
64impl BinOpToken for OpSub {
65    const TOKEN: Token = Token::MINUS;
66}
67
68impl BinOpToken for OpMul {
69    const TOKEN: Token = Token::STAR;
70}
71
72impl BinOpToken for OpDiv {
73    const TOKEN: Token = Token::SLASH;
74}
75
76impl BinOpToken for OpRem {
77    const TOKEN: Token = Token::REM;
78}
79
80impl<'a, V, Lhs, Rhs, Op> ToSQL<'a, V> for ColumnBinOp<Lhs, Rhs, Op>
81where
82    V: SQLParam,
83    Lhs: ToSQL<'a, V>,
84    Rhs: ToSQL<'a, V>,
85    Op: BinOpToken,
86{
87    fn to_sql(&self) -> SQL<'a, V> {
88        self.lhs.to_sql().push(Op::TOKEN).append(self.rhs.to_sql())
89    }
90
91    fn into_sql(self) -> SQL<'a, V> {
92        self.lhs
93            .into_sql()
94            .push(Op::TOKEN)
95            .append(self.rhs.into_sql())
96    }
97}
98
99impl<'a, V, Lhs, Rhs, Op> Expr<'a, V> for ColumnBinOp<Lhs, Rhs, Op>
100where
101    V: SQLParam,
102    Lhs: Expr<'a, V>,
103    Rhs: Expr<'a, V>,
104    Lhs::SQLType: Numeric + ArithmeticOutput<Rhs::SQLType>,
105    Rhs::SQLType: Numeric,
106    Lhs::Nullable: NullOr<Rhs::Nullable>,
107    Rhs::Nullable: Nullability,
108    Lhs::Aggregate: AggOr<Rhs::Aggregate>,
109    Rhs::Aggregate: AggregateKind,
110    Op: BinOpToken,
111{
112    type SQLType = <Lhs::SQLType as ArithmeticOutput<Rhs::SQLType>>::Output;
113    type Nullable = <Lhs::Nullable as NullOr<Rhs::Nullable>>::Output;
114    type Aggregate = <Lhs::Aggregate as AggOr<Rhs::Aggregate>>::Output;
115}
116
117impl<Lhs: super::HasAggStatus, Rhs, Op> super::HasAggStatus for ColumnBinOp<Lhs, Rhs, Op> {
118    type Status = Lhs::Status;
119}
120
121impl<Lhs, Rhs, Op> crate::row::ExprValueType for ColumnBinOp<Lhs, Rhs, Op>
122where
123    Lhs: crate::row::ExprValueType,
124{
125    type ValueType = Lhs::ValueType;
126}
127
128impl<Lhs, Rhs, Op> crate::row::IntoSelectTarget for ColumnBinOp<Lhs, Rhs, Op> {
129    type Marker = crate::row::SelectCols<(Self,)>;
130}
131
132/// Negation result for column arithmetic.
133#[derive(Debug, Clone, Copy)]
134pub struct ColumnNeg<T> {
135    inner: T,
136}
137
138impl<T> ColumnNeg<T> {
139    #[inline]
140    pub const fn new(inner: T) -> Self {
141        Self { inner }
142    }
143}
144
145impl<'a, V, T> ToSQL<'a, V> for ColumnNeg<T>
146where
147    V: SQLParam,
148    T: ToSQL<'a, V>,
149{
150    fn to_sql(&self) -> SQL<'a, V> {
151        SQL::raw("-").append(self.inner.to_sql())
152    }
153
154    fn into_sql(self) -> SQL<'a, V> {
155        SQL::raw("-").append(self.inner.into_sql())
156    }
157}
158
159impl<'a, V, T> Expr<'a, V> for ColumnNeg<T>
160where
161    V: SQLParam,
162    T: Expr<'a, V>,
163    T::SQLType: Numeric,
164{
165    type SQLType = T::SQLType;
166    type Nullable = T::Nullable;
167    type Aggregate = T::Aggregate;
168}
169
170impl<T: super::HasAggStatus> super::HasAggStatus for ColumnNeg<T> {
171    type Status = T::Status;
172}
173
174impl<T: crate::row::ExprValueType> crate::row::ExprValueType for ColumnNeg<T> {
175    type ValueType = T::ValueType;
176}
177
178impl<T> crate::row::IntoSelectTarget for ColumnNeg<T> {
179    type Marker = crate::row::SelectCols<(Self,)>;
180}