gqlite 1.5.1 → 1.8.0

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 (113) hide show
  1. checksums.yaml +4 -4
  2. data/ext/Cargo.toml +10 -4
  3. data/ext/db-index/Cargo.toml +29 -0
  4. data/ext/db-index/src/hnsw/error.rs +66 -0
  5. data/ext/db-index/src/hnsw/graph_store.rs +272 -0
  6. data/ext/db-index/src/hnsw/id.rs +36 -0
  7. data/ext/db-index/src/hnsw/implementation.rs +1517 -0
  8. data/ext/db-index/src/hnsw/kernels.rs +1228 -0
  9. data/ext/db-index/src/hnsw/metric.rs +244 -0
  10. data/ext/db-index/src/hnsw/scalar.rs +72 -0
  11. data/ext/db-index/src/hnsw/simple_store.rs +140 -0
  12. data/ext/db-index/src/hnsw/store.rs +472 -0
  13. data/ext/db-index/src/hnsw/vector.rs +105 -0
  14. data/ext/db-index/src/hnsw/vectors.rs +568 -0
  15. data/ext/db-index/src/hnsw.rs +42 -0
  16. data/ext/db-index/src/lib.rs +3 -0
  17. data/ext/gqlitedb/Cargo.toml +19 -9
  18. data/ext/gqlitedb/benches/common/pokec.rs +62 -2
  19. data/ext/gqlitedb/benches/pokec_divan.rs +66 -2
  20. data/ext/gqlitedb/benches/pokec_iai.rs +60 -3
  21. data/ext/gqlitedb/release.toml +2 -2
  22. data/ext/gqlitedb/src/aggregators/arithmetic.rs +3 -1
  23. data/ext/gqlitedb/src/aggregators/containers.rs +1 -1
  24. data/ext/gqlitedb/src/aggregators/stats.rs +21 -12
  25. data/ext/gqlitedb/src/capi.rs +1 -1
  26. data/ext/gqlitedb/src/compiler/expression_analyser.rs +28 -20
  27. data/ext/gqlitedb/src/compiler/variables_manager.rs +97 -29
  28. data/ext/gqlitedb/src/compiler.rs +505 -225
  29. data/ext/gqlitedb/src/connection.rs +149 -11
  30. data/ext/gqlitedb/src/consts.rs +1 -2
  31. data/ext/gqlitedb/src/error.rs +123 -61
  32. data/ext/gqlitedb/src/functions/common.rs +39 -2
  33. data/ext/gqlitedb/src/functions/math.rs +8 -3
  34. data/ext/gqlitedb/src/functions/path.rs +48 -11
  35. data/ext/gqlitedb/src/functions/value.rs +1 -1
  36. data/ext/gqlitedb/src/functions.rs +23 -7
  37. data/ext/gqlitedb/src/graph.rs +1 -9
  38. data/ext/gqlitedb/src/interpreter/evaluators.rs +968 -130
  39. data/ext/gqlitedb/src/interpreter/instructions.rs +39 -2
  40. data/ext/gqlitedb/src/lib.rs +5 -4
  41. data/ext/gqlitedb/src/planner.rs +329 -0
  42. data/ext/gqlitedb/src/prelude.rs +3 -3
  43. data/ext/gqlitedb/src/store/pgrx.rs +1 -1
  44. data/ext/gqlitedb/src/store/postgres.rs +735 -7
  45. data/ext/gqlitedb/src/store/redb/hnsw_store.rs +702 -0
  46. data/ext/gqlitedb/src/store/redb/index.rs +274 -0
  47. data/ext/gqlitedb/src/store/redb.rs +1268 -113
  48. data/ext/gqlitedb/src/store/sqlbase/sqlmetadata.rs +28 -0
  49. data/ext/gqlitedb/src/store/sqlbase/sqlstore.rs +103 -0
  50. data/ext/gqlitedb/src/store/sqlbase.rs +146 -16
  51. data/ext/gqlitedb/src/store/sqlite.rs +569 -5
  52. data/ext/gqlitedb/src/store/vector_extract.rs +56 -0
  53. data/ext/gqlitedb/src/store.rs +123 -3
  54. data/ext/gqlitedb/src/tests/compiler.rs +207 -10
  55. data/ext/gqlitedb/src/tests/connection/postgres.rs +38 -3
  56. data/ext/gqlitedb/src/tests/connection/redb.rs +23 -0
  57. data/ext/gqlitedb/src/tests/connection/sqlite.rs +31 -0
  58. data/ext/gqlitedb/src/tests/connection.rs +61 -1
  59. data/ext/gqlitedb/src/tests/evaluators.rs +162 -7
  60. data/ext/gqlitedb/src/tests/parser.rs +54 -23
  61. data/ext/gqlitedb/src/tests/planner.rs +511 -0
  62. data/ext/gqlitedb/src/tests/store/postgres.rs +7 -0
  63. data/ext/gqlitedb/src/tests/store/redb.rs +8 -0
  64. data/ext/gqlitedb/src/tests/store/sqlite.rs +8 -0
  65. data/ext/gqlitedb/src/tests/store/vector_index/postgres.rs +182 -0
  66. data/ext/gqlitedb/src/tests/store/vector_index/redb.rs +386 -0
  67. data/ext/gqlitedb/src/tests/store/vector_index/sqlite.rs +166 -0
  68. data/ext/gqlitedb/src/tests/store/vector_index.rs +2313 -0
  69. data/ext/gqlitedb/src/tests/store.rs +78 -14
  70. data/ext/gqlitedb/src/tests/templates/ast.rs +92 -16
  71. data/ext/gqlitedb/src/tests/templates/programs.rs +14 -7
  72. data/ext/gqlitedb/src/tests.rs +15 -9
  73. data/ext/gqlitedb/src/utils.rs +6 -1
  74. data/ext/gqlitedb/src/value/compare.rs +61 -3
  75. data/ext/gqlitedb/src/value.rs +136 -7
  76. data/ext/gqlitedb/templates/sql/postgres/metadata_delete.sql +1 -0
  77. data/ext/gqlitedb/templates/sql/postgres/node_select.sql +1 -1
  78. data/ext/gqlitedb/templates/sql/sqlite/metadata_delete.sql +1 -0
  79. data/ext/gqliterb/src/lib.rs +53 -8
  80. data/ext/gqlparser/Cargo.toml +25 -0
  81. data/ext/gqlparser/README.MD +9 -0
  82. data/ext/gqlparser/benches/pokec_divan.rs +34 -0
  83. data/ext/gqlparser/src/common.rs +69 -0
  84. data/ext/gqlparser/src/gqls/ast.rs +69 -0
  85. data/ext/gqlparser/src/gqls/constraint.rs +79 -0
  86. data/ext/gqlparser/src/gqls/error.rs +22 -0
  87. data/ext/gqlparser/src/gqls/parser.rs +813 -0
  88. data/ext/gqlparser/src/gqls/prelude.rs +8 -0
  89. data/ext/gqlparser/src/gqls/properties.rs +115 -0
  90. data/ext/gqlparser/src/gqls/resolve.rs +207 -0
  91. data/ext/gqlparser/src/gqls.rs +265 -0
  92. data/ext/gqlparser/src/lib.rs +7 -0
  93. data/ext/gqlparser/src/oc/ast.rs +680 -0
  94. data/ext/gqlparser/src/oc/error.rs +172 -0
  95. data/ext/gqlparser/src/oc/lexer.rs +429 -0
  96. data/ext/gqlparser/src/oc/parser/tests.rs +2284 -0
  97. data/ext/gqlparser/src/oc/parser.rs +2005 -0
  98. data/ext/gqlparser/src/oc.rs +33 -0
  99. data/ext/gqlparser/src/prelude.rs +3 -0
  100. data/ext/graphcore/Cargo.toml +1 -0
  101. data/ext/graphcore/src/error.rs +26 -0
  102. data/ext/graphcore/src/graph.rs +177 -51
  103. data/ext/graphcore/src/lib.rs +4 -2
  104. data/ext/graphcore/src/open_cypher.rs +12 -0
  105. data/ext/graphcore/src/table.rs +50 -2
  106. data/ext/graphcore/src/timestamp.rs +127 -104
  107. data/ext/graphcore/src/value/tensor.rs +739 -0
  108. data/ext/graphcore/src/value/value_map.rs +1 -1
  109. data/ext/graphcore/src/value.rs +343 -19
  110. metadata +90 -22
  111. data/ext/gqlitedb/src/parser/ast.rs +0 -604
  112. data/ext/gqlitedb/src/parser/parser_impl.rs +0 -1213
  113. data/ext/gqlitedb/src/parser.rs +0 -4
