gqlite 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/ext/Cargo.toml +4 -3
  3. data/ext/gqlitedb/Cargo.toml +7 -4
  4. data/ext/gqlitedb/src/aggregators/arithmetic.rs +1 -0
  5. data/ext/gqlitedb/src/compiler/expression_analyser.rs +2 -0
  6. data/ext/gqlitedb/src/compiler.rs +31 -19
  7. data/ext/gqlitedb/src/connection.rs +42 -7
  8. data/ext/gqlitedb/src/error.rs +3 -0
  9. data/ext/gqlitedb/src/functions/containers.rs +1 -1
  10. data/ext/gqlitedb/src/functions/path.rs +1 -1
  11. data/ext/gqlitedb/src/functions/scalar.rs +23 -0
  12. data/ext/gqlitedb/src/functions.rs +8 -0
  13. data/ext/gqlitedb/src/interpreter/evaluators.rs +10 -10
  14. data/ext/gqlitedb/src/interpreter/instructions.rs +3 -3
  15. data/ext/gqlitedb/src/lib.rs +1 -3
  16. data/ext/gqlitedb/src/parser/ast.rs +1 -0
  17. data/ext/gqlitedb/src/parser/gql.pest +3 -1
  18. data/ext/gqlitedb/src/parser/parser_impl.rs +8 -0
  19. data/ext/gqlitedb/src/prelude.rs +3 -0
  20. data/ext/gqlitedb/src/store/{pgql.rs → pgrx.rs} +2 -0
  21. data/ext/gqlitedb/src/store/postgres.rs +0 -0
  22. data/ext/gqlitedb/src/store/sqlbase/sqlmetadata.rs +117 -0
  23. data/ext/gqlitedb/src/store/sqlbase/sqlqueries.rs +62 -0
  24. data/ext/gqlitedb/src/store/sqlbase/sqlstore.rs +55 -0
  25. data/ext/gqlitedb/src/store/sqlbase/sqlvalue.rs +189 -0
  26. data/ext/gqlitedb/src/store/sqlbase.rs +456 -0
  27. data/ext/gqlitedb/src/store/sqlite.rs +271 -573
  28. data/ext/gqlitedb/src/store.rs +7 -5
  29. data/ext/gqlitedb/src/tests/templates/programs.rs +10 -10
  30. data/ext/gqlitedb/src/utils.rs +25 -0
  31. data/ext/gqlitedb/src/value/compare.rs +6 -0
  32. data/ext/gqlitedb/src/value.rs +18 -2
  33. data/ext/gqlitedb/templates/sql/sqlite/edge_select.sql +18 -18
  34. data/ext/gqlitedb/templates/sql/sqlite/edge_update.sql +3 -3
  35. data/ext/gqlitedb/templates/sql/sqlite/node_select.sql +6 -6
  36. data/ext/gqlitedb/templates/sql/sqlite/node_update.sql +3 -3
  37. data/ext/gqliterb/src/lib.rs +30 -2
  38. data/ext/graphcore/Cargo.toml +3 -2
  39. data/ext/graphcore/src/error.rs +2 -0
  40. data/ext/graphcore/src/lib.rs +2 -1
  41. data/ext/graphcore/src/prelude.rs +1 -1
  42. data/ext/graphcore/src/table.rs +1 -1
  43. data/ext/graphcore/src/timestamp.rs +104 -0
  44. data/ext/graphcore/src/value.rs +106 -23
  45. metadata +10 -7
  46. data/ext/gqlitedb/gqlite_bench_data/README.MD +0 -6
  47. data/ext/gqlitedb/gqlite_bench_data/scripts/generate_smaller_pokec.rb +0 -85
  48. data/ext/gqlitedb/gqlite_bench_data/scripts/to_efficient_pokec.rb +0 -34
  49. data/ext/graphcore/release.toml +0 -1
@@ -1,15 +1,17 @@
1
- use std::{cell::RefCell, collections::HashSet, path::PathBuf};
1
+ use std::{cell::RefCell, path::PathBuf};
2
2
 
3
- use askama::Template;
4
3
  use ccutils::pool::{self, Pool};
5
- use rusqlite::{named_params, types::FromSql, OptionalExtension, ToSql};
6
- use serde::{Deserialize, Serialize};
7
4
 
8
5
  use crate::{
9
6
  prelude::*,
10
- store::{EdgeResult, TransactionBoxable},
7
+ store::{sqlbase::SqlValue, TransactionBoxable},
11
8
  };
12
9
 
10
+ ccutils::assert_impl_all!(Store: Sync, Send);
11
+
12
+ use askama::Template;
13
+ use rusqlite::named_params;
14
+
13
15
  // _____ _____ ____ _
14
16
  // |_ _|__ | ___| __ ___ _ __ ___ / ___| __ _| |
15
17
  // | |/ _ \| |_ | '__/ _ \| '_ ` _ \\___ \ / _` | |
