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
|
@@ -101,6 +101,17 @@ where
|
|
|
101
101
|
assert_eq!(unwrap_nom(input.clone(), parser.parse(input)), exp);
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
fn parse_string<P>(s: &str, mut parser: P, exp: impl Into<String>)
|
|
105
|
+
where
|
|
106
|
+
for<'a> P: nom::Parser<Input<'a>, Output = String, Error = Error>,
|
|
107
|
+
{
|
|
108
|
+
let exp = exp.into();
|
|
109
|
+
let ctx = Context::new(s);
|
|
110
|
+
let tokens = lexer::tokenize(s).expect("tokenization failed");
|
|
111
|
+
let input = Input(&tokens, &ctx);
|
|
112
|
+
assert_eq!(unwrap_nom(input.clone(), parser.parse(input)), exp);
|
|
113
|
+
}
|
|
114
|
+
|
|
104
115
|
#[test]
|
|
105
116
|
fn test_oc_parse_context_variable_identity()
|
|
106
117
|
{
|
|
@@ -131,19 +142,19 @@ fn test_oc_parse_parameter_name()
|
|
|
131
142
|
#[test]
|
|
132
143
|
fn test_oc_parse_string_literal_double_quote()
|
|
133
144
|
{
|
|
134
|
-
|
|
145
|
+
parse_string(r#""hello world""#, string_literal, "hello world");
|
|
135
146
|
}
|
|
136
147
|
|
|
137
148
|
#[test]
|
|
138
149
|
fn test_oc_parse_string_literal_single_quote()
|
|
139
150
|
{
|
|
140
|
-
|
|
141
|
-
|
|
151
|
+
parse_string("'hello world'", string_literal, "hello world");
|
|
152
|
+
parse_string("', as#?lßdj '", string_literal, ", as#?lßdj ");
|
|
142
153
|
}
|
|
143
154
|
#[test]
|
|
144
155
|
fn test_oc_parse_string_literal_backtick()
|
|
145
156
|
{
|
|
146
|
-
|
|
157
|
+
parse_string("`hello`", string_literal, "hello");
|
|
147
158
|
}
|
|
148
159
|
|
|
149
160
|
#[test]
|
|
@@ -307,6 +318,7 @@ fn test_oc_parse_function_call()
|
|
|
307
318
|
ast::Expression::Value(ast::Value { value: 1.into() }),
|
|
308
319
|
ast::Expression::Value(ast::Value { value: 2.into() }),
|
|
309
320
|
],
|
|
321
|
+
distinct: false,
|
|
310
322
|
},
|
|
311
323
|
);
|
|
312
324
|
}
|
|
@@ -320,6 +332,7 @@ fn test_oc_parse_function_call_all()
|
|
|
320
332
|
ast::FunctionCall {
|
|
321
333
|
name: "func".to_string(),
|
|
322
334
|
arguments: vec![ast::Expression::Value(ast::Value { value: 0.into() })],
|
|
335
|
+
distinct: false,
|
|
323
336
|
},
|
|
324
337
|
);
|
|
325
338
|
}
|
|
@@ -384,6 +397,7 @@ fn test_oc_parse_relational_binary_operator()
|
|
|
384
397
|
}
|
|
385
398
|
.into(),
|
|
386
399
|
],
|
|
400
|
+
distinct: false,
|
|
387
401
|
}
|
|
388
402
|
.into(),
|
|
389
403
|
right: ast::FunctionCall {
|
|
@@ -397,6 +411,7 @@ fn test_oc_parse_relational_binary_operator()
|
|
|
397
411
|
}
|
|
398
412
|
.into(),
|
|
399
413
|
],
|
|
414
|
+
distinct: false,
|
|
400
415
|
}
|
|
401
416
|
.into(),
|
|
402
417
|
},
|
|
@@ -406,7 +421,7 @@ fn test_oc_parse_relational_binary_operator()
|
|
|
406
421
|
#[test]
|
|
407
422
|
fn test_oc_parse_node_pattern_simple()
|
|
408
423
|
{
|
|
409
|
-
let actual = parse("(n:Person)", node_pattern);
|
|
424
|
+
let actual = parse("(n:Person)", node_pattern::<AllowUndirected>);
|
|
410
425
|
|
|
411
426
|
let expected = ast::NodePattern {
|
|
412
427
|
variable: ast::VariableIdentifier {
|
|
@@ -416,6 +431,8 @@ fn test_oc_parse_node_pattern_simple()
|
|
|
416
431
|
.into(),
|
|
417
432
|
labels: ast::LabelExpression::String("Person".to_string()),
|
|
418
433
|
properties: None,
|
|
434
|
+
|
|
435
|
+
predicate: None,
|
|
419
436
|
};
|
|
420
437
|
compare_ast(actual, expected);
|
|
421
438
|
}
|
|
@@ -423,7 +440,7 @@ fn test_oc_parse_node_pattern_simple()
|
|
|
423
440
|
#[test]
|
|
424
441
|
fn test_oc_parse_node_pattern_parameters()
|
|
425
442
|
{
|
|
426
|
-
let node = parse("(n {id: 12, name: 'foo'})", node_pattern);
|
|
443
|
+
let node = parse("(n {id: 12, name: 'foo'})", node_pattern::<AllowUndirected>);
|
|
427
444
|
|
|
428
445
|
let expected_node = ast::NodePattern {
|
|
429
446
|
variable: ast::VariableIdentifier {
|
|
@@ -446,11 +463,16 @@ fn test_oc_parse_node_pattern_parameters()
|
|
|
446
463
|
),
|
|
447
464
|
],
|
|
448
465
|
})),
|
|
466
|
+
|
|
467
|
+
predicate: None,
|
|
449
468
|
};
|
|
450
469
|
|
|
451
470
|
compare_ast(node, expected_node);
|
|
452
471
|
|
|
453
|
-
let node = parse(
|
|
472
|
+
let node = parse(
|
|
473
|
+
r#"(n {id: "12", name: "foo"})"#,
|
|
474
|
+
node_pattern::<AllowUndirected>,
|
|
475
|
+
);
|
|
454
476
|
|
|
455
477
|
let expected_node = ast::NodePattern {
|
|
456
478
|
variable: ast::VariableIdentifier {
|
|
@@ -473,6 +495,8 @@ fn test_oc_parse_node_pattern_parameters()
|
|
|
473
495
|
),
|
|
474
496
|
],
|
|
475
497
|
})),
|
|
498
|
+
|
|
499
|
+
predicate: None,
|
|
476
500
|
};
|
|
477
501
|
|
|
478
502
|
compare_ast(node, expected_node);
|
|
@@ -494,6 +518,7 @@ fn test_oc_parse_edge_patterns()
|
|
|
494
518
|
.into(),
|
|
495
519
|
labels: ast::LabelExpression::None,
|
|
496
520
|
properties: None,
|
|
521
|
+
predicate: None,
|
|
497
522
|
},
|
|
498
523
|
variable: ast::VariableIdentifier {
|
|
499
524
|
name: "m".to_string(),
|
|
@@ -508,11 +533,13 @@ fn test_oc_parse_edge_patterns()
|
|
|
508
533
|
.into(),
|
|
509
534
|
labels: ast::LabelExpression::None,
|
|
510
535
|
properties: None,
|
|
536
|
+
predicate: None,
|
|
511
537
|
},
|
|
512
538
|
directivity: graphcore::EdgeDirectivity::Directed,
|
|
513
539
|
labels: ast::LabelExpression::None,
|
|
514
540
|
properties: None,
|
|
515
|
-
|
|
541
|
+
|
|
542
|
+
predicate: None,
|
|
516
543
|
}
|
|
517
544
|
.into(),
|
|
518
545
|
],
|
|
@@ -547,7 +574,8 @@ fn test_oc_parse_edge_recursive_patterns()
|
|
|
547
574
|
"(n)-[m*1..2]->(p)",
|
|
548
575
|
patterns::<AllowUndirected>,
|
|
549
576
|
vec![
|
|
550
|
-
ast::
|
|
577
|
+
ast::QuantifiedPathPattern {
|
|
578
|
+
variable: None,
|
|
551
579
|
source: ast::NodePattern {
|
|
552
580
|
variable: ast::VariableIdentifier {
|
|
553
581
|
name: "n".to_string(),
|
|
@@ -556,12 +584,45 @@ fn test_oc_parse_edge_recursive_patterns()
|
|
|
556
584
|
.into(),
|
|
557
585
|
labels: ast::LabelExpression::None,
|
|
558
586
|
properties: None,
|
|
587
|
+
predicate: None,
|
|
559
588
|
},
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
589
|
+
group: vec![
|
|
590
|
+
ast::EdgePattern {
|
|
591
|
+
source: ast::NodePattern {
|
|
592
|
+
variable: ast::VariableIdentifier {
|
|
593
|
+
name: "n".to_string(),
|
|
594
|
+
id: 0,
|
|
595
|
+
}
|
|
596
|
+
.into(),
|
|
597
|
+
labels: ast::LabelExpression::None,
|
|
598
|
+
properties: None,
|
|
599
|
+
predicate: None,
|
|
600
|
+
},
|
|
601
|
+
variable: ast::VariableIdentifier {
|
|
602
|
+
name: "m".to_string(),
|
|
603
|
+
id: 2,
|
|
604
|
+
}
|
|
605
|
+
.into(),
|
|
606
|
+
destination: ast::NodePattern {
|
|
607
|
+
variable: ast::VariableIdentifier {
|
|
608
|
+
name: "p".to_string(),
|
|
609
|
+
id: 1,
|
|
610
|
+
}
|
|
611
|
+
.into(),
|
|
612
|
+
labels: ast::LabelExpression::None,
|
|
613
|
+
properties: None,
|
|
614
|
+
predicate: None,
|
|
615
|
+
},
|
|
616
|
+
directivity: graphcore::EdgeDirectivity::Directed,
|
|
617
|
+
labels: ast::LabelExpression::None,
|
|
618
|
+
properties: None,
|
|
619
|
+
predicate: None,
|
|
620
|
+
}
|
|
621
|
+
.into(),
|
|
622
|
+
],
|
|
623
|
+
group_where: None,
|
|
624
|
+
path_where: None,
|
|
625
|
+
quantifier: Some(1..2),
|
|
565
626
|
destination: ast::NodePattern {
|
|
566
627
|
variable: ast::VariableIdentifier {
|
|
567
628
|
name: "p".to_string(),
|
|
@@ -570,11 +631,9 @@ fn test_oc_parse_edge_recursive_patterns()
|
|
|
570
631
|
.into(),
|
|
571
632
|
labels: ast::LabelExpression::None,
|
|
572
633
|
properties: None,
|
|
634
|
+
predicate: None,
|
|
573
635
|
},
|
|
574
|
-
|
|
575
|
-
labels: ast::LabelExpression::None,
|
|
576
|
-
properties: None,
|
|
577
|
-
recursive_range: Some(1..2),
|
|
636
|
+
selector: ast::PathSelector::All,
|
|
578
637
|
}
|
|
579
638
|
.into(),
|
|
580
639
|
],
|
|
@@ -748,7 +807,7 @@ fn test_oc_parse_string_literal()
|
|
|
748
807
|
#[test]
|
|
749
808
|
fn test_oc_parse_node_pattern_with_parameter_properties()
|
|
750
809
|
{
|
|
751
|
-
let node = parse("(n $props)", node_pattern);
|
|
810
|
+
let node = parse("(n $props)", node_pattern::<AllowUndirected>);
|
|
752
811
|
|
|
753
812
|
let expr = node.properties.expect("properties expected");
|
|
754
813
|
|
|
@@ -774,6 +833,8 @@ fn test_oc_parse_match_statement_without_where()
|
|
|
774
833
|
.into(),
|
|
775
834
|
labels: ast::LabelExpression::None,
|
|
776
835
|
properties: None,
|
|
836
|
+
|
|
837
|
+
predicate: None,
|
|
777
838
|
}
|
|
778
839
|
.into(),
|
|
779
840
|
],
|
|
@@ -800,6 +861,8 @@ fn test_oc_parse_optional_match_statement_without_where()
|
|
|
800
861
|
.into(),
|
|
801
862
|
labels: ast::LabelExpression::None,
|
|
802
863
|
properties: None,
|
|
864
|
+
|
|
865
|
+
predicate: None,
|
|
803
866
|
}
|
|
804
867
|
.into(),
|
|
805
868
|
],
|
|
@@ -823,6 +886,7 @@ fn test_oc_parse_match_statement_double_edge()
|
|
|
823
886
|
variable: None,
|
|
824
887
|
labels: ast::LabelExpression::None,
|
|
825
888
|
properties: None,
|
|
889
|
+
predicate: None,
|
|
826
890
|
},
|
|
827
891
|
destination: ast::NodePattern {
|
|
828
892
|
variable: Some(ast::VariableIdentifier {
|
|
@@ -831,12 +895,14 @@ fn test_oc_parse_match_statement_double_edge()
|
|
|
831
895
|
}),
|
|
832
896
|
labels: ast::LabelExpression::None,
|
|
833
897
|
properties: None,
|
|
898
|
+
predicate: None,
|
|
834
899
|
},
|
|
835
900
|
variable: None,
|
|
836
901
|
directivity: graphcore::EdgeDirectivity::Directed,
|
|
837
902
|
labels: ast::LabelExpression::None,
|
|
838
903
|
properties: None,
|
|
839
|
-
|
|
904
|
+
|
|
905
|
+
predicate: None,
|
|
840
906
|
}
|
|
841
907
|
.into(),
|
|
842
908
|
ast::EdgePattern {
|
|
@@ -847,17 +913,20 @@ fn test_oc_parse_match_statement_double_edge()
|
|
|
847
913
|
}),
|
|
848
914
|
labels: ast::LabelExpression::None,
|
|
849
915
|
properties: None,
|
|
916
|
+
predicate: None,
|
|
850
917
|
},
|
|
851
918
|
destination: ast::NodePattern {
|
|
852
919
|
variable: None,
|
|
853
920
|
labels: ast::LabelExpression::None,
|
|
854
921
|
properties: None,
|
|
922
|
+
predicate: None,
|
|
855
923
|
},
|
|
856
924
|
variable: None,
|
|
857
925
|
directivity: graphcore::EdgeDirectivity::Directed,
|
|
858
926
|
labels: ast::LabelExpression::None,
|
|
859
927
|
properties: None,
|
|
860
|
-
|
|
928
|
+
|
|
929
|
+
predicate: None,
|
|
861
930
|
}
|
|
862
931
|
.into(),
|
|
863
932
|
],
|
|
@@ -890,6 +959,8 @@ fn test_oc_parse_merge_basic_pattern()
|
|
|
890
959
|
}),
|
|
891
960
|
)],
|
|
892
961
|
})),
|
|
962
|
+
|
|
963
|
+
predicate: None,
|
|
893
964
|
}
|
|
894
965
|
.into(),
|
|
895
966
|
],
|
|
@@ -914,6 +985,8 @@ fn test_oc_parse_merge_with_on_create_set()
|
|
|
914
985
|
}),
|
|
915
986
|
labels: ast::LabelExpression::String("Person".to_string()),
|
|
916
987
|
properties: None,
|
|
988
|
+
|
|
989
|
+
predicate: None,
|
|
917
990
|
}
|
|
918
991
|
.into(),
|
|
919
992
|
],
|
|
@@ -945,6 +1018,8 @@ fn test_oc_parse_merge_with_on_match_set()
|
|
|
945
1018
|
}),
|
|
946
1019
|
labels: ast::LabelExpression::String("Person".to_string()),
|
|
947
1020
|
properties: None,
|
|
1021
|
+
|
|
1022
|
+
predicate: None,
|
|
948
1023
|
}
|
|
949
1024
|
.into(),
|
|
950
1025
|
],
|
|
@@ -979,6 +1054,8 @@ fn test_oc_parse_merge_with_both_on_clauses()
|
|
|
979
1054
|
}),
|
|
980
1055
|
labels: ast::LabelExpression::String("Person".to_string()),
|
|
981
1056
|
properties: None,
|
|
1057
|
+
|
|
1058
|
+
predicate: None,
|
|
982
1059
|
}
|
|
983
1060
|
.into(),
|
|
984
1061
|
],
|
|
@@ -1020,6 +1097,8 @@ fn test_oc_parse_merge_with_both_on_clauses_reversed()
|
|
|
1020
1097
|
}),
|
|
1021
1098
|
labels: ast::LabelExpression::String("Person".to_string()),
|
|
1022
1099
|
properties: None,
|
|
1100
|
+
|
|
1101
|
+
predicate: None,
|
|
1023
1102
|
}
|
|
1024
1103
|
.into(),
|
|
1025
1104
|
],
|
|
@@ -1059,6 +1138,7 @@ fn test_oc_parse_merge_with_edge_pattern()
|
|
|
1059
1138
|
}),
|
|
1060
1139
|
labels: ast::LabelExpression::None,
|
|
1061
1140
|
properties: None,
|
|
1141
|
+
predicate: None,
|
|
1062
1142
|
},
|
|
1063
1143
|
destination: ast::NodePattern {
|
|
1064
1144
|
variable: Some(ast::VariableIdentifier {
|
|
@@ -1067,12 +1147,14 @@ fn test_oc_parse_merge_with_edge_pattern()
|
|
|
1067
1147
|
}),
|
|
1068
1148
|
labels: ast::LabelExpression::None,
|
|
1069
1149
|
properties: None,
|
|
1150
|
+
predicate: None,
|
|
1070
1151
|
},
|
|
1071
1152
|
variable: None,
|
|
1072
1153
|
labels: ast::LabelExpression::String("KNOWS".to_string()),
|
|
1073
1154
|
properties: None,
|
|
1074
1155
|
directivity: graphcore::EdgeDirectivity::Directed,
|
|
1075
|
-
|
|
1156
|
+
|
|
1157
|
+
predicate: None,
|
|
1076
1158
|
}
|
|
1077
1159
|
.into(),
|
|
1078
1160
|
],
|
|
@@ -1099,6 +1181,8 @@ fn test_oc_parse_merge_statement()
|
|
|
1099
1181
|
.into(),
|
|
1100
1182
|
labels: ast::LabelExpression::None,
|
|
1101
1183
|
properties: None,
|
|
1184
|
+
|
|
1185
|
+
predicate: None,
|
|
1102
1186
|
}
|
|
1103
1187
|
.into(),
|
|
1104
1188
|
],
|
|
@@ -1113,6 +1197,8 @@ fn test_oc_parse_merge_statement()
|
|
|
1113
1197
|
variable: None,
|
|
1114
1198
|
labels: ast::LabelExpression::None,
|
|
1115
1199
|
properties: None,
|
|
1200
|
+
|
|
1201
|
+
predicate: None,
|
|
1116
1202
|
}
|
|
1117
1203
|
.into(),
|
|
1118
1204
|
],
|
|
@@ -1127,6 +1213,8 @@ fn test_oc_parse_merge_statement()
|
|
|
1127
1213
|
variable: None,
|
|
1128
1214
|
labels: ast::LabelExpression::String("A".to_string()),
|
|
1129
1215
|
properties: None,
|
|
1216
|
+
|
|
1217
|
+
predicate: None,
|
|
1130
1218
|
}
|
|
1131
1219
|
.into(),
|
|
1132
1220
|
],
|
|
@@ -1144,6 +1232,8 @@ fn test_oc_parse_merge_statement()
|
|
|
1144
1232
|
ast::LabelExpression::String("B".to_string()),
|
|
1145
1233
|
]),
|
|
1146
1234
|
properties: None,
|
|
1235
|
+
|
|
1236
|
+
predicate: None,
|
|
1147
1237
|
}
|
|
1148
1238
|
.into(),
|
|
1149
1239
|
],
|
|
@@ -1164,17 +1254,20 @@ fn test_oc_parse_create_edge_statements()
|
|
|
1164
1254
|
variable: None,
|
|
1165
1255
|
labels: ast::LabelExpression::None,
|
|
1166
1256
|
properties: None,
|
|
1257
|
+
predicate: None,
|
|
1167
1258
|
},
|
|
1168
1259
|
destination: ast::NodePattern {
|
|
1169
1260
|
variable: None,
|
|
1170
1261
|
labels: ast::LabelExpression::None,
|
|
1171
1262
|
properties: None,
|
|
1263
|
+
predicate: None,
|
|
1172
1264
|
},
|
|
1173
1265
|
variable: None,
|
|
1174
1266
|
directivity: graphcore::EdgeDirectivity::Directed,
|
|
1175
1267
|
labels: ast::LabelExpression::String("R".to_string()),
|
|
1176
1268
|
properties: None,
|
|
1177
|
-
|
|
1269
|
+
|
|
1270
|
+
predicate: None,
|
|
1178
1271
|
}
|
|
1179
1272
|
.into(),
|
|
1180
1273
|
],
|
|
@@ -1193,6 +1286,7 @@ fn test_oc_parse_create_edge_statements()
|
|
|
1193
1286
|
}),
|
|
1194
1287
|
labels: ast::LabelExpression::None,
|
|
1195
1288
|
properties: None,
|
|
1289
|
+
predicate: None,
|
|
1196
1290
|
},
|
|
1197
1291
|
destination: ast::NodePattern {
|
|
1198
1292
|
variable: Some(ast::VariableIdentifier {
|
|
@@ -1201,12 +1295,14 @@ fn test_oc_parse_create_edge_statements()
|
|
|
1201
1295
|
}),
|
|
1202
1296
|
labels: ast::LabelExpression::None,
|
|
1203
1297
|
properties: None,
|
|
1298
|
+
predicate: None,
|
|
1204
1299
|
},
|
|
1205
1300
|
variable: None,
|
|
1206
1301
|
directivity: graphcore::EdgeDirectivity::Directed,
|
|
1207
1302
|
labels: ast::LabelExpression::String("FOO".to_string()),
|
|
1208
1303
|
properties: None,
|
|
1209
|
-
|
|
1304
|
+
|
|
1305
|
+
predicate: None,
|
|
1210
1306
|
}
|
|
1211
1307
|
.into(),
|
|
1212
1308
|
],
|
|
@@ -1261,6 +1357,35 @@ fn test_oc_parse_return_n()
|
|
|
1261
1357
|
compare_ast(vec![stmt], vec![exppected_stmt]);
|
|
1262
1358
|
}
|
|
1263
1359
|
|
|
1360
|
+
#[test]
|
|
1361
|
+
fn test_oc_parse_return_distinct_n()
|
|
1362
|
+
{
|
|
1363
|
+
let stmt = parse("RETURN DISTINCT n", return_statement);
|
|
1364
|
+
|
|
1365
|
+
let exppected_stmt = ast::Statement::Return(ast::Return {
|
|
1366
|
+
all: false,
|
|
1367
|
+
expressions: vec![ast::NamedExpression {
|
|
1368
|
+
identifier: ast::VariableIdentifier {
|
|
1369
|
+
name: "n".to_string(),
|
|
1370
|
+
id: 0,
|
|
1371
|
+
},
|
|
1372
|
+
expression: ast::Variable {
|
|
1373
|
+
identifier: ast::VariableIdentifier {
|
|
1374
|
+
name: "n".to_string(),
|
|
1375
|
+
id: 0,
|
|
1376
|
+
},
|
|
1377
|
+
}
|
|
1378
|
+
.into(),
|
|
1379
|
+
}],
|
|
1380
|
+
where_expression: None,
|
|
1381
|
+
modifiers: ast::Modifiers {
|
|
1382
|
+
distinct: true,
|
|
1383
|
+
..Default::default()
|
|
1384
|
+
},
|
|
1385
|
+
});
|
|
1386
|
+
compare_ast(vec![stmt], vec![exppected_stmt]);
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1264
1389
|
#[test]
|
|
1265
1390
|
fn test_oc_parse_return_n_m()
|
|
1266
1391
|
{
|
|
@@ -1411,9 +1536,8 @@ fn test_oc_parse_return_n_modifiers()
|
|
|
1411
1536
|
}],
|
|
1412
1537
|
where_expression: None,
|
|
1413
1538
|
modifiers: ast::Modifiers {
|
|
1414
|
-
order_by: None,
|
|
1415
1539
|
limit: Some(ast::Expression::Value(ast::Value { value: (-1).into() })),
|
|
1416
|
-
|
|
1540
|
+
..Default::default()
|
|
1417
1541
|
},
|
|
1418
1542
|
}),
|
|
1419
1543
|
);
|
|
@@ -1529,6 +1653,7 @@ fn test_oc_parse_modifiers()
|
|
|
1529
1653
|
}),
|
|
1530
1654
|
limit: Some(ast::Expression::Value(ast::Value { value: 4.into() })),
|
|
1531
1655
|
skip: Some(ast::Expression::Value(ast::Value { value: 2.into() })),
|
|
1656
|
+
..Default::default()
|
|
1532
1657
|
},
|
|
1533
1658
|
);
|
|
1534
1659
|
compare_parse_to_ast(
|
|
@@ -1569,15 +1694,15 @@ fn test_oc_parse_modifiers()
|
|
|
1569
1694
|
}),
|
|
1570
1695
|
limit: Some(ast::Expression::Value(ast::Value { value: 4.into() })),
|
|
1571
1696
|
skip: None,
|
|
1697
|
+
..Default::default()
|
|
1572
1698
|
},
|
|
1573
1699
|
);
|
|
1574
1700
|
compare_parse_to_ast(
|
|
1575
1701
|
"LIMIT -1",
|
|
1576
1702
|
modifiers,
|
|
1577
1703
|
ast::Modifiers {
|
|
1578
|
-
order_by: None,
|
|
1579
1704
|
limit: Some(ast::Expression::Value(ast::Value { value: (-1).into() })),
|
|
1580
|
-
|
|
1705
|
+
..Default::default()
|
|
1581
1706
|
},
|
|
1582
1707
|
);
|
|
1583
1708
|
}
|
|
@@ -1638,7 +1763,7 @@ fn test_oc_parse_with_modifiers()
|
|
|
1638
1763
|
],
|
|
1639
1764
|
}),
|
|
1640
1765
|
limit: Some(ast::Expression::Value(ast::Value { value: 4.into() })),
|
|
1641
|
-
|
|
1766
|
+
..Default::default()
|
|
1642
1767
|
},
|
|
1643
1768
|
},
|
|
1644
1769
|
);
|
|
@@ -1682,6 +1807,8 @@ fn test_oc_parse_queries_multiple_statements()
|
|
|
1682
1807
|
.into(),
|
|
1683
1808
|
labels: ast::LabelExpression::None,
|
|
1684
1809
|
properties: None,
|
|
1810
|
+
|
|
1811
|
+
predicate: None,
|
|
1685
1812
|
}
|
|
1686
1813
|
.into(),
|
|
1687
1814
|
],
|
|
@@ -1721,6 +1848,8 @@ fn test_oc_parse_queries_multiple_queries()
|
|
|
1721
1848
|
.into(),
|
|
1722
1849
|
labels: ast::LabelExpression::None,
|
|
1723
1850
|
properties: None,
|
|
1851
|
+
|
|
1852
|
+
predicate: None,
|
|
1724
1853
|
}
|
|
1725
1854
|
.into(),
|
|
1726
1855
|
],
|
|
@@ -1763,6 +1892,8 @@ fn test_oc_parse_query_union_basic()
|
|
|
1763
1892
|
.into(),
|
|
1764
1893
|
labels: ast::LabelExpression::None,
|
|
1765
1894
|
properties: None,
|
|
1895
|
+
|
|
1896
|
+
predicate: None,
|
|
1766
1897
|
}
|
|
1767
1898
|
.into(),
|
|
1768
1899
|
],
|
|
@@ -1783,6 +1914,8 @@ fn test_oc_parse_query_union_basic()
|
|
|
1783
1914
|
.into(),
|
|
1784
1915
|
labels: ast::LabelExpression::None,
|
|
1785
1916
|
properties: None,
|
|
1917
|
+
|
|
1918
|
+
predicate: None,
|
|
1786
1919
|
}
|
|
1787
1920
|
.into(),
|
|
1788
1921
|
],
|
|
@@ -1817,6 +1950,8 @@ fn test_oc_parse_query_union_all_basic()
|
|
|
1817
1950
|
.into(),
|
|
1818
1951
|
labels: ast::LabelExpression::None,
|
|
1819
1952
|
properties: None,
|
|
1953
|
+
|
|
1954
|
+
predicate: None,
|
|
1820
1955
|
}
|
|
1821
1956
|
.into(),
|
|
1822
1957
|
],
|
|
@@ -1837,6 +1972,8 @@ fn test_oc_parse_query_union_all_basic()
|
|
|
1837
1972
|
.into(),
|
|
1838
1973
|
labels: ast::LabelExpression::None,
|
|
1839
1974
|
properties: None,
|
|
1975
|
+
|
|
1976
|
+
predicate: None,
|
|
1840
1977
|
}
|
|
1841
1978
|
.into(),
|
|
1842
1979
|
],
|
|
@@ -1871,6 +2008,8 @@ fn test_oc_parse_query_chained_union_basic()
|
|
|
1871
2008
|
.into(),
|
|
1872
2009
|
labels: ast::LabelExpression::None,
|
|
1873
2010
|
properties: None,
|
|
2011
|
+
|
|
2012
|
+
predicate: None,
|
|
1874
2013
|
}
|
|
1875
2014
|
.into(),
|
|
1876
2015
|
],
|
|
@@ -1891,6 +2030,8 @@ fn test_oc_parse_query_chained_union_basic()
|
|
|
1891
2030
|
.into(),
|
|
1892
2031
|
labels: ast::LabelExpression::None,
|
|
1893
2032
|
properties: None,
|
|
2033
|
+
|
|
2034
|
+
predicate: None,
|
|
1894
2035
|
}
|
|
1895
2036
|
.into(),
|
|
1896
2037
|
],
|
|
@@ -1911,6 +2052,8 @@ fn test_oc_parse_query_chained_union_basic()
|
|
|
1911
2052
|
.into(),
|
|
1912
2053
|
labels: ast::LabelExpression::None,
|
|
1913
2054
|
properties: None,
|
|
2055
|
+
|
|
2056
|
+
predicate: None,
|
|
1914
2057
|
}
|
|
1915
2058
|
.into(),
|
|
1916
2059
|
],
|
|
@@ -1943,6 +2086,8 @@ fn test_oc_parse_query_plain()
|
|
|
1943
2086
|
.into(),
|
|
1944
2087
|
labels: ast::LabelExpression::None,
|
|
1945
2088
|
properties: None,
|
|
2089
|
+
|
|
2090
|
+
predicate: None,
|
|
1946
2091
|
}
|
|
1947
2092
|
.into(),
|
|
1948
2093
|
],
|
|
@@ -2107,6 +2252,19 @@ fn test_oc_call_internal_stats()
|
|
|
2107
2252
|
);
|
|
2108
2253
|
}
|
|
2109
2254
|
|
|
2255
|
+
#[test]
|
|
2256
|
+
fn test_oc_call_db_list_graphs()
|
|
2257
|
+
{
|
|
2258
|
+
compare_parse_to_ast(
|
|
2259
|
+
"CALL gqlite.db.list_graphs()",
|
|
2260
|
+
call_statement,
|
|
2261
|
+
ast::Call {
|
|
2262
|
+
name: "gqlite.db.list_graphs".to_string(),
|
|
2263
|
+
arguments: vec![],
|
|
2264
|
+
},
|
|
2265
|
+
);
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2110
2268
|
#[test]
|
|
2111
2269
|
fn test_oc_parse_match_with_search_basic()
|
|
2112
2270
|
{
|
|
@@ -2127,6 +2285,72 @@ fn test_oc_parse_match_with_search_basic()
|
|
|
2127
2285
|
}
|
|
2128
2286
|
}
|
|
2129
2287
|
|
|
2288
|
+
#[test]
|
|
2289
|
+
fn test_oc_parse_starts_with()
|
|
2290
|
+
{
|
|
2291
|
+
compare_parse_to_ast(
|
|
2292
|
+
"s STARTS WITH 'hello'",
|
|
2293
|
+
expression,
|
|
2294
|
+
ast::StartsWith {
|
|
2295
|
+
left: ast::Variable {
|
|
2296
|
+
identifier: ast::VariableIdentifier {
|
|
2297
|
+
name: "s".to_string(),
|
|
2298
|
+
id: 0,
|
|
2299
|
+
},
|
|
2300
|
+
}
|
|
2301
|
+
.into(),
|
|
2302
|
+
right: ast::Value {
|
|
2303
|
+
value: "hello".into(),
|
|
2304
|
+
}
|
|
2305
|
+
.into(),
|
|
2306
|
+
},
|
|
2307
|
+
);
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
#[test]
|
|
2311
|
+
fn test_oc_parse_ends_with()
|
|
2312
|
+
{
|
|
2313
|
+
compare_parse_to_ast(
|
|
2314
|
+
"s ENDS WITH 'world'",
|
|
2315
|
+
expression,
|
|
2316
|
+
ast::EndsWith {
|
|
2317
|
+
left: ast::Variable {
|
|
2318
|
+
identifier: ast::VariableIdentifier {
|
|
2319
|
+
name: "s".to_string(),
|
|
2320
|
+
id: 0,
|
|
2321
|
+
},
|
|
2322
|
+
}
|
|
2323
|
+
.into(),
|
|
2324
|
+
right: ast::Value {
|
|
2325
|
+
value: "world".into(),
|
|
2326
|
+
}
|
|
2327
|
+
.into(),
|
|
2328
|
+
},
|
|
2329
|
+
);
|
|
2330
|
+
}
|
|
2331
|
+
|
|
2332
|
+
#[test]
|
|
2333
|
+
fn test_oc_parse_contains()
|
|
2334
|
+
{
|
|
2335
|
+
compare_parse_to_ast(
|
|
2336
|
+
"s CONTAINS 'test'",
|
|
2337
|
+
expression,
|
|
2338
|
+
ast::Contains {
|
|
2339
|
+
left: ast::Variable {
|
|
2340
|
+
identifier: ast::VariableIdentifier {
|
|
2341
|
+
name: "s".to_string(),
|
|
2342
|
+
id: 0,
|
|
2343
|
+
},
|
|
2344
|
+
}
|
|
2345
|
+
.into(),
|
|
2346
|
+
right: ast::Value {
|
|
2347
|
+
value: "test".into(),
|
|
2348
|
+
}
|
|
2349
|
+
.into(),
|
|
2350
|
+
},
|
|
2351
|
+
);
|
|
2352
|
+
}
|
|
2353
|
+
|
|
2130
2354
|
#[test]
|
|
2131
2355
|
fn test_oc_parse_match_with_search_and_score()
|
|
2132
2356
|
{
|
|
@@ -2282,3 +2506,485 @@ fn test_oc_parse_create_vector_index_if_not_exists()
|
|
|
2282
2506
|
},
|
|
2283
2507
|
);
|
|
2284
2508
|
}
|
|
2509
|
+
|
|
2510
|
+
#[test]
|
|
2511
|
+
fn test_oc_parse_not_wraps_full_comparison()
|
|
2512
|
+
{
|
|
2513
|
+
compare_parse_to_ast(
|
|
2514
|
+
r#"NOT n.name = "Alice""#,
|
|
2515
|
+
expression,
|
|
2516
|
+
ast::LogicalNegation {
|
|
2517
|
+
value: ast::RelationalEqual {
|
|
2518
|
+
left: ast::MemberAccess {
|
|
2519
|
+
left: ast::Variable {
|
|
2520
|
+
identifier: ast::VariableIdentifier {
|
|
2521
|
+
name: "n".to_string(),
|
|
2522
|
+
id: 0,
|
|
2523
|
+
},
|
|
2524
|
+
}
|
|
2525
|
+
.into(),
|
|
2526
|
+
path: vec!["name".to_string()],
|
|
2527
|
+
}
|
|
2528
|
+
.into(),
|
|
2529
|
+
right: ast::Value {
|
|
2530
|
+
value: "Alice".into(),
|
|
2531
|
+
}
|
|
2532
|
+
.into(),
|
|
2533
|
+
}
|
|
2534
|
+
.into(),
|
|
2535
|
+
},
|
|
2536
|
+
);
|
|
2537
|
+
}
|
|
2538
|
+
|
|
2539
|
+
#[test]
|
|
2540
|
+
fn test_oc_parse_not_and_precedence()
|
|
2541
|
+
{
|
|
2542
|
+
compare_parse_to_ast(
|
|
2543
|
+
"NOT a = 1 AND c = 2",
|
|
2544
|
+
expression,
|
|
2545
|
+
ast::LogicalAnd {
|
|
2546
|
+
left: ast::LogicalNegation {
|
|
2547
|
+
value: ast::RelationalEqual {
|
|
2548
|
+
left: ast::Variable {
|
|
2549
|
+
identifier: ast::VariableIdentifier {
|
|
2550
|
+
name: "a".to_string(),
|
|
2551
|
+
id: 0,
|
|
2552
|
+
},
|
|
2553
|
+
}
|
|
2554
|
+
.into(),
|
|
2555
|
+
right: ast::Value { value: 1i64.into() }.into(),
|
|
2556
|
+
}
|
|
2557
|
+
.into(),
|
|
2558
|
+
}
|
|
2559
|
+
.into(),
|
|
2560
|
+
right: ast::RelationalEqual {
|
|
2561
|
+
left: ast::Variable {
|
|
2562
|
+
identifier: ast::VariableIdentifier {
|
|
2563
|
+
name: "c".to_string(),
|
|
2564
|
+
id: 1,
|
|
2565
|
+
},
|
|
2566
|
+
}
|
|
2567
|
+
.into(),
|
|
2568
|
+
right: ast::Value { value: 2i64.into() }.into(),
|
|
2569
|
+
}
|
|
2570
|
+
.into(),
|
|
2571
|
+
},
|
|
2572
|
+
);
|
|
2573
|
+
}
|
|
2574
|
+
|
|
2575
|
+
#[test]
|
|
2576
|
+
fn test_oc_parse_double_not()
|
|
2577
|
+
{
|
|
2578
|
+
compare_parse_to_ast(
|
|
2579
|
+
"NOT NOT a = 1",
|
|
2580
|
+
expression,
|
|
2581
|
+
ast::LogicalNegation {
|
|
2582
|
+
value: ast::LogicalNegation {
|
|
2583
|
+
value: ast::RelationalEqual {
|
|
2584
|
+
left: ast::Variable {
|
|
2585
|
+
identifier: ast::VariableIdentifier {
|
|
2586
|
+
name: "a".to_string(),
|
|
2587
|
+
id: 0,
|
|
2588
|
+
},
|
|
2589
|
+
}
|
|
2590
|
+
.into(),
|
|
2591
|
+
right: ast::Value { value: 1i64.into() }.into(),
|
|
2592
|
+
}
|
|
2593
|
+
.into(),
|
|
2594
|
+
}
|
|
2595
|
+
.into(),
|
|
2596
|
+
},
|
|
2597
|
+
);
|
|
2598
|
+
}
|
|
2599
|
+
|
|
2600
|
+
#[test]
|
|
2601
|
+
fn test_oc_parse_not_true_still_works()
|
|
2602
|
+
{
|
|
2603
|
+
compare_parse_to_ast(
|
|
2604
|
+
"NOT true",
|
|
2605
|
+
expression,
|
|
2606
|
+
ast::LogicalNegation {
|
|
2607
|
+
value: ast::Value { value: true.into() }.into(),
|
|
2608
|
+
},
|
|
2609
|
+
);
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2612
|
+
#[test]
|
|
2613
|
+
fn test_oc_parse_is_not_null_unaffected()
|
|
2614
|
+
{
|
|
2615
|
+
compare_parse_to_ast(
|
|
2616
|
+
"n.age IS NOT NULL",
|
|
2617
|
+
expression,
|
|
2618
|
+
ast::IsNotNull {
|
|
2619
|
+
value: ast::MemberAccess {
|
|
2620
|
+
left: ast::Variable {
|
|
2621
|
+
identifier: ast::VariableIdentifier {
|
|
2622
|
+
name: "n".to_string(),
|
|
2623
|
+
id: 0,
|
|
2624
|
+
},
|
|
2625
|
+
}
|
|
2626
|
+
.into(),
|
|
2627
|
+
path: vec!["age".to_string()],
|
|
2628
|
+
}
|
|
2629
|
+
.into(),
|
|
2630
|
+
},
|
|
2631
|
+
);
|
|
2632
|
+
}
|
|
2633
|
+
|
|
2634
|
+
#[test]
|
|
2635
|
+
fn test_oc_parse_not_in_still_works()
|
|
2636
|
+
{
|
|
2637
|
+
compare_parse_to_ast(
|
|
2638
|
+
"x NOT IN [1, 2]",
|
|
2639
|
+
expression,
|
|
2640
|
+
ast::LogicalNegation {
|
|
2641
|
+
value: ast::RelationalIn {
|
|
2642
|
+
left: ast::Variable {
|
|
2643
|
+
identifier: ast::VariableIdentifier {
|
|
2644
|
+
name: "x".to_string(),
|
|
2645
|
+
id: 0,
|
|
2646
|
+
},
|
|
2647
|
+
}
|
|
2648
|
+
.into(),
|
|
2649
|
+
right: ast::Array {
|
|
2650
|
+
array: vec![
|
|
2651
|
+
ast::Value { value: 1i64.into() }.into(),
|
|
2652
|
+
ast::Value { value: 2i64.into() }.into(),
|
|
2653
|
+
],
|
|
2654
|
+
}
|
|
2655
|
+
.into(),
|
|
2656
|
+
}
|
|
2657
|
+
.into(),
|
|
2658
|
+
},
|
|
2659
|
+
);
|
|
2660
|
+
}
|
|
2661
|
+
|
|
2662
|
+
#[test]
|
|
2663
|
+
fn test_oc_parse_count_distinct()
|
|
2664
|
+
{
|
|
2665
|
+
compare_parse_to_ast(
|
|
2666
|
+
"count(DISTINCT x)",
|
|
2667
|
+
expression,
|
|
2668
|
+
ast::FunctionCall {
|
|
2669
|
+
name: "count".to_string(),
|
|
2670
|
+
arguments: vec![
|
|
2671
|
+
ast::Variable {
|
|
2672
|
+
identifier: ast::VariableIdentifier {
|
|
2673
|
+
name: "x".to_string(),
|
|
2674
|
+
id: 0,
|
|
2675
|
+
},
|
|
2676
|
+
}
|
|
2677
|
+
.into(),
|
|
2678
|
+
],
|
|
2679
|
+
distinct: true,
|
|
2680
|
+
},
|
|
2681
|
+
);
|
|
2682
|
+
}
|
|
2683
|
+
|
|
2684
|
+
#[test]
|
|
2685
|
+
fn test_oc_parse_count_without_distinct_defaults_false()
|
|
2686
|
+
{
|
|
2687
|
+
compare_parse_to_ast(
|
|
2688
|
+
"count(x)",
|
|
2689
|
+
expression,
|
|
2690
|
+
ast::FunctionCall {
|
|
2691
|
+
name: "count".to_string(),
|
|
2692
|
+
arguments: vec![
|
|
2693
|
+
ast::Variable {
|
|
2694
|
+
identifier: ast::VariableIdentifier {
|
|
2695
|
+
name: "x".to_string(),
|
|
2696
|
+
id: 0,
|
|
2697
|
+
},
|
|
2698
|
+
}
|
|
2699
|
+
.into(),
|
|
2700
|
+
],
|
|
2701
|
+
distinct: false,
|
|
2702
|
+
},
|
|
2703
|
+
);
|
|
2704
|
+
}
|
|
2705
|
+
|
|
2706
|
+
#[test]
|
|
2707
|
+
fn test_oc_parse_sum_distinct()
|
|
2708
|
+
{
|
|
2709
|
+
compare_parse_to_ast(
|
|
2710
|
+
"sum(DISTINCT n.age)",
|
|
2711
|
+
expression,
|
|
2712
|
+
ast::FunctionCall {
|
|
2713
|
+
name: "sum".to_string(),
|
|
2714
|
+
arguments: vec![
|
|
2715
|
+
ast::MemberAccess {
|
|
2716
|
+
left: ast::Variable {
|
|
2717
|
+
identifier: ast::VariableIdentifier {
|
|
2718
|
+
name: "n".to_string(),
|
|
2719
|
+
id: 0,
|
|
2720
|
+
},
|
|
2721
|
+
}
|
|
2722
|
+
.into(),
|
|
2723
|
+
path: vec!["age".to_string()],
|
|
2724
|
+
}
|
|
2725
|
+
.into(),
|
|
2726
|
+
],
|
|
2727
|
+
distinct: true,
|
|
2728
|
+
},
|
|
2729
|
+
);
|
|
2730
|
+
}
|
|
2731
|
+
|
|
2732
|
+
#[test]
|
|
2733
|
+
fn test_oc_parse_function_call_distinct_with_multiple_args()
|
|
2734
|
+
{
|
|
2735
|
+
compare_parse_to_ast(
|
|
2736
|
+
"some_func(DISTINCT a, b)",
|
|
2737
|
+
expression,
|
|
2738
|
+
ast::FunctionCall {
|
|
2739
|
+
name: "some_func".to_string(),
|
|
2740
|
+
arguments: vec![
|
|
2741
|
+
ast::Variable {
|
|
2742
|
+
identifier: ast::VariableIdentifier {
|
|
2743
|
+
name: "a".to_string(),
|
|
2744
|
+
id: 0,
|
|
2745
|
+
},
|
|
2746
|
+
}
|
|
2747
|
+
.into(),
|
|
2748
|
+
ast::Variable {
|
|
2749
|
+
identifier: ast::VariableIdentifier {
|
|
2750
|
+
name: "b".to_string(),
|
|
2751
|
+
id: 1,
|
|
2752
|
+
},
|
|
2753
|
+
}
|
|
2754
|
+
.into(),
|
|
2755
|
+
],
|
|
2756
|
+
distinct: true,
|
|
2757
|
+
},
|
|
2758
|
+
);
|
|
2759
|
+
}
|
|
2760
|
+
|
|
2761
|
+
// Tests for work item #569: node_pattern predicate parsing
|
|
2762
|
+
|
|
2763
|
+
#[test]
|
|
2764
|
+
fn test_oc_parse_node_pattern_with_predicate_and_label()
|
|
2765
|
+
{
|
|
2766
|
+
// Test parsing (n:Station WHERE n.name = 'X')
|
|
2767
|
+
let actual = parse(
|
|
2768
|
+
"(n:Station WHERE n.name = 'X')",
|
|
2769
|
+
node_pattern::<AllowUndirected>,
|
|
2770
|
+
);
|
|
2771
|
+
|
|
2772
|
+
// Verify predicate is present
|
|
2773
|
+
assert!(actual.predicate.is_some(), "expected predicate to be Some");
|
|
2774
|
+
|
|
2775
|
+
// Verify label is correct
|
|
2776
|
+
assert!(matches!(actual.labels, ast::LabelExpression::String(ref s) if s == "Station"));
|
|
2777
|
+
}
|
|
2778
|
+
|
|
2779
|
+
#[test]
|
|
2780
|
+
fn test_oc_parse_node_pattern_with_predicate_no_label()
|
|
2781
|
+
{
|
|
2782
|
+
// Test parsing (n WHERE n.name = 'X')
|
|
2783
|
+
let actual = parse("(n WHERE n.name = 'X')", node_pattern::<AllowUndirected>);
|
|
2784
|
+
|
|
2785
|
+
// Verify predicate is present
|
|
2786
|
+
assert!(actual.predicate.is_some(), "expected predicate to be Some");
|
|
2787
|
+
|
|
2788
|
+
// Verify label is None
|
|
2789
|
+
assert!(matches!(actual.labels, ast::LabelExpression::None));
|
|
2790
|
+
}
|
|
2791
|
+
|
|
2792
|
+
#[test]
|
|
2793
|
+
fn test_oc_parse_node_pattern_with_predicate_and_properties()
|
|
2794
|
+
{
|
|
2795
|
+
// Test parsing (n:Station {zone: 2} WHERE n.name STARTS WITH 'D')
|
|
2796
|
+
let actual = parse(
|
|
2797
|
+
"(n:Station {zone: 2} WHERE n.name STARTS WITH 'D')",
|
|
2798
|
+
node_pattern::<AllowUndirected>,
|
|
2799
|
+
);
|
|
2800
|
+
|
|
2801
|
+
// Verify both properties and predicate are present
|
|
2802
|
+
assert!(
|
|
2803
|
+
actual.properties.is_some(),
|
|
2804
|
+
"expected properties to be Some"
|
|
2805
|
+
);
|
|
2806
|
+
assert!(actual.predicate.is_some(), "expected predicate to be Some");
|
|
2807
|
+
|
|
2808
|
+
// Verify label is correct
|
|
2809
|
+
assert!(matches!(actual.labels, ast::LabelExpression::String(ref s) if s == "Station"));
|
|
2810
|
+
}
|
|
2811
|
+
|
|
2812
|
+
#[test]
|
|
2813
|
+
fn test_oc_parse_node_pattern_without_predicate_regression()
|
|
2814
|
+
{
|
|
2815
|
+
// Regression test: ensure predicate remains None when not specified
|
|
2816
|
+
let actual = parse("(n)", node_pattern::<AllowUndirected>);
|
|
2817
|
+
|
|
2818
|
+
// Verify predicate is None
|
|
2819
|
+
assert!(actual.predicate.is_none(), "expected predicate to be None");
|
|
2820
|
+
}
|
|
2821
|
+
|
|
2822
|
+
#[test]
|
|
2823
|
+
fn test_oc_parse_create_with_predicate_rejected()
|
|
2824
|
+
{
|
|
2825
|
+
// Test: CREATE patterns with WHERE predicates should be rejected
|
|
2826
|
+
// This is parsed with DisallowUndirected context (used for CREATE)
|
|
2827
|
+
parse_fail(
|
|
2828
|
+
"(n:Station WHERE n.name = 'X')",
|
|
2829
|
+
node_pattern::<DisallowUndirected>,
|
|
2830
|
+
|error_kind| *error_kind == ErrorKind::CreatingWithPredicate,
|
|
2831
|
+
);
|
|
2832
|
+
}
|
|
2833
|
+
|
|
2834
|
+
#[test]
|
|
2835
|
+
fn test_oc_parse_group_pattern_simple()
|
|
2836
|
+
{
|
|
2837
|
+
// Test parsing ((n)-[r:KNOWS]->(m)){1,5}(b)
|
|
2838
|
+
let actual = parse(
|
|
2839
|
+
"((n)-[r:KNOWS]->(m)){1,5}(b)",
|
|
2840
|
+
group_pattern::<AllowUndirected>,
|
|
2841
|
+
);
|
|
2842
|
+
|
|
2843
|
+
// Verify group contains exactly one pattern (the edge)
|
|
2844
|
+
assert_eq!(
|
|
2845
|
+
actual.group.len(),
|
|
2846
|
+
1,
|
|
2847
|
+
"Expected one pattern in group, got {}",
|
|
2848
|
+
actual.group.len()
|
|
2849
|
+
);
|
|
2850
|
+
|
|
2851
|
+
// Verify the group contains an Edge pattern
|
|
2852
|
+
assert!(
|
|
2853
|
+
matches!(&actual.group[0], ast::Pattern::Edge(_)),
|
|
2854
|
+
"Expected Edge pattern in group"
|
|
2855
|
+
);
|
|
2856
|
+
|
|
2857
|
+
// Verify quantifier is 1..5
|
|
2858
|
+
assert_eq!(
|
|
2859
|
+
actual.quantifier,
|
|
2860
|
+
1..5,
|
|
2861
|
+
"Expected quantifier 1..5, got {:?}",
|
|
2862
|
+
actual.quantifier
|
|
2863
|
+
);
|
|
2864
|
+
|
|
2865
|
+
// Verify destination_node is bound to variable 'b'
|
|
2866
|
+
assert!(
|
|
2867
|
+
actual.destination_node.variable.is_some(),
|
|
2868
|
+
"Expected destination_node to have a variable"
|
|
2869
|
+
);
|
|
2870
|
+
if let Some(var) = &actual.destination_node.variable
|
|
2871
|
+
{
|
|
2872
|
+
assert_eq!(
|
|
2873
|
+
var.name(),
|
|
2874
|
+
"b",
|
|
2875
|
+
"Expected destination_node variable to be 'b', got '{}'",
|
|
2876
|
+
var.name()
|
|
2877
|
+
);
|
|
2878
|
+
}
|
|
2879
|
+
}
|
|
2880
|
+
|
|
2881
|
+
#[test]
|
|
2882
|
+
fn test_oc_parse_selector_scoped_pattern_basic()
|
|
2883
|
+
{
|
|
2884
|
+
// Test parsing selector-scoped pattern: ((n)-[r]->(m) WHERE n.x > 1)
|
|
2885
|
+
let actual = parse(
|
|
2886
|
+
"((n)-[r]->(m) WHERE n.x > 1)",
|
|
2887
|
+
selector_scoped_pattern::<AllowUndirected>,
|
|
2888
|
+
);
|
|
2889
|
+
|
|
2890
|
+
// Verify it returns a single QuantifiedPathPattern
|
|
2891
|
+
assert_eq!(
|
|
2892
|
+
actual.len(),
|
|
2893
|
+
1,
|
|
2894
|
+
"Expected one pattern, got {}",
|
|
2895
|
+
actual.len()
|
|
2896
|
+
);
|
|
2897
|
+
|
|
2898
|
+
if let ast::Pattern::QuantifiedPath(qp) = &actual[0]
|
|
2899
|
+
{
|
|
2900
|
+
// Verify quantifier is None (key difference from group pattern)
|
|
2901
|
+
assert_eq!(
|
|
2902
|
+
qp.quantifier, None,
|
|
2903
|
+
"Expected quantifier to be None for selector-scoped pattern, got {:?}",
|
|
2904
|
+
qp.quantifier
|
|
2905
|
+
);
|
|
2906
|
+
|
|
2907
|
+
// Verify group_where is set
|
|
2908
|
+
assert!(qp.group_where.is_some(), "Expected group_where to be set");
|
|
2909
|
+
|
|
2910
|
+
// Verify variable is None (not set in selector_scoped_pattern itself)
|
|
2911
|
+
assert_eq!(
|
|
2912
|
+
qp.variable, None,
|
|
2913
|
+
"Expected variable to be None before patterns() closure applies it"
|
|
2914
|
+
);
|
|
2915
|
+
|
|
2916
|
+
// Verify group contains the pattern(s)
|
|
2917
|
+
assert!(!qp.group.is_empty(), "Expected group to contain patterns");
|
|
2918
|
+
}
|
|
2919
|
+
else
|
|
2920
|
+
{
|
|
2921
|
+
panic!("Expected QuantifiedPathPattern, got {:?}", actual[0]);
|
|
2922
|
+
}
|
|
2923
|
+
}
|
|
2924
|
+
|
|
2925
|
+
#[test]
|
|
2926
|
+
fn test_oc_parse_selector_scoped_pattern_with_variable()
|
|
2927
|
+
{
|
|
2928
|
+
// Test parsing selector-scoped pattern with variable: (p = (n)-[r]->(m))
|
|
2929
|
+
// This tests just the selector_scoped_pattern directly
|
|
2930
|
+
let actual = parse(
|
|
2931
|
+
"(p = (n)-[r]->(m))",
|
|
2932
|
+
selector_scoped_pattern::<AllowUndirected>,
|
|
2933
|
+
);
|
|
2934
|
+
|
|
2935
|
+
// Verify it returns a single QuantifiedPathPattern
|
|
2936
|
+
assert_eq!(
|
|
2937
|
+
actual.len(),
|
|
2938
|
+
1,
|
|
2939
|
+
"Expected one pattern, got {}",
|
|
2940
|
+
actual.len()
|
|
2941
|
+
);
|
|
2942
|
+
|
|
2943
|
+
if let ast::Pattern::QuantifiedPath(qp) = &actual[0]
|
|
2944
|
+
{
|
|
2945
|
+
// Verify variable is set from the p = binding inside the scoped pattern
|
|
2946
|
+
assert!(qp.variable.is_some(), "Expected variable to be set");
|
|
2947
|
+
if let Some(var) = &qp.variable
|
|
2948
|
+
{
|
|
2949
|
+
assert_eq!(
|
|
2950
|
+
var.name(),
|
|
2951
|
+
"p",
|
|
2952
|
+
"Expected variable 'p', got '{}'",
|
|
2953
|
+
var.name()
|
|
2954
|
+
);
|
|
2955
|
+
}
|
|
2956
|
+
|
|
2957
|
+
// Verify quantifier is None (key difference from regular group patterns)
|
|
2958
|
+
assert_eq!(
|
|
2959
|
+
qp.quantifier, None,
|
|
2960
|
+
"Expected quantifier to be None for selector-scoped pattern"
|
|
2961
|
+
);
|
|
2962
|
+
}
|
|
2963
|
+
else
|
|
2964
|
+
{
|
|
2965
|
+
panic!("Expected QuantifiedPathPattern, got {:?}", actual[0]);
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2968
|
+
|
|
2969
|
+
#[test]
|
|
2970
|
+
fn test_oc_parse_selector_scoped_pattern_no_where()
|
|
2971
|
+
{
|
|
2972
|
+
// Test parsing selector-scoped pattern without WHERE: ((n)-[r]->(m))
|
|
2973
|
+
let actual = parse("((n)-[r]->(m))", selector_scoped_pattern::<AllowUndirected>);
|
|
2974
|
+
|
|
2975
|
+
if let ast::Pattern::QuantifiedPath(qp) = &actual[0]
|
|
2976
|
+
{
|
|
2977
|
+
// Verify quantifier is None
|
|
2978
|
+
assert_eq!(qp.quantifier, None, "Expected quantifier to be None");
|
|
2979
|
+
|
|
2980
|
+
// Verify group_where is None when no WHERE clause
|
|
2981
|
+
assert_eq!(
|
|
2982
|
+
qp.group_where, None,
|
|
2983
|
+
"Expected group_where to be None when no WHERE clause"
|
|
2984
|
+
);
|
|
2985
|
+
}
|
|
2986
|
+
else
|
|
2987
|
+
{
|
|
2988
|
+
panic!("Expected QuantifiedPathPattern, got {:?}", actual[0]);
|
|
2989
|
+
}
|
|
2990
|
+
}
|