@@ -160,6 +160,43 @@ where
160
160
}
161
161
}
162
162
163
+ #[ cfg( any( feature = "postgres_backend" , feature = "sqlite" ) ) ]
164
+ impl < Left , Right > QuerySource for Join < Left , Right , FullOuter >
165
+ where
166
+ Left : QuerySource ,
167
+ Right : QuerySource ,
168
+ Nullable < Left :: DefaultSelection > : AppendSelection < Nullable < Right :: DefaultSelection > > ,
169
+ <Nullable < Left :: DefaultSelection > as AppendSelection < Nullable < Right :: DefaultSelection > > >:: Output :
170
+ AppearsOnTable < Self > ,
171
+ Self : Clone ,
172
+ {
173
+ type FromClause = Self ;
174
+ // combining two valid selectable expressions for both tables will always yield a
175
+ // valid selectable expressions for the whole join, so no need to check that here
176
+ // again. These checked turned out to be quite expensive in terms of compile time
177
+ // so we use a wrapper type to just skip the check and forward other more relevant
178
+ // trait implementations to the inner type
179
+ //
180
+ // See https://github.com/diesel-rs/diesel/issues/3223 for details
181
+ type DefaultSelection = self :: private:: SkipSelectableExpressionBoundCheckWrapper <
182
+ <Nullable < Left :: DefaultSelection > as AppendSelection < Nullable < Right :: DefaultSelection > > >:: Output ,
183
+ > ;
184
+
185
+ fn from_clause ( & self ) -> Self :: FromClause {
186
+ self . clone ( )
187
+ }
188
+
189
+ fn default_selection ( & self ) -> Self :: DefaultSelection {
190
+ self :: private:: SkipSelectableExpressionBoundCheckWrapper (
191
+ self . left
192
+ . source
193
+ . default_selection ( )
194
+ . nullable ( )
195
+ . append_selection ( self . right . source . default_selection ( ) . nullable ( ) ) ,
196
+ )
197
+ }
198
+ }
199
+
163
200
#[ derive( Debug , Clone , Copy ) ]
164
201
pub struct OnKeyword ;
165
202
@@ -251,6 +288,15 @@ impl<T: Table, Selection> AppendSelection<Selection> for T {
251
288
}
252
289
}
253
290
291
+ // TODO: not sure if this is the best way, but the existing impls aren't sufficient
292
+ impl < Left : Expression + Clone , Selection > AppendSelection < Selection > for Nullable < Left > {
293
+ type Output = ( Nullable < Left > , Selection ) ;
294
+
295
+ fn append_selection ( & self , selection : Selection ) -> Self :: Output {
296
+ ( self . clone ( ) , selection)
297
+ }
298
+ }
299
+
254
300
impl < Left , Mid , Selection , Kind > AppendSelection < Selection > for Join < Left , Mid , Kind >
255
301
where
256
302
Left : QuerySource ,
@@ -304,6 +350,22 @@ where
304
350
}
305
351
}
306
352
353
+ #[ cfg( any( feature = "postgres_backend" , feature = "sqlite" ) ) ]
354
+ #[ doc( hidden) ]
355
+ #[ derive( Debug , Clone , Copy , Default , QueryId ) ]
356
+ pub struct FullOuter ;
357
+
358
+ #[ cfg( any( feature = "postgres_backend" , feature = "sqlite" ) ) ]
359
+ impl < DB > QueryFragment < DB > for FullOuter
360
+ where
361
+ DB : Backend + DieselReserveSpecialization ,
362
+ {
363
+ fn walk_ast < ' b > ( & ' b self , mut out : AstPass < ' _ , ' b , DB > ) -> QueryResult < ( ) > {
364
+ out. push_sql ( " FULL OUTER" ) ;
365
+ Ok ( ( ) )
366
+ }
367
+ }
368
+
307
369
impl < Left , Mid , Right , Kind > JoinTo < Right > for Join < Left , Mid , Kind >
308
370
where
309
371
Left : JoinTo < Right > + QuerySource ,
@@ -407,6 +469,7 @@ impl<Qs, On> QueryDsl for OnClauseWrapper<Qs, On> {}
407
469
/// may be deeply nested, we need to recursively change any appearances of
408
470
/// `LeftOuter` to `Inner` in order to perform this check.
409
471
pub trait ToInnerJoin {
472
+ // TODO: does anything need to be done for full join here?
410
473
type InnerJoin ;
411
474
}
412
475
0 commit comments