mirror of
https://github.com/ankitects/anki.git
synced 2026-01-15 14:59:00 -05:00
130 lines
3.7 KiB
Rust
130 lines
3.7 KiB
Rust
// Copyright: Ankitects Pty Ltd and contributors
|
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
use crate::card::{Card, CardID, CardQueue, CardType};
|
|
use crate::err::Result;
|
|
use crate::timestamp::TimestampMillis;
|
|
use rusqlite::params;
|
|
use rusqlite::{
|
|
types::{FromSql, FromSqlError, ValueRef},
|
|
OptionalExtension,
|
|
};
|
|
use std::convert::TryFrom;
|
|
|
|
impl FromSql for CardType {
|
|
fn column_result(value: ValueRef<'_>) -> std::result::Result<Self, FromSqlError> {
|
|
if let ValueRef::Integer(i) = value {
|
|
Ok(Self::try_from(i as u8).map_err(|_| FromSqlError::InvalidType)?)
|
|
} else {
|
|
Err(FromSqlError::InvalidType)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl FromSql for CardQueue {
|
|
fn column_result(value: ValueRef<'_>) -> std::result::Result<Self, FromSqlError> {
|
|
if let ValueRef::Integer(i) = value {
|
|
Ok(Self::try_from(i as i8).map_err(|_| FromSqlError::InvalidType)?)
|
|
} else {
|
|
Err(FromSqlError::InvalidType)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl super::SqliteStorage {
|
|
pub fn get_card(&self, cid: CardID) -> Result<Option<Card>> {
|
|
let mut stmt = self.db.prepare_cached(include_str!("get_card.sql"))?;
|
|
stmt.query_row(params![cid], |row| {
|
|
Ok(Card {
|
|
id: cid,
|
|
nid: row.get(0)?,
|
|
did: row.get(1)?,
|
|
ord: row.get(2)?,
|
|
mtime: row.get(3)?,
|
|
usn: row.get(4)?,
|
|
ctype: row.get(5)?,
|
|
queue: row.get(6)?,
|
|
due: row.get(7)?,
|
|
ivl: row.get(8)?,
|
|
factor: row.get(9)?,
|
|
reps: row.get(10)?,
|
|
lapses: row.get(11)?,
|
|
left: row.get(12)?,
|
|
odue: row.get(13)?,
|
|
odid: row.get(14)?,
|
|
flags: row.get(15)?,
|
|
data: row.get(16)?,
|
|
})
|
|
})
|
|
.optional()
|
|
.map_err(Into::into)
|
|
}
|
|
|
|
pub(crate) fn update_card(&self, card: &Card) -> Result<()> {
|
|
let mut stmt = self.db.prepare_cached(include_str!("update_card.sql"))?;
|
|
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(&self, card: &mut Card) -> Result<()> {
|
|
let now = TimestampMillis::now().0;
|
|
let mut stmt = self.db.prepare_cached(include_str!("add_card.sql"))?;
|
|
stmt.execute(params![
|
|
now,
|
|
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 = 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:"), false).unwrap();
|
|
let mut card = Card::default();
|
|
storage.add_card(&mut card).unwrap();
|
|
let id1 = card.id;
|
|
storage.add_card(&mut card).unwrap();
|
|
assert_ne!(id1, card.id);
|
|
}
|
|
}
|