1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
use std::any::{Any, TypeId}; use super::QueryFragment; pub trait QueryId { type QueryId: Any; fn has_static_query_id() -> bool; fn query_id() -> Option<TypeId> { if Self::has_static_query_id() { Some(TypeId::of::<Self::QueryId>()) } else { None } } } impl QueryId for () { type QueryId = (); fn has_static_query_id() -> bool { true } } impl<T: QueryId + ?Sized> QueryId for Box<T> { type QueryId = T::QueryId; fn has_static_query_id() -> bool { T::has_static_query_id() } } impl<'a, T: QueryId + ?Sized> QueryId for &'a T { type QueryId = T::QueryId; fn has_static_query_id() -> bool { T::has_static_query_id() } } impl<DB> QueryId for QueryFragment<DB> { type QueryId = (); fn has_static_query_id() -> bool { false } } #[cfg(test)] mod tests { use std::any::TypeId; use backend::Debug; use prelude::*; use super::QueryId; table! { users { id -> Integer, name -> VarChar, } } fn query_id<T: QueryId>(_: T) -> Option<TypeId> { T::query_id() } #[test] fn queries_with_no_dynamic_elements_have_a_static_id() { use self::users::dsl::*; assert!(query_id(users).is_some()); assert!(query_id(users.select(name)).is_some()); assert!(query_id(users.filter(name.eq("Sean"))).is_some()); } #[test] fn queries_with_different_types_have_different_ids() { let id1 = query_id(users::table.select(users::name)); let id2 = query_id(users::table.select(users::id)); assert!(id1 != id2); } #[test] fn bind_params_use_only_sql_type_for_query_id() { use self::users::dsl::*; let id1 = query_id(users.filter(name.eq("Sean"))); let id2 = query_id(users.filter(name.eq("Tess".to_string()))); assert_eq!(id1, id2); } #[test] fn boxed_queries_do_not_have_static_query_id() { assert!(query_id(users::table.into_boxed::<Debug>()).is_none()); } }