gqlite 1.2.2 → 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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/ext/gqliterb/Cargo.lock +27 -20
  3. data/ext/gqliterb/Cargo.toml +3 -2
  4. data/ext/gqliterb/src/lib.rs +7 -1
  5. data/ext/gqliterb/vendor/gqlitedb/Cargo.lock +88 -33
  6. data/ext/gqliterb/vendor/gqlitedb/Cargo.toml +7 -1
  7. data/ext/gqliterb/vendor/gqlitedb/release.toml +2 -2
  8. data/ext/gqliterb/vendor/gqlitedb/src/capi.rs +24 -1
  9. data/ext/gqliterb/vendor/gqlitedb/src/compiler/expression_analyser.rs +4 -0
  10. data/ext/gqliterb/vendor/gqlitedb/src/compiler/variables_manager.rs +9 -8
  11. data/ext/gqliterb/vendor/gqlitedb/src/compiler.rs +9 -0
  12. data/ext/gqliterb/vendor/gqlitedb/src/connection.rs +192 -58
  13. data/ext/gqliterb/vendor/gqlitedb/src/error.rs +8 -16
  14. data/ext/gqliterb/vendor/gqlitedb/src/functions/edge.rs +1 -1
  15. data/ext/gqliterb/vendor/gqlitedb/src/functions/math.rs +1 -1
  16. data/ext/gqliterb/vendor/gqlitedb/src/functions/node.rs +1 -1
  17. data/ext/gqliterb/vendor/gqlitedb/src/functions/path.rs +33 -1
  18. data/ext/gqliterb/vendor/gqlitedb/src/functions/scalar.rs +1 -1
  19. data/ext/gqliterb/vendor/gqlitedb/src/functions/string.rs +1 -1
  20. data/ext/gqliterb/vendor/gqlitedb/src/functions/value.rs +1 -1
  21. data/ext/gqliterb/vendor/gqlitedb/src/functions.rs +11 -13
  22. data/ext/gqliterb/vendor/gqlitedb/src/graph.rs +15 -0
  23. data/ext/gqliterb/vendor/gqlitedb/src/interpreter/evaluators.rs +21 -33
  24. data/ext/gqliterb/vendor/gqlitedb/src/interpreter/instructions.rs +6 -1
  25. data/ext/gqliterb/vendor/gqlitedb/src/lib.rs +1 -2
  26. data/ext/gqliterb/vendor/gqlitedb/src/parser/ast.rs +10 -24
  27. data/ext/gqliterb/vendor/gqlitedb/src/parser/gql.pest +8 -3
  28. data/ext/gqliterb/vendor/gqlitedb/src/parser/parser.rs +36 -6
  29. data/ext/gqliterb/vendor/gqlitedb/src/store/redb.rs +36 -24
  30. data/ext/gqliterb/vendor/gqlitedb/src/store/sqlite.rs +50 -18
  31. data/ext/gqliterb/vendor/gqlitedb/src/store.rs +9 -2
  32. data/ext/gqliterb/vendor/gqlitedb/src/tests/evaluators.rs +9 -9
  33. data/ext/gqliterb/vendor/gqlitedb/src/tests/store/redb.rs +12 -5
  34. data/ext/gqliterb/vendor/gqlitedb/src/tests/store/sqlite.rs +12 -5
  35. data/ext/gqliterb/vendor/gqlitedb/src/tests/store.rs +11 -3
  36. data/ext/gqliterb/vendor/gqlitedb/src/value.rs +54 -4
  37. data/ext/gqliterb/vendor/gqlitedb/src/value_table.rs +7 -13
  38. metadata +2 -2
@@ -16,18 +16,6 @@ enum Value
16
16
  EdgeQuery(store::SelectEdgeQuery),
17
17
  }
18
18
 
19
- impl Value
20
- {
21
- fn is_null(&self) -> bool
22
- {
23
- match self
24
- {
25
- Value::GraphValue(gv) => gv.is_null(),
26
- _ => false,
27
- }
28
- }
29
- }
30
-
31
19
  impl<T> From<T> for Value
32
20
  where
33
21
  T: Into<value::Value>,
