edgedb_query_builder/
lib.rs

1pub enum Keyword {
2    Select {
3        table: String,
4        fields: Vec<String>
5    },
6    Insert {
7        table: String,
8        fields: Vec<(String, String)>,
9    },
10    Filter {
11        fields: Vec<(String, String)>,
12    }
13}
14
15/// Base struct for all queries built with the query builder
16pub struct Query {
17    pub keywords: Vec<Keyword>
18}
19
20impl Query {
21    /// Create a new query builder
22    pub fn new() -> Self {
23        Query { keywords: Vec::new() }
24    }
25    /// Add a select statement to the query. Takes the name of the table you're selecting and the values.
26    /// You can add a filter with `.filter`.
27    pub fn select<T: Into<String> + std::fmt::Display>(&mut self, table: T, values: Vec<T>) -> &mut Self {
28        self.keywords.push(Keyword::Select { table: table.into(), fields: values.iter().map(|e| e.to_string()).collect::<Vec<String>>() });
29        return self
30    }
31    /// Add a filter statement to the query. Takes a vector of (String,String). The first value is the field name and the 
32    /// second field is the value that should be filtered with. 
33    pub fn filter(&mut self, fields: Vec<(String, String)>) -> &mut Self {
34        self.keywords.push(Keyword::Filter { fields });
35        return self
36    }
37    /// Add an insert statement to your query. Takes the name of the table being inserted into and a vector of (String,String).
38    /// Similarly to `.filter()` this tuple is in the order (field, value).
39    pub fn insert<T: Into<String> + std::fmt::Display>(&mut self, table: T, fields: Vec<(String, String)>) -> &mut Self {
40        self.keywords.push(Keyword::Insert { table: table.into(), fields });
41        return self
42    }
43    /// Builds the query into an actual statement. 
44    /// ```rust
45    /// use edgedb_query_builder::Query;
46    /// 
47    /// let builder = Query::new().select("Movie", vec!["id","title"]).build();
48    /// // This will be turned into:
49    /// // select Movie { id, title };
50    /// ```
51    pub fn build(&self) -> String {
52        let mut query = String::new();
53        for keyword in &self.keywords {
54            match keyword {
55                Keyword::Select { table, fields } => {
56                    query.push_str(&format!("select {table} {{ {} }}", fields.join(",")))
57                },
58                Keyword::Insert { table, fields } => {
59                    query.push_str(&format!("insert {table} {{ {} }}", fields.iter().map(|f| format!("{} := \"{}\"", f.0, f.1)).collect::<Vec<String>>().join(",")))
60                }
61                Keyword::Filter { fields } => {
62                    let mut filter_stmt = String::from("filter");
63                    let filters = fields.iter().map(|f| format!(".{} = \"{}\"", f.0, f.1)).collect::<Vec<String>>().join("and");
64                    filter_stmt.push_str(&filters);
65                    query.push_str(&filter_stmt);
66                }
67            }
68        }
69        query.push(';');
70        return query
71    }
72}
73
74#[cfg(test)]
75mod query_tests {
76    #[test]
77    fn basic_query() {
78        let mut query = crate::Query::new();
79        query.select("movie".to_string(), vec!["title".to_string()]);
80        
81        let query_str = query.build();
82
83        assert_eq!(query_str, String::from("select movie { title }"));
84    }
85}