|
| 1 | +use std::marker::PhantomData; |
| 2 | + |
| 3 | +use backend::Backend; |
| 4 | +use expression::{Expression, SelectableExpression, NonAggregate}; |
| 5 | +use query_builder::*; |
| 6 | +use result::QueryResult; |
| 7 | + |
| 8 | +#[derive(Debug, Copy, Clone)] |
| 9 | +#[doc(hidden)] |
| 10 | +/// Coerces an expression to be another type. No checks are performed to ensure |
| 11 | +/// that the new type is valid in all positions that the previous type was. |
| 12 | +/// This does not perform an actual cast, it just lies to our type system. |
| 13 | +/// |
| 14 | +/// This is used for a few expressions where we know that the types are actually |
| 15 | +/// always interchangeable. (Examples of this include `Timestamp` vs |
| 16 | +/// `Timestamptz`, `VarChar` vs `Text`, and `Json` vs `Jsonb`). |
| 17 | +/// |
| 18 | +/// This struct should not be considered a general solution to equivalent types. |
| 19 | +/// It is a short term workaround for expressions which are known to be commonly |
| 20 | +/// used. |
| 21 | +pub struct Coerce<T, ST> { |
| 22 | + expr: T, |
| 23 | + _marker: PhantomData<ST>, |
| 24 | +} |
| 25 | + |
| 26 | +impl<T, ST> Coerce<T, ST> { |
| 27 | + pub fn new(expr: T) -> Self { |
| 28 | + Coerce { |
| 29 | + expr: expr, |
| 30 | + _marker: PhantomData, |
| 31 | + } |
| 32 | + } |
| 33 | +} |
| 34 | + |
| 35 | +impl<T, ST> Expression for Coerce<T, ST> where |
| 36 | + T: Expression, |
| 37 | +{ |
| 38 | + type SqlType = ST; |
| 39 | +} |
| 40 | + |
| 41 | +impl<T, ST, QS> SelectableExpression<QS> for Coerce<T, ST> where |
| 42 | + T: SelectableExpression<QS>, |
| 43 | +{ |
| 44 | +} |
| 45 | + |
| 46 | +impl<T, ST, DB> QueryFragment<DB> for Coerce<T, ST> where |
| 47 | + T: QueryFragment<DB>, |
| 48 | + DB: Backend, |
| 49 | +{ |
| 50 | + fn to_sql(&self, out: &mut DB::QueryBuilder) -> BuildQueryResult { |
| 51 | + self.expr.to_sql(out) |
| 52 | + } |
| 53 | + |
| 54 | + fn collect_binds(&self, out: &mut DB::BindCollector) -> QueryResult<()> { |
| 55 | + self.expr.collect_binds(out) |
| 56 | + } |
| 57 | + |
| 58 | + fn is_safe_to_cache_prepared(&self) -> bool { |
| 59 | + self.expr.is_safe_to_cache_prepared() |
| 60 | + } |
| 61 | +} |
| 62 | + |
| 63 | +impl<T: QueryId, ST: 'static> QueryId for Coerce<T, ST> { |
| 64 | + type QueryId = Coerce<T::QueryId, ST>; |
| 65 | + |
| 66 | + fn has_static_query_id() -> bool { |
| 67 | + true |
| 68 | + } |
| 69 | +} |
| 70 | + |
| 71 | +impl<T, ST> NonAggregate for Coerce<T, ST> where |
| 72 | + T: NonAggregate, |
| 73 | + Coerce<T, ST>: Expression, |
| 74 | +{ |
| 75 | +} |
0 commit comments