gqlite 1.2.2 → 1.3.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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/ext/Cargo.toml +20 -0
  3. data/ext/gqlitedb/Cargo.toml +77 -0
  4. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/benches/common/pokec.rs +30 -20
  5. data/ext/gqlitedb/gqlite_bench_data/README.MD +6 -0
  6. data/ext/gqlitedb/gqlite_bench_data/scripts/generate_smaller_pokec.rb +85 -0
  7. data/ext/gqlitedb/gqlite_bench_data/scripts/to_efficient_pokec.rb +34 -0
  8. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/release.toml +2 -2
  9. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/aggregators/arithmetic.rs +1 -0
  10. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/aggregators/stats.rs +27 -49
  11. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/aggregators.rs +7 -7
  12. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/capi.rs +34 -10
  13. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/compiler/expression_analyser.rs +10 -4
  14. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/compiler/variables_manager.rs +36 -39
  15. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/compiler.rs +46 -41
  16. data/ext/gqlitedb/src/connection.rs +300 -0
  17. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/error.rs +113 -50
  18. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/functions/containers.rs +21 -26
  19. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/functions/edge.rs +3 -3
  20. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/functions/math.rs +3 -3
  21. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/functions/node.rs +2 -2
  22. data/ext/gqlitedb/src/functions/path.rs +75 -0
  23. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/functions/scalar.rs +3 -3
  24. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/functions/string.rs +1 -1
  25. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/functions/value.rs +7 -7
  26. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/functions.rs +29 -31
  27. data/ext/gqlitedb/src/graph.rs +11 -0
  28. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/interpreter/evaluators.rs +178 -224
  29. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/interpreter/instructions.rs +8 -2
  30. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/lib.rs +9 -5
  31. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/parser/ast.rs +54 -76
  32. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/parser/gql.pest +9 -4
  33. data/ext/{gqliterb/vendor/gqlitedb/src/parser/parser.rs → gqlitedb/src/parser/parser_impl.rs} +86 -34
  34. data/ext/gqlitedb/src/parser.rs +4 -0
  35. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/prelude.rs +3 -2
  36. data/ext/gqlitedb/src/query_result.rs +88 -0
  37. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/store/redb.rs +260 -170
  38. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/store/sqlite.rs +157 -142
  39. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/store.rs +30 -23
  40. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/tests/evaluators.rs +41 -85
  41. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/tests/store/redb.rs +12 -5
  42. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/tests/store/sqlite.rs +12 -5
  43. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/tests/store.rs +106 -114
  44. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/tests/templates/ast.rs +29 -29
  45. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/tests/templates/programs.rs +4 -4
  46. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/value/compare.rs +13 -20
  47. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/value/contains.rs +2 -2
  48. data/ext/gqlitedb/src/value.rs +225 -0
  49. data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/value_table.rs +22 -18
  50. data/ext/gqliterb/Cargo.toml +12 -34
  51. data/ext/gqliterb/src/lib.rs +67 -39
  52. data/ext/graphcore/Cargo.toml +19 -0
  53. data/ext/graphcore/README.MD +4 -0
  54. data/ext/graphcore/release.toml +1 -0
  55. data/ext/graphcore/src/error.rs +28 -0
  56. data/ext/{gqliterb/vendor/gqlitedb → graphcore}/src/graph.rs +146 -35
  57. data/ext/graphcore/src/lib.rs +16 -0
  58. data/ext/graphcore/src/prelude.rs +4 -0
  59. data/ext/{gqliterb/vendor/gqlitedb → graphcore}/src/serialize_with.rs +2 -2
  60. data/ext/graphcore/src/table.rs +272 -0
  61. data/ext/{gqliterb/vendor/gqlitedb → graphcore}/src/value/value_map.rs +44 -49
  62. data/ext/graphcore/src/value.rs +413 -0
  63. metadata +94 -83
  64. data/ext/gqliterb/.cargo/config.toml +0 -2
  65. data/ext/gqliterb/Cargo.lock +0 -1109
  66. data/ext/gqliterb/vendor/gqlitedb/Cargo.lock +0 -2060
  67. data/ext/gqliterb/vendor/gqlitedb/Cargo.toml +0 -132
  68. data/ext/gqliterb/vendor/gqlitedb/src/connection.rs +0 -208
  69. data/ext/gqliterb/vendor/gqlitedb/src/functions/path.rs +0 -48
  70. data/ext/gqliterb/vendor/gqlitedb/src/parser.rs +0 -4
  71. data/ext/gqliterb/vendor/gqlitedb/src/value.rs +0 -559
  72. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/askama.toml +0 -0
  73. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/benches/common/mod.rs +0 -0
  74. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/benches/pokec_divan.rs +0 -0
  75. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/benches/pokec_iai.rs +0 -0
  76. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/aggregators/containers.rs +0 -0
  77. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/aggregators/count.rs +0 -0
  78. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/consts.rs +0 -0
  79. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/interpreter/mod.rs +0 -0
  80. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/store/pgql.rs +0 -0
  81. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/tests/compiler.rs +0 -0
  82. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/tests/parser.rs +0 -0
  83. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/tests/templates.rs +0 -0
  84. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/tests.rs +0 -0
  85. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/utils.rs +0 -0
  86. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/call_stats.sql +0 -0
  87. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/edge_count_for_node.sql +0 -0
  88. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/edge_create.sql +0 -0
  89. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/edge_delete.sql +0 -0
  90. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/edge_delete_by_nodes.sql +0 -0
  91. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/edge_select.sql +0 -0
  92. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/edge_update.sql +0 -0
  93. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/graph_create.sql +0 -0
  94. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/graph_delete.sql +0 -0
  95. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/metadata_create_table.sql +0 -0
  96. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/metadata_get.sql +0 -0
  97. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/metadata_set.sql +0 -0
  98. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/node_create.sql +0 -0
  99. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/node_delete.sql +0 -0
  100. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/node_select.sql +0 -0
  101. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/node_update.sql +0 -0
  102. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/table_exists.sql +0 -0
  103. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/upgrade_from_1_01.sql +0 -0
  104. /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/upgrade_graph_from_1_01.sql +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2a66832adf2787c8b76783992b8a44d69aad4f33a19ec5a386113634d5960c29