@@ -17,31 +19,38 @@ use crate::{
17
19
  // |_|\___/|_| |_| \___/|_| |_| |_|____/ \__, |_|
18
20
  // |_|
19
21
 
20
- ccutils::alias!(PersistentKey, graph::Key, derive: Debug, PartialEq);
21
-
22
- impl rusqlite::ToSql for PersistentKey
22
+ impl<'a> rusqlite::ToSql for SqlValue<'a>
23
23
  {
24
24
  fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>>
25
25
  {
26
- Ok(rusqlite::types::ToSqlOutput::Owned(
27
- rusqlite::types::Value::Blob(self.uuid().to_be_bytes().into()),
28
- ))
29
- }
30
- }
31
-
32
- impl rusqlite::types::FromSql for PersistentKey
33
- {
34
- fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self>
35
- {
36
- Ok(u128::from_be_bytes(<[u8; 16]>::column_result(value)?).into())
26
+ match self
27
+ {
28
+ SqlValue::String(string) => string.to_sql(),
29
+ SqlValue::StringRef(string) => string.to_sql(),
30
+ SqlValue::Key(key) => Ok(rusqlite::types::ToSqlOutput::Owned(
31
+ rusqlite::types::Value::Blob(key.uuid().to_be_bytes().into()),
32
+ )),
33
+ SqlValue::Blob(data) => data.to_sql(),
34
+ SqlValue::Text(text) => std::str::from_utf8(text).unwrap().to_sql(),
35
+ SqlValue::Float(fl) => fl.to_sql(),
36
+ SqlValue::Integer(it) => it.to_sql(),
37
+ SqlValue::Null => rusqlite::types::Null.to_sql(),
38
+ }
37
39
  }
38
40
  }
39
41
 
40
- impl From<u128> for PersistentKey
42
+ impl<'a> sqlbase::Row for rusqlite::Row<'a>
41
43
  {
42
- fn from(value: u128) -> Self
44
+ fn get_value(&self, index: usize) -> Result<SqlValue<'_>>
43
45
  {
44
- Self(graph::Key::new(value))
46
+ match self.get_ref(index)?
47
+ {
48
+ rusqlite::types::ValueRef::Blob(blob) => Ok(SqlValue::Blob(blob)),
49
+ rusqlite::types::ValueRef::Integer(int) => Ok(SqlValue::Integer(int)),
50
+ rusqlite::types::ValueRef::Null => Ok(SqlValue::Null),
51
+ rusqlite::types::ValueRef::Real(f) => Ok(SqlValue::Float(f)),
52
+ rusqlite::types::ValueRef::Text(txt) => Ok(SqlValue::Text(txt)),
53
+ }
45
54
  }
46
55
  }
47
56
 
@@ -186,9 +195,9 @@ mod templates
186
195
  pub(super) struct NodeSelect<'a>
187
196
  {
188
197
  pub graph_name: &'a str,
189
- pub has_keys: bool,
190
- pub has_labels: bool,
191
- pub has_properties: bool,
198
+ pub keys_var: &'a Option<usize>,
199
+ pub labels_var: &'a Option<usize>,
200
+ pub properties_var: &'a Option<usize>,
192
201
  }
193
202
  // Edge queries
194
203
  #[derive(Template)]
@@ -231,15 +240,15 @@ mod templates
231
240
  pub graph_name: &'a str,
232
241
  pub is_undirected: bool,
233
242
  pub table_suffix: &'a str,
234
- pub has_edge_keys: bool,
235
- pub has_edge_labels: bool,
236
- pub has_edge_properties: bool,
237
- pub has_n_left_keys: bool,
238
- pub has_n_left_labels: bool,
239
- pub has_n_left_properties: bool,
240
- pub has_n_right_keys: bool,
241
- pub has_n_right_labels: bool,
242
- pub has_n_right_properties: bool,
243
+ pub edge_keys_var: Option<usize>,
244
+ pub edge_labels_var: Option<usize>,
245
+ pub edge_properties_var: Option<usize>,
246
+ pub left_keys_var: Option<usize>,
247
+ pub left_labels_var: Option<usize>,
248
+ pub left_properties_var: Option<usize>,
249
+ pub right_keys_var: Option<usize>,
250
+ pub right_labels_var: Option<usize>,
251
+ pub right_properties_var: Option<usize>,
243
252
  }
244
253
  #[derive(Template)]
245
254
  #[template(path = "sql/sqlite/call_stats.sql", escape = "none")]
@@ -257,16 +266,10 @@ mod templates
257
266
 
258
267
  type TransactionBox = store::TransactionBox<ReadTransaction, WriteTransaction>;
259
268
 
260
- fn hex(key: impl Into<graph::Key>) -> String
261
- {
262
- format!("{:032X}", key.into().uuid())
263
- }
264
-
265
269
  pub(crate) struct Store
266
270
  {
267
271
  connection: Pool<rusqlite::Connection, ErrorType>,
268
272
  }
269
-
270
273
  ccutils::assert_impl_all!(Store: Sync, Send);
271
274
 
272
275
  impl Store
@@ -299,49 +302,6 @@ impl Store
299
302
  s.initialise()?;
300
303
  Ok(s)
301
304
  }