@@ -1,8 +1,8 @@
1
1
  use std::{collections::HashSet, fs};
2
2
 
3
3
  use ccutils::temporary::TemporaryFile;
4
- use gqlitedb::{value_map, Connection};
5
- use rand::{seq::IndexedRandom, Rng};
4
+ use gqlitedb::{Connection, value_map};
5
+ use rand::{Rng, seq::IndexedRandom};
6
6
  use regex::Regex;
7
7
 
8
8
  /// Marker trait to keep backend-specific resources alive for the benchmark lifetime.
@@ -244,4 +244,64 @@ impl Pokec
244
244
  )
245
245
  .unwrap();
246
246
  }
247
+ pub(crate) fn scan_limit_1(&self)
248
+ {
249
+ self
250
+ .connection
251
+ .execute_oc_query("MATCH (n:User) RETURN n LIMIT 1", Default::default())
252
+ .unwrap();
253
+ }
254
+ pub(crate) fn scan_limit_10(&self)
255
+ {
256
+ self
257
+ .connection
258
+ .execute_oc_query("MATCH (n:User) RETURN n LIMIT 10", Default::default())
259
+ .unwrap();
260
+ }
261
+ pub(crate) fn scan_limit_100(&self)
262
+ {
263
+ self
264
+ .connection
265
+ .execute_oc_query("MATCH (n:User) RETURN n LIMIT 100", Default::default())
266
+ .unwrap();
267
+ }
268
+ pub(crate) fn recursive_1_2<R>(&self, rng: &mut R)
269
+ where
270
+ R: Rng + ?Sized,
271
+ {
272
+ let random_id = self.ids.choose(rng).unwrap();
273
+ self
274
+ .connection
275
+ .execute_oc_query(
276
+ "MATCH (s:User {id: $id})-[*1..2]->(n:User) RETURN n.id",
277
+ value_map!("$id" => *random_id),
278
+ )
279
+ .unwrap();
280
+ }
281
+ pub(crate) fn recursive_1_3<R>(&self, rng: &mut R)
282
+ where
283
+ R: Rng + ?Sized,
284
+ {
285
+ let random_id = self.ids.choose(rng).unwrap();
286
+ self
287
+ .connection
288
+ .execute_oc_query(
289
+ "MATCH (s:User {id: $id})-[*1..3]->(n:User) RETURN n.id",
290
+ value_map!("$id" => *random_id),
291
+ )
292
+ .unwrap();
293
+ }
294
+ pub(crate) fn recursive_1_2_filter<R>(&self, rng: &mut R)
295
+ where
296
+ R: Rng + ?Sized,
297
+ {
298
+ let random_id = self.ids.choose(rng).unwrap();
299
+ self
300
+ .connection
301
+ .execute_oc_query(
302
+ "MATCH (s:User {id: $id})-[*1..2]->(n:User) WHERE n.age >= 18 RETURN n.id",
303
+ value_map!("$id" => *random_id),
304
+ )
305
+ .unwrap();
306
+ }
247
307
  }
