1use bitflags::bitflags;
2
3use crate::compile::CompiledSql;
4use crate::expr::{AggregateExpr, Expr, ExprNode, ExprOperand, IntoExpr, NumericExprType, TrimDirection, Value, VectorBinaryOp};
5use crate::query::Select;
6use crate::PgVector;
7
8pub trait StringUnaryExpr {
9 type Output;
10}
11
12impl StringUnaryExpr for String {
13 type Output = String;
14}
15
16impl StringUnaryExpr for Option<String> {
17 type Output = Option<String>;
18}
19
20pub trait StringLengthExpr {
21 type Output;
22}
23
24impl StringLengthExpr for String {
25 type Output = i32;
26}
27
28impl StringLengthExpr for Option<String> {
29 type Output = Option<i32>;
30}
31
32pub trait StringSplitExpr {
33 type Output;
34}
35
36impl StringSplitExpr for String {
37 type Output = Vec<String>;
38}
39
40impl StringSplitExpr for Option<String> {
41 type Output = Option<Vec<String>>;
42}
43
44pub trait StringBinaryExpr<Rhs, Result> {
45 type Output;
46}
47
48impl<Result> StringBinaryExpr<String, Result> for String {
49 type Output = Result;
50}
51
52impl<Result> StringBinaryExpr<Option<String>, Result> for String {
53 type Output = Option<Result>;
54}
55
56impl<Result> StringBinaryExpr<String, Result> for Option<String> {
57 type Output = Option<Result>;
58}
59
60impl<Result> StringBinaryExpr<Option<String>, Result> for Option<String> {
61 type Output = Option<Result>;
62}
63
64#[doc(hidden)]
65pub struct ConcatExpr {
66 node: ExprNode,
67}
68
69pub trait IntoConcatExpr {
70 fn into_concat_expr(self) -> ConcatExpr;
71}
72
73impl<T> IntoConcatExpr for T
74where
75 T: ExprOperand,
76 T::Value: StringUnaryExpr,
77{
78 fn into_concat_expr(self) -> ConcatExpr {
79 ConcatExpr {
80 node: self.into_operand_expr().node,
81 }
82 }
83}
84
85impl IntoConcatExpr for ConcatExpr {
86 fn into_concat_expr(self) -> ConcatExpr {
87 self
88 }
89}
90
91bitflags! {
92 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
94 pub struct RegexReplaceFlags: u8 {
95 const CASE_INSENSITIVE = 1 << 0;
97 const GLOBAL = 1 << 1;
99 }
100
101 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
103 pub struct RegexSplitFlags: u8 {
104 const CASE_INSENSITIVE = 1 << 0;
106 }
107}
108
109#[derive(Debug, Clone, Copy, PartialEq, Eq)]
111pub enum NormalizationForm {
112 Nfc,
114 Nfd,
116 Nfkc,
118 Nfkd,
120}
121
122pub trait StringBoolExpr {
124 type Output;
126}
127
128impl StringBoolExpr for String {
129 type Output = bool;
130}
131
132impl StringBoolExpr for Option<String> {
133 type Output = Option<bool>;
134}
135
136pub trait CodepointExpr {
138 type Output;
140}
141
142impl CodepointExpr for i32 {
143 type Output = String;
144}
145
146impl CodepointExpr for Option<i32> {
147 type Output = Option<String>;
148}
149
150impl RegexReplaceFlags {
151 fn as_postgres_str(self) -> &'static str {
152 match (self.contains(Self::GLOBAL), self.contains(Self::CASE_INSENSITIVE)) {
153 (false, false) => "",
154 (false, true) => "i",
155 (true, false) => "g",
156 (true, true) => "gi",
157 }
158 }
159}
160
161impl RegexSplitFlags {
162 fn as_postgres_str(self) -> &'static str {
163 if self.contains(Self::CASE_INSENSITIVE) {
164 "i"
165 } else {
166 ""
167 }
168 }
169}
170
171fn unary_string_fn<T>(name: &'static str, arg: impl IntoExpr<T>) -> Expr<<T as StringUnaryExpr>::Output>
172where
173 T: StringUnaryExpr,
174{
175 let expr = arg.into_expr();
176 Expr::new(ExprNode::Func {
177 name,
178 args: vec![expr.node],
179 })
180}
181
182fn string_length_fn<T>(name: &'static str, arg: impl IntoExpr<T>) -> Expr<<T as StringLengthExpr>::Output>
183where
184 T: StringLengthExpr,
185{
186 let expr = arg.into_expr();
187 Expr::new(ExprNode::Func {
188 name,
189 args: vec![expr.node],
190 })
191}
192
193fn string_fn<T>(name: &'static str, arg: impl IntoExpr<T>, extra_args: Vec<ExprNode>) -> Expr<<T as StringUnaryExpr>::Output>
194where
195 T: StringUnaryExpr,
196{
197 let mut args = vec![arg.into_expr().node];
198 args.extend(extra_args);
199 Expr::new(ExprNode::Func { name, args })
200}
201
202fn binary_string_fn<L, R, O>(name: &'static str, left: impl IntoExpr<L>, right: impl IntoExpr<R>) -> Expr<O> {
203 let left = left.into_expr();
204 let right = right.into_expr();
205 Expr::new(ExprNode::Func {
206 name,
207 args: vec![left.node, right.node],
208 })
209}
210
211fn ternary_string_fn<A, B, C, O>(
212 name: &'static str,
213 first: impl IntoExpr<A>,
214 second: impl IntoExpr<B>,
215 third: impl IntoExpr<C>,
216) -> Expr<O> {
217 Expr::new(ExprNode::Func {
218 name,
219 args: vec![first.into_expr().node, second.into_expr().node, third.into_expr().node],
220 })
221}
222
223fn string_expr_nodes<I, A>(args: I) -> Vec<ExprNode>
224where
225 I: IntoIterator<Item = A>,
226 A: IntoConcatExpr,
227{
228 args.into_iter().map(|arg| arg.into_concat_expr().node).collect()
229}
230
231fn directed_trim_fn<T>(
232 arg: impl IntoExpr<T>,
233 direction: TrimDirection,
234 characters: Option<Expr<String>>,
235) -> Expr<<T as StringUnaryExpr>::Output>
236where
237 T: StringUnaryExpr,
238{
239 Expr::new(ExprNode::Trim {
240 direction,
241 expr: Box::new(arg.into_expr().node),
242 characters: characters.map(|characters| Box::new(characters.node)),
243 })
244}
245
246pub fn upper<T>(arg: impl IntoExpr<T>) -> Expr<<T as StringUnaryExpr>::Output>
249where
250 T: StringUnaryExpr,
251{
252 unary_string_fn("UPPER", arg)
253}
254
255pub fn lower<T>(arg: impl IntoExpr<T>) -> Expr<<T as StringUnaryExpr>::Output>
258where
259 T: StringUnaryExpr,
260{
261 unary_string_fn("LOWER", arg)
262}
263
264pub fn title_case<T>(expression: impl IntoExpr<T>) -> Expr<<T as StringUnaryExpr>::Output>
267where
268 T: StringUnaryExpr,
269{
270 unary_string_fn("INITCAP", expression)
271}
272
273pub fn replace<S, F, T>(
277 expression: impl IntoExpr<S>,
278 from: impl IntoExpr<F>,
279 to: impl IntoExpr<T>,
280) -> Expr<<<S as StringBinaryExpr<F, String>>::Output as StringBinaryExpr<T, String>>::Output>
281where
282 S: StringBinaryExpr<F, String>,
283 <S as StringBinaryExpr<F, String>>::Output: StringBinaryExpr<T, String>,
284{
285 ternary_string_fn("REPLACE", expression, from, to)
286}
287
288pub fn replace_range<S, R>(
292 expression: impl IntoExpr<S>,
293 replacement: impl IntoExpr<R>,
294 start: impl IntoExpr<i32>,
295 count: impl IntoExpr<i32>,
296) -> Expr<<S as StringBinaryExpr<R, String>>::Output>
297where
298 S: StringBinaryExpr<R, String>,
299{
300 Expr::new(ExprNode::Func {
301 name: "OVERLAY",
302 args: vec![
303 expression.into_expr().node,
304 replacement.into_expr().node,
305 start.into_expr().node,
306 count.into_expr().node,
307 ],
308 })
309}
310
311pub fn translate_chars<S, F, T>(
315 expression: impl IntoExpr<S>,
316 from: impl IntoExpr<F>,
317 to: impl IntoExpr<T>,
318) -> Expr<<<S as StringBinaryExpr<F, String>>::Output as StringBinaryExpr<T, String>>::Output>
319where
320 S: StringBinaryExpr<F, String>,
321 <S as StringBinaryExpr<F, String>>::Output: StringBinaryExpr<T, String>,
322{
323 ternary_string_fn("TRANSLATE", expression, from, to)
324}
325
326pub fn reverse<T>(expression: impl IntoExpr<T>) -> Expr<<T as StringUnaryExpr>::Output>
329where
330 T: StringUnaryExpr,
331{
332 unary_string_fn("REVERSE", expression)
333}
334
335pub fn trim<T>(arg: impl IntoExpr<T>) -> Expr<<T as StringUnaryExpr>::Output>
338where
339 T: StringUnaryExpr,
340{
341 unary_string_fn("TRIM", arg)
342}
343
344pub fn trim_chars<T>(arg: impl IntoExpr<T>, characters: impl IntoExpr<String>) -> Expr<<T as StringUnaryExpr>::Output>
348where
349 T: StringUnaryExpr,
350{
351 directed_trim_fn(arg, TrimDirection::Both, Some(characters.into_expr()))
352}
353
354pub fn trim_start<T>(arg: impl IntoExpr<T>) -> Expr<<T as StringUnaryExpr>::Output>
357where
358 T: StringUnaryExpr,
359{
360 directed_trim_fn(arg, TrimDirection::Leading, None)
361}
362
363pub fn trim_start_chars<T>(arg: impl IntoExpr<T>, characters: impl IntoExpr<String>) -> Expr<<T as StringUnaryExpr>::Output>
366where
367 T: StringUnaryExpr,
368{
369 directed_trim_fn(arg, TrimDirection::Leading, Some(characters.into_expr()))
370}
371
372pub fn trim_end<T>(arg: impl IntoExpr<T>) -> Expr<<T as StringUnaryExpr>::Output>
375where
376 T: StringUnaryExpr,
377{
378 directed_trim_fn(arg, TrimDirection::Trailing, None)
379}
380
381pub fn trim_end_chars<T>(arg: impl IntoExpr<T>, characters: impl IntoExpr<String>) -> Expr<<T as StringUnaryExpr>::Output>
384where
385 T: StringUnaryExpr,
386{
387 directed_trim_fn(arg, TrimDirection::Trailing, Some(characters.into_expr()))
388}
389
390pub fn char_length<T>(arg: impl IntoExpr<T>) -> Expr<<T as StringLengthExpr>::Output>
393where
394 T: StringLengthExpr,
395{
396 string_length_fn("CHAR_LENGTH", arg)
397}
398
399pub fn byte_length<T>(arg: impl IntoExpr<T>) -> Expr<<T as StringLengthExpr>::Output>
402where
403 T: StringLengthExpr,
404{
405 string_length_fn("OCTET_LENGTH", arg)
406}
407
408pub fn bit_length<T>(arg: impl IntoExpr<T>) -> Expr<<T as StringLengthExpr>::Output>
411where
412 T: StringLengthExpr,
413{
414 string_length_fn("BIT_LENGTH", arg)
415}
416
417pub fn position<L, R>(expression: impl IntoExpr<L>, substring: impl IntoExpr<R>) -> Expr<<L as StringBinaryExpr<R, i32>>::Output>
421where
422 L: StringBinaryExpr<R, i32>,
423{
424 binary_string_fn("STRPOS", expression, substring)
425}
426
427pub fn starts_with<L, R>(expression: impl IntoExpr<L>, prefix: impl IntoExpr<R>) -> Expr<<L as StringBinaryExpr<R, bool>>::Output>
432where
433 L: StringBinaryExpr<R, bool>,
434{
435 binary_string_fn("STARTS_WITH", expression, prefix)
436}
437
438pub fn concat<I, A>(values: I) -> Expr<String>
441where
442 I: IntoIterator<Item = A>,
443 A: IntoConcatExpr,
444{
445 let args = string_expr_nodes(values);
446 Expr::new(ExprNode::Func { name: "CONCAT", args })
447}
448
449pub fn concat_with_separator<S, I, A>(separator: impl IntoExpr<S>, values: I) -> Expr<<S as StringUnaryExpr>::Output>
453where
454 S: StringUnaryExpr,
455 I: IntoIterator<Item = A>,
456 A: IntoConcatExpr,
457{
458 let mut args = vec![separator.into_expr().node];
459 args.extend(string_expr_nodes(values));
460 Expr::new(ExprNode::Func { name: "CONCAT_WS", args })
461}
462
463pub fn split<S, D>(expression: impl IntoExpr<S>, delimiter: impl IntoExpr<D>) -> Expr<<S as StringSplitExpr>::Output>
467where
468 S: StringSplitExpr,
469 D: StringUnaryExpr,
470{
471 binary_string_fn("STRING_TO_ARRAY", expression, delimiter)
472}
473
474pub fn split_part<S, D>(
479 expression: impl IntoExpr<S>,
480 delimiter: impl IntoExpr<D>,
481 index: impl IntoExpr<i32>,
482) -> Expr<<S as StringBinaryExpr<D, String>>::Output>
483where
484 S: StringBinaryExpr<D, String>,
485{
486 let expression = expression.into_expr();
487 let delimiter = delimiter.into_expr();
488 let index = index.into_expr();
489 Expr::new(ExprNode::Func {
490 name: "SPLIT_PART",
491 args: vec![expression.node, delimiter.node, index.node],
492 })
493}
494
495pub fn regex_is_match<L, R>(expression: impl IntoExpr<L>, pattern: impl IntoExpr<R>) -> Expr<<L as StringBinaryExpr<R, bool>>::Output>
499where
500 L: StringBinaryExpr<R, bool>,
501{
502 binary_string_fn("REGEXP_LIKE", expression, pattern)
503}
504
505pub fn regex_count<L, R>(expression: impl IntoExpr<L>, pattern: impl IntoExpr<R>) -> Expr<<L as StringBinaryExpr<R, i32>>::Output>
509where
510 L: StringBinaryExpr<R, i32>,
511{
512 binary_string_fn("REGEXP_COUNT", expression, pattern)
513}
514
515pub fn regex_position<L, R>(expression: impl IntoExpr<L>, pattern: impl IntoExpr<R>) -> Expr<<L as StringBinaryExpr<R, i32>>::Output>
519where
520 L: StringBinaryExpr<R, i32>,
521{
522 binary_string_fn("REGEXP_INSTR", expression, pattern)
523}
524
525pub fn regex_captures<L, R>(expression: impl IntoExpr<L>, pattern: impl IntoExpr<R>) -> Expr<Option<Vec<Option<String>>>>
529where
530 L: StringUnaryExpr,
531 R: StringUnaryExpr,
532{
533 binary_string_fn("REGEXP_MATCH", expression, pattern)
534}
535
536pub fn regex_extract<L, R>(expression: impl IntoExpr<L>, pattern: impl IntoExpr<R>) -> Expr<Option<String>>
540where
541 L: StringUnaryExpr,
542 R: StringUnaryExpr,
543{
544 binary_string_fn("REGEXP_SUBSTR", expression, pattern)
545}
546
547pub fn left<T>(arg: impl IntoExpr<T>, count: impl IntoExpr<i32>) -> Expr<<T as StringUnaryExpr>::Output>
550where
551 T: StringUnaryExpr,
552{
553 string_fn("LEFT", arg, vec![count.into_expr().node])
554}
555
556pub fn right<T>(arg: impl IntoExpr<T>, count: impl IntoExpr<i32>) -> Expr<<T as StringUnaryExpr>::Output>
559where
560 T: StringUnaryExpr,
561{
562 string_fn("RIGHT", arg, vec![count.into_expr().node])
563}
564
565pub fn substring<T>(arg: impl IntoExpr<T>, start: impl IntoExpr<i32>, count: impl IntoExpr<i32>) -> Expr<<T as StringUnaryExpr>::Output>
569where
570 T: StringUnaryExpr,
571{
572 string_fn("SUBSTRING", arg, vec![start.into_expr().node, count.into_expr().node])
573}
574
575pub fn repeat<T>(arg: impl IntoExpr<T>, count: impl IntoExpr<i32>) -> Expr<<T as StringUnaryExpr>::Output>
579where
580 T: StringUnaryExpr,
581{
582 string_fn("REPEAT", arg, vec![count.into_expr().node])
583}
584
585pub fn pad_start<T>(arg: impl IntoExpr<T>, length: impl IntoExpr<i32>, fill: impl IntoExpr<String>) -> Expr<<T as StringUnaryExpr>::Output>
589where
590 T: StringUnaryExpr,
591{
592 string_fn("LPAD", arg, vec![length.into_expr().node, fill.into_expr().node])
593}
594
595pub fn pad_end<T>(arg: impl IntoExpr<T>, length: impl IntoExpr<i32>, fill: impl IntoExpr<String>) -> Expr<<T as StringUnaryExpr>::Output>
599where
600 T: StringUnaryExpr,
601{
602 string_fn("RPAD", arg, vec![length.into_expr().node, fill.into_expr().node])
603}
604
605pub fn regex_replace<S, P, R, SP, O>(
611 source: impl IntoExpr<S>,
612 pattern: impl IntoExpr<P>,
613 replacement: impl IntoExpr<R>,
614 flags: RegexReplaceFlags,
615) -> Expr<O>
616where
617 S: StringBinaryExpr<P, String, Output = SP>,
618 SP: StringBinaryExpr<R, String, Output = O>,
619{
620 Expr::new(ExprNode::Func {
621 name: "REGEXP_REPLACE",
622 args: vec![
623 source.into_expr().node,
624 pattern.into_expr().node,
625 replacement.into_expr().node,
626 ExprNode::Value(Value::String(flags.as_postgres_str().to_string())),
627 ],
628 })
629}
630
631pub fn regex_split<S, P, O>(source: impl IntoExpr<S>, pattern: impl IntoExpr<P>, flags: RegexSplitFlags) -> Expr<O>
638where
639 S: StringBinaryExpr<P, Vec<String>, Output = O>,
640{
641 Expr::new(ExprNode::Func {
642 name: "REGEXP_SPLIT_TO_ARRAY",
643 args: vec![
644 source.into_expr().node,
645 pattern.into_expr().node,
646 ExprNode::Value(Value::String(flags.as_postgres_str().to_string())),
647 ],
648 })
649}
650
651pub fn normalize<T>(arg: impl IntoExpr<T>, form: NormalizationForm) -> Expr<<T as StringUnaryExpr>::Output>
654where
655 T: StringUnaryExpr,
656{
657 Expr::new(ExprNode::Normalize {
658 expr: Box::new(arg.into_expr().node),
659 form,
660 })
661}
662
663pub fn first_codepoint<T>(arg: impl IntoExpr<T>) -> Expr<<T as StringLengthExpr>::Output>
667where
668 T: StringLengthExpr,
669{
670 string_length_fn("ASCII", arg)
671}
672
673pub fn from_codepoint<T>(arg: impl IntoExpr<T>) -> Expr<<T as CodepointExpr>::Output>
677where
678 T: CodepointExpr,
679{
680 let expr = arg.into_expr();
681 Expr::new(ExprNode::Func {
682 name: "CHR",
683 args: vec![expr.node],
684 })
685}
686
687pub fn to_ascii<T>(arg: impl IntoExpr<T>) -> Expr<<T as StringUnaryExpr>::Output>
691where
692 T: StringUnaryExpr,
693{
694 unary_string_fn("TO_ASCII", arg)
695}
696
697pub fn case_fold<T>(arg: impl IntoExpr<T>) -> Expr<<T as StringUnaryExpr>::Output>
700where
701 T: StringUnaryExpr,
702{
703 unary_string_fn("CASEFOLD", arg)
704}
705
706pub fn is_unicode_assigned<T>(arg: impl IntoExpr<T>) -> Expr<<T as StringBoolExpr>::Output>
709where
710 T: StringBoolExpr,
711{
712 let expr = arg.into_expr();
713 Expr::new(ExprNode::Func {
714 name: "UNICODE_ASSIGNED",
715 args: vec![expr.node],
716 })
717}
718
719pub fn count<T>(arg: impl IntoExpr<T>) -> AggregateExpr<i64> {
720 let expr = arg.into_expr();
721 Expr::new(ExprNode::Func {
722 name: "COUNT",
723 args: vec![expr.node],
724 })
725}
726
727pub fn sum<T>(arg: impl IntoExpr<T>) -> AggregateExpr<T> {
728 let expr = arg.into_expr();
729 Expr::new(ExprNode::Func {
730 name: "SUM",
731 args: vec![expr.node],
732 })
733}
734
735pub trait NullableAggregateOutput {
736 type Output;
737}
738
739macro_rules! impl_nullable_aggregate_output {
740 ($($ty:ty),+ $(,)?) => {
741 $(
742 impl NullableAggregateOutput for $ty {
743 type Output = Option<$ty>;
744 }
745
746 impl NullableAggregateOutput for Option<$ty> {
747 type Output = Option<$ty>;
748 }
749 )+
750 };
751}
752
753impl_nullable_aggregate_output!(
754 String,
755 i16,
756 i32,
757 i64,
758 f32,
759 f64,
760 uuid::Uuid,
761 chrono::NaiveDateTime,
762 chrono::DateTime<chrono::Utc>,
763 chrono::NaiveDate,
764 chrono::NaiveTime,
765 crate::PgInterval,
766);
767
768pub fn min<T>(arg: impl IntoExpr<T>) -> AggregateExpr<<T as NullableAggregateOutput>::Output>
769where
770 T: NullableAggregateOutput,
771{
772 let expr = arg.into_expr();
773 Expr::new(ExprNode::Func {
774 name: "MIN",
775 args: vec![expr.node],
776 })
777}
778
779pub fn max<T>(arg: impl IntoExpr<T>) -> AggregateExpr<<T as NullableAggregateOutput>::Output>
780where
781 T: NullableAggregateOutput,
782{
783 let expr = arg.into_expr();
784 Expr::new(ExprNode::Func {
785 name: "MAX",
786 args: vec![expr.node],
787 })
788}
789
790pub fn coalesce<T>(a: impl IntoExpr<T>, b: impl IntoExpr<T>) -> Expr<T> {
791 let left = a.into_expr();
792 let right = b.into_expr();
793 Expr::new(ExprNode::Func {
794 name: "COALESCE",
795 args: vec![left.node, right.node],
796 })
797}
798
799pub fn least<T>(a: impl IntoExpr<T>, b: impl IntoExpr<T>) -> Expr<T> {
800 let left = a.into_expr();
801 let right = b.into_expr();
802 Expr::new(ExprNode::Func {
803 name: "LEAST",
804 args: vec![left.node, right.node],
805 })
806}
807
808pub fn greatest<T>(a: impl IntoExpr<T>, b: impl IntoExpr<T>) -> Expr<T> {
809 let left = a.into_expr();
810 let right = b.into_expr();
811 Expr::new(ExprNode::Func {
812 name: "GREATEST",
813 args: vec![left.node, right.node],
814 })
815}
816
817pub fn power<B, E>(base: impl IntoExpr<B>, exponent: impl IntoExpr<E>) -> Expr<f64>
818where
819 B: NumericExprType,
820 E: NumericExprType,
821{
822 let base = base.into_expr();
823 let exponent = exponent.into_expr();
824 Expr::new(ExprNode::Func {
825 name: "POWER",
826 args: vec![base.node, exponent.node],
827 })
828}
829
830pub fn date_trunc<T>(part: impl IntoExpr<String>, value: impl IntoExpr<T>) -> Expr<T> {
831 let part = part.into_expr();
832 let value = value.into_expr();
833 Expr::new(ExprNode::Func {
834 name: "DATE_TRUNC",
835 args: vec![part.node, value.node],
836 })
837}
838
839fn exists_expr(subquery: CompiledSql) -> Expr<bool> {
840 Expr::new(ExprNode::Exists { subquery })
841}
842
843pub fn exists<Out, Loads, Lock, DistinctState, GroupState>(subquery: Select<Out, Loads, Lock, DistinctState, GroupState>) -> Expr<bool> {
844 exists_expr(subquery.compile_for_exists())
845}
846
847pub trait VectorExpr<const N: usize> {}
849
850impl<const N: usize> VectorExpr<N> for PgVector<N> {}
851impl<const N: usize> VectorExpr<N> for Option<PgVector<N>> {}
852
853fn vector_binary_fn<const N: usize, L, R>(name: &'static str, left: impl IntoExpr<L>, right: impl IntoExpr<R>) -> Expr<f32>
854where
855 L: VectorExpr<N>,
856 R: VectorExpr<N>,
857{
858 let left = left.into_expr();
859 let right = right.into_expr();
860 Expr::new(ExprNode::Func {
861 name,
862 args: vec![left.node, right.node],
863 })
864}
865
866fn vector_binary_operator<const N: usize, L, R>(op: VectorBinaryOp, left: impl IntoExpr<L>, right: impl IntoExpr<R>) -> Expr<f32>
867where
868 L: VectorExpr<N>,
869 R: VectorExpr<N>,
870{
871 let left = left.into_expr();
872 let right = right.into_expr();
873 Expr::new(ExprNode::VectorBinary {
874 left: Box::new(left.node),
875 op,
876 right: Box::new(right.node),
877 })
878}
879
880pub fn l2_distance<const N: usize, L, R>(left: impl IntoExpr<L>, right: impl IntoExpr<R>) -> Expr<f32>
888where
889 L: VectorExpr<N>,
890 R: VectorExpr<N>,
891{
892 vector_binary_operator::<N, L, R>(VectorBinaryOp::L2Distance, left, right)
893}
894
895pub fn cosine_distance<const N: usize, L, R>(left: impl IntoExpr<L>, right: impl IntoExpr<R>) -> Expr<f32>
903where
904 L: VectorExpr<N>,
905 R: VectorExpr<N>,
906{
907 vector_binary_operator::<N, L, R>(VectorBinaryOp::CosineDistance, left, right)
908}
909
910pub fn inner_product<const N: usize, L, R>(left: impl IntoExpr<L>, right: impl IntoExpr<R>) -> Expr<f32>
920where
921 L: VectorExpr<N>,
922 R: VectorExpr<N>,
923{
924 vector_binary_fn::<N, L, R>("INNER_PRODUCT", left, right)
925}
926
927pub fn l1_distance<const N: usize, L, R>(left: impl IntoExpr<L>, right: impl IntoExpr<R>) -> Expr<f32>
935where
936 L: VectorExpr<N>,
937 R: VectorExpr<N>,
938{
939 vector_binary_operator::<N, L, R>(VectorBinaryOp::L1Distance, left, right)
940}
941
942pub fn inner_product_distance<const N: usize, L, R>(left: impl IntoExpr<L>, right: impl IntoExpr<R>) -> Expr<f32>
953where
954 L: VectorExpr<N>,
955 R: VectorExpr<N>,
956{
957 vector_binary_operator::<N, L, R>(VectorBinaryOp::InnerProductDistance, left, right)
958}