store cached statements in a vec instead of separate optionals
This commit is contained in:
parent
369d2d89d9
commit
2f4e35d566
@ -39,6 +39,7 @@ slog-envlogger = "2.2.0"
|
||||
serde_repr = "0.1.5"
|
||||
num_enum = "0.4.2"
|
||||
unicase = "2.6.0"
|
||||
variant_count = "=1.0.0"
|
||||
|
||||
# pinned until rusqlite 0.22 comes out
|
||||
[target.'cfg(target_vendor="apple")'.dependencies.rusqlite]
|
||||
|
@ -52,7 +52,7 @@ pub struct Collection {
|
||||
}
|
||||
|
||||
pub(crate) enum CollectionOp {
|
||||
UpdateCard
|
||||
UpdateCard,
|
||||
}
|
||||
|
||||
pub(crate) struct RequestContext<'a> {
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
use crate::cached_sql;
|
||||
use super::sqlite::CachedStatementKind;
|
||||
use crate::card::{Card, CardID, CardQueue, CardType};
|
||||
use crate::err::Result;
|
||||
use rusqlite::params;
|
||||
@ -35,75 +35,74 @@ impl super::StorageContext<'_> {
|
||||
pub fn get_card(&mut self, cid: CardID) -> Result<Option<Card>> {
|
||||
// the casts are required as Anki didn't prevent add-ons from
|
||||
// storing strings or floats in columns before
|
||||
let stmt = cached_sql!(
|
||||
self.get_card_stmt,
|
||||
self.db,
|
||||
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=?"
|
||||
);
|
||||
|
||||
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)
|
||||
flags, data from cards where id=?",
|
||||
|stmt| {
|
||||
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 flush_card(&mut self, card: &Card) -> Result<()> {
|
||||
let stmt = cached_sql!(
|
||||
self.update_card_stmt,
|
||||
self.db,
|
||||
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
|
||||
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
"
|
||||
);
|
||||
|
||||
stmt.execute(params![
|
||||
card.id,
|
||||
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,
|
||||
])?;
|
||||
|
||||
Ok(())
|
||||
",
|
||||
|stmt| {
|
||||
stmt.execute(params![
|
||||
card.id,
|
||||
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,
|
||||
])?;
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ use std::{
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use unicase::UniCase;
|
||||
use variant_count::VariantCount;
|
||||
|
||||
const SCHEMA_MIN_VERSION: u8 = 11;
|
||||
const SCHEMA_MAX_VERSION: u8 = 11;
|
||||
@ -42,16 +43,6 @@ pub struct SqliteStorage {
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cached_sql {
|
||||
( $label:expr, $db:expr, $sql:expr ) => {{
|
||||
if $label.is_none() {
|
||||
$label = Some($db.prepare_cached($sql)?);
|
||||
}
|
||||
$label.as_mut().unwrap()
|
||||
}};
|
||||
}
|
||||
|
||||
fn open_or_create_collection_db(path: &Path) -> Result<Connection> {
|
||||
let mut db = Connection::open(path)?;
|
||||
|
||||
@ -213,6 +204,12 @@ impl SqliteStorage {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, VariantCount)]
|
||||
pub(super) enum CachedStatementKind {
|
||||
GetCard,
|
||||
FlushCard,
|
||||
}
|
||||
|
||||
pub(crate) struct StorageContext<'a> {
|
||||
pub(crate) db: &'a Connection,
|
||||
server: bool,
|
||||
@ -220,23 +217,38 @@ pub(crate) struct StorageContext<'a> {
|
||||
|
||||
timing_today: Option<SchedTimingToday>,
|
||||
|
||||
// cards
|
||||
pub(super) get_card_stmt: Option<rusqlite::CachedStatement<'a>>,
|
||||
pub(super) update_card_stmt: Option<rusqlite::CachedStatement<'a>>,
|
||||
cached_statements: Vec<Option<rusqlite::CachedStatement<'a>>>,
|
||||
}
|
||||
|
||||
impl StorageContext<'_> {
|
||||
fn new(db: &Connection, server: bool) -> StorageContext {
|
||||
let stmt_len = CachedStatementKind::VARIANT_COUNT;
|
||||
let mut statements = Vec::with_capacity(stmt_len);
|
||||
statements.resize_with(stmt_len, Default::default);
|
||||
StorageContext {
|
||||
db,
|
||||
server,
|
||||
usn: None,
|
||||
timing_today: None,
|
||||
get_card_stmt: None,
|
||||
update_card_stmt: None,
|
||||
cached_statements: statements,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn with_cached_stmt<F, T>(
|
||||
&mut self,
|
||||
kind: CachedStatementKind,
|
||||
sql: &str,
|
||||
func: F,
|
||||
) -> Result<T>
|
||||
where
|
||||
F: FnOnce(&mut rusqlite::CachedStatement) -> Result<T>,
|
||||
{
|
||||
if self.cached_statements[kind as usize].is_none() {
|
||||
self.cached_statements[kind as usize] = Some(self.db.prepare_cached(sql)?);
|
||||
}
|
||||
func(self.cached_statements[kind as usize].as_mut().unwrap())
|
||||
}
|
||||
|
||||
// Standard transaction start/stop
|
||||
//////////////////////////////////////
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user