@@ -1,5 +1,5 @@
1
1
  use divan::Bencher;
2
- use rand::{rngs::StdRng, SeedableRng};
2
+ use rand::{SeedableRng, rngs::StdRng};
3
3
 
4
4
  mod common;
5
5
 
@@ -8,6 +8,8 @@ use common::pokec::{Pokec, PokecSize};
8
8
  const FRIEND_OF_COUNT: u32 = 100;
9
9
  const SINGLE_VERTEX_COUNT: u32 = 100;
10
10
  const IMPORT_COUNT: u32 = 30;
11
+ const LIMIT_COUNT: u32 = 200;
12
+ const RECURSIVE_COUNT: u32 = 100;
11
13
 
12
14
  fn main()
13
15
  {
@@ -125,7 +127,6 @@ fn aggregate_count_filter(bencher: Bencher, backend: &str)
125
127
  tiny_pokec.aggregate_count_filter();
126
128
  });
127
129
  }
128
-
129
130
  #[divan::bench(args = ["postgres", "sqlite", "redb"])]
130
131
  fn aggregate_min_max_avg(bencher: Bencher, backend: &str)
131
132
  {
@@ -135,3 +136,66 @@ fn aggregate_min_max_avg(bencher: Bencher, backend: &str)
135
136
  tiny_pokec.aggregate_min_max_avg();
136
137
  });
137
138
  }
