gqlite 1.3.0 → 1.4.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 +4 -3
- data/ext/gqlitedb/Cargo.toml +7 -4
- data/ext/gqlitedb/src/aggregators/arithmetic.rs +1 -0
- data/ext/gqlitedb/src/compiler/expression_analyser.rs +2 -0
- data/ext/gqlitedb/src/compiler.rs +31 -19
- data/ext/gqlitedb/src/connection.rs +42 -7
- data/ext/gqlitedb/src/error.rs +3 -0
- data/ext/gqlitedb/src/functions/containers.rs +1 -1
- data/ext/gqlitedb/src/functions/path.rs +1 -1
- data/ext/gqlitedb/src/functions/scalar.rs +23 -0
- data/ext/gqlitedb/src/functions.rs +8 -0
- data/ext/gqlitedb/src/interpreter/evaluators.rs +10 -10
- data/ext/gqlitedb/src/interpreter/instructions.rs +3 -3
- data/ext/gqlitedb/src/lib.rs +1 -3
- data/ext/gqlitedb/src/parser/ast.rs +1 -0
- data/ext/gqlitedb/src/parser/gql.pest +3 -1
- data/ext/gqlitedb/src/parser/parser_impl.rs +8 -0
- data/ext/gqlitedb/src/prelude.rs +3 -0
- data/ext/gqlitedb/src/store/{pgql.rs → pgrx.rs} +2 -0
- data/ext/gqlitedb/src/store/postgres.rs +0 -0
- data/ext/gqlitedb/src/store/sqlbase/sqlmetadata.rs +117 -0
- data/ext/gqlitedb/src/store/sqlbase/sqlqueries.rs +62 -0
- data/ext/gqlitedb/src/store/sqlbase/sqlstore.rs +55 -0
- data/ext/gqlitedb/src/store/sqlbase/sqlvalue.rs +189 -0
- data/ext/gqlitedb/src/store/sqlbase.rs +456 -0
- data/ext/gqlitedb/src/store/sqlite.rs +271 -573
- data/ext/gqlitedb/src/store.rs +7 -5
- data/ext/gqlitedb/src/tests/templates/programs.rs +10 -10
- data/ext/gqlitedb/src/utils.rs +25 -0
- data/ext/gqlitedb/src/value/compare.rs +6 -0
- data/ext/gqlitedb/src/value.rs +18 -2
- data/ext/gqlitedb/templates/sql/sqlite/edge_select.sql +18 -18
- data/ext/gqlitedb/templates/sql/sqlite/edge_update.sql +3 -3
- data/ext/gqlitedb/templates/sql/sqlite/node_select.sql +6 -6
- data/ext/gqlitedb/templates/sql/sqlite/node_update.sql +3 -3
- data/ext/gqliterb/src/lib.rs +30 -2
- data/ext/graphcore/Cargo.toml +3 -2
- data/ext/graphcore/src/error.rs +2 -0
- data/ext/graphcore/src/lib.rs +2 -1
- data/ext/graphcore/src/prelude.rs +1 -1
- data/ext/graphcore/src/table.rs +1 -1
- data/ext/graphcore/src/timestamp.rs +104 -0
- data/ext/graphcore/src/value.rs +106 -23
- metadata +10 -7
- data/ext/gqlitedb/gqlite_bench_data/README.MD +0 -6
- data/ext/gqlitedb/gqlite_bench_data/scripts/generate_smaller_pokec.rb +0 -85
- data/ext/gqlitedb/gqlite_bench_data/scripts/to_efficient_pokec.rb +0 -34
- data/ext/graphcore/release.toml +0 -1
data/ext/gqlitedb/src/store.rs
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
#[cfg(feature = "
|
|
2
|
-
pub(crate) mod
|
|
1
|
+
#[cfg(any(feature = "sqlite", feature = "postgres", feature = "_pgrx"))]
|
|
2
|
+
pub(crate) mod sqlbase;
|
|
3
|
+
|
|
4
|
+
#[cfg(feature = "_pgrx")]
|
|
5
|
+
pub(crate) mod pgrx;
|
|
6
|
+
#[cfg(feature = "postgres")]
|
|
7
|
+
pub(crate) mod postgres;
|
|
3
8
|
#[cfg(feature = "redb")]
|
|
4
9
|
pub(crate) mod redb;
|
|
5
10
|
#[cfg(feature = "sqlite")]
|
|
6
11
|
pub(crate) mod sqlite;
|
|
7
12
|
|
|
8
|
-
#[cfg(feature = "_pgql")]
|
|
9
|
-
pub(crate) use pgql::Store;
|
|
10
|
-
|
|
11
13
|
use crate::prelude::*;
|
|
12
14
|
|
|
13
15
|
// ____ _ _ _ _ _
|
|
@@ -71,7 +71,7 @@ pub(crate) fn create_named_node() -> Program
|
|
|
71
71
|
skip: None,
|
|
72
72
|
order_by: vec![],
|
|
73
73
|
},
|
|
74
|
-
|
|
74
|
+
variables_sizes: create_variable_size(2, 0),
|
|
75
75
|
},
|
|
76
76
|
]
|
|
77
77
|
}
|
|
@@ -133,7 +133,7 @@ pub(crate) fn create_named_node_double_return() -> Program
|
|
|
133
133
|
skip: None,
|
|
134
134
|
order_by: vec![],
|
|
135
135
|
},
|
|
136
|
-
|
|
136
|
+
variables_sizes: create_variable_size(3, 0),
|
|
137
137
|
},
|
|
138
138
|
]
|
|
139
139
|
}
|
|
@@ -161,7 +161,7 @@ pub(crate) fn double_with_return() -> Program
|
|
|
161
161
|
skip: None,
|
|
162
162
|
order_by: vec![],
|
|
163
163
|
},
|
|
164
|
-
|
|
164
|
+
variables_sizes: create_variable_size(2, 0),
|
|
165
165
|
},
|
|
166
166
|
Block::With {
|
|
167
167
|
variables: vec![
|
|
@@ -182,7 +182,7 @@ pub(crate) fn double_with_return() -> Program
|
|
|
182
182
|
skip: None,
|
|
183
183
|
order_by: vec![],
|
|
184
184
|
},
|
|
185
|
-
|
|
185
|
+
variables_sizes: create_variable_size(4, 0),
|
|
186
186
|
},
|
|
187
187
|
Block::Return {
|
|
188
188
|
variables: vec![(
|
|
@@ -199,7 +199,7 @@ pub(crate) fn double_with_return() -> Program
|
|
|
199
199
|
skip: None,
|
|
200
200
|
order_by: vec![],
|
|
201
201
|
},
|
|
202
|
-
|
|
202
|
+
variables_sizes: create_variable_size(2, 0),
|
|
203
203
|
},
|
|
204
204
|
]
|
|
205
205
|
}
|
|
@@ -234,7 +234,7 @@ pub(crate) fn unwind() -> Program
|
|
|
234
234
|
skip: None,
|
|
235
235
|
order_by: vec![],
|
|
236
236
|
},
|
|
237
|
-
|
|
237
|
+
variables_sizes: create_variable_size(1, 0),
|
|
238
238
|
},
|
|
239
239
|
]
|
|
240
240
|
}
|
|
@@ -288,7 +288,7 @@ pub(crate) fn match_loop() -> Program
|
|
|
288
288
|
skip: None,
|
|
289
289
|
order_by: vec![],
|
|
290
290
|
},
|
|
291
|
-
|
|
291
|
+
variables_sizes: create_variable_size(1, 0),
|
|
292
292
|
},
|
|
293
293
|
]
|
|
294
294
|
}
|
|
@@ -327,7 +327,7 @@ pub(crate) fn optional_match() -> Program
|
|
|
327
327
|
skip: None,
|
|
328
328
|
order_by: vec![],
|
|
329
329
|
},
|
|
330
|
-
|
|
330
|
+
variables_sizes: create_variable_size(1, 0),
|
|
331
331
|
},
|
|
332
332
|
]
|
|
333
333
|
}
|
|
@@ -378,7 +378,7 @@ pub(crate) fn match_count(function_manager: &functions::Manager) -> Program
|
|
|
378
378
|
skip: None,
|
|
379
379
|
order_by: vec![],
|
|
380
380
|
},
|
|
381
|
-
|
|
381
|
+
variables_sizes: create_variable_size(2, 1),
|
|
382
382
|
},
|
|
383
383
|
]
|
|
384
384
|
}
|
|
@@ -449,7 +449,7 @@ pub(crate) fn aggregation(function_manager: &functions::Manager) -> Program
|
|
|
449
449
|
skip: None,
|
|
450
450
|
order_by: vec![],
|
|
451
451
|
},
|
|
452
|
-
|
|
452
|
+
variables_sizes: create_variable_size(3, 1),
|
|
453
453
|
},
|
|
454
454
|
]
|
|
455
455
|
}
|
data/ext/gqlitedb/src/utils.rs
CHANGED
|
@@ -2,6 +2,8 @@ use std::fmt::{Debug, Display};
|
|
|
2
2
|
|
|
3
3
|
use serde::{Deserialize, Serialize};
|
|
4
4
|
|
|
5
|
+
use crate::prelude::*;
|
|
6
|
+
|
|
5
7
|
#[derive(Serialize, Deserialize)]
|
|
6
8
|
pub struct Version
|
|
7
9
|
{
|
|
@@ -26,3 +28,26 @@ impl Display for Version
|
|
|
26
28
|
f.write_fmt(format_args!("{}.{}.{}", self.major, self.minor, self.patch))
|
|
27
29
|
}
|
|
28
30
|
}
|
|
31
|
+
|
|
32
|
+
pub(crate) fn hex(key: impl Into<graph::Key>) -> String
|
|
33
|
+
{
|
|
34
|
+
format!("{:032X}", key.into().uuid())
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
#[cfg(test)]
|
|
38
|
+
mod tests
|
|
39
|
+
{
|
|
40
|
+
use crate::prelude::*;
|
|
41
|
+
#[test]
|
|
42
|
+
fn test_hex()
|
|
43
|
+
{
|
|
44
|
+
assert_eq!(
|
|
45
|
+
super::hex(graph::Key::new(18580062510968287067562660977870108180)),
|
|
46
|
+
"0DFA63CEE7484B0DBFC407697F77F614"
|
|
47
|
+
);
|
|
48
|
+
assert_eq!(
|
|
49
|
+
super::hex(graph::Key::new(0)),
|
|
50
|
+
"00000000000000000000000000000000"
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -111,6 +111,12 @@ pub(crate) fn compare(lhs: &value::Value, rhs: &value::Value) -> Ordering
|
|
|
111
111
|
Value::Null => Ordering::ComparedNull,
|
|
112
112
|
_ => Ordering::Null,
|
|
113
113
|
},
|
|
114
|
+
Value::TimeStamp(tl) => match rhs
|
|
115
|
+
{
|
|
116
|
+
Value::TimeStamp(tr) => tl.cmp(tr).into(),
|
|
117
|
+
Value::Null => Ordering::ComparedNull,
|
|
118
|
+
_ => Ordering::Null,
|
|
119
|
+
},
|
|
114
120
|
Value::Array(al) => match rhs
|
|
115
121
|
{
|
|
116
122
|
Value::Array(ar) =>
|
data/ext/gqlitedb/src/value.rs
CHANGED
|
@@ -4,7 +4,7 @@ mod contains;
|
|
|
4
4
|
pub(crate) use compare::{compare, Ordering};
|
|
5
5
|
pub(crate) use contains::{contains, ContainResult};
|
|
6
6
|
|
|
7
|
-
pub use graphcore::{array, value_map, Value, ValueMap, ValueTryIntoRef};
|
|
7
|
+
pub use graphcore::{array, value_map, TimeStamp, Value, ValueMap, ValueTryIntoRef};
|
|
8
8
|
|
|
9
9
|
pub(crate) trait ValueExt
|
|
10
10
|
{
|
|
@@ -134,7 +134,7 @@ impl ValueExt for Value
|
|
|
134
134
|
Value::String(rhs) => lhs.cmp(rhs),
|
|
135
135
|
_ => std::cmp::Ordering::Greater,
|
|
136
136
|
},
|
|
137
|
-
Value::
|
|
137
|
+
Value::TimeStamp(lhs) => match rhs
|
|
138
138
|
{
|
|
139
139
|
Value::Null
|
|
140
140
|
| Value::Key(..)
|
|
@@ -142,6 +142,18 @@ impl ValueExt for Value
|
|
|
142
142
|
| Value::Float(..)
|
|
143
143
|
| Value::Boolean(..)
|
|
144
144
|
| Value::String(..) => std::cmp::Ordering::Less,
|
|
145
|
+
Value::TimeStamp(rhs) => lhs.cmp(rhs),
|
|
146
|
+
_ => std::cmp::Ordering::Greater,
|
|
147
|
+
},
|
|
148
|
+
Value::Path(lhs) => match rhs
|
|
149
|
+
{
|
|
150
|
+
Value::Null
|
|
151
|
+
| Value::Key(..)
|
|
152
|
+
| Value::Integer(..)
|
|
153
|
+
| Value::Float(..)
|
|
154
|
+
| Value::Boolean(..)
|
|
155
|
+
| Value::String(..)
|
|
156
|
+
| Value::TimeStamp(..) => std::cmp::Ordering::Less,
|
|
145
157
|
Value::Path(rhs) =>
|
|
146
158
|
{
|
|
147
159
|
match orderability_map(lhs.source().properties(), rhs.source().properties())
|
|
@@ -170,6 +182,7 @@ impl ValueExt for Value
|
|
|
170
182
|
| Value::Float(..)
|
|
171
183
|
| Value::Boolean(..)
|
|
172
184
|
| Value::String(..)
|
|
185
|
+
| Value::TimeStamp(..)
|
|
173
186
|
| Value::Path(..) => std::cmp::Ordering::Less,
|
|
174
187
|
Value::Array(rhs) => lhs
|
|
175
188
|
.iter()
|
|
@@ -187,6 +200,7 @@ impl ValueExt for Value
|
|
|
187
200
|
| Value::Float(..)
|
|
188
201
|
| Value::Boolean(..)
|
|
189
202
|
| Value::String(..)
|
|
203
|
+
| Value::TimeStamp(..)
|
|
190
204
|
| Value::Path(..)
|
|
191
205
|
| Value::Array(..) => std::cmp::Ordering::Less,
|
|
192
206
|
Value::Edge(rhs) => orderability_map(lhs.properties(), rhs.properties()),
|
|
@@ -200,6 +214,7 @@ impl ValueExt for Value
|
|
|
200
214
|
| Value::Float(..)
|
|
201
215
|
| Value::Boolean(..)
|
|
202
216
|
| Value::String(..)
|
|
217
|
+
| Value::TimeStamp(..)
|
|
203
218
|
| Value::Path(..)
|
|
204
219
|
| Value::Array(..)
|
|
205
220
|
| Value::Edge(..) => std::cmp::Ordering::Less,
|
|
@@ -214,6 +229,7 @@ impl ValueExt for Value
|
|
|
214
229
|
| Value::Float(..)
|
|
215
230
|
| Value::Boolean(..)
|
|
216
231
|
| Value::String(..)
|
|
232
|
+
| Value::TimeStamp(..)
|
|
217
233
|
| Value::Path(..)
|
|
218
234
|
| Value::Array(..)
|
|
219
235
|
| Value::Edge(..)
|
|
@@ -17,22 +17,22 @@ JOIN gqlite_{{ graph_name }}_nodes AS n_left ON e.left = n_left.id
|
|
|
17
17
|
JOIN gqlite_{{ graph_name }}_nodes AS n_right ON e.right = n_right.id
|
|
18
18
|
WHERE
|
|
19
19
|
-- Filter by key list (if not empty)
|
|
20
|
-
{% if
|
|
20
|
+
{% if let Some(edge_keys_var) = edge_keys_var %}
|
|
21
21
|
(
|
|
22
22
|
hex(e.edge_key) IN (
|
|
23
|
-
SELECT value FROM json_each(
|
|
23
|
+
SELECT value FROM json_each(?{{ edge_keys_var }})
|
|
24
24
|
)
|
|
25
25
|
)
|
|
26
26
|
{% else %}
|
|
27
27
|
1
|
|
28
28
|
{% endif %}
|
|
29
29
|
AND
|
|
30
|
-
{% if
|
|
30
|
+
{% if let Some(edge_labels_var) = edge_labels_var %}
|
|
31
31
|
-- Filter by required labels (must all be in e.labels)
|
|
32
32
|
(
|
|
33
33
|
NOT EXISTS (
|
|
34
34
|
SELECT 1
|
|
35
|
-
FROM json_each(
|
|
35
|
+
FROM json_each(?{{ edge_labels_var }}) AS required_label
|
|
36
36
|
WHERE NOT EXISTS (
|
|
37
37
|
SELECT 1
|
|
38
38
|
FROM json_each(e.labels) AS edge_label
|
|
@@ -44,11 +44,11 @@ WHERE
|
|
|
44
44
|
1
|
|
45
45
|
{% endif %}
|
|
46
46
|
AND
|
|
47
|
-
{% if
|
|
47
|
+
{% if let Some(edge_properties_var) = edge_properties_var %}
|
|
48
48
|
-- Filter by required properties (must all exist and match)
|
|
49
49
|
NOT EXISTS (
|
|
50
50
|
SELECT 1
|
|
51
|
-
FROM json_each(
|
|
51
|
+
FROM json_each(?{{ edge_properties_var }}) AS required_prop
|
|
52
52
|
WHERE json_extract(e.properties, '$.' || required_prop.key) IS NULL
|
|
53
53
|
OR json_extract(e.properties, '$.' || required_prop.key) != required_prop.value
|
|
54
54
|
)
|
|
@@ -57,22 +57,22 @@ WHERE
|
|
|
57
57
|
{% endif %}
|
|
58
58
|
-- Filter by key list (if not empty)
|
|
59
59
|
AND
|
|
60
|
-
{% if
|
|
60
|
+
{% if let Some(left_keys_var) = left_keys_var %}
|
|
61
61
|
(
|
|
62
62
|
hex(n_left.node_key) IN (
|
|
63
|
-
SELECT value FROM json_each(
|
|
63
|
+
SELECT value FROM json_each(?{{ left_keys_var }})
|
|
64
64
|
)
|
|
65
65
|
)
|
|
66
66
|
{% else %}
|
|
67
67
|
1
|
|
68
68
|
{% endif %}
|
|
69
69
|
AND
|
|
70
|
-
{% if
|
|
70
|
+
{% if let Some(left_labels_var) = left_labels_var %}
|
|
71
71
|
-- Filter by required labels (must all be in n_left.labels)
|
|
72
72
|
(
|
|
73
73
|
NOT EXISTS (
|
|
74
74
|
SELECT 1
|
|
75
|
-
FROM json_each(
|
|
75
|
+
FROM json_each(?{{ left_labels_var }}) AS required_label
|
|
76
76
|
WHERE NOT EXISTS (
|
|
77
77
|
SELECT 1
|
|
78
78
|
FROM json_each(n_left.labels) AS node_label
|
|
@@ -84,12 +84,12 @@ WHERE
|
|
|
84
84
|
1
|
|
85
85
|
{% endif %}
|
|
86
86
|
AND
|
|
87
|
-
{% if
|
|
87
|
+
{% if let Some(left_properties_var) = left_properties_var %}
|
|
88
88
|
-- Filter by required properties (must all exist and match)
|
|
89
89
|
(
|
|
90
90
|
NOT EXISTS (
|
|
91
91
|
SELECT 1
|
|
92
|
-
FROM json_each(
|
|
92
|
+
FROM json_each(?{{ left_properties_var }}) AS required_prop
|
|
93
93
|
WHERE json_extract(n_left.properties, '$.' || required_prop.key) IS NULL
|
|
94
94
|
OR json_extract(n_left.properties, '$.' || required_prop.key) != required_prop.value
|
|
95
95
|
)
|
|
@@ -99,22 +99,22 @@ WHERE
|
|
|
99
99
|
{% endif %}
|
|
100
100
|
AND
|
|
101
101
|
-- Filter by key list (if not empty)
|
|
102
|
-
{% if
|
|
102
|
+
{% if let Some(right_keys_var) = right_keys_var %}
|
|
103
103
|
(
|
|
104
104
|
hex(n_right.node_key) IN (
|
|
105
|
-
SELECT value FROM json_each(
|
|
105
|
+
SELECT value FROM json_each(?{{ right_keys_var }})
|
|
106
106
|
)
|
|
107
107
|
)
|
|
108
108
|
{% else %}
|
|
109
109
|
1
|
|
110
110
|
{% endif %}
|
|
111
111
|
AND
|
|
112
|
-
{% if
|
|
112
|
+
{% if let Some(right_labels_var) = right_labels_var %}
|
|
113
113
|
-- Filter by required labels (must all be in n_right.labels)
|
|
114
114
|
(
|
|
115
115
|
NOT EXISTS (
|
|
116
116
|
SELECT 1
|
|
117
|
-
FROM json_each(
|
|
117
|
+
FROM json_each(?{{ right_labels_var }}) AS required_label
|
|
118
118
|
WHERE NOT EXISTS (
|
|
119
119
|
SELECT 1
|
|
120
120
|
FROM json_each(n_right.labels) AS node_label
|
|
@@ -126,12 +126,12 @@ WHERE
|
|
|
126
126
|
1
|
|
127
127
|
{% endif %}
|
|
128
128
|
|
|
129
|
-
{% if
|
|
129
|
+
{% if let Some(right_properties_var) = right_properties_var %}
|
|
130
130
|
-- Filter by required properties (must all exist and match)
|
|
131
131
|
AND (
|
|
132
132
|
NOT EXISTS (
|
|
133
133
|
SELECT 1
|
|
134
|
-
FROM json_each(
|
|
134
|
+
FROM json_each(?{{ right_properties_var }}) AS required_prop
|
|
135
135
|
WHERE json_extract(n_right.properties, '$.' || required_prop.key) IS NULL
|
|
136
136
|
OR json_extract(n_right.properties, '$.' || required_prop.key) != required_prop.value
|
|
137
137
|
)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
UPDATE gqlite_{{ graph_name }}_edges
|
|
2
|
-
SET labels =
|
|
3
|
-
properties =
|
|
4
|
-
WHERE edge_key =
|
|
2
|
+
SET labels = ?2,
|
|
3
|
+
properties = ?3
|
|
4
|
+
WHERE edge_key = ?1;
|
|
@@ -2,22 +2,22 @@ SELECT node_key, labels, properties
|
|
|
2
2
|
FROM gqlite_{{ graph_name }}_nodes AS nodes
|
|
3
3
|
WHERE
|
|
4
4
|
-- Filter by key list (if not empty)
|
|
5
|
-
{% if
|
|
5
|
+
{% if let Some(keys_var) = keys_var %}
|
|
6
6
|
(
|
|
7
7
|
hex(nodes.node_key) IN (
|
|
8
|
-
SELECT value FROM json_each(
|
|
8
|
+
SELECT value FROM json_each(?{{ keys_var }})
|
|
9
9
|
)
|
|
10
10
|
)
|
|
11
11
|
{% else %}
|
|
12
12
|
1
|
|
13
13
|
{% endif %}
|
|
14
14
|
AND
|
|
15
|
-
{% if
|
|
15
|
+
{% if let Some(labels_var) = labels_var %}
|
|
16
16
|
-- Filter by required labels (must all be in nodes.labels)
|
|
17
17
|
(
|
|
18
18
|
NOT EXISTS (
|
|
19
19
|
SELECT 1
|
|
20
|
-
FROM json_each(
|
|
20
|
+
FROM json_each(?{{ labels_var }}) AS required_label
|
|
21
21
|
WHERE NOT EXISTS (
|
|
22
22
|
SELECT 1
|
|
23
23
|
FROM json_each(nodes.labels) AS node_label
|
|
@@ -29,12 +29,12 @@ WHERE
|
|
|
29
29
|
1
|
|
30
30
|
{% endif %}
|
|
31
31
|
|
|
32
|
-
{% if
|
|
32
|
+
{% if let Some(properties_var) = properties_var %}
|
|
33
33
|
-- Filter by required properties (must all exist and match)
|
|
34
34
|
AND (
|
|
35
35
|
NOT EXISTS (
|
|
36
36
|
SELECT 1
|
|
37
|
-
FROM json_each(
|
|
37
|
+
FROM json_each(?{{ properties_var }}) AS required_prop
|
|
38
38
|
WHERE json_extract(nodes.properties, '$.' || required_prop.key) IS NULL
|
|
39
39
|
OR json_extract(nodes.properties, '$.' || required_prop.key) != required_prop.value
|
|
40
40
|
)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
UPDATE gqlite_{{ graph_name }}_nodes
|
|
2
|
-
SET labels =
|
|
3
|
-
properties =
|
|
4
|
-
WHERE node_key =
|
|
2
|
+
SET labels = ?2,
|
|
3
|
+
properties = ?3
|
|
4
|
+
WHERE node_key = ?1;
|
data/ext/gqliterb/src/lib.rs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
#![deny(warnings)]
|
|
2
|
-
|
|
3
1
|
use std::fmt::Display;
|
|
4
2
|
|
|
3
|
+
use gqlitedb::TimeStamp;
|
|
5
4
|
use magnus::{
|
|
6
5
|
function, method,
|
|
7
6
|
prelude::*,
|
|
@@ -47,6 +46,22 @@ fn from_rvalue(ruby: &Ruby, value: magnus::Value) -> Result<gqlitedb::Value, Err
|
|
|
47
46
|
{
|
|
48
47
|
Ok(String::try_convert(value)?.into())
|
|
49
48
|
}
|
|
49
|
+
else if value.is_kind_of(ruby.class_time())
|
|
50
|
+
{
|
|
51
|
+
let time = magnus::Time::try_convert(value)?;
|
|
52
|
+
let timespec = time.timespec()?;
|
|
53
|
+
Ok(
|
|
54
|
+
map_err(
|
|
55
|
+
ruby,
|
|
56
|
+
TimeStamp::from_unix_timestamp(
|
|
57
|
+
timespec.tv_sec,
|
|
58
|
+
timespec.tv_nsec as i32,
|
|
59
|
+
time.utc_offset() as i32,
|
|
60
|
+
),
|
|
61
|
+
)?
|
|
62
|
+
.into(),
|
|
63
|
+
)
|
|
64
|
+
}
|
|
50
65
|
else if value.is_kind_of(ruby.class_hash())
|
|
51
66
|
{
|
|
52
67
|
Ok(from_rhash(ruby, r_hash::RHash::try_convert(value)?)?.into())
|
|
@@ -152,6 +167,7 @@ fn to_rvalue(ruby: &Ruby, val: gqlitedb::Value) -> Result<magnus::Value, Error>
|
|
|
152
167
|
gqlitedb::Value::Integer(i) => Ok(i.into_value_with(ruby)),
|
|
153
168
|
gqlitedb::Value::Float(f) => Ok(f.into_value_with(ruby)),
|
|
154
169
|
gqlitedb::Value::String(s) => Ok(s.into_value_with(ruby)),
|
|
170
|
+
gqlitedb::Value::TimeStamp(s) => Ok(to_rdatetime(ruby, s)?.into_value_with(ruby)),
|
|
155
171
|
gqlitedb::Value::Map(m) => Ok(to_rhash(ruby, m)?.into_value_with(ruby)),
|
|
156
172
|
gqlitedb::Value::Null => Ok(ruby.qnil().into_value_with(ruby)),
|
|
157
173
|
gqlitedb::Value::Edge(e) => Ok(edge_to_rhash(ruby, e)?),
|
|
@@ -160,6 +176,18 @@ fn to_rvalue(ruby: &Ruby, val: gqlitedb::Value) -> Result<magnus::Value, Error>
|
|
|
160
176
|
}
|
|
161
177
|
}
|
|
162
178
|
|
|
179
|
+
fn to_rdatetime(ruby: &Ruby, ts: gqlitedb::TimeStamp) -> Result<magnus::Time, Error>
|
|
180
|
+
{
|
|
181
|
+
let (tv_sec, tv_nsec) = ts.unix_timestamp();
|
|
182
|
+
ruby.time_timespec_new(
|
|
183
|
+
magnus::time::Timespec {
|
|
184
|
+
tv_sec,
|
|
185
|
+
tv_nsec: tv_nsec as i64,
|
|
186
|
+
},
|
|
187
|
+
map_err(ruby, magnus::time::Offset::from_secs(ts.offset_seconds()))?,
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
|
|
163
191
|
fn to_rhash(ruby: &Ruby, map: gqlitedb::ValueMap) -> Result<r_hash::RHash, Error>
|
|
164
192
|
{
|
|
165
193
|
let r_hash = ruby.hash_new();
|
data/ext/graphcore/Cargo.toml
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "graphcore"
|
|
3
3
|
description = "Base data structure to represent and manipulate property graph."
|
|
4
|
-
# version.workspace = true
|
|
5
|
-
version = "0.2.0"
|
|
6
4
|
readme = "README.MD"
|
|
5
|
+
version.workspace = true
|
|
7
6
|
edition.workspace = true
|
|
8
7
|
license.workspace = true
|
|
9
8
|
homepage.workspace = true
|
|
10
9
|
repository.workspace = true
|
|
11
10
|
|
|
12
11
|
[dependencies]
|
|
12
|
+
ccutils = { workspace = true, features = ["alias"] }
|
|
13
13
|
itertools = { workspace = true }
|
|
14
|
+
jiff = { version = "0.2" }
|
|
14
15
|
serde = { workspace = true, features = ["derive"] }
|
|
15
16
|
thiserror = { workspace = true }
|
|
16
17
|
uuid = { workspace = true }
|
data/ext/graphcore/src/error.rs
CHANGED
data/ext/graphcore/src/lib.rs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#![doc = include_str!("../README.MD")]
|
|
2
2
|
#![warn(missing_docs)]
|
|
3
|
-
#![deny(warnings)]
|
|
4
3
|
#![allow(clippy::result_large_err)]
|
|
5
4
|
|
|
6
5
|
mod error;
|
|
@@ -8,9 +7,11 @@ mod graph;
|
|
|
8
7
|
mod prelude;
|
|
9
8
|
mod serialize_with;
|
|
10
9
|
mod table;
|
|
10
|
+
mod timestamp;
|
|
11
11
|
mod value;
|
|
12
12
|
|
|
13
13
|
pub use error::Error;
|
|
14
14
|
pub use graph::{Edge, Key, Node, SinglePath};
|
|
15
15
|
pub use table::Table;
|
|
16
|
+
pub use timestamp::TimeStamp;
|
|
16
17
|
pub use value::{Value, ValueMap, ValueTryIntoRef};
|
data/ext/graphcore/src/table.rs
CHANGED
|
@@ -15,7 +15,7 @@ impl Table
|
|
|
15
15
|
/// of row is equal to length of data divided by number of columns.
|
|
16
16
|
pub fn new(headers: Vec<String>, data: Vec<crate::Value>) -> Result<Table>
|
|
17
17
|
{
|
|
18
|
-
if data.len()
|
|
18
|
+
if !data.len().is_multiple_of(headers.len())
|
|
19
19
|
{
|
|
20
20
|
Err(error::Error::InvalidTableDimensions)?;
|
|
21
21
|
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
use std::fmt;
|
|
2
|
+
|
|
3
|
+
use jiff::{tz::TimeZone, Zoned};
|
|
4
|
+
use serde::{Deserialize, Serialize};
|
|
5
|
+
|
|
6
|
+
ccutils::alias!(#[doc = "Represent a timestamp"] pub TimeStamp, Zoned, display, derive: Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord);
|
|
7
|
+
|
|
8
|
+
impl TimeStamp
|
|
9
|
+
{
|
|
10
|
+
/// Create a new time stamp with the given unix timestamp and offset
|
|
11
|
+
pub fn from_unix_timestamp(
|
|
12
|
+
seconds: i64,
|
|
13
|
+
nanoseconds: i32,
|
|
14
|
+
offset_whole_seconds: i32,
|
|
15
|
+
) -> Result<TimeStamp, crate::Error>
|
|
16
|
+
{
|
|
17
|
+
let ts = jiff::Timestamp::new(seconds, nanoseconds)?;
|
|
18
|
+
Ok(Self(ts.to_zoned(jiff::tz::TimeZone::fixed(
|
|
19
|
+
jiff::tz::Offset::from_seconds(offset_whole_seconds)?,
|
|
20
|
+
))))
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/// Convert from the current time zone to Utc (aka offset == 0)
|
|
24
|
+
pub fn to_utc(&self) -> TimeStamp
|
|
25
|
+
{
|
|
26
|
+
Self(self.with_time_zone(TimeZone::UTC))
|
|
27
|
+
}
|
|
28
|
+
/// Return the unix timestamp
|
|
29
|
+
pub fn unix_timestamp(&self) -> (i64, i32)
|
|
30
|
+
{
|
|
31
|
+
let ts = self.0.timestamp();
|
|
32
|
+
(ts.as_second(), ts.subsec_nanosecond())
|
|
33
|
+
}
|
|
34
|
+
/// Return the number of whole seconds in the offset
|
|
35
|
+
pub fn offset_seconds(&self) -> i32
|
|
36
|
+
{
|
|
37
|
+
self.0.offset().seconds()
|
|
38
|
+
}
|
|
39
|
+
/// Return the year in the timestamp timezone
|
|
40
|
+
pub fn year(&self) -> i16
|
|
41
|
+
{
|
|
42
|
+
self.0.year()
|
|
43
|
+
}
|
|
44
|
+
/// Return the month in the timestamp timezone
|
|
45
|
+
pub fn month(&self) -> i8
|
|
46
|
+
{
|
|
47
|
+
self.0.month()
|
|
48
|
+
}
|
|
49
|
+
/// Return the day in the timestamp timezone
|
|
50
|
+
pub fn day(&self) -> i8
|
|
51
|
+
{
|
|
52
|
+
self.0.day()
|
|
53
|
+
}
|
|
54
|
+
/// Return the hour in the timestamp timezone
|
|
55
|
+
pub fn hour(&self) -> i8
|
|
56
|
+
{
|
|
57
|
+
self.0.hour()
|
|
58
|
+
}
|
|
59
|
+
/// Return the minute in the timestamp timezone
|
|
60
|
+
pub fn minute(&self) -> i8
|
|
61
|
+
{
|
|
62
|
+
self.0.minute()
|
|
63
|
+
}
|
|
64
|
+
/// Return the second in the timestamp timezone
|
|
65
|
+
pub fn second(&self) -> i8
|
|
66
|
+
{
|
|
67
|
+
self.0.second()
|
|
68
|
+
}
|
|
69
|
+
/// Return the microseconds in the timestamp timezone
|
|
70
|
+
pub fn microsecond(&self) -> i16
|
|
71
|
+
{
|
|
72
|
+
self.0.microsecond()
|
|
73
|
+
}
|
|
74
|
+
/// Parse the time string
|
|
75
|
+
pub fn parse(date: &str) -> Result<TimeStamp, crate::Error>
|
|
76
|
+
{
|
|
77
|
+
Ok(TimeStamp(date.parse()?))
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Serde impl
|
|
82
|
+
|
|
83
|
+
impl Serialize for TimeStamp
|
|
84
|
+
{
|
|
85
|
+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
86
|
+
where
|
|
87
|
+
S: serde::Serializer,
|
|
88
|
+
{
|
|
89
|
+
self.0.to_string().serialize(serializer)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
impl<'de> Deserialize<'de> for TimeStamp
|
|
94
|
+
{
|
|
95
|
+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
96
|
+
where
|
|
97
|
+
D: serde::Deserializer<'de>,
|
|
98
|
+
{
|
|
99
|
+
use serde::de::Error;
|
|
100
|
+
let s = String::deserialize(deserializer)?;
|
|
101
|
+
TimeStamp::parse(&s)
|
|
102
|
+
.map_err(|e| D::Error::custom(format!("Error deserializing timestamp: {}.", e)))
|
|
103
|
+
}
|
|
104
|
+
}
|