add (currently disabled) check for missing/empty decks on card add

This commit is contained in:
Damien Elmes 2020-04-26 16:55:16 +10:00
parent d3b27c302c
commit 36531ea96d
4 changed files with 58 additions and 10 deletions

View file

@ -7,6 +7,7 @@ use crate::log::Logger;
use crate::timestamp::TimestampSecs; use crate::timestamp::TimestampSecs;
use crate::types::Usn; use crate::types::Usn;
use crate::{ use crate::{
decks::{Deck, DeckID},
notetype::{NoteType, NoteTypeID}, notetype::{NoteType, NoteTypeID},
sched::cutoff::{sched_timing_today, SchedTimingToday}, sched::cutoff::{sched_timing_today, SchedTimingToday},
storage::SqliteStorage, storage::SqliteStorage,
@ -52,6 +53,7 @@ pub struct CollectionState {
pub(crate) undo: UndoManager, pub(crate) undo: UndoManager,
timing_today: Option<SchedTimingToday>, timing_today: Option<SchedTimingToday>,
pub(crate) notetype_cache: HashMap<NoteTypeID, Arc<NoteType>>, pub(crate) notetype_cache: HashMap<NoteTypeID, Arc<NoteType>>,
pub(crate) deck_cache: HashMap<DeckID, Arc<Deck>>,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]

View file

@ -1,10 +1,11 @@
// Copyright: Ankitects Pty Ltd and contributors // Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use crate::define_newtype; use crate::{collection::Collection, define_newtype, err::Result};
mod schema11; mod schema11;
pub use schema11::Deck; pub use schema11::Deck;
use std::sync::Arc;
define_newtype!(DeckID, i64); define_newtype!(DeckID, i64);
@ -25,3 +26,24 @@ pub(crate) fn get_deck(decks: &[Deck], id: DeckID) -> Option<&Deck> {
None None
} }
impl Deck {
pub(crate) fn is_filtered(&self) -> bool {
matches!(self, Deck::Filtered(_))
}
}
impl Collection {
pub(crate) fn get_deck(&mut self, did: DeckID) -> Result<Option<Arc<Deck>>> {
if let Some(deck) = self.state.deck_cache.get(&did) {
return Ok(Some(deck.clone()));
}
if let Some(deck) = self.storage.get_deck(did)? {
let deck = Arc::new(deck);
self.state.deck_cache.insert(did, deck.clone());
Ok(Some(deck))
} else {
Ok(None)
}
}
}

View file

@ -216,7 +216,7 @@ impl Collection {
note: &Note, note: &Note,
) -> Result<()> { ) -> Result<()> {
let existing = self.storage.existing_cards_for_note(note.id)?; let existing = self.storage.existing_cards_for_note(note.id)?;
self.generate_cards_for_note(ctx, note, &existing, None) self.generate_cards_for_note(ctx, note, &existing, Some(ctx.notetype.target_deck_id()))
} }
fn generate_cards_for_note( fn generate_cards_for_note(
@ -230,7 +230,7 @@ impl Collection {
if cards.is_empty() { if cards.is_empty() {
return Ok(()); return Ok(());
} }
self.add_generated_cards(ctx, note.id, &cards, target_deck_id) self.add_generated_cards(note.id, &cards, target_deck_id)
} }
pub(crate) fn generate_cards_for_notetype(&mut self, ctx: &CardGenContext) -> Result<()> { pub(crate) fn generate_cards_for_notetype(&mut self, ctx: &CardGenContext) -> Result<()> {
@ -253,19 +253,13 @@ impl Collection {
pub(crate) fn add_generated_cards( pub(crate) fn add_generated_cards(
&mut self, &mut self,
ctx: &CardGenContext,
nid: NoteID, nid: NoteID,
cards: &[CardToGenerate], cards: &[CardToGenerate],
target_deck_id: Option<DeckID>, target_deck_id: Option<DeckID>,
) -> Result<()> { ) -> Result<()> {
let mut next_pos = None; let mut next_pos = None;
for c in cards { for c in cards {
// fixme: deal with case where invalid deck pointed to let did = self.deck_id_for_adding(c.did.or(target_deck_id))?;
// fixme: deprecated note type deck id
let did = c
.did
.or(target_deck_id)
.unwrap_or_else(|| ctx.notetype.target_deck_id());
let due = c.due.unwrap_or_else(|| { let due = c.due.unwrap_or_else(|| {
if next_pos.is_none() { if next_pos.is_none() {
next_pos = Some(self.get_and_update_next_card_position().unwrap_or(0)); next_pos = Some(self.get_and_update_next_card_position().unwrap_or(0));
@ -278,4 +272,28 @@ impl Collection {
Ok(()) Ok(())
} }
/// If deck ID does not exist or points to a filtered deck, fall back on default.
fn deck_id_for_adding(&mut self, did: Option<DeckID>) -> Result<DeckID> {
if let Some(did) = did.and_then(|did| self.deck_id_if_normal(did)) {
Ok(did)
} else {
self.default_deck_id()
}
}
fn default_deck_id(&mut self) -> Result<DeckID> {
// currently hard-coded, we could create this as needed in the future
Ok(DeckID(1))
}
/// If deck exists and and is a normal deck, return it.
fn deck_id_if_normal(&mut self, did: DeckID) -> Option<DeckID> {
// fixme: currently disabled until deck writes are immediate
return Some(did);
self.get_deck(did)
.ok()
.and_then(|opt| opt.and_then(|d| if !d.is_filtered() { Some(d.id()) } else { None }))
}
} }

View file

@ -22,4 +22,10 @@ impl SqliteStorage {
self.db.execute("update col set decks = ?", &[json])?; self.db.execute("update col set decks = ?", &[json])?;
Ok(()) Ok(())
} }
pub(crate) fn get_deck(&self, did: DeckID) -> Result<Option<Deck>> {
// fixme: this is just temporary until we create an extra table
let mut decks = self.get_all_decks()?;
Ok(decks.remove(&did))
}
} }