|
@@ -52,6 +52,24 @@ pub mod re_export {
|
|
|
pub use rusqlite;
|
|
|
}
|
|
|
|
|
|
+#[derive(Debug)]
|
|
|
+pub enum DBError {
|
|
|
+ ConnectFailure,
|
|
|
+ NoSchema,
|
|
|
+ DifferentSchema,
|
|
|
+ DropFailure,
|
|
|
+ CreateFailure,
|
|
|
+ SanityCheckFailure
|
|
|
+}
|
|
|
+
|
|
|
+impl std::fmt::Display for DBError {
|
|
|
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
|
|
+ fmt.write_fmt(format_args!("Database error: {:?}", self))
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl std::error::Error for DBError { }
|
|
|
+
|
|
|
/// SQLite database connection
|
|
|
pub struct DB {
|
|
|
conn: rusqlite::Connection,
|
|
@@ -60,24 +78,24 @@ pub struct DB {
|
|
|
}
|
|
|
|
|
|
impl DB {
|
|
|
- pub fn new(schema: model::SchemaModel, path: &str, allow_recreate: bool) -> Result<Self, &'static str> {
|
|
|
+ pub fn new(schema: model::SchemaModel, path: &str, allow_recreate: bool) -> Result<Self, DBError> {
|
|
|
Self::from_connection(
|
|
|
- rusqlite::Connection::open(path).expect("Opening database connection failed"),
|
|
|
+ rusqlite::Connection::open(path).map_err(|e| DBError::ConnectFailure)?,
|
|
|
schema,
|
|
|
allow_recreate,
|
|
|
)
|
|
|
}
|
|
|
|
|
|
- /// For use in tests
|
|
|
- pub fn new_in_memory(schema: model::SchemaModel) -> Result<Self, &'static str> {
|
|
|
+ /// Mostly for use in tests, but may be useful in some applications as well.
|
|
|
+ pub fn new_in_memory(schema: model::SchemaModel) -> Result<Self, DBError> {
|
|
|
Self::from_connection(
|
|
|
- rusqlite::Connection::open_in_memory().expect("Opening database connection failed"),
|
|
|
+ rusqlite::Connection::open_in_memory().map_err(|e| DBError::ConnectFailure)?,
|
|
|
schema,
|
|
|
true,
|
|
|
)
|
|
|
}
|
|
|
|
|
|
- pub fn recreate_schema(&self) -> Result<(), &'static str> {
|
|
|
+ pub fn recreate_schema(&self) -> Result<(), DBError> {
|
|
|
self.create_schema()
|
|
|
}
|
|
|
|
|
@@ -85,7 +103,7 @@ impl DB {
|
|
|
conn: rusqlite::Connection,
|
|
|
schema: model::SchemaModel,
|
|
|
allow_recreate: bool,
|
|
|
- ) -> Result<Self, &'static str> {
|
|
|
+ ) -> Result<Self, DBError> {
|
|
|
let sig = Self::calculate_schema_hash(&schema);
|
|
|
let ret = Self {
|
|
|
conn,
|
|
@@ -114,12 +132,18 @@ impl DB {
|
|
|
base64::encode(hasher.finalize())
|
|
|
}
|
|
|
|
|
|
- fn check_schema(&self, allow_recreate: bool) -> Result<(), &'static str> {
|
|
|
+ fn check_schema(&self, allow_recreate: bool) -> Result<(), DBError> {
|
|
|
let hash = query::get_one_by(self, meta::MetaschemaColumns::Key, "schema_hash");
|
|
|
|
|
|
- if hash.is_none() || hash.unwrap().value != self.schema_hash {
|
|
|
+ if hash.is_none() {
|
|
|
+ if !allow_recreate {
|
|
|
+ return Err(DBError::NoSchema)
|
|
|
+ }
|
|
|
+ self.create_schema();
|
|
|
+ }
|
|
|
+ else if hash.unwrap().value != self.schema_hash {
|
|
|
if !allow_recreate {
|
|
|
- return Err("No schema version in database, and not allowed to create!")
|
|
|
+ return Err(DBError::DifferentSchema)
|
|
|
}
|
|
|
self.create_schema();
|
|
|
}
|
|
@@ -127,15 +151,15 @@ impl DB {
|
|
|
Ok(())
|
|
|
}
|
|
|
|
|
|
- fn create_schema(&self) -> Result<(), &'static str> {
|
|
|
+ fn create_schema(&self) -> Result<(), DBError> {
|
|
|
for ds in self.schema.drop() {
|
|
|
let prepared = self.conn.prepare(ds);
|
|
|
- prepared.unwrap().execute([]).expect("Dropping sql failed");
|
|
|
+ prepared.unwrap().execute([]).map_err(|e| DBError::DropFailure);
|
|
|
}
|
|
|
|
|
|
for cs in self.schema.create() {
|
|
|
let prepared = self.conn.prepare(cs);
|
|
|
- prepared.unwrap().execute([]).expect("Creation sql failed");
|
|
|
+ prepared.unwrap().execute([]).map_err(|e| DBError::CreateFailure);
|
|
|
}
|
|
|
|
|
|
query::add(
|
|
@@ -148,6 +172,7 @@ impl DB {
|
|
|
|
|
|
let sanity_check = query::get_one_by(self, meta::MetaschemaColumns::Key, "schema_hash");
|
|
|
assert_eq!(sanity_check.is_some(), true);
|
|
|
+ assert_eq!(sanity_check.unwrap().value, self.schema_hash);
|
|
|
|
|
|
Ok(())
|
|
|
}
|