graphql_query_builder/
lib.rs

1mod enums;
2pub mod json;
3pub use enums::{input_values::Values, OperationType};
4
5type Fields = Vec<SelectionSet>;
6type Arguments = std::collections::HashMap<&'static str, Values>;
7
8#[derive(Clone, Debug)]
9pub struct SelectionSet {
10    pub operation: &'static str,
11    pub alias: Option<&'static str>,
12    pub fields: Option<Fields>,
13    pub arguments: Option<Arguments>,
14    pub is_union: bool,
15}
16
17pub fn tabs(level: usize) -> String {
18    "\t".repeat(level)
19}
20
21pub struct Builder;
22
23impl Builder {
24    pub fn new(operation: OperationType, selection_set: &SelectionSet) -> String {
25        Self::generate_field(
26            0,
27            SelectionSet {
28                operation: operation.into(),
29                alias: None,
30                fields: Some(vec![selection_set.clone()]),
31                arguments: None,
32                is_union: false,
33            },
34        )
35    }
36
37    fn parse_arguments(args: &Arguments) -> Vec<String> {
38        args.into_iter()
39            .map(|(key, value)| match value {
40                Values::Int(value) => format!("{}: {}", key, value),
41                Values::Float(_) => todo!(),
42                Values::String(value) => format!("{}: \"{}\"", key, value),
43                Values::Boolean(value) => format!("{}: {}", key, value),
44                Values::Null => format!("{}: null", key),
45                Values::Enum(values) => {
46                    for value in values {
47                        match value {
48                            &"null" | &"true" | &"false" => {
49                                panic!("{key} cannot contain {value} value")
50                            }
51                            _ => (),
52                        }
53                    }
54                    format!("{}: [{}]", key, values.join(", "))
55                }
56                Values::List(value) => format!(
57                    "{}: [{}]",
58                    key,
59                    value
60                        .iter()
61                        .map(|i| i.to_string())
62                        .collect::<Vec<String>>()
63                        .join(", ")
64                ),
65                Values::Object => todo!(),
66            })
67            .collect()
68    }
69
70    fn generate_field(level: usize, field: SelectionSet) -> String {
71        let tabs = tabs(level);
72        let operation = field.operation;
73        let union = if field.is_union { "... on " } else { "" };
74        let alias = if let Some(alias) = field.alias {
75            format!("{}: ", alias)
76        } else {
77            String::from("")
78        };
79        let arguments = if let Some(args) = field.arguments {
80            format!("({})", Self::parse_arguments(&args).join(", "))
81        } else {
82            String::from("")
83        };
84        let sub_field = if let Some(sf) = field.fields {
85            let sub_field = Self::map_fields(level, sf).join("\n");
86            format!(" {{\n{sub_field}\n{tabs}}}")
87        } else {
88            String::from("")
89        };
90        format!("{tabs}{union}{alias}{operation}{arguments}{sub_field}")
91    }
92    fn map_fields(level: usize, selection_sets: Fields) -> Vec<String> {
93        selection_sets
94            .clone()
95            .into_iter()
96            .map(|field| Self::generate_field(level + 1, field))
97            .collect()
98    }
99}