subgraph/data_sources/sql/create_query/create_find_many_query/
mod.rs

1use std::str::FromStr;
2
3use bson::Document;
4use log::{debug, trace};
5
6use crate::{
7    configuration::subgraph::{
8        data_sources::sql::DialectEnum, entities::ServiceEntityConfig, SubGraphConfig,
9    },
10    data_sources::sql::SqlDataSource,
11    filter_operator::FilterOperator,
12    graphql::schema::create_options_input::{DirectionEnum, SortInput},
13    sql_value::SqlValue,
14};
15
16use super::JoinClauses;
17
18impl SqlDataSource {
19    pub fn create_find_many_query(
20        entity: &ServiceEntityConfig,
21        table_name: &str,
22        dialect: &DialectEnum,
23        input: &Document,
24        subgraph_config: &SubGraphConfig,
25        join_clauses: Option<JoinClauses>,
26        disable_eager_loading: bool,
27    ) -> Result<(String, Vec<SqlValue>, String, Vec<String>), async_graphql::Error> {
28        debug!("Creating Find Many Query");
29
30        let mut query = String::new();
31        let mut count_query = String::new();
32        let entity_table_name = if let Some(entity_ds) = entity.data_source.clone() {
33            if entity_ds.table.is_some() {
34                entity_ds.table.unwrap()
35            } else {
36                entity.name.clone()
37            }
38        } else {
39            entity.name.clone()
40        };
41        let select_statement = format!("SELECT {}.* FROM ", entity_table_name);
42        query.push_str(&select_statement);
43        query.push_str(table_name);
44
45        let count_statement = format!("SELECT COUNT(*) as total_count FROM {}", table_name);
46        count_query.push_str(&count_statement);
47
48        let query_input = input.get("query").unwrap();
49        let (
50            nested_query,
51            combined_where_values,
52            combined_join_clauses,
53            combined_where_keys,
54            _offset,
55        ) = SqlDataSource::create_nested_query_recursive(
56            &vec![query_input.clone()],
57            entity,
58            dialect,
59            FilterOperator::And,
60            false,
61            None,
62            subgraph_config,
63            join_clauses,
64            disable_eager_loading,
65        )?;
66
67        for join_clause in combined_join_clauses.0 {
68            trace!("Adding Join Clause: {}", join_clause);
69            query.push_str(&join_clause);
70            count_query.push_str(&join_clause);
71        }
72
73        query.push_str(" WHERE ");
74        count_query.push_str(" WHERE ");
75
76        if let Some(nested_query) = nested_query {
77            query.push_str(&nested_query);
78            count_query.push_str(&nested_query);
79        } else {
80            query.push_str("1=1");
81            count_query.push_str("1=1");
82        }
83
84        let opts_input = input.get("opts");
85        let mut per_page = 10;
86        let mut page = 1;
87        let mut sort_vec = Vec::new();
88
89        if let Some(opts_input) = opts_input {
90            let opts = opts_input.as_document().unwrap();
91            if let Some(per_page_input) = opts.get("per_page") {
92                per_page = per_page_input
93                    .as_i32()
94                    .unwrap_or(per_page_input.as_i64().unwrap_or(10) as i32);
95            }
96            if let Some(page_input) = opts.get("page") {
97                page = page_input
98                    .as_i32()
99                    .unwrap_or(page_input.as_i64().unwrap_or(1) as i32);
100            }
101
102            if let Some(sort_input) = opts.get("sort") {
103                let sort_input = sort_input.as_array();
104                if sort_input.is_none() {
105                    return Err(async_graphql::Error::new("Sort input must be an array"));
106                }
107                let sort_input = sort_input.unwrap();
108                for sort_item in sort_input {
109                    let sort_item = sort_item.as_document().unwrap();
110                    let field = sort_item.get("field").unwrap();
111                    let field = field.as_str().unwrap();
112                    let direction = sort_item.get("direction").unwrap();
113                    let direction = DirectionEnum::from_str(direction.as_str().unwrap()).unwrap();
114
115                    sort_vec.push(SortInput {
116                        field: field.to_string(),
117                        direction,
118                    });
119                }
120            }
121        }
122
123        if sort_vec.len() > 0 {
124            // If postgres, we need to add the sort fields to the group by clause
125            if dialect == &DialectEnum::POSTGRES {
126                query.push_str(" GROUP BY ");
127                for (i, sort_item) in sort_vec.iter().enumerate() {
128                    if i > 0 {
129                        query.push_str(", ");
130                    }
131                    query.push_str(&format!("{} ", sort_item.field));
132                }
133            }
134            query.push_str(" ORDER BY ");
135            for (i, sort_item) in sort_vec.iter().enumerate() {
136                if i > 0 {
137                    query.push_str(", ");
138                }
139                query.push_str(&format!(
140                    "{} {}",
141                    sort_item.field,
142                    sort_item.direction.to_string()
143                ));
144            }
145        }
146
147        if per_page != -1 {
148            let offset = (page - 1) * per_page;
149            query.push_str(&format!(" LIMIT {} OFFSET {}", per_page, offset));
150        }
151
152        if !query.ends_with(';') {
153            query.push(';');
154        }
155
156        if !count_query.ends_with(';') {
157            count_query.push(';');
158        }
159
160        Ok((
161            query,
162            combined_where_values,
163            count_query,
164            combined_where_keys,
165        ))
166    }
167}