wundergraph/query_builder/selection/fields/
field_list.rs

1use super::{FieldListExtractor, NonTableFieldExtractor, WundergraphResolveAssociations};
2use crate::context::WundergraphContext;
3use crate::error::Result;
4use crate::helper::tuple::TupleIndex;
5use crate::query_builder::selection::query_resolver::WundergraphResolvePlaceHolderList;
6use crate::query_builder::types::placeholder::PlaceHolderMarker;
7use crate::query_builder::types::WundergraphValue;
8use crate::scalar::WundergraphScalarValue;
9use diesel::backend::Backend;
10use diesel::{Connection, Queryable};
11use juniper::{Executor, Selection};
12use std::hash::Hash;
13
14/// A internal trait
15pub trait WundergraphFieldList<DB: Backend, Key, Table, Ctx> {
16    /// Placeholder type
17    ///
18    /// Normally a tuple with `TABLE_FIELD_COUNT` entries of type
19    /// `PlaceHolder<RustFieldType>` for the corresponding entry in `SqlType`
20    type PlaceHolder: Queryable<Self::SqlType, DB> + 'static;
21    /// The sql type of the field list
22    /// Normally a tuple with `TABLE_FIELD_COUNT` entries representing
23    /// the (diesel) sql type of the executed query
24    type SqlType: 'static;
25
26    /// Number of fields representing a database column
27    const TABLE_FIELD_COUNT: usize;
28    /// Number of fields not representing a database column
29    const NON_TABLE_FIELD_COUNT: usize;
30
31    /// Resolve all fields in an already executed graphql request
32    ///
33    /// The results of the executed sql query are contained in `placeholder`
34    fn resolve(
35        placeholder: Vec<Self::PlaceHolder>,
36        global_args: &[juniper::LookAheadArgument<WundergraphScalarValue>],
37        select: &juniper::LookAheadSelection<'_, WundergraphScalarValue>,
38        selection: Option<&'_ [Selection<'_, WundergraphScalarValue>]>,
39        name_list: &'static [&'static str],
40        executor: &Executor<'_, Ctx, WundergraphScalarValue>,
41    ) -> Result<Vec<juniper::Value<WundergraphScalarValue>>>;
42
43    #[doc(hidden)]
44    fn map_table_field<F: Fn(usize) -> R, R>(local_index: usize, callback: F) -> Option<R>;
45    #[doc(hidden)]
46    fn map_non_table_field<Func: Fn(usize) -> Ret, Ret>(
47        local_index: usize,
48        callback: Func,
49    ) -> Option<Ret>;
50}
51
52macro_rules! wundergraph_impl_field_list {
53    ($(
54        $Tuple:tt {
55            $(($idx:tt) -> $T:ident, $ST: ident, $TT: ident,) +
56        }
57    )+) => {
58        $(
59
60            impl<Back, Key, Table, Ctx, $($T,)*> WundergraphFieldList<Back, Key, Table, Ctx> for ($($T,)*)
61            where Back: Backend,
62                  ($($T,)*): FieldListExtractor + NonTableFieldExtractor,
63                  <($($T,)*) as FieldListExtractor>::Out: WundergraphValue,
64                  <<($($T,)*) as FieldListExtractor>::Out as WundergraphValue>::PlaceHolder: TupleIndex<Key> +
65                      Queryable<<<($($T,)*) as FieldListExtractor>::Out as WundergraphValue>::SqlType, Back> + 'static,
66            Vec<<<($($T,)*) as FieldListExtractor>::Out as WundergraphValue>::PlaceHolder>:
67            WundergraphResolvePlaceHolderList<<($($T,)*) as FieldListExtractor>::Out, Back, Ctx>,
68            <<<($($T,)*) as FieldListExtractor>::Out as WundergraphValue>::PlaceHolder as TupleIndex<Key>>::Value: PlaceHolderMarker,
69            <<<<($($T,)*) as FieldListExtractor>::Out as WundergraphValue>::PlaceHolder as TupleIndex<Key>>::Value as PlaceHolderMarker>::InnerType: Eq + Hash + Clone,
70            <($($T,)*) as NonTableFieldExtractor>::Out: WundergraphResolveAssociations<<<<<($($T,)*) as FieldListExtractor>::Out as WundergraphValue>::PlaceHolder as TupleIndex<Key>>::Value as PlaceHolderMarker>::InnerType, Table, Back, Ctx>,
71            Ctx: WundergraphContext,
72            Ctx::Connection: Connection<Backend = Back>,
73            {
74                type PlaceHolder = <<($($T,)*) as FieldListExtractor>::Out as WundergraphValue>::PlaceHolder;
75                type SqlType = <<($($T,)*) as FieldListExtractor>::Out as WundergraphValue>::SqlType;
76
77                const TABLE_FIELD_COUNT: usize = <($($T,)*) as FieldListExtractor>::FIELD_COUNT;
78                const NON_TABLE_FIELD_COUNT: usize = <($($T,)*) as NonTableFieldExtractor>::FIELD_COUNT;
79
80                fn resolve(
81                    placeholder: Vec<Self::PlaceHolder>,
82                    global_args: &[juniper::LookAheadArgument<WundergraphScalarValue>],
83                    look_ahead: &juniper::LookAheadSelection<'_, WundergraphScalarValue>,
84                    selection: Option<&'_ [Selection<'_, WundergraphScalarValue>]>,
85                    name_list: &'static [&'static str],
86                    executor: &Executor<'_, Ctx, WundergraphScalarValue>,
87                ) -> Result<Vec<juniper::Value<WundergraphScalarValue>>> {
88                    let extern_values = {
89                        let keys = || {
90                            placeholder.iter()
91                                .map(TupleIndex::<Key>::get)
92                                .map(<_ as PlaceHolderMarker>::into_inner)
93                                .collect::<Vec<_>>()
94                        };
95
96                        let name = |local_pos| {
97                            <($($T,)*) as NonTableFieldExtractor>::map(
98                                local_pos,
99                                |pos| name_list[pos]
100                            ).expect("Name is there")
101                        };
102                        <($($T,)*) as NonTableFieldExtractor>::Out::resolve(
103                            global_args, look_ahead, selection, name, keys, executor,
104                        )?
105                    };
106                    let name = |local_pos| {
107                        <($($T,)*) as FieldListExtractor>::map(local_pos, |pos| {
108                            name_list[pos]
109                        }).expect("Name is there")
110                    };
111                    let objs = placeholder.resolve(
112                        name,
113                        global_args,
114                        look_ahead,
115                        selection,
116                        executor,
117                    )?;
118
119                     Ok(extern_values.merge_with_object_list(objs))
120                }
121
122                #[inline(always)]
123                fn map_table_field<Func: Fn(usize) -> Ret, Ret>(local_index: usize, callback: Func) -> Option<Ret> {
124                    <($($T,)*) as FieldListExtractor>::map(local_index, callback)
125                }
126
127                #[inline(always)]
128                fn map_non_table_field<Func: Fn(usize) -> Ret, Ret>(local_index: usize, callback: Func) -> Option<Ret> {
129                    <($($T,)*) as NonTableFieldExtractor>::map(local_index, callback)
130                }
131            }
132        )*
133    }
134}
135__diesel_for_each_tuple!(wundergraph_impl_field_list);