From 6b9378fb414629eb1635002a754fb96a2576465f Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Fri, 27 Mar 2020 14:39:38 +1000 Subject: [PATCH] add (unused) add_card, and move sql to separate files --- rslib/src/card.rs | 14 ++++- rslib/src/storage/card/add_card.sql | 54 ++++++++++++++++ rslib/src/storage/card/get_card.sql | 23 +++++++ rslib/src/storage/{card.rs => card/mod.rs} | 72 +++++++++++++++++----- rslib/src/storage/card/update_card.sql | 21 +++++++ rslib/src/storage/sqlite.rs | 4 +- 6 files changed, 169 insertions(+), 19 deletions(-) create mode 100644 rslib/src/storage/card/add_card.sql create mode 100644 rslib/src/storage/card/get_card.sql rename rslib/src/storage/{card.rs => card/mod.rs} (63%) create mode 100644 rslib/src/storage/card/update_card.sql diff --git a/rslib/src/card.rs b/rslib/src/card.rs index 1bff9466a..5b7bc08d6 100644 --- a/rslib/src/card.rs +++ b/rslib/src/card.rs @@ -87,12 +87,22 @@ impl Default for Card { } impl RequestContext<'_> { - pub fn update_card(&mut self, card: &mut Card) -> Result<()> { + pub(crate) fn update_card(&mut self, card: &mut Card) -> Result<()> { if card.id.0 == 0 { return Err(AnkiError::invalid_input("card id not set")); } card.mtime = TimestampSecs::now(); card.usn = self.storage.usn()?; - self.storage.flush_card(card) + self.storage.update_card(card) + } + + #[allow(dead_code)] + pub(crate) fn add_card(&mut self, card: &mut Card) -> Result<()> { + if card.id.0 != 0 { + return Err(AnkiError::invalid_input("card id already set")); + } + card.mtime = TimestampSecs::now(); + card.usn = self.storage.usn()?; + self.storage.add_card(card) } } diff --git a/rslib/src/storage/card/add_card.sql b/rslib/src/storage/card/add_card.sql new file mode 100644 index 000000000..5da46ac1f --- /dev/null +++ b/rslib/src/storage/card/add_card.sql @@ -0,0 +1,54 @@ +insert into cards ( + id, + nid, + did, + ord, + mod, + usn, + type, + queue, + due, + ivl, + factor, + reps, + lapses, + left, + odue, + odid, + flags, + data + ) +values + ( + ( + case + when ?1 in ( + select + id + from cards + ) then ( + select + max(id) + 1 + from cards + ) + else ?1 + end + ), + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ? + ) \ No newline at end of file diff --git a/rslib/src/storage/card/get_card.sql b/rslib/src/storage/card/get_card.sql new file mode 100644 index 000000000..a0f3cc13e --- /dev/null +++ b/rslib/src/storage/card/get_card.sql @@ -0,0 +1,23 @@ +-- the casts are required as Anki didn't prevent add-ons from +-- storing strings or floats in columns before +select + nid, + did, + ord, + cast(mod as integer), + usn, + type, + queue, + due, + cast(ivl as integer), + factor, + reps, + lapses, + left, + odue, + odid, + flags, + data +from cards +where + id = ? \ No newline at end of file diff --git a/rslib/src/storage/card.rs b/rslib/src/storage/card/mod.rs similarity index 63% rename from rslib/src/storage/card.rs rename to rslib/src/storage/card/mod.rs index fd3a40e68..0cae97c0e 100644 --- a/rslib/src/storage/card.rs +++ b/rslib/src/storage/card/mod.rs @@ -4,6 +4,7 @@ use super::sqlite::CachedStatementKind; use crate::card::{Card, CardID, CardQueue, CardType}; use crate::err::Result; +use crate::timestamp::TimestampMillis; use rusqlite::params; use rusqlite::{ types::{FromSql, FromSqlError, ValueRef}, @@ -33,14 +34,9 @@ impl FromSql for CardQueue { impl super::StorageContext<'_> { pub fn get_card(&mut self, cid: CardID) -> Result> { - // the casts are required as Anki didn't prevent add-ons from - // storing strings or floats in columns before self.with_cached_stmt( CachedStatementKind::GetCard, - " -select nid, did, ord, cast(mod as integer), usn, type, queue, due, -cast(ivl as integer), factor, reps, lapses, left, odue, odid, -flags, data from cards where id=?", + include_str!("get_card.sql"), |stmt| { stmt.query_row(params![cid], |row| { Ok(Card { @@ -70,19 +66,44 @@ flags, data from cards where id=?", ) } - pub(crate) fn flush_card(&mut self, card: &Card) -> Result<()> { + pub(crate) fn update_card(&mut self, card: &Card) -> Result<()> { self.with_cached_stmt( - CachedStatementKind::FlushCard, - " -insert or replace into cards -(id, nid, did, ord, mod, usn, type, queue, due, ivl, factor, -reps, lapses, left, odue, odid, flags, data) -values -(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) -", + CachedStatementKind::UpdateCard, + include_str!("update_card.sql"), |stmt| { stmt.execute(params![ + card.nid, + card.did, + card.ord, + card.mtime, + card.usn, + card.ctype as u8, + card.queue as i8, + card.due, + card.ivl, + card.factor, + card.reps, + card.lapses, + card.left, + card.odue, + card.odid, + card.flags, + card.data, card.id, + ])?; + Ok(()) + }, + ) + } + + pub(crate) fn add_card(&mut self, card: &mut Card) -> Result<()> { + let now = TimestampMillis::now().0; + self.with_cached_stmt( + CachedStatementKind::AddCard, + include_str!("add_card.sql"), + |stmt| { + stmt.execute(params![ + now, card.nid, card.did, card.ord, @@ -103,6 +124,25 @@ values ])?; Ok(()) }, - ) + )?; + card.id = CardID(self.db.last_insert_rowid()); + Ok(()) + } +} + +#[cfg(test)] +mod test { + use crate::{card::Card, storage::SqliteStorage}; + use std::path::Path; + + #[test] + fn add_card() { + let storage = SqliteStorage::open_or_create(Path::new(":memory:")).unwrap(); + let mut ctx = storage.context(false); + let mut card = Card::default(); + ctx.add_card(&mut card).unwrap(); + let id1 = card.id; + ctx.add_card(&mut card).unwrap(); + assert_ne!(id1, card.id); } } diff --git a/rslib/src/storage/card/update_card.sql b/rslib/src/storage/card/update_card.sql new file mode 100644 index 000000000..3c0f6bfc1 --- /dev/null +++ b/rslib/src/storage/card/update_card.sql @@ -0,0 +1,21 @@ +update cards +set + nid = ?, + did = ?, + ord = ?, + mod = ?, + usn = ?, + type = ?, + queue = ?, + due = ?, + ivl = ?, + factor = ?, + reps = ?, + lapses = ?, + left = ?, + odue = ?, + odid = ?, + flags = ?, + data = ? +where + id = ? \ No newline at end of file diff --git a/rslib/src/storage/sqlite.rs b/rslib/src/storage/sqlite.rs index d49ad3f20..6a07c3d05 100644 --- a/rslib/src/storage/sqlite.rs +++ b/rslib/src/storage/sqlite.rs @@ -205,9 +205,11 @@ impl SqliteStorage { } #[derive(Clone, Copy, VariantCount)] +#[allow(clippy::enum_variant_names)] pub(super) enum CachedStatementKind { GetCard, - FlushCard, + UpdateCard, + AddCard, } pub(crate) struct StorageContext<'a> {