139
+
140
+ #[divan::bench(args = ["postgres", "sqlite", "redb"], sample_count = LIMIT_COUNT)]
141
+ fn scan_limit_1(bencher: Bencher, backend: &str)
142
+ {
143
+ let pokec = load_pokec(backend);
144
+
145
+ bencher.bench_local(move || {
146
+ pokec.scan_limit_1();
147
+ });
148
+ }
149
+
150
+ #[divan::bench(args = ["postgres", "sqlite", "redb"], sample_count = LIMIT_COUNT)]
151
+ fn scan_limit_10(bencher: Bencher, backend: &str)
152
+ {
153
+ let pokec = load_pokec(backend);
154
+
155
+ bencher.bench_local(move || {
156
+ pokec.scan_limit_10();
157
+ });
158
+ }
159
+
160
+ #[divan::bench(args = ["postgres", "sqlite", "redb"], sample_count = LIMIT_COUNT)]
161
+ fn scan_limit_100(bencher: Bencher, backend: &str)
162
+ {
163
+ let pokec = load_pokec(backend);
164
+
165
+ bencher.bench_local(move || {
166
+ pokec.scan_limit_100();
167
+ });
168
+ }
169
+
170
+ #[divan::bench(args = ["postgres", "sqlite", "redb"], sample_count = RECURSIVE_COUNT)]
171
+ fn recursive_1_2(bencher: Bencher, backend: &str)
172
+ {
173
+ let pokec = load_pokec(backend).read_ids();
174
+ let mut rng = StdRng::seed_from_u64(991173);
175
+
176
+ bencher.bench_local(move || {
177
+ pokec.recursive_1_2(&mut rng);
178
+ });
179
+ }
180
+
181
+ #[divan::bench(args = ["postgres", "sqlite", "redb"], sample_count = RECURSIVE_COUNT)]
182
+ fn recursive_1_3(bencher: Bencher, backend: &str)
183
+ {
184
+ let pokec = load_pokec(backend).read_ids();
185
+ let mut rng = StdRng::seed_from_u64(991173);
186
+
187
+ bencher.bench_local(move || {
188
+ pokec.recursive_1_3(&mut rng);
189
+ });
190
+ }
191
+
192
+ #[divan::bench(args = ["postgres", "sqlite", "redb"], sample_count = RECURSIVE_COUNT)]
193
+ fn recursive_1_2_filter(bencher: Bencher, backend: &str)
194
+ {
195
+ let pokec = load_pokec(backend).read_ids();
196
+ let mut rng = StdRng::seed_from_u64(991173);
197
+
198
+ bencher.bench_local(move || {
199
+ pokec.recursive_1_2_filter(&mut rng);
200
+ });
201
+ }
@@ -1,7 +1,7 @@
1
1
  use std::hint::black_box;
2
2
 
3
3
  use iai_callgrind::{library_benchmark, library_benchmark_group, main};
4
- use rand::{rngs::StdRng, SeedableRng};
4
+ use rand::{SeedableRng, rngs::StdRng};
5
5
 
6
6
  mod common;
7
7
 
@@ -123,11 +123,68 @@ fn aggregate_min_max_avg(micro_pokec: Pokec)
123
123
  micro_pokec.aggregate_min_max_avg();
124
124
  }
125
125
 
126
+ #[library_benchmark(setup = load_pokec)]
127
+ #[bench::postgres("postgres")]
128
+ #[bench::redb("redb")]
129
+ #[bench::sqlite("sqlite")]
130
+ fn scan_limit_1(micro_pokec: Pokec)
131
+ {
132
+ micro_pokec.scan_limit_1();
133
+ }
134
+
135
+ #[library_benchmark(setup = load_pokec)]
136
+ #[bench::postgres("postgres")]
137
+ #[bench::redb("redb")]
138
+ #[bench::sqlite("sqlite")]
139
+ fn scan_limit_10(micro_pokec: Pokec)
140
+ {
141
+ micro_pokec.scan_limit_10();
142
+ }
143
+
144
+ #[library_benchmark(setup = load_pokec)]
145
+ #[bench::postgres("postgres")]
146
+ #[bench::redb("redb")]
147
+ #[bench::sqlite("sqlite")]
148
+ fn scan_limit_100(micro_pokec: Pokec)
149
+ {
150
+ micro_pokec.scan_limit_100();
151
+ }
152
+
153
+ #[library_benchmark(setup = load_with_ids)]
154
+ #[bench::postgres("postgres")]
155
+ #[bench::redb("redb")]
156
+ #[bench::sqlite("sqlite")]
157
+ fn recursive_1_2(micro_pokec: Pokec)
158
+ {
159
+ let mut rng = StdRng::seed_from_u64(991173);
160
+ micro_pokec.recursive_1_2(&mut rng);
161
+ }
162
+
163
+ #[library_benchmark(setup = load_with_ids)]
164
+ #[bench::postgres("postgres")]
165
+ #[bench::redb("redb")]
166
+ #[bench::sqlite("sqlite")]
167
+ fn recursive_1_3(micro_pokec: Pokec)
168
+ {
169
+ let mut rng = StdRng::seed_from_u64(991173);
170
+ micro_pokec.recursive_1_3(&mut rng);
171
+ }
172
+
173
+ #[library_benchmark(setup = load_with_ids)]
174
+ #[bench::postgres("postgres")]
175
+ #[bench::redb("redb")]
176
+ #[bench::sqlite("sqlite")]
177
+ fn recursive_1_2_filter(micro_pokec: Pokec)
178
+ {
179
+ let mut rng = StdRng::seed_from_u64(991173);
180
+ micro_pokec.recursive_1_2_filter(&mut rng);
181
+ }
182
+
126
183
  library_benchmark_group!(
127
184
  name = bench_micro_pokec_group;
128
- benchmarks = import_micro_pokec, single_vertex, single_vertex_where, friend_of, friend_of_filter, friend_of_friend_of, friend_of_friend_of_filter, reciprocal_friends, aggregate_count, aggregate_count_filter, aggregate_min_max_avg
185
+ benchmarks = recursive_1_2, import_micro_pokec, single_vertex, single_vertex_where, friend_of, friend_of_filter, friend_of_friend_of, friend_of_friend_of_filter, reciprocal_friends, aggregate_count, aggregate_count_filter, aggregate_min_max_avg, scan_limit_1, scan_limit_10, scan_limit_100, recursive_1_3, recursive_1_2_filter
129
186
  );
