1use super::super::ast::{
4 AskCacheClause, AskQuery, BinOp, DeleteQuery, Expr, FieldRef, Filter, InsertEntityType,
5 InsertQuery, OrderByClause, QueryExpr, ReturningItem, UpdateQuery, UpdateTarget,
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 .map(|expr| match fold_expr_to_value(expr.clone()) {
106 Ok(value) => Ok(value),
107 Err(msg) => {
108 if crate::storage::query::user_params::expr_contains_parameter(&expr) {
109 Ok(Value::Null)
110 } else {
111 Err(msg)
112 }
113 }
114 })
115 .collect::<Result<Vec<_>, _>>()
116 .map_err(|msg| ParseError::new(msg, self.position()))?;
117 all_value_exprs.push(row_exprs);
118 all_values.push(row_values);
119 if !self.consume(&Token::Comma)? {
120 break;
121 }
122 }
123
124 let (ttl_ms, expires_at_ms, with_metadata, auto_embed) = self.parse_with_clauses()?;
126
127 let returning = self.parse_returning_clause()?;
128
129 let suppress_events = if self.consume_ident_ci("SUPPRESS")? {
130 self.expect_ident_ci("EVENTS")?;
131 true
132 } else {
133 false
134 };
135
136 Ok(QueryExpr::Insert(InsertQuery {
137 table,
138 entity_type,
139 columns,
140 value_exprs: all_value_exprs,
141 values: all_values,
142 returning,
143 ttl_ms,
144 expires_at_ms,
145 with_metadata,
146 auto_embed,
147 suppress_events,
148 }))
149 }
150
151 fn parse_ttl_duration(&mut self) -> Result<u64, ParseError> {
153 let ttl_value = self.parse_float()?;
155 let ttl_unit = match self.peek() {
156 Token::Ident(unit) => {
157 let unit = unit.clone();
158 self.advance()?;
159 unit
160 }
161 _ => "s".to_string(),
162 };
163
164 let multiplier_ms = match ttl_unit.to_ascii_lowercase().as_str() {
165 "ms" | "msec" | "millisecond" | "milliseconds" => 1.0,
166 "s" | "sec" | "secs" | "second" | "seconds" => 1_000.0,
167 "m" | "min" | "mins" | "minute" | "minutes" => 60_000.0,
168 "h" | "hr" | "hrs" | "hour" | "hours" => 3_600_000.0,
169 "d" | "day" | "days" => 86_400_000.0,
170 other => {
171 return Err(ParseError::new(
172 format!(
176 "unsupported TTL unit {other:?}; supported units: ms, s, m, h, d (e.g. `WITH TTL 30 m`)"
177 ),
178 self.position(),
179 ));
180 }
181 };
182
183 Ok((ttl_value * multiplier_ms) as u64)
184 }
185
186 pub fn parse_with_clauses(
189 &mut self,
190 ) -> Result<
191 (
192 Option<u64>,
193 Option<u64>,
194 Vec<(String, Value)>,
195 Option<crate::storage::query::ast::AutoEmbedConfig>,
196 ),
197 ParseError,
198 > {
199 let mut ttl_ms = None;
200 let mut expires_at_ms = None;
201 let mut with_metadata = Vec::new();
202 let mut auto_embed = None;
203
204 while self.consume(&Token::With)? {
205 if self.consume_ident_ci("TTL")? {
206 ttl_ms = Some(self.parse_ttl_duration()?);
207 } else if self.consume_ident_ci("EXPIRES")? {
208 self.expect_ident_ci("AT")?;
209 let ts = self.parse_expires_at_value()?;
210 expires_at_ms = Some(ts);
211 } else if self.consume(&Token::Metadata)? || self.consume_ident_ci("METADATA")? {
212 with_metadata = self.parse_with_metadata_pairs()?;
213 } else if self.consume_ident_ci("AUTO")? {
214 self.consume_ident_ci("EMBED")?;
216 self.expect(Token::LParen)?;
217 let mut fields = Vec::new();
218 loop {
219 fields.push(self.expect_ident()?);
220 if !self.consume(&Token::Comma)? {
221 break;
222 }
223 }
224 self.expect(Token::RParen)?;
225 let provider = if self.consume(&Token::Using)? {
230 self.expect_ident()?
231 } else {
232 "openai".to_string()
233 };
234 let model = if self.consume_ident_ci("MODEL")? {
235 Some(self.parse_string()?)
236 } else {
237 None
238 };
239 auto_embed = Some(crate::storage::query::ast::AutoEmbedConfig {
240 fields,
241 provider,
242 model,
243 });
244 } else {
245 return Err(ParseError::expected(
246 vec!["TTL", "EXPIRES AT", "METADATA", "AUTO EMBED"],
247 self.peek(),
248 self.position(),
249 ));
250 }
251 }
252
253 Ok((ttl_ms, expires_at_ms, with_metadata, auto_embed))
254 }
255
256 fn expect_ident_ci(&mut self, expected: &str) -> Result<(), ParseError> {
258 if self.consume_ident_ci(expected)? {
259 Ok(())
260 } else {
261 Err(ParseError::expected(
262 vec![expected],
263 self.peek(),
264 self.position(),
265 ))
266 }
267 }
268
269 fn parse_expires_at_value(&mut self) -> Result<u64, ParseError> {
271 if let Ok(value) = self.parse_integer() {
273 return Ok(value as u64);
274 }
275 if let Ok(text) = self.parse_string() {
277 let trimmed = text.trim();
279 if let Ok(ts) = trimmed.parse::<u64>() {
280 return Ok(ts);
281 }
282 return Err(ParseError::new(
284 format!("EXPIRES AT requires a unix timestamp in milliseconds, got {trimmed:?}"),
288 self.position(),
289 ));
290 }
291 Err(ParseError::expected(
292 vec!["timestamp (unix ms) or 'YYYY-MM-DD'"],
293 self.peek(),
294 self.position(),
295 ))
296 }
297
298 fn parse_with_metadata_pairs(&mut self) -> Result<Vec<(String, Value)>, ParseError> {
300 self.expect(Token::LParen)?;
301 let mut pairs = Vec::new();
302 if !self.check(&Token::RParen) {
303 loop {
304 let key = self.expect_ident_or_keyword()?.to_ascii_lowercase();
305 self.expect(Token::Eq)?;
306 let value = self.parse_literal_value()?;
307 pairs.push((key, value));
308 if !self.consume(&Token::Comma)? {
309 break;
310 }
311 }
312 }
313 self.expect(Token::RParen)?;
314 Ok(pairs)
315 }
316
317 pub fn parse_update_query(&mut self) -> Result<QueryExpr, ParseError> {
319 self.expect(Token::Update)?;
320 let table = self.expect_ident()?;
321 let target = self.parse_update_target()?;
322 self.expect(Token::Set)?;
323
324 let mut assignments = Vec::new();
325 let mut assignment_exprs = Vec::new();
326 let mut compound_assignment_ops = Vec::new();
327 loop {
328 let col = self.expect_column_ident()?;
329 let compound_op = if self.consume(&Token::Eq)? {
330 None
331 } else {
332 let op = match self.peek() {
333 Token::Plus => BinOp::Add,
334 Token::Dash | Token::Minus => BinOp::Sub,
335 Token::Star => BinOp::Mul,
336 Token::Slash => BinOp::Div,
337 Token::Percent => BinOp::Mod,
338 _ => {
339 return Err(ParseError::expected(
340 vec!["=", "+=", "-=", "*=", "/=", "%="],
341 self.peek(),
342 self.position(),
343 ));
344 }
345 };
346 self.advance()?;
347 self.expect(Token::Eq)?;
348 Some(op)
349 };
350 let expr = self.parse_expr()?;
351 let folded = fold_expr_to_value(expr.clone()).ok();
352 assignment_exprs.push((col.clone(), expr));
353 compound_assignment_ops.push(compound_op);
354 if compound_op.is_none() {
355 if let Some(val) = folded {
356 assignments.push((col.clone(), val));
357 }
358 }
359 if !self.consume(&Token::Comma)? {
360 break;
361 }
362 }
363
364 let filter = if self.consume(&Token::Where)? {
365 Some(self.parse_filter()?)
366 } else {
367 None
368 };
369 let where_expr = filter.as_ref().map(filter_to_expr);
370
371 let (ttl_ms, expires_at_ms, with_metadata, _auto_embed) = self.parse_with_clauses()?;
372
373 let mut order_by = if self.consume(&Token::Order)? {
374 self.expect(Token::By)?;
375 let clauses = self.parse_order_by_list()?;
376 validate_update_order_by(&clauses, self.position())?;
377 clauses
378 } else {
379 Vec::new()
380 };
381
382 let limit = if self.consume(&Token::Limit)? {
387 Some(self.parse_integer()? as u64)
388 } else {
389 None
390 };
391 if !order_by.is_empty() && limit.is_none() {
392 return Err(ParseError::new(
393 "UPDATE ORDER BY requires LIMIT",
394 self.position(),
395 ));
396 }
397 if !order_by.is_empty() && !update_order_by_mentions_rid(&order_by) {
398 order_by.push(OrderByClause {
399 field: FieldRef::TableColumn {
400 table: String::new(),
401 column: "rid".to_string(),
402 },
403 expr: None,
404 ascending: true,
405 nulls_first: false,
406 });
407 }
408
409 let returning = self.parse_returning_clause()?;
410
411 let suppress_events = if self.consume_ident_ci("SUPPRESS")? {
412 self.expect_ident_ci("EVENTS")?;
413 true
414 } else {
415 false
416 };
417
418 Ok(QueryExpr::Update(UpdateQuery {
419 table,
420 target,
421 assignment_exprs,
422 compound_assignment_ops,
423 assignments,
424 where_expr,
425 filter,
426 ttl_ms,
427 expires_at_ms,
428 with_metadata,
429 returning,
430 order_by,
431 limit,
432 suppress_events,
433 }))
434 }
435
436 fn parse_update_target(&mut self) -> Result<UpdateTarget, ParseError> {
437 if self.consume(&Token::Kv)? {
438 return Ok(UpdateTarget::Kv);
439 }
440 if self.consume_ident_ci("ROWS")? {
441 return Ok(UpdateTarget::Rows);
442 }
443 if self.consume_ident_ci("DOCUMENTS")? {
444 return Ok(UpdateTarget::Documents);
445 }
446 if self.consume_ident_ci("NODES")? {
447 return Ok(UpdateTarget::Nodes);
448 }
449 if self.consume_ident_ci("EDGES")? {
450 return Ok(UpdateTarget::Edges);
451 }
452 Ok(UpdateTarget::Rows)
453 }
454
455 pub fn parse_delete_query(&mut self) -> Result<QueryExpr, ParseError> {
457 self.expect(Token::Delete)?;
458 self.expect(Token::From)?;
459 let table = self.expect_ident()?;
460
461 let filter = if self.consume(&Token::Where)? {
462 Some(self.parse_filter()?)
463 } else {
464 None
465 };
466
467 let where_expr = filter.as_ref().map(filter_to_expr);
468
469 let returning = self.parse_returning_clause()?;
470
471 let suppress_events = if self.consume_ident_ci("SUPPRESS")? {
472 self.expect_ident_ci("EVENTS")?;
473 true
474 } else {
475 false
476 };
477
478 Ok(QueryExpr::Delete(DeleteQuery {
479 table,
480 where_expr,
481 filter,
482 returning,
483 suppress_events,
484 }))
485 }
486
487 fn parse_returning_clause(&mut self) -> Result<Option<Vec<ReturningItem>>, ParseError> {
491 if !self.consume(&Token::Returning)? {
492 return Ok(None);
493 }
494 if self.consume(&Token::Star)? {
495 return Ok(Some(vec![ReturningItem::All]));
496 }
497 let mut items = Vec::new();
498 loop {
499 if returning_expr_start(self.peek()) {
500 return Err(returning_expr_not_supported(self.position()));
501 }
502 let col = self.expect_update_returning_column()?;
503 items.push(ReturningItem::Column(col));
504 if returning_expr_tail(self.peek()) {
505 return Err(returning_expr_not_supported(self.position()));
506 }
507 if !self.consume(&Token::Comma)? {
508 break;
509 }
510 }
511 if items.is_empty() {
512 return Err(ParseError::expected(
513 vec!["*", "column name"],
514 self.peek(),
515 self.position(),
516 ));
517 }
518 Ok(Some(items))
519 }
520
521 fn expect_update_returning_column(&mut self) -> Result<String, ParseError> {
522 if self.consume(&Token::Weight)? {
523 return Ok("weight".to_string());
524 }
525 self.expect_ident_or_keyword()
526 }
527
528 pub fn parse_ask_query(&mut self) -> Result<QueryExpr, ParseError> {
531 self.parse_ask_query_with_explain(false)
532 }
533
534 pub fn parse_explain_ask_query(&mut self) -> Result<QueryExpr, ParseError> {
536 self.advance()?; if !matches!(self.peek(), Token::Ident(name) if name.eq_ignore_ascii_case("ASK")) {
538 return Err(ParseError::expected(
539 vec!["ASK"],
540 self.peek(),
541 self.position(),
542 ));
543 }
544 self.parse_ask_query_with_explain(true)
545 }
546
547 fn parse_ask_query_with_explain(&mut self, explain: bool) -> Result<QueryExpr, ParseError> {
548 self.advance()?; let (question, question_param) = match self.peek() {
551 Token::String(_) => (self.parse_string()?, None),
552 Token::Dollar | Token::Question => {
553 let index = self.parse_param_slot("ASK question")?;
554 (String::new(), Some(index))
555 }
556 other => {
557 return Err(ParseError::expected(
558 vec!["string", "$N", "?"],
559 other,
560 self.position(),
561 ));
562 }
563 };
564
565 let mut provider = None;
566 let mut model = None;
567 let mut depth = None;
568 let mut limit = None;
569 let mut min_score = None;
570 let mut collection = None;
571 let mut temperature = None;
572 let mut seed = None;
573 let mut strict = true;
574 let mut stream = false;
575 let mut cache = AskCacheClause::Default;
576
577 for _ in 0..12 {
580 if self.consume(&Token::Using)? {
581 provider = Some(match &self.current.token {
582 Token::String(_) => self.parse_string()?,
583 _ => self.expect_ident()?,
584 });
585 } else if self.consume_ident_ci("MODEL")? {
586 model = Some(self.parse_string()?);
587 } else if self.consume(&Token::Depth)? {
588 depth = Some(self.parse_integer()? as usize);
589 } else if self.consume(&Token::Limit)? {
590 limit = Some(self.parse_integer()? as usize);
591 } else if self.consume(&Token::MinScore)? {
592 min_score = Some(self.parse_float()? as f32);
593 } else if self.consume(&Token::Collection)? {
594 collection = Some(self.expect_ident()?);
595 } else if self.consume_ident_ci("TEMPERATURE")? {
596 temperature = Some(self.parse_float()? as f32);
597 } else if self.consume_ident_ci("SEED")? {
598 seed = Some(self.parse_integer()? as u64);
599 } else if self.consume_ident_ci("STRICT")? {
600 let value = self.expect_ident_or_keyword()?;
601 if value.eq_ignore_ascii_case("ON") {
602 strict = true;
603 } else if value.eq_ignore_ascii_case("OFF") {
604 strict = false;
605 } else {
606 return Err(ParseError::new(
607 "Expected ON or OFF after STRICT",
608 self.position(),
609 ));
610 }
611 } else if self.consume_ident_ci("STREAM")? {
612 stream = true;
613 } else if self.consume_ident_ci("CACHE")? {
614 if !matches!(cache, AskCacheClause::Default) {
615 return Err(ParseError::new(
616 "ASK cache clause specified more than once",
617 self.position(),
618 ));
619 }
620 let ttl = self.expect_ident_or_keyword()?;
621 if !ttl.eq_ignore_ascii_case("TTL") {
622 return Err(ParseError::new("Expected TTL after CACHE", self.position()));
623 }
624 cache = AskCacheClause::CacheTtl(self.parse_string()?);
625 } else if self.consume_ident_ci("NOCACHE")? {
626 if !matches!(cache, AskCacheClause::Default) {
627 return Err(ParseError::new(
628 "ASK cache clause specified more than once",
629 self.position(),
630 ));
631 }
632 cache = AskCacheClause::NoCache;
633 } else {
634 break;
635 }
636 }
637
638 Ok(QueryExpr::Ask(AskQuery {
639 explain,
640 question,
641 question_param,
642 provider,
643 model,
644 depth,
645 limit,
646 min_score,
647 collection,
648 temperature,
649 seed,
650 strict,
651 stream,
652 cache,
653 }))
654 }
655
656 fn parse_ident_list(&mut self) -> Result<Vec<String>, ParseError> {
658 let mut idents = Vec::new();
659 loop {
660 idents.push(self.expect_ident_or_keyword()?);
661 if !self.consume(&Token::Comma)? {
662 break;
663 }
664 }
665 Ok(idents)
666 }
667
668 fn parse_dml_value_list(&mut self) -> Result<Vec<Value>, ParseError> {
670 self.parse_dml_expr_list()?
671 .into_iter()
672 .map(fold_expr_to_value)
673 .collect::<Result<Vec<_>, _>>()
674 .map_err(|msg| ParseError::new(msg, self.position()))
675 }
676
677 fn parse_dml_expr_list(&mut self) -> Result<Vec<Expr>, ParseError> {
678 let mut values = Vec::new();
679 loop {
680 values.push(self.parse_expr()?);
681 if !self.consume(&Token::Comma)? {
682 break;
683 }
684 }
685 Ok(values)
686 }
687
688 pub(crate) fn parse_literal_value(&mut self) -> Result<Value, ParseError> {
690 self.enter_depth()?;
699 let result = self.parse_literal_value_inner();
700 self.exit_depth();
701 result
702 }
703
704 fn parse_literal_value_inner(&mut self) -> Result<Value, ParseError> {
705 if let Token::Ident(name) = self.peek().clone() {
712 let upper = name.to_uppercase();
713 if upper == "PASSWORD" || upper == "SECRET" {
714 self.advance()?; self.expect(Token::LParen)?;
716 let plaintext = self.parse_string()?;
717 self.expect(Token::RParen)?;
718 return Ok(match upper.as_str() {
719 "PASSWORD" => Value::Password(format!("@@plain@@{plaintext}")),
720 "SECRET" => Value::Secret(format!("@@plain@@{plaintext}").into_bytes()),
721 _ => unreachable!(),
722 });
723 }
724 if upper == "SECRET_REF" {
725 self.advance()?; self.expect(Token::LParen)?;
727 let store = self.expect_ident_or_keyword()?.to_ascii_lowercase();
728 if store != "vault" {
729 return Err(ParseError::expected(
730 vec!["vault"],
731 self.peek(),
732 self.position(),
733 ));
734 }
735 self.expect(Token::Comma)?;
736 let (collection, key) =
737 self.parse_kv_key(crate::catalog::CollectionModel::Vault)?;
738 self.expect(Token::RParen)?;
739 return Ok(secret_ref_value(&store, &collection, &key));
740 }
741 }
742
743 match self.peek().clone() {
744 Token::String(s) => {
745 let s = s.clone();
746 self.advance()?;
747 Ok(Value::text(s))
748 }
749 Token::JsonLiteral(raw) => {
750 self.advance()?;
755 let json_value = crate::utils::json::parse_json(&raw).map_err(|err| {
756 ParseError::new(
757 format!("invalid JSON object literal: {:?}", err.to_string()),
763 self.position(),
764 )
765 })?;
766 json_literal_depth_check(&json_value)
767 .map_err(|err| ParseError::new(err, self.position()))?;
768 let canonical = crate::serde_json::Value::from(json_value);
769 let bytes = crate::json::to_vec(&canonical).map_err(|err| {
770 ParseError::new(
771 format!("failed to encode JSON literal: {:?}", err.to_string()),
775 self.position(),
776 )
777 })?;
778 Ok(Value::Json(bytes))
779 }
780 Token::Integer(n) => {
781 self.advance()?;
782 Ok(Value::Integer(n))
783 }
784 Token::Float(n) => {
785 self.advance()?;
786 Ok(Value::Float(n))
787 }
788 Token::True => {
789 self.advance()?;
790 Ok(Value::Boolean(true))
791 }
792 Token::False => {
793 self.advance()?;
794 Ok(Value::Boolean(false))
795 }
796 Token::Null => {
797 self.advance()?;
798 Ok(Value::Null)
799 }
800 Token::LBracket => {
801 self.advance()?; let mut items = Vec::new();
805 if !self.check(&Token::RBracket) {
806 loop {
807 items.push(self.parse_literal_value()?);
808 if !self.consume(&Token::Comma)? {
809 break;
810 }
811 }
812 }
813 self.expect(Token::RBracket)?;
814
815 let all_numeric = items
817 .iter()
818 .all(|v| matches!(v, Value::Integer(_) | Value::Float(_)));
819 if all_numeric && !items.is_empty() {
820 let floats: Vec<f32> = items
821 .iter()
822 .map(|v| match v {
823 Value::Float(f) => *f as f32,
824 Value::Integer(i) => *i as f32,
825 _ => 0.0,
826 })
827 .collect();
828 Ok(Value::Vector(floats))
829 } else {
830 let json_arr: Vec<crate::json::Value> = items
832 .iter()
833 .map(|v| match v {
834 Value::Null => crate::json::Value::Null,
835 Value::Boolean(b) => crate::json::Value::Bool(*b),
836 Value::Integer(i) => crate::json::Value::Number(*i as f64),
837 Value::Float(f) => crate::json::Value::Number(*f),
838 Value::Text(s) => crate::json::Value::String(s.to_string()),
839 _ => crate::json::Value::Null,
840 })
841 .collect();
842 let json_val = crate::json::Value::Array(json_arr);
843 let bytes = crate::json::to_vec(&json_val).unwrap_or_default();
844 Ok(Value::Json(bytes))
845 }
846 }
847 Token::LBrace => {
848 self.advance()?; let mut map = crate::json::Map::new();
851 if !self.check(&Token::RBrace) {
852 loop {
853 let key = match self.peek().clone() {
860 Token::String(s) => {
861 self.advance()?;
862 s
863 }
864 Token::Ident(s) => {
865 self.advance()?;
866 s
867 }
868 _ => self.expect_ident_or_keyword()?.to_ascii_lowercase(),
869 };
870 if !self.consume(&Token::Colon)? {
872 self.expect(Token::Eq)?;
873 }
874 let val = self.parse_literal_value()?;
876 let json_val = match val {
877 Value::Null => crate::json::Value::Null,
878 Value::Boolean(b) => crate::json::Value::Bool(b),
879 Value::Integer(i) => crate::json::Value::Number(i as f64),
880 Value::Float(f) => crate::json::Value::Number(f),
881 Value::Text(s) => crate::json::Value::String(s.to_string()),
882 Value::Json(ref bytes) => {
883 crate::json::from_slice(bytes).unwrap_or(crate::json::Value::Null)
884 }
885 _ => crate::json::Value::Null,
886 };
887 map.insert(key, json_val);
888 if !self.consume(&Token::Comma)? {
889 break;
890 }
891 }
892 }
893 self.expect(Token::RBrace)?;
894 let json_val = crate::json::Value::Object(map);
895 let bytes = crate::json::to_vec(&json_val).unwrap_or_default();
896 Ok(Value::Json(bytes))
897 }
898 ref other => Err(ParseError::expected(
899 vec!["string", "number", "true", "false", "null", "[", "{"],
900 other,
901 self.position(),
902 )),
903 }
904 }
905}
906
907fn returning_expr_start(token: &Token) -> bool {
908 matches!(
909 token,
910 Token::Integer(_)
911 | Token::Float(_)
912 | Token::String(_)
913 | Token::JsonLiteral(_)
914 | Token::Null
915 | Token::True
916 | Token::False
917 | Token::LParen
918 | Token::Minus
919 | Token::Question
920 | Token::Dollar
921 )
922}
923
924fn returning_expr_tail(token: &Token) -> bool {
925 matches!(
926 token,
927 Token::LParen
928 | Token::Plus
929 | Token::Minus
930 | Token::Star
931 | Token::Slash
932 | Token::Percent
933 | Token::DoublePipe
934 | Token::Pipe
935 | Token::Eq
936 | Token::Ne
937 | Token::Lt
938 | Token::Le
939 | Token::Gt
940 | Token::Ge
941 | Token::Dot
942 | Token::Colon
943 )
944}
945
946fn validate_update_order_by(
947 clauses: &[OrderByClause],
948 position: super::super::lexer::Position,
949) -> Result<(), ParseError> {
950 for clause in clauses {
951 if clause.expr.is_some() {
952 return Err(ParseError::new(
953 "UPDATE ORDER BY only supports top-level fields",
954 position,
955 ));
956 }
957 match &clause.field {
958 FieldRef::TableColumn { table, column }
959 if table.is_empty() && !column.contains('.') => {}
960 _ => {
961 return Err(ParseError::new(
962 "UPDATE ORDER BY only supports top-level fields",
963 position,
964 ));
965 }
966 }
967 }
968 Ok(())
969}
970
971fn update_order_by_mentions_rid(clauses: &[OrderByClause]) -> bool {
972 clauses.iter().any(|clause| {
973 matches!(
974 &clause.field,
975 FieldRef::TableColumn { table, column }
976 if table.is_empty() && column.eq_ignore_ascii_case("rid")
977 )
978 })
979}
980
981fn returning_expr_not_supported(position: super::super::lexer::Position) -> ParseError {
982 ParseError::new(
983 "NOT_YET_SUPPORTED: RETURNING expressions are not supported yet; use RETURNING * or named columns. Track a follow-up issue for RETURNING <expr>.",
984 position,
985 )
986}
987
988fn secret_ref_value(store: &str, collection: &str, key: &str) -> Value {
989 let mut map = crate::json::Map::new();
990 map.insert(
991 "type".to_string(),
992 crate::json::Value::String("secret_ref".to_string()),
993 );
994 map.insert(
995 "store".to_string(),
996 crate::json::Value::String(store.to_string()),
997 );
998 map.insert(
999 "collection".to_string(),
1000 crate::json::Value::String(collection.to_string()),
1001 );
1002 map.insert(
1003 "key".to_string(),
1004 crate::json::Value::String(key.to_string()),
1005 );
1006 Value::Json(crate::json::to_vec(&crate::json::Value::Object(map)).unwrap_or_default())
1007}