mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 16:56:36 -04:00
migrate the schema11 usages to new structs/sql queries
This commit is contained in:
parent
e2b978e7cb
commit
32bc1e88eb
8 changed files with 88 additions and 83 deletions
|
@ -380,7 +380,7 @@ where
|
||||||
renamed: &HashMap<String, String>,
|
renamed: &HashMap<String, String>,
|
||||||
) -> Result<HashSet<String>> {
|
) -> Result<HashSet<String>> {
|
||||||
let mut referenced_files = HashSet::new();
|
let mut referenced_files = HashSet::new();
|
||||||
let note_types = self.ctx.storage.get_all_notetypes_as_schema11()?;
|
let note_types = self.ctx.storage.get_all_notetype_core()?;
|
||||||
let mut collection_modified = false;
|
let mut collection_modified = false;
|
||||||
|
|
||||||
for_every_note(&self.ctx.storage.db, |note| {
|
for_every_note(&self.ctx.storage.db, |note| {
|
||||||
|
@ -401,7 +401,7 @@ where
|
||||||
&self.mgr.media_folder,
|
&self.mgr.media_folder,
|
||||||
)? {
|
)? {
|
||||||
// note was modified, needs saving
|
// note was modified, needs saving
|
||||||
set_note(&self.ctx.storage.db, note, nt)?;
|
set_note(&self.ctx.storage.db, note, nt.sort_field_idx())?;
|
||||||
collection_modified = true;
|
collection_modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::err::{AnkiError, DBErrorKind, Result};
|
||||||
use crate::notetype::NoteTypeID;
|
use crate::notetype::NoteTypeID;
|
||||||
use crate::text::strip_html_preserving_image_filenames;
|
use crate::text::strip_html_preserving_image_filenames;
|
||||||
use crate::timestamp::TimestampSecs;
|
use crate::timestamp::TimestampSecs;
|
||||||
use crate::{define_newtype, notetype::NoteTypeSchema11, types::Usn};
|
use crate::{define_newtype, types::Usn};
|
||||||
use rusqlite::{params, Connection, Row, NO_PARAMS};
|
use rusqlite::{params, Connection, Row, NO_PARAMS};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
|
@ -84,27 +84,21 @@ fn row_to_note(row: &Row) -> Result<Note> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn set_note(
|
pub(super) fn set_note(db: &Connection, note: &mut Note, sort_field_idx: usize) -> Result<()> {
|
||||||
db: &Connection,
|
|
||||||
note: &mut Note,
|
|
||||||
note_type: &NoteTypeSchema11,
|
|
||||||
) -> Result<()> {
|
|
||||||
note.mtime = TimestampSecs::now();
|
note.mtime = TimestampSecs::now();
|
||||||
// hard-coded for now
|
// hard-coded for now
|
||||||
note.usn = Usn(-1);
|
note.usn = Usn(-1);
|
||||||
let field1_nohtml = strip_html_preserving_image_filenames(¬e.fields()[0]);
|
let field1_nohtml = strip_html_preserving_image_filenames(¬e.fields()[0]);
|
||||||
let csum = field_checksum(field1_nohtml.as_ref());
|
let csum = field_checksum(field1_nohtml.as_ref());
|
||||||
let sort_field = if note_type.sortf == 0 {
|
let sort_field = if sort_field_idx == 0 {
|
||||||
field1_nohtml
|
field1_nohtml
|
||||||
} else {
|
} else {
|
||||||
strip_html_preserving_image_filenames(
|
strip_html_preserving_image_filenames(note.fields().get(sort_field_idx).ok_or_else(
|
||||||
note.fields()
|
|| AnkiError::DBError {
|
||||||
.get(note_type.sortf as usize)
|
info: "sort field out of range".to_string(),
|
||||||
.ok_or_else(|| AnkiError::DBError {
|
kind: DBErrorKind::MissingEntity,
|
||||||
info: "sort field out of range".to_string(),
|
},
|
||||||
kind: DBErrorKind::MissingEntity,
|
)?)
|
||||||
})?,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut stmt =
|
let mut stmt =
|
||||||
|
|
|
@ -37,6 +37,7 @@ pub(crate) const DEFAULT_LATEX_HEADER: &str = r#"\documentclass[12pt]{article}
|
||||||
pub(crate) const DEFAULT_LATEX_FOOTER: &str = r#"\end{document}"#;
|
pub(crate) const DEFAULT_LATEX_FOOTER: &str = r#"\end{document}"#;
|
||||||
|
|
||||||
// other: vec![], // fixme: ensure empty map converted to empty bytes
|
// other: vec![], // fixme: ensure empty map converted to empty bytes
|
||||||
|
// fixme: rollback savepoint when tags not changed
|
||||||
|
|
||||||
impl NoteType {
|
impl NoteType {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
@ -53,6 +54,14 @@ impl NoteType {
|
||||||
NoteTypeID(self.id)
|
NoteTypeID(self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sort_field_idx(&self) -> usize {
|
||||||
|
self.config.as_ref().unwrap().sort_field_idx as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn latex_uses_svg(&self) -> bool {
|
||||||
|
self.config.as_ref().unwrap().latex_svg
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn ensure_names_unique(&mut self) {
|
pub(crate) fn ensure_names_unique(&mut self) {
|
||||||
let mut names = HashSet::new();
|
let mut names = HashSet::new();
|
||||||
for t in &mut self.templates {
|
for t in &mut self.templates {
|
||||||
|
|
|
@ -267,27 +267,16 @@ impl SqlWriter<'_> {
|
||||||
write!(self.sql, "c.ord = {}", n).unwrap();
|
write!(self.sql, "c.ord = {}", n).unwrap();
|
||||||
}
|
}
|
||||||
TemplateKind::Name(name) => {
|
TemplateKind::Name(name) => {
|
||||||
let note_types = self.col.storage.get_all_notetypes_as_schema11()?;
|
if let Some(glob) = glob_to_re(name) {
|
||||||
let mut id_ords = vec![];
|
self.sql.push_str(
|
||||||
for nt in note_types.values() {
|
"(n.mid,c.ord) in (select ntid,ord from templates where name regexp ?)",
|
||||||
for tmpl in &nt.tmpls {
|
);
|
||||||
if matches_wildcard(&tmpl.name, name) {
|
self.args.push(glob);
|
||||||
id_ords.push((nt.id, tmpl.ord));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sort for the benefit of unit tests
|
|
||||||
id_ords.sort();
|
|
||||||
|
|
||||||
if id_ords.is_empty() {
|
|
||||||
self.sql.push_str("false");
|
|
||||||
} else {
|
} else {
|
||||||
let v: Vec<_> = id_ords
|
self.sql.push_str(
|
||||||
.iter()
|
"(n.mid,c.ord) in (select ntid,ord from templates where name = ?)",
|
||||||
.map(|(ntid, ord)| format!("(n.mid = {} and c.ord = {})", ntid, ord))
|
);
|
||||||
.collect();
|
self.args.push(name.to_string());
|
||||||
write!(self.sql, "({})", v.join(" or ")).unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -295,29 +284,27 @@ impl SqlWriter<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_note_type(&mut self, nt_name: &str) -> Result<()> {
|
fn write_note_type(&mut self, nt_name: &str) -> Result<()> {
|
||||||
let mut ntids: Vec<_> = self
|
if let Some(glob) = glob_to_re(nt_name) {
|
||||||
.col
|
self.sql
|
||||||
.storage
|
.push_str("n.mid in (select id from notetypes where name regexp ?)");
|
||||||
.get_all_notetypes_as_schema11()?
|
self.args.push(glob);
|
||||||
.values()
|
} else {
|
||||||
.filter(|nt| matches_wildcard(&nt.name, nt_name))
|
self.sql
|
||||||
.map(|nt| nt.id)
|
.push_str("n.mid in (select id from notetypes where name = ?)");
|
||||||
.collect();
|
self.args.push(nt_name.to_string());
|
||||||
self.sql.push_str("n.mid in ");
|
}
|
||||||
// sort for the benefit of unit tests
|
|
||||||
ntids.sort();
|
|
||||||
ids_to_string(&mut self.sql, &ntids);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_single_field(&mut self, field_name: &str, val: &str, is_re: bool) -> Result<()> {
|
fn write_single_field(&mut self, field_name: &str, val: &str, is_re: bool) -> Result<()> {
|
||||||
let note_types = self.col.storage.get_all_notetypes_as_schema11()?;
|
let note_types = self.col.storage.get_all_notetype_core()?;
|
||||||
|
|
||||||
let mut field_map = vec![];
|
let mut field_map = vec![];
|
||||||
for nt in note_types.values() {
|
for nt in note_types.values() {
|
||||||
for field in &nt.flds {
|
let fields = self.col.storage.get_notetype_fields(nt.id())?;
|
||||||
|
for field in &fields {
|
||||||
if matches_wildcard(&field.name, field_name) {
|
if matches_wildcard(&field.name, field_name) {
|
||||||
field_map.push((nt.id, field.ord));
|
field_map.push((nt.id(), field.ord));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -539,18 +526,11 @@ mod test {
|
||||||
assert_eq!(s(ctx, "deck:filtered"), ("(c.odid > 0)".into(), vec![],));
|
assert_eq!(s(ctx, "deck:filtered"), ("(c.odid > 0)".into(), vec![],));
|
||||||
|
|
||||||
// card
|
// card
|
||||||
assert_eq!(s(ctx, "card:front"), ("(false)".into(), vec![],));
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
s(ctx, r#""card:card 1""#),
|
s(ctx, r#""card:card 1""#),
|
||||||
(
|
(
|
||||||
concat!(
|
"((n.mid,c.ord) in (select ntid,ord from templates where name = ?))".into(),
|
||||||
"(((n.mid = 1581236385344 and c.ord = 0) or ",
|
vec!["card 1".into()]
|
||||||
"(n.mid = 1581236385345 and c.ord = 0) or ",
|
|
||||||
"(n.mid = 1581236385346 and c.ord = 0) or ",
|
|
||||||
"(n.mid = 1581236385347 and c.ord = 0)))"
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
vec![],
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -633,10 +613,19 @@ mod test {
|
||||||
);
|
);
|
||||||
|
|
||||||
// note types by name
|
// note types by name
|
||||||
assert_eq!(&s(ctx, "note:basic").0, "(n.mid in (1581236385347))");
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&s(ctx, "note:basic*").0,
|
s(ctx, "note:basic"),
|
||||||
"(n.mid in (1581236385345,1581236385346,1581236385347,1581236385344))"
|
(
|
||||||
|
"(n.mid in (select id from notetypes where name = ?))".into(),
|
||||||
|
vec!["basic".into()]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
s(ctx, "note:basic*"),
|
||||||
|
(
|
||||||
|
"(n.mid in (select id from notetypes where name regexp ?))".into(),
|
||||||
|
vec!["basic.*".into()]
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// regex
|
// regex
|
||||||
|
|
|
@ -5,3 +5,5 @@ select
|
||||||
from fields
|
from fields
|
||||||
where
|
where
|
||||||
ntid = ?
|
ntid = ?
|
||||||
|
order by
|
||||||
|
ord
|
|
@ -1,8 +1,7 @@
|
||||||
select
|
select
|
||||||
|
id,
|
||||||
name,
|
name,
|
||||||
mtime_secs,
|
mtime_secs,
|
||||||
usn,
|
usn,
|
||||||
config
|
config
|
||||||
from notetypes
|
from notetypes
|
||||||
where
|
|
||||||
id = ?
|
|
|
@ -7,3 +7,5 @@ select
|
||||||
from templates
|
from templates
|
||||||
where
|
where
|
||||||
ntid = ?
|
ntid = ?
|
||||||
|
order by
|
||||||
|
ord
|
|
@ -10,31 +10,41 @@ use crate::{
|
||||||
notetype::{NoteTypeID, NoteTypeSchema11},
|
notetype::{NoteTypeID, NoteTypeSchema11},
|
||||||
};
|
};
|
||||||
use prost::Message;
|
use prost::Message;
|
||||||
use rusqlite::{params, NO_PARAMS};
|
use rusqlite::{params, Row, NO_PARAMS};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use unicase::UniCase;
|
use unicase::UniCase;
|
||||||
|
|
||||||
|
fn row_to_notetype_core(row: &Row) -> Result<NoteType> {
|
||||||
|
let config = NoteTypeConfig::decode(row.get_raw(4).as_blob()?)?;
|
||||||
|
Ok(NoteType {
|
||||||
|
id: row.get(0)?,
|
||||||
|
name: row.get(1)?,
|
||||||
|
mtime_secs: row.get(2)?,
|
||||||
|
usn: row.get(3)?,
|
||||||
|
config: Some(config),
|
||||||
|
fields: vec![],
|
||||||
|
templates: vec![],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
impl SqliteStorage {
|
impl SqliteStorage {
|
||||||
fn get_notetype_core(&self, ntid: NoteTypeID) -> Result<Option<NoteType>> {
|
fn get_notetype_core(&self, ntid: NoteTypeID) -> Result<Option<NoteType>> {
|
||||||
self.db
|
self.db
|
||||||
.prepare_cached(include_str!("get_notetype.sql"))?
|
.prepare_cached(concat!(include_str!("get_notetype.sql"), " where id = ?"))?
|
||||||
.query_and_then(&[ntid], |row| {
|
.query_and_then(&[ntid], row_to_notetype_core)?
|
||||||
let config = NoteTypeConfig::decode(row.get_raw(3).as_blob()?)?;
|
|
||||||
Ok(NoteType {
|
|
||||||
id: ntid.0,
|
|
||||||
name: row.get(0)?,
|
|
||||||
mtime_secs: row.get(1)?,
|
|
||||||
usn: row.get(2)?,
|
|
||||||
config: Some(config),
|
|
||||||
fields: vec![],
|
|
||||||
templates: vec![],
|
|
||||||
})
|
|
||||||
})?
|
|
||||||
.next()
|
.next()
|
||||||
.transpose()
|
.transpose()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_notetype_fields(&self, ntid: NoteTypeID) -> Result<Vec<NoteField>> {
|
pub(crate) fn get_all_notetype_core(&self) -> Result<HashMap<NoteTypeID, NoteType>> {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_notetype_fields(&self, ntid: NoteTypeID) -> Result<Vec<NoteField>> {
|
||||||
self.db
|
self.db
|
||||||
.prepare_cached(include_str!("get_fields.sql"))?
|
.prepare_cached(include_str!("get_fields.sql"))?
|
||||||
.query_and_then(&[ntid], |row| {
|
.query_and_then(&[ntid], |row| {
|
||||||
|
|
Loading…
Reference in a new issue