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.
- checksums.yaml +4 -4
- data/ext/gqliterb/Cargo.lock +27 -20
- data/ext/gqliterb/Cargo.toml +3 -2
- data/ext/gqliterb/src/lib.rs +7 -1
- data/ext/gqliterb/vendor/gqlitedb/Cargo.lock +88 -33
- data/ext/gqliterb/vendor/gqlitedb/Cargo.toml +7 -1
- data/ext/gqliterb/vendor/gqlitedb/release.toml +2 -2
- data/ext/gqliterb/vendor/gqlitedb/src/capi.rs +24 -1
- data/ext/gqliterb/vendor/gqlitedb/src/compiler/expression_analyser.rs +4 -0
- data/ext/gqliterb/vendor/gqlitedb/src/compiler/variables_manager.rs +9 -8
- data/ext/gqliterb/vendor/gqlitedb/src/compiler.rs +9 -0
- data/ext/gqliterb/vendor/gqlitedb/src/connection.rs +192 -58
- data/ext/gqliterb/vendor/gqlitedb/src/error.rs +8 -16
- data/ext/gqliterb/vendor/gqlitedb/src/functions/edge.rs +1 -1
- data/ext/gqliterb/vendor/gqlitedb/src/functions/math.rs +1 -1
- data/ext/gqliterb/vendor/gqlitedb/src/functions/node.rs +1 -1
- data/ext/gqliterb/vendor/gqlitedb/src/functions/path.rs +33 -1
- data/ext/gqliterb/vendor/gqlitedb/src/functions/scalar.rs +1 -1
- data/ext/gqliterb/vendor/gqlitedb/src/functions/string.rs +1 -1
- data/ext/gqliterb/vendor/gqlitedb/src/functions/value.rs +1 -1
- data/ext/gqliterb/vendor/gqlitedb/src/functions.rs +11 -13
- data/ext/gqliterb/vendor/gqlitedb/src/graph.rs +15 -0
- data/ext/gqliterb/vendor/gqlitedb/src/interpreter/evaluators.rs +21 -33
- data/ext/gqliterb/vendor/gqlitedb/src/interpreter/instructions.rs +6 -1
- data/ext/gqliterb/vendor/gqlitedb/src/lib.rs +1 -2
- data/ext/gqliterb/vendor/gqlitedb/src/parser/ast.rs +10 -24
- data/ext/gqliterb/vendor/gqlitedb/src/parser/gql.pest +8 -3
- data/ext/gqliterb/vendor/gqlitedb/src/parser/parser.rs +36 -6
- data/ext/gqliterb/vendor/gqlitedb/src/store/redb.rs +36 -24
- data/ext/gqliterb/vendor/gqlitedb/src/store/sqlite.rs +50 -18
- data/ext/gqliterb/vendor/gqlitedb/src/store.rs +9 -2
- data/ext/gqliterb/vendor/gqlitedb/src/tests/evaluators.rs +9 -9
- data/ext/gqliterb/vendor/gqlitedb/src/tests/store/redb.rs +12 -5
- data/ext/gqliterb/vendor/gqlitedb/src/tests/store/sqlite.rs +12 -5
- data/ext/gqliterb/vendor/gqlitedb/src/tests/store.rs +11 -3
- data/ext/gqliterb/vendor/gqlitedb/src/value.rs +54 -4
- data/ext/gqliterb/vendor/gqlitedb/src/value_table.rs +7 -13
- 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
|
-
|
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, ¶meters)?;
|
@@ -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)
|
126
|
+
pub(crate) struct CreateGraph
|
127
|
+
{
|
128
|
+
pub(crate) name: String,
|
129
|
+
}
|
126
130
|
|
127
131
|
#[derive(Debug)]
|
128
|
-
pub(crate) struct
|
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
|
-
|
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 |
|
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::
|
364
|
-
|
365
|
-
|
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
|
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 =
|
325
|
-
|
326
|
-
|
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(
|
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
|
833
|
-
|
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
|
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
|
-
|
278
|
-
|
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 =
|
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
|
-
|
310
|
+
self.upgrade_database(&mut tx, version)?;
|
289
311
|
}
|
290
312
|
}
|
291
|
-
else if !
|
292
|
-
&&
|
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
|
-
|
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
|
-
|
311
|
-
|
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
|
-
|
335
|
+
self.set_metadata_value_json(&mut tx, "version", &consts::GQLITE_VERSION)?;
|
314
336
|
tx.close()?;
|
315
|
-
Ok(
|
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
|
538
|
-
|
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::
|
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::
|
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);
|