gqlite 1.3.1 → 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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/ext/Cargo.toml +3 -3
  3. data/ext/gqlitedb/Cargo.toml +5 -2
  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 +1 -0
  7. data/ext/gqlitedb/src/connection.rs +42 -7
  8. data/ext/gqlitedb/src/error.rs +3 -0
  9. data/ext/gqlitedb/src/interpreter/evaluators.rs +5 -2
  10. data/ext/gqlitedb/src/interpreter/instructions.rs +1 -1
  11. data/ext/gqlitedb/src/lib.rs +1 -1
  12. data/ext/gqlitedb/src/parser/ast.rs +1 -0
  13. data/ext/gqlitedb/src/parser/gql.pest +3 -1
  14. data/ext/gqlitedb/src/parser/parser_impl.rs +8 -0
  15. data/ext/gqlitedb/src/prelude.rs +3 -0
  16. data/ext/gqlitedb/src/store/{pgql.rs → pgrx.rs} +2 -0
  17. data/ext/gqlitedb/src/store/postgres.rs +0 -0
  18. data/ext/gqlitedb/src/store/sqlbase/sqlmetadata.rs +117 -0
  19. data/ext/gqlitedb/src/store/sqlbase/sqlqueries.rs +62 -0
  20. data/ext/gqlitedb/src/store/sqlbase/sqlstore.rs +55 -0
  21. data/ext/gqlitedb/src/store/sqlbase/sqlvalue.rs +189 -0
  22. data/ext/gqlitedb/src/store/sqlbase.rs +456 -0
  23. data/ext/gqlitedb/src/store/sqlite.rs +271 -573
  24. data/ext/gqlitedb/src/store.rs +7 -5
  25. data/ext/gqlitedb/src/utils.rs +25 -0
  26. data/ext/gqlitedb/src/value/compare.rs +6 -0
  27. data/ext/gqlitedb/src/value.rs +18 -2
  28. data/ext/gqlitedb/templates/sql/sqlite/edge_select.sql +18 -18
  29. data/ext/gqlitedb/templates/sql/sqlite/edge_update.sql +3 -3
  30. data/ext/gqlitedb/templates/sql/sqlite/node_select.sql +6 -6
  31. data/ext/gqlitedb/templates/sql/sqlite/node_update.sql +3 -3
  32. data/ext/gqliterb/src/lib.rs +30 -0
  33. data/ext/graphcore/Cargo.toml +3 -2
  34. data/ext/graphcore/src/error.rs +2 -0
  35. data/ext/graphcore/src/lib.rs +2 -0
  36. data/ext/graphcore/src/prelude.rs +1 -1
  37. data/ext/graphcore/src/timestamp.rs +104 -0
  38. data/ext/graphcore/src/value.rs +106 -23
  39. metadata +15 -5
  40. data/ext/graphcore/release.toml +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 38e53ea482654edda2dec42d18ba7aff7e5660f5643f80f66dfd966e21415ebd
4
- data.tar.gz: ce0cb6a21adbca63605e86d753a3c20f281a2126601c5225c446d161efe97094
3
+ metadata.gz: 1b7eba40745af114ff57ca358b2e03c67a7adb9717ad7c7b81ddd7444503fbb1
4
+ data.tar.gz: 3ae6e7c7b038a2caeaf728ff7ce98c49266160d181f478c8259b98d7d8157ba5
5
5
  SHA512:
