1use crate::dialect::{Dialect, DialectTypes};
13use crate::sql::{SQL, Token};
14use crate::traits::{SQLParam, ToSQL};
15use crate::types::{DataType, Integral, Textual};
16use crate::{MySQLDialect, PostgresDialect, SQLiteDialect};
17use drizzle_types::postgres::types::{
18 Char as PgChar, Int4 as PgInt4, Text as PgText, Varchar as PgVarchar,
19};
20use drizzle_types::sqlite::types::{Integer as SqliteInteger, Text as SqliteText};
21
22use super::{AggOr, AggregateKind, Expr, NonNull, NullOr, Nullability, SQLExpr};
23
24#[diagnostic::on_unimplemented(
25 message = "no length policy for `{Self}` on this dialect",
26 label = "length return type is not defined for this SQL type/dialect"
27)]
28pub trait LengthPolicy<D>: DataType {
29 type Output: DataType;
30}
31
32#[diagnostic::on_unimplemented(
33 message = "this string function is not available for this dialect",
34 label = "use a dialect-specific alternative"
35)]
36pub trait PostgresStringSupport {}
37
38#[diagnostic::on_unimplemented(
39 message = "INSTR is not available for this dialect",
40 label = "use a dialect-specific substring-position function"
41)]
42pub trait InstrPolicy {
43 type Output: DataType;
44}
45
46#[diagnostic::on_unimplemented(
47 message = "LEFT/RIGHT are not available for this dialect",
48 label = "use a dialect-specific substring function"
49)]
50pub trait LeftRightSupport {}
51
52#[diagnostic::on_unimplemented(
53 message = "LPAD/RPAD are not available for this dialect",
54 label = "use a dialect-specific padding expression"
55)]
56pub trait PadSupport {}
57
58#[diagnostic::on_unimplemented(
59 message = "REVERSE is not available for this dialect",
60 label = "use a dialect-specific string expression"
61)]
62pub trait ReverseSupport {}
63
64#[diagnostic::on_unimplemented(
65 message = "REPEAT is not available for this dialect",
66 label = "use a dialect-specific string expression"
67)]
68pub trait RepeatSupport {}
69
70impl LengthPolicy<SQLiteDialect> for SqliteText {
71 type Output = SqliteInteger;
72}
73impl LengthPolicy<SQLiteDialect> for drizzle_types::sqlite::types::Any {
74 type Output = SqliteInteger;
75}
76
77impl LengthPolicy<PostgresDialect> for PgVarchar {
78 type Output = PgInt4;
79}
80impl LengthPolicy<PostgresDialect> for PgText {
81 type Output = PgInt4;
82}
83impl LengthPolicy<PostgresDialect> for PgChar {
84 type Output = PgInt4;
85}
86
87macro_rules! mysql_length_policy {
88 ($($ty:ty),+ $(,)?) => {
89 $(
90 impl LengthPolicy<MySQLDialect> for $ty {
91 type Output = drizzle_types::mysql::types::BigInt;
92 }
93 )+
94 };
95}
96
97mysql_length_policy!(
98 drizzle_types::mysql::types::Char,
99 drizzle_types::mysql::types::Varchar,
100 drizzle_types::mysql::types::TinyText,
101 drizzle_types::mysql::types::Text,
102 drizzle_types::mysql::types::MediumText,
103 drizzle_types::mysql::types::LongText,
104 drizzle_types::mysql::types::Enum,
105 drizzle_types::mysql::types::Set,
106);
107
108impl PostgresStringSupport for PostgresDialect {}
109
110impl InstrPolicy for SQLiteDialect {
111 type Output = SqliteInteger;
112}
113impl InstrPolicy for MySQLDialect {
114 type Output = drizzle_types::mysql::types::BigInt;
115}
116
117impl LeftRightSupport for PostgresDialect {}
118impl LeftRightSupport for MySQLDialect {}
119impl PadSupport for PostgresDialect {}
120impl PadSupport for MySQLDialect {}
121impl ReverseSupport for PostgresDialect {}
122impl ReverseSupport for MySQLDialect {}
123impl RepeatSupport for PostgresDialect {}
124impl RepeatSupport for MySQLDialect {}
125
126pub fn upper<'a, V, E>(
146 expr: E,
147) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Text, E::Nullable, E::Aggregate>
148where
149 V: SQLParam + 'a,
150 E: Expr<'a, V>,
151 E::SQLType: Textual,
152{
153 SQLExpr::new(SQL::func("UPPER", expr.into_sql()))
154}
155
156pub fn lower<'a, V, E>(
171 expr: E,
172) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Text, E::Nullable, E::Aggregate>
173where
174 V: SQLParam + 'a,
175 E: Expr<'a, V>,
176 E::SQLType: Textual,
177{
178 SQLExpr::new(SQL::func("LOWER", expr.into_sql()))
179}
180
181pub fn trim<'a, V, E>(
200 expr: E,
201) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Text, E::Nullable, E::Aggregate>
202where
203 V: SQLParam + 'a,
204 E: Expr<'a, V>,
205 E::SQLType: Textual,
206{
207 SQLExpr::new(SQL::func("TRIM", expr.into_sql()))
208}
209
210pub fn ltrim<'a, V, E>(
214 expr: E,
215) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Text, E::Nullable, E::Aggregate>
216where
217 V: SQLParam + 'a,
218 E: Expr<'a, V>,
219 E::SQLType: Textual,
220{
221 SQLExpr::new(SQL::func("LTRIM", expr.into_sql()))
222}
223
224pub fn rtrim<'a, V, E>(
228 expr: E,
229) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Text, E::Nullable, E::Aggregate>
230where
231 V: SQLParam + 'a,
232 E: Expr<'a, V>,
233 E::SQLType: Textual,
234{
235 SQLExpr::new(SQL::func("RTRIM", expr.into_sql()))
236}
237
238pub fn collate<'a, V, E>(
270 expr: E,
271 name: &'static str,
272) -> SQLExpr<'a, V, E::SQLType, E::Nullable, E::Aggregate>
273where
274 V: SQLParam + 'a,
275 E: Expr<'a, V>,
276 E::SQLType: Textual,
277{
278 let inner = expr.into_sql().parens_if_subquery();
279 SQLExpr::new(
280 SQL::token(Token::LPAREN)
281 .append(inner)
282 .push(Token::COLLATE)
283 .append(SQL::ident(name))
284 .push(Token::RPAREN),
285 )
286}
287
288#[allow(clippy::type_complexity)]
309pub fn length<'a, V, E>(
310 expr: E,
311) -> SQLExpr<'a, V, <E::SQLType as LengthPolicy<V::DialectMarker>>::Output, E::Nullable, E::Aggregate>
312where
313 V: SQLParam + 'a,
314 E: Expr<'a, V>,
315 E::SQLType: LengthPolicy<V::DialectMarker>,
316{
317 SQLExpr::new(SQL::func("LENGTH", expr.into_sql()))
318}
319
320#[allow(clippy::type_complexity)]
340pub fn substr<'a, V, E, S, L>(
341 expr: E,
342 start: S,
343 len: L,
344) -> SQLExpr<
345 'a,
346 V,
347 <V::DialectMarker as DialectTypes>::Text,
348 <<E::Nullable as NullOr<S::Nullable>>::Output as NullOr<L::Nullable>>::Output,
349 <<E::Aggregate as AggOr<S::Aggregate>>::Output as AggOr<L::Aggregate>>::Output,
350>
351where
352 V: SQLParam + 'a,
353 E: Expr<'a, V>,
354 E::SQLType: Textual,
355 S: Expr<'a, V>,
356 S::SQLType: Integral,
357 S::Nullable: Nullability,
358 S::Aggregate: AggregateKind,
359 L: Expr<'a, V>,
360 L::SQLType: Integral,
361 L::Nullable: Nullability,
362 L::Aggregate: AggregateKind,
363 E::Nullable: NullOr<S::Nullable>,
364 <E::Nullable as NullOr<S::Nullable>>::Output: NullOr<L::Nullable>,
365 E::Aggregate: AggOr<S::Aggregate>,
366 <E::Aggregate as AggOr<S::Aggregate>>::Output: AggOr<L::Aggregate>,
367{
368 SQLExpr::new(SQL::func(
369 "SUBSTR",
370 expr.into_sql()
371 .push(Token::COMMA)
372 .append(start.into_sql())
373 .push(Token::COMMA)
374 .append(len.into_sql()),
375 ))
376}
377
378#[allow(clippy::type_complexity)]
398pub fn replace<'a, V, E, F, T>(
399 expr: E,
400 from: F,
401 to: T,
402) -> SQLExpr<
403 'a,
404 V,
405 <V::DialectMarker as DialectTypes>::Text,
406 <<E::Nullable as NullOr<F::Nullable>>::Output as NullOr<T::Nullable>>::Output,
407 <<E::Aggregate as AggOr<F::Aggregate>>::Output as AggOr<T::Aggregate>>::Output,
408>
409where
410 V: SQLParam + 'a,
411 E: Expr<'a, V>,
412 E::SQLType: Textual,
413 F: Expr<'a, V>,
414 F::SQLType: Textual,
415 F::Nullable: Nullability,
416 F::Aggregate: AggregateKind,
417 T: Expr<'a, V>,
418 T::SQLType: Textual,
419 T::Nullable: Nullability,
420 T::Aggregate: AggregateKind,
421 E::Nullable: NullOr<F::Nullable>,
422 <E::Nullable as NullOr<F::Nullable>>::Output: NullOr<T::Nullable>,
423 E::Aggregate: AggOr<F::Aggregate>,
424 <E::Aggregate as AggOr<F::Aggregate>>::Output: AggOr<T::Aggregate>,
425{
426 SQLExpr::new(SQL::func(
427 "REPLACE",
428 expr.into_sql()
429 .push(Token::COMMA)
430 .append(from.into_sql())
431 .push(Token::COMMA)
432 .append(to.into_sql()),
433 ))
434}
435
436#[allow(clippy::type_complexity)]
457pub fn instr<'a, V, E, S>(
458 expr: E,
459 search: S,
460) -> SQLExpr<
461 'a,
462 V,
463 <V::DialectMarker as InstrPolicy>::Output,
464 <E::Nullable as NullOr<S::Nullable>>::Output,
465 <E::Aggregate as AggOr<S::Aggregate>>::Output,
466>
467where
468 V: SQLParam + 'a,
469 V::DialectMarker: InstrPolicy,
470 E: Expr<'a, V>,
471 E::SQLType: Textual,
472 S: Expr<'a, V>,
473 S::SQLType: Textual,
474 S::Nullable: Nullability,
475 E::Nullable: NullOr<S::Nullable>,
476 S::Aggregate: AggregateKind,
477 E::Aggregate: AggOr<S::Aggregate>,
478{
479 SQLExpr::new(SQL::func(
480 "INSTR",
481 expr.into_sql().push(Token::COMMA).append(search.into_sql()),
482 ))
483}
484
485#[allow(clippy::type_complexity)]
487pub fn strpos<'a, V, E, S>(
488 expr: E,
489 search: S,
490) -> SQLExpr<
491 'a,
492 V,
493 drizzle_types::postgres::types::Int4,
494 <E::Nullable as NullOr<S::Nullable>>::Output,
495 <E::Aggregate as AggOr<S::Aggregate>>::Output,
496>
497where
498 V: SQLParam + 'a,
499 V::DialectMarker: PostgresStringSupport,
500 E: Expr<'a, V>,
501 E::SQLType: Textual,
502 S: Expr<'a, V>,
503 S::SQLType: Textual,
504 S::Nullable: Nullability,
505 E::Nullable: NullOr<S::Nullable>,
506 S::Aggregate: AggregateKind,
507 E::Aggregate: AggOr<S::Aggregate>,
508{
509 SQLExpr::new(SQL::func(
510 "STRPOS",
511 expr.into_sql().push(Token::COMMA).append(search.into_sql()),
512 ))
513}
514
515#[allow(clippy::type_complexity)]
552pub fn concat<'a, V, E1, E2>(
553 expr1: E1,
554 expr2: E2,
555) -> SQLExpr<
556 'a,
557 V,
558 <V::DialectMarker as DialectTypes>::Text,
559 <E1::Nullable as NullOr<E2::Nullable>>::Output,
560 <E1::Aggregate as AggOr<E2::Aggregate>>::Output,
561>
562where
563 V: SQLParam + 'a,
564 E1: Expr<'a, V>,
565 E1::SQLType: Textual,
566 E2: Expr<'a, V>,
567 E2::SQLType: Textual,
568 E1::Nullable: NullOr<E2::Nullable>,
569 E2::Nullable: Nullability,
570 E2::Aggregate: AggregateKind,
571 E1::Aggregate: AggOr<E2::Aggregate>,
572{
573 let left = expr1.into_sql();
574 let right = expr2.into_sql();
575 let sql = match V::DIALECT {
576 Dialect::MySQL => SQL::func("CONCAT", left.push(Token::COMMA).append(right)),
577 Dialect::SQLite | Dialect::PostgreSQL => {
578 super::ops::binary_operator_sql(left, Token::CONCAT, right)
579 }
580 };
581 SQLExpr::new(sql)
582}
583
584#[allow(clippy::type_complexity)]
606pub fn concat_ws<'a, V, S, I>(
607 sep: S,
608 values: I,
609) -> SQLExpr<
610 'a,
611 V,
612 <V::DialectMarker as DialectTypes>::Text,
613 S::Nullable,
614 <S::Aggregate as AggOr<<I::Item as Expr<'a, V>>::Aggregate>>::Output,
615>
616where
617 V: SQLParam + 'a,
618 S: Expr<'a, V>,
619 S::SQLType: Textual,
620 I: IntoIterator,
621 I::Item: Expr<'a, V>,
622 <I::Item as Expr<'a, V>>::SQLType: Textual,
623 S::Aggregate: AggOr<<I::Item as Expr<'a, V>>::Aggregate>,
624 <I::Item as Expr<'a, V>>::Aggregate: AggregateKind,
625{
626 let mut sql = sep.into_sql();
627 for value in values {
628 sql = sql.push(Token::COMMA).append(value.into_sql());
629 }
630 SQLExpr::new(SQL::func("CONCAT_WS", sql))
631}
632
633#[allow(clippy::type_complexity)]
652pub fn left<'a, V, E, N>(
653 expr: E,
654 n: N,
655) -> SQLExpr<
656 'a,
657 V,
658 <V::DialectMarker as DialectTypes>::Text,
659 <E::Nullable as NullOr<N::Nullable>>::Output,
660 <E::Aggregate as AggOr<N::Aggregate>>::Output,
661>
662where
663 V: SQLParam + 'a,
664 V::DialectMarker: LeftRightSupport,
665 E: Expr<'a, V>,
666 E::SQLType: Textual,
667 N: Expr<'a, V>,
668 N::SQLType: Integral,
669 N::Nullable: Nullability,
670 E::Nullable: NullOr<N::Nullable>,
671 N::Aggregate: AggregateKind,
672 E::Aggregate: AggOr<N::Aggregate>,
673{
674 SQLExpr::new(SQL::func(
675 "LEFT",
676 expr.into_sql().push(Token::COMMA).append(n.into_sql()),
677 ))
678}
679
680#[allow(clippy::type_complexity)]
695pub fn right<'a, V, E, N>(
696 expr: E,
697 n: N,
698) -> SQLExpr<
699 'a,
700 V,
701 <V::DialectMarker as DialectTypes>::Text,
702 <E::Nullable as NullOr<N::Nullable>>::Output,
703 <E::Aggregate as AggOr<N::Aggregate>>::Output,
704>
705where
706 V: SQLParam + 'a,
707 V::DialectMarker: LeftRightSupport,
708 E: Expr<'a, V>,
709 E::SQLType: Textual,
710 N: Expr<'a, V>,
711 N::SQLType: Integral,
712 N::Nullable: Nullability,
713 E::Nullable: NullOr<N::Nullable>,
714 N::Aggregate: AggregateKind,
715 E::Aggregate: AggOr<N::Aggregate>,
716{
717 SQLExpr::new(SQL::func(
718 "RIGHT",
719 expr.into_sql().push(Token::COMMA).append(n.into_sql()),
720 ))
721}
722
723#[allow(clippy::type_complexity)]
738pub fn split_part<'a, V, E, D, N>(
739 expr: E,
740 delimiter: D,
741 n: N,
742) -> SQLExpr<
743 'a,
744 V,
745 <V::DialectMarker as DialectTypes>::Text,
746 <<E::Nullable as NullOr<D::Nullable>>::Output as NullOr<N::Nullable>>::Output,
747 <<E::Aggregate as AggOr<D::Aggregate>>::Output as AggOr<N::Aggregate>>::Output,
748>
749where
750 V: SQLParam + 'a,
751 V::DialectMarker: PostgresStringSupport,
752 E: Expr<'a, V>,
753 E::SQLType: Textual,
754 D: Expr<'a, V>,
755 D::SQLType: Textual,
756 D::Nullable: Nullability,
757 D::Aggregate: AggregateKind,
758 N: Expr<'a, V>,
759 N::SQLType: Integral,
760 N::Nullable: Nullability,
761 N::Aggregate: AggregateKind,
762 E::Nullable: NullOr<D::Nullable>,
763 <E::Nullable as NullOr<D::Nullable>>::Output: NullOr<N::Nullable>,
764 E::Aggregate: AggOr<D::Aggregate>,
765 <E::Aggregate as AggOr<D::Aggregate>>::Output: AggOr<N::Aggregate>,
766{
767 SQLExpr::new(SQL::func(
768 "SPLIT_PART",
769 expr.into_sql()
770 .push(Token::COMMA)
771 .append(delimiter.into_sql())
772 .push(Token::COMMA)
773 .append(n.into_sql()),
774 ))
775}
776
777#[allow(clippy::type_complexity)]
790pub fn lpad<'a, V, E, L, F>(
791 expr: E,
792 length: L,
793 fill: F,
794) -> SQLExpr<
795 'a,
796 V,
797 <V::DialectMarker as DialectTypes>::Text,
798 <<E::Nullable as NullOr<L::Nullable>>::Output as NullOr<F::Nullable>>::Output,
799 <<E::Aggregate as AggOr<L::Aggregate>>::Output as AggOr<F::Aggregate>>::Output,
800>
801where
802 V: SQLParam + 'a,
803 V::DialectMarker: PadSupport,
804 E: Expr<'a, V>,
805 E::SQLType: Textual,
806 L: Expr<'a, V>,
807 L::SQLType: Integral,
808 L::Nullable: Nullability,
809 L::Aggregate: AggregateKind,
810 F: Expr<'a, V>,
811 F::SQLType: Textual,
812 F::Nullable: Nullability,
813 E::Nullable: NullOr<L::Nullable>,
814 <E::Nullable as NullOr<L::Nullable>>::Output: NullOr<F::Nullable>,
815 F::Aggregate: AggregateKind,
816 E::Aggregate: AggOr<L::Aggregate>,
817 <E::Aggregate as AggOr<L::Aggregate>>::Output: AggOr<F::Aggregate>,
818{
819 SQLExpr::new(SQL::func(
820 "LPAD",
821 expr.into_sql()
822 .push(Token::COMMA)
823 .append(length.into_sql())
824 .push(Token::COMMA)
825 .append(fill.into_sql()),
826 ))
827}
828
829#[allow(clippy::type_complexity)]
842pub fn rpad<'a, V, E, L, F>(
843 expr: E,
844 length: L,
845 fill: F,
846) -> SQLExpr<
847 'a,
848 V,
849 <V::DialectMarker as DialectTypes>::Text,
850 <<E::Nullable as NullOr<L::Nullable>>::Output as NullOr<F::Nullable>>::Output,
851 <<E::Aggregate as AggOr<L::Aggregate>>::Output as AggOr<F::Aggregate>>::Output,
852>
853where
854 V: SQLParam + 'a,
855 V::DialectMarker: PadSupport,
856 E: Expr<'a, V>,
857 E::SQLType: Textual,
858 L: Expr<'a, V>,
859 L::SQLType: Integral,
860 L::Nullable: Nullability,
861 L::Aggregate: AggregateKind,
862 F: Expr<'a, V>,
863 F::SQLType: Textual,
864 F::Nullable: Nullability,
865 E::Nullable: NullOr<L::Nullable>,
866 <E::Nullable as NullOr<L::Nullable>>::Output: NullOr<F::Nullable>,
867 F::Aggregate: AggregateKind,
868 E::Aggregate: AggOr<L::Aggregate>,
869 <E::Aggregate as AggOr<L::Aggregate>>::Output: AggOr<F::Aggregate>,
870{
871 SQLExpr::new(SQL::func(
872 "RPAD",
873 expr.into_sql()
874 .push(Token::COMMA)
875 .append(length.into_sql())
876 .push(Token::COMMA)
877 .append(fill.into_sql()),
878 ))
879}
880
881pub fn initcap<'a, V, E>(
885 expr: E,
886) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Text, E::Nullable, E::Aggregate>
887where
888 V: SQLParam + 'a,
889 V::DialectMarker: PostgresStringSupport,
890 E: Expr<'a, V>,
891 E::SQLType: Textual,
892{
893 SQLExpr::new(SQL::func("INITCAP", expr.into_sql()))
894}
895
896pub fn reverse<'a, V, E>(
900 expr: E,
901) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Text, E::Nullable, E::Aggregate>
902where
903 V: SQLParam + 'a,
904 V::DialectMarker: ReverseSupport,
905 E: Expr<'a, V>,
906 E::SQLType: Textual,
907{
908 SQLExpr::new(SQL::func("REVERSE", expr.into_sql()))
909}
910
911#[allow(clippy::type_complexity)]
924pub fn repeat<'a, V, E, N>(
925 expr: E,
926 n: N,
927) -> SQLExpr<
928 'a,
929 V,
930 <V::DialectMarker as DialectTypes>::Text,
931 <E::Nullable as NullOr<N::Nullable>>::Output,
932 <E::Aggregate as AggOr<N::Aggregate>>::Output,
933>
934where
935 V: SQLParam + 'a,
936 V::DialectMarker: RepeatSupport,
937 E: Expr<'a, V>,
938 E::SQLType: Textual,
939 N: Expr<'a, V>,
940 N::SQLType: Integral,
941 N::Nullable: Nullability,
942 E::Nullable: NullOr<N::Nullable>,
943 N::Aggregate: AggregateKind,
944 E::Aggregate: AggOr<N::Aggregate>,
945{
946 SQLExpr::new(SQL::func(
947 "REPEAT",
948 expr.into_sql().push(Token::COMMA).append(n.into_sql()),
949 ))
950}
951
952#[allow(clippy::type_complexity)]
968pub fn starts_with<'a, V, E, P>(
969 expr: E,
970 prefix: P,
971) -> SQLExpr<
972 'a,
973 V,
974 <V::DialectMarker as DialectTypes>::Bool,
975 NonNull,
976 <E::Aggregate as AggOr<P::Aggregate>>::Output,
977>
978where
979 V: SQLParam + 'a,
980 V::DialectMarker: PostgresStringSupport,
981 E: Expr<'a, V>,
982 E::SQLType: Textual,
983 P: Expr<'a, V>,
984 P::SQLType: Textual,
985 P::Aggregate: AggregateKind,
986 E::Aggregate: AggOr<P::Aggregate>,
987{
988 SQLExpr::new(SQL::func(
989 "STARTS_WITH",
990 expr.into_sql().push(Token::COMMA).append(prefix.into_sql()),
991 ))
992}
993
994pub trait CharLengthPolicy {
1002 const CHAR_LENGTH_FN: &'static str;
1003}
1004
1005impl CharLengthPolicy for SQLiteDialect {
1006 const CHAR_LENGTH_FN: &'static str = "LENGTH";
1007}
1008
1009impl CharLengthPolicy for PostgresDialect {
1010 const CHAR_LENGTH_FN: &'static str = "CHAR_LENGTH";
1011}
1012
1013impl CharLengthPolicy for crate::MySQLDialect {
1014 const CHAR_LENGTH_FN: &'static str = "CHAR_LENGTH";
1015}
1016
1017#[allow(clippy::type_complexity)]
1034pub fn char_length<'a, V, E>(
1035 expr: E,
1036) -> SQLExpr<'a, V, <E::SQLType as LengthPolicy<V::DialectMarker>>::Output, E::Nullable, E::Aggregate>
1037where
1038 V: SQLParam + 'a,
1039 V::DialectMarker: CharLengthPolicy,
1040 E: Expr<'a, V>,
1041 E::SQLType: LengthPolicy<V::DialectMarker>,
1042{
1043 SQLExpr::new(SQL::func(
1044 <V::DialectMarker as CharLengthPolicy>::CHAR_LENGTH_FN,
1045 expr.into_sql(),
1046 ))
1047}
1048
1049#[allow(clippy::type_complexity)]
1064pub fn octet_length<'a, V, E>(
1065 expr: E,
1066) -> SQLExpr<'a, V, <E::SQLType as LengthPolicy<V::DialectMarker>>::Output, E::Nullable, E::Aggregate>
1067where
1068 V: SQLParam + 'a,
1069 E: Expr<'a, V>,
1070 E::SQLType: LengthPolicy<V::DialectMarker>,
1071{
1072 SQLExpr::new(SQL::func("OCTET_LENGTH", expr.into_sql()))
1073}
1074
1075#[allow(clippy::type_complexity)]
1095pub fn translate<'a, V, E, F, T>(
1096 expr: E,
1097 from: F,
1098 to: T,
1099) -> SQLExpr<
1100 'a,
1101 V,
1102 <V::DialectMarker as DialectTypes>::Text,
1103 E::Nullable,
1104 <<E::Aggregate as AggOr<F::Aggregate>>::Output as AggOr<T::Aggregate>>::Output,
1105>
1106where
1107 V: SQLParam + 'a,
1108 V::DialectMarker: PostgresStringSupport,
1109 E: Expr<'a, V>,
1110 E::SQLType: Textual,
1111 F: Expr<'a, V>,
1112 F::SQLType: Textual,
1113 F::Aggregate: AggregateKind,
1114 T: Expr<'a, V>,
1115 T::SQLType: Textual,
1116 T::Aggregate: AggregateKind,
1117 E::Aggregate: AggOr<F::Aggregate>,
1118 <E::Aggregate as AggOr<F::Aggregate>>::Output: AggOr<T::Aggregate>,
1119{
1120 SQLExpr::new(SQL::func(
1121 "TRANSLATE",
1122 expr.into_sql()
1123 .push(Token::COMMA)
1124 .append(from.into_sql())
1125 .push(Token::COMMA)
1126 .append(to.into_sql()),
1127 ))
1128}
1129
1130#[allow(clippy::type_complexity)]
1150pub fn regexp_replace<'a, V, E, P, R>(
1151 expr: E,
1152 pattern: P,
1153 replacement: R,
1154) -> SQLExpr<
1155 'a,
1156 V,
1157 <V::DialectMarker as DialectTypes>::Text,
1158 E::Nullable,
1159 <<E::Aggregate as AggOr<P::Aggregate>>::Output as AggOr<R::Aggregate>>::Output,
1160>
1161where
1162 V: SQLParam + 'a,
1163 V::DialectMarker: PostgresStringSupport,
1164 E: Expr<'a, V>,
1165 E::SQLType: Textual,
1166 P: Expr<'a, V>,
1167 P::SQLType: Textual,
1168 P::Aggregate: AggregateKind,
1169 R: Expr<'a, V>,
1170 R::SQLType: Textual,
1171 R::Aggregate: AggregateKind,
1172 E::Aggregate: AggOr<P::Aggregate>,
1173 <E::Aggregate as AggOr<P::Aggregate>>::Output: AggOr<R::Aggregate>,
1174{
1175 SQLExpr::new(SQL::func(
1176 "REGEXP_REPLACE",
1177 expr.into_sql()
1178 .push(Token::COMMA)
1179 .append(pattern.into_sql())
1180 .push(Token::COMMA)
1181 .append(replacement.into_sql()),
1182 ))
1183}
1184
1185#[allow(clippy::type_complexity)]
1200pub fn regexp_replace_flags<'a, V, E, P, R, F>(
1201 expr: E,
1202 pattern: P,
1203 replacement: R,
1204 flags: F,
1205) -> SQLExpr<
1206 'a,
1207 V,
1208 <V::DialectMarker as DialectTypes>::Text,
1209 E::Nullable,
1210 <<<E::Aggregate as AggOr<P::Aggregate>>::Output as AggOr<R::Aggregate>>::Output as AggOr<
1211 F::Aggregate,
1212 >>::Output,
1213>
1214where
1215 V: SQLParam + 'a,
1216 V::DialectMarker: PostgresStringSupport,
1217 E: Expr<'a, V>,
1218 E::SQLType: Textual,
1219 P: Expr<'a, V>,
1220 P::SQLType: Textual,
1221 P::Aggregate: AggregateKind,
1222 R: Expr<'a, V>,
1223 R::SQLType: Textual,
1224 R::Aggregate: AggregateKind,
1225 F: Expr<'a, V>,
1226 F::SQLType: Textual,
1227 F::Aggregate: AggregateKind,
1228 E::Aggregate: AggOr<P::Aggregate>,
1229 <E::Aggregate as AggOr<P::Aggregate>>::Output: AggOr<R::Aggregate>,
1230 <<E::Aggregate as AggOr<P::Aggregate>>::Output as AggOr<R::Aggregate>>::Output:
1231 AggOr<F::Aggregate>,
1232{
1233 SQLExpr::new(SQL::func(
1234 "REGEXP_REPLACE",
1235 expr.into_sql()
1236 .push(Token::COMMA)
1237 .append(pattern.into_sql())
1238 .push(Token::COMMA)
1239 .append(replacement.into_sql())
1240 .push(Token::COMMA)
1241 .append(flags.into_sql()),
1242 ))
1243}
1244
1245#[allow(clippy::type_complexity)]
1261pub fn regexp_match<'a, V, E, P>(
1262 expr: E,
1263 pattern: P,
1264) -> SQLExpr<
1265 'a,
1266 V,
1267 crate::types::Array<<V::DialectMarker as DialectTypes>::Text>,
1268 super::Null,
1269 <E::Aggregate as AggOr<P::Aggregate>>::Output,
1270>
1271where
1272 V: SQLParam + 'a,
1273 V::DialectMarker: PostgresStringSupport,
1274 E: Expr<'a, V>,
1275 E::SQLType: Textual,
1276 P: Expr<'a, V>,
1277 P::SQLType: Textual,
1278 P::Aggregate: AggregateKind,
1279 E::Aggregate: AggOr<P::Aggregate>,
1280{
1281 SQLExpr::new(SQL::func(
1282 "REGEXP_MATCH",
1283 expr.into_sql()
1284 .push(Token::COMMA)
1285 .append(pattern.into_sql()),
1286 ))
1287}
1288
1289#[allow(clippy::type_complexity)]
1304pub fn regexp_match_flags<'a, V, E, P, F>(
1305 expr: E,
1306 pattern: P,
1307 flags: F,
1308) -> SQLExpr<
1309 'a,
1310 V,
1311 crate::types::Array<<V::DialectMarker as DialectTypes>::Text>,
1312 super::Null,
1313 <<E::Aggregate as AggOr<P::Aggregate>>::Output as AggOr<F::Aggregate>>::Output,
1314>
1315where
1316 V: SQLParam + 'a,
1317 V::DialectMarker: PostgresStringSupport,
1318 E: Expr<'a, V>,
1319 E::SQLType: Textual,
1320 P: Expr<'a, V>,
1321 P::SQLType: Textual,
1322 P::Aggregate: AggregateKind,
1323 F: Expr<'a, V>,
1324 F::SQLType: Textual,
1325 F::Aggregate: AggregateKind,
1326 E::Aggregate: AggOr<P::Aggregate>,
1327 <E::Aggregate as AggOr<P::Aggregate>>::Output: AggOr<F::Aggregate>,
1328{
1329 SQLExpr::new(SQL::func(
1330 "REGEXP_MATCH",
1331 expr.into_sql()
1332 .push(Token::COMMA)
1333 .append(pattern.into_sql())
1334 .push(Token::COMMA)
1335 .append(flags.into_sql()),
1336 ))
1337}