1use super::super::ast::{
4 AskQuery, DeleteQuery, Expr, Filter, InsertEntityType, InsertQuery, QueryExpr, ReturningItem,
5 UpdateQuery,
6};
7use super::super::lexer::Token;
8use super::error::ParseError;
9use super::Parser;
10use crate::storage::query::sql_lowering::{filter_to_expr, fold_expr_to_value};
11use crate::storage::schema::Value;
12
13pub(crate) const JSON_LITERAL_MAX_DEPTH: u32 = 128;
17
18pub(crate) fn json_literal_depth_check(
22 value: &crate::utils::json::JsonValue,
23) -> Result<(), String> {
24 use crate::utils::json::JsonValue;
25 let mut stack: Vec<(&JsonValue, u32)> = vec![(value, 1)];
26 while let Some((node, depth)) = stack.pop() {
27 if depth > JSON_LITERAL_MAX_DEPTH {
28 return Err(format!(
29 "JSON object literal exceeds JSON_LITERAL_MAX_DEPTH ({})",
30 JSON_LITERAL_MAX_DEPTH
31 ));
32 }
33 match node {
34 JsonValue::Object(entries) => {
35 for (_, v) in entries {
36 stack.push((v, depth + 1));
37 }
38 }
39 JsonValue::Array(items) => {
40 for v in items {
41 stack.push((v, depth + 1));
42 }
43 }
44 _ => {}
45 }
46 }
47 Ok(())
48}
49
50impl<'a> Parser<'a> {
51 pub fn parse_insert_query(&mut self) -> Result<QueryExpr, ParseError> {
53 self.expect(Token::Insert)?;
54 self.expect(Token::Into)?;
55 let table = self.expect_ident()?;
56
57 let entity_type = match self.peek().clone() {
59 Token::Node => {
60 self.advance()?;
61 InsertEntityType::Node
62 }
63 Token::Edge => {
64 self.advance()?;
65 InsertEntityType::Edge
66 }
67 Token::Vector => {
68 self.advance()?;
69 InsertEntityType::Vector
70 }
71 Token::Document => {
72 self.advance()?;
73 InsertEntityType::Document
74 }
75 Token::Kv => {
76 self.advance()?;
77 InsertEntityType::Kv
78 }
79 _ => InsertEntityType::Row,
80 };
81
82 self.expect(Token::LParen)?;
84 let columns = self.parse_ident_list()?;
85 self.expect(Token::RParen)?;
86
87 self.expect(Token::Values)?;
89 let mut all_values = Vec::new();
90 let mut all_value_exprs = Vec::new();
91 loop {
92 self.expect(Token::LParen)?;
93 let row_exprs = self.parse_dml_expr_list()?;
94 self.expect(Token::RParen)?;
95 let row_values = row_exprs
96 .iter()
97 .cloned()
98 .map(fold_expr_to_value)
99 .collect::<Result<Vec<_>, _>>()
100 .map_err(|msg| ParseError::new(msg, self.position()))?;
101 all_value_exprs.push(row_exprs);
102 all_values.push(row_values);
103 if !self.consume(&Token::Comma)? {
104 break;
105 }
106 }
107
108 let (ttl_ms, expires_at_ms, with_metadata, auto_embed) = self.parse_with_clauses()?;
110
111 let returning = self.parse_returning_clause()?;
112
113 let suppress_events = if self.consume_ident_ci("SUPPRESS")? {
114 self.expect_ident_ci("EVENTS")?;
115 true
116 } else {
117 false
118 };
119
120 Ok(QueryExpr::Insert(InsertQuery {
121 table,
122 entity_type,
123 columns,
124 value_exprs: all_value_exprs,
125 values: all_values,
126 returning,
127 ttl_ms,
128 expires_at_ms,
129 with_metadata,
130 auto_embed,
131 suppress_events,
132 }))
133 }
134
135 fn parse_ttl_duration(&mut self) -> Result<u64, ParseError> {
137 let ttl_value = self.parse_float()?;
139 let ttl_unit = match self.peek() {
140 Token::Ident(unit) => {
141 let unit = unit.clone();
142 self.advance()?;
143 unit
144 }
145 _ => "s".to_string(),
146 };
147
148 let multiplier_ms = match ttl_unit.to_ascii_lowercase().as_str() {
149 "ms" | "msec" | "millisecond" | "milliseconds" => 1.0,
150 "s" | "sec" | "secs" | "second" | "seconds" => 1_000.0,
151 "m" | "min" | "mins" | "minute" | "minutes" => 60_000.0,
152 "h" | "hr" | "hrs" | "hour" | "hours" => 3_600_000.0,
153 "d" | "day" | "days" => 86_400_000.0,
154 other => {
155 return Err(ParseError::new(
156 format!("unsupported TTL unit {other:?}"),
160 self.position(),
161 ));
162 }
163 };
164
165 Ok((ttl_value * multiplier_ms) as u64)
166 }
167
168 pub fn parse_with_clauses(
171 &mut self,
172 ) -> Result<
173 (
174 Option<u64>,
175 Option<u64>,
176 Vec<(String, Value)>,
177 Option<crate::storage::query::ast::AutoEmbedConfig>,
178 ),
179 ParseError,
180 > {
181 let mut ttl_ms = None;
182 let mut expires_at_ms = None;
183 let mut with_metadata = Vec::new();
184 let mut auto_embed = None;
185
186 while self.consume(&Token::With)? {
187 if self.consume_ident_ci("TTL")? {
188 ttl_ms = Some(self.parse_ttl_duration()?);
189 } else if self.consume_ident_ci("EXPIRES")? {
190 self.expect_ident_ci("AT")?;
191 let ts = self.parse_expires_at_value()?;
192 expires_at_ms = Some(ts);
193 } else if self.consume(&Token::Metadata)? || self.consume_ident_ci("METADATA")? {
194 with_metadata = self.parse_with_metadata_pairs()?;
195 } else if self.consume_ident_ci("AUTO")? {
196 self.consume_ident_ci("EMBED")?;
198 self.expect(Token::LParen)?;
199 let mut fields = Vec::new();
200 loop {
201 fields.push(self.expect_ident()?);
202 if !self.consume(&Token::Comma)? {
203 break;
204 }
205 }
206 self.expect(Token::RParen)?;
207 let provider = if self.consume(&Token::Using)? {
212 self.expect_ident()?
213 } else {
214 "openai".to_string()
215 };
216 let model = if self.consume_ident_ci("MODEL")? {
217 Some(self.parse_string()?)
218 } else {
219 None
220 };
221 auto_embed = Some(crate::storage::query::ast::AutoEmbedConfig {
222 fields,
223 provider,
224 model,
225 });
226 } else {
227 return Err(ParseError::expected(
228 vec!["TTL", "EXPIRES AT", "METADATA", "AUTO EMBED"],
229 self.peek(),
230 self.position(),
231 ));
232 }
233 }
234
235 Ok((ttl_ms, expires_at_ms, with_metadata, auto_embed))
236 }
237
238 fn expect_ident_ci(&mut self, expected: &str) -> Result<(), ParseError> {
240 if self.consume_ident_ci(expected)? {
241 Ok(())
242 } else {
243 Err(ParseError::expected(
244 vec![expected],
245 self.peek(),
246 self.position(),
247 ))
248 }
249 }
250
251 fn parse_expires_at_value(&mut self) -> Result<u64, ParseError> {
253 if let Ok(value) = self.parse_integer() {
255 return Ok(value as u64);
256 }
257 if let Ok(text) = self.parse_string() {
259 let trimmed = text.trim();
261 if let Ok(ts) = trimmed.parse::<u64>() {
262 return Ok(ts);
263 }
264 return Err(ParseError::new(
266 format!("EXPIRES AT requires a unix timestamp in milliseconds, got {trimmed:?}"),
270 self.position(),
271 ));
272 }
273 Err(ParseError::expected(
274 vec!["timestamp (unix ms) or 'YYYY-MM-DD'"],
275 self.peek(),
276 self.position(),
277 ))
278 }
279
280 fn parse_with_metadata_pairs(&mut self) -> Result<Vec<(String, Value)>, ParseError> {
282 self.expect(Token::LParen)?;
283 let mut pairs = Vec::new();
284 if !self.check(&Token::RParen) {
285 loop {
286 let key = self.expect_ident_or_keyword()?.to_ascii_lowercase();
287 self.expect(Token::Eq)?;
288 let value = self.parse_literal_value()?;
289 pairs.push((key, value));
290 if !self.consume(&Token::Comma)? {
291 break;
292 }
293 }
294 }
295 self.expect(Token::RParen)?;
296 Ok(pairs)
297 }
298
299 pub fn parse_update_query(&mut self) -> Result<QueryExpr, ParseError> {
301 self.expect(Token::Update)?;
302 let table = self.expect_ident()?;
303 self.expect(Token::Set)?;
304
305 let mut assignments = Vec::new();
306 let mut assignment_exprs = Vec::new();
307 loop {
308 let col = self.expect_ident()?;
309 self.expect(Token::Eq)?;
310 let expr = self.parse_expr()?;
311 let folded = fold_expr_to_value(expr.clone()).ok();
312 assignment_exprs.push((col.clone(), expr));
313 if let Some(val) = folded {
314 assignments.push((col.clone(), val));
315 }
316 if !self.consume(&Token::Comma)? {
317 break;
318 }
319 }
320
321 let filter = if self.consume(&Token::Where)? {
322 Some(self.parse_filter()?)
323 } else {
324 None
325 };
326 let where_expr = filter.as_ref().map(filter_to_expr);
327
328 let (ttl_ms, expires_at_ms, with_metadata, _auto_embed) = self.parse_with_clauses()?;
329
330 let limit = if self.consume(&Token::Limit)? {
335 Some(self.parse_integer()? as u64)
336 } else {
337 None
338 };
339
340 let returning = self.parse_returning_clause()?;
341
342 let suppress_events = if self.consume_ident_ci("SUPPRESS")? {
343 self.expect_ident_ci("EVENTS")?;
344 true
345 } else {
346 false
347 };
348
349 Ok(QueryExpr::Update(UpdateQuery {
350 table,
351 assignment_exprs,
352 assignments,
353 where_expr,
354 filter,
355 ttl_ms,
356 expires_at_ms,
357 with_metadata,
358 returning,
359 limit,
360 suppress_events,
361 }))
362 }
363
364 pub fn parse_delete_query(&mut self) -> Result<QueryExpr, ParseError> {
366 self.expect(Token::Delete)?;
367 self.expect(Token::From)?;
368 let table = self.expect_ident()?;
369
370 let filter = if self.consume(&Token::Where)? {
371 Some(self.parse_filter()?)
372 } else {
373 None
374 };
375
376 let where_expr = filter.as_ref().map(filter_to_expr);
377
378 let returning = self.parse_returning_clause()?;
379
380 let suppress_events = if self.consume_ident_ci("SUPPRESS")? {
381 self.expect_ident_ci("EVENTS")?;
382 true
383 } else {
384 false
385 };
386
387 Ok(QueryExpr::Delete(DeleteQuery {
388 table,
389 where_expr,
390 filter,
391 returning,
392 suppress_events,
393 }))
394 }
395
396 fn parse_returning_clause(&mut self) -> Result<Option<Vec<ReturningItem>>, ParseError> {
400 if !self.consume(&Token::Returning)? {
401 return Ok(None);
402 }
403 if self.consume(&Token::Star)? {
404 return Ok(Some(vec![ReturningItem::All]));
405 }
406 let mut items = Vec::new();
407 loop {
408 let col = self.expect_ident_or_keyword()?;
409 items.push(ReturningItem::Column(col));
410 if !self.consume(&Token::Comma)? {
411 break;
412 }
413 }
414 if items.is_empty() {
415 return Err(ParseError::expected(
416 vec!["*", "column name"],
417 self.peek(),
418 self.position(),
419 ));
420 }
421 Ok(Some(items))
422 }
423
424 pub fn parse_ask_query(&mut self) -> Result<QueryExpr, ParseError> {
426 self.advance()?; let question = self.parse_string()?;
429
430 let mut provider = None;
431 let mut model = None;
432 let mut depth = None;
433 let mut limit = None;
434 let mut collection = None;
435
436 for _ in 0..5 {
438 if self.consume(&Token::Using)? {
439 provider = Some(self.expect_ident()?);
440 } else if self.consume_ident_ci("MODEL")? {
441 model = Some(self.parse_string()?);
442 } else if self.consume(&Token::Depth)? {
443 depth = Some(self.parse_integer()? as usize);
444 } else if self.consume(&Token::Limit)? {
445 limit = Some(self.parse_integer()? as usize);
446 } else if self.consume(&Token::Collection)? {
447 collection = Some(self.expect_ident()?);
448 } else {
449 break;
450 }
451 }
452
453 Ok(QueryExpr::Ask(AskQuery {
454 question,
455 provider,
456 model,
457 depth,
458 limit,
459 collection,
460 }))
461 }
462
463 fn parse_ident_list(&mut self) -> Result<Vec<String>, ParseError> {
465 let mut idents = Vec::new();
466 loop {
467 idents.push(self.expect_ident_or_keyword()?);
468 if !self.consume(&Token::Comma)? {
469 break;
470 }
471 }
472 Ok(idents)
473 }
474
475 fn parse_dml_value_list(&mut self) -> Result<Vec<Value>, ParseError> {
477 self.parse_dml_expr_list()?
478 .into_iter()
479 .map(fold_expr_to_value)
480 .collect::<Result<Vec<_>, _>>()
481 .map_err(|msg| ParseError::new(msg, self.position()))
482 }
483
484 fn parse_dml_expr_list(&mut self) -> Result<Vec<Expr>, ParseError> {
485 let mut values = Vec::new();
486 loop {
487 values.push(self.parse_expr()?);
488 if !self.consume(&Token::Comma)? {
489 break;
490 }
491 }
492 Ok(values)
493 }
494
495 pub(crate) fn parse_literal_value(&mut self) -> Result<Value, ParseError> {
497 self.enter_depth()?;
506 let result = self.parse_literal_value_inner();
507 self.exit_depth();
508 result
509 }
510
511 fn parse_literal_value_inner(&mut self) -> Result<Value, ParseError> {
512 if let Token::Ident(name) = self.peek().clone() {
519 let upper = name.to_uppercase();
520 if upper == "PASSWORD" || upper == "SECRET" {
521 self.advance()?; self.expect(Token::LParen)?;
523 let plaintext = self.parse_string()?;
524 self.expect(Token::RParen)?;
525 return Ok(match upper.as_str() {
526 "PASSWORD" => Value::Password(format!("@@plain@@{plaintext}")),
527 "SECRET" => Value::Secret(format!("@@plain@@{plaintext}").into_bytes()),
528 _ => unreachable!(),
529 });
530 }
531 if upper == "SECRET_REF" {
532 self.advance()?; self.expect(Token::LParen)?;
534 let store = self.expect_ident_or_keyword()?.to_ascii_lowercase();
535 if store != "vault" {
536 return Err(ParseError::expected(
537 vec!["vault"],
538 self.peek(),
539 self.position(),
540 ));
541 }
542 self.expect(Token::Comma)?;
543 let (collection, key) =
544 self.parse_kv_key(crate::catalog::CollectionModel::Vault)?;
545 self.expect(Token::RParen)?;
546 return Ok(secret_ref_value(&store, &collection, &key));
547 }
548 }
549
550 match self.peek().clone() {
551 Token::String(s) => {
552 let s = s.clone();
553 self.advance()?;
554 Ok(Value::text(s))
555 }
556 Token::JsonLiteral(raw) => {
557 self.advance()?;
562 let json_value = crate::utils::json::parse_json(&raw).map_err(|err| {
563 ParseError::new(
564 format!("invalid JSON object literal: {:?}", err.to_string()),
570 self.position(),
571 )
572 })?;
573 json_literal_depth_check(&json_value)
574 .map_err(|err| ParseError::new(err, self.position()))?;
575 let canonical = crate::serde_json::Value::from(json_value);
576 let bytes = crate::json::to_vec(&canonical).map_err(|err| {
577 ParseError::new(
578 format!("failed to encode JSON literal: {:?}", err.to_string()),
582 self.position(),
583 )
584 })?;
585 Ok(Value::Json(bytes))
586 }
587 Token::Integer(n) => {
588 self.advance()?;
589 Ok(Value::Integer(n))
590 }
591 Token::Float(n) => {
592 self.advance()?;
593 Ok(Value::Float(n))
594 }
595 Token::True => {
596 self.advance()?;
597 Ok(Value::Boolean(true))
598 }
599 Token::False => {
600 self.advance()?;
601 Ok(Value::Boolean(false))
602 }
603 Token::Null => {
604 self.advance()?;
605 Ok(Value::Null)
606 }
607 Token::LBracket => {
608 self.advance()?; let mut items = Vec::new();
612 if !self.check(&Token::RBracket) {
613 loop {
614 items.push(self.parse_literal_value()?);
615 if !self.consume(&Token::Comma)? {
616 break;
617 }
618 }
619 }
620 self.expect(Token::RBracket)?;
621
622 let all_numeric = items
624 .iter()
625 .all(|v| matches!(v, Value::Integer(_) | Value::Float(_)));
626 if all_numeric && !items.is_empty() {
627 let floats: Vec<f32> = items
628 .iter()
629 .map(|v| match v {
630 Value::Float(f) => *f as f32,
631 Value::Integer(i) => *i as f32,
632 _ => 0.0,
633 })
634 .collect();
635 Ok(Value::Vector(floats))
636 } else {
637 let json_arr: Vec<crate::json::Value> = items
639 .iter()
640 .map(|v| match v {
641 Value::Null => crate::json::Value::Null,
642 Value::Boolean(b) => crate::json::Value::Bool(*b),
643 Value::Integer(i) => crate::json::Value::Number(*i as f64),
644 Value::Float(f) => crate::json::Value::Number(*f),
645 Value::Text(s) => crate::json::Value::String(s.to_string()),
646 _ => crate::json::Value::Null,
647 })
648 .collect();
649 let json_val = crate::json::Value::Array(json_arr);
650 let bytes = crate::json::to_vec(&json_val).unwrap_or_default();
651 Ok(Value::Json(bytes))
652 }
653 }
654 Token::LBrace => {
655 self.advance()?; let mut map = crate::json::Map::new();
658 if !self.check(&Token::RBrace) {
659 loop {
660 let key = match self.peek().clone() {
667 Token::String(s) => {
668 self.advance()?;
669 s
670 }
671 Token::Ident(s) => {
672 self.advance()?;
673 s
674 }
675 _ => self.expect_ident_or_keyword()?.to_ascii_lowercase(),
676 };
677 if !self.consume(&Token::Colon)? {
679 self.expect(Token::Eq)?;
680 }
681 let val = self.parse_literal_value()?;
683 let json_val = match val {
684 Value::Null => crate::json::Value::Null,
685 Value::Boolean(b) => crate::json::Value::Bool(b),
686 Value::Integer(i) => crate::json::Value::Number(i as f64),
687 Value::Float(f) => crate::json::Value::Number(f),
688 Value::Text(s) => crate::json::Value::String(s.to_string()),
689 Value::Json(ref bytes) => {
690 crate::json::from_slice(bytes).unwrap_or(crate::json::Value::Null)
691 }
692 _ => crate::json::Value::Null,
693 };
694 map.insert(key, json_val);
695 if !self.consume(&Token::Comma)? {
696 break;
697 }
698 }
699 }
700 self.expect(Token::RBrace)?;
701 let json_val = crate::json::Value::Object(map);
702 let bytes = crate::json::to_vec(&json_val).unwrap_or_default();
703 Ok(Value::Json(bytes))
704 }
705 ref other => Err(ParseError::expected(
706 vec!["string", "number", "true", "false", "null", "[", "{"],
707 other,
708 self.position(),
709 )),
710 }
711 }
712}
713
714fn secret_ref_value(store: &str, collection: &str, key: &str) -> Value {
715 let mut map = crate::json::Map::new();
716 map.insert(
717 "type".to_string(),
718 crate::json::Value::String("secret_ref".to_string()),
719 );
720 map.insert(
721 "store".to_string(),
722 crate::json::Value::String(store.to_string()),
723 );
724 map.insert(
725 "collection".to_string(),
726 crate::json::Value::String(collection.to_string()),
727 );
728 map.insert(
729 "key".to_string(),
730 crate::json::Value::String(key.to_string()),
731 );
732 Value::Json(crate::json::to_vec(&crate::json::Value::Object(map)).unwrap_or_default())
733}