4
- data.tar.gz: a9a06b53be1c30adeb351a89eb6084076aabefa6159a39f33591d3cfcd114344
3
+ metadata.gz: c8b19f14f03ff7f92bf78f132e0c26f800e2d9ce3be108557bb9d23c11e0e8d1
4
+ data.tar.gz: aad435a97e100195806af926765c90f6c57d1232c51afe771d2b89f00ffa2ea2
5
5
  SHA512:
6
- metadata.gz: 7a94734fd53cbab213064dc79a007acbefb864c203bbbe9117bb0bbe726fa18f33235382a16339b184e8ed72d2f63338614c825d148f3affcded6f2ce4e963f2
7
- data.tar.gz: 7dbcd12228a3d5a2280fd5f3848fb04dd60c8804c699c058cc6bed3e6bf044760613fcf5b6e09866288d2723bceef5c3b06020ad6c29c593bf291dde764c3a99
6
+ metadata.gz: fe9d202a5b338e34141df0240867a68b4f794067dc506d173264a66decd973029dc04f64da9f0a1f6192da8cab652e8c71e8c63a1432c4110259d971d64d3697
7
+ data.tar.gz: 6f90979086a3be82858d38b62bc23a84ab8a05266ca048541d59c87d5f43757219e88c8a2d7c158762e19533e17720f2d5b583d24d8614a6bbef9196374b6004
data/ext/Cargo.toml ADDED
@@ -0,0 +1,20 @@
1
+ [workspace]
2
+ resolver = "2"
3
+ members = ["gqliterb", "gqlitedb", "graphcore"]
4
+
5
+ [workspace.package]
6
+ version = "0.6.0"
7
+ edition = "2021"
8
+ license = "MIT"
9
+ homepage = "https://gqlite.org"
10
+ repository = "https://gitlab.com/gqlite/gqlite"
11
+
12
+ [workspace.dependencies]
13
+ graphcore = { version = "0.2.0", path = "graphcore" }
14
+ gqlitedb = { version = "0.6.0", path = "gqlitedb" }
15
+
16
+ askama = { version = "0.14" }
17
+ itertools = "0.14"
18
+ serde = "1"
19
+ thiserror = "2"
20
+ uuid = { version = "1", features = ["v4"] }
@@ -0,0 +1,77 @@
1
+ [package]
2
+ name = "gqlitedb"
3
+ description = "GQLite is a Rust-language library, with a C interface, that implements a small, fast, self-contained, high-reliability, full-featured, Graph Query database engine."
4
+ readme = "../../README.md"
5
+ version.workspace = true
6
+ edition.workspace = true
7
+ license.workspace = true
8
+ homepage.workspace = true
9
+ repository.workspace = true
10
+
11
+ [lib]
12
+ crate-type = ["cdylib", "lib"]
13
+
14
+ [features]
15
+ default = ["redb", "capi", "sqlite"]
16
+ _backtrace = []
17
+ capi = []
18
+ redb = ["dep:redb", "dep:redb2"]
19
+ _pgql = ["dep:pgrx"]
20
+ _pg13 = ["pgrx/pg13"]
21
+ _pg14 = ["pgrx/pg14"]
22
+ _pg15 = ["pgrx/pg15"]
23
+ _pg16 = ["pgrx/pg16"]
24
+ _pg17 = ["pgrx/pg17"]
25
+ sqlite = ["dep:rusqlite", "dep:askama"]
26
+ _value_private = []
27
+ bundled = ["rusqlite/bundled"]
28
+
29
+ [dependencies]
30
+ graphcore = { workspace = true }
31
+
32
+ askama = { workspace = true, optional = true }
33
+ ccutils = { version = "0.4", features = ["alias", "pool", "sync"] }
34
+ ciborium = "0.2"
35
+ itertools = { workspace = true }
36
+ pgrx = { version = "0.16", optional = true }
37
+ pest = "2"
38
+ pest_derive = "2"
39
+ rand = "0.9"
40
+ redb = { version = "3", optional = true }
41
+ redb2 = { version = "2", optional = true, package = "redb" }
42
+ rusqlite = { package = "rusqlite", version = "0.37", optional = true, features = [
43
+ "functions",
44
+ "uuid",
45
+ ] }
46
+ serde = { workspace = true }
47
+ serde_json = "1"
48
+ thiserror = { workspace = true }
49
+ uuid = { workspace = true }
50
+
51
+ [dev-dependencies]
52
+ ccutils = { version = "0.4", features = ["alias", "temporary"] }
53
+ divan = "0.1"
54
+ iai-callgrind = { version = "0.16" }
55
+ regex = "1"
56
+
57
+ # web:
58
+ [target.'cfg(target_arch = "wasm32")'.dependencies]
59
+ # rusqlite_wasm = { package = "rusqlite", version = "0.37", optional = true, git = "https://github.com/Spxg/rusqlite.git", branch = "wasm-demo", features = [
60
+ # "functions",
61
+ # "uuid",
62
+ # ] }
63
+ uuid = { version = "1", features = ["js"] }
64
+
65
+ # [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
66
+ # rusqlite_main = { package = "rusqlite", version = "0.37", optional = true, features = [
67
+ # "functions",
68
+ # "uuid",
69
+ # ] }
70
+
71
+ [[bench]]
72
+ name = "pokec_divan"
73
+ harness = false
74
+
75
+ [[bench]]
76
+ name = "pokec_iai"
77
+ harness = false
@@ -1,7 +1,7 @@
1
1
  use std::{collections::HashSet, fs};
