gqlite 1.8.1 → 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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/ext/Cargo.toml +8 -8
  3. data/ext/gqlitedb/Cargo.toml +0 -2
  4. data/ext/gqlitedb/src/compiler/variables_manager.rs +109 -10
  5. data/ext/gqlitedb/src/compiler.rs +481 -47
  6. data/ext/gqlitedb/src/connection.rs +12 -0
  7. data/ext/gqlitedb/src/consts.rs +1 -1
  8. data/ext/gqlitedb/src/error.rs +24 -0
  9. data/ext/gqlitedb/src/interpreter/evaluators.rs +91 -325
  10. data/ext/gqlitedb/src/interpreter/instructions.rs +72 -0
  11. data/ext/gqlitedb/src/interpreter/mod.rs +1 -0
  12. data/ext/gqlitedb/src/interpreter/path/bfs.rs +494 -0
  13. data/ext/gqlitedb/src/interpreter/path/dfs.rs +267 -0
  14. data/ext/gqlitedb/src/interpreter/path/group.rs +418 -0
  15. data/ext/gqlitedb/src/interpreter/path.rs +542 -0
  16. data/ext/gqlitedb/src/planner.rs +218 -6
  17. data/ext/gqlitedb/src/query_result.rs +19 -4
  18. data/ext/gqlitedb/src/tests/compiler.rs +2453 -1
  19. data/ext/gqlitedb/src/tests/connection/redb.rs +8 -0
  20. data/ext/gqlitedb/src/tests/connection.rs +37 -0
  21. data/ext/gqlitedb/src/tests/evaluators.rs +2206 -1
  22. data/ext/gqlitedb/src/tests/parser.rs +1225 -0
  23. data/ext/gqlitedb/src/tests/planner.rs +432 -2
  24. data/ext/gqlitedb/src/tests/store/vector_index/postgres.rs +5 -5
  25. data/ext/gqlitedb/src/tests/store/vector_index/sqlite.rs +3 -1
  26. data/ext/gqlitedb/src/tests/templates/ast.rs +284 -1
  27. data/ext/gqlitedb/src/tests/templates/programs.rs +306 -0
  28. data/ext/gqliterb/Cargo.toml +0 -1
  29. data/ext/gqlparser/src/oc/ast.rs +52 -3
  30. data/ext/gqlparser/src/oc/error.rs +18 -0
  31. data/ext/gqlparser/src/oc/lexer.rs +146 -0
  32. data/ext/gqlparser/src/oc/parser/tests.rs +365 -20
  33. data/ext/gqlparser/src/oc/parser.rs +1196 -143
  34. data/ext/graphcore/src/value.rs +12 -1
  35. metadata +5 -2
  36. data/ext/gqlitedb/src/parser/gql.pest +0 -198
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4af74e4cc44046fee49a1e9573a876066a80ddc6eaaf2def11f5af0002b89ff2
4
- data.tar.gz: c105b94002e5c43a74e8f7b418ba45d8d17c47bab1a68dc32c914e18c3a3e1cb
3
+ metadata.gz: c6ebd6bd26d6614d8d3edd02d592c4bfd125a5dc3bf8170cb69c3f7e22dd48a7
4
+ data.tar.gz: 1c9f08c8d98976a104166ddc321e23a81e3a66d36fa16c97dcff0aa81adc735f
5
5
  SHA512:
6
- metadata.gz: 885b3a13b70473a45cdad51df3fe04f1aebd98828a6211445bf1907c44f88ff543e78ffbf86b5afa971f76482e0b190ed76a7212cbf8b520a20b6e5505a58081
7
- data.tar.gz: d784d78413e35a708b204a557ef0e1d54236adae193679205b522d788529277c2f183824c87e57946733dd68e36013aea2e0cca6f42fe774d92ce6eccb8d4aed
6
+ metadata.gz: b524bcae9534be01d0d7b5ba78430058c736314c2f57770ca5774edb888b9192653fa23f1664bd62833c27745b29004dc1d78d280c769def4819e54ba5ff8a41
7
+ data.tar.gz: 73f5e717c9e6dc74c19389c939a2c5933c16b4a47da74756fab937e4ece53922e8fe25c8b4979a1d60e6be0d5a7c2701b4747bc5ff803789fa54b3b56132874e
data/ext/Cargo.toml CHANGED
@@ -3,26 +3,26 @@ resolver = "3"
3
3
  members = ["gqliterb", "gqlitedb", "graphcore"]
4
4
 
5
5
  [workspace.package]
6
- version = "0.11.0"
6
+ version = "0.13.0"
7
7
  edition = "2024"
8
8
  license = "MIT"