6
- metadata.gz: f1b60e9c256da4300381ef244158ea61a464529e7518dfe1ee532c0e5ada468860ea08a5c0ab91304b00b5e09590774131fd7487d0bb79d2435d7c13009bd0e6
7
- data.tar.gz: 4009f247ebcdc9519bfa40853b5ab8b32ab3c53fd365cf6f9dd3a25e395596dc70a2c12f7e795496695d8227428f37edfb1375cbcc59ac35e71a76ba973bd318
6
+ metadata.gz: 6674d35ca4d0ec02090ef1521f9f8bb2a4025a050ed312e9c20d50033c8a3472a6a31bdb73dfe6fa9ec99612518c5f5edd72d3ea9d8ead7885c39ed106ac6056
7
+ data.tar.gz: e200b7d2a4203cf803a65bcd6eef82a990fc8c1fa2e2846148673109731353898dacd7b388fe23c9c5b8e5eeae2b56768912408f6f916805111d322c0a83d5ac
data/ext/Cargo.toml CHANGED
@@ -3,15 +3,15 @@ resolver = "2"
3
3
  members = ["gqliterb", "gqlitedb", "graphcore"]
4
4
 
5
5
  [workspace.package]
6
- version = "0.6.0"
6
+ version = "0.7.0"
7
7
  edition = "2021"
8
8
  license = "MIT"
9
9
  homepage = "https://gqlite.org"
10
10
  repository = "https://gitlab.com/gqlite/gqlite"
11
11
 
12
12
  [workspace.dependencies]
13
- graphcore = { version = "0.2.0", path = "graphcore" }
14
- gqlitedb = { version = "0.6.0", path = "gqlitedb" }
13
+ graphcore = { version = "0.7.0", path = "graphcore" }
14
+ gqlitedb = { version = "0.7.0", path = "gqlitedb" }
15
15
 
16
16
  askama = { version = "0.14" }
17
17
  ccutils = { version = "0.4" }
@@ -16,12 +16,13 @@ default = ["redb", "capi", "sqlite"]
16
16
  _backtrace = []
17
17
  capi = []
18
18
  redb = ["dep:redb", "dep:redb2"]
19
- _pgql = ["dep:pgrx"]
19
+ _pgrx = ["dep:pgrx"]
20
20
  _pg13 = ["pgrx/pg13"]
21
21
  _pg14 = ["pgrx/pg14"]
22
22
  _pg15 = ["pgrx/pg15"]
23
23
  _pg16 = ["pgrx/pg16"]
24
24
  _pg17 = ["pgrx/pg17"]
25
+ postgres = ["dep:postgres"]
25
26
  sqlite = ["dep:rusqlite", "dep:askama"]
26
27
  _value_private = []
27
28
  bundled = ["rusqlite/bundled"]
@@ -33,9 +34,10 @@ askama = { workspace = true, optional = true }
33
34
  ccutils = { workspace = true, features = ["alias", "pool", "sync"] }
34
35
  ciborium = "0.2"
35
36
  itertools = { workspace = true }
36
- pgrx = { version = "0.16", optional = true }
37
37
  pest = "2"
38
38
  pest_derive = "2"
39
+ pgrx = { version = "0.16", optional = true }
40
+ postgres = { version = "0.19", optional = true }
39
41
  rand = "0.9"
40
42
  redb = { version = "3", optional = true }
41
43
  redb2 = { version = "2", optional = true, package = "redb" }
@@ -52,6 +54,7 @@ uuid = { workspace = true }
52
54
  ccutils = { workspace = true, features = ["alias", "temporary"] }
53
55
  divan = "0.1"
54
56
  iai-callgrind = { version = "0.16" }
57
+ pgtemp = "0.6"
55
58
  regex = "1"
56
59
 
57
60
  # web:
@@ -46,6 +46,7 @@ where
46
46
  | Value::Edge(..)
47
47
  | Value::Array(..)
48
48
  | Value::String(..)
49
+ | Value::TimeStamp(..)
49
50
  | Value::Map(..)
50
51
  | Value::Path(..) => Err(RunTimeError::InvalidBinaryOperands)?,
51
52
  Value::Null =>
@@ -21,6 +21,7 @@ pub(crate) enum ExpressionType
21
21
  Float,
22
22
  Path,
23
23
  String,
24
+ TimeStamp,
24
25
  Variant,
25
26
  }
26
27
 
@@ -419,6 +420,7 @@ impl<'b> Analyser<'b>
419
420
  value::Value::Map(_) => ExpressionType::Map,
