Skip to main content

linkrs_query/parser/parsing/dml_parser/
delete.rs

1use super::*;
2
3impl DmlParser {
4    /// Analysis of the DELETE statement
5    pub fn parse_delete_statement(&mut self, ctx: &mut ParseContext) -> Result<Stmt, ParseError> {
6        use crate::parser::ast::stmt::{DeleteStmt, DeleteTarget};
7
8        // `->` is an edge arrow inside this statement, not the JSON access
9        // operator, so expression parsing must not treat `-> 'key'` as a
10        // postfix JSON get.
11        ctx.with_edge_syntax_mode(|ctx| {
12            let start_span = ctx.current_span();
13
14            // Support DETACH DELETE syntax: DETACH DELETE ...
15            let detach = ctx.match_token(TokenKind::Detach);
16
17            ctx.expect_token(TokenKind::Delete)?;
18
19            // Check whether there are any keywords such as VERTEX, EDGE, or TAG.
20            let target = if ctx.match_token(TokenKind::Vertex) {
21                // DELETE VERTEX <tag> FROM vid [, vid ...]
22                let tag = ctx.expect_identifier()?;
23                ctx.expect_token(TokenKind::From)?;
24                let mut vids = vec![];
25                loop {
26                    vids.push(self.parse_expression(ctx)?);
27                    if !ctx.match_token(TokenKind::Comma) {
28                        break;
29                    }
30                }
31                DeleteTarget::Vertices { tag, vids }
32            } else if ctx.match_token(TokenKind::Edge) {
33                // Two syntaxes:
34                // 1) DELETE EDGE <edge_type> <src> -> <dst> [@rank] [, ...]
35                // 2) DELETE EDGE <src> -> <dst> [@rank] OF <edge_type> [, ...]
36                // Disambiguate by syntax, not by whether the first token is a literal.
37                // Short form starts with an endpoint expression immediately followed by `->`.
38                // Long form starts with the edge type, then `source -> destination`.
39                let first = self.parse_expression(ctx)?;
40                let (edge_type, edges) = if ctx.check_token(TokenKind::Arrow) {
41                    // Short form: <src> -> <dst> [@rank] [, ...] OF <edge_type>
42                    let mut edges = vec![];
43                    let mut current_src = first;
44                    loop {
45                        ctx.expect_token(TokenKind::Arrow)?;
46                        let dst = self.parse_expression(ctx)?;
47
48                        let rank = if ctx.match_token(TokenKind::At) {
49                            Some(self.parse_expression(ctx)?)
50                        } else {
51                            None
52                        };
53
54                        edges.push((current_src.clone(), dst, rank));
55
56                        if !ctx.match_token(TokenKind::Comma) {
57                            break;
58                        }
59                        current_src = self.parse_expression(ctx)?;
60                    }
61                    ctx.expect_token(TokenKind::Of)?;
62                    let type_name = ctx.expect_identifier()?;
63                    (Some(type_name), edges)
64                } else {
65                    // Long form: <edge_type> <src> -> <dst> [@rank] [, ...]
66                    let type_name = match first.expression().map(|meta| meta.inner().clone()) {
67                        Some(linkrs_core::types::Expression::Variable(name)) => name,
68                        Some(linkrs_core::types::Expression::Literal(
69                            linkrs_core::Value::FixedString(s),
70                        )) => s.to_string(),
71                        Some(linkrs_core::types::Expression::Literal(
72                            linkrs_core::Value::String(s),
73                        )) => s.to_string(),
74                        _ => {
75                            return Err(ParseError::new(
76                                ParseErrorKind::UnexpectedToken,
77                                "Expected edge type name before source expression".to_string(),
78                                ctx.current_position(),
79                            ));
80                        }
81                    };
82                    let edge_type = Some(type_name);
83
84                    let mut edges = vec![];
85                    loop {
86                        let src = self.parse_expression(ctx)?;
87                        ctx.expect_token(TokenKind::Arrow)?;
88                        let dst = self.parse_expression(ctx)?;
89
90                        let rank = if ctx.match_token(TokenKind::At) {
91                            Some(self.parse_expression(ctx)?)
92                        } else {
93                            None
94                        };
95
96                        edges.push((src, dst, rank));
97
98                        if !ctx.match_token(TokenKind::Comma) {
99                            break;
100                        }
101                    }
102                    (edge_type, edges)
103                };
104
105                DeleteTarget::Edges { edge_type, edges }
106            } else {
107                return Err(ParseError::new(
108                    crate::parser::core::error::ParseErrorKind::UnexpectedToken,
109                    "DELETE VERTEX requires a tag qualifier: DELETE VERTEX <tag> FROM <vid>, ..."
110                        .to_string(),
111                    ctx.current_position(),
112                ));
113            };
114
115            let with_edge = if ctx.match_token(TokenKind::With) {
116                ctx.expect_token(TokenKind::Edge)?;
117                true
118            } else {
119                false
120            };
121
122            let span = ctx.span_since(start_span.start);
123
124            Ok(Stmt::Delete(DeleteStmt {
125                span,
126                target,
127                with_edge,
128                detach,
129            }))
130        })
131    }
132}