gqlite 1.1.0 → 1.2.2
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/gqliterb/.cargo/config.toml +2 -0
- data/ext/gqliterb/Cargo.lock +1109 -0
- data/ext/gqliterb/Cargo.toml +43 -0
- data/ext/gqliterb/extconf.rb +4 -0
- data/ext/gqliterb/src/lib.rs +260 -0
- data/ext/gqliterb/vendor/gqlitedb/Cargo.lock +2060 -0
- data/ext/gqliterb/vendor/gqlitedb/Cargo.toml +132 -0
- data/ext/gqliterb/vendor/gqlitedb/askama.toml +3 -0
- data/ext/gqliterb/vendor/gqlitedb/benches/common/mod.rs +25 -0
- data/ext/gqliterb/vendor/gqlitedb/benches/common/pokec.rs +185 -0
- data/ext/gqliterb/vendor/gqlitedb/benches/pokec_divan.rs +137 -0
- data/ext/gqliterb/vendor/gqlitedb/benches/pokec_iai.rs +122 -0
- data/ext/gqliterb/vendor/gqlitedb/release.toml +7 -0
- data/ext/gqliterb/vendor/gqlitedb/src/aggregators/arithmetic.rs +96 -0
- data/ext/gqliterb/vendor/gqlitedb/src/aggregators/containers.rs +33 -0
- data/ext/gqliterb/vendor/gqlitedb/src/aggregators/count.rs +35 -0
- data/ext/gqliterb/vendor/gqlitedb/src/aggregators/stats.rs +168 -0
- data/ext/gqliterb/vendor/gqlitedb/src/aggregators.rs +74 -0
- data/ext/gqliterb/vendor/gqlitedb/src/capi.rs +236 -0
- data/ext/gqliterb/vendor/gqlitedb/src/compiler/expression_analyser.rs +427 -0
- data/ext/gqliterb/vendor/gqlitedb/src/compiler/variables_manager.rs +620 -0
- data/ext/gqliterb/vendor/gqlitedb/src/compiler.rs +1106 -0
- data/ext/gqliterb/vendor/gqlitedb/src/connection.rs +208 -0
- data/ext/gqliterb/vendor/gqlitedb/src/consts.rs +10 -0
- data/ext/gqliterb/vendor/gqlitedb/src/error.rs +621 -0
- data/ext/gqliterb/vendor/gqlitedb/src/functions/containers.rs +115 -0
- data/ext/gqliterb/vendor/gqlitedb/src/functions/edge.rs +20 -0
- data/ext/gqliterb/vendor/gqlitedb/src/functions/math.rs +44 -0
- data/ext/gqliterb/vendor/gqlitedb/src/functions/node.rs +16 -0
- data/ext/gqliterb/vendor/gqlitedb/src/functions/path.rs +48 -0
- data/ext/gqliterb/vendor/gqlitedb/src/functions/scalar.rs +86 -0
- data/ext/gqliterb/vendor/gqlitedb/src/functions/string.rs +28 -0
- data/ext/gqliterb/vendor/gqlitedb/src/functions/value.rs +99 -0
- data/ext/gqliterb/vendor/gqlitedb/src/functions.rs +412 -0
- data/ext/gqliterb/vendor/gqlitedb/src/graph.rs +268 -0
- data/ext/gqliterb/vendor/gqlitedb/src/interpreter/evaluators.rs +1788 -0
- data/ext/gqliterb/vendor/gqlitedb/src/interpreter/instructions.rs +262 -0
- data/ext/gqliterb/vendor/gqlitedb/src/interpreter/mod.rs +4 -0
- data/ext/gqliterb/vendor/gqlitedb/src/lib.rs +42 -0
- data/ext/gqliterb/vendor/gqlitedb/src/parser/ast.rs +625 -0
- data/ext/gqliterb/vendor/gqlitedb/src/parser/gql.pest +191 -0
- data/ext/gqliterb/vendor/gqlitedb/src/parser/parser.rs +1153 -0
- data/ext/gqliterb/vendor/gqlitedb/src/parser.rs +4 -0
- data/ext/gqliterb/vendor/gqlitedb/src/prelude.rs +8 -0
- data/ext/gqliterb/vendor/gqlitedb/src/serialize_with.rs +94 -0
- data/ext/gqliterb/vendor/gqlitedb/src/store/pgql.rs +121 -0
- data/ext/gqliterb/vendor/gqlitedb/src/store/redb.rs +1250 -0
- data/ext/gqliterb/vendor/gqlitedb/src/store/sqlite.rs +994 -0
- data/ext/gqliterb/vendor/gqlitedb/src/store.rs +432 -0
- data/ext/gqliterb/vendor/gqlitedb/src/tests/compiler.rs +92 -0
- data/ext/gqliterb/vendor/gqlitedb/src/tests/evaluators.rs +227 -0
- data/ext/gqliterb/vendor/gqlitedb/src/tests/parser.rs +81 -0
- data/ext/gqliterb/vendor/gqlitedb/src/tests/store/redb.rs +39 -0
- data/ext/gqliterb/vendor/gqlitedb/src/tests/store/sqlite.rs +39 -0
- data/ext/gqliterb/vendor/gqlitedb/src/tests/store.rs +462 -0
- data/ext/gqliterb/vendor/gqlitedb/src/tests/templates/ast.rs +356 -0
- data/ext/gqliterb/vendor/gqlitedb/src/tests/templates/programs.rs +455 -0
- data/ext/gqliterb/vendor/gqlitedb/src/tests/templates.rs +2 -0
- data/ext/gqliterb/vendor/gqlitedb/src/tests.rs +39 -0
- data/ext/gqliterb/vendor/gqlitedb/src/utils.rs +28 -0
- data/ext/gqliterb/vendor/gqlitedb/src/value/compare.rs +212 -0
- data/ext/gqliterb/vendor/gqlitedb/src/value/contains.rs +47 -0
- data/ext/gqliterb/vendor/gqlitedb/src/value/value_map.rs +298 -0
- data/ext/gqliterb/vendor/gqlitedb/src/value.rs +559 -0
- data/ext/gqliterb/vendor/gqlitedb/src/value_table.rs +616 -0
- data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/call_stats.sql +22 -0
- data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_count_for_node.sql +3 -0
- data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_create.sql +6 -0
- data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_delete.sql +1 -0
- data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_delete_by_nodes.sql +2 -0
- data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_select.sql +139 -0
- data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_update.sql +4 -0
- data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/graph_create.sql +16 -0
- data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/graph_delete.sql +3 -0
- data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/metadata_create_table.sql +1 -0
- data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/metadata_get.sql +1 -0
- data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/metadata_set.sql +1 -0
- data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/node_create.sql +1 -0
- data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/node_delete.sql +1 -0
- data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/node_select.sql +42 -0
- data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/node_update.sql +4 -0
- data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/table_exists.sql +5 -0
- data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/upgrade_from_1_01.sql +2 -0
- data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/upgrade_graph_from_1_01.sql +65 -0
- data/lib/gqlite.rb +1 -75
- metadata +118 -25
- data/ext/gqlite/extconf.rb +0 -21
- data/ext/gqlite/gqlite-amalgamate.cpp +0 -9599
- data/ext/gqlite/gqlite-c.h +0 -95
- data/ext/gqlite/gqlite.h +0 -141
@@ -0,0 +1,1250 @@
|
|
1
|
+
use ccutils::sync::ArcRwLock;
|
2
|
+
use redb::{ReadableTable, ReadableTableMetadata};
|
3
|
+
use serde::{Deserialize, Serialize};
|
4
|
+
use std::{cell::RefCell, collections::HashMap, rc::Rc, sync::Arc};
|
5
|
+
|
6
|
+
use crate::{prelude::*, store::TransactionBoxable};
|
7
|
+
|
8
|
+
// ____ _ _ _ _____ _
|
9
|
+
// | _ \ ___ _ __ ___(_)___| |_ ___ _ __ | |_| ____|__| | __ _ ___
|
10
|
+
// | |_) / _ \ '__/ __| / __| __/ _ \ '_ \| __| _| / _` |/ _` |/ _ \
|
11
|
+
// | __/ __/ | \__ \ \__ \ || __/ | | | |_| |__| (_| | (_| | __/
|
12
|
+
// |_| \___|_| |___/_|___/\__\___|_| |_|\__|_____\__,_|\__, |\___|
|
13
|
+
// |___/
|
14
|
+
|
15
|
+
/// This structure is used to represent the internal storage of an edge.
|
16
|
+
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
17
|
+
struct PersistentEdge
|
18
|
+
{
|
19
|
+
pub key: graph::Key,
|
20
|
+
pub source: graph::Key,
|
21
|
+
pub destination: graph::Key,
|
22
|
+
pub labels: Vec<String>,
|
23
|
+
pub properties: value::ValueMap,
|
24
|
+
}
|
25
|
+
|
26
|
+
impl redb::Value for PersistentEdge
|
27
|
+
{
|
28
|
+
type AsBytes<'a> = Vec<u8>;
|
29
|
+
type SelfType<'a> = PersistentEdge;
|
30
|
+
fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> Self::AsBytes<'a>
|
31
|
+
where
|
32
|
+
Self: 'b,
|
33
|
+
{
|
34
|
+
let mut data = Vec::<u8>::new();
|
35
|
+
ciborium::into_writer(value, &mut data).unwrap(); // This unwrap should not happen, unless there is a bug
|
36
|
+
data
|
37
|
+
}
|
38
|
+
fn from_bytes<'a>(data: &'a [u8]) -> Self::SelfType<'a>
|
39
|
+
where
|
40
|
+
Self: 'a,
|
41
|
+
{
|
42
|
+
ciborium::from_reader(data).unwrap() // This unwrap should not happen, unless there is a bug
|
43
|
+
}
|
44
|
+
fn fixed_width() -> Option<usize>
|
45
|
+
{
|
46
|
+
None
|
47
|
+
}
|
48
|
+
fn type_name() -> redb::TypeName
|
49
|
+
{
|
50
|
+
redb::TypeName::new("PersistentEdge")
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
impl redb::Value for graph::Node
|
55
|
+
{
|
56
|
+
type AsBytes<'a> = Vec<u8>;
|
57
|
+
type SelfType<'a> = graph::Node;
|
58
|
+
fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> Self::AsBytes<'a>
|
59
|
+
where
|
60
|
+
Self: 'b,
|
61
|
+
{
|
62
|
+
let mut data = Vec::<u8>::new();
|
63
|
+
ciborium::into_writer(value, &mut data).unwrap(); // This unwrap should not happen, unless there is a bug
|
64
|
+
data
|
65
|
+
}
|
66
|
+
fn from_bytes<'a>(data: &'a [u8]) -> Self::SelfType<'a>
|
67
|
+
where
|
68
|
+
Self: 'a,
|
69
|
+
{
|
70
|
+
ciborium::from_reader(data).unwrap() // This unwrap should not happen, unless there is a bug
|
71
|
+
}
|
72
|
+
fn fixed_width() -> Option<usize>
|
73
|
+
{
|
74
|
+
None
|
75
|
+
}
|
76
|
+
fn type_name() -> redb::TypeName
|
77
|
+
{
|
78
|
+
redb::TypeName::new("graph::Node")
|
79
|
+
}
|
80
|
+
}
|
81
|
+
|
82
|
+
impl redb::Value for graph::Key
|
83
|
+
{
|
84
|
+
type AsBytes<'a> = <u128 as redb::Value>::AsBytes<'a>;
|
85
|
+
type SelfType<'a> = graph::Key;
|
86
|
+
fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> Self::AsBytes<'a>
|
87
|
+
where
|
88
|
+
Self: 'b,
|
89
|
+
{
|
90
|
+
u128::as_bytes(&value.uuid)
|
91
|
+
}
|
92
|
+
fn fixed_width() -> Option<usize>
|
93
|
+
{
|
94
|
+
u128::fixed_width()
|
95
|
+
}
|
96
|
+
fn from_bytes<'a>(data: &'a [u8]) -> Self::SelfType<'a>
|
97
|
+
where
|
98
|
+
Self: 'a,
|
99
|
+
{
|
100
|
+
graph::Key {
|
101
|
+
uuid: u128::from_bytes(data),
|
102
|
+
}
|
103
|
+
}
|
104
|
+
fn type_name() -> redb::TypeName
|
105
|
+
{
|
106
|
+
redb::TypeName::new("gqlite::graph::Key")
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
impl redb::Key for graph::Key
|
111
|
+
{
|
112
|
+
fn compare(data1: &[u8], data2: &[u8]) -> std::cmp::Ordering
|
113
|
+
{
|
114
|
+
u128::compare(data1, data2)
|
115
|
+
}
|
116
|
+
}
|
117
|
+
|
118
|
+
struct EdgeIdResult
|
119
|
+
{
|
120
|
+
edge_data: PersistentEdge,
|
121
|
+
reversed: Option<bool>,
|
122
|
+
source_id: Option<graph::Key>,
|
123
|
+
destination_id: Option<graph::Key>,
|
124
|
+
}
|
125
|
+
|
126
|
+
impl EdgeIdResult
|
127
|
+
{
|
128
|
+
fn new(
|
129
|
+
edge_data: PersistentEdge,
|
130
|
+
reversed: Option<bool>,
|
131
|
+
source_id: Option<graph::Key>,
|
132
|
+
destination_id: Option<graph::Key>,
|
133
|
+
) -> EdgeIdResult
|
134
|
+
{
|
135
|
+
assert!(reversed.is_some() || source_id.is_some() || destination_id.is_some());
|
136
|
+
EdgeIdResult {
|
137
|
+
edge_data,
|
138
|
+
reversed,
|
139
|
+
source_id,
|
140
|
+
destination_id,
|
141
|
+
}
|
142
|
+
}
|
143
|
+
fn is_reversed(&self) -> bool
|
144
|
+
{
|
145
|
+
match self.reversed
|
146
|
+
{
|
147
|
+
Some(v) => v,
|
148
|
+
None => match self.source_id
|
149
|
+
{
|
150
|
+
Some(v) => self.edge_data.destination == v,
|
151
|
+
None => match self.destination_id
|
152
|
+
{
|
153
|
+
Some(v) => self.edge_data.source == v,
|
154
|
+
None => panic!("is_reversed"),
|
155
|
+
},
|
156
|
+
},
|
157
|
+
}
|
158
|
+
}
|
159
|
+
}
|
160
|
+
|
161
|
+
// _____ _ _
|
162
|
+
// |_ _|_ _| |__ | | ___
|
163
|
+
// | |/ _` | '_ \| |/ _ \
|
164
|
+
// | | (_| | |_) | | __/
|
165
|
+
// |_|\__,_|_.__/|_|\___|
|
166
|
+
|
167
|
+
trait NodeTableExtension
|
168
|
+
{
|
169
|
+
fn get_node(&self, key: graph::Key) -> Result<graph::Node>;
|
170
|
+
}
|
171
|
+
|
172
|
+
impl<'txn> NodeTableExtension for redb::Table<'txn, graph::Key, &[u8]>
|
173
|
+
{
|
174
|
+
fn get_node(&self, key: graph::Key) -> Result<graph::Node>
|
175
|
+
{
|
176
|
+
let v = self.get_required(key, || InternalError::UnknownNode)?;
|
177
|
+
let c = ciborium::from_reader::<graph::Node, &[u8]>(&mut v.value())?;
|
178
|
+
Ok::<graph::Node, crate::prelude::ErrorType>(c)
|
179
|
+
}
|
180
|
+
}
|
181
|
+
|
182
|
+
trait TableExtension<K, V>
|
183
|
+
where
|
184
|
+
K: redb::Key + 'static,
|
185
|
+
V: redb::Value + 'static,
|
186
|
+
{
|
187
|
+
fn get_required<'a, TError: Into<Error>>(
|
188
|
+
&self,
|
189
|
+
key: impl std::borrow::Borrow<K::SelfType<'a>>,
|
190
|
+
f: impl FnOnce() -> TError,
|
191
|
+
) -> Result<redb::AccessGuard<V>>;
|
192
|
+
}
|
193
|
+
|
194
|
+
impl<'txn, K, V, T> TableExtension<K, V> for T
|
195
|
+
where
|
196
|
+
T: ReadableTable<K, V>,
|
197
|
+
K: redb::Key + 'static,
|
198
|
+
V: redb::Value + 'static,
|
199
|
+
{
|
200
|
+
fn get_required<'a, TError: Into<ErrorType>>(
|
201
|
+
&self,
|
202
|
+
key: impl std::borrow::Borrow<K::SelfType<'a>>,
|
203
|
+
f: impl FnOnce() -> TError,
|
204
|
+
) -> Result<redb::AccessGuard<V>>
|
205
|
+
{
|
206
|
+
self.get(key)?.ok_or_else(|| f().into())
|
207
|
+
}
|
208
|
+
}
|
209
|
+
|
210
|
+
// ____ _ ___ __
|
211
|
+
// / ___|_ __ __ _ _ __ | |__ |_ _|_ __ / _| ___
|
212
|
+
// | | _| '__/ _` | '_ \| '_ \ | || '_ \| |_ / _ \
|
213
|
+
// | |_| | | | (_| | |_) | | | || || | | | _| (_) |
|
214
|
+
// \____|_| \__,_| .__/|_| |_|___|_| |_|_| \___/
|
215
|
+
// |_|
|
216
|
+
|
217
|
+
#[derive(Debug)]
|
218
|
+
struct GraphInfo
|
219
|
+
{
|
220
|
+
name: String,
|
221
|
+
nodes_table: String,
|
222
|
+
edges_table: String,
|
223
|
+
edges_source_index: String,
|
224
|
+
edges_destination_index: String,
|
225
|
+
}
|
226
|
+
|
227
|
+
impl GraphInfo
|
228
|
+
{
|
229
|
+
fn new(name: impl Into<String>) -> GraphInfo
|
230
|
+
{
|
231
|
+
let name = name.into();
|
232
|
+
let nodes_table = format!("__{}__nodes_table", name);
|
233
|
+
let edges_table = format!("__{}__edges_table", name);
|
234
|
+
let edges_source_index = format!("__{}__edges_source_index", name);
|
235
|
+
let edges_destination_index = format!("__{}__edges_destination_index", name);
|
236
|
+
|
237
|
+
GraphInfo {
|
238
|
+
name,
|
239
|
+
nodes_table,
|
240
|
+
edges_table,
|
241
|
+
edges_source_index,
|
242
|
+
edges_destination_index,
|
243
|
+
}
|
244
|
+
}
|
245
|
+
fn nodes_table_definition<'a>(&'a self) -> redb::TableDefinition<'a, graph::Key, graph::Node>
|
246
|
+
{
|
247
|
+
redb::TableDefinition::new(&self.nodes_table)
|
248
|
+
}
|
249
|
+
fn edges_table_definition<'a>(&'a self) -> redb::TableDefinition<'a, graph::Key, PersistentEdge>
|
250
|
+
{
|
251
|
+
redb::TableDefinition::new(&self.edges_table)
|
252
|
+
}
|
253
|
+
fn edges_source_index_definition<'a>(
|
254
|
+
&'a self,
|
255
|
+
) -> redb::TableDefinition<'a, graph::Key, Vec<graph::Key>>
|
256
|
+
{
|
257
|
+
redb::TableDefinition::new(&self.edges_source_index)
|
258
|
+
}
|
259
|
+
fn edges_destination_index_definition<'a>(
|
260
|
+
&'a self,
|
261
|
+
) -> redb::TableDefinition<'a, graph::Key, Vec<graph::Key>>
|
262
|
+
{
|
263
|
+
redb::TableDefinition::new(&self.edges_destination_index)
|
264
|
+
}
|
265
|
+
}
|
266
|
+
|
267
|
+
// _____ _ _
|
268
|
+
// |_ _| __ __ _ _ __ ___ __ _| |_(_) ___ _ __
|
269
|
+
// | || '__/ _` | '_ \/ __|/ _` | __| |/ _ \| '_ \
|
270
|
+
// | || | | (_| | | | \__ \ (_| | |_| | (_) | | | |
|
271
|
+
// |_||_| \__,_|_| |_|___/\__,_|\__|_|\___/|_| |_|
|
272
|
+
|
273
|
+
impl super::ReadTransaction for redb::ReadTransaction
|
274
|
+
{
|
275
|
+
fn discard(self) -> Result<()>
|
276
|
+
{
|
277
|
+
Ok(self.close()?)
|
278
|
+
}
|
279
|
+
}
|
280
|
+
|
281
|
+
impl super::ReadTransaction for redb::WriteTransaction
|
282
|
+
{
|
283
|
+
fn discard(self) -> Result<()>
|
284
|
+
{
|
285
|
+
Ok(self.abort()?)
|
286
|
+
}
|
287
|
+
}
|
288
|
+
|
289
|
+
impl super::WriteTransaction for redb::WriteTransaction
|
290
|
+
{
|
291
|
+
fn commit(self) -> Result<()>
|
292
|
+
{
|
293
|
+
Ok(self.commit()?)
|
294
|
+
}
|
295
|
+
}
|
296
|
+
|
297
|
+
// ____ _
|
298
|
+
// / ___|| |_ ___ _ __ ___
|
299
|
+
// \___ \| __/ _ \| '__/ _ \
|
300
|
+
// ___) | || (_) | | | __/
|
301
|
+
// |____/ \__\___/|_| \___|
|
302
|
+
|
303
|
+
/// Storage, aka, interface to the underlying redb store.
|
304
|
+
pub(crate) struct Store
|
305
|
+
{
|
306
|
+
redb_store: redb::Database,
|
307
|
+
graphs: ArcRwLock<HashMap<String, Arc<GraphInfo>>>,
|
308
|
+
}
|
309
|
+
|
310
|
+
ccutils::assert_impl_all!(Store: Sync, Send);
|
311
|
+
|
312
|
+
type TransactionBox = store::TransactionBox<redb::ReadTransaction, redb::WriteTransaction>;
|
313
|
+
|
314
|
+
impl Store
|
315
|
+
{
|
316
|
+
/// Crate a new store, with a default graph
|
317
|
+
pub(crate) fn new<P: AsRef<std::path::Path>>(path: P) -> Result<Store>
|
318
|
+
{
|
319
|
+
let s = Self {
|
320
|
+
redb_store: redb::Database::create(path.as_ref())?,
|
321
|
+
graphs: Default::default(),
|
322
|
+
};
|
323
|
+
use crate::store::Store;
|
324
|
+
let mut tx = s.begin_write()?;
|
325
|
+
s.create_graph(&mut tx, &"default".to_string(), true)?;
|
326
|
+
s.set_metadata_value(&mut tx, "version", &consts::GQLITE_VERSION)?;
|
327
|
+
tx.close()?;
|
328
|
+
Ok(s)
|
329
|
+
}
|
330
|
+
fn get_metadata_from_table<TTable, TValue>(
|
331
|
+
&self,
|
332
|
+
table: TTable,
|
333
|
+
key: impl Into<String>,
|
334
|
+
) -> Result<TValue>
|
335
|
+
where
|
336
|
+
TTable: ReadableTable<String, Vec<u8>>,
|
337
|
+
TValue: for<'a> Deserialize<'a>,
|
338
|
+
{
|
339
|
+
let key = key.into();
|
340
|
+
let value = table
|
341
|
+
.get(&key)?
|
342
|
+
.ok_or_else(|| InternalError::MissingMetadata { key: key })?;
|
343
|
+
Ok(ciborium::from_reader(value.value().as_slice())?)
|
344
|
+
}
|
345
|
+
fn get_metadata_value<T: for<'a> Deserialize<'a>>(
|
346
|
+
&self,
|
347
|
+
transaction: &mut TransactionBox,
|
348
|
+
key: impl Into<String>,
|
349
|
+
) -> Result<T>
|
350
|
+
{
|
351
|
+
let table_def = redb::TableDefinition::new("gqlite_metadata");
|
352
|
+
match transaction
|
353
|
+
{
|
354
|
+
TransactionBox::Read(read) =>
|
355
|
+
{
|
356
|
+
self.get_metadata_from_table(read.open_table(table_def)?, key.into())
|
357
|
+
}
|
358
|
+
TransactionBox::Write(write) =>
|
359
|
+
{
|
360
|
+
self.get_metadata_from_table(write.open_table(table_def)?, key.into())
|
361
|
+
}
|
362
|
+
}
|
363
|
+
}
|
364
|
+
fn get_metadata_value_or_else_from_table<TTable, TValue>(
|
365
|
+
&self,
|
366
|
+
table: TTable,
|
367
|
+
key: impl Into<String>,
|
368
|
+
f: impl FnOnce() -> TValue,
|
369
|
+
) -> Result<TValue>
|
370
|
+
where
|
371
|
+
TTable: ReadableTable<String, Vec<u8>>,
|
372
|
+
TValue: for<'a> Deserialize<'a>,
|
373
|
+
{
|
374
|
+
let key = key.into();
|
375
|
+
let value = table
|
376
|
+
.get(&key)?
|
377
|
+
.map(|r| Ok::<_, ErrorType>(ciborium::from_reader(r.value().as_slice())?))
|
378
|
+
.unwrap_or_else(|| Ok(f()))?;
|
379
|
+
Ok(value)
|
380
|
+
}
|
381
|
+
fn get_metadata_value_or_else<T: for<'a> Deserialize<'a>>(
|
382
|
+
&self,
|
383
|
+
transaction: &mut TransactionBox,
|
384
|
+
key: impl Into<String>,
|
385
|
+
f: impl FnOnce() -> T,
|
386
|
+
) -> Result<T>
|
387
|
+
{
|
388
|
+
let table_def = redb::TableDefinition::new("gqlite_metadata");
|
389
|
+
match transaction
|
390
|
+
{
|
391
|
+
TransactionBox::Read(read) =>
|
392
|
+
{
|
393
|
+
self.get_metadata_value_or_else_from_table(read.open_table(table_def)?, key.into(), f)
|
394
|
+
}
|
395
|
+
TransactionBox::Write(write) =>
|
396
|
+
{
|
397
|
+
self.get_metadata_value_or_else_from_table(write.open_table(table_def)?, key.into(), f)
|
398
|
+
}
|
399
|
+
}
|
400
|
+
}
|
401
|
+
fn set_metadata_value<T: Serialize>(
|
402
|
+
&self,
|
403
|
+
transaction: &mut TransactionBox,
|
404
|
+
key: impl Into<String>,
|
405
|
+
value: &T,
|
406
|
+
) -> Result<()>
|
407
|
+
{
|
408
|
+
let tx = transaction.try_into_write()?;
|
409
|
+
let mut metadata_table = tx.open_table(redb::TableDefinition::<'_, String, Vec<u8>>::new(
|
410
|
+
"gqlite_metadata",
|
411
|
+
))?;
|
412
|
+
let key = key.into();
|
413
|
+
let mut data = Vec::<u8>::new();
|
414
|
+
ciborium::into_writer(value, &mut data)?;
|
415
|
+
metadata_table.insert(&key, data)?;
|
416
|
+
Ok(())
|
417
|
+
}
|
418
|
+
fn get_graph_info(&self, graph_name: &String) -> Result<Arc<GraphInfo>>
|
419
|
+
{
|
420
|
+
let graphs = self.graphs.read()?;
|
421
|
+
let graph_info = graphs.get(graph_name);
|
422
|
+
match graph_info
|
423
|
+
{
|
424
|
+
Some(graph_info) => Ok(graph_info.clone()),
|
425
|
+
None =>
|
426
|
+
{
|
427
|
+
drop(graphs);
|
428
|
+
let graph_info = Arc::new(GraphInfo::new(graph_name));
|
429
|
+
self
|
430
|
+
.graphs
|
431
|
+
.write()?
|
432
|
+
.insert(graph_name.to_owned(), graph_info.clone());
|
433
|
+
Ok(graph_info)
|
434
|
+
}
|
435
|
+
}
|
436
|
+
}
|
437
|
+
fn select_nodes_from_table<'txn, T>(
|
438
|
+
&self,
|
439
|
+
nodes_table: &'txn T,
|
440
|
+
query: super::SelectNodeQuery,
|
441
|
+
) -> Result<Vec<crate::graph::Node>>
|
442
|
+
where
|
443
|
+
T: ReadableTable<graph::Key, graph::Node>,
|
444
|
+
{
|
445
|
+
let r = match query.keys
|
446
|
+
{
|
447
|
+
Some(keys) => Box::new(keys.into_iter().map(|key| {
|
448
|
+
Ok(
|
449
|
+
nodes_table
|
450
|
+
.get_required(key, || InternalError::UnknownNode)?
|
451
|
+
.value(),
|
452
|
+
)
|
453
|
+
})) as Box<dyn Iterator<Item = Result<graph::Node>>>,
|
454
|
+
None => Box::new({
|
455
|
+
nodes_table.range::<graph::Key>(..)?.into_iter().map(|r| {
|
456
|
+
let (_, v) = r?;
|
457
|
+
Ok(v.value())
|
458
|
+
})
|
459
|
+
}) as Box<dyn Iterator<Item = Result<graph::Node>>>,
|
460
|
+
};
|
461
|
+
let r = match query.labels
|
462
|
+
{
|
463
|
+
Some(labels) => Box::new(r.filter(move |n| match n
|
464
|
+
{
|
465
|
+
Ok(n) =>
|
466
|
+
{
|
467
|
+
for l in labels.iter()
|
468
|
+
{
|
469
|
+
if !n.labels.contains(l)
|
470
|
+
{
|
471
|
+
return false;
|
472
|
+
}
|
473
|
+
}
|
474
|
+
true
|
475
|
+
}
|
476
|
+
Err(_) => true,
|
477
|
+
})) as Box<dyn Iterator<Item = Result<crate::graph::Node>>>,
|
478
|
+
None => Box::new(r) as Box<dyn Iterator<Item = Result<crate::graph::Node>>>,
|
479
|
+
};
|
480
|
+
let r = match query.properties
|
481
|
+
{
|
482
|
+
Some(properties) => Box::new(r.filter(move |n| match n
|
483
|
+
{
|
484
|
+
Ok(n) =>
|
485
|
+
{
|
486
|
+
for (k, v) in properties.iter()
|
487
|
+
{
|
488
|
+
match n.properties.get(k)
|
489
|
+
{
|
490
|
+
Some(val) =>
|
491
|
+
{
|
492
|
+
if val != v
|
493
|
+
{
|
494
|
+
return false;
|
495
|
+
}
|
496
|
+
}
|
497
|
+
None =>
|
498
|
+
{
|
499
|
+
return false;
|
500
|
+
}
|
501
|
+
}
|
502
|
+
}
|
503
|
+
true
|
504
|
+
}
|
505
|
+
Err(_) => true,
|
506
|
+
})) as Box<dyn Iterator<Item = Result<crate::graph::Node>>>,
|
507
|
+
None => Box::new(r) as Box<dyn Iterator<Item = Result<crate::graph::Node>>>,
|
508
|
+
};
|
509
|
+
r.collect()
|
510
|
+
}
|
511
|
+
|
512
|
+
fn select_edges_from_tables<TEdges, TNodes, TEdgesIndex>(
|
513
|
+
&self,
|
514
|
+
query: super::SelectEdgeQuery,
|
515
|
+
directivity: graph::EdgeDirectivity,
|
516
|
+
edges_table: TEdges,
|
517
|
+
nodes_table: TNodes,
|
518
|
+
edges_source_index: Rc<RefCell<TEdgesIndex>>,
|
519
|
+
edges_destination_index: Rc<RefCell<TEdgesIndex>>,
|
520
|
+
) -> Result<Vec<super::EdgeResult>>
|
521
|
+
where
|
522
|
+
TEdges: ReadableTable<graph::Key, PersistentEdge>,
|
523
|
+
TNodes: ReadableTable<graph::Key, graph::Node>,
|
524
|
+
TEdgesIndex: ReadableTable<graph::Key, Vec<graph::Key>>,
|
525
|
+
{
|
526
|
+
let edges_uuid_indices = match directivity
|
527
|
+
{
|
528
|
+
graph::EdgeDirectivity::Directed => vec![(edges_source_index, edges_destination_index)],
|
529
|
+
graph::EdgeDirectivity::Undirected => vec![
|
530
|
+
(edges_source_index.clone(), edges_destination_index.clone()),
|
531
|
+
(edges_destination_index, edges_source_index),
|
532
|
+
],
|
533
|
+
};
|
534
|
+
|
535
|
+
// Get the UUID of the edges
|
536
|
+
let mut edges_raw = Vec::<EdgeIdResult>::new();
|
537
|
+
|
538
|
+
match &query.keys
|
539
|
+
{
|
540
|
+
Some(keys) =>
|
541
|
+
{
|
542
|
+
for key in keys.into_iter()
|
543
|
+
{
|
544
|
+
edges_raw.push(EdgeIdResult::new(
|
545
|
+
edges_table
|
546
|
+
.get(key)?
|
547
|
+
.ok_or_else(|| InternalError::UnknownNode)?
|
548
|
+
.value(),
|
549
|
+
Some(false),
|
550
|
+
None,
|
551
|
+
None,
|
552
|
+
));
|
553
|
+
}
|
554
|
+
}
|
555
|
+
None =>
|
556
|
+
{
|
557
|
+
if query.source.is_select_all() && query.destination.is_select_all()
|
558
|
+
{
|
559
|
+
edges_raw = edges_table
|
560
|
+
.range::<graph::Key>(..)?
|
561
|
+
.into_iter()
|
562
|
+
.map(|r| {
|
563
|
+
let (_, v) = r?;
|
564
|
+
Ok(EdgeIdResult::new(v.value(), Some(false), None, None))
|
565
|
+
})
|
566
|
+
.collect::<Result<Vec<EdgeIdResult>>>()?
|
567
|
+
}
|
568
|
+
else
|
569
|
+
{
|
570
|
+
let mut edge_ids = Vec::<(graph::Key, Option<graph::Key>, Option<graph::Key>)>::new();
|
571
|
+
for (edges_source_uuid_index, edges_destination_uuid_index) in edges_uuid_indices
|
572
|
+
{
|
573
|
+
if !query.destination.is_select_all() && !query.source.is_select_all()
|
574
|
+
{
|
575
|
+
let dest_it =
|
576
|
+
self.select_nodes_from_table(&nodes_table, query.destination.clone())?;
|
577
|
+
let dest_it: Vec<graph::Key> = dest_it
|
578
|
+
.into_iter()
|
579
|
+
.map(|n| {
|
580
|
+
edges_destination_uuid_index
|
581
|
+
.borrow()
|
582
|
+
.get_required(n.key, || InternalError::UnknownNode)
|
583
|
+
.map(|x| x.value())
|
584
|
+
})
|
585
|
+
.collect::<Result<Vec<_>>>()?
|
586
|
+
.into_iter()
|
587
|
+
.flatten()
|
588
|
+
.collect();
|
589
|
+
let nodes = self.select_nodes_from_table(&nodes_table, query.source.clone())?;
|
590
|
+
for n in nodes.iter()
|
591
|
+
{
|
592
|
+
let nkey = n.key;
|
593
|
+
for k in edges_source_uuid_index
|
594
|
+
.borrow()
|
595
|
+
.get_required(nkey, || InternalError::UnknownNode)?
|
596
|
+
.value()
|
597
|
+
.iter()
|
598
|
+
{
|
599
|
+
if dest_it.contains(k)
|
600
|
+
{
|
601
|
+
let uniq_k = (k.to_owned(), Some(nkey), None);
|
602
|
+
if !edge_ids.contains(&uniq_k)
|
603
|
+
{
|
604
|
+
edges_raw.push(EdgeIdResult::new(
|
605
|
+
edges_table
|
606
|
+
.get_required(k, || InternalError::UnknownEdge)?
|
607
|
+
.value(),
|
608
|
+
None,
|
609
|
+
Some(nkey),
|
610
|
+
None,
|
611
|
+
));
|
612
|
+
edge_ids.push(uniq_k);
|
613
|
+
}
|
614
|
+
}
|
615
|
+
}
|
616
|
+
}
|
617
|
+
}
|
618
|
+
else if !query.source.is_select_all()
|
619
|
+
{
|
620
|
+
let nodes = self.select_nodes_from_table(&nodes_table, query.source.clone())?;
|
621
|
+
|
622
|
+
for n in nodes.into_iter()
|
623
|
+
{
|
624
|
+
let nkey = n.key;
|
625
|
+
for k in edges_source_uuid_index
|
626
|
+
.borrow()
|
627
|
+
.get_required(nkey, || InternalError::UnknownNode)?
|
628
|
+
.value()
|
629
|
+
.iter()
|
630
|
+
{
|
631
|
+
let uniq_k = (k.to_owned(), Some(nkey), None);
|
632
|
+
if !edge_ids.contains(&uniq_k)
|
633
|
+
{
|
634
|
+
edges_raw.push(EdgeIdResult::new(
|
635
|
+
edges_table
|
636
|
+
.get_required(k, || InternalError::UnknownEdge)?
|
637
|
+
.value(),
|
638
|
+
None,
|
639
|
+
Some(nkey),
|
640
|
+
None,
|
641
|
+
));
|
642
|
+
edge_ids.push(uniq_k);
|
643
|
+
}
|
644
|
+
}
|
645
|
+
}
|
646
|
+
}
|
647
|
+
else
|
648
|
+
{
|
649
|
+
let nodes = self.select_nodes_from_table(&nodes_table, query.destination.clone())?;
|
650
|
+
for n in nodes.into_iter()
|
651
|
+
{
|
652
|
+
let nkey = n.key;
|
653
|
+
for k in edges_destination_uuid_index
|
654
|
+
.borrow()
|
655
|
+
.get_required(nkey, || InternalError::UnknownNode)?
|
656
|
+
.value()
|
657
|
+
.iter()
|
658
|
+
{
|
659
|
+
let uniq_k = (k.to_owned(), None, Some(nkey));
|
660
|
+
if !edge_ids.contains(&uniq_k)
|
661
|
+
{
|
662
|
+
edges_raw.push(EdgeIdResult::new(
|
663
|
+
edges_table
|
664
|
+
.get_required(k, || InternalError::UnknownEdge)?
|
665
|
+
.value(),
|
666
|
+
None,
|
667
|
+
None,
|
668
|
+
Some(nkey),
|
669
|
+
));
|
670
|
+
edge_ids.push(uniq_k);
|
671
|
+
}
|
672
|
+
}
|
673
|
+
}
|
674
|
+
}
|
675
|
+
}
|
676
|
+
}
|
677
|
+
}
|
678
|
+
}
|
679
|
+
|
680
|
+
// Get the edges
|
681
|
+
let r = edges_raw.into_iter().map(|v| {
|
682
|
+
Ok::<super::EdgeResult, crate::prelude::ErrorType>({
|
683
|
+
let reversed = v.is_reversed();
|
684
|
+
let edge = v.edge_data;
|
685
|
+
|
686
|
+
let source = nodes_table
|
687
|
+
.get_required(edge.source, || InternalError::UnknownNode)?
|
688
|
+
.value();
|
689
|
+
let destination = nodes_table
|
690
|
+
.get_required(edge.destination, || InternalError::UnknownNode)?
|
691
|
+
.value();
|
692
|
+
|
693
|
+
let edge = graph::Edge {
|
694
|
+
key: edge.key,
|
695
|
+
source,
|
696
|
+
destination,
|
697
|
+
labels: edge.labels,
|
698
|
+
properties: edge.properties,
|
699
|
+
};
|
700
|
+
super::EdgeResult { edge, reversed }
|
701
|
+
})
|
702
|
+
});
|
703
|
+
// Filter using the labels
|
704
|
+
let r = match &query.labels
|
705
|
+
{
|
706
|
+
Some(labels) => Box::new(r.filter(move |e| match e
|
707
|
+
{
|
708
|
+
Ok(e) =>
|
709
|
+
{
|
710
|
+
for l in labels.iter()
|
711
|
+
{
|
712
|
+
if !e.edge.labels.contains(l)
|
713
|
+
{
|
714
|
+
return false;
|
715
|
+
}
|
716
|
+
}
|
717
|
+
true
|
718
|
+
}
|
719
|
+
Err(_) => true,
|
720
|
+
})) as Box<dyn Iterator<Item = Result<super::EdgeResult>>>,
|
721
|
+
None => Box::new(r) as Box<dyn Iterator<Item = Result<super::EdgeResult>>>,
|
722
|
+
};
|
723
|
+
let r = match &query.properties
|
724
|
+
{
|
725
|
+
Some(properties) => Box::new(r.filter(move |e| match e
|
726
|
+
{
|
727
|
+
Ok(e) =>
|
728
|
+
{
|
729
|
+
for (k, v) in properties.iter()
|
730
|
+
{
|
731
|
+
match e.edge.properties.get(k)
|
732
|
+
{
|
733
|
+
Some(val) =>
|
734
|
+
{
|
735
|
+
if val != v
|
736
|
+
{
|
737
|
+
return false;
|
738
|
+
}
|
739
|
+
}
|
740
|
+
None =>
|
741
|
+
{
|
742
|
+
return false;
|
743
|
+
}
|
744
|
+
}
|
745
|
+
}
|
746
|
+
true
|
747
|
+
}
|
748
|
+
Err(_) => true,
|
749
|
+
})) as Box<dyn Iterator<Item = Result<super::EdgeResult>>>,
|
750
|
+
None => Box::new(r) as Box<dyn Iterator<Item = Result<super::EdgeResult>>>,
|
751
|
+
};
|
752
|
+
if query.keys.is_some() && (!query.source.is_select_all() || !query.destination.is_select_all())
|
753
|
+
{
|
754
|
+
r.filter(|e| {
|
755
|
+
if let Ok(e) = &e
|
756
|
+
{
|
757
|
+
query.is_match(&e.edge)
|
758
|
+
}
|
759
|
+
else
|
760
|
+
{
|
761
|
+
return true;
|
762
|
+
}
|
763
|
+
})
|
764
|
+
.collect()
|
765
|
+
}
|
766
|
+
else
|
767
|
+
{
|
768
|
+
r.collect()
|
769
|
+
}
|
770
|
+
}
|
771
|
+
}
|
772
|
+
|
773
|
+
impl store::Store for Store
|
774
|
+
{
|
775
|
+
type TransactionBox = TransactionBox;
|
776
|
+
|
777
|
+
fn begin_write(&self) -> Result<Self::TransactionBox>
|
778
|
+
{
|
779
|
+
let s = self.redb_store.begin_write()?;
|
780
|
+
Ok(Self::TransactionBox::from_write(s))
|
781
|
+
}
|
782
|
+
fn begin_read(&self) -> Result<Self::TransactionBox>
|
783
|
+
{
|
784
|
+
let s = self.redb_store.begin_read()?;
|
785
|
+
Ok(Self::TransactionBox::from_read(s))
|
786
|
+
}
|
787
|
+
fn graphs_list(&self, transaction: &mut Self::TransactionBox) -> Result<Vec<String>>
|
788
|
+
{
|
789
|
+
self.get_metadata_value_or_else(transaction, "graphs".to_string(), || vec![])
|
790
|
+
}
|
791
|
+
fn create_graph(
|
792
|
+
&self,
|
793
|
+
transaction: &mut Self::TransactionBox,
|
794
|
+
graph_name: &String,
|
795
|
+
ignore_if_exists: bool,
|
796
|
+
) -> Result<()>
|
797
|
+
{
|
798
|
+
let mut graphs_list = self.graphs_list(transaction)?;
|
799
|
+
if graphs_list.contains(graph_name)
|
800
|
+
{
|
801
|
+
if ignore_if_exists
|
802
|
+
{
|
803
|
+
return Ok(());
|
804
|
+
}
|
805
|
+
else
|
806
|
+
{
|
807
|
+
return Err(
|
808
|
+
StoreError::DuplicatedGraph {
|
809
|
+
graph_name: graph_name.to_owned(),
|
810
|
+
}
|
811
|
+
.into(),
|
812
|
+
);
|
813
|
+
}
|
814
|
+
}
|
815
|
+
|
816
|
+
{
|
817
|
+
let tx = transaction.try_into_write()?;
|
818
|
+
|
819
|
+
let gi = Arc::new(GraphInfo::new(graph_name));
|
820
|
+
tx.open_table(gi.nodes_table_definition())?;
|
821
|
+
tx.open_table(gi.edges_table_definition())?;
|
822
|
+
tx.open_table(gi.edges_source_index_definition())?;
|
823
|
+
tx.open_table(gi.edges_destination_index_definition())?;
|
824
|
+
|
825
|
+
self.graphs.write()?.insert(graph_name.to_owned(), gi);
|
826
|
+
}
|
827
|
+
graphs_list.push(graph_name.clone());
|
828
|
+
self.set_metadata_value(transaction, "graphs", &graphs_list)?;
|
829
|
+
|
830
|
+
Ok(())
|
831
|
+
}
|
832
|
+
fn delete_graph(&self, transaction: &mut Self::TransactionBox, graph_name: &String)
|
833
|
+
-> Result<()>
|
834
|
+
{
|
835
|
+
let mut graphs_list = self.graphs_list(transaction)?;
|
836
|
+
if graphs_list.contains(graph_name)
|
837
|
+
{
|
838
|
+
{
|
839
|
+
let tx = transaction.try_into_write()?;
|
840
|
+
let graph_info = self.get_graph_info(graph_name)?;
|
841
|
+
tx.delete_table(graph_info.nodes_table_definition())?;
|
842
|
+
tx.delete_table(graph_info.edges_table_definition())?;
|
843
|
+
tx.delete_table(graph_info.edges_source_index_definition())?;
|
844
|
+
tx.delete_table(graph_info.edges_destination_index_definition())?;
|
845
|
+
}
|
846
|
+
graphs_list.retain(|x| x != graph_name);
|
847
|
+
self.set_metadata_value(transaction, "graphs", &graphs_list)?;
|
848
|
+
|
849
|
+
Ok(())
|
850
|
+
}
|
851
|
+
else
|
852
|
+
{
|
853
|
+
Err(
|
854
|
+
StoreError::UnknownGraph {
|
855
|
+
graph_name: graph_name.to_owned(),
|
856
|
+
}
|
857
|
+
.into(),
|
858
|
+
)
|
859
|
+
}
|
860
|
+
}
|
861
|
+
/// Create nodes and add them to a graph
|
862
|
+
fn create_nodes<'a, T: Iterator<Item = &'a crate::graph::Node>>(
|
863
|
+
&self,
|
864
|
+
transaction: &mut Self::TransactionBox,
|
865
|
+
graph_name: &String,
|
866
|
+
nodes_iter: T,
|
867
|
+
) -> Result<()>
|
868
|
+
{
|
869
|
+
let graph_info = self.get_graph_info(graph_name)?;
|
870
|
+
let transaction = transaction.try_into_write()?;
|
871
|
+
let mut table = transaction.open_table(graph_info.nodes_table_definition())?;
|
872
|
+
let mut table_source = transaction.open_table(graph_info.edges_source_index_definition())?;
|
873
|
+
let mut table_destination =
|
874
|
+
transaction.open_table(graph_info.edges_destination_index_definition())?;
|
875
|
+
for x in nodes_iter
|
876
|
+
{
|
877
|
+
table.insert(x.key, x)?;
|
878
|
+
table_source.insert(x.key, vec![])?;
|
879
|
+
table_destination.insert(x.key, vec![])?;
|
880
|
+
}
|
881
|
+
Ok(())
|
882
|
+
}
|
883
|
+
/// Create nodes and add them to a graph
|
884
|
+
fn update_node(
|
885
|
+
&self,
|
886
|
+
transaction: &mut Self::TransactionBox,
|
887
|
+
graph_name: &String,
|
888
|
+
node: &graph::Node,
|
889
|
+
) -> Result<()>
|
890
|
+
{
|
891
|
+
let graph_info = self.get_graph_info(graph_name)?;
|
892
|
+
let transaction = transaction.try_into_write()?;
|
893
|
+
let mut table = transaction.open_table(graph_info.nodes_table_definition())?;
|
894
|
+
table.insert(node.key, node)?;
|
895
|
+
Ok(())
|
896
|
+
}
|
897
|
+
/// Delete nodes according to a given query
|
898
|
+
fn delete_nodes(
|
899
|
+
&self,
|
900
|
+
transaction: &mut Self::TransactionBox,
|
901
|
+
graph_name: &String,
|
902
|
+
query: super::SelectNodeQuery,
|
903
|
+
detach: bool,
|
904
|
+
) -> Result<()>
|
905
|
+
{
|
906
|
+
let graph_info = self.get_graph_info(graph_name)?;
|
907
|
+
|
908
|
+
if query.is_select_all()
|
909
|
+
{
|
910
|
+
let write_transaction = transaction.try_into_write()?;
|
911
|
+
if detach
|
912
|
+
{
|
913
|
+
write_transaction.delete_table(graph_info.edges_table_definition())?;
|
914
|
+
write_transaction.delete_table(graph_info.edges_source_index_definition())?;
|
915
|
+
write_transaction.delete_table(graph_info.edges_destination_index_definition())?;
|
916
|
+
write_transaction.open_table(graph_info.edges_table_definition())?;
|
917
|
+
write_transaction.open_table(graph_info.edges_source_index_definition())?;
|
918
|
+
write_transaction.open_table(graph_info.edges_destination_index_definition())?;
|
919
|
+
}
|
920
|
+
else
|
921
|
+
{
|
922
|
+
let edge_table = write_transaction.open_table(graph_info.edges_table_definition())?;
|
923
|
+
if edge_table.len()? > 0
|
924
|
+
{
|
925
|
+
return Err(error::RunTimeError::DeleteConnectedNode.into());
|
926
|
+
}
|
927
|
+
}
|
928
|
+
write_transaction.delete_table(graph_info.nodes_table_definition())?;
|
929
|
+
write_transaction.open_table(graph_info.nodes_table_definition())?;
|
930
|
+
}
|
931
|
+
else
|
932
|
+
{
|
933
|
+
let node_keys = if query.is_select_only_keys()
|
934
|
+
{
|
935
|
+
query
|
936
|
+
.keys
|
937
|
+
.ok_or_else(|| error::InternalError::Unreachable {
|
938
|
+
context: "persy/store/delete_nodes",
|
939
|
+
})?
|
940
|
+
}
|
941
|
+
else
|
942
|
+
{
|
943
|
+
self
|
944
|
+
.select_nodes(transaction, graph_name, query)?
|
945
|
+
.into_iter()
|
946
|
+
.map(|x| x.key)
|
947
|
+
.collect()
|
948
|
+
};
|
949
|
+
|
950
|
+
if detach
|
951
|
+
{
|
952
|
+
// Delete the edges connected to the nodes
|
953
|
+
self.delete_edges(
|
954
|
+
transaction,
|
955
|
+
graph_name,
|
956
|
+
super::SelectEdgeQuery::select_source_keys(super::SelectNodeQuery::select_keys(
|
957
|
+
node_keys.clone(),
|
958
|
+
)),
|
959
|
+
graph::EdgeDirectivity::Undirected,
|
960
|
+
)?;
|
961
|
+
}
|
962
|
+
else
|
963
|
+
{
|
964
|
+
let write_transaction = transaction.try_into_write()?;
|
965
|
+
// Check if the nodes are disconnected
|
966
|
+
let table_source =
|
967
|
+
write_transaction.open_table(graph_info.edges_source_index_definition())?;
|
968
|
+
let table_destination =
|
969
|
+
write_transaction.open_table(graph_info.edges_destination_index_definition())?;
|
970
|
+
|
971
|
+
for key in node_keys.iter()
|
972
|
+
{
|
973
|
+
if !table_source
|
974
|
+
.get_required(key, || InternalError::UnknownNode)?
|
975
|
+
.value()
|
976
|
+
.is_empty()
|
977
|
+
|| !table_destination
|
978
|
+
.get_required(key, || InternalError::UnknownNode)?
|
979
|
+
.value()
|
980
|
+
.is_empty()
|
981
|
+
{
|
982
|
+
return Err(error::RunTimeError::DeleteConnectedNode.into());
|
983
|
+
}
|
984
|
+
}
|
985
|
+
}
|
986
|
+
let write_transaction = transaction.try_into_write()?;
|
987
|
+
// Delete the nodes
|
988
|
+
let mut table_nodes = write_transaction.open_table(graph_info.nodes_table_definition())?;
|
989
|
+
let mut table_source =
|
990
|
+
write_transaction.open_table(graph_info.edges_source_index_definition())?;
|
991
|
+
let mut table_destination =
|
992
|
+
write_transaction.open_table(graph_info.edges_destination_index_definition())?;
|
993
|
+
for key in node_keys.into_iter()
|
994
|
+
{
|
995
|
+
table_nodes.remove(key)?;
|
996
|
+
table_source.remove(key)?;
|
997
|
+
table_destination.remove(key)?;
|
998
|
+
}
|
999
|
+
}
|
1000
|
+
Ok(())
|
1001
|
+
}
|
1002
|
+
/// Select nodes according to a given query
|
1003
|
+
fn select_nodes(
|
1004
|
+
&self,
|
1005
|
+
transaction: &mut Self::TransactionBox,
|
1006
|
+
graph_name: &String,
|
1007
|
+
query: super::SelectNodeQuery,
|
1008
|
+
) -> Result<Vec<crate::graph::Node>>
|
1009
|
+
{
|
1010
|
+
let graph_info = self.get_graph_info(graph_name)?;
|
1011
|
+
match transaction
|
1012
|
+
{
|
1013
|
+
store::TransactionBox::Read(read) =>
|
1014
|
+
{
|
1015
|
+
let nodes_table = read.open_table(graph_info.nodes_table_definition())?;
|
1016
|
+
self.select_nodes_from_table(&nodes_table, query)
|
1017
|
+
}
|
1018
|
+
store::TransactionBox::Write(write) =>
|
1019
|
+
{
|
1020
|
+
let nodes_table = write.open_table(graph_info.nodes_table_definition())?;
|
1021
|
+
self.select_nodes_from_table(&nodes_table, query)
|
1022
|
+
}
|
1023
|
+
}
|
1024
|
+
}
|
1025
|
+
/// Add edge
|
1026
|
+
fn create_edges<'a, T: Iterator<Item = &'a crate::graph::Edge>>(
|
1027
|
+
&self,
|
1028
|
+
transaction: &mut Self::TransactionBox,
|
1029
|
+
graph_name: &String,
|
1030
|
+
edges_iter: T,
|
1031
|
+
) -> Result<()>
|
1032
|
+
{
|
1033
|
+
let transaction = transaction.try_into_write()?;
|
1034
|
+
let graph_info = self.get_graph_info(graph_name)?;
|
1035
|
+
let mut table = transaction.open_table(graph_info.edges_table_definition())?;
|
1036
|
+
let mut table_source = transaction.open_table(graph_info.edges_source_index_definition())?;
|
1037
|
+
let mut table_destination =
|
1038
|
+
transaction.open_table(graph_info.edges_destination_index_definition())?;
|
1039
|
+
|
1040
|
+
for x in edges_iter
|
1041
|
+
{
|
1042
|
+
let mut keys_source = table_source
|
1043
|
+
.remove(x.source.key)?
|
1044
|
+
.ok_or(InternalError::UnknownNode)?
|
1045
|
+
.value();
|
1046
|
+
keys_source.push(x.key);
|
1047
|
+
let mut keys_destination = table_destination
|
1048
|
+
.remove(x.destination.key)?
|
1049
|
+
.ok_or(InternalError::UnknownNode)?
|
1050
|
+
.value();
|
1051
|
+
keys_destination.push(x.key);
|
1052
|
+
|
1053
|
+
table.insert(
|
1054
|
+
x.key,
|
1055
|
+
&PersistentEdge {
|
1056
|
+
key: x.key,
|
1057
|
+
source: x.source.key,
|
1058
|
+
destination: x.destination.key,
|
1059
|
+
labels: x.labels.clone(),
|
1060
|
+
properties: x.properties.clone(),
|
1061
|
+
},
|
1062
|
+
)?;
|
1063
|
+
table_source.insert(x.source.key, keys_source)?;
|
1064
|
+
table_destination.insert(x.destination.key, keys_destination)?;
|
1065
|
+
}
|
1066
|
+
Ok(())
|
1067
|
+
}
|
1068
|
+
fn update_edge(
|
1069
|
+
&self,
|
1070
|
+
transaction: &mut Self::TransactionBox,
|
1071
|
+
graph_name: &String,
|
1072
|
+
edge: &graph::Edge,
|
1073
|
+
) -> Result<()>
|
1074
|
+
{
|
1075
|
+
let transaction = transaction.try_into_write()?;
|
1076
|
+
let graph_info = self.get_graph_info(graph_name)?;
|
1077
|
+
let mut table = transaction.open_table(graph_info.edges_table_definition())?;
|
1078
|
+
table.insert(
|
1079
|
+
edge.key,
|
1080
|
+
&PersistentEdge {
|
1081
|
+
key: edge.key,
|
1082
|
+
source: edge.source.key,
|
1083
|
+
destination: edge.destination.key,
|
1084
|
+
labels: edge.labels.to_owned(),
|
1085
|
+
properties: edge.properties.to_owned(),
|
1086
|
+
},
|
1087
|
+
)?;
|
1088
|
+
Ok(())
|
1089
|
+
}
|
1090
|
+
/// Delete nodes according to a given query
|
1091
|
+
fn delete_edges(
|
1092
|
+
&self,
|
1093
|
+
transaction: &mut Self::TransactionBox,
|
1094
|
+
graph_name: &String,
|
1095
|
+
query: super::SelectEdgeQuery,
|
1096
|
+
directivity: graph::EdgeDirectivity,
|
1097
|
+
) -> Result<()>
|
1098
|
+
{
|
1099
|
+
let graph_info = self.get_graph_info(graph_name)?;
|
1100
|
+
let edges = self.select_edges(transaction, graph_name, query, directivity)?;
|
1101
|
+
|
1102
|
+
let transaction = transaction.try_into_write()?;
|
1103
|
+
|
1104
|
+
let mut table = transaction.open_table(graph_info.edges_table_definition())?;
|
1105
|
+
let mut table_source = transaction.open_table(graph_info.edges_source_index_definition())?;
|
1106
|
+
let mut table_destination =
|
1107
|
+
transaction.open_table(graph_info.edges_destination_index_definition())?;
|
1108
|
+
|
1109
|
+
for e in edges
|
1110
|
+
{
|
1111
|
+
table.remove(e.edge.key)?;
|
1112
|
+
let (sk, dk) = if e.reversed
|
1113
|
+
{
|
1114
|
+
(e.edge.destination.key, e.edge.source.key)
|
1115
|
+
}
|
1116
|
+
else
|
1117
|
+
{
|
1118
|
+
(e.edge.source.key, e.edge.destination.key)
|
1119
|
+
};
|
1120
|
+
|
1121
|
+
let mut v = table_source
|
1122
|
+
.remove(sk)?
|
1123
|
+
.ok_or_else(|| InternalError::UnknownNode)?
|
1124
|
+
.value();
|
1125
|
+
v.retain(|x| *x != e.edge.key);
|
1126
|
+
table_source.insert(sk, v)?;
|
1127
|
+
|
1128
|
+
let mut v = table_destination
|
1129
|
+
.remove(dk)?
|
1130
|
+
.ok_or_else(|| InternalError::UnknownNode)?
|
1131
|
+
.value();
|
1132
|
+
v.retain(|x| *x != e.edge.key);
|
1133
|
+
table_destination.insert(dk, v)?;
|
1134
|
+
}
|
1135
|
+
Ok(())
|
1136
|
+
}
|
1137
|
+
/// Select edges
|
1138
|
+
fn select_edges(
|
1139
|
+
&self,
|
1140
|
+
transaction: &mut Self::TransactionBox,
|
1141
|
+
graph_name: &String,
|
1142
|
+
query: super::SelectEdgeQuery,
|
1143
|
+
directivity: graph::EdgeDirectivity,
|
1144
|
+
) -> Result<Vec<super::EdgeResult>>
|
1145
|
+
{
|
1146
|
+
if query.source.is_select_none() || query.destination.is_select_none()
|
1147
|
+
{
|
1148
|
+
return Ok(Default::default());
|
1149
|
+
}
|
1150
|
+
let graph_info = self.get_graph_info(graph_name)?;
|
1151
|
+
|
1152
|
+
match transaction
|
1153
|
+
{
|
1154
|
+
store::TransactionBox::Read(read) =>
|
1155
|
+
{
|
1156
|
+
let edges_table = read.open_table(graph_info.edges_table_definition())?;
|
1157
|
+
let nodes_table = read.open_table(graph_info.nodes_table_definition())?;
|
1158
|
+
|
1159
|
+
let edges_source_index = Rc::new(RefCell::new(
|
1160
|
+
read.open_table(graph_info.edges_source_index_definition())?,
|
1161
|
+
));
|
1162
|
+
let edges_destination_index = Rc::new(RefCell::new(
|
1163
|
+
read.open_table(graph_info.edges_destination_index_definition())?,
|
1164
|
+
));
|
1165
|
+
|
1166
|
+
self.select_edges_from_tables(
|
1167
|
+
query,
|
1168
|
+
directivity,
|
1169
|
+
edges_table,
|
1170
|
+
nodes_table,
|
1171
|
+
edges_source_index,
|
1172
|
+
edges_destination_index,
|
1173
|
+
)
|
1174
|
+
}
|
1175
|
+
store::TransactionBox::Write(write) =>
|
1176
|
+
{
|
1177
|
+
let edges_table = write.open_table(graph_info.edges_table_definition())?;
|
1178
|
+
let nodes_table = write.open_table(graph_info.nodes_table_definition())?;
|
1179
|
+
|
1180
|
+
let edges_source_index = Rc::new(RefCell::new(
|
1181
|
+
write.open_table(graph_info.edges_source_index_definition())?,
|
1182
|
+
));
|
1183
|
+
let edges_destination_index = Rc::new(RefCell::new(
|
1184
|
+
write.open_table(graph_info.edges_destination_index_definition())?,
|
1185
|
+
));
|
1186
|
+
|
1187
|
+
self.select_edges_from_tables(
|
1188
|
+
query,
|
1189
|
+
directivity,
|
1190
|
+
edges_table,
|
1191
|
+
nodes_table,
|
1192
|
+
edges_source_index,
|
1193
|
+
edges_destination_index,
|
1194
|
+
)
|
1195
|
+
}
|
1196
|
+
}
|
1197
|
+
}
|
1198
|
+
fn compute_statistics(&self, transaction: &mut Self::TransactionBox)
|
1199
|
+
-> Result<super::Statistics>
|
1200
|
+
{
|
1201
|
+
let mut edges_count = 0;
|
1202
|
+
let mut nodes_count = 0;
|
1203
|
+
let mut labels = Vec::new();
|
1204
|
+
let mut properties_count = 0;
|
1205
|
+
|
1206
|
+
for n in self.select_nodes(
|
1207
|
+
transaction,
|
1208
|
+
&"default".into(),
|
1209
|
+
super::SelectNodeQuery::select_all(),
|
1210
|
+
)?
|
1211
|
+
{
|
1212
|
+
nodes_count += 1;
|
1213
|
+
for l in n.labels.iter()
|
1214
|
+
{
|
1215
|
+
if !labels.contains(l)
|
1216
|
+
{
|
1217
|
+
labels.push(l.to_owned());
|
1218
|
+
}
|
1219
|
+
}
|
1220
|
+
properties_count += n
|
1221
|
+
.properties
|
1222
|
+
.iter()
|
1223
|
+
.filter(|(_, v)| **v != value::Value::Null)
|
1224
|
+
.count();
|
1225
|
+
}
|
1226
|
+
for e in self.select_edges(
|
1227
|
+
transaction,
|
1228
|
+
&"default".into(),
|
1229
|
+
super::SelectEdgeQuery::select_all(),
|
1230
|
+
graph::EdgeDirectivity::Directed,
|
1231
|
+
)?
|
1232
|
+
{
|
1233
|
+
edges_count += 1;
|
1234
|
+
|
1235
|
+
properties_count += e
|
1236
|
+
.edge
|
1237
|
+
.properties
|
1238
|
+
.iter()
|
1239
|
+
.filter(|(_, v)| **v != value::Value::Null)
|
1240
|
+
.count();
|
1241
|
+
}
|
1242
|
+
|
1243
|
+
Ok(super::Statistics {
|
1244
|
+
nodes_count,
|
1245
|
+
edges_count,
|
1246
|
+
labels_nodes_count: labels.len(),
|
1247
|
+
properties_count,
|
1248
|
+
})
|
1249
|
+
}
|
1250
|
+
}
|