nexus_sdk/query_builder.rs
1//! Query builder for constructing Cypher queries in a type-safe manner
2
3use crate::models::Value;
4use std::collections::HashMap;
5
6/// Query builder for constructing Cypher queries
7#[derive(Debug, Clone)]
8pub struct QueryBuilder {
9 parts: Vec<String>,
10 params: HashMap<String, Value>,
11 current_clause: Option<ClauseType>,
12}
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15enum ClauseType {
16 Match,
17 Create,
18 Merge,
19 Where,
20 Return,
21 Set,
22 Delete,
23 With,
24 OrderBy,
25 Limit,
26 Skip,
27}
28
29impl QueryBuilder {
30 /// Create a new query builder
31 pub fn new() -> Self {
32 Self {
33 parts: Vec::new(),
34 params: HashMap::new(),
35 current_clause: None,
36 }
37 }
38
39 /// Add a MATCH clause
40 ///
41 /// # Example
42 ///
43 /// ```no_run
44 /// use nexus_sdk::query_builder::QueryBuilder;
45 ///
46 /// let query = QueryBuilder::new()
47 /// .match_("(n:Person)")
48 /// .build();
49 /// ```
50 pub fn match_(mut self, pattern: &str) -> Self {
51 self.parts.push(format!("MATCH {}", pattern));
52 self.current_clause = Some(ClauseType::Match);
53 self
54 }
55
56 /// Add a CREATE clause
57 ///
58 /// # Example
59 ///
60 /// ```no_run
61 /// use nexus_sdk::query_builder::QueryBuilder;
62 ///
63 /// let query = QueryBuilder::new()
64 /// .create("(n:Person {name: $name})")
65 /// .param("name", "Alice")
66 /// .build();
67 /// ```
68 pub fn create(mut self, pattern: &str) -> Self {
69 self.parts.push(format!("CREATE {}", pattern));
70 self.current_clause = Some(ClauseType::Create);
71 self
72 }
73
74 /// Add a MERGE clause
75 pub fn merge(mut self, pattern: &str) -> Self {
76 self.parts.push(format!("MERGE {}", pattern));
77 self.current_clause = Some(ClauseType::Merge);
78 self
79 }
80
81 /// Add a WHERE clause
82 ///
83 /// # Example
84 ///
85 /// ```no_run
86 /// use nexus_sdk::query_builder::QueryBuilder;
87 ///
88 /// let query = QueryBuilder::new()
89 /// .match_("(n:Person)")
90 /// .where_("n.age > $min_age")
91 /// .param("min_age", 18)
92 /// .build();
93 /// ```
94 pub fn where_(mut self, condition: &str) -> Self {
95 self.parts.push(format!("WHERE {}", condition));
96 self.current_clause = Some(ClauseType::Where);
97 self
98 }
99
100 /// Add a RETURN clause
101 ///
102 /// # Example
103 ///
104 /// ```no_run
105 /// use nexus_sdk::query_builder::QueryBuilder;
106 ///
107 /// let query = QueryBuilder::new()
108 /// .match_("(n:Person)")
109 /// .return_("n")
110 /// .build();
111 /// ```
112 pub fn return_(mut self, items: &str) -> Self {
113 self.parts.push(format!("RETURN {}", items));
114 self.current_clause = Some(ClauseType::Return);
115 self
116 }
117
118 /// Add a SET clause
119 pub fn set(mut self, assignments: &str) -> Self {
120 self.parts.push(format!("SET {}", assignments));
121 self.current_clause = Some(ClauseType::Set);
122 self
123 }
124
125 /// Add a DELETE clause
126 pub fn delete(mut self, items: &str) -> Self {
127 self.parts.push(format!("DELETE {}", items));
128 self.current_clause = Some(ClauseType::Delete);
129 self
130 }
131
132 /// Add a WITH clause
133 pub fn with(mut self, items: &str) -> Self {
134 self.parts.push(format!("WITH {}", items));
135 self.current_clause = Some(ClauseType::With);
136 self
137 }
138
139 /// Add an ORDER BY clause
140 ///
141 /// # Example
142 ///
143 /// ```no_run
144 /// use nexus_sdk::query_builder::QueryBuilder;
145 ///
146 /// let query = QueryBuilder::new()
147 /// .match_("(n:Person)")
148 /// .return_("n")
149 /// .order_by("n.name ASC")
150 /// .build();
151 /// ```
152 pub fn order_by(mut self, expression: &str) -> Self {
153 self.parts.push(format!("ORDER BY {}", expression));
154 self.current_clause = Some(ClauseType::OrderBy);
155 self
156 }
157
158 /// Add a LIMIT clause
159 ///
160 /// # Example
161 ///
162 /// ```no_run
163 /// use nexus_sdk::query_builder::QueryBuilder;
164 ///
165 /// let query = QueryBuilder::new()
166 /// .match_("(n:Person)")
167 /// .return_("n")
168 /// .limit(10)
169 /// .build();
170 /// ```
171 pub fn limit(mut self, count: usize) -> Self {
172 self.parts.push(format!("LIMIT {}", count));
173 self.current_clause = Some(ClauseType::Limit);
174 self
175 }
176
177 /// Add a SKIP clause
178 pub fn skip(mut self, count: usize) -> Self {
179 self.parts.push(format!("SKIP {}", count));
180 self.current_clause = Some(ClauseType::Skip);
181 self
182 }
183
184 /// Add a parameter to the query
185 ///
186 /// # Example
187 ///
188 /// ```no_run
189 /// use nexus_sdk::query_builder::QueryBuilder;
190 ///
191 /// let query = QueryBuilder::new()
192 /// .match_("(n:Person)")
193 /// .where_("n.name = $name")
194 /// .param("name", "Alice")
195 /// .build();
196 /// ```
197 pub fn param<T: Into<Value>>(mut self, name: &str, value: T) -> Self {
198 self.params.insert(name.to_string(), value.into());
199 self
200 }
201
202 /// Build the final query string
203 pub fn build(self) -> BuiltQuery {
204 BuiltQuery {
205 query: self.parts.join(" "),
206 params: if self.params.is_empty() {
207 None
208 } else {
209 Some(self.params)
210 },
211 }
212 }
213}
214
215impl Default for QueryBuilder {
216 fn default() -> Self {
217 Self::new()
218 }
219}
220
221/// Built query ready for execution
222#[derive(Debug, Clone)]
223pub struct BuiltQuery {
224 query: String,
225 params: Option<HashMap<String, Value>>,
226}
227
228impl BuiltQuery {
229 /// Get the query string
230 pub fn query(&self) -> &str {
231 &self.query
232 }
233
234 /// Get the parameters
235 pub fn params(&self) -> Option<&HashMap<String, Value>> {
236 self.params.as_ref()
237 }
238
239 /// Convert to query string and parameters tuple
240 pub fn into_parts(self) -> (String, Option<HashMap<String, Value>>) {
241 (self.query, self.params)
242 }
243}