130
187
 
131
188
  main!(
132
- setup = common::get_bench_data();
189
+ setup = common::get_bench_data();
133
190
  library_benchmark_groups = bench_micro_pokec_group);
@@ -1,7 +1,7 @@
1
1
  pre-release-replacements = [
2
2
  { file = "../../CHANGELOG.md", search = "Unreleased", replace = "{{version}}" },
3
- { file = "../../CHANGELOG.md", search = "\\.\\.\\.dev/1", replace = "...{{tag_name}}", exactly = 1 },
3
+ { file = "../../CHANGELOG.md", search = "\\.\\.\\.dev/1", replace = "...gqlitedb-v{{version}}", exactly = 1 },
4
4
  { file = "../../CHANGELOG.md", search = "ReleaseDate", replace = "{{date}}" },
5
5
  { file = "../../CHANGELOG.md", search = "<!-- next-header -->", replace = "<!-- next-header -->\n\n## [Unreleased] - ReleaseDate", exactly = 1 },
6
- { file = "../../CHANGELOG.md", search = "<!-- next-url -->", replace = "<!-- next-url -->\n[Unreleased]: https://gitlab.com/gqlite/gqlite/compare/{{tag_name}}...dev/1", exactly = 1 },
6
+ { file = "../../CHANGELOG.md", search = "<!-- next-url -->", replace = "<!-- next-url -->\n[Unreleased]: https://gitlab.com/auksys/gqlite/compare/gqlitedb-v{{version}}...dev/1", exactly = 1 },
7
7
  ]
@@ -2,7 +2,7 @@ use std::fmt::Debug;
2
2
 
3
3
  use super::AggregatorState;
4
4
 
5
- use crate::{error::RunTimeError, value::Value, Result};
5
+ use crate::{Result, error::RunTimeError, value::Value};
6
6
 
7
7
  trait Op
8
8
  {
@@ -45,9 +45,11 @@ where
45
45
  | Value::Node(..)
46
46
  | Value::Edge(..)
47
47
  | Value::Array(..)
48
+ | Value::Tensor(..)
48
49
  | Value::String(..)
49
50
  | Value::TimeStamp(..)
50
51
  | Value::Map(..)
52
+ | Value::SinglePath(..)
51
53
  | Value::Path(..) => Err(RunTimeError::InvalidBinaryOperands)?,
52
54
  Value::Null =>
53
55
  {
@@ -1,6 +1,6 @@
1
1
  use super::AggregatorState;
2
2
 
3
- use crate::{value::Value, Result};
3
+ use crate::{Result, value::Value};
4
4
 
5
5
  #[derive(Debug)]
6
6
  struct CollectState
@@ -26,17 +26,17 @@ impl AggregatorState for AvgState
26
26
  {
27
27
  fn next(&mut self, value: value::Value) -> crate::Result<()>
28
28
  {
29
- if self.value.is_null()
30
- {
31
- self.value = value;
32
- }
33
- else
29
+ match value
34
30
  {
35
- match value
31
+ value::Value::Null => Ok(()),
32
+ value::Value::Integer(i) =>
36
33
  {
37
- value::Value::Null =>
38
- {}
39
- value::Value::Integer(i) =>
34
+ if self.value.is_null()
35
+ {
36
+ self.value = value::Value::Integer(i);
37
+ self.count = 1;
38
+ }
39
+ else
40
40
  {
41
41
  self.count += 1;
42
42
  match self.value
@@ -46,7 +46,16 @@ impl AggregatorState for AvgState
46
46
  _ => Err(InternalError::InvalidAggregationState)?,
47
47
  }
48
48
  }
49
- value::Value::Float(f) =>
49
+ Ok(())
50
+ }
51
+ value::Value::Float(f) =>
52
+ {
53
+ if self.value.is_null()
54
+ {
55
+ self.value = value::Value::Float(f);
56
+ self.count = 1;
57
+ }
58
+ else
50
59
  {
51
60
  self.count += 1;
52
61
  match self.value
@@ -56,10 +65,10 @@ impl AggregatorState for AvgState
56
65
  _ => Err(InternalError::InvalidAggregationState)?,
57
66
  }
58
67
  }
59
- _ => Err(RunTimeError::InvalidArgumentType)?,
68
+ Ok(())
60
69
  }
70
+ _ => Err(RunTimeError::InvalidArgumentType)?,
61
71
  }
62
- Ok(())
63
72
  }
64
73
  fn finalise(self: Box<Self>) -> crate::Result<crate::value::Value>
65
74
  {
@@ -41,7 +41,7 @@ fn check_error(context: *mut GqliteApiContextT)
41
41
  {
42
42
  let context = unsafe { Box::from_raw(context) };
43
43
  let stri = context.string.to_str().unwrap();
44
- println!("Error message '{stri:?}' was not cleared from context!");
44
+ log::error!("Error message '{stri:?}' was not cleared from context!");
45
45
  let _ = Box::into_raw(context);
46
46
  }
47
47
  }
@@ -1,4 +1,6 @@
1
- use crate::{compiler::variables_manager::VariablesManager, parser::ast, prelude::*};
1
+ use gqlparser::oc::ast;
2
+
3
+ use crate::{compiler::variables_manager::VariablesManager, prelude::*};
2
4
 
3
5
  // __ __ _ _ _ _____
4
6
  // \ \ / /_ _ _ __(_) __ _| |__ | | __|_ _| _ _ __ ___
@@ -23,6 +25,8 @@ pub(crate) enum ExpressionType
23
25
  String,
24
26
  TimeStamp,
25
27
  Variant,
28
+ #[expect(dead_code)]
29
+ Tensor,
26
30
  }
