linkrs_query/parser/parsing/ddl_parser/
alter_parser.rs1use crate::parser::ast::stmt::*;
2
3use crate::parser::core::error::{ParseError, ParseErrorKind};
4use crate::parser::parsing::parse_context::ParseContext;
5use crate::parser::TokenKind;
6
7use super::DdlParser;
8
9type AlterOpsResult = (
10 Vec<linkrs_core::types::PropertyDef>,
11 Vec<String>,
12 Vec<PropertyChange>,
13 Option<String>,
14);
15
16impl DdlParser {
17 pub fn parse_alter_statement(&mut self, ctx: &mut ParseContext) -> Result<Stmt, ParseError> {
18 let start_span = ctx.current_span();
19 ctx.expect_token(TokenKind::Alter)?;
20
21 if ctx.check_keyword("FULLTEXT") {
22 return crate::parser::parsing::fulltext_parser::parse_alter_fulltext_index_after_alter(
23 ctx,
24 );
25 }
26
27 if ctx.check_token(TokenKind::User) {
28 return crate::parser::parsing::user_parser::UserParser::new()
29 .parse_alter_user_internal(ctx, start_span);
30 }
31
32 if ctx.match_token(TokenKind::Sequence) {
33 let name = ctx.expect_identifier()?;
34 let mut increment = None;
35 let mut min_value = None;
36 let mut max_value = None;
37 let mut cycle = None;
38
39 loop {
40 if ctx.check_keyword("INCREMENT") && increment.is_none() {
41 ctx.next_token();
42 ctx.expect_token(TokenKind::Assign)?;
43 increment = Some(ctx.expect_integer_literal()?);
44 } else if ctx.check_keyword("MINVALUE") && min_value.is_none() {
45 ctx.next_token();
46 ctx.expect_token(TokenKind::Assign)?;
47 min_value = Some(ctx.expect_integer_literal()?);
48 } else if ctx.check_keyword("MAXVALUE") && max_value.is_none() {
49 ctx.next_token();
50 ctx.expect_token(TokenKind::Assign)?;
51 max_value = Some(ctx.expect_integer_literal()?);
52 } else if ctx.match_token(TokenKind::Cycle) {
53 cycle = Some(true);
54 } else if ctx.check_keyword("NOCYCLE") {
55 ctx.next_token();
56 cycle = Some(false);
57 } else {
58 break;
59 }
60 }
61
62 let span = ctx.span_since(start_span.start);
63 return Ok(Stmt::Alter(AlterStmt {
64 span,
65 target: AlterTarget::Sequence {
66 name,
67 increment,
68 min_value,
69 max_value,
70 cycle,
71 },
72 }));
73 }
74
75 let (is_tag, name) = if ctx.match_token(TokenKind::Tag) {
76 (true, ctx.expect_identifier()?)
77 } else if ctx.match_token(TokenKind::Edge) {
78 (false, ctx.expect_identifier()?)
79 } else {
80 return Err(ParseError::new(
81 ParseErrorKind::UnexpectedToken,
82 "Expected TAG, EDGE, SEQUENCE, or USER".to_string(),
83 ctx.current_position(),
84 ));
85 };
86
87 if ctx.match_token(TokenKind::Rename) {
88 ctx.expect_token(TokenKind::To)?;
89 let new_name = ctx.expect_identifier()?;
90 let span = ctx.span_since(start_span.start);
91 return Ok(Stmt::Alter(AlterStmt {
92 span,
93 target: if is_tag {
94 AlterTarget::RenameTag {
95 old_name: name,
96 new_name,
97 }
98 } else {
99 AlterTarget::RenameEdge {
100 old_name: name,
101 new_name,
102 }
103 },
104 }));
105 }
106
107 if !is_tag
111 && matches!(ctx.current_token().kind, TokenKind::Add | TokenKind::Drop)
112 && matches!(ctx.peek_token().kind, TokenKind::From)
113 {
114 let is_add = matches!(ctx.current_token().kind, TokenKind::Add);
115 ctx.next_token(); ctx.next_token(); let src_tag = ctx.expect_identifier()?;
118 ctx.expect_token(TokenKind::To)?;
119 let dst_tag = ctx.expect_identifier()?;
120 let span = ctx.span_since(start_span.start);
121 let target = if is_add {
122 AlterTarget::AddFrom {
123 edge_name: name,
124 src_tag,
125 dst_tag,
126 }
127 } else {
128 AlterTarget::DropFrom {
129 edge_name: name,
130 src_tag,
131 dst_tag,
132 }
133 };
134 return Ok(Stmt::Alter(AlterStmt { span, target }));
135 }
136
137 let (additions, deletions, changes, new_comment) = self.parse_alter_operations(ctx)?;
138 if additions.is_empty()
139 && deletions.is_empty()
140 && changes.is_empty()
141 && new_comment.is_none()
142 {
143 return Err(ParseError::new(
144 ParseErrorKind::SyntaxError,
145 "ALTER TAG/EDGE requires ADD, DROP, CHANGE, or COMMENT".to_string(),
146 ctx.current_position(),
147 ));
148 }
149
150 let span = ctx.span_since(start_span.start);
151 if is_tag {
152 Ok(Stmt::Alter(AlterStmt {
153 span,
154 target: AlterTarget::Tag {
155 tag_name: name,
156 additions,
157 deletions,
158 changes,
159 new_comment,
160 },
161 }))
162 } else {
163 Ok(Stmt::Alter(AlterStmt {
164 span,
165 target: AlterTarget::Edge {
166 edge_name: name,
167 additions,
168 deletions,
169 changes,
170 new_comment,
171 },
172 }))
173 }
174 }
175
176 fn parse_alter_operations(
177 &mut self,
178 ctx: &mut ParseContext,
179 ) -> Result<AlterOpsResult, ParseError> {
180 let mut additions = Vec::new();
181 let mut deletions = Vec::new();
182 let mut changes = Vec::new();
183 let mut new_comment: Option<String> = None;
184
185 loop {
186 if ctx.match_token(TokenKind::Add) {
187 additions.extend(self.parse_property_defs(ctx)?);
188 } else if ctx.match_token(TokenKind::Drop) {
189 ctx.expect_token(TokenKind::LParen)?;
190 loop {
191 deletions.push(ctx.expect_identifier()?);
192 if !ctx.match_token(TokenKind::Comma) {
193 break;
194 }
195 }
196 ctx.expect_token(TokenKind::RParen)?;
197 } else if ctx.match_token(TokenKind::Change) {
198 ctx.expect_token(TokenKind::LParen)?;
199 loop {
200 let old_name = ctx.expect_identifier()?;
201 let new_name = ctx.expect_identifier()?;
202 ctx.expect_token(TokenKind::Colon)?;
203 let data_type = self.parse_data_type(ctx)?;
204 changes.push(PropertyChange {
205 old_name,
206 new_name,
207 data_type,
208 });
209 if !ctx.match_token(TokenKind::Comma) {
210 break;
211 }
212 }
213 ctx.expect_token(TokenKind::RParen)?;
214 } else if ctx.match_token(TokenKind::Comment) {
215 if new_comment.is_some() {
216 return Err(ParseError::new(
217 ParseErrorKind::SyntaxError,
218 "duplicate COMMENT clause".to_string(),
219 ctx.current_position(),
220 ));
221 }
222 ctx.expect_token(TokenKind::Assign)?;
223 new_comment = Some(ctx.expect_string_literal()?);
224 } else {
225 break;
226 }
227 }
228
229 Ok((additions, deletions, changes, new_comment))
230 }
231}