1use crate::compile::CompiledSql;
2use crate::expr::{Expr, ExprNode, IntoExpr, NumericExprType, VectorBinaryOp};
3use crate::query::Select;
4use crate::PgVector;
5
6pub trait StringUnaryExpr {
7 type Output;
8}
9
10impl StringUnaryExpr for String {
11 type Output = String;
12}
13
14impl StringUnaryExpr for Option<String> {
15 type Output = Option<String>;
16}
17
18pub trait StringLengthExpr {
19 type Output;
20}
21
22impl StringLengthExpr for String {
23 type Output = i32;
24}
25
26impl StringLengthExpr for Option<String> {
27 type Output = Option<i32>;
28}
29
30fn unary_string_fn<T>(name: &'static str, arg: impl IntoExpr<T>) -> Expr<<T as StringUnaryExpr>::Output>
31where
32 T: StringUnaryExpr,
33{
34 let expr = arg.into_expr();
35 Expr::new(ExprNode::Func {
36 name,
37 args: vec![expr.node],
38 })
39}
40
41fn string_length_fn<T>(name: &'static str, arg: impl IntoExpr<T>) -> Expr<<T as StringLengthExpr>::Output>
42where
43 T: StringLengthExpr,
44{
45 let expr = arg.into_expr();
46 Expr::new(ExprNode::Func {
47 name,
48 args: vec![expr.node],
49 })
50}
51
52pub fn upper<T>(arg: impl IntoExpr<T>) -> Expr<<T as StringUnaryExpr>::Output>
53where
54 T: StringUnaryExpr,
55{
56 unary_string_fn("UPPER", arg)
57}
58
59pub fn trim<T>(arg: impl IntoExpr<T>) -> Expr<<T as StringUnaryExpr>::Output>
60where
61 T: StringUnaryExpr,
62{
63 unary_string_fn("TRIM", arg)
64}
65
66pub fn char_length<T>(arg: impl IntoExpr<T>) -> Expr<<T as StringLengthExpr>::Output>
67where
68 T: StringLengthExpr,
69{
70 string_length_fn("CHAR_LENGTH", arg)
71}
72
73pub fn count<T>(arg: impl IntoExpr<T>) -> Expr<i64> {
74 let expr = arg.into_expr();
75 Expr::new(ExprNode::Func {
76 name: "COUNT",
77 args: vec![expr.node],
78 })
79}
80
81pub fn sum<T>(arg: impl IntoExpr<T>) -> Expr<T> {
82 let expr = arg.into_expr();
83 Expr::new(ExprNode::Func {
84 name: "SUM",
85 args: vec![expr.node],
86 })
87}
88
89pub trait NullableAggregateOutput {
90 type Output;
91}
92
93macro_rules! impl_nullable_aggregate_output {
94 ($($ty:ty),+ $(,)?) => {
95 $(
96 impl NullableAggregateOutput for $ty {
97 type Output = Option<$ty>;
98 }
99
100 impl NullableAggregateOutput for Option<$ty> {
101 type Output = Option<$ty>;
102 }
103 )+
104 };
105}
106
107impl_nullable_aggregate_output!(
108 String,
109 i16,
110 i32,
111 i64,
112 f32,
113 f64,
114 uuid::Uuid,
115 chrono::NaiveDateTime,
116 chrono::DateTime<chrono::Utc>,
117 chrono::NaiveDate,
118 chrono::NaiveTime,
119 crate::PgInterval,
120);
121
122pub fn min<T>(arg: impl IntoExpr<T>) -> Expr<<T as NullableAggregateOutput>::Output>
123where
124 T: NullableAggregateOutput,
125{
126 let expr = arg.into_expr();
127 Expr::new(ExprNode::Func {
128 name: "MIN",
129 args: vec![expr.node],
130 })
131}
132
133pub fn max<T>(arg: impl IntoExpr<T>) -> Expr<<T as NullableAggregateOutput>::Output>
134where
135 T: NullableAggregateOutput,
136{
137 let expr = arg.into_expr();
138 Expr::new(ExprNode::Func {
139 name: "MAX",
140 args: vec![expr.node],
141 })
142}
143
144pub fn coalesce<T>(a: impl IntoExpr<T>, b: impl IntoExpr<T>) -> Expr<T> {
145 let left = a.into_expr();
146 let right = b.into_expr();
147 Expr::new(ExprNode::Func {
148 name: "COALESCE",
149 args: vec![left.node, right.node],
150 })
151}
152
153pub fn least<T>(a: impl IntoExpr<T>, b: impl IntoExpr<T>) -> Expr<T> {
154 let left = a.into_expr();
155 let right = b.into_expr();
156 Expr::new(ExprNode::Func {
157 name: "LEAST",
158 args: vec![left.node, right.node],
159 })
160}
161
162pub fn greatest<T>(a: impl IntoExpr<T>, b: impl IntoExpr<T>) -> Expr<T> {
163 let left = a.into_expr();
164 let right = b.into_expr();
165 Expr::new(ExprNode::Func {
166 name: "GREATEST",
167 args: vec![left.node, right.node],
168 })
169}
170
171pub fn power<B, E>(base: impl IntoExpr<B>, exponent: impl IntoExpr<E>) -> Expr<f64>
172where
173 B: NumericExprType,
174 E: NumericExprType,
175{
176 let base = base.into_expr();
177 let exponent = exponent.into_expr();
178 Expr::new(ExprNode::Func {
179 name: "POWER",
180 args: vec![base.node, exponent.node],
181 })
182}
183
184pub fn date_trunc<T>(part: impl IntoExpr<String>, value: impl IntoExpr<T>) -> Expr<T> {
185 let part = part.into_expr();
186 let value = value.into_expr();
187 Expr::new(ExprNode::Func {
188 name: "DATE_TRUNC",
189 args: vec![part.node, value.node],
190 })
191}
192
193fn exists_expr(subquery: CompiledSql) -> Expr<bool> {
194 Expr::new(ExprNode::Exists { subquery })
195}
196
197pub fn exists<Out, Loads, Lock, DistinctState, GroupState>(subquery: Select<Out, Loads, Lock, DistinctState, GroupState>) -> Expr<bool> {
198 exists_expr(subquery.compile_for_exists())
199}
200
201pub trait VectorExpr<const N: usize> {}
203
204impl<const N: usize> VectorExpr<N> for PgVector<N> {}
205impl<const N: usize> VectorExpr<N> for Option<PgVector<N>> {}
206
207fn vector_binary_fn<const N: usize, L, R>(name: &'static str, left: impl IntoExpr<L>, right: impl IntoExpr<R>) -> Expr<f32>
208where
209 L: VectorExpr<N>,
210 R: VectorExpr<N>,
211{
212 let left = left.into_expr();
213 let right = right.into_expr();
214 Expr::new(ExprNode::Func {
215 name,
216 args: vec![left.node, right.node],
217 })
218}
219
220fn vector_binary_operator<const N: usize, L, R>(op: VectorBinaryOp, left: impl IntoExpr<L>, right: impl IntoExpr<R>) -> Expr<f32>
221where
222 L: VectorExpr<N>,
223 R: VectorExpr<N>,
224{
225 let left = left.into_expr();
226 let right = right.into_expr();
227 Expr::new(ExprNode::VectorBinary {
228 left: Box::new(left.node),
229 op,
230 right: Box::new(right.node),
231 })
232}
233
234pub fn l2_distance<const N: usize, L, R>(left: impl IntoExpr<L>, right: impl IntoExpr<R>) -> Expr<f32>
242where
243 L: VectorExpr<N>,
244 R: VectorExpr<N>,
245{
246 vector_binary_operator::<N, L, R>(VectorBinaryOp::L2Distance, left, right)
247}
248
249pub fn cosine_distance<const N: usize, L, R>(left: impl IntoExpr<L>, right: impl IntoExpr<R>) -> Expr<f32>
257where
258 L: VectorExpr<N>,
259 R: VectorExpr<N>,
260{
261 vector_binary_operator::<N, L, R>(VectorBinaryOp::CosineDistance, left, right)
262}
263
264pub fn inner_product<const N: usize, L, R>(left: impl IntoExpr<L>, right: impl IntoExpr<R>) -> Expr<f32>
274where
275 L: VectorExpr<N>,
276 R: VectorExpr<N>,
277{
278 vector_binary_fn::<N, L, R>("INNER_PRODUCT", left, right)
279}
280
281pub fn l1_distance<const N: usize, L, R>(left: impl IntoExpr<L>, right: impl IntoExpr<R>) -> Expr<f32>
289where
290 L: VectorExpr<N>,
291 R: VectorExpr<N>,
292{
293 vector_binary_operator::<N, L, R>(VectorBinaryOp::L1Distance, left, right)
294}
295
296pub fn inner_product_distance<const N: usize, L, R>(left: impl IntoExpr<L>, right: impl IntoExpr<R>) -> Expr<f32>
307where
308 L: VectorExpr<N>,
309 R: VectorExpr<N>,
310{
311 vector_binary_operator::<N, L, R>(VectorBinaryOp::InnerProductDistance, left, right)
312}