27
31
 
28
32
  // _ _ _ _
@@ -34,7 +38,7 @@ pub(crate) enum ExpressionType
34
38
 
35
39
  mod validators
36
40
  {
37
- use crate::{error, Result};
41
+ use crate::{Result, error};
38
42
 
39
43
  use super::{ExpressionInfo, ExpressionType};
40
44
 
@@ -136,15 +140,15 @@ where
136
140
  }
137
141
  }
138
142
 
139
- impl<VT> ExpressionAnalyser for (&ast::Expression, VT)
140
- where
141
- VT: Fn(ExpressionInfo) -> Result<ExpressionInfo>,
142
- {
143
- fn analyse<'b>(self, analyser: &Analyser<'b>) -> Result<Vec<ExpressionInfo>>
144
- {
145
- Ok(vec![self.1(analyser.analyse(self.0)?)?])
146
- }
147
- }
143
+ // impl<VT> ExpressionAnalyser for (&ast::Expression, VT)
144
+ // where
145
+ // VT: Fn(ExpressionInfo) -> Result<ExpressionInfo>,
146
+ // {
147
+ // fn analyse<'b>(self, analyser: &Analyser<'b>) -> Result<Vec<ExpressionInfo>>
148
+ // {
149
+ // Ok(vec![self.1(analyser.analyse(self.0)?)?])
150
+ // }
151
+ // }
148
152
 
149
153
  impl<'a, VT0, VT1> ExpressionAnalyser for ((&'a ast::Expression, &'a ast::Expression), (VT0, VT1))
150
154
  where
@@ -154,8 +158,8 @@ where
154
158
  fn analyse<'b>(self, analyser: &Analyser<'b>) -> Result<Vec<ExpressionInfo>>
155
159
  {
156
160
  Ok(vec![
157
- self.1 .0(analyser.analyse(self.0 .0)?)?,
158
- self.1 .1(analyser.analyse(self.0 .1)?)?,
161
+ self.1.0(analyser.analyse(self.0.0)?)?,
162
+ self.1.1(analyser.analyse(self.0.1)?)?,
159
163
  ])
160
164
  }
161
165
  }
@@ -171,17 +175,21 @@ where
171
175
  pub(crate) struct ExpressionInfo
172
176
  {
173
177
  pub(crate) expression_type: ExpressionType,
174
- pub(crate) constant: bool,
178
+ /// runtime constant indicates a constant that can be evaluated during compilation, but
179
+ /// that might not always be deterministic. For instance, `toInteger(rand()*9)` is such
180
+ /// a contant.
181
+ pub(crate) runtime_constant: bool,
175
182
  pub(crate) aggregation_result: bool,
176
183
  }
177
184
 
178
185
  impl ExpressionInfo
179
186
  {
180
- fn new(expression_type: ExpressionType, constant: bool, aggregation_result: bool) -> Self
187
+ fn new(expression_type: ExpressionType, runtime_constant: bool, aggregation_result: bool)
188
+ -> Self
181
189
  {
182
190
  Self {
183
191
  expression_type,
184
- constant,
192
+ runtime_constant,
185
193
  aggregation_result,
186
194
  }
187
195
  }
@@ -190,7 +198,7 @@ impl ExpressionInfo
190
198
  let dependents = dependents.into();
191
199
  Self {
192
200
  expression_type,
193
- constant: dependents.iter().all(|x| x.constant),
201
+ runtime_constant: dependents.iter().all(|x| x.runtime_constant),
194
202
  aggregation_result: dependents.into_iter().any(|x| x.aggregation_result),
195
203
  }
196
204
  }
