Write SqlDbLayer
This commit is contained in:
1 parent
8ec7c8f05d
commit
45830a7985
7 files changed
+150
-19
No files matched your search
@@ -1,3 +1,14 @@
|
||||
use crate::core::srs::OrderMode;
|
||||
use crate::data::Id;
|
||||
use crate::data::entities::{DeckSettings, EntityData};
|
||||
use crate::data::repositories::{BatchedDbLayer, DbLayer};
|
||||
use crate::notification::MaybeError;
|
||||
use crate::notification::NotificationData::{DbLoadError, DbSaveError};
|
||||
use log::info;
|
||||
use rusqlite::{Connection, Params, Row, params};
|
||||
use std::marker::PhantomData;
|
||||
use std::time::Instant;
|
||||
|
||||
pub(crate) mod card_states;
|
||||
pub(crate) mod decks;
|
||||
pub(crate) mod history;
|
||||
@@ -7,3 +18,112 @@ pub(crate) mod sqlite;
|
||||
pub(crate) mod voice;
|
||||
pub(crate) mod web_api;
|
||||
pub(crate) mod words;
|
||||
|
||||
pub trait TableAccessQuerySet<T> {
|
||||
fn load() -> &'static str;
|
||||
fn save() -> &'static str;
|
||||
fn add() -> &'static str;
|
||||
fn name() -> &'static str;
|
||||
fn from_sql(row: &Row) -> T;
|
||||
fn insert_params(entity: &T) -> impl Params;
|
||||
fn update_params(entity: &T) -> impl Params;
|
||||
}
|
||||
|
||||
pub struct SqliteDbLayer<T, Q>
|
||||
where
|
||||
Q: TableAccessQuerySet<T>,
|
||||
{
|
||||
query_set: Q,
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: EntityData, Q: TableAccessQuerySet<T>> DbLayer<T> for SqliteDbLayer<T, Q> {
|
||||
fn write_entity(&self, entity: &T, connection: &Connection) -> MaybeError {
|
||||
connection
|
||||
.execute(Q::load(), Q::update_params(entity))
|
||||
.map_err(|_| DbSaveError)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_entity(&mut self, entity: &mut T, connection: &Connection) -> MaybeError {
|
||||
let index: u32 = connection
|
||||
.query_row(Q::add(), Q::insert_params(entity), |row| row.get(0))
|
||||
.map_err(|_| DbSaveError)?;
|
||||
|
||||
entity.set_id(index.into());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn delete_entity(&mut self, id: Id, connection: &Connection) -> MaybeError {
|
||||
if !id.is_valid() {
|
||||
return Err(DbSaveError);
|
||||
}
|
||||
connection
|
||||
.execute(
|
||||
format!("DELETE FROM {} WHERE id = ?1", Q::name()).as_str(),
|
||||
(&id,),
|
||||
)
|
||||
.map_err(|_| DbSaveError)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load_all(&self, storage: &mut Vec<T>, connection: &Connection) -> MaybeError {
|
||||
let mut stmt = connection
|
||||
.prepare(Q::load())
|
||||
.expect("Failed to prepare state query");
|
||||
let iter = stmt
|
||||
.query_map([], |row| Ok(Q::from_sql(row)))
|
||||
.map_err(|_| DbLoadError)?;
|
||||
|
||||
iter.filter_map(|res| res.ok())
|
||||
.for_each(|i| storage.push(i));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EntityData, Q: TableAccessQuerySet<T>> BatchedDbLayer<T> for SqliteDbLayer<T, Q> {
|
||||
fn delete_many_entities(&mut self, ids: &[Id], connection: &mut Connection) -> MaybeError {
|
||||
for chunk in ids.chunks(1000) {
|
||||
let stringed = chunk
|
||||
.iter()
|
||||
.map(|i| i.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(",");
|
||||
connection
|
||||
.execute(
|
||||
format!("DELETE FROM {} WHERE id in ({})", Q::name(), stringed).as_str(),
|
||||
(),
|
||||
)
|
||||
.map_err(|_| DbSaveError)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_many_entities(&mut self, entities: &mut [T], connection: &mut Connection) -> MaybeError {
|
||||
let time = Instant::now();
|
||||
let tx = connection
|
||||
.transaction()
|
||||
.expect("Failed to create transaction");
|
||||
let count = entities.len();
|
||||
|
||||
{
|
||||
let mut stmt = tx.prepare(Q::add()).expect("Failed to prepare state query");
|
||||
for entity in entities.iter() {
|
||||
stmt.execute(Q::insert_params(entity))
|
||||
.map_err(|_| DbSaveError)?;
|
||||
}
|
||||
}
|
||||
|
||||
let last_index: u32 = tx.last_insert_rowid() as u32;
|
||||
tx.commit().expect("Failed to commit");
|
||||
|
||||
let start_index = last_index - (count as u32) + 1;
|
||||
|
||||
for (index, id) in (start_index..=last_index).enumerate() {
|
||||
entities[index].set_id(id.into());
|
||||
}
|
||||
|
||||
info!("Added {} entities for {:?}", entities.len(), time.elapsed());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user