9
9
  homepage = "https://gqlite.org"
10
10
  repository = "https://gitlab.com/gqlite/gqlite"
11
11
 
12
12
  [workspace.dependencies]
13
- graphcore = { version = "0.11.0", path = "graphcore" }
14
- gqlitedb = { version = "0.11.0", path = "gqlitedb" }
15
- gqlparser = { version = "0.11.0", path = "gqlparser" }
16
- db-index = { version = "0.11.0", path = "db-index" }
13
+ graphcore = { version = "0.13.0", path = "graphcore" }
14
+ gqlitedb = { version = "0.13.0", path = "gqlitedb" }
15
+ gqlparser = { version = "0.13.0", path = "gqlparser" }
16
+ db-index = { version = "0.13.0", path = "db-index" }
17
17
 
18
- askama = { version = "0.15" }
18
+ askama = { version = "0.16" }
19
19
  ccutils = { version = "0.4" }
20
20
  ciborium = "0.2"
21
21
  divan = "0.1"
22
22
  indexmap = "2"
23
- itertools = "0.14"
23
+ itertools = "0.15"
24
24
  log = "0.4"
25
- rusqlite = { version = "0.38", features = ["load_extension"] }
25
+ rusqlite = { version = "0.40", features = ["load_extension"] }
26
26
  serde = "1"
27
27
  thiserror = "2"
28
28
  uuid = { version = "1", features = ["v4"] }
@@ -38,8 +38,6 @@ db-index = { workspace = true, optional = true }
38
38
  indexmap = { version = "2", features = ["serde"] }
39
39
  itertools = { workspace = true }
40
40
  log = { workspace = true }
41
- pest = "2"
42
- pest_derive = "2"
43
41
  pgrx = { version = "0.18", optional = true }
44
42
  postgres = { version = "0.19", optional = true, features = [
45
43
  "with-uuid-1",
@@ -2,7 +2,10 @@ use std::collections::HashMap;
2
2
 
3
3
  use gqlparser::oc::ast;
4
4
 
5
- use crate::{planner::LogicalPlan, prelude::*};
5
+ use crate::{
6
+ planner::{self, LogicalPlan},
7
+ prelude::*,
8
+ };
6
9
 
7
10
  use compiler::expression_analyser::{self, ExpressionType};
8
11
 
@@ -72,14 +75,17 @@ impl Variable
72
75
  variable: None,
73
76
  labels: ast::LabelExpression::None,
74
77
  properties: None,
78
+ predicate: None,
75
79
  },
76
80
  destination: ast::NodePattern {
77
81
  variable: None,
78
82
  labels: ast::LabelExpression::None,
79
83
  properties: None,
84
+ predicate: None,
80
85
  },
81
86
  directivity: graphcore::EdgeDirectivity::Directed,
82
- recursive_range: None,
87
+
88
+ predicate: None,
83
89
  }),
84
90
  variable_type: ExpressionType::Edge,
85
91
  col_id,
@@ -90,6 +96,8 @@ impl Variable
90
96
  variable: None,
91
97
  labels: ast::LabelExpression::None,
92
98
  properties: None,
99
+
100
+ predicate: None,
93
101
  }),
94
102
  variable_type: ExpressionType::Node,
95
103
  col_id,
@@ -484,23 +492,101 @@ impl VariablesManager
484
492
  Ok(())
485
493
  }
486
494
 
