gqlite 1.8.0 → 1.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/Cargo.toml +8 -8
- data/ext/db-index/Cargo.toml +2 -2
- data/ext/gqlitedb/Cargo.toml +0 -2
- data/ext/gqlitedb/src/aggregators.rs +28 -0
- data/ext/gqlitedb/src/compiler/expression_analyser.rs +33 -0
- data/ext/gqlitedb/src/compiler/variables_manager.rs +111 -11
- data/ext/gqlitedb/src/compiler.rs +506 -48
- data/ext/gqlitedb/src/connection.rs +14 -2
- data/ext/gqlitedb/src/consts.rs +1 -1
- data/ext/gqlitedb/src/error.rs +31 -0
- data/ext/gqlitedb/src/interpreter/evaluators.rs +153 -331
- data/ext/gqlitedb/src/interpreter/instructions.rs +77 -0
- data/ext/gqlitedb/src/interpreter/mod.rs +1 -0
- data/ext/gqlitedb/src/interpreter/path/bfs.rs +494 -0
- data/ext/gqlitedb/src/interpreter/path/dfs.rs +267 -0
- data/ext/gqlitedb/src/interpreter/path/group.rs +418 -0
- data/ext/gqlitedb/src/interpreter/path.rs +542 -0
- data/ext/gqlitedb/src/planner.rs +231 -6
- data/ext/gqlitedb/src/query_result.rs +19 -4
- data/ext/gqlitedb/src/store/redb.rs +1 -1
- data/ext/gqlitedb/src/tests/compiler.rs +2454 -1
- data/ext/gqlitedb/src/tests/connection/postgres.rs +22 -0
- data/ext/gqlitedb/src/tests/connection/redb.rs +24 -0
- data/ext/gqlitedb/src/tests/connection/sqlite.rs +16 -0
- data/ext/gqlitedb/src/tests/connection.rs +101 -0
- data/ext/gqlitedb/src/tests/evaluators.rs +2206 -1
- data/ext/gqlitedb/src/tests/parser.rs +1225 -0
- data/ext/gqlitedb/src/tests/planner.rs +433 -2
- data/ext/gqlitedb/src/tests/store/vector_index/postgres.rs +5 -5
- data/ext/gqlitedb/src/tests/store/vector_index/sqlite.rs +3 -1
- data/ext/gqlitedb/src/tests/templates/ast.rs +294 -1
- data/ext/gqlitedb/src/tests/templates/programs.rs +318 -0
- data/ext/gqliterb/Cargo.toml +0 -1
- data/ext/gqlparser/src/oc/ast.rs +72 -3
- data/ext/gqlparser/src/oc/error.rs +18 -0
- data/ext/gqlparser/src/oc/lexer.rs +157 -2
- data/ext/gqlparser/src/oc/parser/tests.rs +735 -29
- data/ext/gqlparser/src/oc/parser.rs +1312 -182
- data/ext/gqlparser/src/oc/string.rs +172 -0
- data/ext/gqlparser/src/oc.rs +1 -0
- data/ext/graphcore/src/value/value_map.rs +2 -2
- data/ext/graphcore/src/value.rs +13 -1
- metadata +6 -2
- data/ext/gqlitedb/src/parser/gql.pest +0 -198
|
@@ -73,6 +73,7 @@ pub(crate) fn create_named_node() -> Program
|
|
|
73
73
|
limit: None,
|
|
74
74
|
skip: None,
|
|
75
75
|
order_by: vec![],
|
|
76
|
+
distinct: false,
|
|
76
77
|
},
|
|
77
78
|
variables_sizes: create_variable_size(2, 0),
|
|
78
79
|
},
|
|
@@ -138,6 +139,7 @@ pub(crate) fn create_named_node_double_return() -> Program
|
|
|
138
139
|
limit: None,
|
|
139
140
|
skip: None,
|
|
140
141
|
order_by: vec![],
|
|
142
|
+
distinct: false,
|
|
141
143
|
},
|
|
142
144
|
variables_sizes: create_variable_size(3, 0),
|
|
143
145
|
},
|
|
@@ -166,6 +168,7 @@ pub(crate) fn double_with_return() -> Program
|
|
|
166
168
|
limit: None,
|
|
167
169
|
skip: None,
|
|
168
170
|
order_by: vec![],
|
|
171
|
+
distinct: false,
|
|
169
172
|
},
|
|
170
173
|
variables_sizes: create_variable_size(2, 0),
|
|
171
174
|
},
|
|
@@ -187,6 +190,7 @@ pub(crate) fn double_with_return() -> Program
|
|
|
187
190
|
limit: None,
|
|
188
191
|
skip: None,
|
|
189
192
|
order_by: vec![],
|
|
193
|
+
distinct: false,
|
|
190
194
|
},
|
|
191
195
|
variables_sizes: create_variable_size(4, 0),
|
|
192
196
|
},
|
|
@@ -204,6 +208,7 @@ pub(crate) fn double_with_return() -> Program
|
|
|
204
208
|
limit: None,
|
|
205
209
|
skip: None,
|
|
206
210
|
order_by: vec![],
|
|
211
|
+
distinct: false,
|
|
207
212
|
},
|
|
208
213
|
variables_sizes: create_variable_size(2, 0),
|
|
209
214
|
},
|
|
@@ -239,6 +244,7 @@ pub(crate) fn unwind() -> Program
|
|
|
239
244
|
limit: None,
|
|
240
245
|
skip: None,
|
|
241
246
|
order_by: vec![],
|
|
247
|
+
distinct: false,
|
|
242
248
|
},
|
|
243
249
|
variables_sizes: create_variable_size(1, 0),
|
|
244
250
|
},
|
|
@@ -294,6 +300,7 @@ pub(crate) fn match_loop() -> Program
|
|
|
294
300
|
limit: None,
|
|
295
301
|
skip: None,
|
|
296
302
|
order_by: vec![],
|
|
303
|
+
distinct: false,
|
|
297
304
|
},
|
|
298
305
|
variables_sizes: create_variable_size(1, 0),
|
|
299
306
|
},
|
|
@@ -333,6 +340,7 @@ pub(crate) fn optional_match() -> Program
|
|
|
333
340
|
limit: None,
|
|
334
341
|
skip: None,
|
|
335
342
|
order_by: vec![],
|
|
343
|
+
distinct: false,
|
|
336
344
|
},
|
|
337
345
|
variables_sizes: create_variable_size(1, 0),
|
|
338
346
|
},
|
|
@@ -375,6 +383,7 @@ pub(crate) fn match_count(function_manager: &functions::Manager) -> Program
|
|
|
375
383
|
aggregator: function_manager
|
|
376
384
|
.get_aggregator::<error::CompileTimeError>("count")
|
|
377
385
|
.unwrap(),
|
|
386
|
+
distinct: false,
|
|
378
387
|
},
|
|
379
388
|
)],
|
|
380
389
|
},
|
|
@@ -384,6 +393,7 @@ pub(crate) fn match_count(function_manager: &functions::Manager) -> Program
|
|
|
384
393
|
limit: None,
|
|
385
394
|
skip: None,
|
|
386
395
|
order_by: vec![],
|
|
396
|
+
distinct: false,
|
|
387
397
|
},
|
|
388
398
|
variables_sizes: create_variable_size(2, 1),
|
|
389
399
|
},
|
|
@@ -445,6 +455,7 @@ pub(crate) fn aggregation(function_manager: &functions::Manager) -> Program
|
|
|
445
455
|
aggregator: function_manager
|
|
446
456
|
.get_aggregator::<error::CompileTimeError>("count")
|
|
447
457
|
.unwrap(),
|
|
458
|
+
distinct: false,
|
|
448
459
|
},
|
|
449
460
|
)],
|
|
450
461
|
},
|
|
@@ -455,8 +466,315 @@ pub(crate) fn aggregation(function_manager: &functions::Manager) -> Program
|
|
|
455
466
|
limit: None,
|
|
456
467
|
skip: None,
|
|
457
468
|
order_by: vec![],
|
|
469
|
+
distinct: false,
|
|
458
470
|
},
|
|
459
471
|
variables_sizes: create_variable_size(3, 1),
|
|
460
472
|
},
|
|
461
473
|
]
|
|
462
474
|
}
|
|
475
|
+
|
|
476
|
+
/// Program for `MATCH (a) ((n)-[:R]->(m)){1,3} (b) RETURN a, b`.
|
|
477
|
+
/// Uses MatchQuantifiedPath since the group's inner nodes (n, m) differ
|
|
478
|
+
/// from the outer anchors (a, b) - this is an explicit group pattern.
|
|
479
|
+
pub(crate) fn group_single_edge_range() -> Program
|
|
480
|
+
{
|
|
481
|
+
vec![
|
|
482
|
+
Block::Match {
|
|
483
|
+
blocks: vec![BlockMatch::MatchQuantifiedPath {
|
|
484
|
+
source_instructions: vec![
|
|
485
|
+
Instruction::Push {
|
|
486
|
+
value: ValueMap::default().into(),
|
|
487
|
+
},
|
|
488
|
+
Instruction::CreateNodeQuery { labels: vec![] },
|
|
489
|
+
],
|
|
490
|
+
source_variable: Some(0),
|
|
491
|
+
source_filter: vec![],
|
|
492
|
+
destination_variable: Some(1),
|
|
493
|
+
destination_filter: vec![],
|
|
494
|
+
path_variable: None,
|
|
495
|
+
quantifier: 1..3,
|
|
496
|
+
group_instructions: vec![BlockMatch::MatchEdge {
|
|
497
|
+
instructions: vec![
|
|
498
|
+
Instruction::GetVariable { col_id: 2 },
|
|
499
|
+
Instruction::CreateNodeQuery { labels: vec![] },
|
|
500
|
+
Instruction::Push {
|
|
501
|
+
value: ValueMap::default().into(),
|
|
502
|
+
},
|
|
503
|
+
Instruction::CreateNodeQuery { labels: vec![] },
|
|
504
|
+
Instruction::Push {
|
|
505
|
+
value: ValueMap::default().into(),
|
|
506
|
+
},
|
|
507
|
+
Instruction::CreateEdgeQuery {
|
|
508
|
+
labels: vec!["R".into()],
|
|
509
|
+
},
|
|
510
|
+
],
|
|
511
|
+
left_variable: None,
|
|
512
|
+
edge_variable: Some(4),
|
|
513
|
+
right_variable: Some(3),
|
|
514
|
+
path_variable: None,
|
|
515
|
+
filter: vec![],
|
|
516
|
+
directivity: EdgeDirectivity::Directed,
|
|
517
|
+
recursive_range: None,
|
|
518
|
+
}],
|
|
519
|
+
group_variables: vec![2, 4, 3],
|
|
520
|
+
group_terminal_variable: 3,
|
|
521
|
+
group_entry_variable: 2,
|
|
522
|
+
group_where_filter: None,
|
|
523
|
+
path_filter: None,
|
|
524
|
+
strategy: PathStrategy::Dfs,
|
|
525
|
+
}],
|
|
526
|
+
filter: vec![],
|
|
527
|
+
optional: false,
|
|
528
|
+
variables_size: create_variable_size(5, 0),
|
|
529
|
+
},
|
|
530
|
+
Block::Return {
|
|
531
|
+
variables: vec![
|
|
532
|
+
(
|
|
533
|
+
"a".into(),
|
|
534
|
+
RWExpression {
|
|
535
|
+
col_id: 0,
|
|
536
|
+
instructions: vec![Instruction::GetVariable { col_id: 0 }],
|
|
537
|
+
aggregations: Default::default(),
|
|
538
|
+
},
|
|
539
|
+
),
|
|
540
|
+
(
|
|
541
|
+
"b".into(),
|
|
542
|
+
RWExpression {
|
|
543
|
+
col_id: 1,
|
|
544
|
+
instructions: vec![Instruction::GetVariable { col_id: 1 }],
|
|
545
|
+
aggregations: Default::default(),
|
|
546
|
+
},
|
|
547
|
+
),
|
|
548
|
+
],
|
|
549
|
+
filter: vec![],
|
|
550
|
+
modifiers: Modifiers {
|
|
551
|
+
limit: None,
|
|
552
|
+
skip: None,
|
|
553
|
+
order_by: vec![],
|
|
554
|
+
distinct: false,
|
|
555
|
+
},
|
|
556
|
+
variables_sizes: create_variable_size(5, 0),
|
|
557
|
+
},
|
|
558
|
+
]
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/// Program for `MATCH (a) ((n)-[:R1]->(x)-[:R2]->(m)){1,3} (b) RETURN a, b`.
|
|
562
|
+
/// Two-edge group: compiler allocates edge columns (5, 6) for deduplication,
|
|
563
|
+
/// and adds filter logic to second edge to prevent revisiting the same edge.
|
|
564
|
+
pub(crate) fn group_two_edges_range() -> Program
|
|
565
|
+
{
|
|
566
|
+
vec![
|
|
567
|
+
Block::Match {
|
|
568
|
+
blocks: vec![BlockMatch::MatchQuantifiedPath {
|
|
569
|
+
source_instructions: vec![
|
|
570
|
+
Instruction::Push {
|
|
571
|
+
value: ValueMap::default().into(),
|
|
572
|
+
},
|
|
573
|
+
Instruction::CreateNodeQuery { labels: vec![] },
|
|
574
|
+
],
|
|
575
|
+
source_variable: Some(0),
|
|
576
|
+
source_filter: vec![],
|
|
577
|
+
destination_variable: Some(1),
|
|
578
|
+
destination_filter: vec![],
|
|
579
|
+
path_variable: None,
|
|
580
|
+
quantifier: 1..3,
|
|
581
|
+
group_instructions: vec![
|
|
582
|
+
BlockMatch::MatchEdge {
|
|
583
|
+
instructions: vec![
|
|
584
|
+
Instruction::GetVariable { col_id: 2 },
|
|
585
|
+
Instruction::CreateNodeQuery { labels: vec![] },
|
|
586
|
+
Instruction::Push {
|
|
587
|
+
value: ValueMap::default().into(),
|
|
588
|
+
},
|
|
589
|
+
Instruction::CreateNodeQuery { labels: vec![] },
|
|
590
|
+
Instruction::Push {
|
|
591
|
+
value: ValueMap::default().into(),
|
|
592
|
+
},
|
|
593
|
+
Instruction::CreateEdgeQuery {
|
|
594
|
+
labels: vec!["R1".into()],
|
|
595
|
+
},
|
|
596
|
+
],
|
|
597
|
+
left_variable: None,
|
|
598
|
+
edge_variable: Some(4),
|
|
599
|
+
right_variable: Some(3),
|
|
600
|
+
path_variable: None,
|
|
601
|
+
filter: vec![],
|
|
602
|
+
directivity: EdgeDirectivity::Directed,
|
|
603
|
+
recursive_range: None,
|
|
604
|
+
},
|
|
605
|
+
BlockMatch::MatchEdge {
|
|
606
|
+
instructions: vec![
|
|
607
|
+
Instruction::GetVariable { col_id: 3 },
|
|
608
|
+
Instruction::CreateNodeQuery { labels: vec![] },
|
|
609
|
+
Instruction::Push {
|
|
610
|
+
value: ValueMap::default().into(),
|
|
611
|
+
},
|
|
612
|
+
Instruction::CreateNodeQuery { labels: vec![] },
|
|
613
|
+
Instruction::Push {
|
|
614
|
+
value: ValueMap::default().into(),
|
|
615
|
+
},
|
|
616
|
+
Instruction::CreateEdgeQuery {
|
|
617
|
+
labels: vec!["R2".into()],
|
|
618
|
+
},
|
|
619
|
+
],
|
|
620
|
+
left_variable: None,
|
|
621
|
+
edge_variable: Some(6),
|
|
622
|
+
right_variable: Some(5),
|
|
623
|
+
path_variable: None,
|
|
624
|
+
filter: vec![
|
|
625
|
+
Instruction::Duplicate,
|
|
626
|
+
Instruction::GetVariable { col_id: 4 },
|
|
627
|
+
Instruction::NotEqualBinaryOperator,
|
|
628
|
+
Instruction::InverseRot3,
|
|
629
|
+
Instruction::AndBinaryOperator,
|
|
630
|
+
Instruction::Swap,
|
|
631
|
+
],
|
|
632
|
+
directivity: EdgeDirectivity::Directed,
|
|
633
|
+
recursive_range: None,
|
|
634
|
+
},
|
|
635
|
+
],
|
|
636
|
+
group_variables: vec![2, 4, 3, 3, 6, 5],
|
|
637
|
+
group_terminal_variable: 5,
|
|
638
|
+
group_entry_variable: 2,
|
|
639
|
+
group_where_filter: None,
|
|
640
|
+
path_filter: None,
|
|
641
|
+
strategy: PathStrategy::Dfs,
|
|
642
|
+
}],
|
|
643
|
+
filter: vec![],
|
|
644
|
+
optional: false,
|
|
645
|
+
variables_size: create_variable_size(7, 0),
|
|
646
|
+
},
|
|
647
|
+
Block::Return {
|
|
648
|
+
variables: vec![
|
|
649
|
+
(
|
|
650
|
+
"a".into(),
|
|
651
|
+
RWExpression {
|
|
652
|
+
col_id: 0,
|
|
653
|
+
instructions: vec![Instruction::GetVariable { col_id: 0 }],
|
|
654
|
+
aggregations: Default::default(),
|
|
655
|
+
},
|
|
656
|
+
),
|
|
657
|
+
(
|
|
658
|
+
"b".into(),
|
|
659
|
+
RWExpression {
|
|
660
|
+
col_id: 1,
|
|
661
|
+
instructions: vec![Instruction::GetVariable { col_id: 1 }],
|
|
662
|
+
aggregations: Default::default(),
|
|
663
|
+
},
|
|
664
|
+
),
|
|
665
|
+
],
|
|
666
|
+
filter: vec![],
|
|
667
|
+
modifiers: Modifiers {
|
|
668
|
+
limit: None,
|
|
669
|
+
skip: None,
|
|
670
|
+
order_by: vec![],
|
|
671
|
+
distinct: false,
|
|
672
|
+
},
|
|
673
|
+
variables_sizes: create_variable_size(7, 0),
|
|
674
|
+
},
|
|
675
|
+
]
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
/// Program for `MATCH p = SHORTEST 1 (a)-[:R]-+(b) RETURN a, b, length(p)`
|
|
679
|
+
/// Shortest path uses BFS with stop condition. **KEY FINDING**: group_variables
|
|
680
|
+
/// DOES include source/destination columns [1, 2] - this was the open question
|
|
681
|
+
/// in WI721.
|
|
682
|
+
pub(crate) fn shortest_single_edge_full_return(function_manager: &functions::Manager) -> Program
|
|
683
|
+
{
|
|
684
|
+
vec![
|
|
685
|
+
Block::Match {
|
|
686
|
+
blocks: vec![BlockMatch::MatchQuantifiedPath {
|
|
687
|
+
source_instructions: vec![
|
|
688
|
+
Instruction::Push {
|
|
689
|
+
value: ValueMap::default().into(),
|
|
690
|
+
},
|
|
691
|
+
Instruction::CreateNodeQuery { labels: vec![] },
|
|
692
|
+
],
|
|
693
|
+
source_variable: Some(1),
|
|
694
|
+
source_filter: vec![],
|
|
695
|
+
destination_variable: Some(2),
|
|
696
|
+
destination_filter: vec![],
|
|
697
|
+
path_variable: Some(0),
|
|
698
|
+
quantifier: 1..usize::MAX,
|
|
699
|
+
group_instructions: vec![BlockMatch::MatchEdge {
|
|
700
|
+
instructions: vec![
|
|
701
|
+
Instruction::GetVariable { col_id: 1 },
|
|
702
|
+
Instruction::CreateNodeQuery { labels: vec![] },
|
|
703
|
+
Instruction::Push {
|
|
704
|
+
value: ValueMap::default().into(),
|
|
705
|
+
},
|
|
706
|
+
Instruction::CreateNodeQuery { labels: vec![] },
|
|
707
|
+
Instruction::Push {
|
|
708
|
+
value: ValueMap::default().into(),
|
|
709
|
+
},
|
|
710
|
+
Instruction::CreateEdgeQuery {
|
|
711
|
+
labels: vec!["R".into()],
|
|
712
|
+
},
|
|
713
|
+
],
|
|
714
|
+
left_variable: None,
|
|
715
|
+
edge_variable: Some(3),
|
|
716
|
+
right_variable: Some(2),
|
|
717
|
+
path_variable: None,
|
|
718
|
+
filter: vec![],
|
|
719
|
+
directivity: EdgeDirectivity::Undirected,
|
|
720
|
+
recursive_range: None,
|
|
721
|
+
}],
|
|
722
|
+
group_variables: vec![1, 3, 2],
|
|
723
|
+
group_terminal_variable: 2,
|
|
724
|
+
group_entry_variable: 1,
|
|
725
|
+
group_where_filter: None,
|
|
726
|
+
path_filter: None,
|
|
727
|
+
strategy: PathStrategy::Bfs {
|
|
728
|
+
stop_condition: StopCondition::Shortest(vec![Instruction::Push { value: 1.into() }]),
|
|
729
|
+
},
|
|
730
|
+
}],
|
|
731
|
+
filter: vec![],
|
|
732
|
+
optional: false,
|
|
733
|
+
variables_size: create_variable_size(4, 0),
|
|
734
|
+
},
|
|
735
|
+
Block::Return {
|
|
736
|
+
variables: vec![
|
|
737
|
+
(
|
|
738
|
+
"a".into(),
|
|
739
|
+
RWExpression {
|
|
740
|
+
col_id: 1,
|
|
741
|
+
instructions: vec![Instruction::GetVariable { col_id: 1 }],
|
|
742
|
+
aggregations: Default::default(),
|
|
743
|
+
},
|
|
744
|
+
),
|
|
745
|
+
(
|
|
746
|
+
"b".into(),
|
|
747
|
+
RWExpression {
|
|
748
|
+
col_id: 2,
|
|
749
|
+
instructions: vec![Instruction::GetVariable { col_id: 2 }],
|
|
750
|
+
aggregations: Default::default(),
|
|
751
|
+
},
|
|
752
|
+
),
|
|
753
|
+
(
|
|
754
|
+
"length(p)".into(),
|
|
755
|
+
RWExpression {
|
|
756
|
+
col_id: 4,
|
|
757
|
+
instructions: vec![
|
|
758
|
+
Instruction::GetVariable { col_id: 0 },
|
|
759
|
+
Instruction::FunctionCall {
|
|
760
|
+
function: function_manager
|
|
761
|
+
.get_function::<error::CompileTimeError>("length")
|
|
762
|
+
.unwrap(),
|
|
763
|
+
arguments_count: 1,
|
|
764
|
+
},
|
|
765
|
+
],
|
|
766
|
+
aggregations: Default::default(),
|
|
767
|
+
},
|
|
768
|
+
),
|
|
769
|
+
],
|
|
770
|
+
filter: vec![],
|
|
771
|
+
modifiers: Modifiers {
|
|
772
|
+
limit: None,
|
|
773
|
+
skip: None,
|
|
774
|
+
order_by: vec![],
|
|
775
|
+
distinct: false,
|
|
776
|
+
},
|
|
777
|
+
variables_sizes: create_variable_size(5, 0),
|
|
778
|
+
},
|
|
779
|
+
]
|
|
780
|
+
}
|
data/ext/gqliterb/Cargo.toml
CHANGED
data/ext/gqlparser/src/oc/ast.rs
CHANGED
|
@@ -378,11 +378,22 @@ pub struct OrderBy
|
|
|
378
378
|
#[derive(Default, Debug)]
|
|
379
379
|
pub struct Modifiers
|
|
380
380
|
{
|
|
381
|
+
pub distinct: bool,
|
|
381
382
|
pub skip: Option<Expression>,
|
|
382
383
|
pub limit: Option<Expression>,
|
|
383
384
|
pub order_by: Option<OrderBy>,
|
|
384
385
|
}
|
|
385
386
|
|
|
387
|
+
impl Modifiers
|
|
388
|
+
{
|
|
389
|
+
/// Set the distinct field
|
|
390
|
+
pub(crate) fn set_distinct(mut self, distinct: bool) -> Self
|
|
391
|
+
{
|
|
392
|
+
self.distinct = distinct;
|
|
393
|
+
self
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
386
397
|
// Expressions
|
|
387
398
|
|
|
388
399
|
#[derive(Debug, Clone, PartialEq)]
|
|
@@ -411,6 +422,10 @@ pub enum Expression
|
|
|
411
422
|
RelationalIn(Box<RelationalIn>),
|
|
412
423
|
RelationalNotIn(Box<RelationalNotIn>),
|
|
413
424
|
|
|
425
|
+
Contains(Box<Contains>),
|
|
426
|
+
EndsWith(Box<EndsWith>),
|
|
427
|
+
StartsWith(Box<StartsWith>),
|
|
428
|
+
|
|
414
429
|
Addition(Box<Addition>),
|
|
415
430
|
Subtraction(Box<Subtraction>),
|
|
416
431
|
Multiplication(Box<Multiplication>),
|
|
@@ -435,12 +450,13 @@ pub struct OrderByExpression
|
|
|
435
450
|
|
|
436
451
|
// Values: CreatePatterns
|
|
437
452
|
|
|
438
|
-
#[derive(Debug)]
|
|
453
|
+
#[derive(Debug, Clone)]
|
|
439
454
|
pub enum Pattern
|
|
440
455
|
{
|
|
441
456
|
Node(NodePattern),
|
|
442
457
|
Edge(EdgePattern),
|
|
443
458
|
Path(PathPattern),
|
|
459
|
+
QuantifiedPath(QuantifiedPathPattern),
|
|
444
460
|
}
|
|
445
461
|
|
|
446
462
|
macro_rules! create_from_pattern {
|
|
@@ -455,6 +471,7 @@ pub struct NodePattern
|
|
|
455
471
|
pub variable: Option<VariableIdentifier>,
|
|
456
472
|
pub labels: LabelExpression,
|
|
457
473
|
pub properties: Option<Expression>,
|
|
474
|
+
pub predicate: Option<Expression>,
|
|
458
475
|
}
|
|
459
476
|
|
|
460
477
|
create_from_pattern! {NodePattern, Node}
|
|
@@ -468,8 +485,7 @@ pub struct EdgePattern
|
|
|
468
485
|
pub directivity: graphcore::EdgeDirectivity,
|
|
469
486
|
pub labels: LabelExpression,
|
|
470
487
|
pub properties: Option<Expression>,
|
|
471
|
-
|
|
472
|
-
pub recursive_range: Option<std::ops::Range<usize>>,
|
|
488
|
+
pub predicate: Option<Expression>,
|
|
473
489
|
}
|
|
474
490
|
|
|
475
491
|
create_from_pattern! {EdgePattern, Edge}
|
|
@@ -483,6 +499,54 @@ pub struct PathPattern
|
|
|
483
499
|
|
|
484
500
|
create_from_pattern! {PathPattern, Path}
|
|
485
501
|
|
|
502
|
+
#[derive(Debug, Clone)]
|
|
503
|
+
pub struct QuantifiedPathPattern
|
|
504
|
+
{
|
|
505
|
+
/// Path variable, if bound via `p = ...`. `None` for a bare quantified
|
|
506
|
+
/// relationship/group with no path variable.
|
|
507
|
+
pub variable: Option<VariableIdentifier>,
|
|
508
|
+
/// The fixed source node anchor outside the repeated group. For
|
|
509
|
+
/// `(a) ((n)-[r]->(m)){1,5} (b)`, this is `a` (the left outer anchor).
|
|
510
|
+
pub source: NodePattern,
|
|
511
|
+
/// The repeated unit. For the single-edge case (legacy `[*min..max]` or
|
|
512
|
+
/// new `{min,max}`/`*`/`+` syntax — the only case Milestone 2 produces),
|
|
513
|
+
/// this is always exactly one `Pattern::Edge`. Multi-element groups
|
|
514
|
+
/// (Milestone 3) populate more than one element here.
|
|
515
|
+
pub group: Vec<Pattern>,
|
|
516
|
+
/// Optional inline `WHERE` scoped to the group (Milestone 3). Always
|
|
517
|
+
/// `None` for anything Milestone 2 produces. Applied per repetition during
|
|
518
|
+
/// group expansion (genuine groups only, never present on wrapper-promoted patterns).
|
|
519
|
+
pub group_where: Option<Expression>,
|
|
520
|
+
/// Optional `WHERE` for the whole assembled path, from a selector-scoped wrapper.
|
|
521
|
+
/// Evaluated once when a candidate reaches `destination`, distinct from
|
|
522
|
+
/// `group_where`'s per-repetition timing. Only populated by wrapper resolution
|
|
523
|
+
/// in `planner::plan_pattern`; genuine groups never have `path_where`.
|
|
524
|
+
pub path_where: Option<Expression>,
|
|
525
|
+
/// `Some(min..max)` for a repeatable group (everything Milestone 2
|
|
526
|
+
/// produces). `None` is reserved for the pre-filter scoping-wrapper use
|
|
527
|
+
/// (Milestone 5, design §1d) — not constructible yet.
|
|
528
|
+
pub quantifier: Option<std::ops::Range<usize>>,
|
|
529
|
+
/// The fixed destination node anchor outside the repeated group. For
|
|
530
|
+
/// `(a) ((n)-[r]->(m)){1,5} (b)`, this is `b` (the right outer anchor).
|
|
531
|
+
pub destination: NodePattern,
|
|
532
|
+
/// Path selector (`SHORTEST`/`ALL SHORTEST`/etc., design's `PathSelector`
|
|
533
|
+
/// below). Always `PathSelector::All` for anything Milestone 2 produces
|
|
534
|
+
/// — no grammar exists yet to populate the other variants.
|
|
535
|
+
pub selector: PathSelector,
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
create_from_pattern! {QuantifiedPathPattern, QuantifiedPath}
|
|
539
|
+
|
|
540
|
+
#[derive(Debug, Clone)]
|
|
541
|
+
pub enum PathSelector
|
|
542
|
+
{
|
|
543
|
+
All,
|
|
544
|
+
Any,
|
|
545
|
+
AllShortest,
|
|
546
|
+
Shortest(Expression),
|
|
547
|
+
ShortestGroups(Expression),
|
|
548
|
+
}
|
|
549
|
+
|
|
486
550
|
// Label Expression
|
|
487
551
|
#[derive(Debug, Clone, PartialEq)]
|
|
488
552
|
pub enum LabelExpression
|
|
@@ -601,6 +665,7 @@ pub struct FunctionCall
|
|
|
601
665
|
{
|
|
602
666
|
pub name: String,
|
|
603
667
|
pub arguments: Vec<Expression>,
|
|
668
|
+
pub distinct: bool,
|
|
604
669
|
}
|
|
605
670
|
|
|
606
671
|
create_from_expr! {FunctionCall}
|
|
@@ -630,6 +695,10 @@ create_binary_op! {RelationalSuperiorEqual}
|
|
|
630
695
|
create_binary_op! {RelationalIn}
|
|
631
696
|
create_binary_op! {RelationalNotIn}
|
|
632
697
|
|
|
698
|
+
create_binary_op! {Contains}
|
|
699
|
+
create_binary_op! {EndsWith}
|
|
700
|
+
create_binary_op! {StartsWith}
|
|
701
|
+
|
|
633
702
|
create_binary_op! {Addition}
|
|
634
703
|
create_binary_op! {Subtraction}
|
|
635
704
|
create_binary_op! {Multiplication}
|
|
@@ -27,6 +27,9 @@ pub enum ErrorKind
|
|
|
27
27
|
NoSingleRelationshipType,
|
|
28
28
|
MixedUnionOperators,
|
|
29
29
|
VariableNotFound,
|
|
30
|
+
CreatingWithPredicate,
|
|
31
|
+
ConflictingQuantifiers,
|
|
32
|
+
EmptyQuantifiedGroup,
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
pub(crate) fn parse_int_error_to_error_kind(e: std::num::ParseIntError) -> ErrorKind
|
|
@@ -157,6 +160,21 @@ impl std::fmt::Display for Error
|
|
|
157
160
|
"NoSingleRelationshipType: edge patterns must have exactly one relationship type at {}..{}.",
|
|
158
161
|
self.span.start, self.span.end
|
|
159
162
|
),
|
|
163
|
+
ErrorKind::CreatingWithPredicate => write!(
|
|
164
|
+
f,
|
|
165
|
+
"CreatingWithPredicate: CREATE patterns cannot use an inline WHERE predicate at {}..{}.",
|
|
166
|
+
self.span.start, self.span.end
|
|
167
|
+
),
|
|
168
|
+
ErrorKind::ConflictingQuantifiers => write!(
|
|
169
|
+
f,
|
|
170
|
+
"ConflictingQuantifiers: cannot specify both a legacy `[*min..max]` range and a `{{min,max}}`/`*`/`+` quantifier on the same relationship at {}..{}.",
|
|
171
|
+
self.span.start, self.span.end
|
|
172
|
+
),
|
|
173
|
+
ErrorKind::EmptyQuantifiedGroup => write!(
|
|
174
|
+
f,
|
|
175
|
+
"EmptyQuantifiedGroup: a quantified group must contain at least one relationship at {}..{}.",
|
|
176
|
+
self.span.start, self.span.end
|
|
177
|
+
),
|
|
160
178
|
ErrorKind::MixedUnionOperators => write!(
|
|
161
179
|
f,
|
|
162
180
|
"MixedUnionOperators: cannot mix UNION and UNION ALL in the same query at {}..{}.",
|