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::{Expr, NullOr, Nullability, Scalar};
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 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    Op: BinOpToken,
102{
103    type SQLType = <Lhs::SQLType as ArithmeticOutput<Rhs::SQLType>>::Output;
104    type Nullable = <Lhs::Nullable as NullOr<Rhs::Nullable>>::Output;
105    type Aggregate = Scalar;
106}
107
108/// Negation result for column arithmetic.
109#[derive(Debug, Clone, Copy)]
110pub struct ColumnNeg<T> {
111    inner: T,
112}
113
114impl<T> ColumnNeg<T> {
115    #[inline]
116    pub fn new(inner: T) -> Self {
117        Self { inner }
118    }
119}
120
121impl<'a, V, T> ToSQL<'a, V> for ColumnNeg<T>
122where
123    V: SQLParam,
124    T: ToSQL<'a, V>,
125{
126    fn to_sql(&self) -> SQL<'a, V> {
127        SQL::raw("-").append(self.inner.to_sql())
128    }
129}
130
131impl<'a, V, T> Expr<'a, V> for ColumnNeg<T>
132where
133    V: SQLParam,
134    T: Expr<'a, V>,
135    T::SQLType: Numeric,
136{
137    type SQLType = T::SQLType;
138    type Nullable = T::Nullable;
139    type Aggregate = Scalar;
140}