mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 06:22:22 -04:00
add missing decks in backend
- need to compare parents with unicode case folding - duplicate check enforced by the DB
This commit is contained in:
parent
67421e02ec
commit
5fb5338d97
8 changed files with 49 additions and 33 deletions
|
@ -71,7 +71,7 @@ message BackendInput {
|
|||
int32 get_changed_notetypes = 56;
|
||||
AddOrUpdateNotetypeIn add_or_update_notetype = 57;
|
||||
Empty get_all_decks = 58;
|
||||
// bytes set_all_decks = 59;
|
||||
Empty check_database = 59;
|
||||
Empty all_stock_notetypes = 60;
|
||||
int64 get_notetype_legacy = 61;
|
||||
Empty get_notetype_names = 62;
|
||||
|
@ -140,7 +140,7 @@ message BackendOutput {
|
|||
bytes get_changed_notetypes = 56;
|
||||
int64 add_or_update_notetype = 57;
|
||||
bytes get_all_decks = 58;
|
||||
// Empty set_all_decks = 59;
|
||||
Empty check_database = 59;
|
||||
bytes get_notetype_legacy = 61;
|
||||
NoteTypeNames get_notetype_names = 62;
|
||||
NoteTypeUseCounts get_notetype_names_and_counts = 63;
|
||||
|
|
|
@ -958,6 +958,8 @@ and type=0 and queue!=4""",
|
|||
# models
|
||||
if self.models.ensureNotEmpty():
|
||||
problems.append("Added missing note type.")
|
||||
# misc other
|
||||
self.backend.check_database()
|
||||
# and finally, optimize
|
||||
self.optimize()
|
||||
newSize = os.stat(self.path)[stat.ST_SIZE]
|
||||
|
|
|
@ -5,7 +5,7 @@ from __future__ import annotations
|
|||
|
||||
import copy
|
||||
import unicodedata
|
||||
from typing import Any, Dict, List, Optional, Set, Tuple, Union
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
|
||||
import anki # pylint: disable=unused-import
|
||||
import anki.backend_pb2 as pb
|
||||
|
@ -524,37 +524,8 @@ class DeckManager:
|
|||
# )
|
||||
# self.col.db.mod = mod
|
||||
|
||||
def _checkDeckTree(self) -> None:
|
||||
decks = self.all()
|
||||
decks.sort(key=self.key)
|
||||
names: Set[str] = set()
|
||||
|
||||
for deck in decks:
|
||||
# two decks with the same name?
|
||||
if deck["name"] in names:
|
||||
self.col.log("fix duplicate deck name", deck["name"])
|
||||
deck["name"] += "%d" % intTime(1000)
|
||||
self.save(deck)
|
||||
|
||||
# ensure no sections are blank
|
||||
if not all(self.path(deck["name"])):
|
||||
self.col.log("fix deck with missing sections", deck["name"])
|
||||
deck["name"] = "recovered%d" % intTime(1000)
|
||||
self.save(deck)
|
||||
|
||||
# immediate parent must exist
|
||||
if "::" in deck["name"]:
|
||||
immediateParent = self.immediate_parent(deck["name"])
|
||||
if immediateParent not in names:
|
||||
self.col.log("fix deck with missing parent", deck["name"])
|
||||
self._ensureParents(deck["name"])
|
||||
names.add(immediateParent)
|
||||
|
||||
names.add(deck["name"])
|
||||
|
||||
def checkIntegrity(self) -> None:
|
||||
self._recoverOrphans()
|
||||
self._checkDeckTree()
|
||||
|
||||
def should_deck_be_displayed(
|
||||
self, deck, force_default: bool = True, assume_no_child: bool = False
|
||||
|
|
|
@ -735,6 +735,9 @@ class RustBackend:
|
|||
pb.BackendInput(deck_tree=pb.DeckTreeIn(include_counts=include_counts))
|
||||
).deck_tree
|
||||
|
||||
def check_database(self) -> None:
|
||||
self._run_command(pb.BackendInput(check_database=pb.Empty()))
|
||||
|
||||
|
||||
def translate_string_in(
|
||||
key: TR, **kwargs: Union[str, int, float]
|
||||
|
|
|
@ -356,6 +356,10 @@ impl Backend {
|
|||
self.remove_deck(did)?;
|
||||
pb::Empty {}
|
||||
}),
|
||||
Value::CheckDatabase(_) => {
|
||||
self.check_database()?;
|
||||
OValue::CheckDatabase(pb::Empty {})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1046,6 +1050,10 @@ impl Backend {
|
|||
fn remove_deck(&self, did: i64) -> Result<()> {
|
||||
self.with_col(|col| col.remove_deck_and_child_decks(DeckID(did)))
|
||||
}
|
||||
|
||||
fn check_database(&self) -> Result<()> {
|
||||
self.with_col(|col| col.transact(None, |col| col.check_database()))
|
||||
}
|
||||
}
|
||||
|
||||
fn translate_arg_to_fluent_val(arg: &pb::TranslateArgValue) -> FluentValue {
|
||||
|
|
12
rslib/src/dbcheck.rs
Normal file
12
rslib/src/dbcheck.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
use crate::{collection::Collection, err::Result};
|
||||
|
||||
impl Collection {
|
||||
pub(crate) fn check_database(&mut self) -> Result<()> {
|
||||
let names = self.storage.get_all_deck_names()?;
|
||||
self.add_missing_decks(&names)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -3,7 +3,11 @@
|
|||
|
||||
use super::Deck;
|
||||
use crate::{backend_proto::DeckTreeNode, collection::Collection, decks::DeckID, err::Result};
|
||||
use std::{collections::HashMap, iter::Peekable};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
iter::Peekable,
|
||||
};
|
||||
use unicase::UniCase;
|
||||
|
||||
// fixme: handle mixed case of parents
|
||||
|
||||
|
@ -80,6 +84,21 @@ impl Collection {
|
|||
|
||||
Ok(tree)
|
||||
}
|
||||
|
||||
pub(crate) fn add_missing_decks(&mut self, names: &[(DeckID, String)]) -> Result<()> {
|
||||
let mut parents = HashSet::new();
|
||||
for (_id, name) in names {
|
||||
parents.insert(UniCase::new(name.as_str()));
|
||||
if let Some(immediate_parent) = name.rsplitn(2, "::").nth(1) {
|
||||
let immediate_parent_uni = UniCase::new(immediate_parent);
|
||||
if !parents.contains(&immediate_parent_uni) {
|
||||
self.get_or_create_normal_deck(immediate_parent)?;
|
||||
parents.insert(immediate_parent_uni);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -14,6 +14,7 @@ pub mod card;
|
|||
pub mod cloze;
|
||||
pub mod collection;
|
||||
pub mod config;
|
||||
pub mod dbcheck;
|
||||
pub mod deckconf;
|
||||
pub mod decks;
|
||||
pub mod err;
|
||||
|
|
Loading…
Reference in a new issue