@@ -254,8 +262,7 @@ impl<'b> Analyser<'b>
254
262
  &call.name,
255
263
  arguments.iter().map(|x| x.expression_type).collect(),
256
264
  )?,
257
- self.functions_manager.is_deterministic(&call.name)?
258
- && arguments.iter().all(|x| x.constant),
265
+ arguments.iter().all(|x| x.runtime_constant),
259
266
  self.functions_manager.is_aggregate(&call.name)?,
260
267
  ))
261
268
  }
@@ -410,6 +417,7 @@ impl<'b> Analyser<'b>
410
417
  match val.value
411
418
  {
412
419
  value::Value::Array(_) => ExpressionType::Array,
420
+ value::Value::Tensor(_) => ExpressionType::Array,
413
421
  value::Value::Key(_) => ExpressionType::Key,
414
422
  value::Value::Boolean(_) => ExpressionType::Boolean,
415
423
  value::Value::Edge(_) => ExpressionType::Edge,
@@ -418,7 +426,7 @@ impl<'b> Analyser<'b>
418
426
  value::Value::Integer(_) => ExpressionType::Integer,
419
427
  value::Value::Null => ExpressionType::Null,
420
428
  value::Value::Map(_) => ExpressionType::Map,
421
- value::Value::Path(_) => ExpressionType::Path,
429
+ value::Value::SinglePath(_) | value::Value::Path(_) => ExpressionType::Path,
422
430
  value::Value::String(_) => ExpressionType::String,
423
431
  value::Value::TimeStamp(_) => ExpressionType::TimeStamp,
424
432
  },
@@ -1,13 +1,14 @@
1
1
  use std::collections::HashMap;
2
2
 
3
- use crate::prelude::*;
3
+ use gqlparser::oc::ast;
4
+
5
+ use crate::{planner::LogicalPlan, prelude::*};
4
6
 
5
7
  use compiler::expression_analyser::{self, ExpressionType};
6
- use parser::ast;
7
8
 
8
9
  fn unknown_variable_error(name: &ast::VariableIdentifier) -> ErrorType
9
10
  {
10
- InternalError::UnknownVariable {
11
+ CompileTimeError::UndefinedVariable {
11
12
  name: name.name().clone(),
12
13
  }
13
14
  .into()
@@ -77,7 +78,8 @@ impl Variable
77
78
  labels: ast::LabelExpression::None,
78
79
  properties: None,
79
80
  },
80
- directivity: crate::graph::EdgeDirectivity::Directed,
81
+ directivity: graphcore::EdgeDirectivity::Directed,
82
+ recursive_range: None,
81
83
  }),
82
84
  variable_type: ExpressionType::Edge,
83
85
  col_id,
@@ -253,7 +255,7 @@ impl VariablesManager
253
255
  }
254
256
  }
255
257
  _ => Err(
256
- InternalError::ExpectedNode {
258
+ CompileTimeError::ExpectedNode {
257
259
  context: "validate_node",
258
260
  }
259
261
  .into(),
@@ -358,7 +360,7 @@ impl VariablesManager
358
360
  }
359
361
  }
360
362
  _ => Err(
361
- InternalError::ExpectedNode {
363
+ CompileTimeError::ExpectedNode {
362
364
  context: "is_valid_existing_node",
363
365
  }
364
366
  .into(),
@@ -413,7 +415,7 @@ impl VariablesManager
413
415
  }
414
416
  }
