1use crate::ast::ddl::{
2 ColumnConstraint, ColumnDef, CreateIndex, CreateTable, DataType, DropIndex, DropTable,
3 IndexMethod, IndexOption, TableConstraint, VectorMetric,
4};
5use crate::ast::span::{Span, Spanned};
6use crate::error::{ParserError, Result};
7use crate::tokenizer::keyword::Keyword;
8use crate::tokenizer::token::{Token, Word};
9
10use super::Parser;
11
12impl<'a> Parser<'a> {
13 pub fn parse_create_table(&mut self) -> Result<CreateTable> {
14 let start_span = self.expect_keyword("CREATE", Keyword::CREATE)?;
15 self.expect_keyword("TABLE", Keyword::TABLE)?;
16 let if_not_exists = if self.consume_keyword(Keyword::IF) {
17 self.expect_keyword("NOT", Keyword::NOT)?;
18 self.expect_keyword("EXISTS", Keyword::EXISTS)?;
19 true
20 } else {
21 false
22 };
23
24 let (name, _name_span) = self.parse_identifier()?;
25 self.expect_token("'('", |t| matches!(t, Token::LParen))?;
26
27 let mut columns = Vec::new();
28 let mut constraints = Vec::new();
29
30 loop {
31 if self.consume_keyword(Keyword::PRIMARY) {
32 self.expect_keyword("KEY", Keyword::KEY)?;
33 self.expect_token("'('", |t| matches!(t, Token::LParen))?;
34 let mut cols = Vec::new();
35 loop {
36 let (col, _) = self.parse_identifier()?;
37 cols.push(col);
38 if matches!(self.peek().token, Token::Comma) {
39 self.advance();
40 continue;
41 }
42 break;
43 }
44 let pk_end = self
45 .expect_token("')'", |t| matches!(t, Token::RParen))?
46 .span;
47 constraints.push(TableConstraint::PrimaryKey {
48 columns: cols,
49 span: start_span.union(&pk_end),
50 });
51 } else {
52 let (col_name, col_span) = self.parse_identifier()?;
53 let (data_type, dt_span) = self.parse_data_type()?;
54 let mut col_constraints = Vec::new();
55 while let Token::Word(Word { keyword, .. }) = &self.peek().token {
56 let constraint = match keyword {
57 Keyword::NOT => {
58 let start = self.peek().span;
59 self.advance();
60 self.expect_keyword("NULL", Keyword::NULL)?;
61 ColumnConstraint::WithSpan {
62 kind: Box::new(ColumnConstraint::NotNull),
63 span: start.union(&self.prev().unwrap().span),
64 }
65 }
66 Keyword::NULL => {
67 let s = self.advance().span;
68 ColumnConstraint::WithSpan {
69 kind: Box::new(ColumnConstraint::Null),
70 span: s,
71 }
72 }
73 Keyword::PRIMARY => {
74 let start = self.advance().span;
75 self.expect_keyword("KEY", Keyword::KEY)?;
76 ColumnConstraint::WithSpan {
77 kind: Box::new(ColumnConstraint::PrimaryKey),
78 span: start.union(&self.prev().unwrap().span),
79 }
80 }
81 Keyword::UNIQUE => {
82 let s = self.advance().span;
83 ColumnConstraint::WithSpan {
84 kind: Box::new(ColumnConstraint::Unique),
85 span: s,
86 }
87 }
88 Keyword::DEFAULT => {
89 let start = self.advance().span;
90 let expr = self.parse_expr()?;
91 let span = start.union(&expr.span());
92 ColumnConstraint::WithSpan {
93 kind: Box::new(ColumnConstraint::Default(expr)),
94 span,
95 }
96 }
97 _ => break,
98 };
99 col_constraints.push(constraint);
100 }
101
102 let end_span = if let Some(last) = col_constraints.last() {
103 last.span()
104 } else {
105 dt_span
106 };
107
108 columns.push(ColumnDef {
109 name: col_name,
110 data_type,
111 constraints: col_constraints,
112 span: col_span.union(&end_span),
113 });
114 }
115
116 if matches!(self.peek().token, Token::Comma) {
117 self.advance();
118 continue;
119 }
120 break;
121 }
122
123 let end_span = self
124 .expect_token("')'", |t| matches!(t, Token::RParen))?
125 .span;
126
127 let mut with_options = Vec::new();
129 let mut span = start_span.union(&end_span);
130 if self.consume_keyword(Keyword::WITH) {
131 let with_start = self
132 .expect_token("'('", |t| matches!(t, Token::LParen))?
133 .span;
134 loop {
135 let (key, key_span) = self.parse_identifier()?;
136 self.expect_token("'='", |t| matches!(t, Token::Eq))?;
137 let val_tok = self.expect_token("option value", |t| {
138 matches!(
139 t,
140 Token::Number(_) | Token::Word(_) | Token::SingleQuotedString(_)
141 )
142 })?;
143 let value = match val_tok.token {
144 Token::Number(n) => n,
145 Token::Word(Word { value, .. }) => value,
146 Token::SingleQuotedString(s) => s,
147 _ => unreachable!(),
148 };
149 let _span = key_span.union(&val_tok.span);
150 with_options.push((key, value));
151
152 if matches!(self.peek().token, Token::Comma) {
153 self.advance();
154 continue;
155 }
156 break;
157 }
158 let with_end = self
159 .expect_token("')'", |t| matches!(t, Token::RParen))?
160 .span;
161 span = span.union(&with_start).union(&with_end);
162 }
163
164 Ok(CreateTable {
165 if_not_exists,
166 name,
167 columns,
168 constraints,
169 with_options,
170 span,
171 })
172 }
173
174 pub fn parse_drop_table(&mut self) -> Result<DropTable> {
175 let start_span = self.expect_keyword("DROP", Keyword::DROP)?;
176 self.expect_keyword("TABLE", Keyword::TABLE)?;
177 let if_exists = if self.consume_keyword(Keyword::IF) {
178 self.expect_keyword("EXISTS", Keyword::EXISTS)?;
179 true
180 } else {
181 false
182 };
183 let (name, name_span) = self.parse_identifier()?;
184 let span = start_span.union(&name_span);
185 Ok(DropTable {
186 if_exists,
187 name,
188 span,
189 })
190 }
191
192 pub fn parse_create_index(&mut self) -> Result<CreateIndex> {
193 let start_span = self.expect_keyword("CREATE", Keyword::CREATE)?;
194 self.expect_keyword("INDEX", Keyword::INDEX)?;
195 let if_not_exists = if self.consume_keyword(Keyword::IF) {
196 self.expect_keyword("NOT", Keyword::NOT)?;
197 self.expect_keyword("EXISTS", Keyword::EXISTS)?;
198 true
199 } else {
200 false
201 };
202
203 let (name, _name_span) = self.parse_identifier()?;
204 self.expect_keyword("ON", Keyword::ON)?;
205 let (table, _table_span) = self.parse_identifier()?;
206 self.expect_token("'('", |t| matches!(t, Token::LParen))?;
207 let (column, _col_span) = self.parse_identifier()?;
208 let end_paren = self
209 .expect_token("')'", |t| matches!(t, Token::RParen))?
210 .span;
211
212 let mut method = None;
213 if self.consume_keyword(Keyword::USING) {
214 let meth = self
215 .expect_keyword("index method", Keyword::HNSW)
216 .or_else(|_| self.expect_keyword("index method", Keyword::BTREE))?;
217 method = Some(match self.prev().unwrap().token {
218 Token::Word(Word {
219 keyword: Keyword::HNSW,
220 ..
221 }) => IndexMethod::Hnsw,
222 _ => IndexMethod::BTree,
223 });
224 let _ = meth;
226 }
227
228 let mut options = Vec::new();
229 if self.consume_keyword(Keyword::WITH) {
230 self.expect_token("'('", |t| matches!(t, Token::LParen))?;
231 loop {
232 let (key, key_span) = self.parse_identifier()?;
233 self.expect_token("'='", |t| matches!(t, Token::Eq))?;
234 let val_tok = self.expect_token("option value", |t| {
235 matches!(
236 t,
237 Token::Number(_) | Token::Word(_) | Token::SingleQuotedString(_)
238 )
239 })?;
240 let value = match val_tok.token {
241 Token::Number(n) => n,
242 Token::Word(Word { value, .. }) => value,
243 Token::SingleQuotedString(s) => s,
244 _ => unreachable!(),
245 };
246 let span = key_span.union(&val_tok.span);
247 options.push(IndexOption { key, value, span });
248
249 if matches!(self.peek().token, Token::Comma) {
250 self.advance();
251 continue;
252 }
253 break;
254 }
255 let _ = self.expect_token("')'", |t| matches!(t, Token::RParen))?;
256 }
257
258 let span = start_span.union(&end_paren);
259 Ok(CreateIndex {
260 if_not_exists,
261 name,
262 table,
263 column,
264 method,
265 options,
266 span,
267 })
268 }
269
270 pub fn parse_drop_index(&mut self) -> Result<DropIndex> {
271 let start_span = self.expect_keyword("DROP", Keyword::DROP)?;
272 self.expect_keyword("INDEX", Keyword::INDEX)?;
273 let if_exists = if self.consume_keyword(Keyword::IF) {
274 self.expect_keyword("EXISTS", Keyword::EXISTS)?;
275 true
276 } else {
277 false
278 };
279 let (name, name_span) = self.parse_identifier()?;
280 let span = start_span.union(&name_span);
281 Ok(DropIndex {
282 if_exists,
283 name,
284 span,
285 })
286 }
287
288 fn parse_data_type(&mut self) -> Result<(DataType, Span)> {
289 let tok = self.peek().clone();
290 let (dtype, end_span) = match &tok.token {
291 Token::Word(Word { keyword, .. }) => match keyword {
292 Keyword::INTEGER => {
293 self.advance();
294 (DataType::Integer, tok.span)
295 }
296 Keyword::INT => {
297 self.advance();
298 (DataType::Int, tok.span)
299 }
300 Keyword::BIGINT => {
301 self.advance();
302 (DataType::BigInt, tok.span)
303 }
304 Keyword::FLOAT => {
305 self.advance();
306 (DataType::Float, tok.span)
307 }
308 Keyword::DOUBLE => {
309 self.advance();
310 (DataType::Double, tok.span)
311 }
312 Keyword::TEXT => {
313 self.advance();
314 (DataType::Text, tok.span)
315 }
316 Keyword::BLOB => {
317 self.advance();
318 (DataType::Blob, tok.span)
319 }
320 Keyword::BOOLEAN => {
321 self.advance();
322 (DataType::Boolean, tok.span)
323 }
324 Keyword::BOOL => {
325 self.advance();
326 (DataType::Bool, tok.span)
327 }
328 Keyword::TIMESTAMP => {
329 self.advance();
330 (DataType::Timestamp, tok.span)
331 }
332 Keyword::VECTOR => {
333 self.advance();
334 self.expect_token("'('", |t| matches!(t, Token::LParen))?;
335 let dim_tok =
336 self.expect_token("dimension", |t| matches!(t, Token::Number(_)))?;
337 let dimension: u32 = match dim_tok.token {
338 Token::Number(ref n) => {
339 n.parse().map_err(|_| ParserError::InvalidVector {
340 line: dim_tok.span.start.line,
341 column: dim_tok.span.start.column,
342 })?
343 }
344 _ => unreachable!(),
345 };
346 let mut metric = None;
347 let mut last_span = dim_tok.span;
348 if matches!(self.peek().token, Token::Comma) {
349 self.advance();
350 let m_tok = self.expect_token("metric", |t| {
351 matches!(
352 t,
353 Token::Word(Word {
354 keyword: Keyword::COSINE | Keyword::L2 | Keyword::INNER,
355 ..
356 })
357 )
358 })?;
359 metric = Some(match m_tok.token {
360 Token::Word(Word {
361 keyword: Keyword::COSINE,
362 ..
363 }) => VectorMetric::Cosine,
364 Token::Word(Word {
365 keyword: Keyword::L2,
366 ..
367 }) => VectorMetric::L2,
368 _ => VectorMetric::Inner,
369 });
370 last_span = m_tok.span;
371 }
372 let end = self
373 .expect_token("')'", |t| matches!(t, Token::RParen))?
374 .span;
375 let span = tok.span.union(&end);
376 (
377 DataType::Vector { dimension, metric },
378 span.union(&last_span),
379 )
380 }
381 _ => {
382 return Err(ParserError::UnexpectedToken {
383 line: tok.span.start.line,
384 column: tok.span.start.column,
385 expected: "data type".into(),
386 found: format!("{:?}", tok.token),
387 });
388 }
389 },
390 _ => {
391 return Err(ParserError::UnexpectedToken {
392 line: tok.span.start.line,
393 column: tok.span.start.column,
394 expected: "data type".into(),
395 found: format!("{:?}", tok.token),
396 });
397 }
398 };
399
400 Ok((dtype, end_span))
401 }
402}