@@ -659,10 +647,6 @@ fn eval_instructions(
659
647
  stack.push(a);
660
648
  stack.push(b);
661
649
  }
662
- &instructions::Instruction::Drop =>
663
- {
664
- stack.try_pop()?;
665
- }
666
650
  &instructions::Instruction::AndBinaryOperator
667
651
  | &instructions::Instruction::OrBinaryOperator
668
652
  | &instructions::Instruction::XorBinaryOperator =>
@@ -803,6 +787,10 @@ fn eval_instructions(
803
787
  {
804
788
  execute_binary_operator(stack, |a, b| a % b)?;
805
789
  }
790
+ &instructions::Instruction::ExponentBinaryOperator =>
791
+ {
792
+ execute_binary_operator(stack, |a, b| a.pow(b))?;
793
+ }
806
794
  }
807
795
  }
808
796
  Ok(())
@@ -874,8 +862,6 @@ pub(crate) fn eval_update_property<TStore: store::Store>(
874
862
  Ok(())
875
863
  }
876
864
 
877
- struct OrderByKey(Vec<(value::Value, bool)>);
878
-
879
865
  fn handle_asc(o: std::cmp::Ordering, asc: bool) -> std::cmp::Ordering
880
866
  {
881
867
  if asc
@@ -893,18 +879,6 @@ fn handle_asc(o: std::cmp::Ordering, asc: bool) -> std::cmp::Ordering
893
879
  }
894
880
  }
895
881
 
896
- fn compute_order_by(
897
- a: &Vec<(value::Value, bool)>,
898
- b: &Vec<(value::Value, bool)>,
899
- ) -> std::cmp::Ordering
900
- {
901
- a.iter()
902
- .zip(b.iter())
903
- .map(|(a, b)| handle_asc(a.0.orderability(&b.0), a.1))
904
- .find(|p| *p != std::cmp::Ordering::Equal)
905
- .unwrap_or(std::cmp::Ordering::Equal)
906
- }
907
-
908
882
  #[derive(Debug, Default, Clone, Hash, PartialEq)]
909
883
  struct RowKey(value_table::Row);
910
884
 
@@ -1012,8 +986,8 @@ fn compute_return_with_table(
1012
986
  }
1013
987
  }
1014
988
 
