linkrs_query/parser/parsing/
dml_parser.rs1use crate::parser::ast::stmt::*;
6use crate::parser::core::error::ParseError;
7use crate::parser::core::error::ParseErrorKind;
8use crate::parser::core::token::TokenKindExt;
9use crate::parser::parsing::clause_parser::ClauseParser;
10use crate::parser::parsing::expr_parser::parse_expression_with_context;
11use crate::parser::parsing::parse_context::ParseContext;
12use crate::parser::parsing::traversal_parser::TraversalParser;
13use crate::parser::TokenKind;
14use linkrs_core::types::expr::contextual::ContextualExpression;
15use linkrs_core::types::expr::Expression as CoreExpression;
16
17mod copy;
18mod create;
19mod delete;
20mod insert;
21mod merge;
22mod update;
23
24pub struct DmlParser;
26
27impl DmlParser {
28 pub fn new() -> Self {
29 Self
30 }
31
32 fn extract_id_with_residual(
38 ctx: &mut ParseContext,
39 where_clause: Option<&ContextualExpression>,
40 var_names: &[&str],
41 ) -> (Option<linkrs_core::Value>, Option<ContextualExpression>) {
42 let Some(root) = where_clause.and_then(|w| w.get_expression()) else {
43 return (None, None);
44 };
45 let mut conjuncts = Vec::new();
46 Self::collect_conjuncts(root, &mut conjuncts);
47 let mut extracted = None;
48 let mut rest = Vec::new();
49 for conjunct in conjuncts {
50 if extracted.is_none() {
51 if let Some(value) = Self::match_id_equality(&conjunct, var_names) {
52 extracted = Some(value);
53 continue;
54 }
55 }
56 rest.push(conjunct);
57 }
58 (extracted, Self::combine_conjuncts(ctx, rest))
59 }
60
61 fn collect_conjuncts(expr: CoreExpression, out: &mut Vec<CoreExpression>) {
63 use linkrs_core::types::operators::BinaryOperator;
64 match expr {
65 CoreExpression::Binary { left, op, right } if matches!(op, BinaryOperator::And) => {
66 Self::collect_conjuncts(*left, out);
67 Self::collect_conjuncts(*right, out);
68 }
69 other => out.push(other),
70 }
71 }
72
73 fn match_id_equality(
75 conjunct: &CoreExpression,
76 var_names: &[&str],
77 ) -> Option<linkrs_core::Value> {
78 use linkrs_core::types::operators::BinaryOperator;
79 match conjunct {
80 CoreExpression::Binary { left, op, right } if matches!(op, BinaryOperator::Equal) => {
81 if let CoreExpression::Function { name, args } = left.as_ref() {
82 if name == "id" && args.len() == 1 {
83 if let CoreExpression::Variable(v) = args[0].as_expr() {
84 if var_names.iter().any(|n| **n == *v) {
85 if let CoreExpression::Literal(value) = right.as_ref() {
86 return Some(value.clone());
87 }
88 }
89 }
90 }
91 }
92 None
93 }
94 _ => None,
95 }
96 }
97
98 fn combine_conjuncts(
100 ctx: &mut ParseContext,
101 conjuncts: Vec<CoreExpression>,
102 ) -> Option<ContextualExpression> {
103 use linkrs_core::types::operators::BinaryOperator;
104 let mut iter = conjuncts.into_iter();
105 let mut acc = iter.next()?;
106 for next in iter {
107 acc = CoreExpression::Binary {
108 left: Box::new(acc),
109 op: BinaryOperator::And,
110 right: Box::new(next),
111 };
112 }
113 let meta = linkrs_core::types::expr::ExpressionMeta::with_span(acc, ctx.current_span());
114 let id = ctx.expression_context_clone().register_expression(meta);
115 Some(ContextualExpression::new(
116 id,
117 ctx.expression_context_clone(),
118 ))
119 }
120
121 fn parse_expression(
123 &mut self,
124 ctx: &mut ParseContext,
125 ) -> Result<ContextualExpression, ParseError> {
126 parse_expression_with_context(ctx, ctx.expression_context_clone())
127 }
128
129 fn parse_property_map(
131 &mut self,
132 ctx: &mut ParseContext,
133 ) -> Result<ContextualExpression, ParseError> {
134 let _start_span = ctx.current_span();
135 let mut properties = Vec::new();
136
137 if !ctx.check_token(TokenKind::RBrace) {
138 loop {
139 let key = ctx.expect_identifier()?;
140 ctx.expect_token(TokenKind::Colon)?;
141 let value = self.parse_expression(ctx)?;
142 let value_expr = value
143 .expression()
144 .ok_or_else(|| {
145 ParseError::new_simple(
146 "Expression not registered in context".to_string(),
147 ctx.current_position(),
148 )
149 })?
150 .inner()
151 .clone();
152 properties.push((key, value_expr));
153
154 if !ctx.match_token(TokenKind::Comma) {
155 break;
156 }
157 }
158 }
159
160 let expr = CoreExpression::Map(properties);
161 let expr_meta = linkrs_core::types::expr::ExpressionMeta::new(expr);
162 let id = ctx.expression_context().register_expression(expr_meta);
163 Ok(ContextualExpression::new(
164 id,
165 ctx.expression_context_clone(),
166 ))
167 }
168}
169
170impl Default for DmlParser {
171 fn default() -> Self {
172 Self::new()
173 }
174}