302
- fn initialise(&self) -> Result<()>
303
- {
304
- use store::Store;
305
- let mut tx = self.begin_write()?;
306
- if self.check_if_table_exists(&mut tx, "gqlite_metadata")?
307
- {
308
- // gqlite version 1.1 incorrectly use ' instead of " in the version number
309
- let version_raw = self
310
- .get_metadata_value::<String>(&mut tx, "version")?
311
- .replace("'", "\"");
312
- let version: utils::Version = serde_json::from_str(&version_raw)?;
313
- if version.major != consts::GQLITE_VERSION.major
314
- || version.minor != consts::GQLITE_VERSION.minor
315
- {
316
- self.upgrade_database(&mut tx, version)?;
317
- }
318
- }
319
- else if !self.check_if_table_exists(&mut tx, "gqlite_metadata")?
320
- && self.check_if_table_exists(&mut tx, "gqlite_default_nodes")?
321
- {
322
- // 1.0 didn't have the metadata table
323
- self.upgrade_database(
324
- &mut tx,
325
- utils::Version {
326
- major: 1,
327
- minor: 0,
328
- patch: 0,
329
- },
330
- )?;
331
- }
332
- else
333
- {
334
- tx.get_connection().execute(
335
- include_str!("../../templates/sql/sqlite/metadata_create_table.sql"),
336
- (),
337
- )?;
338
- self.set_metadata_value_json(&mut tx, "graphs", &Vec::<String>::new())?;
339
- self.create_graph(&mut tx, "default", true)?;
340
- }
341
- self.set_metadata_value_json(&mut tx, "version", &consts::GQLITE_VERSION)?;
342
- tx.close()?;
343
- Ok(())
344
- }
345
305
  fn upgrade_database(&self, transaction: &mut TransactionBox, from: utils::Version) -> Result<()>
346
306
  {
347
307
  use crate::store::Store;
@@ -405,100 +365,68 @@ impl Store
405
365
  |row| Ok(row.get::<_, i32>(0)? == 1),
406
366
  )?)
407
367
  }
408
- pub(crate) fn get_metadata_value<T: FromSql>(
409
- &self,
410
- transaction: &mut TransactionBox,
411
- key: impl Into<String>,
412
- ) -> Result<T>
413
- {
414
- Ok(transaction.get_connection().query_row(
415
- include_str!("../../templates/sql/sqlite/metadata_get.sql"),
416
- named_params! {":name": key.into()},
417
- |row| row.get(0),
418
- )?)
419
- }
420
- #[allow(dead_code)]
421
- pub(crate) fn get_metadata_value_or_else<T: FromSql>(
422
- &self,
423
- transaction: &mut TransactionBox,
424
- key: impl Into<String>,
425
- f: impl FnOnce() -> T,
426
- ) -> Result<T>
427
- {
428
- Ok(
429
- transaction
430
- .get_connection()
431
- .query_row(
432
- include_str!("../../templates/sql/sqlite/metadata_get.sql"),
433
- named_params! { ":name": key.into()},
434
- |row| row.get(0),
435
- )
436
- .optional()
437
- .map(|v| v.unwrap_or_else(f))?,
438
- )
439
- }
440
- pub(crate) fn set_metadata_value(
441
- &self,
442
- transaction: &mut TransactionBox,
443
- key: impl Into<String>,
444
- value: &impl ToSql,
445
- ) -> Result<()>
446
- {
447
- transaction.get_connection().execute(
448
- include_str!("../../templates/sql/sqlite/metadata_set.sql"),
449
- named_params! { ":name": key.into(), ":value": value },
450
- )?;
451
- Ok(())
452
- }
368
+ }
453
369
 
454
- pub(crate) fn get_metadata_value_json<T: for<'a> Deserialize<'a>>(
455
- &self,
456
- transaction: &mut TransactionBox,
457
- key: impl Into<String>,
458
- ) -> Result<T>
459
- {
460
- Ok(serde_json::from_str(
461
- &self.get_metadata_value::<String>(transaction, key)?,
462
- )?)
463
- }
464
- #[allow(dead_code)]
465
- pub(crate) fn get_metadata_value_json_or_else<T: for<'a> Deserialize<'a>>(
466
- &self,
467
- transaction: &mut TransactionBox,
468
- key: impl Into<String>,
469
- f: impl FnOnce() -> T,
470
- ) -> Result<T>
370
+ impl super::sqlbase::SqlMetaDataQueries for Store
371
+ {
372
+ fn metadata_get_query() -> Result<String>
471
373
  {
472
- Ok(
473
- transaction
474
- .get_connection()
475
- .query_row(
476
- include_str!("../../templates/sql/sqlite/metadata_get.sql"),
477
- named_params! {":name": key.into()},
478
- |row| row.get::<_, String>(0),
479
- )
480
- .optional()
481
- .map(|v| {
482
- v.map(|x| serde_json::from_str(&x))
483
- .unwrap_or_else(|| Ok(f()))
484
- })??,
485
- )
374
+ Ok(include_str!("../../templates/sql/sqlite/metadata_get.sql").to_string())
486
375
  }
487
- pub(crate) fn set_metadata_value_json(
488
- &self,
489
- transaction: &mut TransactionBox,
490
- key: impl Into<String>,
491
- value: &impl Serialize,
492
- ) -> Result<()>
376
+ fn metadata_set_query() -> Result<String>
493
377
  {
494
- self.set_metadata_value(transaction, key, &serde_json::to_string(value)?)
378
+ Ok(include_str!("../../templates/sql/sqlite/metadata_set.sql").to_string())
495
379
  }
496
380
  }
497
381
 