1015
- // Aggregation always return at least once
1016
- if aggregation_table.is_empty()
989
+ // Aggregation always return at least once, unless there is a non-aggregated value
990
+ if aggregation_table.is_empty() && variables.iter().all(|v| v.aggregations.len() > 0)
1017
991
  {
1018
992
  let row = Row::new(Default::default(), variables_sizes.total_size());
1019
993
  let aggregations_states = create_aggregations_states(&variables, parameters)?;
@@ -1024,6 +998,7 @@ fn compute_return_with_table(
1024
998
 
1025
999
  for (row, aggregations_states) in aggregation_table
1026
1000
  {
1001
+ let mut non_null_aggregation = false;
1027
1002
  let mut out_row = value_table::Row::new(Default::default(), variables_sizes.total_size());
1028
1003
  for (idx, (rw_expr, aggregation_states)) in variables
1029
1004
  .iter()
@@ -1038,7 +1013,9 @@ fn compute_return_with_table(
1038
1013
  {
1039
1014
  for (name, s) in aggregation_states.into_iter()
1040
1015
  {
1041
- out_row.set(name, s.finalise()?)?;
1016
+ let value = s.finalise()?;
1017
+ non_null_aggregation = non_null_aggregation | !value.is_null();
1018
+ out_row.set(name, value)?;
1042
1019
  }
1043
1020
  let mut stack = Stack::default();
1044
1021
  eval_instructions(&mut stack, &out_row, &rw_expr.instructions, &parameters)?;
@@ -1201,6 +1178,7 @@ fn is_write_program(program: &super::Program) -> bool
1201
1178
  | Block::Call { .. }
1202
1179
  | Block::With { .. } => false,
1203
1180
  Block::CreateGraph { .. }
1181
+ | Block::DropGraph { .. }
1204
1182
  | Block::Create { .. }
1205
1183
  | Block::Update { .. }
1206
1184
  | Block::Delete { .. } => true,
@@ -1245,6 +1223,16 @@ pub(crate) fn eval_program<TStore: store::Store>(
1245
1223
  } ))?;
1246
1224
  graph_name = name.to_owned();
1247
1225
  }
1226
+ instructions::Block::DropGraph { name, if_exists } =>
1227
+ {
1228
+ store
1229
+ .drop_graph(&mut tx, name, *if_exists)
1230
+ .map_err(|e|
1231
+ error::map_error!(e, Error::StoreError(StoreError::UnknownGraph { graph_name }) => RunTimeError::UnknownGraph {
1232
+ graph_name: graph_name.clone(),
1233
+ } ))?;
1234
+ graph_name = name.to_owned();
1235
+ }
1248
1236
  instructions::Block::UseGraph { name } =>
1249
1237
  {
1250
1238
  graph_name = name.to_owned();
@@ -58,7 +58,6 @@ pub(crate) enum Instruction
58
58
  Rot3, // If a is the top of the stack, then a b c -> b c a
59
59
  InverseRot3, // If a is the top of the stack, then a b c -> c a b
60
60
  Swap,
61
- Drop,
62
61
  AndBinaryOperator,
63
62
  OrBinaryOperator,
64
63
  XorBinaryOperator,
@@ -78,6 +77,7 @@ pub(crate) enum Instruction
78
77
  MultiplicationBinaryOperator,
79
78
  DivisionBinaryOperator,
80
79
  ModuloBinaryOperator,
80
+ ExponentBinaryOperator,
81
81
  }
82
82
 
83
83
  pub(crate) type Instructions = Vec<Instruction>;
@@ -208,6 +208,10 @@ pub(crate) enum Block
208
208
  {
209
209
  name: String
210
210
  },
211
+ DropGraph
212
+ {
213
+ name: String, if_exists: bool
214
+ },
211
215
  UseGraph
212
216
  {
213
217
  name: String
@@ -233,6 +237,7 @@ pub(crate) enum Block
233
237
  },
234
238
  Call
235
239
  {
240
+ #[allow(dead_code)]
236
241
  arguments: Instructions,
237
242
  name: String,
238
243
  },
@@ -7,7 +7,6 @@
7
7
  //! for an example of use.
8
8
 
9
9
  #![warn(missing_docs)]
10
- #![allow(dead_code)]
11
10
  #![deny(warnings)]
12
11
 
13
12
  mod aggregators;
@@ -35,7 +34,7 @@ pub use {
35
34
  connection::Connection,
36
35
  error::{CompileTimeError, Error, RunTimeError, StoreError},
37
36
  graph::{Edge, Node, Path},
38
- value::{Value, ValueMap},
37
+ value::{Value, ValueMap, ValueTryIntoRef},
39
38
  };
40
39
 
41
40
  /// GQLite Result alias. Usable as a standard `Result<T, E>` or default to gqlite::Error with `Result<T>`
@@ -95,6 +95,7 @@ impl VariableIdentifiers
95
95
  pub(crate) enum Statement
96
96
  {
97
97
  CreateGraph(CreateGraph),
98
+ DropGraph(DropGraph),
98
99
  UseGraph(UseGraph),
99
100
  Create(Create),
100
101
  Match(Match),
@@ -122,12 +123,16 @@ pub(crate) type Statements = Vec<Statement>;
122
123
  pub(crate) type Queries = Vec<Statements>;
123
124
 
124
125
  #[derive(Debug)]
125
- pub(crate) enum Node {}
126
+ pub(crate) struct CreateGraph
127
+ {
128
+ pub(crate) name: String,
129
+ }
126
130
 
127
131
  #[derive(Debug)]
128
- pub(crate) struct CreateGraph
132
+ pub(crate) struct DropGraph
129
133
  {
130
134
  pub(crate) name: String,
135
+ pub(crate) if_exists: bool,
131
136
  }
132
137
 
133
138
  #[derive(Debug)]
@@ -198,18 +203,11 @@ pub(crate) struct Update
198
203
  pub(crate) updates: Vec<OneUpdate>,
199
204
  }
200
205
 
201
- #[derive(Debug)]
202
- pub(crate) struct Remove
203
- {
204
- pub(crate) expressions: Vec<Expression>,
205
- }
206
-
207
206
  #[derive(Debug)]
208
207
  pub(crate) struct Call
209
208
  {
210
209
  pub(crate) name: String,
211
210
  pub(crate) arguments: Vec<Expression>,
212
- pub(crate) yield_: Vec<String>,
213
211
  }
214
212
 
215
213
  // Set/remove Statements
@@ -294,6 +292,7 @@ pub(crate) enum Expression
294
292
  Multiplication(Box<Multiplication>),
295
293
  Division(Box<Division>),
296
294
  Modulo(Box<Modulo>),
295
+ Exponent(Box<Exponent>),
297
296
 
298
297
  Negation(Box<Negation>),
299
298
  LogicalNegation(Box<LogicalNegation>),
@@ -350,6 +349,7 @@ pub(crate) struct PathPattern
350
349
  #[derive(Debug, Clone, PartialEq)]
351
350
  pub(crate) enum LabelExpression
352
351
  {
352
+ #[allow(dead_code)]
353
353
  Not(Box<LabelExpression>),
354
354
  And(Vec<Box<LabelExpression>>),
355
355
  Or(Vec<Box<LabelExpression>>),
@@ -421,10 +421,6 @@ impl LabelExpression
421
421
  },
422
422
  }
423
423
  }
