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
104 .iter()
105 .cloned()
106 .map(|expr| match fold_expr_to_value(expr.clone()) {
107 Ok(value) => Ok(value),
108 Err(msg) => {
109 if crate::storage::query::user_params::expr_contains_parameter(&expr) {
110 Ok(Value::Null)
111 } else {
112 Err(msg)
113 }
114 }
115 })
116 .collect::<Result<Vec<_>, _>>()
117 .map_err(|msg| ParseError::new(msg, self.position()))?;
118 all_value_exprs.push(row_exprs);
119 all_values.push(row_values);
120 if !self.consume(&Token::Comma)? {
121 break;
122 }
123 }
124
125 let (ttl_ms, expires_at_ms, with_metadata, auto_embed) = self.parse_with_clauses()?;
127
128 let returning = self.parse_returning_clause()?;
129
130 let suppress_events = if self.consume_ident_ci("SUPPRESS")? {
131 self.expect_ident_ci("EVENTS")?;
132 true
133 } else {
134 false
135 };
136
137 Ok(QueryExpr::Insert(InsertQuery {
138 table,
139 entity_type,
140 columns,
141 value_exprs: all_value_exprs,
142 values: all_values,
143 returning,
144 ttl_ms,
145 expires_at_ms,
146 with_metadata,
147 auto_embed,
148 suppress_events,
149 }))
150 }
151
152 fn parse_ttl_duration(&mut self) -> Result<u64, ParseError> {
154 let ttl_value = self.parse_float()?;
156 let ttl_unit = match self.peek() {
157 Token::Ident(unit) => {
158 let unit = unit.clone();
159 self.advance()?;
160 unit
161 }
162 _ => "s".to_string(),
163 };
164
165 let multiplier_ms = match ttl_unit.to_ascii_lowercase().as_str() {
166 "ms" | "msec" | "millisecond" | "milliseconds" => 1.0,
167 "s" | "sec" | "secs" | "second" | "seconds" => 1_000.0,
168 "m" | "min" | "mins" | "minute" | "minutes" => 60_000.0,
169 "h" | "hr" | "hrs" | "hour" | "hours" => 3_600_000.0,
170 "d" | "day" | "days" => 86_400_000.0,
171 other => {
172 return Err(ParseError::new(
173 format!("unsupported TTL unit {other:?}"),
177 self.position(),
178 ));
179 }
180 };
181
182 Ok((ttl_value * multiplier_ms) as u64)
183 }
184
185 pub fn parse_with_clauses(
188 &mut self,
189 ) -> Result<
190 (
191 Option<u64>,
192 Option<u64>,
193 Vec<(String, Value)>,
194 Option<crate::storage::query::ast::AutoEmbedConfig>,
195 ),
196 ParseError,
197 > {
198 let mut ttl_ms = None;
199 let mut expires_at_ms = None;
200 let mut with_metadata = Vec::new();
201 let mut auto_embed = None;
202
203 while self.consume(&Token::With)? {
204 if self.consume_ident_ci("TTL")? {
205 ttl_ms = Some(self.parse_ttl_duration()?);
206 } else if self.consume_ident_ci("EXPIRES")? {
207 self.expect_ident_ci("AT")?;
208 let ts = self.parse_expires_at_value()?;
209 expires_at_ms = Some(ts);
210 } else if self.consume(&Token::Metadata)? || self.consume_ident_ci("METADATA")? {
211 with_metadata = self.parse_with_metadata_pairs()?;
212 } else if self.consume_ident_ci("AUTO")? {
213 self.consume_ident_ci("EMBED")?;
215 self.expect(Token::LParen)?;
216 let mut fields = Vec::new();
217 loop {
218 fields.push(self.expect_ident()?);
219 if !self.consume(&Token::Comma)? {
220 break;
221 }
222 }
223 self.expect(Token::RParen)?;
224 let provider = if self.consume(&Token::Using)? {
229 self.expect_ident()?
230 } else {
231 "openai".to_string()
232 };
233 let model = if self.consume_ident_ci("MODEL")? {
234 Some(self.parse_string()?)
235 } else {
236 None
237 };
238 auto_embed = Some(crate::storage::query::ast::AutoEmbedConfig {
239 fields,
240 provider,
241 model,
242 });
243 } else {
244 return Err(ParseError::expected(
245 vec!["TTL", "EXPIRES AT", "METADATA", "AUTO EMBED"],
246 self.peek(),
247 self.position(),
248 ));
249 }
250 }
251
252 Ok((ttl_ms, expires_at_ms, with_metadata, auto_embed))
253 }
254
255 fn expect_ident_ci(&mut self, expected: &str) -> Result<(), ParseError> {
257 if self.consume_ident_ci(expected)? {
258 Ok(())
259 } else {
260 Err(ParseError::expected(
261 vec![expected],
262 self.peek(),
263 self.position(),
264 ))
265 }
266 }
267
268 fn parse_expires_at_value(&mut self) -> Result<u64, ParseError> {
270 if let Ok(value) = self.parse_integer() {
272 return Ok(value as u64);
273 }
274 if let Ok(text) = self.parse_string() {
276 let trimmed = text.trim();
278 if let Ok(ts) = trimmed.parse::<u64>() {
279 return Ok(ts);
280 }
281 return Err(ParseError::new(
283 format!("EXPIRES AT requires a unix timestamp in milliseconds, got {trimmed:?}"),
287 self.position(),
288 ));
289 }
290 Err(ParseError::expected(
291 vec!["timestamp (unix ms) or 'YYYY-MM-DD'"],
292 self.peek(),
293 self.position(),
294 ))
295 }
296
297 fn parse_with_metadata_pairs(&mut self) -> Result<Vec<(String, Value)>, ParseError> {
299 self.expect(Token::LParen)?;
300 let mut pairs = Vec::new();
301 if !self.check(&Token::RParen) {
302 loop {
303 let key = self.expect_ident_or_keyword()?.to_ascii_lowercase();
304 self.expect(Token::Eq)?;
305 let value = self.parse_literal_value()?;
306 pairs.push((key, value));
307 if !self.consume(&Token::Comma)? {
308 break;
309 }
310 }
311 }
312 self.expect(Token::RParen)?;
313 Ok(pairs)
314 }
315
316 pub fn parse_update_query(&mut self) -> Result<QueryExpr, ParseError> {
318 self.expect(Token::Update)?;
319 let table = self.expect_ident()?;
320 self.expect(Token::Set)?;
321
322 let mut assignments = Vec::new();
323 let mut assignment_exprs = Vec::new();
324 loop {
325 let col = self.expect_ident()?;
326 self.expect(Token::Eq)?;
327 let expr = self.parse_expr()?;
328 let folded = fold_expr_to_value(expr.clone()).ok();
329 assignment_exprs.push((col.clone(), expr));
330 if let Some(val) = folded {
331 assignments.push((col.clone(), val));
332 }
333 if !self.consume(&Token::Comma)? {
334 break;
335 }
336 }
337
338 let filter = if self.consume(&Token::Where)? {
339 Some(self.parse_filter()?)
340 } else {
341 None
342 };
343 let where_expr = filter.as_ref().map(filter_to_expr);
344
345 let (ttl_ms, expires_at_ms, with_metadata, _auto_embed) = self.parse_with_clauses()?;
346
347 let limit = if self.consume(&Token::Limit)? {
352 Some(self.parse_integer()? as u64)
353 } else {
354 None
355 };
356
357 let returning = self.parse_returning_clause()?;
358
359 let suppress_events = if self.consume_ident_ci("SUPPRESS")? {
360 self.expect_ident_ci("EVENTS")?;
361 true
362 } else {
363 false
364 };
365
366 Ok(QueryExpr::Update(UpdateQuery {
367 table,
368 assignment_exprs,
369 assignments,
370 where_expr,
371 filter,
372 ttl_ms,
373 expires_at_ms,
374 with_metadata,
375 returning,
376 limit,
377 suppress_events,
378 }))
379 }
380
381 pub fn parse_delete_query(&mut self) -> Result<QueryExpr, ParseError> {
383 self.expect(Token::Delete)?;
384 self.expect(Token::From)?;
385 let table = self.expect_ident()?;
386
387 let filter = if self.consume(&Token::Where)? {
388 Some(self.parse_filter()?)
389 } else {
390 None
391 };
392
393 let where_expr = filter.as_ref().map(filter_to_expr);
394
395 let returning = self.parse_returning_clause()?;
396
397 let suppress_events = if self.consume_ident_ci("SUPPRESS")? {
398 self.expect_ident_ci("EVENTS")?;
399 true
400 } else {
401 false
402 };
403
404 Ok(QueryExpr::Delete(DeleteQuery {
405 table,
406 where_expr,
407 filter,
408 returning,
409 suppress_events,
410 }))
411 }
412
413 fn parse_returning_clause(&mut self) -> Result<Option<Vec<ReturningItem>>, ParseError> {
417 if !self.consume(&Token::Returning)? {
418 return Ok(None);
419 }
420 if self.consume(&Token::Star)? {
421 return Ok(Some(vec![ReturningItem::All]));
422 }
423 let mut items = Vec::new();
424 loop {
425 let col = self.expect_ident_or_keyword()?;
426 items.push(ReturningItem::Column(col));
427 if !self.consume(&Token::Comma)? {
428 break;
429 }
430 }
431 if items.is_empty() {
432 return Err(ParseError::expected(
433 vec!["*", "column name"],
434 self.peek(),
435 self.position(),
436 ));
437 }
438 Ok(Some(items))
439 }
440
441 pub fn parse_ask_query(&mut self) -> Result<QueryExpr, ParseError> {
443 self.advance()?; let question = self.parse_string()?;
446
447 let mut provider = None;
448 let mut model = None;
449 let mut depth = None;
450 let mut limit = None;
451 let mut collection = None;
452
453 for _ in 0..5 {
455 if self.consume(&Token::Using)? {
456 provider = Some(self.expect_ident()?);
457 } else if self.consume_ident_ci("MODEL")? {
458 model = Some(self.parse_string()?);
459 } else if self.consume(&Token::Depth)? {
460 depth = Some(self.parse_integer()? as usize);
461 } else if self.consume(&Token::Limit)? {
462 limit = Some(self.parse_integer()? as usize);
463 } else if self.consume(&Token::Collection)? {
464 collection = Some(self.expect_ident()?);
465 } else {
466 break;
467 }
468 }
469
470 Ok(QueryExpr::Ask(AskQuery {
471 question,
472 provider,
473 model,
474 depth,
475 limit,
476 collection,
477 }))
478 }
479
480 fn parse_ident_list(&mut self) -> Result<Vec<String>, ParseError> {
482 let mut idents = Vec::new();
483 loop {
484 idents.push(self.expect_ident_or_keyword()?);
485 if !self.consume(&Token::Comma)? {
486 break;
487 }
488 }
489 Ok(idents)
490 }
491
492 fn parse_dml_value_list(&mut self) -> Result<Vec<Value>, ParseError> {
494 self.parse_dml_expr_list()?
495 .into_iter()
496 .map(fold_expr_to_value)
497 .collect::<Result<Vec<_>, _>>()
498 .map_err(|msg| ParseError::new(msg, self.position()))
499 }
500
501 fn parse_dml_expr_list(&mut self) -> Result<Vec<Expr>, ParseError> {
502 let mut values = Vec::new();
503 loop {
504 values.push(self.parse_expr()?);
505 if !self.consume(&Token::Comma)? {
506 break;
507 }
508 }
509 Ok(values)
510 }
511
512 pub(crate) fn parse_literal_value(&mut self) -> Result<Value, ParseError> {
514 self.enter_depth()?;
523 let result = self.parse_literal_value_inner();
524 self.exit_depth();
525 result
526 }
527
528 fn parse_literal_value_inner(&mut self) -> Result<Value, ParseError> {
529 if let Token::Ident(name) = self.peek().clone() {
536 let upper = name.to_uppercase();
537 if upper == "PASSWORD" || upper == "SECRET" {
538 self.advance()?; self.expect(Token::LParen)?;
540 let plaintext = self.parse_string()?;
541 self.expect(Token::RParen)?;
542 return Ok(match upper.as_str() {
543 "PASSWORD" => Value::Password(format!("@@plain@@{plaintext}")),
544 "SECRET" => Value::Secret(format!("@@plain@@{plaintext}").into_bytes()),
545 _ => unreachable!(),
546 });
547 }
548 if upper == "SECRET_REF" {
549 self.advance()?; self.expect(Token::LParen)?;
551 let store = self.expect_ident_or_keyword()?.to_ascii_lowercase();
552 if store != "vault" {
553 return Err(ParseError::expected(
554 vec!["vault"],
555 self.peek(),
556 self.position(),
557 ));
558 }
559 self.expect(Token::Comma)?;
560 let (collection, key) =
561 self.parse_kv_key(crate::catalog::CollectionModel::Vault)?;
562 self.expect(Token::RParen)?;
563 return Ok(secret_ref_value(&store, &collection, &key));
564 }
565 }
566
567 match self.peek().clone() {
568 Token::String(s) => {
569 let s = s.clone();
570 self.advance()?;
571 Ok(Value::text(s))
572 }
573 Token::JsonLiteral(raw) => {
574 self.advance()?;
579 let json_value = crate::utils::json::parse_json(&raw).map_err(|err| {
580 ParseError::new(
581 format!("invalid JSON object literal: {:?}", err.to_string()),
587 self.position(),
588 )
589 })?;
590 json_literal_depth_check(&json_value)
591 .map_err(|err| ParseError::new(err, self.position()))?;
592 let canonical = crate::serde_json::Value::from(json_value);
593 let bytes = crate::json::to_vec(&canonical).map_err(|err| {
594 ParseError::new(
595 format!("failed to encode JSON literal: {:?}", err.to_string()),
599 self.position(),
600 )
601 })?;
602 Ok(Value::Json(bytes))
603 }
604 Token::Integer(n) => {
605 self.advance()?;
606 Ok(Value::Integer(n))
607 }
608 Token::Float(n) => {
609 self.advance()?;
610 Ok(Value::Float(n))
611 }
612 Token::True => {
613 self.advance()?;
614 Ok(Value::Boolean(true))
615 }
616 Token::False => {
617 self.advance()?;
618 Ok(Value::Boolean(false))
619 }
620 Token::Null => {
621 self.advance()?;
622 Ok(Value::Null)
623 }
624 Token::LBracket => {
625 self.advance()?; let mut items = Vec::new();
629 if !self.check(&Token::RBracket) {
630 loop {
631 items.push(self.parse_literal_value()?);
632 if !self.consume(&Token::Comma)? {
633 break;
634 }
635 }
636 }
637 self.expect(Token::RBracket)?;
638
639 let all_numeric = items
641 .iter()
642 .all(|v| matches!(v, Value::Integer(_) | Value::Float(_)));
643 if all_numeric && !items.is_empty() {
644 let floats: Vec<f32> = items
645 .iter()
646 .map(|v| match v {
647 Value::Float(f) => *f as f32,
648 Value::Integer(i) => *i as f32,
649 _ => 0.0,
650 })
651 .collect();
652 Ok(Value::Vector(floats))
653 } else {
654 let json_arr: Vec<crate::json::Value> = items
656 .iter()
657 .map(|v| match v {
658 Value::Null => crate::json::Value::Null,
659 Value::Boolean(b) => crate::json::Value::Bool(*b),
660 Value::Integer(i) => crate::json::Value::Number(*i as f64),
661 Value::Float(f) => crate::json::Value::Number(*f),
662 Value::Text(s) => crate::json::Value::String(s.to_string()),
663 _ => crate::json::Value::Null,
664 })
665 .collect();
666 let json_val = crate::json::Value::Array(json_arr);
667 let bytes = crate::json::to_vec(&json_val).unwrap_or_default();
668 Ok(Value::Json(bytes))
669 }
670 }
671 Token::LBrace => {
672 self.advance()?; let mut map = crate::json::Map::new();
675 if !self.check(&Token::RBrace) {
676 loop {
677 let key = match self.peek().clone() {
684 Token::String(s) => {
685 self.advance()?;
686 s
687 }
688 Token::Ident(s) => {
689 self.advance()?;
690 s
691 }
692 _ => self.expect_ident_or_keyword()?.to_ascii_lowercase(),
693 };
694 if !self.consume(&Token::Colon)? {
696 self.expect(Token::Eq)?;
697 }
698 let val = self.parse_literal_value()?;
700 let json_val = match val {
701 Value::Null => crate::json::Value::Null,
702 Value::Boolean(b) => crate::json::Value::Bool(b),
703 Value::Integer(i) => crate::json::Value::Number(i as f64),
704 Value::Float(f) => crate::json::Value::Number(f),
705 Value::Text(s) => crate::json::Value::String(s.to_string()),
706 Value::Json(ref bytes) => {
707 crate::json::from_slice(bytes).unwrap_or(crate::json::Value::Null)
708 }
709 _ => crate::json::Value::Null,
710 };
711 map.insert(key, json_val);
712 if !self.consume(&Token::Comma)? {
713 break;
714 }
715 }
716 }
717 self.expect(Token::RBrace)?;
718 let json_val = crate::json::Value::Object(map);
719 let bytes = crate::json::to_vec(&json_val).unwrap_or_default();
720 Ok(Value::Json(bytes))
721 }
722 ref other => Err(ParseError::expected(
723 vec!["string", "number", "true", "false", "null", "[", "{"],
724 other,
725 self.position(),
726 )),
727 }
728 }
729}
730
731fn secret_ref_value(store: &str, collection: &str, key: &str) -> Value {
732 let mut map = crate::json::Map::new();
733 map.insert(
734 "type".to_string(),
735 crate::json::Value::String("secret_ref".to_string()),
736 );
737 map.insert(
738 "store".to_string(),
739 crate::json::Value::String(store.to_string()),
740 );
741 map.insert(
742 "collection".to_string(),
743 crate::json::Value::String(collection.to_string()),
744 );
745 map.insert(
746 "key".to_string(),
747 crate::json::Value::String(key.to_string()),
748 );
749 Value::Json(crate::json::to_vec(&crate::json::Value::Object(map)).unwrap_or_default())
750}