Skip to main content

marsdb_query/
params.rs

1use std::collections::HashMap;
2
3use marsdb_graph::PropertyValue;
4
5use crate::ast::{Expr, Literal, NodePattern, Pattern, QueryPart, ReturnExpr, Statement, Tail, WithClause, WithExpr};
6use crate::error::QueryError;
7
8/// Resolves every `$name` placeholder in `stmt` to a concrete `Literal`
9/// using `params`, in place. Called before execution so the executor never
10/// sees `Literal::Param` — see the `unreachable!` in
11/// `executor::literal_to_value`.
12pub 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(where_clause) = &mut with.where_clause {
55        substitute_with_expr(where_clause, params)?;
56    }
57    if let Some(items) = &mut with.order_by {
58        for (expr, _) in items {
59            substitute_return_expr(expr, params)?;
60        }
61    }
62    Ok(())
63}
64
65fn substitute_with_expr(expr: &mut WithExpr, params: &HashMap<String, PropertyValue>) -> Result<(), QueryError> {
66    match expr {
67        WithExpr::And(l, r) | WithExpr::Or(l, r) => {
68            substitute_with_expr(l, params)?;
69            substitute_with_expr(r, params)?;
70        }
71        WithExpr::Not(e) => substitute_with_expr(e, params)?,
72        WithExpr::Compare(lhs, _, lit) => {
73            substitute_return_expr(lhs, params)?;
74            substitute_literal(lit, params)?;
75        }
76    }
77    Ok(())
78}
79
80fn substitute_pattern(pattern: &mut Pattern, params: &HashMap<String, PropertyValue>) -> Result<(), QueryError> {
81    substitute_node(&mut pattern.start, params)?;
82    for (rel, node) in &mut pattern.hops {
83        for (_, lit) in &mut rel.props {
84            substitute_literal(lit, params)?;
85        }
86        substitute_node(node, params)?;
87    }
88    Ok(())
89}
90
91fn substitute_node(node: &mut NodePattern, params: &HashMap<String, PropertyValue>) -> Result<(), QueryError> {
92    for (_, lit) in &mut node.props {
93        substitute_literal(lit, params)?;
94    }
95    Ok(())
96}
97
98fn substitute_expr(expr: &mut Expr, params: &HashMap<String, PropertyValue>) -> Result<(), QueryError> {
99    match expr {
100        Expr::And(l, r) | Expr::Or(l, r) => {
101            substitute_expr(l, params)?;
102            substitute_expr(r, params)?;
103        }
104        Expr::Not(e) => substitute_expr(e, params)?,
105        Expr::Compare(_, _, lit) => substitute_literal(lit, params)?,
106        Expr::HasLabel(_, _) => {}
107        Expr::VarEq(_, _) => {}
108    }
109    Ok(())
110}
111
112fn substitute_tail(tail: &mut Tail, params: &HashMap<String, PropertyValue>) -> Result<(), QueryError> {
113    match tail {
114        Tail::Return(items) => {
115            for item in items {
116                substitute_return_expr(&mut item.expr, params)?;
117            }
118        }
119        Tail::Delete(_) | Tail::DetachDelete(_) => {}
120        Tail::Set(items) => {
121            for (_, lit) in items {
122                substitute_literal(lit, params)?;
123            }
124        }
125    }
126    Ok(())
127}
128
129fn substitute_return_expr(expr: &mut ReturnExpr, params: &HashMap<String, PropertyValue>) -> Result<(), QueryError> {
130    match expr {
131        ReturnExpr::Var(_) | ReturnExpr::Prop(_) | ReturnExpr::CountStar => {}
132        ReturnExpr::Lit(lit) => substitute_literal(lit, params)?,
133        ReturnExpr::Call { args, .. } => {
134            for arg in args {
135                substitute_return_expr(arg, params)?;
136            }
137        }
138        ReturnExpr::Case { test, whens, else_ } => {
139            if let Some(t) = test {
140                substitute_return_expr(t, params)?;
141            }
142            for (when, then) in whens {
143                substitute_return_expr(when, params)?;
144                substitute_return_expr(then, params)?;
145            }
146            if let Some(e) = else_ {
147                substitute_return_expr(e, params)?;
148            }
149        }
150    }
151    Ok(())
152}
153
154fn substitute_literal(lit: &mut Literal, params: &HashMap<String, PropertyValue>) -> Result<(), QueryError> {
155    if let Literal::Param(name) = lit {
156        let value = params
157            .get(name)
158            .ok_or_else(|| QueryError::MissingParam(name.clone()))?;
159        *lit = property_value_to_literal(value);
160    }
161    Ok(())
162}
163
164fn property_value_to_literal(pv: &PropertyValue) -> Literal {
165    match pv {
166        PropertyValue::Null => Literal::Null,
167        PropertyValue::Bool(b) => Literal::Bool(*b),
168        PropertyValue::Int(i) => Literal::Int(*i),
169        PropertyValue::Float(f) => Literal::Float(*f),
170        PropertyValue::String(s) => Literal::String(s.clone()),
171    }
172}