diesel/pg/expression/
operators.rs

1use crate::backend::{Backend, DieselReserveSpecialization};
2use crate::expression::expression_types::NotSelectable;
3use crate::expression::{TypedExpressionType, ValidGrouping};
4use crate::pg::Pg;
5use crate::query_builder::update_statement::changeset::AssignmentTarget;
6use crate::query_builder::{AstPass, QueryFragment, QueryId};
7use crate::query_dsl::positional_order_dsl::{IntoPositionalOrderExpr, PositionalOrderExpr};
8use crate::sql_types::{
9    Array, Bigint, Bool, DieselNumericOps, Inet, Integer, Jsonb, SqlType, Text,
10};
11use crate::{Column, QueryResult};
12
13__diesel_infix_operator!(IsDistinctFrom, " IS DISTINCT FROM ", ConstantNullability Bool, backend: Pg);
14__diesel_infix_operator!(IsNotDistinctFrom, " IS NOT DISTINCT FROM ", ConstantNullability Bool, backend: Pg);
15infix_operator!(OverlapsWith, " && ", backend: Pg);
16infix_operator!(Contains, " @> ", backend: Pg);
17infix_operator!(IsContainedBy, " <@ ", backend: Pg);
18infix_operator!(ILike, " ILIKE ", backend: Pg);
19infix_operator!(ExtendsRightTo, " &< ", backend: Pg);
20infix_operator!(ExtendsLeftTo, " &> ", backend: Pg);
21infix_operator!(NotILike, " NOT ILIKE ", backend: Pg);
22infix_operator!(SimilarTo, " SIMILAR TO ", backend: Pg);
23infix_operator!(NotSimilarTo, " NOT SIMILAR TO ", backend: Pg);
24postfix_operator!(NullsFirst, " NULLS FIRST", NotSelectable, backend: Pg);
25postfix_operator!(NullsLast, " NULLS LAST", NotSelectable, backend: Pg);
26postfix_operator!(IsJson, " IS JSON", ConditionalNullability Bool, backend: Pg);
27postfix_operator!(IsNotJson, " IS NOT JSON", ConditionalNullability Bool, backend: Pg);
28postfix_operator!(IsJsonObject, " IS JSON OBJECT", ConditionalNullability Bool, backend: Pg);
29postfix_operator!(IsNotJsonObject, " IS NOT JSON OBJECT", ConditionalNullability Bool, backend: Pg);
30postfix_operator!(IsJsonArray, " IS JSON ARRAY", ConditionalNullability Bool, backend: Pg);
31postfix_operator!(IsNotJsonArray, " IS NOT JSON ARRAY", ConditionalNullability Bool, backend: Pg);
32postfix_operator!(IsJsonScalar, " IS JSON SCALAR", ConditionalNullability Bool, backend: Pg);
33postfix_operator!(IsNotJsonScalar, " IS NOT JSON SCALAR", ConditionalNullability Bool, backend: Pg);
34infix_operator!(ContainsNet, " >> ", backend: Pg);
35infix_operator!(ContainsNetLoose, " >>= ", backend: Pg);
36infix_operator!(IsContainedByNet, " << ", backend: Pg);
37infix_operator!(IsContainedByNetLoose, " <<= ", backend: Pg);
38infix_operator!(AndNet, " & ", Inet, backend: Pg);
39infix_operator!(OrNet, " | ", Inet, backend: Pg);
40infix_operator!(DifferenceNet, " - ", Bigint, backend: Pg);
41infix_operator!(HasKeyJsonb, " ? ", backend: Pg);
42infix_operator!(HasAnyKeyJsonb, " ?| ", backend: Pg);
43infix_operator!(HasAllKeysJsonb, " ?& ", backend: Pg);
44infix_operator!(RangeAdjacent, " -|- ", backend: Pg);
45infix_operator!(RemoveFromJsonb, " - ", Jsonb, backend: Pg);
46__diesel_infix_operator!(
47    RetrieveAsObjectJson,
48    " -> ",
49    __diesel_internal_SameResultAsInput,
50    backend: Pg
51);
52infix_operator!(RetrieveAsTextJson, " ->> ", Text, backend: Pg);
53__diesel_infix_operator!(
54    RetrieveByPathAsObjectJson,
55    " #> ",
56    __diesel_internal_SameResultAsInput,
57    backend: Pg
58);
59infix_operator!(RetrieveByPathAsTextJson, " #>> ", Text, backend: Pg);
60infix_operator!(RemoveByPathFromJsonb, " #-", Jsonb, backend: Pg);
61
62__diesel_infix_operator!(
63    UnionsRange,
64    " + ",
65    __diesel_internal_SameResultAsInput,
66    backend: Pg
67);
68
69__diesel_infix_operator!(
70    DifferenceRange,
71    " - ",
72    __diesel_internal_SameResultAsInput,
73    backend: Pg
74);
75
76__diesel_infix_operator!(
77    IntersectionRange,
78    " * ",
79    __diesel_internal_SameResultAsInput,
80    backend: Pg
81);
82
83impl<T: PositionalOrderExpr> PositionalOrderExpr for NullsFirst<T> {}
84impl<T: PositionalOrderExpr> PositionalOrderExpr for NullsLast<T> {}
85
86impl<T: PositionalOrderExpr> IntoPositionalOrderExpr for NullsFirst<T> {
87    type Output = NullsFirst<T>;
88
89    fn into_positional_expr(self) -> Self::Output {
90        self
91    }
92}
93impl<T: PositionalOrderExpr> IntoPositionalOrderExpr for NullsLast<T> {
94    type Output = NullsLast<T>;
95
96    fn into_positional_expr(self) -> Self::Output {
97        self
98    }
99}
100
101#[derive(Debug, Clone, Copy, QueryId, DieselNumericOps, ValidGrouping)]
102#[doc(hidden)]
103pub struct ArrayIndex<L, R> {
104    pub(crate) array_expr: L,
105    pub(crate) index_expr: R,
106}
107
108impl<L, R> ArrayIndex<L, R> {
109    pub fn new(array_expr: L, index_expr: R) -> Self {
110        Self {
111            array_expr,
112            index_expr,
113        }
114    }
115}
116
117impl<L, R, ST> crate::expression::Expression for ArrayIndex<L, R>
118where
119    L: crate::expression::Expression<SqlType = Array<ST>>,
120    R: crate::expression::Expression<SqlType = Integer>,
121    ST: SqlType + TypedExpressionType,
122{
123    type SqlType = ST;
124}
125
126impl_selectable_expression!(ArrayIndex<L, R>);
127
128impl<L, R> QueryFragment<Pg> for ArrayIndex<L, R>
129where
130    L: QueryFragment<Pg>,
131    R: QueryFragment<Pg>,
132{
133    fn walk_ast<'b>(
134        &'b self,
135        mut out: crate::query_builder::AstPass<'_, 'b, Pg>,
136    ) -> crate::result::QueryResult<()> {
137        out.push_sql("(");
138        self.array_expr.walk_ast(out.reborrow())?;
139        out.push_sql(")");
140        out.push_sql("[");
141        self.index_expr.walk_ast(out.reborrow())?;
142        out.push_sql("]");
143        Ok(())
144    }
145}
146
147// we cannot use the additional
148// parenthesis for updates
149#[derive(Debug)]
150pub struct UpdateArrayIndex<L, R>(ArrayIndex<L, R>);
151
152impl<L, R> QueryFragment<Pg> for UpdateArrayIndex<L, R>
153where
154    L: QueryFragment<Pg>,
155    R: QueryFragment<Pg>,
156{
157    fn walk_ast<'b>(
158        &'b self,
159        mut out: crate::query_builder::AstPass<'_, 'b, Pg>,
160    ) -> crate::result::QueryResult<()> {
161        self.0.array_expr.walk_ast(out.reborrow())?;
162        out.push_sql("[");
163        self.0.index_expr.walk_ast(out.reborrow())?;
164        out.push_sql("]");
165        Ok(())
166    }
167}
168
169impl<L, R> AssignmentTarget for ArrayIndex<L, R>
170where
171    L: Column,
172{
173    type Table = <L as Column>::Table;
174    type QueryAstNode = UpdateArrayIndex<UncorrelatedColumn<L>, R>;
175
176    fn into_target(self) -> Self::QueryAstNode {
177        UpdateArrayIndex(ArrayIndex::new(
178            UncorrelatedColumn(self.array_expr),
179            self.index_expr,
180        ))
181    }
182}
183
184/// Signifies that this column should be rendered without its 'correlation'
185/// (i.e. table name prefix). For update statements, fully qualified column
186/// names aren't allowed.
187#[derive(Debug)]
188pub struct UncorrelatedColumn<C>(C);
189
190impl<C, DB> QueryFragment<DB> for UncorrelatedColumn<C>
191where
192    C: Column,
193    DB: Backend + DieselReserveSpecialization,
194{
195    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
196        out.push_identifier(C::NAME)
197    }
198}