420
421
  value::Value::Path(_) => ExpressionType::Path,
421
422
  value::Value::String(_) => ExpressionType::String,
423
+ value::Value::TimeStamp(_) => ExpressionType::TimeStamp,
422
424
  },
423
425
  true,
424
426
  false,
@@ -942,6 +942,7 @@ pub(crate) fn compile(
942
942
  {
943
943
  ast::Statement::CreateGraph(create_graph) => Ok(Block::CreateGraph {
944
944
  name: create_graph.name.to_owned(),
945
+ if_not_exists: create_graph.if_not_exists,
945
946
  }),
946
947
  ast::Statement::DropGraph(drop_graph) => Ok(Block::DropGraph {
947
948
  name: drop_graph.name.to_owned(),
@@ -8,12 +8,15 @@ pub enum Backend
8
8
  {
9
9
  /// Select the first available backend.
10
10
  Automatic,
11
- /// SQLite backend.
12
- #[cfg(feature = "sqlite")]
13
- SQLite,
11
+ /// Postgres backend.
12
+ #[cfg(feature = "postgres")]
13
+ Postgres,
14
14
  /// Redb backend.
15
15
  #[cfg(feature = "redb")]
16
16
  Redb,
17
+ /// SQLite backend.
18
+ #[cfg(feature = "sqlite")]
19
+ SQLite,
17
20
  }
18
21
 
19
22
  /// Builder with high-level API for creating connection.
@@ -52,16 +55,21 @@ impl ConnectionBuilder
52
55
  {
53
56
  self.map.insert(key, "automatic".into());
54
57
  }
55
- #[cfg(feature = "sqlite")]
56
- Backend::SQLite =>
58
+ #[cfg(feature = "postgres")]
59
+ Backend::Postgres =>
57
60
  {
58
- self.map.insert(key, "sqlite".into());
61
+ self.map.insert(key, "postgres".into());
59
62
  }
60
63
  #[cfg(feature = "redb")]
61
64
  Backend::Redb =>
62
65
  {
63
66
  self.map.insert(key, "redb".into());
64
67
  }
68
+ #[cfg(feature = "sqlite")]
69
+ Backend::SQLite =>
70
+ {
71
+ self.map.insert(key, "sqlite".into());
72
+ }
65
73
  }
66
74
  self
67
75
  }
@@ -204,7 +212,7 @@ impl Connection
204
212
 
205
213
  sq_r.map_err(|rb_e| {
206
214
  StoreError::OpeningError {
207
- errors: error::vec_to_error(&vec![sq_e, rb_e]),
215
+ errors: error::vec_to_error(&[sq_e, rb_e]),
208
216
  }
209
217
  .into()
210
218
  })
@@ -251,6 +259,33 @@ impl Connection
251
259
  .boxed(),
252
260
  })
253
261
  }
262
+ #[cfg(feature = "postgres")]
263
+ "postgres" =>
264
+ {
265
+ let mut config = postgres::Config::new();
266
+ if let Some(host) = options.get("host")
267
+ {
268
+ let host: &String = host.try_into_ref()?;
269
+ config.host(host);
270
+ }
271
+ if let Some(user) = options.get("user")
272
+ {
273
+ let user: &String = user.try_into_ref()?;
274
+ config.user(user);
275
+ }
276
+ if let Some(password) = options.get("password")
277
+ {
278
+ let password: &String = password.try_into_ref()?;
279
+ config.password(password);
280
+ }
281
+ let store = store::postgres::Store::connect(config)?;
282
+ Ok(Connection {
283
+ connection: ConnectionImpl {
284
+ store,
285
+ function_manager: functions::Manager::new(),
286
+ },
287
+ })
288
+ }
254
289
  _ => Err(StoreError::UnknownBackend { backend }.into()),
255
290
  }
256
291
  }
@@ -313,6 +313,8 @@ pub enum InternalError
313
313
  Poison(String),
