1use std::collections::HashMap;
2
3use marsdb_graph::PropertyValue;
4
5use crate::ast::{Expr, Literal, NodePattern, Pattern, QueryPart, ReturnExpr, Statement, Tail, WithClause};
6use crate::error::QueryError;
7
8pub fn substitute_params(stmt: &mut Statement, params: &HashMap<String, PropertyValue>) -> Result<(), QueryError> {
13 match stmt {
14 Statement::Create(patterns) => {
15 for pattern in patterns {
16 substitute_pattern(pattern, params)?;
17 }
18 }
19 Statement::Match {
20 parts,
21 tail,
22 order_by,
23 limit: _,
24 } => {
25 for part in parts {
26 substitute_query_part(part, params)?;
27 }
28 substitute_tail(tail, params)?;
29 if let Some(items) = order_by {
30 for (expr, _) in items {
31 substitute_return_expr(expr, params)?;
32 }
33 }
34 }
35 }
36 Ok(())
37}
38
39fn substitute_query_part(part: &mut QueryPart, params: &HashMap<String, PropertyValue>) -> Result<(), QueryError> {
40 substitute_pattern(&mut part.pattern, params)?;
41 if let Some(expr) = &mut part.where_clause {
42 substitute_expr(expr, params)?;
43 }
44 if let Some(with) = &mut part.with {
45 substitute_with_clause(with, params)?;
46 }
47 Ok(())
48}
49
50fn substitute_with_clause(with: &mut WithClause, params: &HashMap<String, PropertyValue>) -> Result<(), QueryError> {
51 for item in &mut with.items {
52 substitute_return_expr(&mut item.expr, params)?;
53 }
54 if let Some(items) = &mut with.order_by {
55 for (expr, _) in items {
56 substitute_return_expr(expr, params)?;
57 }
58 }
59 Ok(())
60}
61
62fn substitute_pattern(pattern: &mut Pattern, params: &HashMap<String, PropertyValue>) -> Result<(), QueryError> {
63 substitute_node(&mut pattern.start, params)?;
64 for (rel, node) in &mut pattern.hops {
65 for (_, lit) in &mut rel.props {
66 substitute_literal(lit, params)?;
67 }
68 substitute_node(node, params)?;
69 }
70 Ok(())
71}
72
73fn substitute_node(node: &mut NodePattern, params: &HashMap<String, PropertyValue>) -> Result<(), QueryError> {
74 for (_, lit) in &mut node.props {
75 substitute_literal(lit, params)?;
76 }
77 Ok(())
78}
79
80fn substitute_expr(expr: &mut Expr, params: &HashMap<String, PropertyValue>) -> Result<(), QueryError> {
81 match expr {
82 Expr::And(l, r) | Expr::Or(l, r) => {
83 substitute_expr(l, params)?;
84 substitute_expr(r, params)?;
85 }
86 Expr::Not(e) => substitute_expr(e, params)?,
87 Expr::Compare(_, _, lit) => substitute_literal(lit, params)?,
88 Expr::HasLabel(_, _) => {}
89 Expr::VarEq(_, _) => {}
90 }
91 Ok(())
92}
93
94fn substitute_tail(tail: &mut Tail, params: &HashMap<String, PropertyValue>) -> Result<(), QueryError> {
95 match tail {
96 Tail::Return(items) => {
97 for item in items {
98 substitute_return_expr(&mut item.expr, params)?;
99 }
100 }
101 Tail::Delete(_) | Tail::DetachDelete(_) => {}
102 Tail::Set(items) => {
103 for (_, lit) in items {
104 substitute_literal(lit, params)?;
105 }
106 }
107 }
108 Ok(())
109}
110
111fn substitute_return_expr(expr: &mut ReturnExpr, params: &HashMap<String, PropertyValue>) -> Result<(), QueryError> {
112 match expr {
113 ReturnExpr::Var(_) | ReturnExpr::Prop(_) => {}
114 ReturnExpr::Lit(lit) => substitute_literal(lit, params)?,
115 ReturnExpr::Call(_, args) => {
116 for arg in args {
117 substitute_return_expr(arg, params)?;
118 }
119 }
120 ReturnExpr::Case { test, whens, else_ } => {
121 if let Some(t) = test {
122 substitute_return_expr(t, params)?;
123 }
124 for (when, then) in whens {
125 substitute_return_expr(when, params)?;
126 substitute_return_expr(then, params)?;
127 }
128 if let Some(e) = else_ {
129 substitute_return_expr(e, params)?;
130 }
131 }
132 }
133 Ok(())
134}
135
136fn substitute_literal(lit: &mut Literal, params: &HashMap<String, PropertyValue>) -> Result<(), QueryError> {
137 if let Literal::Param(name) = lit {
138 let value = params
139 .get(name)
140 .ok_or_else(|| QueryError::MissingParam(name.clone()))?;
141 *lit = property_value_to_literal(value);
142 }
143 Ok(())
144}
145
146fn property_value_to_literal(pv: &PropertyValue) -> Literal {
147 match pv {
148 PropertyValue::Null => Literal::Null,
149 PropertyValue::Bool(b) => Literal::Bool(*b),
150 PropertyValue::Int(i) => Literal::Int(*i),
151 PropertyValue::Float(f) => Literal::Float(*f),
152 PropertyValue::String(s) => Literal::String(s.clone()),
153 }
154}