1
1
//! This module contains the query dsl node definitions
2
2
//! for array comparison operations like `IN` and `NOT IN`
3
3
4
+ use super :: expression_types:: NotSelectable ;
4
5
use crate :: backend:: { sql_dialect, Backend , SqlDialect } ;
5
6
use crate :: expression:: subselect:: Subselect ;
6
7
use crate :: expression:: {
@@ -71,7 +72,7 @@ impl<T, U> NotIn<T, U> {
71
72
impl < T , U > Expression for In < T , U >
72
73
where
73
74
T : Expression ,
74
- U : Expression < SqlType = T :: SqlType > ,
75
+ U : InExpression < SqlType = T :: SqlType > ,
75
76
T :: SqlType : SqlType ,
76
77
sql_types:: is_nullable:: IsSqlTypeNullable < T :: SqlType > :
77
78
sql_types:: MaybeNullableType < sql_types:: Bool > ,
85
86
impl < T , U > Expression for NotIn < T , U >
86
87
where
87
88
T : Expression ,
88
- U : Expression < SqlType = T :: SqlType > ,
89
+ U : InExpression < SqlType = T :: SqlType > ,
89
90
T :: SqlType : SqlType ,
90
91
sql_types:: is_nullable:: IsSqlTypeNullable < T :: SqlType > :
91
92
sql_types:: MaybeNullableType < sql_types:: Bool > ,
@@ -111,7 +112,7 @@ where
111
112
DB : Backend
112
113
+ SqlDialect < ArrayComparison = sql_dialect:: array_comparison:: AnsiSqlArrayComparison > ,
113
114
T : QueryFragment < DB > ,
114
- U : QueryFragment < DB > + MaybeEmpty ,
115
+ U : QueryFragment < DB > + InExpression ,
115
116
{
116
117
fn walk_ast < ' b > ( & ' b self , mut out : AstPass < ' _ , ' b , DB > ) -> QueryResult < ( ) > {
117
118
if self . values . is_empty ( ) {
@@ -142,7 +143,7 @@ where
142
143
DB : Backend
143
144
+ SqlDialect < ArrayComparison = sql_dialect:: array_comparison:: AnsiSqlArrayComparison > ,
144
145
T : QueryFragment < DB > ,
145
- U : QueryFragment < DB > + MaybeEmpty ,
146
+ U : QueryFragment < DB > + InExpression ,
146
147
{
147
148
fn walk_ast < ' b > ( & ' b self , mut out : AstPass < ' _ , ' b , DB > ) -> QueryResult < ( ) > {
148
149
if self . values . is_empty ( ) {
@@ -176,9 +177,9 @@ impl_selectable_expression!(NotIn<T, U>);
176
177
/// This trait is exposed for custom third party backends so
177
178
/// that they can restrict the [`QueryFragment`] implementations
178
179
/// for [`In`] and [`NotIn`].
179
- pub trait AsInExpression < T : SqlType + TypedExpressionType > {
180
+ pub trait AsInExpression < T : SqlType > {
180
181
/// Type of the expression returned by [AsInExpression::as_in_expression]
181
- type InExpression : MaybeEmpty + Expression < SqlType = T > ;
182
+ type InExpression : InExpression < SqlType = T > ;
182
183
183
184
/// Construct the diesel query dsl representation of
184
185
/// the `IN (values)` clause for the given type
@@ -204,9 +205,15 @@ where
204
205
}
205
206
}
206
207
207
- /// A helper trait to check if the values clause of
208
- /// an [`In`] or [`NotIn`] query dsl node is empty or not
209
- pub trait MaybeEmpty {
208
+ /// A marker trait that identifies query fragments that can be used in `IN(...)` and `NOT IN(...)`
209
+ /// clauses, (or `= ANY (...)` clauses on the Postgres backend)
210
+ ///
211
+ /// These can be wrapped in [`In`] or [`NotIn`] query dsl nodes
212
+ pub trait InExpression {
213
+ /// The SQL type of the inner values, which should be the same as the left of the `IN` or
214
+ /// `NOT IN` clause
215
+ type SqlType : SqlType ;
216
+
210
217
/// Returns `true` if self represents an empty collection
211
218
/// Otherwise `false` is returned.
212
219
fn is_empty ( & self ) -> bool ;
@@ -215,7 +222,7 @@ pub trait MaybeEmpty {
215
222
impl < ST , F , S , D , W , O , LOf , G , H , LC > AsInExpression < ST >
216
223
for SelectStatement < F , S , D , W , O , LOf , G , H , LC >
217
224
where
218
- ST : SqlType + TypedExpressionType ,
225
+ ST : SqlType ,
219
226
Subselect < Self , ST > : Expression < SqlType = ST > ,
220
227
Self : SelectQuery < SqlType = ST > ,
221
228
{
@@ -228,7 +235,7 @@ where
228
235
229
236
impl < ' a , ST , QS , DB , GB > AsInExpression < ST > for BoxedSelectStatement < ' a , ST , QS , DB , GB >
230
237
where
231
- ST : SqlType + TypedExpressionType ,
238
+ ST : SqlType ,
232
239
Subselect < BoxedSelectStatement < ' a , ST , QS , DB , GB > , ST > : Expression < SqlType = ST > ,
233
240
{
234
241
type InExpression = Subselect < Self , ST > ;
@@ -241,7 +248,7 @@ where
241
248
impl < ST , Combinator , Rule , Source , Rhs > AsInExpression < ST >
242
249
for CombinationClause < Combinator , Rule , Source , Rhs >
243
250
where
244
- ST : SqlType + TypedExpressionType ,
251
+ ST : SqlType ,
245
252
Self : SelectQuery < SqlType = ST > ,
246
253
Subselect < Self , ST > : Expression < SqlType = ST > ,
247
254
{
@@ -252,8 +259,8 @@ where
252
259
}
253
260
}
254
261
255
- /// Query dsl node for an `IN (values)` clause containing
256
- /// a variable number of bind values.
262
+ /// Query dsl node for the `values` part of an `IN (values)` clause
263
+ /// containing a variable number of bind values.
257
264
///
258
265
/// Third party backend can customize the [`QueryFragment`]
259
266
/// implementation of this query dsl node via
@@ -284,10 +291,18 @@ impl<ST, I> Expression for Many<ST, I>
284
291
where
285
292
ST : TypedExpressionType ,
286
293
{
287
- type SqlType = ST ;
294
+ // Comma-ed fake expressions are not usable directly in SQL
295
+ // This is only implemented so that we can use the usual SelectableExpression & co traits
296
+ // as constraints for the same implementations on [`In`] and [`NotIn`]
297
+ type SqlType = NotSelectable ;
288
298
}
289
299
290
- impl < ST , I > MaybeEmpty for Many < ST , I > {
300
+ impl < ST , I > InExpression for Many < ST , I >
301
+ where
302
+ ST : SqlType ,
303
+ {
304
+ type SqlType = ST ;
305
+
291
306
fn is_empty ( & self ) -> bool {
292
307
self . values . is_empty ( )
293
308
}
0 commit comments