aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/db/cards.rs160
-rw-r--r--src/db/mod.rs160
-rw-r--r--src/gui/mod.rs8
-rw-r--r--src/sync.rs8
4 files changed, 170 insertions, 166 deletions
diff --git a/src/db/cards.rs b/src/db/cards.rs
new file mode 100644
index 0000000..6d3e28d
--- /dev/null
+++ b/src/db/cards.rs
@@ -0,0 +1,160 @@
+use anyhow::Result;
+use rusqlite::{params, Connection};
+
+use crate::model::DbEntry;
+use crate::util::time;
+use crate::{
+ model::{Card, Question},
+ space_repetition,
+ util::serialization,
+};
+
+pub fn all(conn: &Connection) -> Result<Vec<DbEntry>> {
+ let mut stmt = conn.prepare("SELECT question, responses, deleted FROM cards")?;
+
+ let res: Result<Vec<DbEntry>, rusqlite::Error> = stmt
+ .query_map([], |row| {
+ let responses: String = row.get(1)?;
+ Ok(DbEntry {
+ question: row.get(0)?,
+ responses: serialization::line_to_words(&responses),
+ deleted: row.get(2)?,
+ })
+ })?
+ .collect();
+
+ Ok(res?)
+}
+
+pub fn insert(conn: &mut Connection, questions: &Vec<Question>) -> Result<()> {
+ let now = time::seconds_since_unix_epoch()?;
+ let state = serde_json::to_string(&space_repetition::init())?;
+
+ let tx = conn.transaction()?;
+ for Question {
+ question,
+ responses,
+ } in questions
+ {
+ let responses = serialization::words_to_line(responses);
+ tx.execute(
+ "
+ INSERT INTO cards (question, responses, state, created, ready)
+ VALUES (?, ?, ?, ?, ?)
+ ",
+ params![question, responses, state, now, now],
+ )?;
+ }
+ tx.commit()?;
+ Ok(())
+}
+
+pub fn delete(conn: &mut Connection, questions: &Vec<Question>) -> Result<()> {
+ let now = time::seconds_since_unix_epoch()?;
+
+ let tx = conn.transaction()?;
+ for Question {
+ question,
+ responses,
+ } in questions
+ {
+ let responses = serialization::words_to_line(responses);
+ tx.execute(
+ "UPDATE cards SET deleted = ? WHERE question = ? AND responses = ?",
+ params![now, question, responses],
+ )?;
+ }
+ tx.commit()?;
+ Ok(())
+}
+
+pub fn undelete(conn: &mut Connection, questions: &Vec<Question>) -> Result<()> {
+ let tx = conn.transaction()?;
+ for Question {
+ question,
+ responses,
+ } in questions
+ {
+ let responses = serialization::words_to_line(responses);
+ tx.execute(
+ "UPDATE cards SET deleted = NULL WHERE question = ? AND responses = ?",
+ params![question, responses],
+ )?;
+ }
+ tx.commit()?;
+ Ok(())
+}
+
+pub fn pick_random_ready(conn: &Connection) -> Option<Card> {
+ let now = time::seconds_since_unix_epoch().ok()?;
+
+ let mut stmt = conn
+ .prepare(
+ "
+ SELECT question, responses, state, ready
+ FROM cards
+ WHERE deleted IS NULL AND ready <= ?
+ ORDER BY RANDOM()
+ LIMIT 1
+ ",
+ )
+ .ok()?;
+
+ let mut rows = stmt.query([now]).ok()?;
+ let row = rows.next().ok()??;
+ let state_str: String = row.get(2).ok()?;
+ let responses_str: String = row.get(1).ok()?;
+
+ Some(Card {
+ question: row.get(0).ok()?,
+ responses: serialization::line_to_words(&responses_str),
+ state: serde_json::from_str(&state_str).ok()?,
+ ready: row.get(3).ok()?,
+ })
+}
+
+pub fn next_ready(conn: &Connection) -> Option<u64> {
+ let mut stmt = conn
+ .prepare(
+ "
+ SELECT ready
+ FROM cards
+ WHERE deleted IS NULL
+ ORDER BY ready
+ LIMIT 1
+ ",
+ )
+ .ok()?;
+
+ let mut rows = stmt.query([]).ok()?;
+ let row = rows.next().ok()??;
+ row.get(0).ok()?
+}
+
+pub fn count_available(conn: &Connection) -> Option<i32> {
+ let now = time::seconds_since_unix_epoch().ok()?;
+ let mut stmt = conn
+ .prepare("SELECT COUNT(*) FROM cards WHERE ready <= ? AND deleted IS NULL")
+ .ok()?;
+
+ let mut rows = stmt.query([now]).ok()?;
+ let row = rows.next().ok()??;
+ row.get(0).ok()?
+}
+
+pub fn update(conn: &Connection, question: &str, state: &space_repetition::State) -> Result<()> {
+ let now = time::seconds_since_unix_epoch()?;
+ let ready = now + state.get_interval_seconds();
+ let state_str = serde_json::to_string(state)?;
+
+ conn.execute(
+ "
+ UPDATE cards
+ SET state = ?, updated = ?, ready = ?
+ WHERE question = ?
+ ",
+ params![state_str, now, ready, question],
+ )?;
+
+ Ok(())
+}
diff --git a/src/db/mod.rs b/src/db/mod.rs
index 434d74a..54bf90f 100644
--- a/src/db/mod.rs
+++ b/src/db/mod.rs
@@ -1,14 +1,8 @@
use anyhow::Result;
-use rusqlite::{params, Connection};
+use rusqlite::Connection;
use rusqlite_migration::{Migrations, M};
-use crate::model::DbEntry;
-use crate::util::time;
-use crate::{
- model::{Card, Question},
- space_repetition,
- util::serialization,
-};
+pub mod cards;
pub fn init(database: String) -> Result<Connection> {
let mut conn = Connection::open(database)?;
@@ -20,153 +14,3 @@ pub fn init(database: String) -> Result<Connection> {
migrations.to_latest(&mut conn)?;
Ok(conn)
}
-
-pub fn all(conn: &Connection) -> Result<Vec<DbEntry>> {
- let mut stmt = conn.prepare("SELECT question, responses, deleted FROM cards")?;
-
- let res: Result<Vec<DbEntry>, rusqlite::Error> = stmt
- .query_map([], |row| {
- let responses: String = row.get(1)?;
- Ok(DbEntry {
- question: row.get(0)?,
- responses: serialization::line_to_words(&responses),
- deleted: row.get(2)?,
- })
- })?
- .collect();
-
- Ok(res?)
-}
-
-pub fn insert(conn: &mut Connection, questions: &Vec<Question>) -> Result<()> {
- let now = time::seconds_since_unix_epoch()?;
- let state = serde_json::to_string(&space_repetition::init())?;
-
- let tx = conn.transaction()?;
- for Question {
- question,
- responses,
- } in questions
- {
- let responses = serialization::words_to_line(responses);
- tx.execute(
- "
- INSERT INTO cards (question, responses, state, created, ready)
- VALUES (?, ?, ?, ?, ?)
- ",
- params![question, responses, state, now, now],
- )?;
- }
- tx.commit()?;
- Ok(())
-}
-
-pub fn delete(conn: &mut Connection, questions: &Vec<Question>) -> Result<()> {
- let now = time::seconds_since_unix_epoch()?;
-
- let tx = conn.transaction()?;
- for Question {
- question,
- responses,
- } in questions
- {
- let responses = serialization::words_to_line(responses);
- tx.execute(
- "UPDATE cards SET deleted = ? WHERE question = ? AND responses = ?",
- params![now, question, responses],
- )?;
- }
- tx.commit()?;
- Ok(())
-}
-
-pub fn undelete(conn: &mut Connection, questions: &Vec<Question>) -> Result<()> {
- let tx = conn.transaction()?;
- for Question {
- question,
- responses,
- } in questions
- {
- let responses = serialization::words_to_line(responses);
- tx.execute(
- "UPDATE cards SET deleted = NULL WHERE question = ? AND responses = ?",
- params![question, responses],
- )?;
- }
- tx.commit()?;
- Ok(())
-}
-
-pub fn pick_random_ready(conn: &Connection) -> Option<Card> {
- let now = time::seconds_since_unix_epoch().ok()?;
-
- let mut stmt = conn
- .prepare(
- "
- SELECT question, responses, state, ready
- FROM cards
- WHERE deleted IS NULL AND ready <= ?
- ORDER BY RANDOM()
- LIMIT 1
- ",
- )
- .ok()?;
-
- let mut rows = stmt.query([now]).ok()?;
- let row = rows.next().ok()??;
- let state_str: String = row.get(2).ok()?;
- let responses_str: String = row.get(1).ok()?;
-
- Some(Card {
- question: row.get(0).ok()?,
- responses: serialization::line_to_words(&responses_str),
- state: serde_json::from_str(&state_str).ok()?,
- ready: row.get(3).ok()?,
- })
-}
-
-pub fn next_ready(conn: &Connection) -> Option<u64> {
- let mut stmt = conn
- .prepare(
- "
- SELECT ready
- FROM cards
- WHERE deleted IS NULL
- ORDER BY ready
- LIMIT 1
- ",
- )
- .ok()?;
-
- let mut rows = stmt.query([]).ok()?;
- let row = rows.next().ok()??;
- row.get(0).ok()?
-}
-
-pub fn count_available(conn: &Connection) -> Option<i32> {
- let now = time::seconds_since_unix_epoch().ok()?;
- let mut stmt = conn
- .prepare("SELECT COUNT(*) FROM cards WHERE ready <= ? AND deleted IS NULL")
- .ok()?;
-
- let mut rows = stmt.query([now]).ok()?;
- let row = rows.next().ok()??;
- row.get(0).ok()?
-}
-
-pub fn update(conn: &Connection, question: &str, state: &space_repetition::State) -> Result<()> {
- let now = time::seconds_since_unix_epoch()?;
- let ready = now + state.get_interval_seconds();
- let state_str = serde_json::to_string(state)?;
-
- conn.execute(
- "
- UPDATE cards
- SET state = ?, updated = ?, ready = ?
- WHERE question = ?
- ",
- params![state_str, now, ready, question],
- )?;
-
- Ok(())
-}
diff --git a/src/gui/mod.rs b/src/gui/mod.rs
index 3abe238..d721b90 100644
--- a/src/gui/mod.rs
+++ b/src/gui/mod.rs
@@ -47,15 +47,15 @@ pub fn start(
let title = title(
deck_name,
- db::count_available(conn).unwrap_or(0),
+ db::cards::count_available(conn).unwrap_or(0),
hide_remaining,
);
- match db::pick_random_ready(conn) {
+ match db::cards::pick_random_ready(conn) {
Some(card) => match question::ask(term, &title, &card)? {
question::Response::Aborted => break,
question::Response::Answered { difficulty } => {
- db::update(
+ db::cards::update(
conn,
&card.question,
&space_repetition::update(card.state, difficulty),
@@ -63,7 +63,7 @@ pub fn start(
}
},
None => {
- let message = match db::next_ready(conn) {
+ let message = match db::cards::next_ready(conn) {
Some(ready) => {
let now = time::seconds_since_unix_epoch()?;
let duration = time::pp_duration(ready - now);
diff --git a/src/sync.rs b/src/sync.rs
index 974e838..f96d93a 100644
--- a/src/sync.rs
+++ b/src/sync.rs
@@ -8,7 +8,7 @@ use std::collections::HashMap;
use std::collections::HashSet;
pub fn run(conn: &mut Connection, deck_path: &str) -> Result<()> {
- let db_entries = db::all(conn)?;
+ let db_entries = db::cards::all(conn)?;
let lines = deck::read_file(deck_path)?;
let Diff {
new,
@@ -16,9 +16,9 @@ pub fn run(conn: &mut Connection, deck_path: &str) -> Result<()> {
undeleted,
} = diff(db_entries, lines);
- db::insert(conn, &new)?;
- db::delete(conn, &deleted)?;
- db::undelete(conn, &undeleted)?;
+ db::cards::insert(conn, &new)?;
+ db::cards::delete(conn, &deleted)?;
+ db::cards::undelete(conn, &undeleted)?;
Ok(())
}