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
92impl<'a, V, Lhs, Rhs, Op> Expr<'a, V> for ColumnBinOp<Lhs, Rhs, Op>
93where
94    V: SQLParam,
95    Lhs: Expr<'a, V>,
96    Rhs: Expr<'a, V>,
97    Lhs::SQLType: Numeric + ArithmeticOutput<Rhs::SQLType>,
98    Rhs::SQLType: Numeric,
99    Lhs::Nullable: NullOr<Rhs::Nullable>,
100    Rhs::Nullable: Nullability,
101    Lhs::Aggregate: AggOr<Rhs::Aggregate>,
102    Rhs::Aggregate: AggregateKind,
103    Op: BinOpToken,
104{
105    type SQLType = <Lhs::SQLType as ArithmeticOutput<Rhs::SQLType>>::Output;
106    type Nullable = <Lhs::Nullable as NullOr<Rhs::Nullable>>::Output;
107    type Aggregate = <Lhs::Aggregate as AggOr<Rhs::Aggregate>>::Output;
108}
109
110impl<Lhs: super::HasAggStatus, Rhs, Op> super::HasAggStatus for ColumnBinOp<Lhs, Rhs, Op> {
111    type Status = Lhs::Status;
112}
113
114impl<Lhs, Rhs, Op> crate::row::ExprValueType for ColumnBinOp<Lhs, Rhs, Op>
115where
116    Lhs: crate::row::ExprValueType,
117{
118    type ValueType = Lhs::ValueType;
119}
120
121impl<Lhs, Rhs, Op> crate::row::IntoSelectTarget for ColumnBinOp<Lhs, Rhs, Op> {
122    type Marker = crate::row::SelectCols<(Self,)>;
123}
124
125/// Negation result for column arithmetic.
126#[derive(Debug, Clone, Copy)]
127pub struct ColumnNeg<T> {
128    inner: T,
129}
130
131impl<T> ColumnNeg<T> {
132    #[inline]
133    pub const fn new(inner: T) -> Self {
134        Self { inner }
135    }
136}
137
138impl<'a, V, T> ToSQL<'a, V> for ColumnNeg<T>
139where
140    V: SQLParam,
141    T: ToSQL<'a, V>,
142{
143    fn to_sql(&self) -> SQL<'a, V> {
144        SQL::raw("-").append(self.inner.to_sql())
145    }
146}
147
148impl<'a, V, T> Expr<'a, V> for ColumnNeg<T>
149where
150    V: SQLParam,
151    T: Expr<'a, V>,
152    T::SQLType: Numeric,
153{
154    type SQLType = T::SQLType;
155    type Nullable = T::Nullable;
156    type Aggregate = T::Aggregate;
157}
158
159impl<T: super::HasAggStatus> super::HasAggStatus for ColumnNeg<T> {
160    type Status = T::Status;
161}
162
163impl<T: crate::row::ExprValueType> crate::row::ExprValueType for ColumnNeg<T> {
164    type ValueType = T::ValueType;
165}
166
167impl<T> crate::row::IntoSelectTarget for ColumnNeg<T> {
168    type Marker = crate::row::SelectCols<(Self,)>;
169}