314
314
  #[error("IOError: {0}.")]
315
315
  IOError(#[from] std::io::Error),
316
+ #[error("Utf8Error: {0}.")]
317
+ Utf8Error(#[from] std::str::Utf8Error),
316
318
  }
317
319
 
318
320
  /// Error in the store backend.
@@ -541,6 +543,7 @@ error_as_internal! {ciborium::ser::Error<std::io::Error>}
541
543
  error_as_internal! {ciborium::de::Error<std::io::Error>}
542
544
  error_as_internal! {serde_json::Error}
543
545
  error_as_internal! {std::num::ParseFloatError}
546
+ error_as_internal! {std::str::Utf8Error}
544
547
 
545
548
  #[cfg(feature = "redb")]
546
549
  mod _trait_impl_redb
@@ -1212,10 +1212,13 @@ pub(crate) fn eval_program<TStore: store::Store>(
1212
1212
  }
1213
1213
  match block
1214
1214
  {
1215
- instructions::Block::CreateGraph { name } =>
1215
+ instructions::Block::CreateGraph {
1216
+ name,
1217
+ if_not_exists,
1218
+ } =>
1216
1219
  {
1217
1220
  store
1218
- .create_graph(&mut tx, name, false)
1221
+ .create_graph(&mut tx, name, *if_not_exists)
1219
1222
  .map_err(|e|
1220
1223
  error::map_error!(e, Error::StoreError(StoreError::DuplicatedGraph { graph_name }) => RunTimeError::DuplicatedGraph {
1221
1224
  graph_name: graph_name.clone(),
@@ -207,7 +207,7 @@ pub(crate) enum Block
207
207
  {
208
208
  CreateGraph
209
209
  {
210
- name: String
210
+ name: String, if_not_exists: bool
211
211
  },
212
212
  DropGraph
213
213
  {
@@ -35,7 +35,7 @@ pub use {
35
35
  error::{CompileTimeError, Error, RunTimeError, StoreError},
36
36
  graph::{labels, Edge, Node, Path},
37
37
  query_result::QueryResult,
38
- value::{array, value_map, Value, ValueMap, ValueTryIntoRef},
38
+ value::{array, value_map, TimeStamp, Value, ValueMap, ValueTryIntoRef},
39
39
  };
40
40
 
41
41
  pub use graphcore::{table, Table};
@@ -129,6 +129,7 @@ pub(crate) type Queries = Vec<Statements>;
129
129
  pub(crate) struct CreateGraph
130
130
  {
131
131
  pub(crate) name: String,
132
+ pub(crate) if_not_exists: bool,
132
133
  }
133
134
 
134
135
  #[derive(Debug)]
@@ -63,7 +63,8 @@ where_modifier = { "WHERE" ~ expression }
63
63
 
64
64
  // Statements
65
65
  statement = {
66
- create_graph_statement
66
+ create_graph_if_not_exists_statement
67
+ | create_graph_statement
67
68
  | drop_graph_if_exists_statement
68
69
  | drop_graph_statement
69
70
  | use_graph_statement
@@ -83,6 +84,7 @@ statement = {
83
84
  star = { "*" }
84
85
 
85
86
  create_graph_statement = { "CREATE" ~ "GRAPH" ~ ident }
87
+ create_graph_if_not_exists_statement = { "CREATE" ~ "GRAPH" ~ "IF" ~ "NOT" ~ "EXISTS" ~ ident }
86
88
  drop_graph_statement = { "DROP" ~ "GRAPH" ~ ident }
87
89
  drop_graph_if_exists_statement = { "DROP" ~ "GRAPH" ~ "IF" ~ "EXISTS" ~ ident }
88
90
  use_graph_statement = { "USE" ~ ident }
@@ -909,7 +909,15 @@ impl AstBuilder
909
909
  {
910
910
  Rule::create_graph_statement => Ok(ast::Statement::CreateGraph(ast::CreateGraph {
911
911
  name: self.build_ident(&mut pair.into_inner())?,
912
+ if_not_exists: false,
912
913
  })),
914
+ Rule::create_graph_if_not_exists_statement =>
915
+ {
916
+ Ok(ast::Statement::CreateGraph(ast::CreateGraph {
917
+ name: self.build_ident(&mut pair.into_inner())?,
918
+ if_not_exists: true,
919
+ }))
920
+ }
913
921
  Rule::drop_graph_statement => Ok(ast::Statement::DropGraph(ast::DropGraph {
914
922
  name: self.build_ident(&mut pair.into_inner())?,
915
923
  if_exists: false,
@@ -7,3 +7,6 @@ pub(crate) use crate::{
7
7
  };
8
8
 
9
9
  pub(crate) use error::export::Error as ErrorType;
10
+
11
+ #[cfg(any(feature = "sqlite", feature = "postgres", feature = "_pgrx"))]
12
+ pub(crate) use store::sqlbase::{self, Row as _, SqlMetaDataStore as _, SqlStore as _};
@@ -1,5 +1,7 @@
1
1
  use crate::{graph, Result};
2
2
 
3
+ impl SqlParams for &[&(dyn tokio_postgres::types::ToSql + Sync)] {}
4
+
3
5
  // _____ _ _
4
6
  // |_ _| __ __ _ _ __ ___ __ _ ___| |_(_) ___ _ __
5
7
  // | || '__/ _` | '_ \/ __|/ _` |/ __| __| |/ _ \| '_ \
File without changes
@@ -0,0 +1,117 @@
1
+ use serde::{Deserialize, Serialize};
2
+
3
+ use super::{FromSqlValue, SqlValue};
4
+ use crate::prelude::*;
5
+
6
+ pub(crate) trait SqlMetaDataQueries
7
+ {
8
+ fn metadata_get_query() -> Result<String>;
9
+ fn metadata_set_query() -> Result<String>;
10
+ }
11
+
12
+ pub(crate) trait SqlMetaDataStore: super::SqlStore
13
+ {
14
+ /// Get the metavalue
15
+ fn get_optional_metadata_value<T: FromSqlValue>(
16
+ &self,
17
+ transaction: &mut Self::TransactionBox,
18
+ key: impl Into<String>,
19
+ ) -> Result<Option<T>>;
20
+ fn get_metadata_value<T: FromSqlValue>(
21
+ &self,
22
+ transaction: &mut Self::TransactionBox,
23
+ key: impl Into<String>,
24
+ ) -> Result<T>
25
+ {
26
+ let key = key.into();
27
+ self
28
+ .get_optional_metadata_value(transaction, &key)?
29
+ .ok_or_else(|| InternalError::MissingMetadata { key }.into())
30
+ }
31
+ #[allow(dead_code)]
32
+ fn get_metadata_value_or_else<T: FromSqlValue>(
33
+ &self,
34
+ transaction: &mut Self::TransactionBox,
35
+ key: impl Into<String>,
36
+ f: impl FnOnce() -> T,
37
+ ) -> Result<T>
38
+ {
39
+ let v = self.get_optional_metadata_value(transaction, key)?;
40
+ Ok(v.unwrap_or_else(f))
41
+ }
42
+ /// Get the metadata value and deserialize it from JSON.
43
+ fn get_metadata_value_json<T: for<'a> Deserialize<'a>>(
44
+ &self,
45
+ transaction: &mut Self::TransactionBox,
46
+ key: impl Into<String>,
47
+ ) -> Result<T>
48
+ {
49
+ Ok(serde_json::from_str(
50
+ &self.get_metadata_value::<String>(transaction, key)?,
51
+ )?)
52
+ }
53
+ #[allow(dead_code)]
54
+ fn get_metadata_value_json_or_else<T: for<'a> Deserialize<'a>>(
55
+ &self,
56
+ transaction: &mut Self::TransactionBox,
57
+ key: impl Into<String>,
58
+ f: impl FnOnce() -> T,
59
+ ) -> Result<T>
60
+ {
61
+ let v = self.get_optional_metadata_value::<String>(transaction, key)?;
62
+ v.map_or_else(|| Ok(f()), |x| Ok(serde_json::from_str(&x)?))
63
+ }
64
+ fn set_metadata_value<'a>(
65
+ &self,
66
+ transaction: &mut Self::TransactionBox,
67
+ key: impl Into<String>,
68
+ value: impl Into<SqlValue<'a>>,
69
+ ) -> Result<()>;
70
+ /// Serialize a value to JSON and store the result in the database.
71
+ fn set_metadata_value_json(
72
+ &self,
73
+ transaction: &mut Self::TransactionBox,
74
+ key: impl Into<String>,
75
+ value: &impl Serialize,
76
+ ) -> Result<()>
77
+ {
78
+ self.set_metadata_value(transaction, key, &serde_json::to_string(value)?)
79
+ }
80
+ }
81
+
82
+ impl<TStore> SqlMetaDataStore for TStore
83
+ where
84
+ TStore: super::SqlStore + SqlMetaDataQueries,
85
+ {
86
+ fn get_optional_metadata_value<T: FromSqlValue>(
87
+ &self,
88
+ transaction: &mut Self::TransactionBox,
89
+ key: impl Into<String>,
90
+ ) -> Result<Option<T>>
91
+ {
92
+ let mut res = None;
93
+ self.query_rows(
94
+ transaction,
95
+ Self::metadata_get_query()?,
96
+ (&key.into(),),
97
+ |x| {
98
+ res = Some(x.get(0)?);
99
+ Ok(())
100
+ },
101
+ )?;
102
+ Ok(res)
103
+ }
104
+ fn set_metadata_value<'a>(
105
+ &self,
106
+ transaction: &mut Self::TransactionBox,
107
+ key: impl Into<String>,
108
+ value: impl Into<SqlValue<'a>>,
109
+ ) -> Result<()>
110
+ {
111
+ self.execute(
112
+ transaction,
113
+ Self::metadata_set_query()?,
114
+ (&key.into(), value.into()),
115
+ )
116
+ }
117
+ }
@@ -0,0 +1,62 @@
1
+ use crate::prelude::*;
2
+
3
+ pub(crate) trait SqlQueries
4
+ {
5
+ /// Query for creating a new graph.
6
+ fn graph_create_query(graph_name: impl AsRef<str>) -> Result<String>;
7
+ /// Query for deleting a graph.
8
+ fn graph_delete(graph_name: impl AsRef<str>) -> Result<String>;
9
+ /// Query for creating a new node
10
+ fn node_create_query(graph_name: impl AsRef<str>) -> Result<String>;
11
+ /// Query for deleting the nodes.
12
+ fn node_delete_query(
13
+ graph_name: impl AsRef<str>,
14
+ keys: impl AsRef<Vec<String>>,
15
+ ) -> Result<String>;
16
+ /// Query for updating a node.
17
+ fn node_update_query(graph_name: impl AsRef<str>) -> Result<String>;
18
+ /// Query for selecting a node.
19
+ fn node_select_query(
20
+ graph_name: impl AsRef<str>,
21
+ keys_var: Option<usize>,
22
+ labels_var: Option<usize>,
23
+ properties_var: Option<usize>,
24
+ ) -> Result<String>;
25
+ /// Query for createing an edge.
26
+ fn edge_create_query(graph_name: impl AsRef<str>) -> Result<String>;
27
+ /// Query for deleting the edges.
28
+ fn edge_delete_query(
29
+ graph_name: impl AsRef<str>,
30
+ keys: impl AsRef<Vec<String>>,
31
+ ) -> Result<String>;
32
+ /// Query for updating a node.
33
+ fn edge_update_query(graph_name: impl AsRef<str>) -> Result<String>;
34
+ /// Query for deleting edges for the given nodes.
35
+ fn edge_delete_by_nodes_query(
36
+ graph_name: impl AsRef<str>,
37
+ keys: impl AsRef<Vec<String>>,
38
+ ) -> Result<String>;
39
+ /// Query for the number of edges connected to the nodes.
40
+ fn edge_count_for_nodes_query(
41
+ graph_name: impl AsRef<str>,
42
+ keys: impl AsRef<Vec<String>>,
43
+ ) -> Result<String>;
44
+ /// Query for selecting an edge.
45
+ #[allow(clippy::too_many_arguments)]
46
+ fn edge_select_query(
47
+ graph_name: impl AsRef<str>,
48
+ is_undirected: bool,
49
+ table_suffix: impl AsRef<str>,
50
+ edge_keys_var: Option<usize>,
51
+ edge_labels_var: Option<usize>,
52
+ edge_properties_var: Option<usize>,
53
+ left_keys_var: Option<usize>,
54
+ left_labels_var: Option<usize>,
55
+ left_properties_var: Option<usize>,
56
+ right_keys_var: Option<usize>,
57
+ right_labels_var: Option<usize>,
58
+ right_properties_var: Option<usize>,
59
+ ) -> Result<String>;
60
+ /// Query for computing statistics.
61
+ fn compute_statistics_query(graph_name: impl AsRef<str>) -> Result<String>;
62
+ }
@@ -0,0 +1,55 @@
1
+ use crate::{prelude::*, store::TransactionBoxable};
2
+
3
+ use super::{FromSqlValue, IntoBindings, SqlValue};
4
+
5
+ pub(crate) trait Row: Sized
6
+ {
7
+ fn get<T: FromSqlValue>(&self, index: usize) -> Result<T>
8
+ {
9
+ T::from_sql_value(self.get_value(index)?)
10
+ }
11
+ fn get_value(&self, index: usize) -> Result<SqlValue<'_>>;
12
+ }
13
+
14
+ /// Base trait for SQL Store.
15
+ pub(crate) trait SqlStore
16
+ {
17
+ type TransactionBox: TransactionBoxable;
18
+ type Row<'a>: Row;
19
+ /// Initialise an SQL store
20
+ fn initialise(&self) -> Result<()>;
21
+
22
+ /// Begin a read transaction.
23
+ fn begin_sql_read(&self) -> Result<Self::TransactionBox>;
24
+ /// Begin a write transaction.
25
+ fn begin_sql_write(&self) -> Result<Self::TransactionBox>;
26
+ /// Execute a batch of SQL queries for the given transaction.
27
+ fn execute_batch(
28
+ &self,
29
+ transaction: &mut Self::TransactionBox,
30
+ sql: impl AsRef<str>,
31
+ ) -> Result<()>;
32
+ /// Execute a single SQL query for the given transaction.
33
+ fn execute<'a>(
34
+ &self,
35
+ transaction: &mut Self::TransactionBox,
36
+ sql: impl AsRef<str>,
37
+ bindings: impl IntoBindings<'a>,
38
+ ) -> Result<()>;
39
+ /// Execute a SQL Query that return a single row.
40
+ fn query_row<'a, 'tx, T>(
41
+ &self,
42
+ transaction: &'tx mut Self::TransactionBox,
43
+ sql: impl AsRef<str>,
44
+ bindings: impl IntoBindings<'a>,
45
+ f: impl for<'b> FnOnce(&Self::Row<'b>) -> Result<T>,
46
+ ) -> Result<T>;
47
+ /// Execute a SQL Query that return multiple rows.
48
+ fn query_rows<'a, 'tx>(
49
+ &self,
50
+ transaction: &'tx mut Self::TransactionBox,
51
+ sql: impl AsRef<str>,
52
+ bindings: impl IntoBindings<'a>,
53
+ f: impl for<'b> FnMut(&Self::Row<'b>) -> Result<()>,
54
+ ) -> Result<()>;
55
+ }