424
- fn clone_boxed(&self) -> Box<LabelExpression>
425
- {
426
- self.clone().boxed()
427
- }
428
424
  pub(crate) fn boxed(self) -> Box<LabelExpression>
429
425
  {
430
426
  Box::new(self)
@@ -530,12 +526,6 @@ pub(crate) struct RangeAccess
530
526
  pub(crate) start: Option<Expression>,
531
527
  pub(crate) end: Option<Expression>,
532
528
  }
533
- #[derive(Debug)]
534
- pub(crate) struct HasLabels
535
- {
536
- pub(crate) left: String,
537
- pub(crate) labels: Vec<String>,
538
- }
539
529
 
540
530
  #[derive(Debug, Clone, PartialEq)]
541
531
  pub(crate) struct FunctionCall
@@ -576,6 +566,7 @@ create_binary_op! {Subtraction}
576
566
  create_binary_op! {Multiplication}
577
567
  create_binary_op! {Division}
578
568
  create_binary_op! {Modulo}
569
+ create_binary_op! {Exponent}
579
570
 
580
571
  macro_rules! create_unary_op {
581
572
  ( $x:tt ) => {
@@ -595,11 +586,6 @@ create_unary_op! {IsNotNull}
595
586
 
596
587
  // Values
597
588
 
598
- #[derive(Debug)]
599
- pub(crate) struct All {}
600
- #[derive(Debug)]
601
- pub(crate) struct EndOfList {}
602
-
603
589
  #[derive(Debug, Clone, PartialEq)]
604
590
  pub(crate) struct Value
605
591
  {
@@ -64,6 +64,8 @@ where_modifier = { "WHERE" ~ expression }
64
64
  // Statements
65
65
  statement = {
66
66
  create_graph_statement
67
+ | drop_graph_if_exists_statement
68
+ | drop_graph_statement
67
69
  | use_graph_statement
68
70
  | create_statement
69
71
  | optional_match_statement
@@ -81,6 +83,8 @@ statement = {
81
83
  star = { "*" }
82
84
 
83
85
  create_graph_statement = { "CREATE" ~ "GRAPH" ~ ident }
86
+ drop_graph_statement = { "DROP" ~ "GRAPH" ~ ident }
87
+ drop_graph_if_exists_statement = { "DROP" ~ "GRAPH" ~ "IF" ~ "EXISTS" ~ ident }
84
88
  use_graph_statement = { "USE" ~ ident }
85
89
 
86
90
  create_statement = { "CREATE" ~ node_or_edge_pattern ~ ("," ~ node_or_edge_pattern)* }
@@ -121,7 +125,7 @@ remove_member_access = { (("(" ~ ident ~ ")") | ident) ~ ("." ~ ident)+ }
121
125
 
122
126
  expression = { prefix* ~ expression_term ~ postfix* ~ (infix ~ prefix? ~ expression_term ~ postfix*)* }
123
127
 
124
- infix = _{ addition | subtraction | multiplication | division | modulo | or | and | xor | equal | different | in_ | not_in | superior_equal | inferior_equal | superior | inferior }
128
+ infix = _{ addition | subtraction | multiplication | division | modulo | exponent | or | and | xor | equal | different | in_ | not_in | superior_equal | inferior_equal | superior | inferior }
125
129
  postfix = _{ is_null | is_not_null | member_access | range_access | range_access_to | index_access }
126
130
  prefix = _{ negation | not }
127
131
 
@@ -130,6 +134,7 @@ subtraction = { "-" }
130
134
  multiplication = { "*" }
131
135
  division = { "/" }
132
136
  modulo = { "%" }
137
+ exponent = { "^" }
133
138
 
134
139
  xor_kw = @{ "XOR" ~ !ASCII_ALPHA }
135
140
  xor = { xor_kw }
@@ -164,8 +169,8 @@ label_check_expression = { ident ~ (":" ~ ident)+ }
164
169
  parenthesised_expression = { "(" ~ expression ~ ")" }
165
170
  named_expression = { (expression ~ "AS" ~ ident) | expression }
166
171
  function_call = { function_name ~ "(" ~ (expression ~ ("," ~ expression)*)? ~ ")" }
167
- count_star = { "count" ~ "(" ~ "*" ~ ")" }
168
- expression_term = { null_lit | true_lit | false_lit | num | hexa_int | octa_int | int | string_literal | map | array | label_check_expression | parameter | parenthesised_expression | function_call | count_star | ident }
172
+ function_star = { function_name ~ "(" ~ "*" ~ ")" }
173
+ expression_term = { null_lit | true_lit | false_lit | num | hexa_int | octa_int | int | string_literal | map | array | label_check_expression | parameter | parenthesised_expression | function_call | function_star | ident }
169
174
 
170
175
  parameter = { "$" ~ parameter_name }
171
176
 
@@ -197,6 +197,13 @@ impl AstBuilder
197
197
  }
198
198
  .into(),
199
199
  ),
200
+ Rule::exponent => Ok(
201
+ ast::Exponent {
202
+ left: lhs?,
203
+ right: rhs?,
204
+ }
205
+ .into(),
206
+ ),
200
207
  Rule::or => Ok(
201
208
  ast::LogicalOr {
202
209
  left: lhs?,
@@ -360,10 +367,25 @@ impl AstBuilder
360
367
  .collect::<Result<_>>()?,
361
368
  }))
362
369
  }
363
- Rule::count_star => Ok(ast::Expression::FunctionCall(ast::FunctionCall {
364
- name: "count".into(),
365
- arguments: vec![ast::Expression::Value(ast::Value { value: 0.into() })],
366
- })),
370
+ Rule::function_star =>
371
+ {
372
+ let mut it = pair.into_inner();
373
+ let function_name = it
374
+ .next()
375
+ .ok_or_else(|| error::InternalError::MissingFunctionName)?
376
+ .as_str();
377
+ if function_name.to_lowercase() != "count"
378
+ {
379
+ Err(error::CompileTimeError::UnknownFunction {
380
+ name: function_name.to_owned(),
381
+ })?;
382
+ }
383
+
384
+ Ok(ast::Expression::FunctionCall(ast::FunctionCall {
385
+ name: "count".into(),
386
+ arguments: vec![ast::Expression::Value(ast::Value { value: 0.into() })],
387
+ }))
388
+ }
367
389
  Rule::parenthesised_expression =>
368
390
  {
369
391
  let mut it = pair.into_inner();
@@ -874,6 +896,14 @@ impl AstBuilder
874
896
  Rule::create_graph_statement => Ok(ast::Statement::CreateGraph(ast::CreateGraph {
875
897
  name: self.build_ident(&mut pair.into_inner())?,
876
898
  })),
899
+ Rule::drop_graph_statement => Ok(ast::Statement::DropGraph(ast::DropGraph {
900
+ name: self.build_ident(&mut pair.into_inner())?,
901
+ if_exists: false,
902
+ })),
903
+ Rule::drop_graph_if_exists_statement => Ok(ast::Statement::DropGraph(ast::DropGraph {
904
+ name: self.build_ident(&mut pair.into_inner())?,
905
+ if_exists: true,
906
+ })),
877
907
  Rule::use_graph_statement => Ok(ast::Statement::UseGraph(ast::UseGraph {
878
908
  name: self.build_ident(&mut pair.into_inner())?,
879
909
  })),
@@ -1054,7 +1084,6 @@ impl AstBuilder
1054
1084
  Ok(ast::Statement::Call(ast::Call {
1055
1085
  name: name,
1056
1086
  arguments: Default::default(),
1057
- yield_: Default::default(),
1058
1087
  }))
1059
1088
  }
1060
1089
  unknown_expression => Err(
@@ -1086,7 +1115,8 @@ pub(crate) fn parse(input: &str) -> Result<ast::Queries>
1086
1115
  .op(
1087
1116
  Op::infix(Rule::multiplication, Assoc::Left)
1088
1117
  | Op::infix(Rule::division, Assoc::Left)
1089
- | Op::infix(Rule::modulo, Assoc::Left),
1118
+ | Op::infix(Rule::modulo, Assoc::Left)
1119
+ | Op::infix(Rule::exponent, Assoc::Left),
1090
1120
  )
1091
1121
  .op(Op::prefix(Rule::not) | Op::prefix(Rule::negation))
1092
1122
  .op(
@@ -164,21 +164,6 @@ impl EdgeIdResult
164
164
  // | | (_| | |_) | | __/
165
165
  // |_|\__,_|_.__/|_|\___|
166
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
167
  trait TableExtension<K, V>
183
168
  where
184
169
  K: redb::Key + 'static,
@@ -188,7 +173,7 @@ where
188
173
  &self,
189
174
  key: impl std::borrow::Borrow<K::SelfType<'a>>,
190
175
  f: impl FnOnce() -> TError,
191
- ) -> Result<redb::AccessGuard<V>>;
176
+ ) -> Result<redb::AccessGuard<'_, V>>;
192
177
  }
