django_query/persian_rug/
filtering.rs

1use crate::filtering::{FilterableWithContext, Meta, MetaVisitor};
2
3use crate::filtering::{Field, Member, MemberVisitor, Operable, Operator, OperatorClass};
4
5use persian_rug::{Accessor, Contextual, Proxy};
6
7#[persian_rug::constraints(context = C, access(T))]
8impl<'a, A, C, T> FilterableWithContext<'a, A> for Proxy<T>
9where
10    T: FilterableWithContext<'a, A> + Contextual<Context = C>,
11    A: Accessor<Context = C> + 'a,
12{
13    type Meta = ProxyMeta<A>;
14    fn get_meta(access: A) -> Self::Meta {
15        ProxyMeta { access }
16    }
17}
18
19pub struct ProxyMeta<A> {
20    access: A,
21}
22
23#[persian_rug::constraints(context = C, access(T))]
24impl<'f, A, C, T> Meta<'f, Proxy<T>> for ProxyMeta<A>
25where
26    T: FilterableWithContext<'f, A>,
27    A: Accessor<Context = C> + 'f,
28    T: Contextual<Context = C>,
29{
30    fn accept_visitor<V: MetaVisitor<'f, Proxy<T>>>(&self, visitor: &mut V)
31    where
32        Self: Sized,
33    {
34        let mut n = ProxyMetaVisitor {
35            parent: visitor,
36            access: self.access.clone(),
37        };
38        T::get_meta(self.access.clone()).accept_visitor(&mut n);
39    }
40}
41
42struct ProxyMetaVisitor<'p, P, A> {
43    parent: &'p mut P,
44    access: A,
45}
46
47#[persian_rug::constraints(context = C, access(R))]
48impl<'a, 'p, A, C, P, R> MetaVisitor<'a, R> for ProxyMetaVisitor<'p, P, A>
49where
50    P: MetaVisitor<'a, Proxy<R>>,
51    A: Accessor<Context = C> + 'a,
52{
53    fn visit_member<F, O, T>(&mut self, name: &str, field: &F, defop: O)
54    where
55        F: Member<'a, R, Value = T> + Clone,
56        O: OperatorClass<<T as Operable>::Base>,
57        <O as OperatorClass<<T as Operable>::Base>>::Instance: 'a,
58        T: Operable,
59    {
60        self.parent.visit_member(
61            name,
62            &ProxyField {
63                inner_field: field.clone(),
64                access: self.access.clone(),
65            },
66            defop,
67        );
68    }
69
70    fn visit_record<F, T, U>(&mut self, name: &str, field: &F, inner_record: &T)
71    where
72        F: Field<R, Value = U> + Clone + 'a,
73        T: Meta<'a, U>,
74    {
75        self.parent.visit_record(
76            name,
77            &ProxyField {
78                inner_field: field.clone(),
79                access: self.access.clone(),
80            },
81            inner_record,
82        )
83    }
84}
85
86#[derive(Clone)]
87struct ProxyField<F, A> {
88    inner_field: F,
89    access: A,
90}
91
92#[persian_rug::constraints(context = C, access(U))]
93impl<A, C, F, T, U> Field<Proxy<U>> for ProxyField<F, A>
94where
95    F: Field<U, Value = T>,
96    A: Accessor<Context = C>,
97{
98    type Value = T;
99    fn apply<O: Operator<T>>(&'_ self, op: &O, data: &Proxy<U>) -> bool {
100        self.inner_field.apply(op, self.access.get(data))
101    }
102}
103
104#[persian_rug::constraints(context = C, access(U))]
105impl<'a, A, C, F, T, U> Member<'a, Proxy<U>> for ProxyField<F, A>
106where
107    F: Member<'a, U, Value = T>,
108    T: Operable,
109    A: Accessor<Context = C> + 'a,
110{
111    type Value = T;
112    fn apply<O: Operator<<T as Operable>::Base>>(&'_ self, op: &O, data: &Proxy<U>) -> bool {
113        self.inner_field.apply(op, self.access.get(data))
114    }
115    fn accept_visitor<V: MemberVisitor<'a, Self, Proxy<U>, T>>(&self, visitor: &mut V) {
116        let mut n = ProxyMemberVisitor {
117            parent: visitor,
118            field: self,
119            _marker: Default::default(),
120        };
121        self.inner_field.accept_visitor(&mut n);
122    }
123}
124
125struct ProxyMemberVisitor<'a, A, F, P, U> {
126    parent: &'a mut P,
127    field: &'a ProxyField<F, A>,
128    _marker: core::marker::PhantomData<U>,
129}
130
131#[persian_rug::constraints(context = C, access(U))]
132impl<'a, 'b, A, C, F, P, T, U> MemberVisitor<'b, F, U, T> for ProxyMemberVisitor<'a, A, F, P, U>
133where
134    P: MemberVisitor<'b, ProxyField<F, A>, Proxy<U>, T>,
135    F: Member<'b, U, Value = T>,
136    T: Operable,
137    A: Accessor<Context = C> + 'b,
138{
139    fn visit_operator<O>(&mut self, name: &str, _f: &F, op: O)
140    where
141        O: OperatorClass<<T as Operable>::Base>,
142        <O as OperatorClass<<T as Operable>::Base>>::Instance: 'b,
143    {
144        self.parent.visit_operator(name, self.field, op);
145    }
146}
147
148pub use django_query_derive::FilterableWithPersianRug;