2
2
 
3
3
  use ccutils::temporary::TemporaryFile;
4
- use gqlitedb::{map, Connection};
4
+ use gqlitedb::{value_map, Connection};
5
5
  use rand::{seq::IndexedRandom, Rng};
6
6
  use regex::Regex;
7
7
 
@@ -24,11 +24,21 @@ impl Pokec
24
24
  {
25
25
  pub(crate) fn load(backend: &str, size: PokecSize) -> Pokec
26
26
  {
27
+ let backend = match backend
28
+ {
29
+ "sqlite" => gqlitedb::Backend::SQLite,
30
+ "redb" => gqlitedb::Backend::Redb,
31
+ o => panic!("Unknown backend '{}'", o),
32
+ };
27
33
  let temporary_file = TemporaryFile::builder()
28
34
  .should_create_file(false)
29
35
  .label("gqlite_bench")
30
36
  .create();
31
- let connection = Connection::open(temporary_file.path(), map!("backend" => backend)).unwrap();
37
+ let connection = Connection::builder()
38
+ .path(temporary_file.path())
39
+ .backend(backend)
40
+ .create()
41
+ .unwrap();
32
42
 
33
43
  let filename = match size
34
44
  {
@@ -39,7 +49,7 @@ impl Pokec
39
49
  let import_query = fs::read_to_string(filename).unwrap();
40
50
 
41
51
  connection
42
- .execute_query(import_query, Default::default())
52
+ .execute_oc_query(import_query, Default::default())
43
53
  .unwrap();
44
54
  Self {
45
55
  temporary_file,
@@ -71,9 +81,9 @@ impl Pokec
71
81
  let random_id = self.ids.choose(rng).unwrap();
72
82
  self
73
83
  .connection
74
- .execute_query(
84
+ .execute_oc_query(
75
85
  "MATCH (n:User {id: $id}) RETURN n",
76
- map!("$id" => *random_id),
86
+ value_map!("$id" => *random_id),
77
87
  )
78
88
  .unwrap();
79
89
  }
@@ -84,9 +94,9 @@ impl Pokec
84
94
  let random_id = self.ids.choose(rng).unwrap();
85
95
  self
86
96
  .connection
87
- .execute_query(
97
+ .execute_oc_query(
88
98
  "MATCH (n:User) WHERE n.id = $id RETURN n",
89
- map!("$id" => *random_id),
99
+ value_map!("$id" => *random_id),
90
100
  )
91
101
  .unwrap();
92
102
  }
@@ -97,9 +107,9 @@ impl Pokec
97
107
  let random_id = self.ids.choose(rng).unwrap();
98
108
  self
99
109
  .connection
100
- .execute_query(
110
+ .execute_oc_query(
101
111
  "MATCH (s:User {id: $id})-->(n:User) RETURN n.id",
102
- map!("$id" => *random_id),
112
+ value_map!("$id" => *random_id),
103
113
  )
104
114
  .unwrap();
105
115
  }
@@ -110,9 +120,9 @@ impl Pokec
110
120
  let random_id = self.ids.choose(rng).unwrap();
111
121
  self
112
122
  .connection
113
- .execute_query(
123
+ .execute_oc_query(
114
124
  "MATCH (s:User {id: $id})-->(n:User) WHERE n.age >= 18 RETURN n.id",
115
- map!("$id" => *random_id),
125
+ value_map!("$id" => *random_id),
116
126
  )
117
127
  .unwrap();
118
128
  }
@@ -123,9 +133,9 @@ impl Pokec
123
133
  let random_id = self.ids.choose(rng).unwrap();
124
134
  self
125
135
  .connection
126
- .execute_query(
136
+ .execute_oc_query(
127
137
  "MATCH (s:User {id: $id})-->()-->(n:User) RETURN n.id",
128
- map!("$id" => *random_id),
138
+ value_map!("$id" => *random_id),
129
139
  )
130
140
  .unwrap();
131
141
  }
@@ -136,9 +146,9 @@ impl Pokec
136
146
  let random_id = self.ids.choose(rng).unwrap();
137
147
  self
138
148
  .connection
139
- .execute_query(
149
+ .execute_oc_query(
140
150
  "MATCH (s:User {id: $id})-->()-->(n:User) WHERE n.age >= 18 RETURN n.id",
141
- map!("$id" => *random_id),
151
+ value_map!("$id" => *random_id),
142
152
  )
143
153
  .unwrap();
144
154
  }
@@ -149,9 +159,9 @@ impl Pokec
149
159
  let random_id = self.ids.choose(rng).unwrap();
150
160
  self
151
161
  .connection
152
- .execute_query(
162
+ .execute_oc_query(
153
163
  "MATCH (n:User {id: $id})-[e1]->(m)-[e2]->(n) RETURN e1, m, e2",
154
- map!("$id" => *random_id),
164
+ value_map!("$id" => *random_id),
155
165
  )
156
166
  .unwrap();
157
167
  }
@@ -159,14 +169,14 @@ impl Pokec
159
169
  {
160
170
  self
161
171
  .connection
162
- .execute_query("MATCH (n:User) RETURN n.age, count(*)", Default::default())
172
+ .execute_oc_query("MATCH (n:User) RETURN n.age, count(*)", Default::default())
163
173
  .unwrap();
164
174
  }
165
175
  pub(crate) fn aggregate_count_filter(&self)
166
176
  {
167
177
  self
168
178
  .connection
169
- .execute_query(
179
+ .execute_oc_query(
170
180
  "MATCH (n:User) WHERE n.age >= 18 RETURN n.age, count(*)",
171
181
  Default::default(),
172
182
  )
@@ -176,7 +186,7 @@ impl Pokec
176
186
  {
177
187
  self
178
188
  .connection
179
- .execute_query(
189
+ .execute_oc_query(
180
190
  "MATCH (n) RETURN min(n.age), max(n.age), avg(n.age)",
181
191
  Default::default(),
182
192
  )
@@ -0,0 +1,6 @@
1
+ ![GQLite logo](logo.png) GQLite Benchnark Data
2
+ ==============================================
3
+
4
+ This repository includes data used to benchmark GQLite.
5
+
6
+ * `pokec_tiny_nodes.cypher` is a subset of the [pokec mini](https://github.com/memgraph/memgraph/tree/master/tests/mgbench#pokec) dataset ([original](https://snap.stanford.edu/data/soc-Pokec.html)).
@@ -0,0 +1,85 @@
1
+ # Script that reduces the pokec dataset, to reduce it to a subset of users.
2
+ # It also reduce the initial set of queries into a single one.
3
+ #
4
+ # Use as:
5
+ # ```bash
6
+ # ruby reduce_pokec.rb size input.cypher > output.cypher
7
+ # ```
8
+
9
+ require 'set'
10
+
11
+ size = ARGV[0] or abort("Usage: ruby #{$0} micro/tiny input.cypher")
12
+ input_file = ARGV[1] or abort("Usage: ruby #{$0} micro/tiny input.cypher")
13
+
14
+ if size == "tiny"
15
+ initial = 5
16
+ increments = 2
17
+ elsif size == "micro"
18
+ initial = 1
19
+ increments = 1
20
+ else
21
+ abort("Unknown size '#{size}', should be 'tiny' or 'micro'")
22
+ end
23
+
24
+ user_lines = {}
25
+ all_edges = []
26
+ edges_by_user = Hash.new { |h, k| h[k] = [] }
27
+ selected_edges = []
28
+ seen_edges = Set.new
29
+ selected_users = Set.new
30
+
31
+ def edge_key(id1, id2)
32
+ [id1, id2].sort.join('-')
33
+ end
34
+
35
+ File.foreach(input_file) do |line|
36
+ if line =~ /CREATE\s+\(:User\s*(\{.*id:\s*(\d+)[^}]*\})\)/i
37
+ user_lines[$2.to_i] = $1
38
+
39
+ elsif line =~ /MATCH\s+\(n:User\s*\{id:\s*(\d+)\}\),\s*\(m:User\s*\{id:\s*(\d+)\}\).*CREATE.*Friend/i
40
+ id1, id2 = $1.to_i, $2.to_i
41
+ edge = { line: line, ids: [id1, id2] }
42
+ all_edges << edge
43
+ edges_by_user[id1] << edge
44
+ edges_by_user[id2] << edge
45
+ end
46
+ end
47
+
48
+ # Step 1: Select initial edges
49
+ initial_edges = all_edges.take(initial)
50
+ initial_edges.each do |edge|
51
+ k = edge_key(*edge[:ids])
52
+ next if seen_edges.include?(k)
53
+
54
+ seen_edges << k
55
+ selected_edges << edge
56
+ selected_users.merge(edge[:ids])
57
+ end
58
+
59
+ # Step 2: Find all other edges connected to selected users
60
+ for i in 0...increments
61
+ for uid in selected_users.clone()
62
+ edges_by_user[uid].each do |edge|
63
+ k = edge_key(*edge[:ids])
64
+ next if seen_edges.include?(k)
65
+
66
+ seen_edges << k
67
+ selected_edges << edge
68
+
69
+ # Add any new user ID to the queue
70
+ selected_users.merge(edge[:ids])
71
+ end
72
+ end
73
+ end
74
+
75
+ puts "CREATE"
76
+ # Output user CREATEs
77
+ selected_users.each do |id|
78
+ puts " (user_#{id}:User #{user_lines[id]})," if user_lines.key?(id)
79
+ end
80
+
81
+ # Output edges
82
+ selected_edges.each do |edge|
83
+ ids = edge[:ids]
84
+ puts " (user_#{ids[0]})-[:Friend]->(user_#{ids[1]}),"
85
+ end
@@ -0,0 +1,34 @@
1
+ # Script that transform the pokec dataset into a more efficient query.
2
+ #
3
+ # Use as:
4
+ # ```bash
5
+ # ruby to_efficient_pokec.rb input.cypher > output.cypher
6
+ # ```
7
+
8
+ require 'set'
9
+
10
+ input_file = ARGV[0] or abort("Usage: ruby #{$0} input.cypher")
11
+
12
+ user_lines = []
13
+ edge_lines = []
14
+
15
+ File.foreach(input_file) do |line|
16
+ if line =~ /CREATE\s+\(:User\s*(\{.*id:\s*(\d+)[^}]*\})\)/i
17
+ user_lines.append({ id: $2.to_i, data: $1})
18
+
19
+ elsif line =~ /MATCH\s+\(n:User\s*\{id:\s*(\d+)\}\),\s*\(m:User\s*\{id:\s*(\d+)\}\).*CREATE.*Friend/i
20
+ id1, id2 = $1.to_i, $2.to_i
21
+ edge_lines.append({ id1: id1, id2: id2 })
22
+ end
23
+ end
24
+
25
+ puts "CREATE"
26
+ # Output user CREATEs
27
+ user_lines.each do |user|
28
+ puts " (user_#{user[:id]}:User #{user[:data]}),"
29
+ end
30
+
31
+ # Output edges
32
+ edge_lines.each do |edge|
33
+ puts " (user_#{edge[:id1]})-[:Friend]->(user_#{edge[:id2]}),"
34
+ end
@@ -1,7 +1,7 @@
1
1
  pre-release-replacements = [
2
2
  { file = "../../CHANGELOG.md", search = "Unreleased", replace = "{{version}}" },
3
- { file = "../../CHANGELOG.md", search = "\\.\\.\\.dev/2", replace = "...{{tag_name}}", exactly = 1 },
3
+ { file = "../../CHANGELOG.md", search = "\\.\\.\\.dev/1", replace = "...{{tag_name}}", 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/2", 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 },
7
7
  ]
@@ -41,6 +41,7 @@ where
41
41
  match self.value
42
42
  {
43
43
  Value::Boolean(..)
44
+ | Value::Key(..)
44
45
  | Value::Node(..)
45
46
  | Value::Edge(..)
46
47
  | Value::Array(..)
@@ -2,16 +2,12 @@ use std::fmt::Debug;
2
2
 
3
3
  use super::AggregatorState;
4
4
 
5
- use crate::{
6
- error::{InternalError, RunTimeError},
7
- value::Value,
8
- Result,
9
- };
5
+ use crate::prelude::*;
10
6
 
11
7
  #[derive(Debug)]
12
8
  struct AvgState
13
9
  {
14
- value: Value,
10
+ value: value::Value,
15
11
  count: usize,
16
12
  }
17
13
 
@@ -20,7 +16,7 @@ impl AvgState
20
16
  fn new() -> Result<Self>
21
17
  {
22
18
  Ok(Self {
23
- value: Value::Null,
19
+ value: value::Value::Null,
24
20
  count: 0,
25
21
  })
26
22
  }
@@ -28,7 +24,7 @@ impl AvgState
28
24
 
29
25
  impl AggregatorState for AvgState
30
26
  {
31
- fn next(&mut self, value: Value) -> crate::Result<()>
27
+ fn next(&mut self, value: value::Value) -> crate::Result<()>
32
28
  {
33
29
  if self.value.is_null()
34
30
  {
@@ -38,25 +34,25 @@ impl AggregatorState for AvgState
38
34
  {
39
35
  match value
40
36
  {
41
- Value::Null =>
37
+ value::Value::Null =>
42
38
  {}
43
- Value::Integer(i) =>
39
+ value::Value::Integer(i) =>
44
40
  {
45
41
  self.count += 1;
46
42
  match self.value
47
43
  {
48
- Value::Integer(vi) => self.value = (vi + i).into(),
49
- Value::Float(vf) => self.value = (vf + i as f64).into(),
44
+ value::Value::Integer(vi) => self.value = (vi + i).into(),
45
+ value::Value::Float(vf) => self.value = (vf + i as f64).into(),
50
46
  _ => Err(InternalError::InvalidAggregationState)?,
51
47
  }
52
48
  }
53
- Value::Float(f) =>
49
+ value::Value::Float(f) =>
54
50
  {
55
51
  self.count += 1;
56
52
  match self.value
57
53
  {
58
- Value::Integer(vi) => self.value = (vi as f64 + f).into(),
59
- Value::Float(vf) => self.value = (vf + f).into(),
54
+ value::Value::Integer(vi) => self.value = (vi as f64 + f).into(),
55
+ value::Value::Float(vf) => self.value = (vf + f).into(),
60
56
  _ => Err(InternalError::InvalidAggregationState)?,
61
57
  }
62
58
  }
@@ -69,50 +65,41 @@ impl AggregatorState for AvgState
69
65
  {
70
66
  match self.value
71
67
  {
72
- Value::Null => Ok(Value::Null),
73
- Value::Integer(vi) => Ok((vi / self.count as i64).into()),
74
- Value::Float(vf) => Ok((vf / self.count as f64).into()),
68
+ value::Value::Null => Ok(value::Value::Null),
69
+ value::Value::Integer(vi) => Ok((vi / self.count as i64).into()),
70
+ value::Value::Float(vf) => Ok((vf / self.count as f64).into()),
75
71
  _ => Err(InternalError::InvalidAggregationState)?,
76
72
  }
77
73
  }
78
74
  }
79
75
 
80
- super::declare_aggregator!(avg, Avg, AvgState, () -> Value);
76
+ super::declare_aggregator!(avg, Avg, AvgState, () -> value::Value);
81
77
 
82
78
  #[derive(Debug)]
83
79
  struct MinState
84
80
  {
85
- value: Value,
81
+ value: value::Value,
86
82
  }
87
83
 
88
84
  impl MinState
89
85
  {
90
86
  fn new() -> Result<Self>
91
87
  {
92
- Ok(Self { value: Value::Null })
88
+ Ok(Self {
89
+ value: value::Value::Null,
90
+ })
93
91
  }
94
92
  }
95
93
 
96
94
  impl AggregatorState for MinState
97
95
  {
98
- fn next(&mut self, value: Value) -> crate::Result<()>
96
+ fn next(&mut self, value: value::Value) -> crate::Result<()>
99
97
  {
100
98
  if self.value.is_null()
99
+ || (!value.is_null() && value.orderability(&self.value) == std::cmp::Ordering::Less)
101
100
  {
102
101
  self.value = value;
103
102
  }
104
- else if !value.is_null()
105
- {
106
- match value.orderability(&self.value)
107
- {
108
- std::cmp::Ordering::Less =>
109
- {
110
- self.value = value;
111
- }
112
- _ =>
113
- {}
114
- }
115
- }
116
103
  Ok(())
117
104
  }
118
105
  fn finalise(self: Box<Self>) -> crate::Result<crate::value::Value>
@@ -126,37 +113,28 @@ super::declare_aggregator!(min, Min, MinState, () -> i64);
126
113
  #[derive(Debug)]
127
114
  struct MaxState
128
115
  {
129
- value: Value,
116
+ value: value::Value,
130
117
  }
131
118
 
132
119
  impl MaxState
133
120
  {
134
121
  fn new() -> Result<Self>
135
122
  {
136
- Ok(Self { value: Value::Null })
123
+ Ok(Self {
124
+ value: value::Value::Null,
125
+ })
137
126
  }
138
127
  }
139
128
 
140
129
  impl AggregatorState for MaxState
141
130
  {
142
- fn next(&mut self, value: Value) -> crate::Result<()>
131
+ fn next(&mut self, value: value::Value) -> crate::Result<()>
143
132
  {
144
133
  if self.value.is_null()
134
+ || (!value.is_null() && value.orderability(&self.value) == std::cmp::Ordering::Greater)
145
135
  {
146
136
  self.value = value;
147
137
  }
148
- else if !value.is_null()
149
- {
150
- match value.orderability(&self.value)
151
- {
152
- std::cmp::Ordering::Greater =>
153
- {
154
- self.value = value;
155
- }
156
- _ =>
157
- {}
158
- }
159
- }
160
138
  Ok(())
161
139
  }
162
140
  fn finalise(self: Box<Self>) -> crate::Result<crate::value::Value>
@@ -28,7 +28,7 @@ macro_rules! declare_aggregator {
28
28
  pub(super) struct $type_name {}
29
29
  impl $type_name
30
30
  {
31
- pub(crate) fn new() -> (String, crate::aggregators::Aggregator)
31
+ pub(crate) fn create() -> (String, crate::aggregators::Aggregator)
32
32
  {
33
33
  (
34
34
  stringify!($function_name).to_string(),
@@ -63,12 +63,12 @@ pub(crate) use declare_aggregator;
63
63
  pub(crate) fn init_aggregators() -> std::collections::HashMap<String, Aggregator>
64
64
  {
65
65
  [
66
- count::Count::new(),
67
- arithmetic::Sum::new(),
68
- containers::Collect::new(),
69
- stats::Avg::new(),
70
- stats::Min::new(),
71
- stats::Max::new(),
66
+ count::Count::create(),
67
+ arithmetic::Sum::create(),
68
+ containers::Collect::create(),
69
+ stats::Avg::create(),
70
+ stats::Min::create(),
71
+ stats::Max::create(),
72
72
  ]
73
73
  .into()
74
74
  }