487
- fn analyse_pattern(&mut self, pattern: &ast::Pattern, is_create: bool) -> Result<()>
495
+ fn analyse_pattern(&mut self, pattern: &planner::PlannedPattern, is_create: bool) -> Result<()>
488
496
  {
489
497
  match pattern
490
498
  {
491
- ast::Pattern::Node(node) =>
499
+ planner::PlannedPattern::Node(node) =>
492
500
  {
493
501
  self.validate_node(node)?;
494
502
  }
495
- ast::Pattern::Edge(edge) =>
503
+ planner::PlannedPattern::Edge(edge) =>
496
504
  {
497
505
  self.analyse_edge_path(None, edge, is_create)?;
498
506
  }
499
- ast::Pattern::Path(path) =>
507
+ planner::PlannedPattern::Path(path) =>
500
508
  {
501
509
  self.analyse_edge_path(None, &path.edge, is_create)?;
502
510
  self.declare_variable(&path.variable, ExpressionType::Path)?;
503
511
  }
512
+ planner::PlannedPattern::QuantifiedPath { pattern: qp, .. } =>
513
+ {
514
+ if qp.group.len() != 1
515
+ {
516
+ // Multi-element groups: declare path variable and outer anchors
517
+ if let Some(path_variable) = &qp.variable
518
+ {
519
+ self.declare_variable(path_variable, ExpressionType::Path)?;
520
+ }
521
+ if !self.is_valid_existing_node(&qp.source)?
522
+ {
523
+ self.validate_node(&qp.source)?;
524
+ }
525
+ if !self.is_valid_existing_node(&qp.destination)?
526
+ {
527
+ self.validate_node(&qp.destination)?;
528
+ }
529
+ // Multi-element groups: analyze all patterns in the group
530
+ for pattern in &qp.group
531
+ {
532
+ match pattern
533
+ {
534
+ ast::Pattern::Node(node) =>
535
+ {
536
+ self.validate_node(node)?;
537
+ }
538
+ ast::Pattern::Edge(edge) =>
539
+ {
540
+ self.validate_edge(edge)?;
541
+ }
542
+ ast::Pattern::Path(path) =>
543
+ {
544
+ self.declare_variable(&path.variable, ExpressionType::Path)?;
545
+ self.validate_edge(&path.edge)?;
546
+ }
547
+ ast::Pattern::QuantifiedPath(_) =>
548
+ {
549
+ return Err(InternalError::Unimplemented("nested quantified path patterns").into());
550
+ }
551
+ }
552
+ }
553
+ }
554
+ else
555
+ {
556
+ if let Some(edge) = super::as_plain_quantifier(qp)
557
+ {
558
+ self.analyse_edge_path(qp.variable.clone(), edge, is_create)?;
559
+ }
560
+ else
561
+ {
562
+ // Explicit group: outer anchors differ from inner nodes
563
+ // Need to declare the outer anchors
564
+ if let Some(path_variable) = &qp.variable
565
+ {
566
+ self.declare_variable(path_variable, ExpressionType::Path)?;
567
+ }
568
+ if !self.is_valid_existing_node(&qp.source)?
569
+ {
570
+ self.validate_node(&qp.source)?;
571
+ }
572
+ if !self.is_valid_existing_node(&qp.destination)?
573
+ {
574
+ self.validate_node(&qp.destination)?;
575
+ }
576
+ // Validate every inner edge, not just the first - group.len() may be
577
+ // > 1 for multi-element groups (e.g. ((n)-[r1]->(x)-[r2]->(m))), and
578
+ // only checking group[0] would silently skip every subsequent edge's
579
+ // label/property/predicate constraints.
580
+ for pattern in &qp.group
581
+ {
582
+ if let ast::Pattern::Edge(edge) = pattern
583
+ {
584
+ self.validate_edge(edge)?;
585
+ }
586
+ }
587
+ }
588
+ }
589
+ }
504
590
  }
505
591
  Ok(())
506
592
  }
@@ -573,7 +659,7 @@ impl VariablesManager
573
659
  {
574
660
  for pattern in patterns.iter()
575
661
  {
576
- if let ast::Pattern::Node(n) = &pattern
662
+ if let planner::PlannedPattern::Node(n) = pattern
577
663
  && self.has_variable(&n.variable)
578
664
  {
579
665
  return Err(
@@ -617,7 +703,7 @@ impl VariablesManager
617
703
  {
618
704
  match pattern
619
705
  {
620
- ast::Pattern::Node(n) =>
706
+ planner::PlannedPattern::Node(n) =>
621
707
  {
622
708
  if self.has_variable(&n.variable)
623
709
  {
@@ -629,7 +715,7 @@ impl VariablesManager
629
715
  );
630
716
  }
631
717
  }
632
- ast::Pattern::Edge(e) =>
718
+ planner::PlannedPattern::Edge(e) =>
633
719
  {
634
720
  if self.has_variable(&e.variable)
635
721
  {
@@ -641,7 +727,7 @@ impl VariablesManager
641
727
  );
642
728
  }
643
729
  }
644
- ast::Pattern::Path(p) =>
730
+ planner::PlannedPattern::Path(p) =>
645
731
  {
646
732
  if self.has_variable(&Some(p.variable.clone()))
647
733
  {
@@ -653,6 +739,19 @@ impl VariablesManager
653
739
  );
654
740
  }
655
741
  }
742
+ planner::PlannedPattern::QuantifiedPath { pattern: qp, .. } =>
743
+ {
744
+ if let Some(var) = &qp.variable
745
+ && self.has_variable(&Some(var.clone()))
746
+ {
747
+ return Err(
748
+ CompileTimeError::VariableAlreadyBound {
749
+ name: var.name().clone(),
750
+ }
751
+ .into(),
752
+ );
753
+ }
754
+ }
656
755
  }
657
756
  self.analyse_pattern(pattern, false)?;
658
757
  }