entity_async_graphql/
lib.rs

1mod ent;
2mod filter;
3
4pub use ent::*;
5pub use filter::*;
6
7#[cfg(feature = "macros")]
8pub use entity_async_graphql_macros::*;
9
10#[cfg(test)]
11mod tests {
12    use super::*;
13
14    use async_graphql::{value, Context, EmptyMutation, EmptySubscription, Object, Schema};
15    use entity::{Database, DatabaseRc, Edge, Field, Id, UntypedEnt, Value};
16    use entity_inmemory::InmemoryDatabase;
17    use entity_sled::SledDatabase;
18    use std::collections::HashMap;
19
20    macro_rules! impl_tests {
21        ($db_type:ty, $new_db:expr) => {
22            /// Creates a new database with some test entries used throughout
23            ///
24            /// IDs: 1-3 ~ are type1 with no fields or edges
25            /// IDs: 4-6 ~ are type2 with value fields and no edges
26            /// IDs: 7-9 ~ are type3 with collection fields and no edges
27            /// IDs: 10-12 ~ are type4 with edges to 1-9 and no fields
28            fn new_test_database() -> $db_type {
29                let db = $new_db;
30
31                // 1-3 have no fields or edges
32                let _ = db
33                    .insert(Box::from(UntypedEnt::from_collections(1, vec![], vec![])))
34                    .unwrap();
35                let _ = db
36                    .insert(Box::from(UntypedEnt::from_collections(2, vec![], vec![])))
37                    .unwrap();
38                let _ = db
39                    .insert(Box::from(UntypedEnt::from_collections(3, vec![], vec![])))
40                    .unwrap();
41
42                // 4-6 have value fields only
43                let _ = db
44                    .insert(Box::from(UntypedEnt::from_collections(
45                        4,
46                        vec![Field::new("a", 1), Field::new("b", 2)],
47                        vec![],
48                    )))
49                    .unwrap();
50                let _ = db
51                    .insert(Box::from(UntypedEnt::from_collections(
52                        5,
53                        vec![Field::new("a", 3), Field::new("b", 4)],
54                        vec![],
55                    )))
56                    .unwrap();
57                let _ = db
58                    .insert(Box::from(UntypedEnt::from_collections(
59                        6,
60                        vec![Field::new("a", 5), Field::new("b", 6)],
61                        vec![],
62                    )))
63                    .unwrap();
64
65                // 7-9 have collection fields only
66                let _ = db
67                    .insert(Box::from(UntypedEnt::from_collections(
68                        7,
69                        vec![Field::new(
70                            "f",
71                            Value::from(
72                                vec![(String::from("a"), 3), (String::from("b"), 5)]
73                                    .into_iter()
74                                    .collect::<HashMap<String, u8>>(),
75                            ),
76                        )],
77                        vec![],
78                    )))
79                    .unwrap();
80                let _ = db
81                    .insert(Box::from(UntypedEnt::from_collections(
82                        8,
83                        vec![Field::new("f", vec![1, 2])],
84                        vec![],
85                    )))
86                    .unwrap();
87                let _ = db
88                    .insert(Box::from(UntypedEnt::from_collections(
89                        9,
90                        vec![Field::new(
91                            "f",
92                            Value::from(
93                                vec![
94                                    (String::from("a"), Value::from(vec![1, 2])),
95                                    (String::from("b"), Value::from(vec![3, 4])),
96                                ]
97                                .into_iter()
98                                .collect::<HashMap<String, Value>>(),
99                            ),
100                        )],
101                        vec![],
102                    )))
103                    .unwrap();
104
105                // 10-12 have edges only
106                let _ = db
107                    .insert(Box::from(UntypedEnt::from_collections(
108                        10,
109                        vec![],
110                        vec![
111                            Edge::new("a", 1),
112                            Edge::new("b", vec![3, 4, 5]),
113                            Edge::new("c", None),
114                        ],
115                    )))
116                    .unwrap();
117                let _ = db
118                    .insert(Box::from(UntypedEnt::from_collections(
119                        11,
120                        vec![],
121                        vec![Edge::new("a", 2), Edge::new("b", vec![1, 2, 3, 4, 5, 6])],
122                    )))
123                    .unwrap();
124                let _ = db
125                    .insert(Box::from(UntypedEnt::from_collections(
126                        12,
127                        vec![],
128                        vec![
129                            Edge::new("a", 3),
130                            Edge::new("b", vec![]),
131                            Edge::new("c", Some(8)),
132                        ],
133                    )))
134                    .unwrap();
135
136                db
137            }
138
139            struct TestQuery;
140
141            #[Object]
142            impl TestQuery {
143                async fn ent<'ctx>(
144                    &self,
145                    ctx: &'ctx Context<'_>,
146                    id: Option<Id>,
147                    filter: Option<GqlEntFilter>,
148                ) -> async_graphql::Result<Vec<GqlDynEnt>> {
149                    let db = ctx.data::<DatabaseRc>()?;
150
151                    if let Some(id) = id {
152                        db.get_all(vec![id]).map(|x| x.into_iter().map(GqlDynEnt::from).collect())
153                            .map_err(|x| async_graphql::Error::new(x.to_string()))
154                    } else if let Some(filter) = filter {
155                        db.find_all(filter.into()).map(|x| x.into_iter().map(GqlDynEnt::from).collect())
156                            .map_err(|x| async_graphql::Error::new(x.to_string()))
157                    } else {
158                        Err(async_graphql::Error::new("Must provide one argument"))
159                    }
160                }
161            }
162
163            #[test]
164            fn supports_ent_trait_object_as_output_object() {
165                let schema = Schema::build(TestQuery, EmptyMutation, EmptySubscription)
166                    .data(DatabaseRc::new(Box::new(new_test_database())))
167                    .finish();
168                let input = r#"
169                    { 
170                        ent(id: 1) { 
171                            id 
172                        } 
173                    }
174                "#;
175                let response = futures::executor::block_on(schema.execute(input.trim()));
176                assert_eq!(
177                    response.data,
178                    value!({
179                        "ent": [
180                            { "id": 1 },
181                        ],
182                    })
183                );
184            }
185
186            #[test]
187            fn supports_filtering() {
188                let schema = Schema::build(TestQuery, EmptyMutation, EmptySubscription)
189                    .data(DatabaseRc::new(Box::new(new_test_database())))
190                    .finish();
191                let input = r#"
192                    { 
193                        ent(filter: { id: { equals: 1 } }) { 
194                            id 
195                        } 
196                    }
197                "#;
198                let response = futures::executor::block_on(schema.execute(input.trim()));
199                assert_eq!(
200                    response.data,
201                    value!({
202                        "ent": [
203                            { "id": 1 },
204                        ],
205                    })
206                );
207            }
208        };
209    }
210
211    mod inmemory {
212        use super::*;
213
214        impl_tests!(InmemoryDatabase, InmemoryDatabase::default());
215    }
216
217    mod sled {
218        use super::*;
219
220        impl_tests!(
221            SledDatabase,
222            SledDatabase::new(::sled::Config::new().temporary(true).open().unwrap())
223        );
224    }
225}