mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
migrate cards and notes
This commit is contained in:
parent
7550e6241c
commit
95735f106a
7 changed files with 234 additions and 194 deletions
|
@ -21,6 +21,10 @@ message Int32 {
|
|||
sint32 val = 1;
|
||||
}
|
||||
|
||||
message UInt32 {
|
||||
uint32 val = 1;
|
||||
}
|
||||
|
||||
message Int64 {
|
||||
int64 val = 1;
|
||||
}
|
||||
|
@ -37,6 +41,19 @@ message Bool {
|
|||
bool val = 1;
|
||||
}
|
||||
|
||||
message NoteTypeID {
|
||||
int64 ntid = 1;
|
||||
}
|
||||
|
||||
message NoteID {
|
||||
int64 nid = 1;
|
||||
}
|
||||
|
||||
message CardID {
|
||||
int64 cid = 1;
|
||||
}
|
||||
|
||||
|
||||
// New style RPC definitions
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -86,6 +103,22 @@ service BackendService {
|
|||
rpc NewDeckConfigLegacy (Empty) returns (Bytes);
|
||||
rpc RemoveDeckConfig (Int64) returns (Empty);
|
||||
|
||||
// cards
|
||||
|
||||
rpc GetCard (CardID) returns (Card);
|
||||
rpc UpdateCard (Card) returns (Empty);
|
||||
rpc AddCard (Card) returns (CardID);
|
||||
|
||||
// notes
|
||||
|
||||
rpc NewNote (NoteTypeID) returns (Note);
|
||||
rpc AddNote (AddNoteIn) returns (NoteID);
|
||||
rpc UpdateNote (Note) returns (Empty);
|
||||
rpc GetNote (NoteID) returns (Note);
|
||||
rpc AddNoteTags (AddNoteTagsIn) returns (UInt32);
|
||||
rpc UpdateNoteTags (UpdateNoteTagsIn) returns (UInt32);
|
||||
rpc ClozeNumbersInNote (Note) returns (ClozeNumbersInNoteOut);
|
||||
|
||||
// misc
|
||||
|
||||
rpc CheckDatabase (Empty) returns (CheckDatabaseOut);
|
||||
|
@ -344,9 +377,6 @@ message BackendInput {
|
|||
Empty restore_trash = 35;
|
||||
OpenCollectionIn open_collection = 36;
|
||||
CloseCollectionIn close_collection = 37;
|
||||
int64 get_card = 38;
|
||||
Card update_card = 39;
|
||||
Card add_card = 40;
|
||||
Empty abort_media_sync = 46;
|
||||
Empty before_upload = 47;
|
||||
RegisterTagsIn register_tags = 48;
|
||||
|
@ -364,19 +394,12 @@ message BackendInput {
|
|||
Empty get_notetype_names_and_counts = 63;
|
||||
string get_notetype_id_by_name = 64;
|
||||
int64 remove_notetype = 65;
|
||||
int64 new_note = 66;
|
||||
AddNoteIn add_note = 67;
|
||||
Note update_note = 68;
|
||||
int64 get_note = 69;
|
||||
FieldNamesForNotesIn field_names_for_notes = 78;
|
||||
FindAndReplaceIn find_and_replace = 79;
|
||||
AfterNoteUpdatesIn after_note_updates = 80;
|
||||
AddNoteTagsIn add_note_tags = 81;
|
||||
UpdateNoteTagsIn update_note_tags = 82;
|
||||
int32 set_local_minutes_west = 83;
|
||||
Empty get_preferences = 84;
|
||||
Preferences set_preferences = 85;
|
||||
Note cloze_numbers_in_note = 87;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -388,7 +411,6 @@ message BackendOutput {
|
|||
string studied_today = 32;
|
||||
string congrats_learn_msg = 33;
|
||||
Empty abort_media_sync = 46;
|
||||
ClozeNumbersInNoteOut cloze_numbers_in_note = 87;
|
||||
|
||||
// fallible commands
|
||||
string add_media_file = 26;
|
||||
|
@ -396,9 +418,6 @@ message BackendOutput {
|
|||
Empty restore_trash = 35;
|
||||
Empty open_collection = 36;
|
||||
Empty close_collection = 37;
|
||||
GetCardOut get_card = 38;
|
||||
Empty update_card = 39;
|
||||
int64 add_card = 40;
|
||||
Empty before_upload = 47;
|
||||
bool register_tags = 48;
|
||||
AllTagsOut all_tags = 50;
|
||||
|
@ -414,15 +433,9 @@ message BackendOutput {
|
|||
NoteTypeUseCounts get_notetype_names_and_counts = 63;
|
||||
int64 get_notetype_id_by_name = 64;
|
||||
Empty remove_notetype = 65;
|
||||
Note new_note = 66;
|
||||
int64 add_note = 67;
|
||||
Empty update_note = 68;
|
||||
Note get_note = 69;
|
||||
FieldNamesForNotesOut field_names_for_notes = 78;
|
||||
uint32 find_and_replace = 79;
|
||||
Empty after_note_updates = 80;
|
||||
uint32 add_note_tags = 81;
|
||||
uint32 update_note_tags = 82;
|
||||
Empty set_local_minutes_west = 83;
|
||||
Preferences get_preferences = 84;
|
||||
Empty set_preferences = 85;
|
||||
|
@ -698,11 +711,6 @@ message BuiltinSearchOrder {
|
|||
bool reverse = 2;
|
||||
}
|
||||
|
||||
|
||||
message GetCardOut {
|
||||
Card card = 1;
|
||||
}
|
||||
|
||||
message CloseCollectionIn {
|
||||
bool downgrade_to_schema11 = 1;
|
||||
}
|
||||
|
|
|
@ -467,4 +467,4 @@ and notes.mid = ? and cards.ord = ?""",
|
|||
def _availClozeOrds(self, m: NoteType, flds: str, allowEmpty: bool = True) -> List:
|
||||
print("_availClozeOrds() is deprecated; use note.cloze_numbers_in_fields()")
|
||||
note = anki.rsbackend.BackendNote(fields=[flds])
|
||||
return self.col.backend.cloze_numbers_in_note(note)
|
||||
return list(self.col.backend.cloze_numbers_in_note(note))
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, List, Optional, Tuple
|
||||
from typing import Any, List, Optional, Sequence, Tuple
|
||||
|
||||
import anki # pylint: disable=unused-import
|
||||
from anki import hooks
|
||||
|
@ -82,7 +82,7 @@ class Note:
|
|||
|
||||
_model = property(model)
|
||||
|
||||
def cloze_numbers_in_fields(self) -> List[int]:
|
||||
def cloze_numbers_in_fields(self) -> Sequence[int]:
|
||||
return self.col.backend.cloze_numbers_in_note(self.to_backend_note())
|
||||
|
||||
# Dict interface
|
||||
|
|
|
@ -306,20 +306,6 @@ class RustBackend:
|
|||
def _db_command(self, input: Dict[str, Any]) -> Any:
|
||||
return orjson.loads(self._backend.db_command(orjson.dumps(input)))
|
||||
|
||||
def get_card(self, cid: int) -> Optional[pb.Card]:
|
||||
output = self._run_command(pb.BackendInput(get_card=cid)).get_card
|
||||
if output.HasField("card"):
|
||||
return output.card
|
||||
else:
|
||||
return None
|
||||
|
||||
def update_card(self, card: BackendCard) -> None:
|
||||
self._run_command(pb.BackendInput(update_card=card))
|
||||
|
||||
# returns the new card id
|
||||
def add_card(self, card: BackendCard) -> int:
|
||||
return self._run_command(pb.BackendInput(add_card=card)).add_card
|
||||
|
||||
def abort_media_sync(self):
|
||||
self._run_command(pb.BackendInput(abort_media_sync=pb.Empty()))
|
||||
|
||||
|
@ -442,23 +428,6 @@ class RustBackend:
|
|||
def remove_notetype(self, ntid: int) -> None:
|
||||
self._run_command(pb.BackendInput(remove_notetype=ntid), release_gil=True)
|
||||
|
||||
def new_note(self, ntid: int) -> BackendNote:
|
||||
return self._run_command(pb.BackendInput(new_note=ntid)).new_note
|
||||
|
||||
def add_note(self, note: BackendNote, deck_id: int) -> int:
|
||||
return self._run_command(
|
||||
pb.BackendInput(add_note=pb.AddNoteIn(note=note, deck_id=deck_id))
|
||||
).add_note
|
||||
|
||||
def update_note(self, note: BackendNote) -> None:
|
||||
self._run_command(pb.BackendInput(update_note=note))
|
||||
|
||||
def get_note(self, nid) -> Optional[BackendNote]:
|
||||
try:
|
||||
return self._run_command(pb.BackendInput(get_note=nid)).get_note
|
||||
except NotFoundError:
|
||||
return None
|
||||
|
||||
def field_names_for_note_ids(self, nids: List[int]) -> Sequence[str]:
|
||||
return self._run_command(
|
||||
pb.BackendInput(field_names_for_notes=pb.FieldNamesForNotesIn(nids=nids)),
|
||||
|
@ -502,22 +471,6 @@ class RustBackend:
|
|||
release_gil=True,
|
||||
)
|
||||
|
||||
def add_note_tags(self, nids: List[int], tags: str) -> int:
|
||||
return self._run_command(
|
||||
pb.BackendInput(add_note_tags=pb.AddNoteTagsIn(nids=nids, tags=tags))
|
||||
).add_note_tags
|
||||
|
||||
def update_note_tags(
|
||||
self, nids: List[int], tags: str, replacement: str, regex: bool
|
||||
) -> int:
|
||||
return self._run_command(
|
||||
pb.BackendInput(
|
||||
update_note_tags=pb.UpdateNoteTagsIn(
|
||||
nids=nids, tags=tags, replacement=replacement, regex=regex
|
||||
)
|
||||
)
|
||||
).update_note_tags
|
||||
|
||||
def set_local_minutes_west(self, mins: int) -> None:
|
||||
self._run_command(pb.BackendInput(set_local_minutes_west=mins))
|
||||
|
||||
|
@ -529,13 +482,6 @@ class RustBackend:
|
|||
def set_preferences(self, prefs: pb.Preferences) -> None:
|
||||
self._run_command(pb.BackendInput(set_preferences=prefs))
|
||||
|
||||
def cloze_numbers_in_note(self, note: pb.Note) -> List[int]:
|
||||
return list(
|
||||
self._run_command(
|
||||
pb.BackendInput(cloze_numbers_in_note=note)
|
||||
).cloze_numbers_in_note.numbers
|
||||
)
|
||||
|
||||
def _run_command2(self, method: int, input: Any) -> bytes:
|
||||
input_bytes = input.SerializeToString()
|
||||
try:
|
||||
|
@ -731,10 +677,70 @@ class RustBackend:
|
|||
output.ParseFromString(self._run_command2(27, input))
|
||||
return output
|
||||
|
||||
def get_card(self, cid: int) -> pb.Card:
|
||||
input = pb.CardID(cid=cid)
|
||||
output = pb.Card()
|
||||
output.ParseFromString(self._run_command2(28, input))
|
||||
return output
|
||||
|
||||
def update_card(self, input: pb.Card) -> pb.Empty:
|
||||
output = pb.Empty()
|
||||
output.ParseFromString(self._run_command2(29, input))
|
||||
return output
|
||||
|
||||
def add_card(self, input: pb.Card) -> int:
|
||||
output = pb.CardID()
|
||||
output.ParseFromString(self._run_command2(30, input))
|
||||
return output.cid
|
||||
|
||||
def new_note(self, ntid: int) -> pb.Note:
|
||||
input = pb.NoteTypeID(ntid=ntid)
|
||||
output = pb.Note()
|
||||
output.ParseFromString(self._run_command2(31, input))
|
||||
return output
|
||||
|
||||
def add_note(self, note: pb.Note, deck_id: int) -> int:
|
||||
input = pb.AddNoteIn(note=note, deck_id=deck_id)
|
||||
output = pb.NoteID()
|
||||
output.ParseFromString(self._run_command2(32, input))
|
||||
return output.nid
|
||||
|
||||
def update_note(self, input: pb.Note) -> pb.Empty:
|
||||
output = pb.Empty()
|
||||
output.ParseFromString(self._run_command2(33, input))
|
||||
return output
|
||||
|
||||
def get_note(self, nid: int) -> pb.Note:
|
||||
input = pb.NoteID(nid=nid)
|
||||
output = pb.Note()
|
||||
output.ParseFromString(self._run_command2(34, input))
|
||||
return output
|
||||
|
||||
def add_note_tags(self, nids: Sequence[int], tags: str) -> int:
|
||||
input = pb.AddNoteTagsIn(nids=nids, tags=tags)
|
||||
output = pb.UInt32()
|
||||
output.ParseFromString(self._run_command2(35, input))
|
||||
return output.val
|
||||
|
||||
def update_note_tags(
|
||||
self, nids: Sequence[int], tags: str, replacement: str, regex: bool
|
||||
) -> int:
|
||||
input = pb.UpdateNoteTagsIn(
|
||||
nids=nids, tags=tags, replacement=replacement, regex=regex
|
||||
)
|
||||
output = pb.UInt32()
|
||||
output.ParseFromString(self._run_command2(36, input))
|
||||
return output.val
|
||||
|
||||
def cloze_numbers_in_note(self, input: pb.Note) -> Sequence[int]:
|
||||
output = pb.ClozeNumbersInNoteOut()
|
||||
output.ParseFromString(self._run_command2(37, input))
|
||||
return output.numbers
|
||||
|
||||
def check_database(self) -> Sequence[str]:
|
||||
input = pb.Empty()
|
||||
output = pb.CheckDatabaseOut()
|
||||
output.ParseFromString(self._run_command2(28, input))
|
||||
output.ParseFromString(self._run_command2(38, input))
|
||||
return output.problems
|
||||
|
||||
# @@AUTOGEN@@
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import time
|
||||
|
||||
from anki.consts import MODEL_CLOZE
|
||||
from anki.rsbackend import NotFoundError
|
||||
from anki.utils import isWin, stripHTML
|
||||
from tests.shared import getEmptyCol
|
||||
|
||||
|
@ -323,7 +324,7 @@ def test_modelChange():
|
|||
try:
|
||||
c1.load()
|
||||
assert 0
|
||||
except AssertionError:
|
||||
except NotFoundError:
|
||||
pass
|
||||
# but we have two cards, as a new one was generated
|
||||
assert len(f.cards()) == 2
|
||||
|
|
|
@ -77,8 +77,16 @@ def get_input_assign(msg):
|
|||
|
||||
|
||||
def render_method(method, idx):
|
||||
input_args = get_input_args(method.input_type)
|
||||
input_assign = get_input_assign(method.input_type)
|
||||
input_name = method.input_type.name
|
||||
if input_name.endswith("In") or len(method.input_type.fields) < 2:
|
||||
input_args = get_input_args(method.input_type)
|
||||
input_assign = get_input_assign(method.input_type)
|
||||
input_assign_outer = (
|
||||
f"input = pb.{method.input_type.name}({input_assign})\n "
|
||||
)
|
||||
else:
|
||||
input_args = f"self, input: pb.{input_name}"
|
||||
input_assign_outer = ""
|
||||
name = fix_snakecase(stringcase.snakecase(method.name))
|
||||
if len(method.output_type.fields) == 1:
|
||||
# unwrap single return arg
|
||||
|
@ -90,8 +98,7 @@ def render_method(method, idx):
|
|||
return_type = f"pb.{method.output_type.name}"
|
||||
return f"""\
|
||||
def {name}({input_args}) -> {return_type}:
|
||||
input = pb.{method.input_type.name}({input_assign})
|
||||
output = pb.{method.output_type.name}()
|
||||
{input_assign_outer}output = pb.{method.output_type.name}()
|
||||
output.ParseFromString(self._run_command2({idx+1}, input))
|
||||
return output{single_field}
|
||||
"""
|
||||
|
|
|
@ -166,12 +166,36 @@ impl From<i64> for pb::Int64 {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<u32> for pb::UInt32 {
|
||||
fn from(val: u32) -> Self {
|
||||
pb::UInt32 { val }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<()> for pb::Empty {
|
||||
fn from(_val: ()) -> Self {
|
||||
pb::Empty {}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pb::CardId> for CardID {
|
||||
fn from(cid: pb::CardId) -> Self {
|
||||
CardID(cid.cid)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pb::NoteId> for NoteID {
|
||||
fn from(nid: pb::NoteId) -> Self {
|
||||
NoteID(nid.nid)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pb::NoteTypeId> for NoteTypeID {
|
||||
fn from(ntid: pb::NoteTypeId) -> Self {
|
||||
NoteTypeID(ntid.ntid)
|
||||
}
|
||||
}
|
||||
|
||||
impl BackendService for Backend {
|
||||
// card rendering
|
||||
|
||||
|
@ -486,6 +510,106 @@ impl BackendService for Backend {
|
|||
.map(Into::into)
|
||||
}
|
||||
|
||||
// cards
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
fn get_card(&mut self, input: pb::CardId) -> BackendResult<pb::Card> {
|
||||
self.with_col(|col| {
|
||||
col.storage
|
||||
.get_card(input.into())
|
||||
.and_then(|opt| opt.ok_or(AnkiError::NotFound))
|
||||
.map(card_to_pb)
|
||||
})
|
||||
}
|
||||
|
||||
fn update_card(&mut self, input: pb::Card) -> BackendResult<Empty> {
|
||||
let mut card = pbcard_to_native(input)?;
|
||||
self.with_col(|col| {
|
||||
col.transact(None, |ctx| {
|
||||
let orig = ctx
|
||||
.storage
|
||||
.get_card(card.id)?
|
||||
.ok_or_else(|| AnkiError::invalid_input("missing card"))?;
|
||||
ctx.update_card(&mut card, &orig)
|
||||
})
|
||||
})
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
fn add_card(&mut self, input: pb::Card) -> BackendResult<pb::CardId> {
|
||||
let mut card = pbcard_to_native(input)?;
|
||||
self.with_col(|col| col.transact(None, |ctx| ctx.add_card(&mut card)))?;
|
||||
Ok(pb::CardId { cid: card.id.0 })
|
||||
}
|
||||
|
||||
// notes
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
fn new_note(&mut self, input: pb::NoteTypeId) -> BackendResult<pb::Note> {
|
||||
self.with_col(|col| {
|
||||
let nt = col.get_notetype(input.into())?.ok_or(AnkiError::NotFound)?;
|
||||
Ok(nt.new_note().into())
|
||||
})
|
||||
}
|
||||
|
||||
fn add_note(&mut self, input: pb::AddNoteIn) -> BackendResult<pb::NoteId> {
|
||||
self.with_col(|col| {
|
||||
let mut note: Note = input.note.ok_or(AnkiError::NotFound)?.into();
|
||||
col.add_note(&mut note, DeckID(input.deck_id))
|
||||
.map(|_| pb::NoteId { nid: note.id.0 })
|
||||
})
|
||||
}
|
||||
|
||||
fn update_note(&mut self, input: pb::Note) -> BackendResult<Empty> {
|
||||
self.with_col(|col| {
|
||||
let mut note: Note = input.into();
|
||||
col.update_note(&mut note)
|
||||
})
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
fn get_note(&mut self, input: pb::NoteId) -> BackendResult<pb::Note> {
|
||||
self.with_col(|col| {
|
||||
col.storage
|
||||
.get_note(input.into())?
|
||||
.ok_or(AnkiError::NotFound)
|
||||
.map(Into::into)
|
||||
})
|
||||
}
|
||||
|
||||
fn add_note_tags(&mut self, input: pb::AddNoteTagsIn) -> BackendResult<pb::UInt32> {
|
||||
self.with_col(|col| {
|
||||
col.add_tags_for_notes(&to_nids(input.nids), &input.tags)
|
||||
.map(|n| n as u32)
|
||||
})
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
fn update_note_tags(&mut self, input: pb::UpdateNoteTagsIn) -> BackendResult<pb::UInt32> {
|
||||
self.with_col(|col| {
|
||||
col.replace_tags_for_notes(
|
||||
&to_nids(input.nids),
|
||||
&input.tags,
|
||||
&input.replacement,
|
||||
input.regex,
|
||||
)
|
||||
.map(|n| (n as u32).into())
|
||||
})
|
||||
}
|
||||
|
||||
fn cloze_numbers_in_note(
|
||||
&mut self,
|
||||
note: pb::Note,
|
||||
) -> BackendResult<pb::ClozeNumbersInNoteOut> {
|
||||
let mut set = HashSet::with_capacity(4);
|
||||
for field in ¬e.fields {
|
||||
add_cloze_numbers_in_string(field, &mut set);
|
||||
}
|
||||
Ok(pb::ClozeNumbersInNoteOut {
|
||||
numbers: set.into_iter().map(|n| n as u32).collect(),
|
||||
})
|
||||
}
|
||||
|
||||
// media
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
|
@ -669,12 +793,6 @@ impl Backend {
|
|||
self.close_collection(input.downgrade_to_schema11)?;
|
||||
OValue::CloseCollection(Empty {})
|
||||
}
|
||||
Value::GetCard(cid) => OValue::GetCard(self.get_card(cid)?),
|
||||
Value::UpdateCard(card) => {
|
||||
self.update_card(card)?;
|
||||
OValue::UpdateCard(pb::Empty {})
|
||||
}
|
||||
Value::AddCard(card) => OValue::AddCard(self.add_card(card)?),
|
||||
Value::AbortMediaSync(_) => {
|
||||
self.abort_media_sync();
|
||||
OValue::AbortMediaSync(pb::Empty {})
|
||||
|
@ -721,13 +839,6 @@ impl Backend {
|
|||
self.remove_notetype(id)?;
|
||||
OValue::RemoveNotetype(pb::Empty {})
|
||||
}
|
||||
Value::NewNote(ntid) => OValue::NewNote(self.new_note(ntid)?),
|
||||
Value::AddNote(input) => OValue::AddNote(self.add_note(input)?),
|
||||
Value::UpdateNote(note) => {
|
||||
self.update_note(note)?;
|
||||
OValue::UpdateNote(pb::Empty {})
|
||||
}
|
||||
Value::GetNote(nid) => OValue::GetNote(self.get_note(nid)?),
|
||||
Value::FieldNamesForNotes(input) => {
|
||||
OValue::FieldNamesForNotes(self.field_names_for_notes(input)?)
|
||||
}
|
||||
|
@ -735,8 +846,6 @@ impl Backend {
|
|||
Value::AfterNoteUpdates(input) => {
|
||||
OValue::AfterNoteUpdates(self.after_note_updates(input)?)
|
||||
}
|
||||
Value::AddNoteTags(input) => OValue::AddNoteTags(self.add_note_tags(input)?),
|
||||
Value::UpdateNoteTags(input) => OValue::UpdateNoteTags(self.update_note_tags(input)?),
|
||||
Value::SetLocalMinutesWest(mins) => OValue::SetLocalMinutesWest({
|
||||
self.set_local_mins_west(mins)?;
|
||||
pb::Empty {}
|
||||
|
@ -746,9 +855,6 @@ impl Backend {
|
|||
self.set_preferences(prefs)?;
|
||||
pb::Empty {}
|
||||
}),
|
||||
Value::ClozeNumbersInNote(note) => {
|
||||
OValue::ClozeNumbersInNote(self.cloze_numbers_in_note(note))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -924,32 +1030,6 @@ impl Backend {
|
|||
self.with_col(|col| db_command_bytes(&col.storage, input))
|
||||
}
|
||||
|
||||
fn get_card(&self, cid: i64) -> Result<pb::GetCardOut> {
|
||||
let card = self.with_col(|col| col.storage.get_card(CardID(cid)))?;
|
||||
Ok(pb::GetCardOut {
|
||||
card: card.map(card_to_pb),
|
||||
})
|
||||
}
|
||||
|
||||
fn update_card(&self, pbcard: pb::Card) -> Result<()> {
|
||||
let mut card = pbcard_to_native(pbcard)?;
|
||||
self.with_col(|col| {
|
||||
col.transact(None, |ctx| {
|
||||
let orig = ctx
|
||||
.storage
|
||||
.get_card(card.id)?
|
||||
.ok_or_else(|| AnkiError::invalid_input("missing card"))?;
|
||||
ctx.update_card(&mut card, &orig)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn add_card(&self, pbcard: pb::Card) -> Result<i64> {
|
||||
let mut card = pbcard_to_native(pbcard)?;
|
||||
self.with_col(|col| col.transact(None, |ctx| ctx.add_card(&mut card)))?;
|
||||
Ok(card.id.0)
|
||||
}
|
||||
|
||||
fn before_upload(&self) -> Result<()> {
|
||||
self.with_col(|col| col.before_upload())
|
||||
}
|
||||
|
@ -1104,39 +1184,6 @@ impl Backend {
|
|||
self.with_col(|col| col.remove_notetype(NoteTypeID(id)))
|
||||
}
|
||||
|
||||
fn new_note(&self, ntid: i64) -> Result<pb::Note> {
|
||||
self.with_col(|col| {
|
||||
let nt = col
|
||||
.get_notetype(NoteTypeID(ntid))?
|
||||
.ok_or(AnkiError::NotFound)?;
|
||||
Ok(nt.new_note().into())
|
||||
})
|
||||
}
|
||||
|
||||
fn add_note(&self, input: pb::AddNoteIn) -> Result<i64> {
|
||||
self.with_col(|col| {
|
||||
let mut note: Note = input.note.ok_or(AnkiError::NotFound)?.into();
|
||||
col.add_note(&mut note, DeckID(input.deck_id))
|
||||
.map(|_| note.id.0)
|
||||
})
|
||||
}
|
||||
|
||||
fn update_note(&self, pbnote: pb::Note) -> Result<()> {
|
||||
self.with_col(|col| {
|
||||
let mut note: Note = pbnote.into();
|
||||
col.update_note(&mut note)
|
||||
})
|
||||
}
|
||||
|
||||
fn get_note(&self, nid: i64) -> Result<pb::Note> {
|
||||
self.with_col(|col| {
|
||||
col.storage
|
||||
.get_note(NoteID(nid))?
|
||||
.ok_or(AnkiError::NotFound)
|
||||
.map(Into::into)
|
||||
})
|
||||
}
|
||||
|
||||
fn field_names_for_notes(
|
||||
&self,
|
||||
input: pb::FieldNamesForNotesIn,
|
||||
|
@ -1184,25 +1231,6 @@ impl Backend {
|
|||
})
|
||||
}
|
||||
|
||||
fn add_note_tags(&self, input: pb::AddNoteTagsIn) -> Result<u32> {
|
||||
self.with_col(|col| {
|
||||
col.add_tags_for_notes(&to_nids(input.nids), &input.tags)
|
||||
.map(|n| n as u32)
|
||||
})
|
||||
}
|
||||
|
||||
fn update_note_tags(&self, input: pb::UpdateNoteTagsIn) -> Result<u32> {
|
||||
self.with_col(|col| {
|
||||
col.replace_tags_for_notes(
|
||||
&to_nids(input.nids),
|
||||
&input.tags,
|
||||
&input.replacement,
|
||||
input.regex,
|
||||
)
|
||||
.map(|n| n as u32)
|
||||
})
|
||||
}
|
||||
|
||||
fn set_local_mins_west(&self, mins: i32) -> Result<()> {
|
||||
self.with_col(|col| col.transact(None, |col| col.set_local_mins_west(mins)))
|
||||
}
|
||||
|
@ -1215,16 +1243,6 @@ impl Backend {
|
|||
self.with_col(|col| col.transact(None, |col| col.set_preferences(prefs)))
|
||||
}
|
||||
|
||||
fn cloze_numbers_in_note(&self, note: pb::Note) -> pb::ClozeNumbersInNoteOut {
|
||||
let mut set = HashSet::with_capacity(4);
|
||||
for field in ¬e.fields {
|
||||
add_cloze_numbers_in_string(field, &mut set);
|
||||
}
|
||||
pb::ClozeNumbersInNoteOut {
|
||||
numbers: set.into_iter().map(|n| n as u32).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_stock_notetype_legacy(&self, kind: i32) -> Result<Vec<u8>> {
|
||||
// fixme: use individual functions instead of full vec
|
||||
let mut all = all_stock_notetypes(&self.i18n);
|
||||
|
|
Loading…
Reference in a new issue