498
- impl store::Store for Store
382
+ impl super::sqlbase::SqlStore for Store
499
383
  {
500
384
  type TransactionBox = TransactionBox;
501
- fn begin_read(&self) -> Result<Self::TransactionBox>
385
+ type Row<'a> = rusqlite::Row<'a>;
386
+ fn initialise(&self) -> Result<()>
387
+ {
388
+ use store::Store;
389
+ let mut tx = self.begin_sql_write()?;
390
+ if self.check_if_table_exists(&mut tx, "gqlite_metadata")?
391
+ {
392
+ // gqlite version 1.1 incorrectly use ' instead of " in the version number
393
+ let version_raw = self
394
+ .get_metadata_value::<String>(&mut tx, "version")?
395
+ .replace("'", "\"");
396
+ let version: utils::Version = serde_json::from_str(&version_raw)?;
397
+ if version.major != consts::GQLITE_VERSION.major
398
+ || version.minor != consts::GQLITE_VERSION.minor
399
+ {
400
+ self.upgrade_database(&mut tx, version)?;
401
+ }
402
+ }
403
+ else if !self.check_if_table_exists(&mut tx, "gqlite_metadata")?
404
+ && self.check_if_table_exists(&mut tx, "gqlite_default_nodes")?
405
+ {
406
+ // 1.0 didn't have the metadata table
407
+ self.upgrade_database(
408
+ &mut tx,
409
+ utils::Version {
410
+ major: 1,
411
+ minor: 0,
412
+ patch: 0,
413
+ },
414
+ )?;
415
+ }
416
+ else
417
+ {
418
+ tx.get_connection().execute(
419
+ include_str!("../../templates/sql/sqlite/metadata_create_table.sql"),
420
+ (),
421
+ )?;
422
+ self.set_metadata_value_json(&mut tx, "graphs", &Vec::<String>::new())?;
423
+ self.create_graph(&mut tx, "default", true)?;
424
+ }
425
+ self.set_metadata_value_json(&mut tx, "version", &consts::GQLITE_VERSION)?;
426
+ tx.close()?;
427
+ Ok(())
428
+ }
429
+ fn begin_sql_read(&self) -> Result<Self::TransactionBox>
502
430
  {
503
431
  let connection = self.connection.get()?;
504
432
  connection.execute("BEGIN", ())?;
@@ -509,7 +437,7 @@ impl store::Store for Store
509
437
  },
510
438
  }))
511
439
  }
512
- fn begin_write(&self) -> Result<Self::TransactionBox>
440
+ fn begin_sql_write(&self) -> Result<Self::TransactionBox>
513
441
  {
514
442
  let connection = self.connection.get()?;
515
443
  connection.execute("BEGIN", ())?;
@@ -520,475 +448,245 @@ impl store::Store for Store
520
448
  },
521
449
  }))
522
450
  }
523
- fn graphs_list(&self, transaction: &mut Self::TransactionBox) -> Result<Vec<String>>
451
+
452
+ fn execute_batch(
453
+ &self,
454
+ transaction: &mut Self::TransactionBox,
455
+ sql: impl AsRef<str>,
456
+ ) -> Result<()>
524
457
  {
525
- self.get_metadata_value_json(transaction, "graphs")
458
+ Ok(transaction.get_connection().execute_batch(sql.as_ref())?)
526
459
  }
527
- fn create_graph(
460
+ fn execute<'a>(
528
461
  &self,
529
462
  transaction: &mut Self::TransactionBox,
530
- graph_name: impl AsRef<str>,
531
- ignore_if_exists: bool,
463
+ sql: impl AsRef<str>,
464
+ bindings: impl sqlbase::IntoBindings<'a>,
532
465
  ) -> Result<()>
533
466
  {
534
- let graph_name = graph_name.as_ref();
535
- let mut graphs_list = self.graphs_list(transaction)?;
536
- if graphs_list.iter().any(|s| s == graph_name)
467
+ transaction.get_connection().execute(
468
+ sql.as_ref(),
469
+ rusqlite::params_from_iter(bindings.into_bindings_iter()),
470
+ )?;
471
+ Ok(())
472
+ }
473
+ fn query_rows<'a, 'tx>(
474
+ &self,
475
+ transaction: &'tx mut Self::TransactionBox,
476
+ sql: impl AsRef<str>,
477
+ bindings: impl sqlbase::IntoBindings<'a>,
478
+ mut f: impl for<'b> FnMut(&Self::Row<'b>) -> Result<()>,
479
+ ) -> Result<()>
480
+ {
481
+ let mut statement = transaction.get_connection().prepare(sql.as_ref())?;
482
+ let mut rows = statement.query(rusqlite::params_from_iter(bindings.into_bindings_iter()))?;
483
+ loop
537
484
  {
538
- if ignore_if_exists
539
- {
540
- return Ok(());
541
- }
542
- else
485
+ let row = rows.next()?;
486
+ match row
543
487
  {
544
- return Err(
545
- StoreError::DuplicatedGraph {
546
- graph_name: graph_name.to_owned(),
547
- }
548
- .into(),
549
- );
488
+ Some(row) => f(row)?,
489
+ None => break,
550
490
  }
551
491
  }
552
- transaction
553
- .get_connection()
554
- .execute_batch(templates::GraphCreate { graph_name }.render()?.as_str())?;
555
- graphs_list.push(graph_name.to_owned());
556
- self.set_metadata_value_json(transaction, "graphs", &graphs_list)?;
557
492
  Ok(())
558
493
  }