193
178
 
194
179
  impl<'txn, K, V, T> TableExtension<K, V> for T
@@ -201,7 +186,7 @@ where
201
186
  &self,
202
187
  key: impl std::borrow::Borrow<K::SelfType<'a>>,
203
188
  f: impl FnOnce() -> TError,
204
- ) -> Result<redb::AccessGuard<V>>
189
+ ) -> Result<redb::AccessGuard<'_, V>>
205
190
  {
206
191
  self.get(key)?.ok_or_else(|| f().into())
207
192
  }
@@ -217,6 +202,7 @@ where
217
202
  #[derive(Debug)]
218
203
  struct GraphInfo
219
204
  {
205
+ #[allow(dead_code)]
220
206
  name: String,
221
207
  nodes_table: String,
222
208
  edges_table: String,
@@ -314,19 +300,36 @@ type TransactionBox = store::TransactionBox<redb::ReadTransaction, redb::WriteTr
314
300
  impl Store
315
301
  {
316
302
  /// Crate a new store, with a default graph
317
- pub(crate) fn new<P: AsRef<std::path::Path>>(path: P) -> Result<Store>
303
+ pub(crate) fn open<P: AsRef<std::path::Path>>(path: P) -> Result<Store>
318
304
  {
319
305
  let s = Self {
320
306
  redb_store: redb::Database::create(path.as_ref())?,
321
307
  graphs: Default::default(),
322
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
+ {
323
325
  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)?;
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)?;
327
329
  tx.close()?;
328
- Ok(s)
330
+ Ok(())
329
331
  }
332
+ #[allow(dead_code)]
330
333
  fn get_metadata_from_table<TTable, TValue>(
331
334
  &self,
332
335
  table: TTable,
@@ -342,6 +345,7 @@ impl Store
342
345
  .ok_or_else(|| InternalError::MissingMetadata { key: key })?;
343
346
  Ok(ciborium::from_reader(value.value().as_slice())?)
344
347
  }
348
+ #[allow(dead_code)]
345
349
  fn get_metadata_value<T: for<'a> Deserialize<'a>>(
346
350
  &self,
347
351
  transaction: &mut TransactionBox,
@@ -829,8 +833,12 @@ impl store::Store for Store
829
833
 
830
834
  Ok(())
831
835
  }
832
- fn delete_graph(&self, transaction: &mut Self::TransactionBox, graph_name: &String)
833
- -> Result<()>
836
+ fn drop_graph(
837
+ &self,
838
+ transaction: &mut Self::TransactionBox,
839
+ graph_name: &String,
840
+ if_exists: bool,
841
+ ) -> Result<()>
834
842
  {
835
843
  let mut graphs_list = self.graphs_list(transaction)?;
836
844
  if graphs_list.contains(graph_name)
@@ -848,6 +856,10 @@ impl store::Store for Store
848
856
 
849
857
  Ok(())
850
858
  }
859
+ else if if_exists
860
+ {
861
+ Ok(())
862
+ }
851
863
  else
852
864
  {
853
865
  Err(
@@ -1,5 +1,7 @@
1
1
  use std::{cell::RefCell, collections::HashSet, path::PathBuf};
2
2
 
3
+ use rusqlite;
4
+
3
5
  use askama::Template;
4
6
  use ccutils::pool::{self, Pool};
5
7
  use rusqlite::{named_params, types::FromSql, OptionalExtension, ToSql};
@@ -264,35 +266,55 @@ ccutils::assert_impl_all!(Store: Sync, Send);
264
266
  impl Store
265
267
  {
266
268
  /// Crate a new store, with a default graph
267
- pub(crate) fn new<P: AsRef<std::path::Path>>(path: P) -> Result<Store>
269
+ pub(crate) fn open<P: AsRef<std::path::Path>>(path: P) -> Result<Store>
268
270
  {
269
- use store::Store;
270
271
  let path: PathBuf = path.as_ref().into();
271
272
  let connection = Pool::new(
272
273
  move || Ok(rusqlite::Connection::open(&path)?),
273
274
  pool::Options::default().minimum_pool_size(1).pool_size(3),
274
275
  )?;
275
276
  let s = Self { connection };
276
-
277
- let mut tx = s.begin_write()?;
278
- if s.check_if_table_exists(&mut tx, "gqlite_metadata")?
277
+ s.initialise()?;
278
+ Ok(s)
279
+ }
280
+ pub(crate) fn in_memory() -> Result<Store>
281
+ {
282
+ let id = uuid::Uuid::new_v4().as_u128();
283
+ let connection = Pool::new(
284
+ move || {
285
+ Ok(rusqlite::Connection::open_with_flags(
286
+ format!("file:{}?mode=memory&cache=shared", id),
287
+ rusqlite::OpenFlags::default(),
288
+ )?)
289
+ },
290
+ pool::Options::default().minimum_pool_size(1).pool_size(3),
291
+ )?;
292
+ let s = Self { connection };
293
+ s.initialise()?;
294
+ Ok(s)
295
+ }
296
+ fn initialise(&self) -> Result<()>
297
+ {
298
+ use store::Store;
299
+ let mut tx = self.begin_write()?;
300
+ if self.check_if_table_exists(&mut tx, "gqlite_metadata")?
279
301
  {
280
302
  // gqlite version 1.1 incorrectly use ' instead of " in the version number
281
- let version_raw = s
303
+ let version_raw = self
282
304
  .get_metadata_value::<String>(&mut tx, "version")?
283
305
  .replace("'", "\"");
284
306
  let version: utils::Version = serde_json::from_str(&version_raw)?;
285
307
  if version.major != consts::GQLITE_VERSION.major
286
308
  || version.minor != consts::GQLITE_VERSION.minor
287
309
  {
288
- s.upgrade_database(&mut tx, version)?;
310
+ self.upgrade_database(&mut tx, version)?;
289
311
  }
290
312
  }
291
- else if !s.check_if_table_exists(&mut tx, "gqlite_metadata")?
292
- && s.check_if_table_exists(&mut tx, "gqlite_default_nodes")?
313
+ else if !self.check_if_table_exists(&mut tx, "gqlite_metadata")?
314
+ && self.check_if_table_exists(&mut tx, "gqlite_default_nodes")?
293
315
  {
294
316
  // 1.0 didn't have the metadata table
295
- s.upgrade_database(
317
+ self.upgrade_database(
296
318
  &mut tx,
297
319
  utils::Version {
298
320
  major: 1,
@@ -307,12 +329,12 @@ impl Store
307
329
  include_str!("../../templates/sql/sqlite/metadata_create_table.sql"),
308
330
  (),
309
331
  )?;
310
- s.set_metadata_value_json(&mut tx, "graphs", &Vec::<String>::new())?;
311
- s.create_graph(&mut tx, &"default".to_string(), true)?;
332
+ self.set_metadata_value_json(&mut tx, "graphs", &Vec::<String>::new())?;
333
+ self.create_graph(&mut tx, &"default".to_string(), true)?;
312
334
  }
313
- s.set_metadata_value_json(&mut tx, "version", &consts::GQLITE_VERSION)?;
335
+ self.set_metadata_value_json(&mut tx, "version", &consts::GQLITE_VERSION)?;
314
336
  tx.close()?;
315
- Ok(s)
337
+ Ok(())
316
338
  }
317
339
  fn upgrade_database(&self, transaction: &mut TransactionBox, from: utils::Version) -> Result<()>
318
340
  {
@@ -394,6 +416,7 @@ impl Store
394
416
  |row| row.get(0),
395
417
  )?)
396
418
  }
419
+ #[allow(dead_code)]
397
420
  pub(crate) fn get_metadata_value_or_else<T: FromSql>(
398
421
  &self,
399
422
  transaction: &mut TransactionBox,
@@ -437,6 +460,7 @@ impl Store
437
460
  &self.get_metadata_value::<String>(transaction, key)?,
438
461
  )?)
439
462
  }
463
+ #[allow(dead_code)]
440
464
  pub(crate) fn get_metadata_value_json_or_else<T: for<'a> Deserialize<'a>>(
441
465
  &self,
442
466
  transaction: &mut TransactionBox,
@@ -534,8 +558,12 @@ impl store::Store for Store
534
558
  self.set_metadata_value_json(transaction, "graphs", &graphs_list)?;
535
559
  Ok(())
536
560
  }
537
- fn delete_graph(&self, transaction: &mut Self::TransactionBox, graph_name: &String)
538
- -> Result<()>
561
+ fn drop_graph(
562
+ &self,
563
+ transaction: &mut Self::TransactionBox,
564
+ graph_name: &String,
565
+ if_exists: bool,
566
+ ) -> Result<()>
539
567
  {
540
568
  let mut graphs_list = self.graphs_list(transaction)?;
541
569
  if graphs_list.contains(graph_name)
@@ -552,6 +580,10 @@ impl store::Store for Store
552
580
 
553
581
  Ok(())
554
582
  }
583
+ else if if_exists
584
+ {
585
+ Ok(())
586
+ }
555
587
  else
556
588
  {
557
589
  Err(
@@ -972,7 +1004,7 @@ mod tests
972
1004
  fn test_sqlite_metadata()
973
1005
  {
974
1006
  let temp_file = crate::tests::create_tmp_file();
975
- let store = super::Store::new(temp_file.path()).unwrap();
1007
+ let store = super::Store::open(temp_file.path()).unwrap();
976
1008
  let mut tx = store.begin_read().unwrap();
977
1009
  let version: utils::Version = store.get_metadata_value_json(&mut tx, "version").unwrap();
978
1010
  assert_eq!(version.major, consts::GQLITE_VERSION.major);
@@ -982,7 +1014,7 @@ mod tests
982
1014
  drop(store);
983
1015
 
984
1016
  // Try to reopen
985
- let store = super::Store::new(temp_file.path()).unwrap();
1017
+ let store = super::Store::open(temp_file.path()).unwrap();
986
1018
  let mut tx = store.begin_read().unwrap();
987
1019
  let version: utils::Version = store.get_metadata_value_json(&mut tx, "version").unwrap();
988
1020
  assert_eq!(version.major, consts::GQLITE_VERSION.major);