1use 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#[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#[derive(Debug, Clone, Copy)]
37pub struct OpAdd;
38
39#[derive(Debug, Clone, Copy)]
41pub struct OpSub;
42
43#[derive(Debug, Clone, Copy)]
45pub struct OpMul;
46
47#[derive(Debug, Clone, Copy)]
49pub struct OpDiv;
50
51#[derive(Debug, Clone, Copy)]
53pub struct OpRem;
54
55pub 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#[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}