gqlite 1.2.3 → 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.
- checksums.yaml +4 -4
- data/ext/Cargo.toml +20 -0
- data/ext/gqlitedb/Cargo.toml +77 -0
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/benches/common/pokec.rs +30 -20
- data/ext/gqlitedb/gqlite_bench_data/README.MD +6 -0
- data/ext/gqlitedb/gqlite_bench_data/scripts/generate_smaller_pokec.rb +85 -0
- data/ext/gqlitedb/gqlite_bench_data/scripts/to_efficient_pokec.rb +34 -0
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/aggregators/arithmetic.rs +1 -0
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/aggregators/stats.rs +27 -49
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/aggregators.rs +7 -7
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/capi.rs +10 -9
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/compiler/expression_analyser.rs +6 -4
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/compiler/variables_manager.rs +27 -31
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/compiler.rs +37 -41
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/connection.rs +42 -84
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/error.rs +105 -34
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/functions/containers.rs +21 -26
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/functions/edge.rs +2 -2
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/functions/math.rs +2 -2
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/functions/node.rs +1 -1
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/functions/path.rs +15 -20
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/functions/scalar.rs +2 -2
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/functions/value.rs +6 -6
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/functions.rs +20 -20
- data/ext/gqlitedb/src/graph.rs +11 -0
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/interpreter/evaluators.rs +160 -194
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/interpreter/instructions.rs +2 -1
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/lib.rs +9 -4
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/parser/ast.rs +44 -52
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/parser/gql.pest +1 -1
- data/ext/{gqliterb/vendor/gqlitedb/src/parser/parser.rs → gqlitedb/src/parser/parser_impl.rs} +50 -28
- data/ext/gqlitedb/src/parser.rs +4 -0
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/prelude.rs +3 -2
- data/ext/gqlitedb/src/query_result.rs +88 -0
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/store/redb.rs +226 -148
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/store/sqlite.rs +111 -128
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/store.rs +22 -22
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/tests/evaluators.rs +32 -76
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/tests/store.rs +95 -111
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/tests/templates/ast.rs +29 -29
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/tests/templates/programs.rs +4 -4
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/value/compare.rs +13 -20
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/value/contains.rs +2 -2
- data/ext/gqlitedb/src/value.rs +225 -0
- data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/value_table.rs +15 -5
- data/ext/gqliterb/Cargo.toml +12 -35
- data/ext/gqliterb/src/lib.rs +60 -38
- data/ext/graphcore/Cargo.toml +19 -0
- data/ext/graphcore/README.MD +4 -0
- data/ext/graphcore/release.toml +1 -0
- data/ext/graphcore/src/error.rs +28 -0
- data/ext/{gqliterb/vendor/gqlitedb → graphcore}/src/graph.rs +134 -38
- data/ext/graphcore/src/lib.rs +16 -0
- data/ext/graphcore/src/prelude.rs +4 -0
- data/ext/{gqliterb/vendor/gqlitedb → graphcore}/src/serialize_with.rs +2 -2
- data/ext/graphcore/src/table.rs +272 -0
- data/ext/{gqliterb/vendor/gqlitedb → graphcore}/src/value/value_map.rs +44 -49
- data/ext/graphcore/src/value.rs +413 -0
- metadata +94 -83
- data/ext/gqliterb/.cargo/config.toml +0 -2
- data/ext/gqliterb/Cargo.lock +0 -1116
- data/ext/gqliterb/vendor/gqlitedb/Cargo.lock +0 -2115
- data/ext/gqliterb/vendor/gqlitedb/Cargo.toml +0 -138
- data/ext/gqliterb/vendor/gqlitedb/src/parser.rs +0 -4
- data/ext/gqliterb/vendor/gqlitedb/src/value.rs +0 -609
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/askama.toml +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/benches/common/mod.rs +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/benches/pokec_divan.rs +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/benches/pokec_iai.rs +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/release.toml +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/aggregators/containers.rs +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/aggregators/count.rs +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/consts.rs +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/functions/string.rs +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/interpreter/mod.rs +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/store/pgql.rs +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/tests/compiler.rs +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/tests/parser.rs +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/tests/store/redb.rs +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/tests/store/sqlite.rs +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/tests/templates.rs +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/tests.rs +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/src/utils.rs +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/call_stats.sql +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/edge_count_for_node.sql +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/edge_create.sql +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/edge_delete.sql +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/edge_delete_by_nodes.sql +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/edge_select.sql +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/edge_update.sql +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/graph_create.sql +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/graph_delete.sql +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/metadata_create_table.sql +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/metadata_get.sql +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/metadata_set.sql +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/node_create.sql +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/node_delete.sql +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/node_select.sql +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/node_update.sql +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/table_exists.sql +0 -0
- /data/ext/{gqliterb/vendor/gqlitedb → gqlitedb}/templates/sql/sqlite/upgrade_from_1_01.sql +0 -0
- /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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c8b19f14f03ff7f92bf78f132e0c26f800e2d9ce3be108557bb9d23c11e0e8d1
|
4
|
+
data.tar.gz: aad435a97e100195806af926765c90f6c57d1232c51afe771d2b89f00ffa2ea2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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::{
|
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::
|
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
|
-
.
|
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
|
-
.
|
84
|
+
.execute_oc_query(
|
75
85
|
"MATCH (n:User {id: $id}) RETURN n",
|
76
|
-
|
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
|
-
.
|
97
|
+
.execute_oc_query(
|
88
98
|
"MATCH (n:User) WHERE n.id = $id RETURN n",
|
89
|
-
|
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
|
-
.
|
110
|
+
.execute_oc_query(
|
101
111
|
"MATCH (s:User {id: $id})-->(n:User) RETURN n.id",
|
102
|
-
|
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
|
-
.
|
123
|
+
.execute_oc_query(
|
114
124
|
"MATCH (s:User {id: $id})-->(n:User) WHERE n.age >= 18 RETURN n.id",
|
115
|
-
|
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
|
-
.
|
136
|
+
.execute_oc_query(
|
127
137
|
"MATCH (s:User {id: $id})-->()-->(n:User) RETURN n.id",
|
128
|
-
|
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
|
-
.
|
149
|
+
.execute_oc_query(
|
140
150
|
"MATCH (s:User {id: $id})-->()-->(n:User) WHERE n.age >= 18 RETURN n.id",
|
141
|
-
|
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
|
-
.
|
162
|
+
.execute_oc_query(
|
153
163
|
"MATCH (n:User {id: $id})-[e1]->(m)-[e2]->(n) RETURN e1, m, e2",
|
154
|
-
|
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
|
-
.
|
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
|
-
.
|
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
|
-
.
|
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 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
|
@@ -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 {
|
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 {
|
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
|
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::
|
67
|
-
arithmetic::Sum::
|
68
|
-
containers::Collect::
|
69
|
-
stats::Avg::
|
70
|
-
stats::Min::
|
71
|
-
stats::Max::
|
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
|
}
|
@@ -173,11 +173,13 @@ pub extern "C" fn gqlite_connection_query(
|
|
173
173
|
let conn = unsafe { Box::from_raw(connection) };
|
174
174
|
let result = conn
|
175
175
|
.connection
|
176
|
-
.
|
176
|
+
.execute_oc_query(query, get_value(bindings).into_map());
|
177
177
|
let _ = Box::into_raw(conn);
|
178
178
|
if let Ok(v) = handle_error(context, result)
|
179
179
|
{
|
180
|
-
return Box::into_raw(Box::new(GqliteValueT {
|
180
|
+
return Box::into_raw(Box::new(GqliteValueT {
|
181
|
+
value: v.into_value(),
|
182
|
+
}));
|
181
183
|
}
|
182
184
|
}
|
183
185
|
std::ptr::null::<GqliteValueT>() as *mut GqliteValueT
|
@@ -222,7 +224,7 @@ pub extern "C" fn gqlite_value_to_json(
|
|
222
224
|
return r;
|
223
225
|
}
|
224
226
|
let _ = Box::into_raw(value);
|
225
|
-
|
227
|
+
std::ptr::null()
|
226
228
|
}
|
227
229
|
|
228
230
|
#[no_mangle]
|
@@ -241,7 +243,7 @@ pub extern "C" fn gqlite_value_from_json(
|
|
241
243
|
return Box::into_raw(Box::new(GqliteValueT { value: v }));
|
242
244
|
}
|
243
245
|
}
|
244
|
-
|
246
|
+
std::ptr::null::<GqliteValueT>() as *mut GqliteValueT
|
245
247
|
}
|
246
248
|
|
247
249
|
#[no_mangle]
|
@@ -251,9 +253,8 @@ pub extern "C" fn gqlite_value_is_valid(
|
|
251
253
|
) -> bool
|
252
254
|
{
|
253
255
|
check_error(context);
|
254
|
-
|
255
|
-
|
256
|
-
crate::value::Value::Null
|
257
|
-
|
258
|
-
}
|
256
|
+
!matches!(
|
257
|
+
unsafe { (*value).value.borrow() },
|
258
|
+
crate::value::Value::Null
|
259
|
+
)
|
259
260
|
}
|
@@ -11,6 +11,7 @@ use crate::{compiler::variables_manager::VariablesManager, parser::ast, prelude:
|
|
11
11
|
pub(crate) enum ExpressionType
|
12
12
|
{
|
13
13
|
Array,
|
14
|
+
Key,
|
14
15
|
Map,
|
15
16
|
Node,
|
16
17
|
Edge,
|
@@ -134,7 +135,7 @@ where
|
|
134
135
|
}
|
135
136
|
}
|
136
137
|
|
137
|
-
impl<
|
138
|
+
impl<VT> ExpressionAnalyser for (&ast::Expression, VT)
|
138
139
|
where
|
139
140
|
VT: Fn(ExpressionInfo) -> Result<ExpressionInfo>,
|
140
141
|
{
|
@@ -188,8 +189,8 @@ impl ExpressionInfo
|
|
188
189
|
let dependents = dependents.into();
|
189
190
|
Self {
|
190
191
|
expression_type,
|
191
|
-
constant: dependents.iter().all(|x| x.constant
|
192
|
-
aggregation_result: dependents.into_iter().any(|x| x.aggregation_result
|
192
|
+
constant: dependents.iter().all(|x| x.constant),
|
193
|
+
aggregation_result: dependents.into_iter().any(|x| x.aggregation_result),
|
193
194
|
}
|
194
195
|
}
|
195
196
|
}
|
@@ -253,7 +254,7 @@ impl<'b> Analyser<'b>
|
|
253
254
|
arguments.iter().map(|x| x.expression_type).collect(),
|
254
255
|
)?,
|
255
256
|
self.functions_manager.is_deterministic(&call.name)?
|
256
|
-
&& arguments.iter().all(|x| x.constant
|
257
|
+
&& arguments.iter().all(|x| x.constant),
|
257
258
|
self.functions_manager.is_aggregate(&call.name)?,
|
258
259
|
))
|
259
260
|
}
|
@@ -408,6 +409,7 @@ impl<'b> Analyser<'b>
|
|
408
409
|
match val.value
|
409
410
|
{
|
410
411
|
value::Value::Array(_) => ExpressionType::Array,
|
412
|
+
value::Value::Key(_) => ExpressionType::Key,
|
411
413
|
value::Value::Boolean(_) => ExpressionType::Boolean,
|
412
414
|
value::Value::Edge(_) => ExpressionType::Edge,
|
413
415
|
value::Value::Node(_) => ExpressionType::Node,
|