415
417
  _ => Err(
416
- InternalError::ExpectedEdge {
418
+ CompileTimeError::ExpectedEdge {
417
419
  context: "is_valid_existing_edge",
418
420
  }
419
421
  .into(),
@@ -459,7 +461,7 @@ impl VariablesManager
459
461
  fn analyse_edge_path(
460
462
  &mut self,
461
463
  path_variable: Option<ast::VariableIdentifier>,
462
- edge: &crate::parser::ast::EdgePattern,
464
+ edge: &gqlparser::oc::ast::EdgePattern,
463
465
  is_create: bool,
464
466
  ) -> Result<()>
465
467
  {
@@ -538,7 +540,7 @@ impl VariablesManager
538
540
  self.variables = new_variables;
539
541
  Ok(())
540
542
  }
541
- pub(crate) fn analyse(&mut self, statement: &ast::Statement) -> Result<()>
543
+ pub(crate) fn analyse(&mut self, logical_plan: &LogicalPlan) -> Result<()>
542
544
  {
543
545
  if self.variables.iter().any(|(_, var)| !var.is_set)
544
546
  {
@@ -559,17 +561,17 @@ impl VariablesManager
559
561
  .into(),
560
562
  );
561
563
  }
562
- match statement
564
+ match logical_plan
563
565
  {
564
- ast::Statement::CreateGraph(..) =>
566
+ LogicalPlan::CreateGraph { .. } =>
565
567
  {}
566
- ast::Statement::DropGraph(..) =>
568
+ LogicalPlan::DropGraph { .. } =>
567
569
  {}
568
- ast::Statement::UseGraph(..) =>
570
+ LogicalPlan::UseGraph { .. } =>
569
571
  {}
570
- ast::Statement::Create(create) =>
572
+ LogicalPlan::Create { patterns } =>
571
573
  {
572
- for pattern in create.patterns.iter()
574
+ for pattern in patterns.iter()
573
575
  {
574
576
  if let ast::Pattern::Node(n) = &pattern
575
577
  && self.has_variable(&n.variable)
@@ -584,31 +586,97 @@ impl VariablesManager
584
586
  self.analyse_pattern(pattern, true)?;
585
587
  }
586
588
  }
587
- ast::Statement::Match(match_statement) =>
589
+ LogicalPlan::NodeScan { patterns, .. } =>
588
590
  {
589
- for pattern in match_statement.patterns.iter()
591
+ for pattern in patterns.iter()
590
592
  {
591
593
  self.analyse_pattern(pattern, false)?;
592
594
  }
593
595
  }
594
- ast::Statement::Return(..) =>
595
- {}
596
- ast::Statement::Call(..) =>
596
+ LogicalPlan::Filter { source, .. }
597
+ | LogicalPlan::Sort { source, .. }
598
+ | LogicalPlan::Skip { source, .. }
599
+ | LogicalPlan::Limit { source, .. } => self.analyse(source.as_ref())?,
600
+ LogicalPlan::Projection { .. } =>
597
601
  {}
598
- ast::Statement::With(..) =>
602
+ LogicalPlan::Call { .. } =>
599
603
  {}
600
- ast::Statement::Unwind(unwind) =>
604
+ LogicalPlan::Unwind { identifier, .. } =>
601
605
  {
602
- self.declare_variable(
603
- &unwind.identifier.to_owned(),
604
- expression_analyser::ExpressionType::Variant,
605
- )?;
606
- self.mark_variables_as_set(&unwind.identifier)?;
606
+ self.declare_variable(identifier, expression_analyser::ExpressionType::Variant)?;
607
+ self.mark_variables_as_set(identifier)?;
607
608
  }
608
- ast::Statement::Delete(..) =>
609
+ LogicalPlan::Delete { .. } =>
609
610
  {}
610
- ast::Statement::Update(..) =>
611
+ LogicalPlan::Update { .. } =>
611
612
  {}
613
+ LogicalPlan::Merge { patterns, .. } =>
614
+ {
615
+ for pattern in patterns.iter()
616
+ {
617
+ match pattern
618
+ {
619
+ ast::Pattern::Node(n) =>
620
+ {
621
+ if self.has_variable(&n.variable)
622
+ {
623
+ return Err(
624
+ CompileTimeError::VariableAlreadyBound {
625
+ name: n.variable.as_ref().unwrap().name().clone(),
626
+ }
627
+ .into(),
628
+ );
629
+ }
630
+ }
631
+ ast::Pattern::Edge(e) =>
632
+ {
633
+ if self.has_variable(&e.variable)
634
+ {
635
+ return Err(
636
+ CompileTimeError::VariableAlreadyBound {
637
+ name: e.variable.as_ref().unwrap().name().clone(),
638
+ }
639
+ .into(),
640
+ );
641
+ }
642
+ }
643
+ ast::Pattern::Path(p) =>
644
+ {
645
+ if self.has_variable(&Some(p.variable.clone()))
646
+ {
647
+ return Err(
648
+ CompileTimeError::VariableAlreadyBound {
649
+ name: p.variable.name().clone(),
650
+ }
651
+ .into(),
652
+ );
653
+ }
654
+ }
655
+ }
656
+ self.analyse_pattern(pattern, false)?;
657
+ }
658
+ }
659
+ LogicalPlan::VectorSearch {
660
+ result_var,
661
+ score_var,
662
+ ..
663
+ } =>
664
+ {
665
+ // Declare the result variable as a Node
666
+ self.declare_variable(result_var, expression_analyser::ExpressionType::Node)?;
667
+ self.mark_variables_as_set(result_var)?;
668
+
669
+ // Declare the score variable if present
670
+ if let Some(score_var_id) = score_var
671
+ {
672
+ self.declare_variable(score_var_id, expression_analyser::ExpressionType::Float)?;
673
+ self.mark_variables_as_set(score_var_id)?;
674
+ }
675
+ }
676
+ LogicalPlan::CreateVectorIndex { .. } =>
677
+ {
678
+ // Schema operation - no variable analysis needed
679
+ }
612
680
  }
613
681
  Ok(())
614
682
  }