Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 57 additions & 4 deletions teos/src/dbm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@ use std::iter::FromIterator;
use std::path::PathBuf;
use std::str::FromStr;

use rusqlite::ffi::{SQLITE_CONSTRAINT_FOREIGNKEY, SQLITE_CONSTRAINT_PRIMARYKEY};
use rusqlite::limits::Limit;
use rusqlite::{params, params_from_iter, Connection, Error as SqliteError};
use rusqlite::{params, params_from_iter, Connection, Error as SqliteError, ErrorCode, Params};

use bitcoin::consensus;
use bitcoin::hashes::Hash;
use bitcoin::secp256k1::SecretKey;
use bitcoin::BlockHash;

use teos_common::appointment::{Appointment, Locator};
use teos_common::dbm::{DatabaseConnection, DatabaseManager, Error};
use teos_common::appointment::{compute_appointment_slots, Appointment, Locator};
use teos_common::constants::ENCRYPTED_BLOB_MAX_SIZE;
use teos_common::UserId;

use crate::extended_appointment::{ExtendedAppointment, UUID};
Expand Down Expand Up @@ -64,6 +65,16 @@ const TABLES: [&str; 6] = [
)",
];

/// Packs the errors than can raise when interacting with the underlying database.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: typo "that"

#[derive(Debug)]
pub enum Error {
AlreadyExists,
MissingForeignKey,
MissingField,
NotFound,
Unknown(SqliteError),
}

/// Component in charge of interacting with the underlying database.
///
/// Currently works for `SQLite`. `PostgreSQL` should also be added in the future.
Expand All @@ -73,14 +84,56 @@ pub struct DBM {
connection: Connection,
}

impl DatabaseConnection for DBM {
impl DBM {
fn get_connection(&self) -> &Connection {
&self.connection
}

fn get_mut_connection(&mut self) -> &mut Connection {
&mut self.connection
}

/// Creates the database tables if not present.
fn create_tables(&mut self, tables: Vec<&str>) -> Result<(), SqliteError> {
let tx = self.get_mut_connection().transaction().unwrap();
for table in tables.iter() {
tx.execute(table, [])?;
}
tx.commit()
}

/// Generic method to store data into the database.
fn store_data<P: Params>(&self, query: &str, params: P) -> Result<(), Error> {
match self.get_connection().execute(query, params) {
Ok(_) => Ok(()),
Err(e) => match e {
SqliteError::SqliteFailure(ie, _) => match ie.code {
ErrorCode::ConstraintViolation => match ie.extended_code {
SQLITE_CONSTRAINT_FOREIGNKEY => Err(Error::MissingForeignKey),
SQLITE_CONSTRAINT_PRIMARYKEY => Err(Error::AlreadyExists),
_ => Err(Error::Unknown(e)),
},
_ => Err(Error::Unknown(e)),
},
_ => Err(Error::Unknown(e)),
},
}
}

/// Generic method to remove data from the database.
fn remove_data<P: Params>(&self, query: &str, params: P) -> Result<(), Error> {
match self.get_connection().execute(query, params).unwrap() {
0 => Err(Error::NotFound),
_ => Ok(()),
}
}

/// Generic method to update data from the database.
fn update_data<P: Params>(&self, query: &str, params: P) -> Result<(), Error> {
// Updating data is fundamentally the same as deleting it in terms of interface.
// A query is sent and either no row is modified or some rows are
self.remove_data(query, params)
}
}

impl DBM {
Expand Down