559
- fn drop_graph(
494
+ fn query_row<'a, 'tx, T>(
560
495
  &self,
561
- transaction: &mut Self::TransactionBox,
562
- graph_name: impl AsRef<str>,
563
- if_exists: bool,
564
- ) -> Result<()>
496
+ transaction: &'tx mut Self::TransactionBox,
497
+ sql: impl AsRef<str>,
498
+ bindings: impl sqlbase::IntoBindings<'a>,
499
+ f: impl for<'b> FnOnce(&Self::Row<'b>) -> Result<T>,
500
+ ) -> Result<T>
565
501
  {
566
- let graph_name = graph_name.as_ref();
567
- let mut graphs_list = self.graphs_list(transaction)?;
568
- if graphs_list.iter().any(|s| s == graph_name)
569
- {
570
- transaction
571
- .get_connection()
572
- .execute_batch(templates::GraphDelete { graph_name }.render()?.as_str())?;
573
- graphs_list.retain(|x| x != graph_name);
574
- self.set_metadata_value_json(transaction, "graphs", &graphs_list)?;
502
+ transaction.get_connection().query_row(
503
+ sql.as_ref(),
504
+ rusqlite::params_from_iter(bindings.into_bindings_iter()),
505
+ |row| Ok(f(row)),
506
+ )?
507
+ }
508
+ }
575
509
 
