gqlite 1.5.0 → 1.7.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 +12 -6
- data/ext/db-index/Cargo.toml +29 -0
- data/ext/db-index/src/hnsw/error.rs +66 -0
- data/ext/db-index/src/hnsw/graph_store.rs +272 -0
- data/ext/db-index/src/hnsw/id.rs +36 -0
- data/ext/db-index/src/hnsw/implementation.rs +1517 -0
- data/ext/db-index/src/hnsw/kernels.rs +1228 -0
- data/ext/db-index/src/hnsw/metric.rs +244 -0
- data/ext/db-index/src/hnsw/scalar.rs +72 -0
- data/ext/db-index/src/hnsw/simple_store.rs +140 -0
- data/ext/db-index/src/hnsw/store.rs +472 -0
- data/ext/db-index/src/hnsw/vector.rs +105 -0
- data/ext/db-index/src/hnsw/vectors.rs +568 -0
- data/ext/db-index/src/hnsw.rs +42 -0
- data/ext/db-index/src/lib.rs +3 -0
- data/ext/gqlitedb/Cargo.toml +19 -8
- data/ext/gqlitedb/benches/common/pokec.rs +62 -2
- data/ext/gqlitedb/benches/pokec_divan.rs +66 -2
- data/ext/gqlitedb/benches/pokec_iai.rs +60 -3
- data/ext/gqlitedb/release.toml +2 -2
- data/ext/gqlitedb/src/aggregators/arithmetic.rs +3 -1
- data/ext/gqlitedb/src/aggregators/containers.rs +1 -1
- data/ext/gqlitedb/src/aggregators/stats.rs +21 -12
- data/ext/gqlitedb/src/capi.rs +20 -24
- data/ext/gqlitedb/src/compiler/expression_analyser.rs +28 -20
- data/ext/gqlitedb/src/compiler/variables_manager.rs +104 -38
- data/ext/gqlitedb/src/compiler.rs +506 -227
- data/ext/gqlitedb/src/connection.rs +151 -11
- data/ext/gqlitedb/src/consts.rs +1 -2
- data/ext/gqlitedb/src/error.rs +123 -61
- data/ext/gqlitedb/src/functions/common.rs +64 -0
- data/ext/gqlitedb/src/functions/containers.rs +2 -46
- data/ext/gqlitedb/src/functions/edge.rs +1 -1
- data/ext/gqlitedb/src/functions/math.rs +87 -15
- data/ext/gqlitedb/src/functions/node.rs +1 -1
- data/ext/gqlitedb/src/functions/path.rs +48 -11
- data/ext/gqlitedb/src/functions/scalar.rs +47 -4
- data/ext/gqlitedb/src/functions/string.rs +123 -1
- data/ext/gqlitedb/src/functions/value.rs +1 -1
- data/ext/gqlitedb/src/functions.rs +165 -28
- data/ext/gqlitedb/src/graph.rs +1 -9
- data/ext/gqlitedb/src/interpreter/evaluators.rs +968 -130
- data/ext/gqlitedb/src/interpreter/instructions.rs +39 -2
- data/ext/gqlitedb/src/lib.rs +5 -4
- data/ext/gqlitedb/src/parser/gql.pest +1 -1
- data/ext/gqlitedb/src/planner.rs +329 -0
- data/ext/gqlitedb/src/prelude.rs +3 -3
- data/ext/gqlitedb/src/store/pgrx.rs +1 -1
- data/ext/gqlitedb/src/store/postgres.rs +742 -16
- data/ext/gqlitedb/src/store/redb/hnsw_store.rs +702 -0
- data/ext/gqlitedb/src/store/redb/index.rs +274 -0
- data/ext/gqlitedb/src/store/redb.rs +1268 -113
- data/ext/gqlitedb/src/store/sqlbase/sqlmetadata.rs +28 -0
- data/ext/gqlitedb/src/store/sqlbase/sqlstore.rs +103 -0
- data/ext/gqlitedb/src/store/sqlbase.rs +146 -16
- data/ext/gqlitedb/src/store/sqlite.rs +576 -14
- data/ext/gqlitedb/src/store/vector_extract.rs +56 -0
- data/ext/gqlitedb/src/store.rs +140 -29
- data/ext/gqlitedb/src/tests/compiler.rs +207 -10
- data/ext/gqlitedb/src/tests/connection/postgres.rs +38 -3
- data/ext/gqlitedb/src/tests/connection/redb.rs +23 -0
- data/ext/gqlitedb/src/tests/connection/sqlite.rs +31 -0
- data/ext/gqlitedb/src/tests/connection.rs +61 -1
- data/ext/gqlitedb/src/tests/evaluators.rs +162 -7
- data/ext/gqlitedb/src/tests/parser.rs +54 -23
- data/ext/gqlitedb/src/tests/planner.rs +511 -0
- data/ext/gqlitedb/src/tests/store/postgres.rs +7 -0
- data/ext/gqlitedb/src/tests/store/redb.rs +8 -0
- data/ext/gqlitedb/src/tests/store/sqlite.rs +8 -0
- data/ext/gqlitedb/src/tests/store/vector_index/postgres.rs +182 -0
- data/ext/gqlitedb/src/tests/store/vector_index/redb.rs +386 -0
- data/ext/gqlitedb/src/tests/store/vector_index/sqlite.rs +166 -0
- data/ext/gqlitedb/src/tests/store/vector_index.rs +2313 -0
- data/ext/gqlitedb/src/tests/store.rs +78 -14
- data/ext/gqlitedb/src/tests/templates/ast.rs +92 -16
- data/ext/gqlitedb/src/tests/templates/programs.rs +14 -7
- data/ext/gqlitedb/src/tests.rs +15 -9
- data/ext/gqlitedb/src/utils.rs +6 -1
- data/ext/gqlitedb/src/value/compare.rs +61 -3
- data/ext/gqlitedb/src/value.rs +136 -7
- data/ext/gqlitedb/templates/sql/postgres/metadata_delete.sql +1 -0
- data/ext/gqlitedb/templates/sql/postgres/node_select.sql +1 -1
- data/ext/gqlitedb/templates/sql/sqlite/metadata_delete.sql +1 -0
- data/ext/gqliterb/src/lib.rs +53 -8
- data/ext/gqlparser/Cargo.toml +25 -0
- data/ext/gqlparser/README.MD +9 -0
- data/ext/gqlparser/benches/pokec_divan.rs +34 -0
- data/ext/gqlparser/src/common.rs +69 -0
- data/ext/gqlparser/src/gqls/ast.rs +69 -0
- data/ext/gqlparser/src/gqls/constraint.rs +79 -0
- data/ext/gqlparser/src/gqls/error.rs +22 -0
- data/ext/gqlparser/src/gqls/parser.rs +813 -0
- data/ext/gqlparser/src/gqls/prelude.rs +8 -0
- data/ext/gqlparser/src/gqls/properties.rs +115 -0
- data/ext/gqlparser/src/gqls/resolve.rs +207 -0
- data/ext/gqlparser/src/gqls.rs +265 -0
- data/ext/gqlparser/src/lib.rs +7 -0
- data/ext/gqlparser/src/oc/ast.rs +680 -0
- data/ext/gqlparser/src/oc/error.rs +172 -0
- data/ext/gqlparser/src/oc/lexer.rs +429 -0
- data/ext/gqlparser/src/oc/parser/tests.rs +2284 -0
- data/ext/gqlparser/src/oc/parser.rs +2005 -0
- data/ext/gqlparser/src/oc.rs +33 -0
- data/ext/gqlparser/src/prelude.rs +3 -0
- data/ext/graphcore/Cargo.toml +1 -0
- data/ext/graphcore/src/error.rs +26 -0
- data/ext/graphcore/src/graph.rs +177 -51
- data/ext/graphcore/src/lib.rs +4 -2
- data/ext/graphcore/src/open_cypher.rs +12 -0
- data/ext/graphcore/src/table.rs +50 -2
- data/ext/graphcore/src/timestamp.rs +127 -104
- data/ext/graphcore/src/value/tensor.rs +739 -0
- data/ext/graphcore/src/value/value_map.rs +1 -1
- data/ext/graphcore/src/value.rs +343 -19
- metadata +93 -28
- data/ext/gqlitedb/src/parser/ast.rs +0 -604
- data/ext/gqlitedb/src/parser/parser_impl.rs +0 -1213
- data/ext/gqlitedb/src/parser.rs +0 -4
data/ext/gqlitedb/src/value.rs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
mod compare;
|
|
2
2
|
mod contains;
|
|
3
3
|
|
|
4
|
-
pub(crate) use compare::{
|
|
5
|
-
pub(crate) use contains::{
|
|
4
|
+
pub(crate) use compare::{Ordering, compare};
|
|
5
|
+
pub(crate) use contains::{ContainResult, contains};
|
|
6
6
|
|
|
7
|
-
pub use graphcore::{
|
|
7
|
+
pub use graphcore::{DType, Tensor, TimeStamp, Value, ValueMap, ValueTryIntoRef, array, value_map};
|
|
8
8
|
|
|
9
9
|
pub(crate) trait ValueExt
|
|
10
10
|
{
|
|
@@ -115,6 +115,36 @@ impl ValueExt for Value
|
|
|
115
115
|
Value::Float(rhs) => orderability_float(lhs, rhs),
|
|
116
116
|
_ => std::cmp::Ordering::Greater,
|
|
117
117
|
},
|
|
118
|
+
Value::Tensor(lhs) => match rhs
|
|
119
|
+
{
|
|
120
|
+
Value::Null | Value::Key(..) => std::cmp::Ordering::Less,
|
|
121
|
+
Value::Tensor(rhs) =>
|
|
122
|
+
{
|
|
123
|
+
let dc = (lhs.dtype() as u8).cmp(&(rhs.dtype() as u8));
|
|
124
|
+
if dc != std::cmp::Ordering::Equal
|
|
125
|
+
{
|
|
126
|
+
return dc;
|
|
127
|
+
}
|
|
128
|
+
let sc = lhs.shape().cmp(rhs.shape());
|
|
129
|
+
if sc != std::cmp::Ordering::Equal
|
|
130
|
+
{
|
|
131
|
+
return sc;
|
|
132
|
+
}
|
|
133
|
+
lhs.as_bytes().cmp(rhs.as_bytes())
|
|
134
|
+
}
|
|
135
|
+
Value::Array(rhs) =>
|
|
136
|
+
{
|
|
137
|
+
let left_arr = Value::Array(
|
|
138
|
+
lhs
|
|
139
|
+
.to_f32_vec()
|
|
140
|
+
.into_iter()
|
|
141
|
+
.map(|f| Value::Float(f as f64))
|
|
142
|
+
.collect(),
|
|
143
|
+
);
|
|
144
|
+
left_arr.orderability(&Value::Array(rhs.clone()))
|
|
145
|
+
}
|
|
146
|
+
_ => std::cmp::Ordering::Greater,
|
|
147
|
+
},
|
|
118
148
|
Value::Boolean(lhs) => match rhs
|
|
119
149
|
{
|
|
120
150
|
Value::Null | Value::Key(..) | Value::Integer(..) | Value::Float(..) =>
|
|
@@ -145,7 +175,7 @@ impl ValueExt for Value
|
|
|
145
175
|
Value::TimeStamp(rhs) => lhs.cmp(rhs),
|
|
146
176
|
_ => std::cmp::Ordering::Greater,
|
|
147
177
|
},
|
|
148
|
-
Value::
|
|
178
|
+
Value::SinglePath(lhs) => match rhs
|
|
149
179
|
{
|
|
150
180
|
Value::Null
|
|
151
181
|
| Value::Key(..)
|
|
@@ -154,7 +184,7 @@ impl ValueExt for Value
|
|
|
154
184
|
| Value::Boolean(..)
|
|
155
185
|
| Value::String(..)
|
|
156
186
|
| Value::TimeStamp(..) => std::cmp::Ordering::Less,
|
|
157
|
-
Value::
|
|
187
|
+
Value::SinglePath(rhs) =>
|
|
158
188
|
{
|
|
159
189
|
match orderability_map(lhs.source().properties(), rhs.source().properties())
|
|
160
190
|
{
|
|
@@ -172,6 +202,97 @@ impl ValueExt for Value
|
|
|
172
202
|
o => o,
|
|
173
203
|
}
|
|
174
204
|
}
|
|
205
|
+
Value::Path(rhs) =>
|
|
206
|
+
{
|
|
207
|
+
if rhs.elements_count() == 1
|
|
208
|
+
{
|
|
209
|
+
match orderability_map(lhs.source().properties(), rhs.source().properties())
|
|
210
|
+
{
|
|
211
|
+
std::cmp::Ordering::Equal =>
|
|
212
|
+
{
|
|
213
|
+
match orderability_map(lhs.properties(), rhs.elements()[0].0.properties())
|
|
214
|
+
{
|
|
215
|
+
std::cmp::Ordering::Equal => orderability_map(
|
|
216
|
+
lhs.destination().properties(),
|
|
217
|
+
rhs.elements()[0].1.properties(),
|
|
218
|
+
),
|
|
219
|
+
o => o,
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
o => o,
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
else
|
|
226
|
+
{
|
|
227
|
+
// rhs has more elements
|
|
228
|
+
std::cmp::Ordering::Less
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
_ => std::cmp::Ordering::Greater,
|
|
232
|
+
},
|
|
233
|
+
Value::Path(lhs) => match rhs
|
|
234
|
+
{
|
|
235
|
+
Value::Null
|
|
236
|
+
| Value::Key(..)
|
|
237
|
+
| Value::Integer(..)
|
|
238
|
+
| Value::Float(..)
|
|
239
|
+
| Value::Boolean(..)
|
|
240
|
+
| Value::String(..)
|
|
241
|
+
| Value::TimeStamp(..) => std::cmp::Ordering::Less,
|
|
242
|
+
Value::SinglePath(rhs) =>
|
|
243
|
+
{
|
|
244
|
+
if lhs.elements_count() == 1
|
|
245
|
+
{
|
|
246
|
+
match orderability_map(lhs.source().properties(), rhs.source().properties())
|
|
247
|
+
{
|
|
248
|
+
std::cmp::Ordering::Equal =>
|
|
249
|
+
{
|
|
250
|
+
match orderability_map(lhs.elements()[0].0.properties(), rhs.properties())
|
|
251
|
+
{
|
|
252
|
+
std::cmp::Ordering::Equal => orderability_map(
|
|
253
|
+
lhs.elements()[0].1.properties(),
|
|
254
|
+
rhs.destination().properties(),
|
|
255
|
+
),
|
|
256
|
+
o => o,
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
o => o,
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
else
|
|
263
|
+
{
|
|
264
|
+
// lhs has more elements
|
|
265
|
+
std::cmp::Ordering::Greater
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
Value::Path(rhs) =>
|
|
269
|
+
{
|
|
270
|
+
match orderability_map(lhs.source().properties(), rhs.source().properties())
|
|
271
|
+
{
|
|
272
|
+
std::cmp::Ordering::Equal =>
|
|
273
|
+
{
|
|
274
|
+
for ((lhs_edge, lhs_destination), (rhs_edge, rhs_destination)) in
|
|
275
|
+
lhs.elements().iter().zip(rhs.elements().iter())
|
|
276
|
+
{
|
|
277
|
+
match orderability_map(lhs_edge.properties(), rhs_edge.properties())
|
|
278
|
+
{
|
|
279
|
+
std::cmp::Ordering::Equal => match orderability_map(
|
|
280
|
+
lhs_destination.properties(),
|
|
281
|
+
rhs_destination.properties(),
|
|
282
|
+
)
|
|
283
|
+
{
|
|
284
|
+
std::cmp::Ordering::Equal =>
|
|
285
|
+
{}
|
|
286
|
+
o => return o,
|
|
287
|
+
},
|
|
288
|
+
o => return o,
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
std::cmp::Ordering::Equal
|
|
292
|
+
}
|
|
293
|
+
o => o,
|
|
294
|
+
}
|
|
295
|
+
}
|
|
175
296
|
_ => std::cmp::Ordering::Greater,
|
|
176
297
|
},
|
|
177
298
|
Value::Array(lhs) => match rhs
|
|
@@ -183,7 +304,9 @@ impl ValueExt for Value
|
|
|
183
304
|
| Value::Boolean(..)
|
|
184
305
|
| Value::String(..)
|
|
185
306
|
| Value::TimeStamp(..)
|
|
186
|
-
| Value::
|
|
307
|
+
| Value::SinglePath(..)
|
|
308
|
+
| Value::Path(..)
|
|
309
|
+
| Value::Tensor(..) => std::cmp::Ordering::Less,
|
|
187
310
|
Value::Array(rhs) => lhs
|
|
188
311
|
.iter()
|
|
189
312
|
.zip(rhs.iter())
|
|
@@ -201,8 +324,10 @@ impl ValueExt for Value
|
|
|
201
324
|
| Value::Boolean(..)
|
|
202
325
|
| Value::String(..)
|
|
203
326
|
| Value::TimeStamp(..)
|
|
327
|
+
| Value::SinglePath(..)
|
|
204
328
|
| Value::Path(..)
|
|
205
|
-
| Value::Array(..)
|
|
329
|
+
| Value::Array(..)
|
|
330
|
+
| Value::Tensor(..) => std::cmp::Ordering::Less,
|
|
206
331
|
Value::Edge(rhs) => orderability_map(lhs.properties(), rhs.properties()),
|
|
207
332
|
_ => std::cmp::Ordering::Greater,
|
|
208
333
|
},
|
|
@@ -215,8 +340,10 @@ impl ValueExt for Value
|
|
|
215
340
|
| Value::Boolean(..)
|
|
216
341
|
| Value::String(..)
|
|
217
342
|
| Value::TimeStamp(..)
|
|
343
|
+
| Value::SinglePath(..)
|
|
218
344
|
| Value::Path(..)
|
|
219
345
|
| Value::Array(..)
|
|
346
|
+
| Value::Tensor(..)
|
|
220
347
|
| Value::Edge(..) => std::cmp::Ordering::Less,
|
|
221
348
|
Value::Node(rhs) => orderability_map(lhs.properties(), rhs.properties()),
|
|
222
349
|
_ => std::cmp::Ordering::Greater,
|
|
@@ -230,8 +357,10 @@ impl ValueExt for Value
|
|
|
230
357
|
| Value::Boolean(..)
|
|
231
358
|
| Value::String(..)
|
|
232
359
|
| Value::TimeStamp(..)
|
|
360
|
+
| Value::SinglePath(..)
|
|
233
361
|
| Value::Path(..)
|
|
234
362
|
| Value::Array(..)
|
|
363
|
+
| Value::Tensor(..)
|
|
235
364
|
| Value::Edge(..)
|
|
236
365
|
| Value::Node(..) => std::cmp::Ordering::Less,
|
|
237
366
|
Value::Map(rhs) => orderability_map(lhs, rhs),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
DELETE FROM gqlite_metadata WHERE name = $1
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
DELETE FROM gqlite_metadata WHERE name = ?
|
data/ext/gqliterb/src/lib.rs
CHANGED
|
@@ -2,13 +2,12 @@ use std::fmt::Display;
|
|
|
2
2
|
|
|
3
3
|
use gqlitedb::TimeStamp;
|
|
4
4
|
use magnus::{
|
|
5
|
-
function, method,
|
|
5
|
+
Error, ExceptionClass, Integer, IntoValue, RModule, Ruby, Symbol, function, method,
|
|
6
6
|
prelude::*,
|
|
7
7
|
r_array,
|
|
8
8
|
r_hash::{self, ForEach},
|
|
9
9
|
scan_args,
|
|
10
10
|
value::Lazy,
|
|
11
|
-
Error, ExceptionClass, Integer, IntoValue, RModule, Ruby, Symbol,
|
|
12
11
|
};
|
|
13
12
|
|
|
14
13
|
static MODULE: Lazy<RModule> = Lazy::new(|ruby| ruby.define_module("GQLite").unwrap());
|
|
@@ -125,8 +124,12 @@ fn integer_from_u128(ruby: &Ruby, i: u128) -> Result<Integer, Error>
|
|
|
125
124
|
fn node_to_rhash(ruby: &Ruby, node: gqlitedb::Node) -> Result<magnus::Value, Error>
|
|
126
125
|
{
|
|
127
126
|
let r_hash = ruby.hash_new();
|
|
128
|
-
let (key, labels, properties) = node.unpack();
|
|
127
|
+
let (graph_name, key, labels, properties) = node.unpack();
|
|
129
128
|
r_hash.aset("type", "node")?;
|
|
129
|
+
if let Some(graph_name) = graph_name
|
|
130
|
+
{
|
|
131
|
+
r_hash.aset("graph_name", graph_name)?;
|
|
132
|
+
}
|
|
130
133
|
r_hash.aset("key", integer_from_u128(ruby, key.into())?)?;
|
|
131
134
|
r_hash.aset("labels", labels)?;
|
|
132
135
|
r_hash.aset("properties", to_rhash(ruby, properties)?)?;
|
|
@@ -136,19 +139,28 @@ fn node_to_rhash(ruby: &Ruby, node: gqlitedb::Node) -> Result<magnus::Value, Err
|
|
|
136
139
|
fn edge_to_rhash(ruby: &Ruby, edge: gqlitedb::Edge) -> Result<magnus::Value, Error>
|
|
137
140
|
{
|
|
138
141
|
let r_hash = ruby.hash_new();
|
|
139
|
-
let (key, labels, properties) = edge.unpack();
|
|
142
|
+
let (graph_name, key, labels, properties) = edge.unpack();
|
|
140
143
|
r_hash.aset("type", "edge")?;
|
|
144
|
+
if let Some(graph_name) = graph_name
|
|
145
|
+
{
|
|
146
|
+
r_hash.aset("graph_name", graph_name)?;
|
|
147
|
+
}
|
|
141
148
|
r_hash.aset("key", integer_from_u128(ruby, key.into())?)?;
|
|
142
149
|
r_hash.aset("labels", labels)?;
|
|
143
150
|
r_hash.aset("properties", to_rhash(ruby, properties)?)?;
|
|
144
151
|
Ok(r_hash.into_value_with(ruby))
|
|
145
152
|
}
|
|
146
153
|
|
|
147
|
-
fn
|
|
154
|
+
fn single_path_to_rhash(ruby: &Ruby, path: gqlitedb::SinglePath) -> Result<magnus::Value, Error>
|
|
148
155
|
{
|
|
149
156
|
let r_hash = ruby.hash_new();
|
|
150
|
-
let (
|
|
151
|
-
r_hash.aset("type", "
|
|
157
|
+
let (source, edge, destination) = path.unpack();
|
|
158
|
+
r_hash.aset("type", "single_path")?;
|
|
159
|
+
let (graph_name, key, labels, properties) = edge.unpack();
|
|
160
|
+
if let Some(graph_name) = graph_name
|
|
161
|
+
{
|
|
162
|
+
r_hash.aset("graph_name", graph_name)?;
|
|
163
|
+
}
|
|
152
164
|
r_hash.aset("key", integer_from_u128(ruby, key.into())?)?;
|
|
153
165
|
r_hash.aset("labels", labels)?;
|
|
154
166
|
r_hash.aset("properties", to_rhash(ruby, properties)?)?;
|
|
@@ -157,6 +169,29 @@ fn path_to_rhash(ruby: &Ruby, path: gqlitedb::Path) -> Result<magnus::Value, Err
|
|
|
157
169
|
Ok(r_hash.into_value_with(ruby))
|
|
158
170
|
}
|
|
159
171
|
|
|
172
|
+
fn path_to_rhash(ruby: &Ruby, path: gqlitedb::Path) -> Result<magnus::Value, Error>
|
|
173
|
+
{
|
|
174
|
+
let r_hash = ruby.hash_new();
|
|
175
|
+
let (source, elements) = path.unpack();
|
|
176
|
+
r_hash.aset("type", "path")?;
|
|
177
|
+
r_hash.aset("source", node_to_rhash(ruby, source)?)?;
|
|
178
|
+
|
|
179
|
+
let r_elements = ruby.ary_new();
|
|
180
|
+
|
|
181
|
+
for el in elements.into_iter().map(|(edge, destination)| {
|
|
182
|
+
let r_hash_element = ruby.hash_new();
|
|
183
|
+
r_hash_element.aset("edge", edge_to_rhash(ruby, edge)?)?;
|
|
184
|
+
r_hash_element.aset("destination", node_to_rhash(ruby, destination)?)?;
|
|
185
|
+
Ok::<_, Error>(r_hash_element)
|
|
186
|
+
})
|
|
187
|
+
{
|
|
188
|
+
r_elements.push(el?)?;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
r_hash.aset("elements", r_elements)?;
|
|
192
|
+
Ok(r_hash.into_value_with(ruby))
|
|
193
|
+
}
|
|
194
|
+
|
|
160
195
|
fn to_rvalue(ruby: &Ruby, val: gqlitedb::Value) -> Result<magnus::Value, Error>
|
|
161
196
|
{
|
|
162
197
|
match val
|
|
@@ -172,7 +207,17 @@ fn to_rvalue(ruby: &Ruby, val: gqlitedb::Value) -> Result<magnus::Value, Error>
|
|
|
172
207
|
gqlitedb::Value::Null => Ok(ruby.qnil().into_value_with(ruby)),
|
|
173
208
|
gqlitedb::Value::Edge(e) => Ok(edge_to_rhash(ruby, e)?),
|
|
174
209
|
gqlitedb::Value::Node(n) => Ok(node_to_rhash(ruby, n)?),
|
|
175
|
-
gqlitedb::Value::
|
|
210
|
+
gqlitedb::Value::SinglePath(p) => Ok(single_path_to_rhash(ruby, *p)?),
|
|
211
|
+
gqlitedb::Value::Path(p) => Ok(path_to_rhash(ruby, *p)?),
|
|
212
|
+
gqlitedb::Value::Tensor(t) =>
|
|
213
|
+
{
|
|
214
|
+
// Represent tensor as an array of floats in Ruby
|
|
215
|
+
let arr = t
|
|
216
|
+
.into_iter()
|
|
217
|
+
.map(|f| gqlitedb::Value::Float(f as f64))
|
|
218
|
+
.collect();
|
|
219
|
+
Ok(to_rarray(ruby, arr)?.into_value_with(ruby))
|
|
220
|
+
}
|
|
176
221
|
}
|
|
177
222
|
}
|
|
178
223
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "gqlparser"
|
|
3
|
+
description = "GQL Parsing library, including GQLS."
|
|
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
|
+
[dependencies]
|
|
12
|
+
ccutils = { workspace = true, features = ["static_asserts"] }
|
|
13
|
+
graphcore = { workspace = true }
|
|
14
|
+
indexmap = { workspace = true }
|
|
15
|
+
logos = "0.16"
|
|
16
|
+
nom = "8"
|
|
17
|
+
nom-language = "0.1"
|
|
18
|
+
thiserror = { workspace = true }
|
|
19
|
+
|
|
20
|
+
[dev-dependencies]
|
|
21
|
+
divan.workspace = true
|
|
22
|
+
|
|
23
|
+
[[bench]]
|
|
24
|
+
name = "pokec_divan"
|
|
25
|
+
harness = false
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
gqlparser
|
|
2
|
+
=========
|
|
3
|
+
|
|
4
|
+
Home of the future GQL parser for [GQLite](http://gqlite.org). Currently only supporter GQL-Schemas, a GQLite extension to GQL for expressing Graph constraints.
|
|
5
|
+
|
|
6
|
+
GQL-Schemas
|
|
7
|
+
-----------
|
|
8
|
+
|
|
9
|
+
`Schema Validation and Evolution for Graph Databases`, Bonifati et al, International Conference on Conceptual Modeling, 2019 [arxiv](https://arxiv.org/pdf/1902.06427).
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
fn main()
|
|
2
|
+
{
|
|
3
|
+
if std::fs::exists("gqlite_bench_data").unwrap()
|
|
4
|
+
{
|
|
5
|
+
std::process::Command::new("git")
|
|
6
|
+
.arg("pull")
|
|
7
|
+
.spawn()
|
|
8
|
+
.unwrap()
|
|
9
|
+
.wait()
|
|
10
|
+
.unwrap();
|
|
11
|
+
}
|
|
12
|
+
else
|
|
13
|
+
{
|
|
14
|
+
std::process::Command::new("git")
|
|
15
|
+
.arg("clone")
|
|
16
|
+
.arg("https://gitlab.com/auksys/data/gqlite_bench.git")
|
|
17
|
+
.arg("gqlite_bench_data")
|
|
18
|
+
.spawn()
|
|
19
|
+
.unwrap()
|
|
20
|
+
.wait()
|
|
21
|
+
.unwrap();
|
|
22
|
+
}
|
|
23
|
+
// Run registered benchmarks.
|
|
24
|
+
divan::main();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Parse the small `pokec` dataset.
|
|
28
|
+
#[divan::bench()]
|
|
29
|
+
fn parse_small_pokec()
|
|
30
|
+
{
|
|
31
|
+
let filename = "gqlite_bench_data/pokec_small_import.cypher";
|
|
32
|
+
let import_query = std::fs::read_to_string(filename).unwrap();
|
|
33
|
+
let _ = gqlparser::oc::parse_oc_query(&import_query);
|
|
34
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
use nom::{
|
|
2
|
+
AsChar, Emit, IResult, Input, Mode as _, OutputM, OutputMode, PResult, Parser,
|
|
3
|
+
character::complete::multispace0,
|
|
4
|
+
error::{FromExternalError, ParseError},
|
|
5
|
+
sequence::preceded,
|
|
6
|
+
};
|
|
7
|
+
use nom_language::error::VerboseError;
|
|
8
|
+
|
|
9
|
+
pub(crate) type VResult<I, O> = IResult<I, O, VerboseError<I>>;
|
|
10
|
+
|
|
11
|
+
pub(crate) fn ws0<I, E: ParseError<I>, F>(
|
|
12
|
+
f: F,
|
|
13
|
+
) -> impl Parser<I, Output = <F as Parser<I>>::Output, Error = E>
|
|
14
|
+
where
|
|
15
|
+
F: Parser<I, Error = E>,
|
|
16
|
+
I: Input,
|
|
17
|
+
<I as Input>::Item: AsChar,
|
|
18
|
+
{
|
|
19
|
+
preceded(multispace0, f)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
pub fn map_res_failure<I: Clone, O, E: ParseError<I> + FromExternalError<I, E2>, E2, F, G>(
|
|
23
|
+
parser: F,
|
|
24
|
+
g: G,
|
|
25
|
+
) -> impl Parser<I, Output = O, Error = E>
|
|
26
|
+
where
|
|
27
|
+
F: Parser<I, Error = E>,
|
|
28
|
+
G: FnMut(<F as Parser<I>>::Output) -> Result<O, E2>,
|
|
29
|
+
{
|
|
30
|
+
MapResFailure { f: parser, g }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/// Implementation of `Parser::map_res`
|
|
34
|
+
pub struct MapResFailure<F, G>
|
|
35
|
+
{
|
|
36
|
+
f: F,
|
|
37
|
+
g: G,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
impl<I, O2, E2, F, G> Parser<I> for MapResFailure<F, G>
|
|
41
|
+
where
|
|
42
|
+
I: Clone,
|
|
43
|
+
<F as Parser<I>>::Error: FromExternalError<I, E2>,
|
|
44
|
+
F: Parser<I>,
|
|
45
|
+
G: FnMut(<F as Parser<I>>::Output) -> Result<O2, E2>,
|
|
46
|
+
{
|
|
47
|
+
type Output = O2;
|
|
48
|
+
type Error = <F as Parser<I>>::Error;
|
|
49
|
+
|
|
50
|
+
fn process<OM: OutputMode>(&mut self, i: I) -> PResult<OM, I, Self::Output, Self::Error>
|
|
51
|
+
{
|
|
52
|
+
let (input, o1) = self
|
|
53
|
+
.f
|
|
54
|
+
.process::<OutputM<Emit, OM::Error, OM::Incomplete>>(i.clone())?;
|
|
55
|
+
|
|
56
|
+
match (self.g)(o1)
|
|
57
|
+
{
|
|
58
|
+
Ok(o2) => Ok((input, OM::Output::bind(|| o2))),
|
|
59
|
+
Err(e) => Err(nom::Err::Failure(
|
|
60
|
+
<F as Parser<I>>::Error::from_external_error(i, nom::error::ErrorKind::MapRes, e),
|
|
61
|
+
)),
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
pub(crate) fn fixed_digit<const N: usize>(input: &str) -> VResult<&str, &str>
|
|
67
|
+
{
|
|
68
|
+
nom::bytes::complete::take_while_m_n(N, N, |c: char| c.is_ascii_digit())(input)
|
|
69
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
//! AST module
|
|
2
|
+
|
|
3
|
+
use indexmap::IndexMap;
|
|
4
|
+
|
|
5
|
+
use crate::gqls::prelude::*;
|
|
6
|
+
|
|
7
|
+
/// Abstract Syntax Tree of the schema
|
|
8
|
+
#[derive(Debug)]
|
|
9
|
+
pub struct Ast
|
|
10
|
+
{
|
|
11
|
+
/// List of elements
|
|
12
|
+
pub elements: IndexMap<String, PropertiesDefinition>,
|
|
13
|
+
/// List of nodes
|
|
14
|
+
pub nodes: Vec<Node>,
|
|
15
|
+
/// List of edges
|
|
16
|
+
pub edges: Vec<Edge>,
|
|
17
|
+
/// List of named constrained type definitions
|
|
18
|
+
pub constrained_types: IndexMap<String, ConstrainedTypeDef>,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/// Represent an element
|
|
22
|
+
#[derive(Debug)]
|
|
23
|
+
pub struct PropertiesDefinition
|
|
24
|
+
{
|
|
25
|
+
/// List of parament element
|
|
26
|
+
pub parents: Vec<String>,
|
|
27
|
+
/// Properties of the element
|
|
28
|
+
pub properties: IndexMap<String, Property>,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/// Represent a node
|
|
32
|
+
#[derive(Debug)]
|
|
33
|
+
pub struct Node
|
|
34
|
+
{
|
|
35
|
+
/// Main label of the node, used as identifer
|
|
36
|
+
pub label: String,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/// Represent an edge
|
|
40
|
+
#[derive(Debug)]
|
|
41
|
+
pub struct Edge
|
|
42
|
+
{
|
|
43
|
+
/// Identifier of the source
|
|
44
|
+
pub source: String,
|
|
45
|
+
/// Main label of the edge, used as identifer
|
|
46
|
+
pub label: String,
|
|
47
|
+
/// Identifier of the destination
|
|
48
|
+
pub destination: String,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/// Either a base scalar type, or a reference to another named constrained type.
|
|
52
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
53
|
+
pub enum TypeRef
|
|
54
|
+
{
|
|
55
|
+
/// A base scalar type
|
|
56
|
+
Base(LiteralBaseType),
|
|
57
|
+
/// A reference to another named constrained type
|
|
58
|
+
Named(String),
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/// A `type Name = TypeRef: Constraint?;` declaration, pre-resolution.
|
|
62
|
+
#[derive(Debug, Clone)]
|
|
63
|
+
pub struct ConstrainedTypeDef
|
|
64
|
+
{
|
|
65
|
+
/// Base type or reference to another named type
|
|
66
|
+
pub base: TypeRef,
|
|
67
|
+
/// Optional constraint on this type
|
|
68
|
+
pub constraint: Option<Constraint>,
|
|
69
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
//! Constraint data model: literal values and the constraints that can be
|
|
2
|
+
//! placed on them.
|
|
3
|
+
use graphcore::Value;
|
|
4
|
+
|
|
5
|
+
use super::{Error, Result, properties::LiteralBaseType};
|
|
6
|
+
|
|
7
|
+
/// The base type this value belongs to.
|
|
8
|
+
pub fn base_type(value: &Value) -> Result<LiteralBaseType>
|
|
9
|
+
{
|
|
10
|
+
match value
|
|
11
|
+
{
|
|
12
|
+
Value::Boolean(_) => Ok(LiteralBaseType::Boolean),
|
|
13
|
+
Value::Integer(_) => Ok(LiteralBaseType::Integer),
|
|
14
|
+
Value::Float(_) => Ok(LiteralBaseType::Float),
|
|
15
|
+
Value::String(_) => Ok(LiteralBaseType::String),
|
|
16
|
+
Value::TimeStamp(_) => Ok(LiteralBaseType::TimeStamp),
|
|
17
|
+
_ => Err(Error::InvalidValue),
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/// A constraint tree, restricting the set of values a property may take.
|
|
22
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
23
|
+
pub enum Constraint
|
|
24
|
+
{
|
|
25
|
+
In(Vec<Value>),
|
|
26
|
+
Eq(Value),
|
|
27
|
+
Ne(Value),
|
|
28
|
+
LessThan(Value),
|
|
29
|
+
LessOrEqual(Value),
|
|
30
|
+
GreaterThan(Value),
|
|
31
|
+
GreaterOrEqual(Value),
|
|
32
|
+
And(Vec<Constraint>),
|
|
33
|
+
Or(Vec<Constraint>),
|
|
34
|
+
Not(Box<Constraint>),
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
#[cfg(test)]
|
|
38
|
+
mod tests
|
|
39
|
+
{
|
|
40
|
+
use super::*;
|
|
41
|
+
|
|
42
|
+
#[test]
|
|
43
|
+
fn value_base_type_matches_variant()
|
|
44
|
+
{
|
|
45
|
+
assert_eq!(
|
|
46
|
+
base_type(&Value::Boolean(true)).unwrap(),
|
|
47
|
+
LiteralBaseType::Boolean
|
|
48
|
+
);
|
|
49
|
+
assert_eq!(
|
|
50
|
+
base_type(&Value::Integer(1)).unwrap(),
|
|
51
|
+
LiteralBaseType::Integer
|
|
52
|
+
);
|
|
53
|
+
assert_eq!(
|
|
54
|
+
base_type(&Value::Float(1.0)).unwrap(),
|
|
55
|
+
LiteralBaseType::Float
|
|
56
|
+
);
|
|
57
|
+
assert_eq!(
|
|
58
|
+
base_type(&Value::String("x".into())).unwrap(),
|
|
59
|
+
LiteralBaseType::String
|
|
60
|
+
);
|
|
61
|
+
assert_eq!(
|
|
62
|
+
base_type(&Value::TimeStamp(graphcore::TimeStamp::now())).unwrap(),
|
|
63
|
+
LiteralBaseType::TimeStamp
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
#[test]
|
|
68
|
+
fn nested_constraint_tree_clones_and_compares_equal()
|
|
69
|
+
{
|
|
70
|
+
let c = Constraint::And(vec![
|
|
71
|
+
Constraint::Or(vec![
|
|
72
|
+
Constraint::GreaterThan(Value::Integer(10)),
|
|
73
|
+
Constraint::LessThan(Value::Integer(0)),
|
|
74
|
+
]),
|
|
75
|
+
Constraint::Not(Box::new(Constraint::Eq(Value::Integer(5)))),
|
|
76
|
+
]);
|
|
77
|
+
assert_eq!(c, c.clone());
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#[derive(thiserror::Error, Debug, PartialEq, Clone)]
|
|
2
|
+
#[allow(missing_docs)]
|
|
3
|
+
#[non_exhaustive]
|
|
4
|
+
pub enum Error
|
|
5
|
+
{
|
|
6
|
+
#[error("ParseError: {0}.")]
|
|
7
|
+
Parse(String),
|
|
8
|
+
#[error("IncompleteParsingError: '{0}' was not parsed.")]
|
|
9
|
+
IncompleteParsing(String),
|
|
10
|
+
#[error("MultiTypeCannotBeConvertedToSingle")]
|
|
11
|
+
MultiTypeCannotBeConvertedToSingle,
|
|
12
|
+
#[error("InvalidType")]
|
|
13
|
+
InvalidType,
|
|
14
|
+
#[error("InvalidValue")]
|
|
15
|
+
InvalidValue,
|
|
16
|
+
/// A type reference points to an undefined type.
|
|
17
|
+
#[error("undefined type '{0}'")]
|
|
18
|
+
UndefinedType(String),
|
|
19
|
+
/// A cycle was detected in the type hierarchy.
|
|
20
|
+
#[error("cycle detected: {}", .0.join(" -> "))]
|
|
21
|
+
Cycle(Vec<String>),
|
|
22
|
+
}
|