gqlite 1.2.0 → 1.2.3

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