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#[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#[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}