rename some card+note fields in backend

This commit is contained in:
Damien Elmes 2020-08-31 17:09:49 +10:00
parent d3dede057a
commit a834df60ce
18 changed files with 197 additions and 181 deletions

View file

@ -408,7 +408,7 @@ message CardTemplate {
message Note { message Note {
int64 id = 1; int64 id = 1;
string guid = 2; string guid = 2;
int64 ntid = 3; int64 notetype_id = 3;
uint32 mtime_secs = 4; uint32 mtime_secs = 4;
int32 usn = 5; int32 usn = 5;
repeated string tags = 6; repeated string tags = 6;
@ -417,21 +417,21 @@ message Note {
message Card { message Card {
int64 id = 1; int64 id = 1;
int64 nid = 2; int64 note_id = 2;
int64 did = 3; int64 deck_id = 3;
uint32 ord = 4; uint32 template_idx = 4;
int64 mtime = 5; int64 mtime_secs = 5;
sint32 usn = 6; sint32 usn = 6;
uint32 ctype = 7; uint32 ctype = 7;
sint32 queue = 8; sint32 queue = 8;
sint32 due = 9; sint32 due = 9;
uint32 ivl = 10; uint32 interval = 10;
uint32 factor = 11; uint32 ease_factor = 11;
uint32 reps = 12; uint32 reps = 12;
uint32 lapses = 13; uint32 lapses = 13;
uint32 left = 14; uint32 remaining_steps = 14;
sint32 odue = 15; sint32 original_due = 15;
int64 odid = 16; int64 original_deck_id = 16;
uint32 flags = 17; uint32 flags = 17;
string data = 18; string data = 18;
} }

View file

@ -56,21 +56,21 @@ class Card:
self._render_output = None self._render_output = None
self._note = None self._note = None
self.id = c.id self.id = c.id
self.nid = c.nid self.nid = c.note_id
self.did = c.did self.did = c.deck_id
self.ord = c.ord self.ord = c.template_idx
self.mod = c.mtime self.mod = c.mtime_secs
self.usn = c.usn self.usn = c.usn
self.type = c.ctype self.type = c.ctype
self.queue = c.queue self.queue = c.queue
self.due = c.due self.due = c.due
self.ivl = c.ivl self.ivl = c.interval
self.factor = c.factor self.factor = c.ease_factor
self.reps = c.reps self.reps = c.reps
self.lapses = c.lapses self.lapses = c.lapses
self.left = c.left self.left = c.remaining_steps
self.odue = c.odue self.odue = c.original_due
self.odid = c.odid self.odid = c.original_deck_id
self.flags = c.flags self.flags = c.flags
self.data = c.data self.data = c.data
@ -88,19 +88,19 @@ class Card:
# mtime & usn are set by backend # mtime & usn are set by backend
card = BackendCard( card = BackendCard(
id=self.id, id=self.id,
nid=self.nid, note_id=self.nid,
did=self.did, deck_id=self.did,
ord=self.ord, template_idx=self.ord,
ctype=self.type, ctype=self.type,
queue=self.queue, queue=self.queue,
due=self.due, due=self.due,
ivl=self.ivl, interval=self.ivl,
factor=self.factor, ease_factor=self.factor,
reps=self.reps, reps=self.reps,
lapses=self.lapses, lapses=self.lapses,
left=self.left, remaining_steps=self.left,
odue=self.odue, original_due=self.odue,
odid=self.odid, original_deck_id=self.odid,
flags=self.flags, flags=self.flags,
data=self.data, data=self.data,
) )

View file

@ -44,7 +44,7 @@ class Note:
def _load_from_backend_note(self, n: BackendNote) -> None: def _load_from_backend_note(self, n: BackendNote) -> None:
self.id = n.id self.id = n.id
self.guid = n.guid self.guid = n.guid
self.mid = n.ntid self.mid = n.notetype_id
self.mod = n.mtime_secs self.mod = n.mtime_secs
self.usn = n.usn self.usn = n.usn
self.tags = list(n.tags) self.tags = list(n.tags)
@ -56,7 +56,7 @@ class Note:
return BackendNote( return BackendNote(
id=self.id, id=self.id,
guid=self.guid, guid=self.guid,
ntid=self.mid, notetype_id=self.mid,
mtime_secs=self.mod, mtime_secs=self.mod,
usn=self.usn, usn=self.usn,
tags=self.tags, tags=self.tags,

View file

@ -1755,21 +1755,21 @@ impl From<Card> for pb::Card {
fn from(c: Card) -> Self { fn from(c: Card) -> Self {
pb::Card { pb::Card {
id: c.id.0, id: c.id.0,
nid: c.nid.0, note_id: c.note_id.0,
did: c.did.0, deck_id: c.deck_id.0,
ord: c.ord as u32, template_idx: c.template_idx as u32,
mtime: c.mtime.0, mtime_secs: c.mtime.0,
usn: c.usn.0, usn: c.usn.0,
ctype: c.ctype as u32, ctype: c.ctype as u32,
queue: c.queue as i32, queue: c.queue as i32,
due: c.due, due: c.due,
ivl: c.ivl, interval: c.interval,
factor: c.factor as u32, ease_factor: c.ease_factor as u32,
reps: c.reps, reps: c.reps,
lapses: c.lapses, lapses: c.lapses,
left: c.left, remaining_steps: c.remaining_steps,
odue: c.odue, original_due: c.original_due,
odid: c.odid.0, original_deck_id: c.original_deck_id.0,
flags: c.flags as u32, flags: c.flags as u32,
data: c.data, data: c.data,
} }
@ -1783,21 +1783,21 @@ fn pbcard_to_native(c: pb::Card) -> Result<Card> {
.map_err(|_| AnkiError::invalid_input("invalid card queue"))?; .map_err(|_| AnkiError::invalid_input("invalid card queue"))?;
Ok(Card { Ok(Card {
id: CardID(c.id), id: CardID(c.id),
nid: NoteID(c.nid), note_id: NoteID(c.note_id),
did: DeckID(c.did), deck_id: DeckID(c.deck_id),
ord: c.ord as u16, template_idx: c.template_idx as u16,
mtime: TimestampSecs(c.mtime), mtime: TimestampSecs(c.mtime_secs),
usn: Usn(c.usn), usn: Usn(c.usn),
ctype, ctype,
queue, queue,
due: c.due, due: c.due,
ivl: c.ivl, interval: c.interval,
factor: c.factor as u16, ease_factor: c.ease_factor as u16,
reps: c.reps, reps: c.reps,
lapses: c.lapses, lapses: c.lapses,
left: c.left, remaining_steps: c.remaining_steps,
odue: c.odue, original_due: c.original_due,
odid: DeckID(c.odid), original_deck_id: DeckID(c.original_deck_id),
flags: c.flags as u8, flags: c.flags as u8,
data: c.data, data: c.data,
}) })

View file

@ -52,21 +52,21 @@ pub enum CardQueue {
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Card { pub struct Card {
pub(crate) id: CardID, pub(crate) id: CardID,
pub(crate) nid: NoteID, pub(crate) note_id: NoteID,
pub(crate) did: DeckID, pub(crate) deck_id: DeckID,
pub(crate) ord: u16, pub(crate) template_idx: u16,
pub(crate) mtime: TimestampSecs, pub(crate) mtime: TimestampSecs,
pub(crate) usn: Usn, pub(crate) usn: Usn,
pub(crate) ctype: CardType, pub(crate) ctype: CardType,
pub(crate) queue: CardQueue, pub(crate) queue: CardQueue,
pub(crate) due: i32, pub(crate) due: i32,
pub(crate) ivl: u32, pub(crate) interval: u32,
pub(crate) factor: u16, pub(crate) ease_factor: u16,
pub(crate) reps: u32, pub(crate) reps: u32,
pub(crate) lapses: u32, pub(crate) lapses: u32,
pub(crate) left: u32, pub(crate) remaining_steps: u32,
pub(crate) odue: i32, pub(crate) original_due: i32,
pub(crate) odid: DeckID, pub(crate) original_deck_id: DeckID,
pub(crate) flags: u8, pub(crate) flags: u8,
pub(crate) data: String, pub(crate) data: String,
} }
@ -75,21 +75,21 @@ impl Default for Card {
fn default() -> Self { fn default() -> Self {
Self { Self {
id: CardID(0), id: CardID(0),
nid: NoteID(0), note_id: NoteID(0),
did: DeckID(0), deck_id: DeckID(0),
ord: 0, template_idx: 0,
mtime: TimestampSecs(0), mtime: TimestampSecs(0),
usn: Usn(0), usn: Usn(0),
ctype: CardType::New, ctype: CardType::New,
queue: CardQueue::New, queue: CardQueue::New,
due: 0, due: 0,
ivl: 0, interval: 0,
factor: 0, ease_factor: 0,
reps: 0, reps: 0,
lapses: 0, lapses: 0,
left: 0, remaining_steps: 0,
odue: 0, original_due: 0,
odid: DeckID(0), original_deck_id: DeckID(0),
flags: 0, flags: 0,
data: "".to_string(), data: "".to_string(),
} }
@ -103,17 +103,17 @@ impl Card {
} }
pub(crate) fn return_home(&mut self, sched: SchedulerVersion) { pub(crate) fn return_home(&mut self, sched: SchedulerVersion) {
if self.odid.0 == 0 { if self.original_deck_id.0 == 0 {
// not in a filtered deck // not in a filtered deck
return; return;
} }
self.did = self.odid; self.deck_id = self.original_deck_id;
self.odid.0 = 0; self.original_deck_id.0 = 0;
if self.odue > 0 { if self.original_due > 0 {
self.due = self.odue; self.due = self.original_due;
} }
self.odue = 0; self.original_due = 0;
self.queue = match sched { self.queue = match sched {
SchedulerVersion::V1 => { SchedulerVersion::V1 => {
@ -166,17 +166,17 @@ impl Card {
if self.ctype == CardType::Review { if self.ctype == CardType::Review {
// reviews are removed from relearning // reviews are removed from relearning
self.due = self.odue; self.due = self.original_due;
self.odue = 0; self.original_due = 0;
self.queue = CardQueue::Review; self.queue = CardQueue::Review;
} else { } else {
// other cards are reset to new // other cards are reset to new
self.ctype = CardType::New; self.ctype = CardType::New;
self.queue = CardQueue::New; self.queue = CardQueue::New;
self.ivl = 0; self.interval = 0;
self.due = 0; self.due = 0;
self.odue = 0; self.original_due = 0;
self.factor = INITIAL_EASE_FACTOR; self.ease_factor = INITIAL_EASE_FACTOR;
} }
} }
} }
@ -196,9 +196,9 @@ impl Undoable for UpdateCardUndo {
impl Card { impl Card {
pub fn new(nid: NoteID, ord: u16, deck_id: DeckID, due: i32) -> Self { pub fn new(nid: NoteID, ord: u16, deck_id: DeckID, due: i32) -> Self {
let mut card = Card::default(); let mut card = Card::default();
card.nid = nid; card.note_id = nid;
card.ord = ord; card.template_idx = ord;
card.did = deck_id; card.deck_id = deck_id;
card.due = due; card.due = due;
card card
} }
@ -247,7 +247,7 @@ impl Collection {
for cid in cids { for cid in cids {
if let Some(card) = self.storage.get_card(*cid)? { if let Some(card) = self.storage.get_card(*cid)? {
// fixme: undo // fixme: undo
nids.insert(card.nid); nids.insert(card.note_id);
self.storage.remove_card(*cid)?; self.storage.remove_card(*cid)?;
self.storage.add_card_grave(*cid, usn)?; self.storage.add_card_grave(*cid, usn)?;
} }
@ -280,7 +280,7 @@ mod test {
let mut col = open_test_collection(); let mut col = open_test_collection();
let mut card = Card::default(); let mut card = Card::default();
card.ivl = 1; card.interval = 1;
col.add_card(&mut card).unwrap(); col.add_card(&mut card).unwrap();
let cid = card.id; let cid = card.id;
@ -290,11 +290,11 @@ mod test {
// outside of a transaction, no undo info recorded // outside of a transaction, no undo info recorded
let card = col let card = col
.get_and_update_card(cid, |card| { .get_and_update_card(cid, |card| {
card.ivl = 2; card.interval = 2;
Ok(()) Ok(())
}) })
.unwrap(); .unwrap();
assert_eq!(card.ivl, 2); assert_eq!(card.interval, 2);
assert_eq!(col.can_undo(), None); assert_eq!(col.can_undo(), None);
assert_eq!(col.can_redo(), None); assert_eq!(col.can_redo(), None);
@ -302,7 +302,7 @@ mod test {
for i in 3..=4 { for i in 3..=4 {
col.transact(Some(CollectionOp::UpdateCard), |col| { col.transact(Some(CollectionOp::UpdateCard), |col| {
col.get_and_update_card(cid, |card| { col.get_and_update_card(cid, |card| {
card.ivl = i; card.interval = i;
Ok(()) Ok(())
}) })
.unwrap(); .unwrap();
@ -311,51 +311,51 @@ mod test {
.unwrap(); .unwrap();
} }
assert_eq!(col.storage.get_card(cid).unwrap().unwrap().ivl, 4); assert_eq!(col.storage.get_card(cid).unwrap().unwrap().interval, 4);
assert_eq!(col.can_undo(), Some(CollectionOp::UpdateCard)); assert_eq!(col.can_undo(), Some(CollectionOp::UpdateCard));
assert_eq!(col.can_redo(), None); assert_eq!(col.can_redo(), None);
// undo a step // undo a step
col.undo().unwrap(); col.undo().unwrap();
assert_eq!(col.storage.get_card(cid).unwrap().unwrap().ivl, 3); assert_eq!(col.storage.get_card(cid).unwrap().unwrap().interval, 3);
assert_eq!(col.can_undo(), Some(CollectionOp::UpdateCard)); assert_eq!(col.can_undo(), Some(CollectionOp::UpdateCard));
assert_eq!(col.can_redo(), Some(CollectionOp::UpdateCard)); assert_eq!(col.can_redo(), Some(CollectionOp::UpdateCard));
// and again // and again
col.undo().unwrap(); col.undo().unwrap();
assert_eq!(col.storage.get_card(cid).unwrap().unwrap().ivl, 2); assert_eq!(col.storage.get_card(cid).unwrap().unwrap().interval, 2);
assert_eq!(col.can_undo(), None); assert_eq!(col.can_undo(), None);
assert_eq!(col.can_redo(), Some(CollectionOp::UpdateCard)); assert_eq!(col.can_redo(), Some(CollectionOp::UpdateCard));
// redo a step // redo a step
col.redo().unwrap(); col.redo().unwrap();
assert_eq!(col.storage.get_card(cid).unwrap().unwrap().ivl, 3); assert_eq!(col.storage.get_card(cid).unwrap().unwrap().interval, 3);
assert_eq!(col.can_undo(), Some(CollectionOp::UpdateCard)); assert_eq!(col.can_undo(), Some(CollectionOp::UpdateCard));
assert_eq!(col.can_redo(), Some(CollectionOp::UpdateCard)); assert_eq!(col.can_redo(), Some(CollectionOp::UpdateCard));
// and another // and another
col.redo().unwrap(); col.redo().unwrap();
assert_eq!(col.storage.get_card(cid).unwrap().unwrap().ivl, 4); assert_eq!(col.storage.get_card(cid).unwrap().unwrap().interval, 4);
assert_eq!(col.can_undo(), Some(CollectionOp::UpdateCard)); assert_eq!(col.can_undo(), Some(CollectionOp::UpdateCard));
assert_eq!(col.can_redo(), None); assert_eq!(col.can_redo(), None);
// and undo the redo // and undo the redo
col.undo().unwrap(); col.undo().unwrap();
assert_eq!(col.storage.get_card(cid).unwrap().unwrap().ivl, 3); assert_eq!(col.storage.get_card(cid).unwrap().unwrap().interval, 3);
assert_eq!(col.can_undo(), Some(CollectionOp::UpdateCard)); assert_eq!(col.can_undo(), Some(CollectionOp::UpdateCard));
assert_eq!(col.can_redo(), Some(CollectionOp::UpdateCard)); assert_eq!(col.can_redo(), Some(CollectionOp::UpdateCard));
// if any action is performed, it should clear the redo queue // if any action is performed, it should clear the redo queue
col.transact(Some(CollectionOp::UpdateCard), |col| { col.transact(Some(CollectionOp::UpdateCard), |col| {
col.get_and_update_card(cid, |card| { col.get_and_update_card(cid, |card| {
card.ivl = 5; card.interval = 5;
Ok(()) Ok(())
}) })
.unwrap(); .unwrap();
Ok(()) Ok(())
}) })
.unwrap(); .unwrap();
assert_eq!(col.storage.get_card(cid).unwrap().unwrap().ivl, 5); assert_eq!(col.storage.get_card(cid).unwrap().unwrap().interval, 5);
assert_eq!(col.can_undo(), Some(CollectionOp::UpdateCard)); assert_eq!(col.can_undo(), Some(CollectionOp::UpdateCard));
assert_eq!(col.can_redo(), None); assert_eq!(col.can_redo(), None);

View file

@ -205,8 +205,8 @@ impl Collection {
if let Some(deck) = decks.get(&did) { if let Some(deck) = decks.get(&did) {
if !deck.is_filtered() { if !deck.is_filtered() {
let mut card = self.storage.get_card(cid)?.unwrap(); let mut card = self.storage.get_card(cid)?.unwrap();
card.odid.0 = 0; card.original_deck_id.0 = 0;
card.odue = 0; card.original_due = 0;
self.storage.update_card(&card)?; self.storage.update_card(&card)?;
wrong += 1; wrong += 1;
} }
@ -278,7 +278,7 @@ impl Collection {
} }
// note type ID may have changed if we created a recovery notetype // note type ID may have changed if we created a recovery notetype
note.ntid = nt.id; note.notetype_id = nt.id;
// write note, updating tags and generating missing cards // write note, updating tags and generating missing cards
let ctx = genctx.get_or_insert_with(|| CardGenContext::new(&nt, usn)); let ctx = genctx.get_or_insert_with(|| CardGenContext::new(&nt, usn));
@ -509,7 +509,7 @@ mod test {
let cid = col.search_cards("", SortMode::NoOrder)?[0]; let cid = col.search_cards("", SortMode::NoOrder)?[0];
let mut card = col.storage.get_card(cid)?.unwrap(); let mut card = col.storage.get_card(cid)?.unwrap();
card.id.0 += 1; card.id.0 += 1;
card.ord = 10; card.template_idx = 10;
col.storage.add_card(&mut card)?; col.storage.add_card(&mut card)?;
let out = col.check_database(progress_fn)?; let out = col.check_database(progress_fn)?;

View file

@ -380,7 +380,7 @@ where
} }
let mut note = self.ctx.storage.get_note(nid)?.unwrap(); let mut note = self.ctx.storage.get_note(nid)?.unwrap();
let nt = note_types let nt = note_types
.get(&note.ntid) .get(&note.notetype_id)
.ok_or_else(|| AnkiError::DBError { .ok_or_else(|| AnkiError::DBError {
info: "missing note type".to_string(), info: "missing note type".to_string(),
kind: DBErrorKind::MissingEntity, kind: DBErrorKind::MissingEntity,

View file

@ -36,7 +36,7 @@ pub(crate) struct TransformNoteOutput {
pub struct Note { pub struct Note {
pub id: NoteID, pub id: NoteID,
pub guid: String, pub guid: String,
pub ntid: NoteTypeID, pub notetype_id: NoteTypeID,
pub mtime: TimestampSecs, pub mtime: TimestampSecs,
pub usn: Usn, pub usn: Usn,
pub tags: Vec<String>, pub tags: Vec<String>,
@ -50,7 +50,7 @@ impl Note {
Note { Note {
id: NoteID(0), id: NoteID(0),
guid: guid(), guid: guid(),
ntid: notetype.id, notetype_id: notetype.id,
mtime: TimestampSecs(0), mtime: TimestampSecs(0),
usn: Usn(0), usn: Usn(0),
tags: vec![], tags: vec![],
@ -78,7 +78,7 @@ impl Note {
/// Prepare note for saving to the database. Does not mark it as modified. /// Prepare note for saving to the database. Does not mark it as modified.
pub fn prepare_for_update(&mut self, nt: &NoteType, normalize_text: bool) -> Result<()> { pub fn prepare_for_update(&mut self, nt: &NoteType, normalize_text: bool) -> Result<()> {
assert!(nt.id == self.ntid); assert!(nt.id == self.notetype_id);
let notetype_field_count = nt.fields.len().max(1); let notetype_field_count = nt.fields.len().max(1);
if notetype_field_count != self.fields.len() { if notetype_field_count != self.fields.len() {
return Err(AnkiError::invalid_input(format!( return Err(AnkiError::invalid_input(format!(
@ -183,7 +183,7 @@ impl From<Note> for pb::Note {
pb::Note { pb::Note {
id: n.id.0, id: n.id.0,
guid: n.guid, guid: n.guid,
ntid: n.ntid.0, notetype_id: n.notetype_id.0,
mtime_secs: n.mtime.0 as u32, mtime_secs: n.mtime.0 as u32,
usn: n.usn.0, usn: n.usn.0,
tags: n.tags, tags: n.tags,
@ -197,7 +197,7 @@ impl From<pb::Note> for Note {
Note { Note {
id: NoteID(n.id), id: NoteID(n.id),
guid: n.guid, guid: n.guid,
ntid: NoteTypeID(n.ntid), notetype_id: NoteTypeID(n.notetype_id),
mtime: TimestampSecs(n.mtime_secs as i64), mtime: TimestampSecs(n.mtime_secs as i64),
usn: Usn(n.usn), usn: Usn(n.usn),
tags: n.tags, tags: n.tags,
@ -248,7 +248,7 @@ impl Collection {
pub fn add_note(&mut self, note: &mut Note, did: DeckID) -> Result<()> { pub fn add_note(&mut self, note: &mut Note, did: DeckID) -> Result<()> {
self.transact(None, |col| { self.transact(None, |col| {
let nt = col let nt = col
.get_notetype(note.ntid)? .get_notetype(note.notetype_id)?
.ok_or_else(|| AnkiError::invalid_input("missing note type"))?; .ok_or_else(|| AnkiError::invalid_input("missing note type"))?;
let ctx = CardGenContext::new(&nt, col.usn()?); let ctx = CardGenContext::new(&nt, col.usn()?);
let norm = col.normalize_note_text(); let norm = col.normalize_note_text();
@ -282,7 +282,7 @@ impl Collection {
self.transact(None, |col| { self.transact(None, |col| {
let nt = col let nt = col
.get_notetype(note.ntid)? .get_notetype(note.notetype_id)?
.ok_or_else(|| AnkiError::invalid_input("missing note type"))?; .ok_or_else(|| AnkiError::invalid_input("missing note type"))?;
let ctx = CardGenContext::new(&nt, col.usn()?); let ctx = CardGenContext::new(&nt, col.usn()?);
let norm = col.normalize_note_text(); let norm = col.normalize_note_text();
@ -434,9 +434,9 @@ impl Collection {
Ok(DuplicateState::Empty) Ok(DuplicateState::Empty)
} else { } else {
let csum = field_checksum(&stripped); let csum = field_checksum(&stripped);
for field in self for field in
.storage self.storage
.note_fields_by_checksum(note.id, note.ntid, csum)? .note_fields_by_checksum(note.id, note.notetype_id, csum)?
{ {
if strip_html_preserving_image_filenames(&field) == stripped { if strip_html_preserving_image_filenames(&field) == stripped {
return Ok(DuplicateState::Duplicate); return Ok(DuplicateState::Duplicate);

View file

@ -26,13 +26,13 @@ impl Collection {
.ok_or_else(|| AnkiError::invalid_input("no such card"))?; .ok_or_else(|| AnkiError::invalid_input("no such card"))?;
let note = self let note = self
.storage .storage
.get_note(card.nid)? .get_note(card.note_id)?
.ok_or_else(|| AnkiError::invalid_input("no such note"))?; .ok_or_else(|| AnkiError::invalid_input("no such note"))?;
let nt = self let nt = self
.get_notetype(note.ntid)? .get_notetype(note.notetype_id)?
.ok_or_else(|| AnkiError::invalid_input("no such notetype"))?; .ok_or_else(|| AnkiError::invalid_input("no such notetype"))?;
let template = match nt.config.kind() { let template = match nt.config.kind() {
NoteTypeKind::Normal => nt.templates.get(card.ord as usize), NoteTypeKind::Normal => nt.templates.get(card.template_idx as usize),
NoteTypeKind::Cloze => nt.templates.get(0), NoteTypeKind::Cloze => nt.templates.get(0),
} }
.ok_or_else(|| AnkiError::invalid_input("missing template"))?; .ok_or_else(|| AnkiError::invalid_input("missing template"))?;
@ -52,7 +52,7 @@ impl Collection {
) -> Result<RenderCardOutput> { ) -> Result<RenderCardOutput> {
let card = self.existing_or_synthesized_card(note.id, template.ord, card_ord)?; let card = self.existing_or_synthesized_card(note.id, template.ord, card_ord)?;
let nt = self let nt = self
.get_notetype(note.ntid)? .get_notetype(note.notetype_id)?
.ok_or_else(|| AnkiError::invalid_input("no such notetype"))?; .ok_or_else(|| AnkiError::invalid_input("no such notetype"))?;
if fill_empty { if fill_empty {
@ -77,7 +77,7 @@ impl Collection {
// no existing card; synthesize one // no existing card; synthesize one
let mut card = Card::default(); let mut card = Card::default();
card.ord = card_ord; card.template_idx = card_ord;
Ok(card) Ok(card)
} }
@ -94,7 +94,7 @@ impl Collection {
let card_num; let card_num;
self.add_special_fields(&mut field_map, note, card, &nt, template)?; self.add_special_fields(&mut field_map, note, card, &nt, template)?;
// due to lifetime restrictions we need to add card number here // due to lifetime restrictions we need to add card number here
card_num = format!("c{}", card.ord + 1); card_num = format!("c{}", card.template_idx + 1);
field_map.entry(&card_num).or_insert_with(|| "1".into()); field_map.entry(&card_num).or_insert_with(|| "1".into());
let (qfmt, afmt) = if browser { let (qfmt, afmt) = if browser {
@ -109,8 +109,14 @@ impl Collection {
) )
}; };
let (qnodes, anodes) = let (qnodes, anodes) = render_card(
render_card(qfmt, afmt, &field_map, card.ord, nt.is_cloze(), &self.i18n)?; qfmt,
afmt,
&field_map,
card.template_idx,
nt.is_cloze(),
&self.i18n,
)?;
Ok(RenderCardOutput { qnodes, anodes }) Ok(RenderCardOutput { qnodes, anodes })
} }
@ -127,7 +133,11 @@ impl Collection {
map.entry("Tags").or_insert_with(|| tags.into()); map.entry("Tags").or_insert_with(|| tags.into());
map.entry("Type").or_insert_with(|| nt.name.clone().into()); map.entry("Type").or_insert_with(|| nt.name.clone().into());
let deck_name: Cow<str> = self let deck_name: Cow<str> = self
.get_deck(if card.odid.0 > 0 { card.odid } else { card.did })? .get_deck(if card.original_deck_id.0 > 0 {
card.original_deck_id
} else {
card.deck_id
})?
.map(|d| d.human_name().into()) .map(|d| d.human_name().into())
.unwrap_or_else(|| "(Deck)".into()); .unwrap_or_else(|| "(Deck)".into());
let subdeck_name = deck_name.rsplit("::").next().unwrap(); let subdeck_name = deck_name.rsplit("::").next().unwrap();

View file

@ -23,7 +23,11 @@ impl Card {
} else { } else {
self.queue = match self.ctype { self.queue = match self.ctype {
CardType::Learn | CardType::Relearn => { CardType::Learn | CardType::Relearn => {
let original_due = if self.odue > 0 { self.odue } else { self.due }; let original_due = if self.original_due > 0 {
self.original_due
} else {
self.due
};
if original_due > 1_000_000_000 { if original_due > 1_000_000_000 {
// previous interval was in seconds // previous interval was in seconds
CardQueue::Learn CardQueue::Learn

View file

@ -65,12 +65,14 @@ impl Collection {
let card = self.storage.get_card(cid)?.ok_or(AnkiError::NotFound)?; let card = self.storage.get_card(cid)?.ok_or(AnkiError::NotFound)?;
let note = self let note = self
.storage .storage
.get_note(card.nid)? .get_note(card.note_id)?
.ok_or(AnkiError::NotFound)?;
let nt = self
.get_notetype(note.notetype_id)?
.ok_or(AnkiError::NotFound)?; .ok_or(AnkiError::NotFound)?;
let nt = self.get_notetype(note.ntid)?.ok_or(AnkiError::NotFound)?;
let deck = self let deck = self
.storage .storage
.get_deck(card.did)? .get_deck(card.deck_id)?
.ok_or(AnkiError::NotFound)?; .ok_or(AnkiError::NotFound)?;
let revlog = self.storage.get_revlog_entries_for_card(card.id)?; let revlog = self.storage.get_revlog_entries_for_card(card.id)?;
@ -104,16 +106,16 @@ impl Collection {
first_review: revlog.first().map(|e| e.id.as_secs()), first_review: revlog.first().map(|e| e.id.as_secs()),
latest_review: revlog.last().map(|e| e.id.as_secs()), latest_review: revlog.last().map(|e| e.id.as_secs()),
due, due,
interval_secs: card.ivl * 86_400, interval_secs: card.interval * 86_400,
ease: (card.factor as u32) / 10, ease: (card.ease_factor as u32) / 10,
reviews: card.reps, reviews: card.reps,
lapses: card.lapses, lapses: card.lapses,
average_secs, average_secs,
total_secs, total_secs,
card_type: nt.get_template(card.ord)?.name.clone(), card_type: nt.get_template(card.template_idx)?.name.clone(),
note_type: nt.name.clone(), note_type: nt.name.clone(),
deck: deck.human_name(), deck: deck.human_name(),
nid: card.nid, nid: card.note_id,
cid: card.id, cid: card.id,
revlog: revlog.into_iter().map(Into::into).collect(), revlog: revlog.into_iter().map(Into::into).collect(),
}) })

View file

@ -41,21 +41,21 @@ impl FromSql for CardQueue {
fn row_to_card(row: &Row) -> result::Result<Card, rusqlite::Error> { fn row_to_card(row: &Row) -> result::Result<Card, rusqlite::Error> {
Ok(Card { Ok(Card {
id: row.get(0)?, id: row.get(0)?,
nid: row.get(1)?, note_id: row.get(1)?,
did: row.get(2)?, deck_id: row.get(2)?,
ord: row.get(3)?, template_idx: row.get(3)?,
mtime: row.get(4)?, mtime: row.get(4)?,
usn: row.get(5)?, usn: row.get(5)?,
ctype: row.get(6)?, ctype: row.get(6)?,
queue: row.get(7)?, queue: row.get(7)?,
due: row.get(8).ok().unwrap_or_default(), due: row.get(8).ok().unwrap_or_default(),
ivl: row.get(9)?, interval: row.get(9)?,
factor: row.get(10)?, ease_factor: row.get(10)?,
reps: row.get(11)?, reps: row.get(11)?,
lapses: row.get(12)?, lapses: row.get(12)?,
left: row.get(13)?, remaining_steps: row.get(13)?,
odue: row.get(14).ok().unwrap_or_default(), original_due: row.get(14).ok().unwrap_or_default(),
odid: row.get(15)?, original_deck_id: row.get(15)?,
flags: row.get(16)?, flags: row.get(16)?,
data: row.get(17)?, data: row.get(17)?,
}) })
@ -73,21 +73,21 @@ impl super::SqliteStorage {
pub(crate) fn update_card(&self, card: &Card) -> Result<()> { pub(crate) fn update_card(&self, card: &Card) -> Result<()> {
let mut stmt = self.db.prepare_cached(include_str!("update_card.sql"))?; let mut stmt = self.db.prepare_cached(include_str!("update_card.sql"))?;
stmt.execute(params![ stmt.execute(params![
card.nid, card.note_id,
card.did, card.deck_id,
card.ord, card.template_idx,
card.mtime, card.mtime,
card.usn, card.usn,
card.ctype as u8, card.ctype as u8,
card.queue as i8, card.queue as i8,
card.due, card.due,
card.ivl, card.interval,
card.factor, card.ease_factor,
card.reps, card.reps,
card.lapses, card.lapses,
card.left, card.remaining_steps,
card.odue, card.original_due,
card.odid, card.original_deck_id,
card.flags, card.flags,
card.data, card.data,
card.id, card.id,
@ -100,21 +100,21 @@ impl super::SqliteStorage {
let mut stmt = self.db.prepare_cached(include_str!("add_card.sql"))?; let mut stmt = self.db.prepare_cached(include_str!("add_card.sql"))?;
stmt.execute(params![ stmt.execute(params![
now, now,
card.nid, card.note_id,
card.did, card.deck_id,
card.ord, card.template_idx,
card.mtime, card.mtime,
card.usn, card.usn,
card.ctype as u8, card.ctype as u8,
card.queue as i8, card.queue as i8,
card.due, card.due,
card.ivl, card.interval,
card.factor, card.ease_factor,
card.reps, card.reps,
card.lapses, card.lapses,
card.left, card.remaining_steps,
card.odue, card.original_due,
card.odid, card.original_deck_id,
card.flags, card.flags,
card.data, card.data,
])?; ])?;
@ -127,21 +127,21 @@ impl super::SqliteStorage {
let mut stmt = self.db.prepare_cached(include_str!("add_or_update.sql"))?; let mut stmt = self.db.prepare_cached(include_str!("add_or_update.sql"))?;
stmt.execute(params![ stmt.execute(params![
card.id, card.id,
card.nid, card.note_id,
card.did, card.deck_id,
card.ord, card.template_idx,
card.mtime, card.mtime,
card.usn, card.usn,
card.ctype as u8, card.ctype as u8,
card.queue as i8, card.queue as i8,
card.due, card.due,
card.ivl, card.interval,
card.factor, card.ease_factor,
card.reps, card.reps,
card.lapses, card.lapses,
card.left, card.remaining_steps,
card.odue, card.original_due,
card.odid, card.original_deck_id,
card.flags, card.flags,
card.data, card.data,
])?; ])?;

View file

@ -22,7 +22,7 @@ fn row_to_note(row: &Row) -> Result<Note> {
Ok(Note { Ok(Note {
id: row.get(0)?, id: row.get(0)?,
guid: row.get(1)?, guid: row.get(1)?,
ntid: row.get(2)?, notetype_id: row.get(2)?,
mtime: row.get(3)?, mtime: row.get(3)?,
usn: row.get(4)?, usn: row.get(4)?,
tags: split_tags(row.get_raw(5).as_str()?) tags: split_tags(row.get_raw(5).as_str()?)
@ -49,7 +49,7 @@ impl super::SqliteStorage {
let mut stmt = self.db.prepare_cached(include_str!("update.sql"))?; let mut stmt = self.db.prepare_cached(include_str!("update.sql"))?;
stmt.execute(params![ stmt.execute(params![
note.guid, note.guid,
note.ntid, note.notetype_id,
note.mtime, note.mtime,
note.usn, note.usn,
join_tags(&note.tags), join_tags(&note.tags),
@ -67,7 +67,7 @@ impl super::SqliteStorage {
stmt.execute(params![ stmt.execute(params![
TimestampMillis::now(), TimestampMillis::now(),
note.guid, note.guid,
note.ntid, note.notetype_id,
note.mtime, note.mtime,
note.usn, note.usn,
join_tags(&note.tags), join_tags(&note.tags),
@ -85,7 +85,7 @@ impl super::SqliteStorage {
stmt.execute(params![ stmt.execute(params![
note.id, note.id,
note.guid, note.guid,
note.ntid, note.notetype_id,
note.mtime, note.mtime,
note.usn, note.usn,
join_tags(&note.tags), join_tags(&note.tags),

View file

@ -945,7 +945,7 @@ impl Collection {
if proceed { if proceed {
let mut note: Note = entry.into(); let mut note: Note = entry.into();
let nt = self let nt = self
.get_notetype(note.ntid)? .get_notetype(note.notetype_id)?
.ok_or_else(|| AnkiError::invalid_input("note missing notetype"))?; .ok_or_else(|| AnkiError::invalid_input("note missing notetype"))?;
note.prepare_for_update(&nt, false)?; note.prepare_for_update(&nt, false)?;
self.storage.add_or_update_note(&note)?; self.storage.add_or_update_note(&note)?;
@ -1065,21 +1065,21 @@ impl From<CardEntry> for Card {
fn from(e: CardEntry) -> Self { fn from(e: CardEntry) -> Self {
Card { Card {
id: e.id, id: e.id,
nid: e.nid, note_id: e.nid,
did: e.did, deck_id: e.did,
ord: e.ord, template_idx: e.ord,
mtime: e.mtime, mtime: e.mtime,
usn: e.usn, usn: e.usn,
ctype: e.ctype, ctype: e.ctype,
queue: e.queue, queue: e.queue,
due: e.due, due: e.due,
ivl: e.ivl, interval: e.ivl,
factor: e.factor, ease_factor: e.factor,
reps: e.reps, reps: e.reps,
lapses: e.lapses, lapses: e.lapses,
left: e.left, remaining_steps: e.left,
odue: e.odue, original_due: e.odue,
odid: e.odid, original_deck_id: e.odid,
flags: e.flags, flags: e.flags,
data: e.data, data: e.data,
} }
@ -1090,21 +1090,21 @@ impl From<Card> for CardEntry {
fn from(e: Card) -> Self { fn from(e: Card) -> Self {
CardEntry { CardEntry {
id: e.id, id: e.id,
nid: e.nid, nid: e.note_id,
did: e.did, did: e.deck_id,
ord: e.ord, ord: e.template_idx,
mtime: e.mtime, mtime: e.mtime,
usn: e.usn, usn: e.usn,
ctype: e.ctype, ctype: e.ctype,
queue: e.queue, queue: e.queue,
due: e.due, due: e.due,
ivl: e.ivl, ivl: e.interval,
factor: e.factor, factor: e.ease_factor,
reps: e.reps, reps: e.reps,
lapses: e.lapses, lapses: e.lapses,
left: e.left, left: e.remaining_steps,
odue: e.odue, odue: e.original_due,
odid: e.odid, odid: e.original_deck_id,
flags: e.flags, flags: e.flags,
data: e.data, data: e.data,
} }
@ -1116,7 +1116,7 @@ impl From<NoteEntry> for Note {
Note { Note {
id: e.id, id: e.id,
guid: e.guid, guid: e.guid,
ntid: e.ntid, notetype_id: e.ntid,
mtime: e.mtime, mtime: e.mtime,
usn: e.usn, usn: e.usn,
tags: split_tags(&e.tags).map(ToString::to_string).collect(), tags: split_tags(&e.tags).map(ToString::to_string).collect(),
@ -1132,7 +1132,7 @@ impl From<Note> for NoteEntry {
NoteEntry { NoteEntry {
id: e.id, id: e.id,
guid: e.guid, guid: e.guid,
ntid: e.ntid, ntid: e.notetype_id,
mtime: e.mtime, mtime: e.mtime,
usn: e.usn, usn: e.usn,
tags: join_tags(&e.tags), tags: join_tags(&e.tags),

View file

@ -39,7 +39,7 @@ export function gatherData(data: pb.BackendProto.GraphsOut, i18n: I18n): GraphDa
newCards += 1; newCards += 1;
break; break;
case CardQueue.Review: case CardQueue.Review:
if (card.ivl >= 21) { if (card.interval >= 21) {
mature += 1; mature += 1;
break; break;
} }

View file

@ -22,7 +22,7 @@ export interface GraphData {
export function gatherData(data: pb.BackendProto.GraphsOut): GraphData { export function gatherData(data: pb.BackendProto.GraphsOut): GraphData {
const eases = (data.cards as pb.BackendProto.Card[]) const eases = (data.cards as pb.BackendProto.Card[])
.filter((c) => c.queue == CardQueue.Review) .filter((c) => c.queue == CardQueue.Review)
.map((c) => c.factor / 10); .map((c) => c.easeFactor / 10);
return { eases }; return { eases };
} }

View file

@ -40,7 +40,7 @@ export function gatherData(data: pb.BackendProto.GraphsOut): GraphData {
// - testing just odue fails on day 1 // - testing just odue fails on day 1
// - testing just odid fails on lapsed cards that // - testing just odid fails on lapsed cards that
// have due calculated at regraduation time // have due calculated at regraduation time
const due = c.odid && c.odue ? c.odue : c.due; const due = c.originalDeckId && c.originalDue ? c.originalDue : c.due;
const dueDay = due - data.daysElapsed; const dueDay = due - data.daysElapsed;
if (dueDay < 0) { if (dueDay < 0) {
haveBacklog = true; haveBacklog = true;

View file

@ -30,7 +30,7 @@ export enum IntervalRange {
export function gatherIntervalData(data: pb.BackendProto.GraphsOut): IntervalGraphData { export function gatherIntervalData(data: pb.BackendProto.GraphsOut): IntervalGraphData {
const intervals = (data.cards as pb.BackendProto.Card[]) const intervals = (data.cards as pb.BackendProto.Card[])
.filter((c) => c.queue == CardQueue.Review) .filter((c) => c.queue == CardQueue.Review)
.map((c) => c.ivl); .map((c) => c.interval);
return { intervals }; return { intervals };
} }