subgraph/data_sources/mongo/services/
mod.rs

1use bson::{doc, Document};
2use log::{debug, trace};
3
4use crate::filter_operator::FilterOperator;
5
6mod create_one;
7mod find_many;
8mod find_one;
9mod update_many;
10mod update_one;
11
12#[derive(Debug)]
13pub struct Services;
14
15impl Services {
16    pub fn create_nested_fields(doc: &Document) -> Document {
17        debug!("Creating Nested Filter");
18        let mut set_doc = Document::new();
19        for (key, value) in doc.iter() {
20            if let Some(sub_doc) = value.as_document() {
21                debug!("Found Sub Document: {:?}", sub_doc);
22                let sub_set_doc = Services::create_nested_fields(sub_doc);
23                for (sub_key, sub_value) in sub_set_doc.iter() {
24                    let nested_key = format!("{}.{}", key, sub_key);
25                    set_doc.insert(nested_key, sub_value.clone());
26                }
27            } else {
28                set_doc.insert(key.clone(), value.clone());
29            }
30        }
31        debug!("Created Nested Filter: {:?}", set_doc);
32        set_doc
33    }
34
35    /// Takes in a graphql input `query` and parses it into a nested find filter.
36    pub fn create_nested_find_filter(query_doc: &Document) -> Document {
37        debug!("Creating Nested Find Filter");
38        trace!("Query Doc: {:?}", query_doc);
39        let mut find_doc = Document::new();
40        for (key, value) in query_doc.clone().iter_mut() {
41            // If the value is a doc, create a key that represents the nested field
42            if let Some(sub_doc) = value.as_document() {
43                trace!("Found Sub Document: {:?}", sub_doc);
44                let sub_set_doc = Services::create_nested_find_filter(sub_doc);
45                for (sub_key, sub_value) in sub_set_doc.iter() {
46                    let is_filter_operator =
47                        FilterOperator::list_mongo_operators().contains(sub_key);
48                    if is_filter_operator {
49                        let filter_operator = FilterOperator::from_str(sub_key).unwrap();
50                        let filter = FilterOperator::convert_value_to_mongo(
51                            &filter_operator,
52                            key,
53                            sub_value,
54                        );
55                        trace!("Inserted Filter: {:?}", filter);
56                        find_doc.insert(key.clone(), filter);
57                    } else {
58                        let nested_key = format!("{}.{}", key, sub_key);
59                        find_doc.insert(nested_key, sub_value.clone());
60                    }
61                }
62            } else {
63                if let Some(array) = value.as_array() {
64                    trace!("Found Array: {:?}", array);
65                    // If not a filter array, then call recursively on each document in the array
66                    if key == "$and" || key == "$or" {
67                        let mut docs = vec![];
68                        for b in array {
69                            let find_filter =
70                                Services::create_nested_find_filter(b.as_document().unwrap());
71                            docs.push(find_filter);
72                        }
73                        find_doc.insert(key.clone(), docs);
74                        continue;
75                    }
76
77                    // Handle Object Types
78                    trace!("Checking if array is docs");
79                    let is_docs = array.iter().all(|bson| bson.as_document().is_some());
80                    if is_docs {
81                        let mut docs = vec![];
82                        for b in array {
83                            docs.push(doc! { key.clone(): {"$elemMatch": b}})
84                        }
85                        if docs.len() > 0 {
86                            find_doc.insert("$and", docs);
87                        } else {
88                            find_doc.insert(key.clone(), doc! { "$in": array });
89                        }
90                    } else {
91                        // Handle array of primitives.
92                        trace!("Array is not docs");
93                        find_doc.insert(key.clone(), doc! { "$in": array });
94                    }
95                    continue;
96                }
97                // Handle primitive default
98                trace!("Found Primitive: {:?}", value);
99                find_doc.insert(key.clone(), value.clone());
100            }
101        }
102        debug!("Created Nested Find Filter");
103        trace!("Nested Find Filter: {:?}", find_doc);
104        find_doc
105    }
106}