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.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/ext/gqliterb/.cargo/config.toml +2 -0
  3. data/ext/gqliterb/Cargo.lock +1109 -0
  4. data/ext/gqliterb/Cargo.toml +43 -0
  5. data/ext/gqliterb/extconf.rb +4 -0
  6. data/ext/gqliterb/src/lib.rs +260 -0
  7. data/ext/gqliterb/vendor/gqlitedb/Cargo.lock +2060 -0
  8. data/ext/gqliterb/vendor/gqlitedb/Cargo.toml +132 -0
  9. data/ext/gqliterb/vendor/gqlitedb/askama.toml +3 -0
  10. data/ext/gqliterb/vendor/gqlitedb/benches/common/mod.rs +25 -0
  11. data/ext/gqliterb/vendor/gqlitedb/benches/common/pokec.rs +185 -0
  12. data/ext/gqliterb/vendor/gqlitedb/benches/pokec_divan.rs +137 -0
  13. data/ext/gqliterb/vendor/gqlitedb/benches/pokec_iai.rs +122 -0
  14. data/ext/gqliterb/vendor/gqlitedb/release.toml +7 -0
  15. data/ext/gqliterb/vendor/gqlitedb/src/aggregators/arithmetic.rs +96 -0
  16. data/ext/gqliterb/vendor/gqlitedb/src/aggregators/containers.rs +33 -0
  17. data/ext/gqliterb/vendor/gqlitedb/src/aggregators/count.rs +35 -0
  18. data/ext/gqliterb/vendor/gqlitedb/src/aggregators/stats.rs +168 -0
  19. data/ext/gqliterb/vendor/gqlitedb/src/aggregators.rs +74 -0
  20. data/ext/gqliterb/vendor/gqlitedb/src/capi.rs +236 -0
  21. data/ext/gqliterb/vendor/gqlitedb/src/compiler/expression_analyser.rs +427 -0
  22. data/ext/gqliterb/vendor/gqlitedb/src/compiler/variables_manager.rs +620 -0
  23. data/ext/gqliterb/vendor/gqlitedb/src/compiler.rs +1106 -0
  24. data/ext/gqliterb/vendor/gqlitedb/src/connection.rs +208 -0
  25. data/ext/gqliterb/vendor/gqlitedb/src/consts.rs +10 -0
  26. data/ext/gqliterb/vendor/gqlitedb/src/error.rs +621 -0
  27. data/ext/gqliterb/vendor/gqlitedb/src/functions/containers.rs +115 -0
  28. data/ext/gqliterb/vendor/gqlitedb/src/functions/edge.rs +20 -0
  29. data/ext/gqliterb/vendor/gqlitedb/src/functions/math.rs +44 -0
  30. data/ext/gqliterb/vendor/gqlitedb/src/functions/node.rs +16 -0
  31. data/ext/gqliterb/vendor/gqlitedb/src/functions/path.rs +48 -0
  32. data/ext/gqliterb/vendor/gqlitedb/src/functions/scalar.rs +86 -0
  33. data/ext/gqliterb/vendor/gqlitedb/src/functions/string.rs +28 -0
  34. data/ext/gqliterb/vendor/gqlitedb/src/functions/value.rs +99 -0
  35. data/ext/gqliterb/vendor/gqlitedb/src/functions.rs +412 -0
  36. data/ext/gqliterb/vendor/gqlitedb/src/graph.rs +268 -0
  37. data/ext/gqliterb/vendor/gqlitedb/src/interpreter/evaluators.rs +1788 -0
  38. data/ext/gqliterb/vendor/gqlitedb/src/interpreter/instructions.rs +262 -0
  39. data/ext/gqliterb/vendor/gqlitedb/src/interpreter/mod.rs +4 -0
  40. data/ext/gqliterb/vendor/gqlitedb/src/lib.rs +42 -0
  41. data/ext/gqliterb/vendor/gqlitedb/src/parser/ast.rs +625 -0
  42. data/ext/gqliterb/vendor/gqlitedb/src/parser/gql.pest +191 -0
  43. data/ext/gqliterb/vendor/gqlitedb/src/parser/parser.rs +1153 -0
  44. data/ext/gqliterb/vendor/gqlitedb/src/parser.rs +4 -0
  45. data/ext/gqliterb/vendor/gqlitedb/src/prelude.rs +8 -0
  46. data/ext/gqliterb/vendor/gqlitedb/src/serialize_with.rs +94 -0
  47. data/ext/gqliterb/vendor/gqlitedb/src/store/pgql.rs +121 -0
  48. data/ext/gqliterb/vendor/gqlitedb/src/store/redb.rs +1250 -0
  49. data/ext/gqliterb/vendor/gqlitedb/src/store/sqlite.rs +994 -0
  50. data/ext/gqliterb/vendor/gqlitedb/src/store.rs +432 -0
  51. data/ext/gqliterb/vendor/gqlitedb/src/tests/compiler.rs +92 -0
  52. data/ext/gqliterb/vendor/gqlitedb/src/tests/evaluators.rs +227 -0
  53. data/ext/gqliterb/vendor/gqlitedb/src/tests/parser.rs +81 -0
  54. data/ext/gqliterb/vendor/gqlitedb/src/tests/store/redb.rs +39 -0
  55. data/ext/gqliterb/vendor/gqlitedb/src/tests/store/sqlite.rs +39 -0
  56. data/ext/gqliterb/vendor/gqlitedb/src/tests/store.rs +462 -0
  57. data/ext/gqliterb/vendor/gqlitedb/src/tests/templates/ast.rs +356 -0
  58. data/ext/gqliterb/vendor/gqlitedb/src/tests/templates/programs.rs +455 -0
  59. data/ext/gqliterb/vendor/gqlitedb/src/tests/templates.rs +2 -0
  60. data/ext/gqliterb/vendor/gqlitedb/src/tests.rs +39 -0
  61. data/ext/gqliterb/vendor/gqlitedb/src/utils.rs +28 -0
  62. data/ext/gqliterb/vendor/gqlitedb/src/value/compare.rs +212 -0
  63. data/ext/gqliterb/vendor/gqlitedb/src/value/contains.rs +47 -0
  64. data/ext/gqliterb/vendor/gqlitedb/src/value/value_map.rs +298 -0
  65. data/ext/gqliterb/vendor/gqlitedb/src/value.rs +559 -0
  66. data/ext/gqliterb/vendor/gqlitedb/src/value_table.rs +616 -0
  67. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/call_stats.sql +22 -0
  68. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_count_for_node.sql +3 -0
  69. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_create.sql +6 -0
  70. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_delete.sql +1 -0
  71. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_delete_by_nodes.sql +2 -0
  72. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_select.sql +139 -0
  73. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/edge_update.sql +4 -0
  74. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/graph_create.sql +16 -0
  75. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/graph_delete.sql +3 -0
  76. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/metadata_create_table.sql +1 -0
  77. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/metadata_get.sql +1 -0
  78. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/metadata_set.sql +1 -0
  79. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/node_create.sql +1 -0
  80. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/node_delete.sql +1 -0
  81. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/node_select.sql +42 -0
  82. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/node_update.sql +4 -0
  83. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/table_exists.sql +5 -0
  84. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/upgrade_from_1_01.sql +2 -0
  85. data/ext/gqliterb/vendor/gqlitedb/templates/sql/sqlite/upgrade_graph_from_1_01.sql +65 -0
  86. data/lib/gqlite.rb +1 -75
  87. metadata +118 -25
  88. data/ext/gqlite/extconf.rb +0 -21
  89. data/ext/gqlite/gqlite-amalgamate.cpp +0 -9599
  90. data/ext/gqlite/gqlite-c.h +0 -95
  91. 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
+ }