linkrs_query/parser/parsing/dml_parser/
update.rs1use super::*;
2
3impl DmlParser {
4 pub fn parse_update_statement(&mut self, ctx: &mut ParseContext) -> Result<Stmt, ParseError> {
6 let start_span = ctx.current_span();
7 ctx.expect_token(TokenKind::Update)?;
8 self.parse_update_after_token(ctx, start_span)
9 }
10
11 pub fn parse_upsert_statement(&mut self, ctx: &mut ParseContext) -> Result<Stmt, ParseError> {
13 let start_span = ctx.current_span();
14 ctx.expect_token(TokenKind::Upsert)?;
15 ctx.set_upsert_mode(true);
16 let result = self.parse_update_after_token(ctx, start_span);
17 ctx.set_upsert_mode(false);
18 result
19 }
20
21 pub fn parse_update_after_token(
23 &mut self,
24 ctx: &mut ParseContext,
25 start_span: crate::parser::ast::types::Span,
26 ) -> Result<Stmt, ParseError> {
27 use crate::parser::ast::stmt::{SetClause, UpdateStmt, UpdateTarget};
28 use crate::parser::parsing::clause_parser::ClauseParser;
29
30 let is_upsert = ctx.is_upsert_mode();
32
33 let target = if ctx.match_token(TokenKind::Vertex) {
34 if is_upsert && ctx.check_token(TokenKind::On) {
35 ctx.match_token(TokenKind::On);
37 let tag_name = ctx.expect_identifier()?;
38 let set_clause = if ctx.match_token(TokenKind::Set) {
40 ClauseParser::new().parse_set_clause(ctx)?
41 } else {
42 SetClause {
43 span: ctx.current_span(),
44 assignments: Vec::new(),
45 }
46 };
47 let where_clause = if ctx.match_token(TokenKind::Where) {
49 ctx.recover_clause(|_| Ok(None), |c| self.parse_expression(c).map(Some))?
50 } else {
51 None
52 };
53 let yield_clause = if ctx.match_token(TokenKind::Yield) {
55 Some(ClauseParser::new().parse_yield_clause(ctx)?)
56 } else {
57 None
58 };
59 if ctx.match_token(TokenKind::When) {
62 ctx.recover_clause(|_| Ok(None), |c| self.parse_expression(c).map(Some))?;
63 }
64 let (vid_value_opt, residual) =
68 Self::extract_id_with_residual(ctx, where_clause.as_ref(), &["vid"]);
69 let vid_value = vid_value_opt.ok_or_else(|| {
70 ParseError::new(
71 crate::parser::core::error::ParseErrorKind::SyntaxError,
72 "UPSERT VERTEX ON form requires WHERE id(vid) == <literal>".to_string(),
73 ctx.current_position(),
74 )
75 })?;
76 let vid_expr = CoreExpression::Literal(vid_value);
77 let vid_expr_meta = linkrs_core::types::expr::ExpressionMeta::with_span(
78 vid_expr,
79 ctx.current_span(),
80 );
81 let vid_id = ctx
82 .expression_context_clone()
83 .register_expression(vid_expr_meta);
84 let vid = ContextualExpression::new(vid_id, ctx.expression_context_clone());
85 let span = ctx.span_since(start_span.start);
86 return Ok(Stmt::Update(UpdateStmt {
87 span,
88 target: UpdateTarget::TagOnVertex {
89 vid: Box::new(vid),
90 tag_name,
91 },
92 set_clause,
93 where_clause: residual,
94 yield_clause,
95 is_upsert,
96 }));
97 }
98 match self.parse_update_vertex(ctx)? {
99 UpdateTarget::Vertex(vid) if ctx.match_token(TokenKind::On) => {
100 let tag_name = ctx.expect_identifier()?;
101 UpdateTarget::TagOnVertex {
102 vid: Box::new(vid),
103 tag_name,
104 }
105 }
106 other => other,
107 }
108 } else if ctx.match_token(TokenKind::Tag) {
109 let tag_name = ctx.expect_identifier()?;
111 UpdateTarget::Tag(tag_name)
112 } else if ctx.match_token(TokenKind::Edge) {
113 if is_upsert && ctx.check_token(TokenKind::On) {
114 ctx.match_token(TokenKind::On);
116 let edge_type = ctx.expect_identifier()?;
117 let set_clause = if ctx.match_token(TokenKind::Set) {
119 ClauseParser::new().parse_set_clause(ctx)?
120 } else {
121 SetClause {
122 span: ctx.current_span(),
123 assignments: Vec::new(),
124 }
125 };
126 let where_clause = if ctx.match_token(TokenKind::Where) {
128 ctx.recover_clause(|_| Ok(None), |c| self.parse_expression(c).map(Some))?
129 } else {
130 None
131 };
132 let rank = if ctx.match_token(TokenKind::At) {
134 Some(self.parse_expression(ctx)?)
135 } else {
136 None
137 };
138 let yield_clause = if ctx.match_token(TokenKind::Yield) {
140 Some(ClauseParser::new().parse_yield_clause(ctx)?)
141 } else {
142 None
143 };
144 if ctx.match_token(TokenKind::When) {
147 ctx.recover_clause(|_| Ok(None), |c| self.parse_expression(c).map(Some))?;
148 }
149 let (src_value_opt, after_src) =
153 Self::extract_id_with_residual(ctx, where_clause.as_ref(), &["src", "source"]);
154 let src_value = src_value_opt.ok_or_else(|| {
155 ParseError::new(
156 crate::parser::core::error::ParseErrorKind::SyntaxError,
157 "UPSERT EDGE ON form requires WHERE id(src) == <literal> AND id(dst) == <literal>"
158 .to_string(),
159 ctx.current_position(),
160 )
161 })?;
162 let (dst_value_opt, residual) = Self::extract_id_with_residual(
163 ctx,
164 after_src.as_ref(),
165 &["dst", "dest", "destination"],
166 );
167 let dst_value = dst_value_opt.ok_or_else(|| {
168 ParseError::new(
169 crate::parser::core::error::ParseErrorKind::SyntaxError,
170 "UPSERT EDGE ON form requires WHERE id(src) == <literal> AND id(dst) == <literal>"
171 .to_string(),
172 ctx.current_position(),
173 )
174 })?;
175 let make_literal_expr =
176 |ctx: &mut ParseContext, value: linkrs_core::Value| -> ContextualExpression {
177 let expr = CoreExpression::Literal(value);
178 let meta = linkrs_core::types::expr::ExpressionMeta::with_span(
179 expr,
180 ctx.current_span(),
181 );
182 let id = ctx.expression_context_clone().register_expression(meta);
183 ContextualExpression::new(id, ctx.expression_context_clone())
184 };
185 let src = make_literal_expr(ctx, src_value);
186 let dst = make_literal_expr(ctx, dst_value);
187 let span = ctx.span_since(start_span.start);
188 return Ok(Stmt::Update(UpdateStmt {
189 span,
190 target: UpdateTarget::Edge {
191 edge_type: Some(edge_type),
192 src,
193 dst,
194 rank,
195 },
196 set_clause,
197 where_clause: residual,
198 is_upsert,
199 yield_clause,
200 }));
201 }
202 self.parse_update_edge(ctx)?
203 } else {
204 if is_upsert {
206 let vid = self.parse_expression(ctx)?;
207 if ctx.match_token(TokenKind::On) {
208 let tag_name = ctx.expect_identifier()?;
209 UpdateTarget::TagOnVertex {
210 vid: Box::new(vid),
211 tag_name,
212 }
213 } else {
214 UpdateTarget::Vertex(vid)
215 }
216 } else {
217 if matches!(
221 ctx.current_token().kind,
222 TokenKind::Set
223 | TokenKind::Where
224 | TokenKind::When
225 | TokenKind::Yield
226 | TokenKind::On
227 | TokenKind::Of
228 ) {
229 ctx.next_token();
230 return Err(ParseError::new(
231 crate::parser::core::error::ParseErrorKind::UnexpectedToken,
232 "Expected vertex id or edge target after UPDATE".to_string(),
233 ctx.current_position(),
234 ));
235 }
236 let expr = self.parse_expression(ctx)?;
239 if ctx.check_token(TokenKind::Arrow) {
240 self.parse_update_edge_short(ctx, expr)?
242 } else if ctx.match_token(TokenKind::On) {
243 let tag_name = ctx.expect_identifier()?;
244 UpdateTarget::TagOnVertex {
245 vid: Box::new(expr),
246 tag_name,
247 }
248 } else {
249 UpdateTarget::Vertex(expr)
251 }
252 }
253 };
254
255 let set_clause = if ctx.match_token(TokenKind::Set) {
256 ClauseParser::new().parse_set_clause(ctx)?
257 } else {
258 SetClause {
259 span: ctx.current_span(),
260 assignments: Vec::new(),
261 }
262 };
263
264 let where_clause = if ctx.match_token(TokenKind::Where) || ctx.match_token(TokenKind::When)
265 {
266 ctx.recover_clause(|_| Ok(None), |c| self.parse_expression(c).map(Some))?
267 } else {
268 None
269 };
270
271 let yield_clause = if ctx.match_token(TokenKind::Yield) {
273 Some(ClauseParser::new().parse_yield_clause(ctx)?)
274 } else {
275 None
276 };
277
278 let span = ctx.span_since(start_span.start);
279
280 Ok(Stmt::Update(UpdateStmt {
281 span,
282 target,
283 set_clause,
284 where_clause,
285 is_upsert,
286 yield_clause,
287 }))
288 }
289
290 fn parse_update_vertex(&mut self, ctx: &mut ParseContext) -> Result<UpdateTarget, ParseError> {
291 let vid = self.parse_expression(ctx)?;
292 Ok(UpdateTarget::Vertex(vid))
293 }
294
295 fn parse_update_edge(&mut self, ctx: &mut ParseContext) -> Result<UpdateTarget, ParseError> {
296 ctx.with_edge_syntax_mode(|ctx| {
300 let is_upsert = ctx.is_upsert_mode();
304 if is_upsert || ctx.check_token(TokenKind::Of) == false {
307 let src = if ctx.check_token(TokenKind::Arrow) {
310 return Err(ParseError::new(
312 ParseErrorKind::UnexpectedToken,
313 "Expected edge source expression before ->".to_string(),
314 ctx.current_position(),
315 ));
316 } else {
317 self.parse_expression(ctx)?
318 };
319 ctx.expect_token(TokenKind::Arrow)?;
320 let dst = self.parse_expression(ctx)?;
321
322 let rank = if ctx.match_token(TokenKind::At) {
323 Some(self.parse_expression(ctx)?)
324 } else {
325 None
326 };
327
328 ctx.expect_token(TokenKind::Of)?;
329 let edge_type = Some(ctx.expect_identifier()?);
330
331 Ok(UpdateTarget::Edge {
332 edge_type,
333 src,
334 dst,
335 rank,
336 })
337 } else {
338 ctx.expect_token(TokenKind::Of)?;
340
341 let edge_type = ctx.expect_identifier()?;
343
344 ctx.expect_token(TokenKind::From)?;
346 let src = self.parse_expression(ctx)?;
347
348 ctx.expect_token(TokenKind::To)?;
349 let dst = self.parse_expression(ctx)?;
350
351 let rank = if ctx.match_token(TokenKind::At) {
353 Some(self.parse_expression(ctx)?)
354 } else {
355 None
356 };
357
358 Ok(UpdateTarget::Edge {
359 edge_type: Some(edge_type),
360 src,
361 dst,
362 rank,
363 })
364 }
365 })
366 }
367
368 fn parse_update_edge_short(
371 &mut self,
372 ctx: &mut ParseContext,
373 src: ContextualExpression,
374 ) -> Result<UpdateTarget, ParseError> {
375 use crate::parser::ast::stmt::UpdateTarget;
376
377 ctx.with_edge_syntax_mode(|ctx| {
378 ctx.expect_token(TokenKind::Arrow)?;
380
381 let dst = self.parse_expression(ctx)?;
383
384 let rank = if ctx.match_token(TokenKind::At) {
386 Some(self.parse_expression(ctx)?)
387 } else {
388 None
389 };
390
391 ctx.expect_token(TokenKind::Of)?;
393 let edge_type = Some(ctx.expect_identifier()?);
394
395 Ok(UpdateTarget::Edge {
396 edge_type,
397 src,
398 dst,
399 rank,
400 })
401 })
402 }
403}