Exam base
This commit is contained in:
1 parent
6628d79307
commit
4b9e257cdf
12 files changed
+183
-17
No files matched your search
@@ -0,0 +1,5 @@
|
||||
create table exams(
|
||||
id integer primary key,
|
||||
timestamp integer,
|
||||
deck_id integer not null references decks on delete cascade
|
||||
);
|
||||
@@ -0,0 +1,7 @@
|
||||
create table exam_entry
|
||||
(
|
||||
id integer primary key,
|
||||
exam_id integer not null references exam on delete cascade,
|
||||
word_id integer not null references words on delete cascade,
|
||||
status integer default null
|
||||
);
|
||||
+7
-1
@@ -18,6 +18,7 @@ use log::info;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use rusqlite::Connection;
|
||||
use std::sync::Arc;
|
||||
use crate::data_provider::exam::{ExamEntryRepository, ExamRepository};
|
||||
|
||||
pub const USER_FONT: Font = Font::with_name("Noto Sans JP");
|
||||
|
||||
@@ -70,6 +71,8 @@ pub struct AppState {
|
||||
pub connection: Arc<Mutex<SqliteConnection>>,
|
||||
pub sync_data: Arc<RwLock<AppSettings>>,
|
||||
pub history: HistoryRepository,
|
||||
pub exam: ExamRepository,
|
||||
pub exam_entries: ExamEntryRepository
|
||||
}
|
||||
|
||||
impl Default for AppState {
|
||||
@@ -87,7 +90,9 @@ impl AppState {
|
||||
word_groups: WordGroupRepository::new(connection.clone()),
|
||||
card_states: CardStateRepository::new(connection.clone()),
|
||||
history: HistoryRepository::new(connection.clone()),
|
||||
exam: ExamRepository::new(connection.clone()),
|
||||
custom_fields: CustomFieldRepository::new(connection.clone()),
|
||||
exam_entries: ExamEntryRepository::new(connection.clone()),
|
||||
sync_data: Arc::new(RwLock::new(AppSettings {
|
||||
key: None,
|
||||
auto_web_fetch: false,
|
||||
@@ -108,7 +113,8 @@ pub fn fill_state(state: &mut AppState) {
|
||||
state.history.write().start().unwrap();
|
||||
state.card_states.write().start().unwrap();
|
||||
state.custom_fields.write().start().unwrap();
|
||||
|
||||
state.exam.write().start().unwrap();
|
||||
state.exam_entries.write().start().unwrap();
|
||||
state.sync_data = Arc::new(RwLock::new(setting))
|
||||
}
|
||||
|
||||
|
||||
@@ -216,6 +216,40 @@ impl EntityData for CustomField {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Exam {
|
||||
pub id: Id,
|
||||
pub timestamp: DateTime<Utc>,
|
||||
pub deck_id: Id,
|
||||
}
|
||||
|
||||
impl EntityData for Exam {
|
||||
fn id(&self) -> Id {
|
||||
self.id
|
||||
}
|
||||
fn set_id(&mut self, id: Id) {
|
||||
self.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ExamEntry{
|
||||
pub id: Id,
|
||||
pub exam_id: Id,
|
||||
pub word_id: Id,
|
||||
pub status: Option<bool>
|
||||
}
|
||||
|
||||
impl EntityData for ExamEntry {
|
||||
fn id(&self) -> Id {
|
||||
self.id
|
||||
}
|
||||
|
||||
fn set_id(&mut self, id: Id) {
|
||||
self.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EntityHandle<E> {
|
||||
pub(crate) id: Id,
|
||||
index: u32,
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
use crate::data::Id;
|
||||
use crate::data::entities::CardState;
|
||||
use crate::data::repositories::{DataRepository, DataRepositoryInner, Query};
|
||||
use crate::data::Id;
|
||||
use crate::data_access_methods;
|
||||
use crate::data_provider::{SqliteDbLayer, TableAccessQuerySet};
|
||||
use chrono::NaiveDate;
|
||||
use fsrs::MemoryState;
|
||||
use rusqlite::{Error, Params, Row};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub type CardStateRepository = DataRepository<CardState, CardStateDbLayer>;
|
||||
pub type CardStateRepositoryInner = DataRepositoryInner<CardState, CardStateDbLayer>;
|
||||
pub type CardStateDbLayer = SqliteDbLayer<CardState, CardStatesQuerySet>;
|
||||
data_access_methods!(
|
||||
CardStateDbLayer,
|
||||
CardStateRepository,
|
||||
CardStateRepositoryInner,
|
||||
CardState,
|
||||
CardStatesQuerySet,
|
||||
CardStateQuery
|
||||
);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CardStatesQuerySet;
|
||||
impl TableAccessQuerySet<CardState> for CardStatesQuerySet {
|
||||
|
||||
@@ -2,10 +2,9 @@ use crate::data::entities::CustomField;
|
||||
use crate::data::repositories::{DataRepository, DataRepositoryInner};
|
||||
use crate::data_provider::{SqliteDbLayer, TableAccessQuerySet};
|
||||
use rusqlite::{Error, Params, Row};
|
||||
use crate::data_access_methods;
|
||||
|
||||
pub type CustomFieldRepository = DataRepository<CustomField, CustomFieldDbLayer>;
|
||||
pub type CustomFieldRepositoryInner = DataRepositoryInner<CustomField, CustomFieldDbLayer>;
|
||||
pub type CustomFieldDbLayer = SqliteDbLayer<CustomField, CustomFieldsQuerySet>;
|
||||
data_access_methods!(CustomFieldDbLayer, CustomFieldRepository, CustomFieldRepositoryInner, CustomField, CustomFieldsQuerySet, CustomFieldQuery);
|
||||
#[derive(Clone)]
|
||||
pub struct CustomFieldsQuerySet;
|
||||
impl TableAccessQuerySet<CustomField> for CustomFieldsQuerySet {
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
use crate::data::entities::{Exam, ExamEntry};
|
||||
use crate::data::repositories::*;
|
||||
use crate::data_access_methods;
|
||||
use crate::data_provider::{SqliteDbLayer, TableAccessQuerySet};
|
||||
use rusqlite::{Error, Params, Row};
|
||||
|
||||
data_access_methods!(
|
||||
ExamDataLayer,
|
||||
ExamRepository,
|
||||
ExamRepositoryInner,
|
||||
Exam,
|
||||
ExamQuerySet,
|
||||
ExamQuery
|
||||
);
|
||||
|
||||
data_access_methods!(
|
||||
ExamEntryLayer,
|
||||
ExamEntryRepository,
|
||||
ExamEntryRepositoryInner,
|
||||
ExamEntry,
|
||||
ExamEntryQuerySet,
|
||||
ExamEntryQuery
|
||||
);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ExamQuerySet;
|
||||
|
||||
impl TableAccessQuerySet<Exam> for ExamQuerySet {
|
||||
fn load() -> &'static str {
|
||||
"SELECT id, timestamp, deck_id FROM exams"
|
||||
}
|
||||
|
||||
fn save() -> &'static str {
|
||||
"UPDATE exams set deck_id = $1, timestamp = $2 WHERE id = $3"
|
||||
}
|
||||
|
||||
fn add() -> &'static str {
|
||||
"INSERT INTO exams (timestamp, deck_id) values ($1, $2)"
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"exams"
|
||||
}
|
||||
|
||||
fn from_sql(row: &Row) -> Result<Exam, Error> {
|
||||
Ok(Exam {
|
||||
id: row.get(0)?,
|
||||
timestamp: row.get(1)?,
|
||||
deck_id: row.get(2)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn insert_params(entity: &Exam) -> impl Params {
|
||||
(entity.timestamp.timestamp(), entity.deck_id)
|
||||
}
|
||||
|
||||
fn update_params(entity: &Exam) -> impl Params {
|
||||
(entity.timestamp.timestamp(), entity.deck_id, entity.id)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ExamEntryQuerySet;
|
||||
|
||||
impl TableAccessQuerySet<ExamEntry> for ExamEntryQuerySet {
|
||||
fn load() -> &'static str {
|
||||
"SELECT id, exam_id, word_id, status FROM exam_entry"
|
||||
}
|
||||
|
||||
fn save() -> &'static str {
|
||||
"UPDATE exam_entry set status = $1 WHERE id = $2"
|
||||
}
|
||||
|
||||
fn add() -> &'static str {
|
||||
"INSERT into exam_entry (exam_id, word_id, status) VALUES ($1, $2, $3)"
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"exam_entry"
|
||||
}
|
||||
|
||||
fn from_sql(row: &Row) -> Result<ExamEntry, Error> {
|
||||
Ok(ExamEntry {
|
||||
id: row.get(0)?,
|
||||
exam_id: row.get(1)?,
|
||||
word_id: row.get(2)?,
|
||||
status: row.get(3)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn insert_params(entity: &ExamEntry) -> impl Params {
|
||||
(entity.exam_id, entity.word_id, entity.status)
|
||||
}
|
||||
|
||||
fn update_params(entity: &ExamEntry) -> impl Params {
|
||||
(entity.status, entity.id)
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,9 @@ use crate::data::repositories::{DataRepository, DataRepositoryInner};
|
||||
use crate::data_provider::{SqliteDbLayer, TableAccessQuerySet};
|
||||
use rusqlite::types::{FromSql, FromSqlResult, ToSqlOutput, ValueRef};
|
||||
use rusqlite::{Error, Params, Row, ToSql};
|
||||
use crate::data_access_methods;
|
||||
|
||||
pub type HistoryRepository = DataRepository<HistoryNote, HistoryDataLayer>;
|
||||
pub type HistoryRepositoryInner = DataRepositoryInner<HistoryNote, HistoryDataLayer>;
|
||||
pub type HistoryDataLayer = SqliteDbLayer<HistoryNote, HistoryQuerySet>;
|
||||
data_access_methods!(HistoryDataLayer, HistoryRepository, HistoryRepositoryInner, HistoryNote, HistoryQuerySet, HistoryQuery);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct HistoryQuerySet;
|
||||
|
||||
@@ -19,6 +19,7 @@ pub(crate) mod voice;
|
||||
pub(crate) mod web_api;
|
||||
pub mod word_groups;
|
||||
pub(crate) mod words;
|
||||
pub(crate) mod exam;
|
||||
|
||||
pub trait TableAccessQuerySet<T> {
|
||||
fn load() -> &'static str;
|
||||
@@ -190,3 +191,12 @@ impl<T: EntityData, Q: TableAccessQuerySet<T>> BatchedDbLayer<T> for SqliteDbLay
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! data_access_methods {
|
||||
($layer:ident, $repo:ident, $repoinner:ident, $data:ty, $queryset:ty, $query:ident) => {
|
||||
pub type $repo = DataRepository<$data, $layer>;
|
||||
pub type $repoinner = DataRepositoryInner<$data, $layer>;
|
||||
pub type $layer = SqliteDbLayer<$data, $queryset>;
|
||||
};
|
||||
}
|
||||
@@ -2,10 +2,9 @@ use crate::data::entities::WordGroup;
|
||||
use crate::data::repositories::{DataRepository, DataRepositoryInner};
|
||||
use crate::data_provider::{SqliteDbLayer, TableAccessQuerySet};
|
||||
use rusqlite::{Error, Params, Row};
|
||||
use crate::data_access_methods;
|
||||
|
||||
pub type WordGroupRepository = DataRepository<WordGroup, WordGroupDataLayer>;
|
||||
pub type WordGroupRepositoryInner = DataRepositoryInner<WordGroup, WordGroupDataLayer>;
|
||||
pub type WordGroupDataLayer = SqliteDbLayer<WordGroup, WordGroupQuerySet>;
|
||||
data_access_methods!(WordGroupDataLayer, WordGroupRepository, WordGroupRepositoryInner, WordGroup, WordGroupQuerySet, WordGroupQuery);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WordGroupQuerySet;
|
||||
|
||||
@@ -4,10 +4,10 @@ use crate::data::repositories::{DataRepository, DataRepositoryInner};
|
||||
use crate::data_provider::{SqliteDbLayer, TableAccessQuerySet};
|
||||
use litemap::LiteMap;
|
||||
use rusqlite::{Error, Params, Row};
|
||||
use crate::data_access_methods;
|
||||
|
||||
data_access_methods!(WordDataLayer, WordRepository, WordRepositoryInner, WordData, WordQuerySet, WordQuery);
|
||||
|
||||
pub type WordRepository = DataRepository<WordData, WordDataLayer>;
|
||||
pub type WordRepositoryInner = DataRepositoryInner<WordData, WordDataLayer>;
|
||||
pub type WordDataLayer = SqliteDbLayer<WordData, WordQuerySet>;
|
||||
#[derive(Clone)]
|
||||
pub struct WordQuerySet;
|
||||
impl TableAccessQuerySet<WordData> for WordQuerySet {
|
||||
|
||||
@@ -218,6 +218,8 @@ impl SyncState {
|
||||
self.state.decks.write().reload()?;
|
||||
self.state.dictionary.write().reload()?;
|
||||
self.state.history.write().reload()?;
|
||||
self.state.exam.write().reload()?;
|
||||
self.state.exam_entries.write().reload()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user