nova_boot_graphdb/
builders.rs1use crate::types::GraphQuery;
2
3pub(crate) fn sanitize_symbol(value: &str) -> String {
4 let cleaned = value
5 .chars()
6 .filter(|c| c.is_ascii_alphanumeric() || *c == '_')
7 .collect::<String>();
8 if cleaned.is_empty() {
9 "Node".to_string()
10 } else {
11 cleaned
12 }
13}
14
15pub struct CypherQueryBuilder {
16 query: String,
17}
18
19impl CypherQueryBuilder {
20 pub fn new() -> Self {
21 Self {
22 query: String::new(),
23 }
24 }
25
26 pub fn raw(mut self, fragment: impl AsRef<str>) -> Self {
27 if !self.query.is_empty() {
28 self.query.push(' ');
29 }
30 self.query.push_str(fragment.as_ref());
31 self
32 }
33
34 pub fn match_node(mut self, alias: &str, label: &str) -> Self {
35 self.query.push_str(&format!("MATCH ({alias}:{label}) "));
36 self
37 }
38
39 pub fn where_eq(mut self, alias: &str, field: &str, value: &str) -> Self {
40 self.query
41 .push_str(&format!("WHERE {alias}.{field} = '{value}' "));
42 self
43 }
44
45 pub fn return_fields(mut self, fields: impl AsRef<str>) -> Self {
46 self.query.push_str(&format!("RETURN {}", fields.as_ref()));
47 self
48 }
49
50 pub fn build(self) -> GraphQuery {
51 GraphQuery::Cypher(self.query.trim().to_string())
52 }
53}
54
55impl Default for CypherQueryBuilder {
56 fn default() -> Self {
57 Self::new()
58 }
59}
60
61pub struct GraphQlQueryBuilder {
62 root: String,
63 fields: Vec<String>,
64 args: Vec<(String, String)>,
65}
66
67impl GraphQlQueryBuilder {
68 pub fn new(root: impl Into<String>) -> Self {
69 Self {
70 root: root.into(),
71 fields: Vec::new(),
72 args: Vec::new(),
73 }
74 }
75
76 pub fn arg(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
77 self.args.push((key.into(), value.into()));
78 self
79 }
80
81 pub fn field(mut self, field: impl Into<String>) -> Self {
82 self.fields.push(field.into());
83 self
84 }
85
86 pub fn build(self) -> GraphQuery {
87 let args = if self.args.is_empty() {
88 String::new()
89 } else {
90 let joined = self
91 .args
92 .into_iter()
93 .map(|(k, v)| format!("{k}: \"{v}\""))
94 .collect::<Vec<_>>()
95 .join(", ");
96 format!("({joined})")
97 };
98
99 let fields = if self.fields.is_empty() {
100 "id".to_string()
101 } else {
102 self.fields.join(" ")
103 };
104
105 GraphQuery::GraphQl(format!(
106 "query {{ {}{} {{ {} }} }}",
107 self.root, args, fields
108 ))
109 }
110}