diff --git a/rslib/src/collection.rs b/rslib/src/collection.rs index a9c43a79b..6406c751d 100644 --- a/rslib/src/collection.rs +++ b/rslib/src/collection.rs @@ -7,11 +7,12 @@ use crate::log::Logger; use crate::timestamp::TimestampSecs; use crate::types::Usn; use crate::{ + notetype::{NoteType, NoteTypeID}, sched::cutoff::{sched_timing_today, SchedTimingToday}, storage::SqliteStorage, undo::UndoManager, }; -use std::path::PathBuf; +use std::{collections::HashMap, path::PathBuf, sync::Arc}; pub fn open_collection>( path: P, @@ -50,6 +51,7 @@ pub struct CollectionState { task_state: CollectionTaskState, pub(crate) undo: UndoManager, timing_today: Option, + pub(crate) notetype_cache: HashMap>, } #[derive(Debug, PartialEq)] diff --git a/rslib/src/media/check.rs b/rslib/src/media/check.rs index 58c91f045..d250722c8 100644 --- a/rslib/src/media/check.rs +++ b/rslib/src/media/check.rs @@ -380,7 +380,7 @@ where renamed: &HashMap, ) -> Result> { let mut referenced_files = HashSet::new(); - let note_types = self.ctx.storage.get_all_notetype_core()?; + let note_types = self.ctx.get_all_notetypes()?; let mut collection_modified = false; let nids = self.ctx.search_notes("")?; diff --git a/rslib/src/notetype/mod.rs b/rslib/src/notetype/mod.rs index d5ad7a583..d21da9846 100644 --- a/rslib/src/notetype/mod.rs +++ b/rslib/src/notetype/mod.rs @@ -30,7 +30,10 @@ use crate::{ timestamp::TimestampSecs, types::Usn, }; -use std::collections::{HashMap, HashSet}; +use std::{ + collections::{HashMap, HashSet}, + sync::Arc, +}; use unicase::UniCase; define_newtype!(NoteTypeID, i64); @@ -200,11 +203,45 @@ impl Collection { .get_notetype(nt.id)? .ok_or_else(|| AnkiError::invalid_input("no such notetype"))?; col.update_notes_for_changed_fields(nt, existing_notetype.fields.len())?; + // fixme: card templates + // fixme: update cache instead of clearing + col.state.notetype_cache.remove(&nt.id); + Ok(()) }) } - pub fn get_notetype_by_name(&mut self, name: &str) -> Result> { - self.storage.get_notetype_by_name(name) + pub fn get_notetype_by_name(&mut self, name: &str) -> Result>> { + if let Some(ntid) = self.storage.get_notetype_id(name)? { + self.get_notetype(ntid) + } else { + Ok(None) + } + } + + pub fn get_notetype(&mut self, ntid: NoteTypeID) -> Result>> { + if let Some(nt) = self.state.notetype_cache.get(&ntid) { + return Ok(Some(nt.clone())); + } + if let Some(nt) = self.storage.get_notetype(ntid)? { + let nt = Arc::new(nt); + self.state.notetype_cache.insert(ntid, nt.clone()); + Ok(Some(nt)) + } else { + Ok(None) + } + } + + pub fn get_all_notetypes(&mut self) -> Result>> { + self.storage + .get_all_notetype_names()? + .into_iter() + .map(|(ntid, _)| { + self.get_notetype(ntid) + .transpose() + .unwrap() + .map(|nt| (ntid, nt)) + }) + .collect() } } diff --git a/rslib/src/search/sqlwriter.rs b/rslib/src/search/sqlwriter.rs index 66c09dc7e..9026e4aa6 100644 --- a/rslib/src/search/sqlwriter.rs +++ b/rslib/src/search/sqlwriter.rs @@ -297,12 +297,11 @@ impl SqlWriter<'_> { } fn write_single_field(&mut self, field_name: &str, val: &str, is_re: bool) -> Result<()> { - let note_types = self.col.storage.get_all_notetype_core()?; + let note_types = self.col.get_all_notetypes()?; let mut field_map = vec![]; for nt in note_types.values() { - let fields = self.col.storage.get_notetype_fields(nt.id)?; - for field in &fields { + for field in &nt.fields { if matches_wildcard(&field.name, field_name) { field_map.push((nt.id, field.ord)); } diff --git a/rslib/src/storage/notetype/mod.rs b/rslib/src/storage/notetype/mod.rs index b5b7734c7..072e485c6 100644 --- a/rslib/src/storage/notetype/mod.rs +++ b/rslib/src/storage/notetype/mod.rs @@ -46,21 +46,7 @@ impl SqliteStorage { .transpose() } - pub(crate) fn get_all_notetype_core(&self) -> Result> { - let mut nts: HashMap = self - .db - .prepare_cached(include_str!("get_notetype.sql"))? - .query_and_then(NO_PARAMS, row_to_notetype_core)? - .map(|ntres| ntres.map(|nt| (nt.id, nt))) - .collect::>()?; - for nt in nts.values_mut() { - nt.fields = self.get_notetype_fields(nt.id)?; - } - Ok(nts) - } - - // pub as currently used by searching code - pub(crate) fn get_notetype_fields(&self, ntid: NoteTypeID) -> Result> { + fn get_notetype_fields(&self, ntid: NoteTypeID) -> Result> { self.db .prepare_cached(include_str!("get_fields.sql"))? .query_and_then(&[ntid], |row| { @@ -90,7 +76,7 @@ impl SqliteStorage { .collect() } - fn get_notetype_id(&self, name: &str) -> Result> { + pub(crate) fn get_notetype_id(&self, name: &str) -> Result> { self.db .prepare_cached("select id from notetypes where name = ?")? .query_row(params![name], |row| row.get(0)) @@ -98,16 +84,7 @@ impl SqliteStorage { .map_err(Into::into) } - pub fn get_notetype_by_name(&mut self, name: &str) -> Result> { - if let Some(id) = self.get_notetype_id(name)? { - self.get_notetype(id) - } else { - Ok(None) - } - } - - #[allow(dead_code)] - fn get_all_notetype_names(&self) -> Result> { + pub fn get_all_notetype_names(&self) -> Result> { self.db .prepare_cached(include_str!("get_notetype_names.sql"))? .query_and_then(NO_PARAMS, |row| Ok((row.get(0)?, row.get(1)?)))?