1use reblessive::Stk;
2
3use crate::{
4 sql::{
5 part::{DestructurePart, Recurse, RecurseInstruction},
6 Dir, Edges, Field, Fields, Graph, Ident, Idiom, Param, Part, Table, Tables, Value,
7 },
8 syn::{
9 error::bail,
10 token::{t, Glued, Span, TokenKind},
11 },
12};
13
14use super::{
15 mac::{expected, parse_option, unexpected},
16 ParseResult, Parser,
17};
18
19impl Parser<'_> {
20 pub(super) fn peek_continues_idiom(&mut self) -> bool {
21 let peek = self.peek().kind;
22 if matches!(peek, t!("->") | t!("[") | t!(".") | t!("...") | t!("?")) {
23 return true;
24 }
25 peek == t!("<") && matches!(self.peek1().kind, t!("-") | t!("->"))
26 }
27
28 pub(super) async fn parse_fields(&mut self, ctx: &mut Stk) -> ParseResult<Fields> {
33 if self.eat(t!("VALUE")) {
34 let expr = ctx.run(|ctx| self.parse_value_field(ctx)).await?;
35 let alias = if self.eat(t!("AS")) {
36 Some(self.parse_plain_idiom(ctx).await?)
37 } else {
38 None
39 };
40 Ok(Fields(
41 vec![Field::Single {
42 expr,
43 alias,
44 }],
45 true,
46 ))
47 } else {
48 let mut fields = Vec::new();
49 loop {
50 let field = if self.eat(t!("*")) {
51 Field::All
52 } else {
53 let expr = ctx.run(|ctx| self.parse_value_field(ctx)).await?;
54 let alias = if self.eat(t!("AS")) {
55 Some(self.parse_plain_idiom(ctx).await?)
56 } else {
57 None
58 };
59 Field::Single {
60 expr,
61 alias,
62 }
63 };
64 fields.push(field);
65 if !self.eat(t!(",")) {
66 break;
67 }
68 }
69 Ok(Fields(fields, false))
70 }
71 }
72
73 pub(super) async fn parse_idiom_list(&mut self, ctx: &mut Stk) -> ParseResult<Vec<Idiom>> {
75 let mut res = vec![self.parse_plain_idiom(ctx).await?];
76 while self.eat(t!(",")) {
77 res.push(self.parse_plain_idiom(ctx).await?);
78 }
79 Ok(res)
80 }
81
82 pub(super) async fn parse_remaining_idiom(
87 &mut self,
88 stk: &mut Stk,
89 start: Vec<Part>,
90 ) -> ParseResult<Idiom> {
91 let mut res = start;
92 loop {
93 match self.peek_kind() {
94 t!("?") => {
95 self.pop_peek();
96 res.push(Part::Optional);
97 }
98 t!("...") => {
99 self.pop_peek();
100 res.push(Part::Flatten);
101 }
102 t!(".") => {
103 self.pop_peek();
104 res.push(self.parse_dot_part(stk).await?)
105 }
106 t!("[") => {
107 let span = self.pop_peek().span;
108 let part = self.parse_bracket_part(stk, span).await?;
109 res.push(part)
110 }
111 t!("->") => {
112 self.pop_peek();
113 let graph = stk.run(|stk| self.parse_graph(stk, Dir::Out)).await?;
114 res.push(Part::Graph(graph))
115 }
116 t!("<") => {
117 let peek = self.peek_whitespace1();
118 if peek.kind == t!("-") {
119 self.pop_peek();
120 self.pop_peek();
121 let graph = stk.run(|stk| self.parse_graph(stk, Dir::In)).await?;
122 res.push(Part::Graph(graph))
123 } else if peek.kind == t!("->") {
124 self.pop_peek();
125 self.pop_peek();
126 let graph = stk.run(|stk| self.parse_graph(stk, Dir::Both)).await?;
127 res.push(Part::Graph(graph))
128 } else {
129 break;
130 }
131 }
132 t!("..") => {
133 bail!("Unexpected token `{}` expected and idiom",t!(".."),
134 @self.last_span() => "Did you maybe intent to use the flatten operator `...`");
135 }
136 _ => break,
137 }
138 }
139 Ok(Idiom(res))
140 }
141
142 pub(super) async fn parse_remaining_value_idiom(
149 &mut self,
150 ctx: &mut Stk,
151 start: Vec<Part>,
152 ) -> ParseResult<Value> {
153 let mut res = start;
154 loop {
155 match self.peek_kind() {
156 t!("?") => {
157 self.pop_peek();
158 res.push(Part::Optional);
159 }
160 t!("...") => {
161 self.pop_peek();
162 res.push(Part::Flatten);
163 }
164 t!(".") => {
165 self.pop_peek();
166 res.push(self.parse_dot_part(ctx).await?)
167 }
168 t!("[") => {
169 let span = self.pop_peek().span;
170 let part = self.parse_bracket_part(ctx, span).await?;
171 res.push(part)
172 }
173 t!("->") => {
174 self.pop_peek();
175 if let Some(x) = self.parse_graph_idiom(ctx, &mut res, Dir::Out).await? {
176 return Ok(x);
177 }
178 }
179 t!("<") => {
180 let peek = self.peek_whitespace1();
181 if peek.kind == t!("-") {
182 self.pop_peek();
183 self.pop_peek();
184
185 if let Some(x) = self.parse_graph_idiom(ctx, &mut res, Dir::In).await? {
186 return Ok(x);
187 }
188 } else if peek.kind == t!("->") {
189 self.pop_peek();
190 self.pop_peek();
191
192 if let Some(x) = self.parse_graph_idiom(ctx, &mut res, Dir::Both).await? {
193 return Ok(x);
194 }
195 } else {
196 break;
197 }
198 }
199 t!("..") => {
200 bail!("Unexpected token `{}` expected and idiom",t!(".."),
201 @self.last_span() => "Did you maybe intent to use the flatten operator `...`");
202 }
203 _ => break,
204 }
205 }
206 Ok(Value::Idiom(Idiom(res)))
207 }
208
209 async fn parse_graph_idiom(
212 &mut self,
213 ctx: &mut Stk,
214 res: &mut Vec<Part>,
215 dir: Dir,
216 ) -> ParseResult<Option<Value>> {
217 let graph = ctx.run(|ctx| self.parse_graph(ctx, dir)).await?;
218 if res.len() == 1
221 && graph.alias.is_none()
222 && graph.cond.is_none()
223 && graph.group.is_none()
224 && graph.limit.is_none()
225 && graph.order.is_none()
226 && graph.split.is_none()
227 && graph.start.is_none()
228 && graph.expr.is_none()
229 {
230 match std::mem::replace(&mut res[0], Part::All) {
231 Part::Value(Value::Thing(t)) | Part::Start(Value::Thing(t)) => {
232 let edge = Edges {
233 dir: graph.dir,
234 from: t,
235 what: graph.what,
236 };
237 let value = Value::Edges(Box::new(edge));
238
239 if !self.peek_continues_idiom() {
240 return Ok(Some(value));
241 }
242 res[0] = Part::Start(value);
243 return Ok(None);
244 }
245 x => {
246 res[0] = x;
247 }
248 }
249 }
250 res.push(Part::Graph(graph));
251 Ok(None)
252 }
253
254 pub async fn parse_plain_idiom(&mut self, ctx: &mut Stk) -> ParseResult<Idiom> {
257 let start = match self.peek_kind() {
258 t!("->") => {
259 self.pop_peek();
260 let graph = ctx.run(|ctx| self.parse_graph(ctx, Dir::Out)).await?;
261 Part::Graph(graph)
262 }
263 t!("<") => {
264 let t = self.pop_peek();
265 let graph = if self.eat_whitespace(t!("-")) {
266 ctx.run(|ctx| self.parse_graph(ctx, Dir::In)).await?
267 } else if self.eat_whitespace(t!("->")) {
268 ctx.run(|ctx| self.parse_graph(ctx, Dir::Both)).await?
269 } else {
270 unexpected!(self, t, "either `<-` `<->` or `->`")
271 };
272 Part::Graph(graph)
273 }
274 _ => Part::Field(self.next_token_value()?),
275 };
276 let start = vec![start];
277 self.parse_remaining_idiom(ctx, start).await
278 }
279
280 pub(super) async fn parse_dot_part(&mut self, ctx: &mut Stk) -> ParseResult<Part> {
282 let res = match self.peek_kind() {
283 t!("*") => {
284 self.pop_peek();
285 Part::All
286 }
287 t!("@") => {
288 self.pop_peek();
289 Part::RepeatRecurse
290 }
291 t!("{") => {
292 self.pop_peek();
293 ctx.run(|ctx| self.parse_curly_part(ctx)).await?
294 }
295 _ => {
296 let ident: Ident = self.next_token_value()?;
297 if self.eat(t!("(")) {
298 self.parse_function_part(ctx, ident).await?
299 } else {
300 Part::Field(ident)
301 }
302 }
303 };
304 Ok(res)
305 }
306 pub(super) async fn parse_function_part(
307 &mut self,
308 ctx: &mut Stk,
309 name: Ident,
310 ) -> ParseResult<Part> {
311 let args = self.parse_function_args(ctx).await?;
312 Ok(Part::Method(name.0, args))
313 }
314 pub(super) async fn parse_curly_part(&mut self, ctx: &mut Stk) -> ParseResult<Part> {
316 match self.peek_kind() {
317 t!("*") | t!("..") | TokenKind::Digits => self.parse_recurse_part(ctx).await,
318 _ => self.parse_destructure_part(ctx).await,
319 }
320 }
321 pub(super) async fn parse_destructure_part(&mut self, ctx: &mut Stk) -> ParseResult<Part> {
323 let start = self.last_span();
324 let mut destructured: Vec<DestructurePart> = Vec::new();
325 loop {
326 if self.eat(t!("}")) {
327 break;
329 }
330
331 let field: Ident = self.next_token_value()?;
332 let part = match self.peek_kind() {
333 t!(":") => {
334 self.pop_peek();
335 let start = match self.peek_kind() {
336 x if Parser::kind_is_identifier(x) => Part::Field(self.next_token_value()?),
337 t!("->") => {
338 self.pop_peek();
339 let graph = ctx.run(|ctx| self.parse_graph(ctx, Dir::Out)).await?;
340 Part::Graph(graph)
341 }
342 found @ t!("<") => match self.peek_whitespace1().kind {
343 t!("-") => {
344 self.pop_peek();
345 self.pop_peek();
346 let graph = ctx.run(|ctx| self.parse_graph(ctx, Dir::In)).await?;
347 Part::Graph(graph)
348 }
349 t!("->") => {
350 self.pop_peek();
351 self.pop_peek();
352 let graph = ctx.run(|ctx| self.parse_graph(ctx, Dir::Both)).await?;
353 Part::Graph(graph)
354 }
355 _ => {
356 bail!("Unexpected token `{}` expected an identifier, `->`, `<-` or `<->`", found, @self.recent_span());
357 }
358 },
359 found => {
360 bail!("Unexpected token `{}` expected an identifier, `->`, `<-` or `<->`", found, @self.recent_span());
361 }
362 };
363 DestructurePart::Aliased(
364 field,
365 self.parse_remaining_idiom(ctx, vec![start]).await?,
366 )
367 }
368 t!(".") => {
369 self.pop_peek();
370 let found = self.peek_kind();
371 match self.parse_dot_part(ctx).await? {
372 Part::All => DestructurePart::All(field),
373 Part::Destructure(v) => DestructurePart::Destructure(field, v),
374 _ => {
375 bail!("Unexpected token `{}` expected a `*` or a destructuring", found, @self.last_span());
376 }
377 }
378 }
379 _ => DestructurePart::Field(field),
380 };
381
382 destructured.push(part);
383
384 if !self.eat(t!(",")) {
385 self.expect_closing_delimiter(t!("}"), start)?;
387 break;
388 }
389 }
390
391 Ok(Part::Destructure(destructured))
392 }
393 pub(super) fn parse_recurse_inner(&mut self) -> ParseResult<Recurse> {
395 let min = if matches!(self.peek().kind, TokenKind::Digits) {
396 Some(self.next_token_value::<u32>()?)
397 } else {
398 None
399 };
400
401 match (self.eat_whitespace(t!("..")), min) {
402 (true, _) => (),
403 (false, Some(v)) => {
404 return Ok(Recurse::Fixed(v));
405 }
406 _ => {
407 let found = self.next().kind;
408 bail!("Unexpected token `{}` expected an integer or ..", found, @self.last_span());
409 }
410 }
411
412 let max = if matches!(self.peek_whitespace().kind, TokenKind::Digits) {
414 Some(self.next_token_value::<u32>()?)
415 } else {
416 None
417 };
418
419 Ok(Recurse::Range(min, max))
420 }
421 pub(super) async fn parse_recurse_instruction(
423 &mut self,
424 ctx: &mut Stk,
425 ) -> ParseResult<Option<RecurseInstruction>> {
426 let instruction = parse_option!(
427 self,
428 "instruction",
429 "path" => {
430 let mut inclusive = false;
431 loop {
432 parse_option!(
433 self,
434 "option",
435 "inclusive" => inclusive = true,
436 _ => break
437 );
438 };
439
440 Some(RecurseInstruction::Path { inclusive })
441 },
442 "collect" => {
443 let mut inclusive = false;
444 loop {
445 parse_option!(
446 self,
447 "option",
448 "inclusive" => inclusive = true,
449 _ => break
450 );
451 };
452
453 Some(RecurseInstruction::Collect { inclusive })
454 },
455 "shortest" => {
456 expected!(self, t!("="));
457 let token = self.peek();
458 let expects = match token.kind {
459 TokenKind::Parameter => {
460 Value::from(self.next_token_value::<Param>()?)
461 },
462 x if Parser::kind_is_identifier(x) => {
463 Value::from(self.parse_thing(ctx).await?)
464 }
465 _ => {
466 unexpected!(self, token, "a param or thing");
467 }
468 };
469 let mut inclusive = false;
470 loop {
471 parse_option!(
472 self,
473 "option",
474 "inclusive" => inclusive = true,
475 _ => break
476 );
477 };
478
479 Some(RecurseInstruction::Shortest { expects, inclusive })
480 },
481 _ => None
482 );
483
484 Ok(instruction)
485 }
486 pub(super) async fn parse_recurse_part(&mut self, ctx: &mut Stk) -> ParseResult<Part> {
488 let start = self.last_span();
489 let recurse = self.parse_recurse_inner()?;
490 let instruction = self.parse_recurse_instruction(ctx).await?;
491 self.expect_closing_delimiter(t!("}"), start)?;
492
493 let nest = if self.eat(t!("(")) {
494 let start = self.last_span();
495 let idiom = self.parse_remaining_idiom(ctx, vec![]).await?;
496 self.expect_closing_delimiter(t!(")"), start)?;
497 Some(idiom)
498 } else {
499 None
500 };
501
502 Ok(Part::Recurse(recurse, nest, instruction))
503 }
504 pub(super) async fn parse_bracket_part(
506 &mut self,
507 ctx: &mut Stk,
508 start: Span,
509 ) -> ParseResult<Part> {
510 let peek = self.peek();
511 let res = match peek.kind {
512 t!("*") => {
513 self.pop_peek();
514 Part::All
515 }
516 t!("$") => {
517 self.pop_peek();
518 Part::Last
519 }
520 t!("?") | t!("WHERE") => {
521 self.pop_peek();
522 let value = ctx.run(|ctx| self.parse_value_field(ctx)).await?;
523 Part::Where(value)
524 }
525 _ => {
526 let value = ctx.run(|ctx| self.parse_value_inherit(ctx)).await?;
527 if let Value::Number(x) = value {
528 Part::Index(x)
529 } else {
530 Part::Value(value)
531 }
532 }
533 };
534 self.expect_closing_delimiter(t!("]"), start)?;
535 Ok(res)
536 }
537
538 pub(super) async fn parse_basic_idiom(&mut self, ctx: &mut Stk) -> ParseResult<Idiom> {
543 let start = self.next_token_value::<Ident>()?;
544 let mut parts = vec![Part::Field(start)];
545 loop {
546 let token = self.peek();
547 let part = match token.kind {
548 t!(".") => {
549 self.pop_peek();
550 self.parse_dot_part(ctx).await?
551 }
552 t!("[") => {
553 self.pop_peek();
554 let peek = self.peek();
555 let res = match peek.kind {
556 t!("*") => {
557 self.pop_peek();
558 Part::All
559 }
560 t!("$") => {
561 self.pop_peek();
562 Part::Last
563 }
564 TokenKind::Digits | t!("+") | TokenKind::Glued(Glued::Number) => {
565 let number = self.next_token_value()?;
566 Part::Index(number)
567 }
568 t!("-") => {
569 let peek_digit = self.peek_whitespace1();
570 if let TokenKind::Digits = peek_digit.kind {
571 let span = self.recent_span().covers(peek_digit.span);
572 bail!("Unexpected token `-` expected $, *, or a number", @span => "an index can't be negative");
573 }
574 unexpected!(self, peek, "$, * or a number");
575 }
576 _ => unexpected!(self, peek, "$, * or a number"),
577 };
578 self.expect_closing_delimiter(t!("]"), token.span)?;
579 res
580 }
581 _ => break,
582 };
583 parts.push(part);
584 }
585 Ok(Idiom(parts))
586 }
587
588 pub(super) async fn parse_local_idiom(&mut self, ctx: &mut Stk) -> ParseResult<Idiom> {
594 let start = self.next_token_value()?;
595 let mut parts = vec![Part::Field(start)];
596 loop {
597 let token = self.peek();
598 let part = match token.kind {
599 t!(".") => {
600 self.pop_peek();
601 self.parse_dot_part(ctx).await?
602 }
603 t!("[") => {
604 self.pop_peek();
605 let token = self.peek();
606 let res = match token.kind {
607 t!("*") => {
608 self.pop_peek();
609 Part::All
610 }
611 TokenKind::Digits | t!("+") | TokenKind::Glued(Glued::Number) => {
612 let number = self.next_token_value()?;
613 Part::Index(number)
614 }
615 t!("-") => {
616 let peek_digit = self.peek_whitespace1();
617 if let TokenKind::Digits = peek_digit.kind {
618 let span = self.recent_span().covers(peek_digit.span);
619 bail!("Unexpected token `-` expected $, *, or a number", @span => "an index can't be negative");
620 }
621 unexpected!(self, token, "$, * or a number");
622 }
623 _ => unexpected!(self, token, "$, * or a number"),
624 };
625 self.expect_closing_delimiter(t!("]"), token.span)?;
626 res
627 }
628 _ => break,
629 };
630
631 parts.push(part);
632 }
633
634 if self.eat(t!("...")) {
635 let token = self.peek();
636 if let t!(".") | t!("[") = token.kind {
637 bail!("Unexpected token `...` expected a local idiom to end.",
638 @token.span => "Flattening can only be done at the end of a local idiom")
639 }
640 parts.push(Part::Flatten);
641 }
642
643 Ok(Idiom(parts))
644 }
645
646 pub(super) async fn parse_what_list(&mut self, ctx: &mut Stk) -> ParseResult<Vec<Value>> {
651 let mut res = vec![self.parse_what_value(ctx).await?];
652 while self.eat(t!(",")) {
653 res.push(self.parse_what_value(ctx).await?)
654 }
655 Ok(res)
656 }
657
658 pub(super) async fn parse_what_value(&mut self, ctx: &mut Stk) -> ParseResult<Value> {
663 let start = self.parse_what_primary(ctx).await?;
664 if start.can_start_idiom() && self.peek_continues_idiom() {
665 let start = match start {
666 Value::Table(Table(x)) => vec![Part::Field(Ident(x))],
667 Value::Idiom(Idiom(x)) => x,
668 x => vec![Part::Start(x)],
669 };
670
671 let idiom = self.parse_remaining_value_idiom(ctx, start).await?;
672 Ok(idiom)
673 } else {
674 Ok(start)
675 }
676 }
677
678 pub(super) async fn parse_graph(&mut self, ctx: &mut Stk, dir: Dir) -> ParseResult<Graph> {
684 let token = self.peek();
685 match token.kind {
686 t!("?") => {
687 self.pop_peek();
688 Ok(Graph {
689 dir,
690 ..Default::default()
691 })
692 }
693 t!("(") => {
694 let span = self.pop_peek().span;
695 let expr = if self.eat(t!("SELECT")) {
696 let before = self.peek().span;
697 let expr = self.parse_fields(ctx).await?;
698 let fields_span = before.covers(self.last_span());
699 expected!(self, t!("FROM"));
700 Some((expr, fields_span))
701 } else {
702 None
703 };
704
705 let token = self.peek();
706 let what = match token.kind {
707 t!("?") => {
708 self.pop_peek();
709 Tables::default()
710 }
711 x if Self::kind_is_identifier(x) => {
712 let table = self.next_token_value().unwrap();
715 let mut tables = Tables(vec![table]);
716 while self.eat(t!(",")) {
717 tables.0.push(self.next_token_value()?);
718 }
719 tables
720 }
721 _ => unexpected!(self, token, "`?` or an identifier"),
722 };
723
724 let cond = self.try_parse_condition(ctx).await?;
725 let (split, group, order) = if let Some((ref expr, fields_span)) = expr {
726 let split = self.try_parse_split(ctx, expr, fields_span).await?;
727 let group = self.try_parse_group(ctx, expr, fields_span).await?;
728 let order = self.try_parse_orders(ctx, expr, fields_span).await?;
729 (split, group, order)
730 } else {
731 (None, None, None)
732 };
733
734 let (limit, start) = if let t!("START") = self.peek_kind() {
735 let start = self.try_parse_start(ctx).await?;
736 let limit = self.try_parse_limit(ctx).await?;
737 (limit, start)
738 } else {
739 let limit = self.try_parse_limit(ctx).await?;
740 let start = self.try_parse_start(ctx).await?;
741 (limit, start)
742 };
743
744 let alias = if self.eat(t!("AS")) {
745 Some(self.parse_plain_idiom(ctx).await?)
746 } else {
747 None
748 };
749
750 self.expect_closing_delimiter(t!(")"), span)?;
751
752 Ok(Graph {
753 dir,
754 what,
755 cond,
756 alias,
757 expr: expr.map(|(x, _)| x),
758 split,
759 group,
760 order,
761 limit,
762 start,
763 ..Default::default()
764 })
765 }
766 x if Self::kind_is_identifier(x) => {
767 let table = self.next_token_value().unwrap();
770 Ok(Graph {
771 dir,
772 what: Tables(vec![table]),
773 ..Default::default()
774 })
775 }
776 _ => unexpected!(self, token, "`?`, `(` or an identifier"),
777 }
778 }
779}
780
781#[cfg(test)]
782mod tests {
783 use crate::sql::{Expression, Id, Number, Object, Operator, Param, Strand, Thing};
784 use crate::syn::Parse;
785
786 use super::*;
787
788 #[test]
789 fn graph_in() {
790 let sql = "<-likes";
791 let out = Value::parse(sql);
792 assert_eq!("<-likes", format!("{}", out));
793 }
794
795 #[test]
796 fn graph_out() {
797 let sql = "->likes";
798 let out = Value::parse(sql);
799 assert_eq!("->likes", format!("{}", out));
800 }
801
802 #[test]
803 fn graph_both() {
804 let sql = "<->likes";
805 let out = Value::parse(sql);
806 assert_eq!("<->likes", format!("{}", out));
807 }
808
809 #[test]
810 fn graph_multiple() {
811 let sql = "->(likes, follows)";
812 let out = Value::parse(sql);
813 assert_eq!("->(likes, follows)", format!("{}", out));
814 }
815
816 #[test]
817 fn graph_aliases() {
818 let sql = "->(likes, follows AS connections)";
819 let out = Value::parse(sql);
820 assert_eq!("->(likes, follows AS connections)", format!("{}", out));
821 }
822
823 #[test]
824 fn graph_conditions() {
825 let sql = "->(likes, follows WHERE influencer = true)";
826 let out = Value::parse(sql);
827 assert_eq!("->(likes, follows WHERE influencer = true)", format!("{}", out));
828 }
829
830 #[test]
831 fn graph_conditions_aliases() {
832 let sql = "->(likes, follows WHERE influencer = true AS connections)";
833 let out = Value::parse(sql);
834 assert_eq!("->(likes, follows WHERE influencer = true AS connections)", format!("{}", out));
835 }
836
837 #[test]
838 fn idiom_normal() {
839 let sql = "test";
840 let out = Value::parse(sql);
841 assert_eq!("test", format!("{}", out));
842 assert_eq!(out, Value::from(Idiom(vec![Part::from("test")])));
843 }
844
845 #[test]
846 fn idiom_quoted_backtick() {
847 let sql = "`test`";
848 let out = Value::parse(sql);
849 assert_eq!("test", format!("{}", out));
850 assert_eq!(out, Value::from(Idiom(vec![Part::from("test")])));
851 }
852
853 #[test]
854 fn idiom_quoted_brackets() {
855 let sql = "⟨test⟩";
856 let out = Value::parse(sql);
857 assert_eq!("test", format!("{}", out));
858 assert_eq!(out, Value::from(Idiom(vec![Part::from("test")])));
859 }
860
861 #[test]
862 fn idiom_nested() {
863 let sql = "test.temp";
864 let out = Value::parse(sql);
865 assert_eq!("test.temp", format!("{}", out));
866 assert_eq!(out, Value::from(Idiom(vec![Part::from("test"), Part::from("temp")])));
867 }
868
869 #[test]
870 fn idiom_nested_quoted() {
871 let sql = "test.`some key`";
872 let out = Value::parse(sql);
873 assert_eq!("test.`some key`", format!("{}", out));
874 assert_eq!(out, Value::from(Idiom(vec![Part::from("test"), Part::from("some key")])));
875 }
876
877 #[test]
878 fn idiom_nested_array_all() {
879 let sql = "test.temp[*]";
880 let out = Value::parse(sql);
881 assert_eq!("test.temp[*]", format!("{}", out));
882 assert_eq!(
883 out,
884 Value::from(Idiom(vec![Part::from("test"), Part::from("temp"), Part::All]))
885 );
886 }
887
888 #[test]
889 fn idiom_nested_array_last() {
890 let sql = "test.temp[$]";
891 let out = Value::parse(sql);
892 assert_eq!("test.temp[$]", format!("{}", out));
893 assert_eq!(
894 out,
895 Value::from(Idiom(vec![Part::from("test"), Part::from("temp"), Part::Last]))
896 );
897 }
898
899 #[test]
900 fn idiom_nested_array_value() {
901 let sql = "test.temp[*].text";
902 let out = Value::parse(sql);
903 assert_eq!("test.temp[*].text", format!("{}", out));
904 assert_eq!(
905 out,
906 Value::from(Idiom(vec![
907 Part::from("test"),
908 Part::from("temp"),
909 Part::All,
910 Part::from("text")
911 ]))
912 );
913 }
914
915 #[test]
916 fn idiom_nested_array_question() {
917 let sql = "test.temp[? test = true].text";
918 let out = Value::parse(sql);
919 assert_eq!("test.temp[WHERE test = true].text", format!("{}", out));
920 assert_eq!(
921 out,
922 Value::from(Idiom(vec![
923 Part::from("test"),
924 Part::from("temp"),
925 Part::Where(Value::Expression(Box::new(Expression::Binary {
926 l: Value::Idiom(Idiom(vec![Part::Field(Ident("test".to_string()))])),
927 o: Operator::Equal,
928 r: Value::Bool(true)
929 }))),
930 Part::from("text")
931 ]))
932 );
933 }
934
935 #[test]
936 fn idiom_nested_array_condition() {
937 let sql = "test.temp[WHERE test = true].text";
938 let out = Value::parse(sql);
939 assert_eq!("test.temp[WHERE test = true].text", format!("{}", out));
940 assert_eq!(
941 out,
942 Value::from(Idiom(vec![
943 Part::from("test"),
944 Part::from("temp"),
945 Part::Where(Value::Expression(Box::new(Expression::Binary {
946 l: Value::Idiom(Idiom(vec![Part::Field(Ident("test".to_string()))])),
947 o: Operator::Equal,
948 r: Value::Bool(true)
949 }))),
950 Part::from("text")
951 ]))
952 );
953 }
954
955 #[test]
956 fn idiom_start_param_local_field() {
957 let sql = "$test.temporary[0].embedded…";
958 let out = Value::parse(sql);
959 assert_eq!("$test.temporary[0].embedded…", format!("{}", out));
960 assert_eq!(
961 out,
962 Value::from(Idiom(vec![
963 Part::Start(Param::from("test").into()),
964 Part::from("temporary"),
965 Part::Index(Number::Int(0)),
966 Part::from("embedded"),
967 Part::Flatten,
968 ]))
969 );
970 }
971
972 #[test]
973 fn idiom_start_thing_remote_traversal() {
974 let sql = "person:test.friend->like->person";
975 let out = Value::parse(sql);
976 assert_eq!("person:test.friend->like->person", format!("{}", out));
977 assert_eq!(
978 out,
979 Value::from(Idiom(vec![
980 Part::Start(Thing::from(("person", "test")).into()),
981 Part::from("friend"),
982 Part::Graph(Graph {
983 dir: Dir::Out,
984 what: Table::from("like").into(),
985 ..Default::default()
986 }),
987 Part::Graph(Graph {
988 dir: Dir::Out,
989 what: Table::from("person").into(),
990 ..Default::default()
991 }),
992 ]))
993 );
994 }
995
996 #[test]
997 fn part_all() {
998 let sql = "{}[*]";
999 let out = Value::parse(sql);
1000 assert_eq!("{ }[*]", format!("{}", out));
1001 assert_eq!(
1002 out,
1003 Value::from(Idiom(vec![Part::Start(Value::from(Object::default())), Part::All]))
1004 );
1005 }
1006
1007 #[test]
1008 fn part_last() {
1009 let sql = "{}[$]";
1010 let out = Value::parse(sql);
1011 assert_eq!("{ }[$]", format!("{}", out));
1012 assert_eq!(
1013 out,
1014 Value::from(Idiom(vec![Part::Start(Value::from(Object::default())), Part::Last]))
1015 );
1016 }
1017
1018 #[test]
1019 fn part_param() {
1020 let sql = "{}[$param]";
1021 let out = Value::parse(sql);
1022 assert_eq!("{ }[$param]", format!("{}", out));
1023 assert_eq!(
1024 out,
1025 Value::from(Idiom(vec![
1026 Part::Start(Value::from(Object::default())),
1027 Part::Value(Value::Param(Param::from("param")))
1028 ]))
1029 );
1030 }
1031
1032 #[test]
1033 fn part_flatten() {
1034 let sql = "{}...";
1035 let out = Value::parse(sql);
1036 assert_eq!("{ }…", format!("{}", out));
1037 assert_eq!(
1038 out,
1039 Value::from(Idiom(vec![Part::Start(Value::from(Object::default())), Part::Flatten]))
1040 );
1041 }
1042
1043 #[test]
1044 fn part_flatten_ellipsis() {
1045 let sql = "{}…";
1046 let out = Value::parse(sql);
1047 assert_eq!("{ }…", format!("{}", out));
1048 assert_eq!(
1049 out,
1050 Value::from(Idiom(vec![Part::Start(Value::from(Object::default())), Part::Flatten]))
1051 );
1052 }
1053
1054 #[test]
1055 fn part_number() {
1056 let sql = "{}[0]";
1057 let out = Value::parse(sql);
1058 assert_eq!("{ }[0]", format!("{}", out));
1059 assert_eq!(
1060 out,
1061 Value::from(Idiom(vec![
1062 Part::Start(Value::from(Object::default())),
1063 Part::Index(Number::from(0))
1064 ]))
1065 );
1066 }
1067
1068 #[test]
1069 fn part_expression_question() {
1070 let sql = "{}[?test = true]";
1071 let out = Value::parse(sql);
1072 assert_eq!("{ }[WHERE test = true]", format!("{}", out));
1073 assert_eq!(
1074 out,
1075 Value::from(Idiom(vec![
1076 Part::Start(Value::from(Object::default())),
1077 Part::Where(Value::Expression(Box::new(Expression::Binary {
1078 l: Value::Idiom(Idiom(vec![Part::Field(Ident("test".to_string()))])),
1079 o: Operator::Equal,
1080 r: Value::Bool(true)
1081 }))),
1082 ]))
1083 );
1084 }
1085
1086 #[test]
1087 fn part_expression_condition() {
1088 let sql = "{}[WHERE test = true]";
1089 let out = Value::parse(sql);
1090 assert_eq!("{ }[WHERE test = true]", format!("{}", out));
1091 assert_eq!(
1092 out,
1093 Value::from(Idiom(vec![
1094 Part::Start(Value::from(Object::default())),
1095 Part::Where(Value::Expression(Box::new(Expression::Binary {
1096 l: Value::Idiom(Idiom(vec![Part::Field(Ident("test".to_string()))])),
1097 o: Operator::Equal,
1098 r: Value::Bool(true)
1099 }))),
1100 ]))
1101 );
1102 }
1103
1104 #[test]
1105 fn idiom_thing_number() {
1106 let sql = "test:1.foo";
1107 let out = Value::parse(sql);
1108 assert_eq!(
1109 out,
1110 Value::from(Idiom(vec![
1111 Part::Start(Value::Thing(Thing {
1112 tb: "test".to_owned(),
1113 id: Id::from(1),
1114 })),
1115 Part::from("foo"),
1116 ]))
1117 );
1118 }
1119
1120 #[test]
1121 fn idiom_thing_index() {
1122 let sql = "test:1['foo']";
1123 let out = Value::parse(sql);
1124 assert_eq!(
1125 out,
1126 Value::from(Idiom(vec![
1127 Part::Start(Value::Thing(Thing {
1128 tb: "test".to_owned(),
1129 id: Id::from(1),
1130 })),
1131 Part::Value(Value::Strand(Strand("foo".to_owned()))),
1132 ]))
1133 );
1134 }
1135
1136 #[test]
1137 fn idiom_thing_all() {
1138 let sql = "test:1.*";
1139 let out = Value::parse(sql);
1140 assert_eq!(
1141 out,
1142 Value::from(Idiom(vec![
1143 Part::Start(Value::Thing(Thing {
1144 tb: "test".to_owned(),
1145 id: Id::from(1),
1146 })),
1147 Part::All
1148 ]))
1149 );
1150 }
1151}