576
- Ok(())
577
- }
578
- else if if_exists
579
- {
580
- Ok(())
581
- }
582
- else
583
- {
584
- Err(
585
- StoreError::UnknownGraph {
586
- graph_name: graph_name.to_owned(),
587
- }
588
- .into(),
589
- )
590
- }
510
+ impl super::sqlbase::SqlQueries for Store
511
+ {
512
+ fn graph_create_query(graph_name: impl AsRef<str>) -> Result<String>
513
+ {
514
+ Ok(
515
+ templates::GraphCreate {
516
+ graph_name: graph_name.as_ref(),
517
+ }
518
+ .render()?,
519
+ )
591
520
  }
592
- fn create_nodes<'a, T: IntoIterator<Item = &'a crate::graph::Node>>(
593
- &self,
594
- transaction: &mut Self::TransactionBox,
521
+ fn graph_delete(graph_name: impl AsRef<str>) -> Result<String>
522
+ {
523
+ Ok(
524
+ templates::GraphDelete {
525
+ graph_name: graph_name.as_ref(),
526
+ }
527
+ .render()?,
528
+ )
529
+ }
530
+ fn node_create_query(graph_name: impl AsRef<str>) -> Result<String>
531
+ {
532
+ Ok(
533
+ templates::NodeCreate {
534
+ graph_name: graph_name.as_ref(),
535
+ }
536
+ .render()?,
537
+ )
538
+ }
539
+ fn edge_delete_by_nodes_query(
595
540
  graph_name: impl AsRef<str>,
596
- nodes_iter: T,
597
- ) -> Result<()>
541
+ keys: impl AsRef<Vec<String>>,
542
+ ) -> Result<String>
598
543
  {
599
- for x in nodes_iter
600
- {
601
- transaction.get_connection().execute(
602
- templates::NodeCreate {
603
- graph_name: graph_name.as_ref(),
604
- }
605
- .render()?
606
- .as_str(),
607
- (
608
- PersistentKey(x.key()),
609
- serde_json::to_string(x.labels())?,
610
- serde_json::to_string(x.properties())?,
611
- ),
612
- )?;
613
- }
614
- Ok(())
544
+ Ok(
545
+ templates::EdgeDeleteByNodes {
546
+ graph_name: graph_name.as_ref(),
547
+ keys: keys.as_ref(),
548
+ }
549
+ .render()?,
550
+ )
615
551
  }
616
- fn delete_nodes(
617
- &self,
618
- transaction: &mut Self::TransactionBox,
552
+
553
+ fn edge_count_for_nodes_query(
619
554
  graph_name: impl AsRef<str>,
620
- query: store::SelectNodeQuery,
621
- detach: bool,
622
- ) -> Result<()>
555
+ keys: impl AsRef<Vec<String>>,
556
+ ) -> Result<String>
623
557
  {
624
- let graph_name = graph_name.as_ref();
625
- let nodes = self.select_nodes(transaction, graph_name, query)?;
626
- let nodes_keys: Vec<String> = nodes.into_iter().map(|x| hex(x.key())).collect();
627
- if detach
628
- {
629
- transaction.get_connection().execute(
630
- templates::EdgeDeleteByNodes {
631
- graph_name,
632
- keys: &nodes_keys,
633
- }
634
- .render()?
635
- .as_str(),
636
- (),
637
- )?;
638
- }
639
- else
640
- {
641
- let count = transaction.get_connection().query_row(
642
- templates::EdgeCountForNode {
643
- graph_name,
644
- keys: &nodes_keys,
645
- }
646
- .render()?
647
- .as_str(),
648
- (),
649
- |row| row.get::<_, usize>(0),
650
- )?;
651
- if count > 0
652
- {
653
- return Err(error::RunTimeError::DeleteConnectedNode.into());
558
+ Ok(
559
+ templates::EdgeCountForNode {
560
+ graph_name: graph_name.as_ref(),
561
+ keys: keys.as_ref(),
654
562
  }
655
- }
656
- transaction.get_connection().execute(
563
+ .render()?,
564
+ )
565
+ }
566
+
567
+ fn node_delete_query(graph_name: impl AsRef<str>, keys: impl AsRef<Vec<String>>)
568
+ -> Result<String>
569
+ {
570
+ Ok(
657
571
  templates::NodeDelete {
658
- graph_name,
659
- keys: &nodes_keys,
572
+ graph_name: graph_name.as_ref(),
573
+ keys: keys.as_ref(),
660
574
  }
661
- .render()?
662
- .as_str(),
663
- (),
664
- )?;
665
- Ok(())
575
+ .render()?,
576
+ )
666
577
  }
667
- fn update_node(
668
- &self,
669
- transaction: &mut Self::TransactionBox,
670
- graph_name: impl AsRef<str>,
671
- node: &crate::graph::Node,
672
- ) -> Result<()>
578
+
579
+ fn node_update_query(graph_name: impl AsRef<str>) -> Result<String>
673
580
  {
674
- transaction.get_connection().execute(
581
+ Ok(
675
582
  templates::NodeUpdate {
676
583
  graph_name: graph_name.as_ref(),
677
584
  }
678
- .render()?
679
- .as_str(),
680
- named_params! {
681
- ":key": PersistentKey(node.key()),
682
- ":labels": serde_json::to_string(node.labels())?,
683
- ":properties": serde_json::to_string(node.properties())?
684
- },
685
- )?;
686
- Ok(())
585
+ .render()?,
586
+ )
687
587
  }
688
- fn select_nodes(
689
- &self,
690
- transaction: &mut Self::TransactionBox,
588
+
589
+ fn node_select_query(
691
590
  graph_name: impl AsRef<str>,
692
- query: store::SelectNodeQuery,
693
- ) -> Result<Vec<crate::graph::Node>>
591
+ keys_var: Option<usize>,
592
+ labels_var: Option<usize>,
593
+ properties_var: Option<usize>,
594
+ ) -> Result<String>
694
595
  {
695
- let mut prepared_query = transaction.get_connection().prepare(
596
+ Ok(
696
597
  templates::NodeSelect {
697
598
  graph_name: graph_name.as_ref(),
698
- has_keys: query.keys.is_some(),
699
- has_labels: query.labels.is_some(),
700
- has_properties: query.properties.is_some(),
599
+ keys_var: &keys_var,
600
+ labels_var: &labels_var,
601
+ properties_var: &properties_var,
701
602
  }
702
- .render()?
703
- .as_str(),
704
- )?;
705
- let mut bindings = Vec::<(&'static str, String)>::new();
706
- if let Some(keys) = query.keys
707
- {
708
- let hex_keys = keys.iter().map(|key| hex(*key)).collect::<Vec<_>>();
709
- bindings.push((":keys", serde_json::to_string(&hex_keys)?));
710
- }
711
- if let Some(labels) = query.labels
712
- {
713
- bindings.push((":labels", serde_json::to_string(&labels)?));
714
- }
715
- if let Some(properties) = query.properties
716
- {
717
- bindings.push((":properties", serde_json::to_string(&properties)?));
718
- }
719
- let mut it = prepared_query.query(
720
- bindings
721
- .iter()
722
- .map(|(k, v)| (*k, v as &dyn rusqlite::ToSql))
723
- .collect::<Vec<_>>()
724
- .as_slice(),
725
- )?;
726
- let mut nodes: Vec<graph::Node> = Default::default();
727
- while let Some(row) = it.next()?
728
- {
729
- let key: graph::Key = row.get::<_, PersistentKey>(0)?.into();
730
- let labels = serde_json::from_str(&row.get::<_, String>(1)?)?;
731
- let properties = serde_json::from_str(&row.get::<_, String>(2)?)?;
732
- nodes.push(graph::Node::new(key, labels, properties));
733
- }
734
- Ok(nodes)
603
+ .render()?,
604
+ )
735
605
  }
736
- fn create_edges<'a, T: IntoIterator<Item = &'a crate::graph::SinglePath>>(
737
- &self,
738
- transaction: &mut Self::TransactionBox,
739
- graph_name: impl AsRef<str>,
740
- edges_iter: T,
741
- ) -> Result<()>
606
+
607
+ fn edge_create_query(graph_name: impl AsRef<str>) -> Result<String>
742
608
  {
743
- for x in edges_iter
744
- {
745
- transaction.get_connection().execute(
746
- templates::EdgeCreate {
747
- graph_name: graph_name.as_ref(),
748
- }
749
- .render()?
750
- .as_str(),
751
- (
752
- PersistentKey(x.key()),
753
- serde_json::to_string(x.labels())?,
754
- serde_json::to_string(x.properties())?,
755
- PersistentKey(x.source().key()),
756
- PersistentKey(x.destination().key()),
757
- ),
758
- )?;
759
- }
760
- Ok(())
609
+ Ok(
610
+ templates::EdgeCreate {
611
+ graph_name: graph_name.as_ref(),
612
+ }
613
+ .render()?,
614
+ )
761
615
  }
762
- fn delete_edges(
763
- &self,
764
- transaction: &mut Self::TransactionBox,
765
- graph_name: impl AsRef<str>,
766
- query: store::SelectEdgeQuery,
767
- directivity: crate::graph::EdgeDirectivity,
768
- ) -> Result<()>
616
+ fn edge_delete_query(graph_name: impl AsRef<str>, keys: impl AsRef<Vec<String>>)
617
+ -> Result<String>
769
618
  {
770
- let graph_name = graph_name.as_ref();
771
- let edges = self.select_edges(transaction, graph_name, query, directivity)?;
772
- let edges_keys: Vec<String> = edges.into_iter().map(|x| hex(x.path.key())).collect();
773
- transaction.get_connection().execute(
619
+ Ok(
774
620
  templates::EdgeDelete {
775
- graph_name,
776
- keys: &edges_keys,
621
+ graph_name: graph_name.as_ref(),
622
+ keys: keys.as_ref(),
777
623
  }
778
- .render()?
779
- .as_str(),
780
- (),
781
- )?;
782
- Ok(())
624
+ .render()?,
625
+ )
783
626
  }
784
- fn update_edge(
785
- &self,
786
- transaction: &mut Self::TransactionBox,
787
- graph_name: impl AsRef<str>,
788
- edge: &crate::graph::Edge,
789
- ) -> Result<()>
627
+ fn edge_update_query(graph_name: impl AsRef<str>) -> Result<String>
790
628
  {
791
- transaction.get_connection().execute(
629
+ Ok(
792
630
  templates::EdgeUpdate {
793
631
  graph_name: graph_name.as_ref(),
794
632
  }
795
- .render()?
796
- .as_str(),
797
- named_params! {
798
- ":key": PersistentKey(edge.key().to_owned()),
799
- ":labels": serde_json::to_string(edge.labels())?,
800
- ":properties": serde_json::to_string(edge.properties())?
801
- },
802
- )?;
803
- Ok(())
633
+ .render()?,
634
+ )
804
635
  }
805
- fn select_edges(
806
- &self,
807
- transaction: &mut Self::TransactionBox,
636
+ fn edge_select_query(
808
637
  graph_name: impl AsRef<str>,
809
- query: store::SelectEdgeQuery,
810
- directivity: crate::graph::EdgeDirectivity,
811
- ) -> Result<Vec<store::EdgeResult>>
638
+ is_undirected: bool,
639
+ table_suffix: impl AsRef<str>,
640
+ edge_keys_var: Option<usize>,
641
+ edge_labels_var: Option<usize>,
642
+ edge_properties_var: Option<usize>,
643
+ left_keys_var: Option<usize>,
644
+ left_labels_var: Option<usize>,
645
+ left_properties_var: Option<usize>,
646
+ right_keys_var: Option<usize>,
647
+ right_labels_var: Option<usize>,
648
+ right_properties_var: Option<usize>,
649
+ ) -> Result<String>
812
650
  {
813
- if query.source.is_select_none() || query.destination.is_select_none()
814
- {
815
- return Ok(Default::default());
816
- }
817
- let (is_undirected, table_suffix) = match directivity
818
- {
819
- graph::EdgeDirectivity::Directed => (false, ""),
820
- graph::EdgeDirectivity::Undirected => (true, "_undirected"),
821
- };
822
- let mut prepared_query = transaction.get_connection().prepare(
651
+ Ok(
823
652
  templates::EdgeSelect {
824
653
  graph_name: graph_name.as_ref(),
825
654
  is_undirected,
826
- table_suffix,
827
- has_edge_keys: query.keys.is_some(),
828
- has_edge_labels: query.labels.is_some(),
829
- has_edge_properties: query.properties.is_some(),
830
- has_n_left_keys: query.source.keys.is_some(),
831
- has_n_left_labels: query.source.labels.is_some(),
832
- has_n_left_properties: query.source.properties.is_some(),
833
- has_n_right_keys: query.destination.keys.is_some(),
834
- has_n_right_labels: query.destination.labels.is_some(),
835
- has_n_right_properties: query.destination.properties.is_some(),
836
- }
837
- .render()?
838
- .as_str(),
839
- )?;
840
-
841
- let mut bindings = Vec::<(&'static str, String)>::new();
842
-
843
- // Edge queries
844
- if let Some(keys) = query.keys
845
- {
846
- let hex_keys = keys.iter().map(|key| hex(*key)).collect::<Vec<_>>();
847
- bindings.push((":edge_keys", serde_json::to_string(&hex_keys)?));
848
- }
849
- if let Some(labels) = query.labels
850
- {
851
- bindings.push((":edge_labels", serde_json::to_string(&labels)?));
852
- }
853
- if let Some(properties) = query.properties
854
- {
855
- bindings.push((":edge_properties", serde_json::to_string(&properties)?));
856
- }
857
-
858
- // Left queries
859
- if let Some(keys) = query.source.keys
860
- {
861
- let hex_keys = keys.iter().map(|key| hex(*key)).collect::<Vec<_>>();
862
- bindings.push((":n_left_keys", serde_json::to_string(&hex_keys)?));
863
- }
864
- if let Some(labels) = query.source.labels
865
- {
866
- bindings.push((":n_left_labels", serde_json::to_string(&labels)?));
867
- }
868
- if let Some(properties) = query.source.properties
869
- {
870
- bindings.push((":n_left_properties", serde_json::to_string(&properties)?));
871
- }
872
-
873
- // Right queries
874
- if let Some(keys) = query.destination.keys
875
- {
876
- let hex_keys = keys.iter().map(|key| hex(*key)).collect::<Vec<_>>();
877
- bindings.push((":n_right_keys", serde_json::to_string(&hex_keys)?));
878
- }
879
- if let Some(labels) = query.destination.labels
880
- {
881
- bindings.push((":n_right_labels", serde_json::to_string(&labels)?));
882
- }
883
- if let Some(properties) = query.destination.properties
884
- {
885
- bindings.push((":n_right_properties", serde_json::to_string(&properties)?));
886
- }
887
-
888
- // Execute query
889
- let mut it = prepared_query.query(
890
- bindings
891
- .iter()
892
- .map(|(k, v)| (*k, v as &dyn rusqlite::ToSql))
893
- .collect::<Vec<_>>()
894
- .as_slice(),
895
- )?;
896
-
897
- let mut edges: Vec<EdgeResult> = Default::default();
898
- let mut edges_keys: HashSet<u128> = Default::default();
899
- while let Some(row) = it.next()?
900
- {
901
- let edge_key: PersistentKey = row.get(0)?;
902
- let n_left_key: PersistentKey = row.get(4)?;
903
- let n_right_key: PersistentKey = row.get(7)?;
904
-
905
- // This ensure that if (a)-[]->(a) the edge is returned only once. But matching [a]-[]-[b] return the edge twice.
906
- if n_left_key == n_right_key && edges_keys.contains(&edge_key.uuid())
907
- {
908
- continue;
655
+ table_suffix: table_suffix.as_ref(),
656
+ edge_keys_var,
657
+ edge_labels_var,
658
+ edge_properties_var,
659
+ left_keys_var,
660
+ left_labels_var,
661
+ left_properties_var,
662
+ right_keys_var,
663
+ right_labels_var,
664
+ right_properties_var,
909
665
  }
910
- edges_keys.insert(edge_key.uuid());
911
- let edge_labels = serde_json::from_str(&row.get::<_, String>(1)?)?;
912
- let edge_properties = serde_json::from_str(&row.get::<_, String>(2)?)?;
913
-
914
- let n_left_labels = serde_json::from_str(&row.get::<_, String>(5)?)?;
915
- let n_left_properties = serde_json::from_str(&row.get::<_, String>(6)?)?;
916
-
917
- let n_right_labels = serde_json::from_str(&row.get::<_, String>(8)?)?;
918
- let n_right_properties = serde_json::from_str(&row.get::<_, String>(9)?)?;
919
-
920
- let source = graph::Node::new(n_left_key.into(), n_left_labels, n_left_properties);
921
- let destination = graph::Node::new(n_right_key.into(), n_right_labels, n_right_properties);
922
- let reversed = row.get::<_, u32>(3)? == 1;
923
- let (source, destination) = if reversed
924
- {
925
- (destination, source)
926
- }
927
- else
928
- {
929
- (source, destination)
930
- };
931
-
932
- edges.push(EdgeResult {
933
- path: graph::Path::new(
934
- edge_key.into(),
935
- source,
936
- edge_labels,
937
- edge_properties,
938
- destination,
939
- ),
940
- reversed,
941
- });
942
- }
943
- Ok(edges)
666
+ .render()?,
667
+ )
944
668
  }
945
- fn compute_statistics(&self, transaction: &mut Self::TransactionBox)
946
- -> Result<store::Statistics>
669
+ fn compute_statistics_query(graph_name: impl AsRef<str>) -> Result<String>
947
670
  {
948
- let (nodes_count, edges_count, labels_nodes_count, properties_count) =
949
- transaction.get_connection().query_row(
950
- templates::CallStats {
951
- graph_name: "default",
952
- }
953
- .render()?
954
- .as_str(),
955
- (),
956
- |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)),
957
- )?;
958
- Ok(store::Statistics {
959
- nodes_count,
960
- edges_count,
961
- labels_nodes_count,
962
- properties_count,
963
- })
671
+ Ok(
672
+ templates::CallStats {
673
+ graph_name: graph_name.as_ref(),
674
+ }
675
+ .render()?,
676
+ )
964
677
  }
965
678
  }
966
679
 
967
680
  #[cfg(test)]
968
681
  mod tests
969
682
  {
970
- use crate::{
971
- prelude::*,
972
- store::{Store, TransactionBoxable},
973
- };
974
- #[test]
975
- fn test_hex()
976
- {
977
- assert_eq!(
978
- super::hex(graph::Key::new(18580062510968287067562660977870108180)),
979
- "0DFA63CEE7484B0DBFC407697F77F614"
980
- );
981
- assert_eq!(
982
- super::hex(graph::Key::new(0)),
983
- "00000000000000000000000000000000"
984
- );
985
- }
683
+ use crate::{prelude::*, store::TransactionBoxable};
986
684
  #[test]
987
685
  fn test_sqlite_metadata()
988
686
  {
989
687
  let temp_file = crate::tests::create_tmp_file();
990
688
  let store = super::Store::open(temp_file.path()).unwrap();
991
- let mut tx = store.begin_read().unwrap();
689
+ let mut tx = store.begin_sql_read().unwrap();
992
690
  let version: utils::Version = store.get_metadata_value_json(&mut tx, "version").unwrap();
993
691
  assert_eq!(version.major, consts::GQLITE_VERSION.major);
994
692
  assert_eq!(version.minor, consts::GQLITE_VERSION.minor);
@@ -998,7 +696,7 @@ mod tests
998
696
 
999
697
  // Try to reopen
1000
698
  let store = super::Store::open(temp_file.path()).unwrap();
1001
- let mut tx = store.begin_read().unwrap();
699
+ let mut tx = store.begin_sql_read().unwrap();
1002
700
  let version: utils::Version = store.get_metadata_value_json(&mut tx, "version").unwrap();
1003
701
  assert_eq!(version.major, consts::GQLITE_VERSION.major);
1004
702
  assert_eq!(version.minor, consts::GQLITE_VERSION.minor);