tailwag_orm/queries/filters/
filterable_types.rs

1use std::marker::PhantomData;
2
3use uuid::Uuid;
4
5use crate::data_definition::table::Identifier;
6
7use super::Filter;
8
9pub trait Filterable {
10    type FilterType: Default;
11}
12
13// Trying out the type-state pattern here.
14trait TypeFilter {}
15macro_rules! typetype {
16    ($item:ty) => {
17        // pub enum $item {}
18        impl TypeFilter for $item {}
19    };
20}
21macro_rules! impl_filter_for {
22        ($item:ty: $base_type:ty, $table_column_fn_name:ident, $param_type_enum:ident, $trait_name:ident $($func_name:ident:$comparison_type:ident),*) => {
23            impl $trait_name for FilterableType<$item> {
24                type Type = $base_type;
25                $(fn $func_name(
26                    &self,
27                    value: impl Into<<Self as $trait_name>::Type>,
28                ) -> Filter {
29                    Filter::$comparison_type(
30                        super::FilterComparisonParam::TableColumn(
31                            self.column_name.clone(),                        ),
32                        super::FilterComparisonParam::$param_type_enum(value.into()),
33                    )
34                }
35                )*
36            }
37
38        };
39    }
40
41impl<T: TypeFilter> TypeFilter for Option<T> {}
42impl<T: TypeFilter> TypeFilter for Vec<T> {}
43// ^^^^ Allows for base types only
44// vvvv Allows for custom types (only - breaks basic types)
45// impl<T: Filterable> TypeFilter for Option<T> {}
46// impl<T: Filterable> TypeFilter for Vec<T> {}
47
48/// vv Need to impl for all types, but should follow this pattern.
49// impl<T: FilterEq + TypeFilter> FilterEq for FilterableType<Option<T>> {
50//     type Type = Option<T>;
51
52//     fn eq(
53//         &self,
54//         t: impl Into<<Self as crate::queries::filters::filterable_types::FilterEq>::Type>,
55//     ) -> Filter {
56//         todo!()
57//     }
58
59//     fn ne(
60//         &self,
61//         t: impl Into<<Self as crate::queries::filters::filterable_types::FilterEq>::Type>,
62//     ) -> Filter {
63//         todo!()
64//     }
65// }
66
67macro_rules! impl_numeric_type {
68    ($type:ty: $db_type:ident) => {
69        typetype! {$type}
70        impl_filter_for!($type: $type, new_int, $db_type, FilterEq eq:Equal, ne:NotEqual);
71        impl_filter_for!($type: $type, new_int, $db_type, FilterPartialEq lt:LessThan, lte:LessThanOrEqual, gt:GreaterThan, gte:GreaterThanOrEqual);
72    }
73}
74
75// Here we define the filterabilities of each type
76typetype! {Uuid}
77impl_filter_for!(Uuid: uuid::Uuid, new_uuid, Uuid, FilterEq eq:Equal, ne:NotEqual);
78impl_filter_for!(Uuid: uuid::Uuid, new_uuid, Uuid, FilterLike like:Like);
79typetype! {bool}
80impl_filter_for!(bool: bool, new_bool, Bool, FilterEq eq:Equal, ne:NotEqual);
81typetype! {String}
82impl_filter_for!(String: String, new_string, String, FilterEq eq:Equal, ne:NotEqual);
83impl_filter_for!(String: String, new_string, String, FilterPartialEq lt:LessThan, lte:LessThanOrEqual, gt:GreaterThan, gte:GreaterThanOrEqual);
84impl_filter_for!(String: String, new_string, String, FilterLike like:Like);
85impl_numeric_type!(i64: Integer);
86impl_numeric_type!(f64: Float);
87
88// TODO: Implement this for OPTIONS too
89// TODO: Implement this for stronger dynamic typing with numerics
90// impl_numeric_type!(usize: Integer);
91// impl_numeric_type!(u64: Integer);
92// impl_numeric_type!(u32: Integer);
93// impl_numeric_type!(u16: Integer);
94// impl_numeric_type!(u8: Integer);
95// impl_numeric_type!(isize: Integer);
96// impl_numeric_type!(i32: Integer);
97// impl_numeric_type!(i16: Integer);
98// impl_numeric_type!(i8: Integer);
99// impl_numeric_type!(f32: Float);
100typetype! {chrono::NaiveDateTime}
101impl_filter_for!(chrono::NaiveDateTime: chrono::NaiveDateTime, new_timestamp, Timestamp, FilterEq eq:Equal, ne:NotEqual);
102
103// impl<T> TypeFilter for Vec<T> where T: TypeFilter {}
104// impl<T> TypeFilter for Option<T> where T: TypeFilter {}
105
106#[allow(private_bounds)]
107pub struct FilterableType<T: TypeFilter> {
108    // _table_name: Identifier,
109    column_name: Identifier,
110    _t: PhantomData<T>,
111}
112
113#[allow(private_bounds)]
114impl<T: TypeFilter> FilterableType<T> {
115    pub fn new(
116        // _table_name: Identifier,
117        column_name: Identifier,
118    ) -> Self {
119        Self {
120            // _table_name,
121            column_name,
122            _t: PhantomData,
123        }
124    }
125}
126
127pub trait FilterEq {
128    type Type;
129    fn eq(
130        &self,
131        t: impl Into<<Self as crate::queries::filters::filterable_types::FilterEq>::Type>,
132    ) -> Filter;
133    fn ne(
134        &self,
135        t: impl Into<<Self as crate::queries::filters::filterable_types::FilterEq>::Type>,
136    ) -> Filter;
137}
138pub trait FilterPartialEq
139where
140    Self: FilterEq,
141{
142    type Type;
143    fn lt(
144        &self,
145        t: impl Into<<Self as crate::queries::filters::filterable_types::FilterPartialEq>::Type>,
146    ) -> Filter;
147    fn gt(
148        &self,
149        t: impl Into<<Self as crate::queries::filters::filterable_types::FilterPartialEq>::Type>,
150    ) -> Filter;
151    fn lte(
152        &self,
153        t: impl Into<<Self as crate::queries::filters::filterable_types::FilterPartialEq>::Type>,
154    ) -> Filter;
155    fn gte(
156        &self,
157        t: impl Into<<Self as crate::queries::filters::filterable_types::FilterPartialEq>::Type>,
158    ) -> Filter;
159}
160pub trait FilterLike {
161    type Type;
162    fn like(
163        &self,
164        t: impl Into<<Self as crate::queries::filters::filterable_types::FilterLike>::Type>,
165    ) -> Filter;
166}
167pub trait FilterIn {
168    type Type;
169    fn contained_in(
170        &self,
171        t: impl Into<<Self as crate::queries::filters::filterable_types::FilterIn>::Type>,
172    ) -> Filter;
173}
174
175// #[cfg(features = "experimental")]
176// FilterableTypes for OneToOne / OneToMany
177// pub trait Filter