migrate notetypes, update GIL list

This commit is contained in:
Damien Elmes 2020-05-23 20:43:55 +10:00
parent 6710e3d528
commit a105037ec9
8 changed files with 302 additions and 274 deletions

View file

@ -128,6 +128,18 @@ service BackendService {
rpc AddNoteTags (AddNoteTagsIn) returns (UInt32); rpc AddNoteTags (AddNoteTagsIn) returns (UInt32);
rpc UpdateNoteTags (UpdateNoteTagsIn) returns (UInt32); rpc UpdateNoteTags (UpdateNoteTagsIn) returns (UInt32);
rpc ClozeNumbersInNote (Note) returns (ClozeNumbersInNoteOut); rpc ClozeNumbersInNote (Note) returns (ClozeNumbersInNoteOut);
rpc AfterNoteUpdates (AfterNoteUpdatesIn) returns (Empty);
rpc FieldNamesForNotes (FieldNamesForNotesIn) returns (FieldNamesForNotesOut);
// note types
rpc AddOrUpdateNotetype (AddOrUpdateNotetypeIn) returns (NoteTypeID);
rpc GetStockNotetypeLegacy (GetStockNotetypeIn) returns (Json);
rpc GetNotetypeLegacy (NoteTypeID) returns (Json);
rpc GetNotetypeNames (Empty) returns (NoteTypeNames);
rpc GetNotetypeNamesAndCounts (Empty) returns (NoteTypeUseCounts);
rpc GetNotetypeIDByName (String) returns (NoteTypeID);
rpc RemoveNotetype (NoteTypeID) returns (Empty);
// misc // misc
@ -379,34 +391,31 @@ message I18nBackendInit {
message BackendInput { message BackendInput {
oneof value { oneof value {
AddMediaFileIn add_media_file = 26; AddMediaFileIn add_media_file = 26;
Empty empty_trash = 34;
Empty restore_trash = 35;
Empty abort_media_sync = 46;
TranslateStringIn translate_string = 30; TranslateStringIn translate_string = 30;
FormatTimeSpanIn format_time_span = 31; FormatTimeSpanIn format_time_span = 31;
StudiedTodayIn studied_today = 32; StudiedTodayIn studied_today = 32;
CongratsLearnMsgIn congrats_learn_msg = 33; CongratsLearnMsgIn congrats_learn_msg = 33;
Empty empty_trash = 34;
Empty restore_trash = 35;
OpenCollectionIn open_collection = 36; OpenCollectionIn open_collection = 36;
CloseCollectionIn close_collection = 37; CloseCollectionIn close_collection = 37;
Empty abort_media_sync = 46;
Empty before_upload = 47; Empty before_upload = 47;
RegisterTagsIn register_tags = 48; RegisterTagsIn register_tags = 48;
Empty all_tags = 50; Empty all_tags = 50;
int32 get_changed_tags = 51; int32 get_changed_tags = 51;
string get_config_json = 52; string get_config_json = 52;
SetConfigJson set_config_json = 53; SetConfigJson set_config_json = 53;
bytes set_all_config = 54; bytes set_all_config = 54;
Empty get_all_config = 55; Empty get_all_config = 55;
int32 get_changed_notetypes = 56;
AddOrUpdateNotetypeIn add_or_update_notetype = 57;
StockNoteType get_stock_notetype_legacy = 60;
int64 get_notetype_legacy = 61;
Empty get_notetype_names = 62;
Empty get_notetype_names_and_counts = 63;
string get_notetype_id_by_name = 64;
int64 remove_notetype = 65;
FieldNamesForNotesIn field_names_for_notes = 78;
FindAndReplaceIn find_and_replace = 79; FindAndReplaceIn find_and_replace = 79;
AfterNoteUpdatesIn after_note_updates = 80;
int32 set_local_minutes_west = 83; int32 set_local_minutes_west = 83;
Empty get_preferences = 84; Empty get_preferences = 84;
Preferences set_preferences = 85; Preferences set_preferences = 85;
@ -436,20 +445,12 @@ message BackendOutput {
Empty set_config_json = 53; Empty set_config_json = 53;
Empty set_all_config = 54; Empty set_all_config = 54;
bytes get_all_config = 55; bytes get_all_config = 55;
bytes get_changed_notetypes = 56;
int64 add_or_update_notetype = 57;
bytes get_notetype_legacy = 61;
NoteTypeNames get_notetype_names = 62;
NoteTypeUseCounts get_notetype_names_and_counts = 63;
int64 get_notetype_id_by_name = 64;
Empty remove_notetype = 65;
FieldNamesForNotesOut field_names_for_notes = 78;
uint32 find_and_replace = 79; uint32 find_and_replace = 79;
Empty after_note_updates = 80;
Empty set_local_minutes_west = 83; Empty set_local_minutes_west = 83;
Preferences get_preferences = 84; Preferences get_preferences = 84;
Empty set_preferences = 85; Empty set_preferences = 85;
bytes get_stock_notetype_legacy = 60;
BackendError error = 2047; BackendError error = 2047;
} }
@ -766,6 +767,10 @@ enum StockNoteType {
STOCK_NOTE_TYPE_CLOZE = 4; STOCK_NOTE_TYPE_CLOZE = 4;
} }
message GetStockNotetypeIn {
StockNoteType kind = 1;
}
message NoteTypeNames { message NoteTypeNames {
repeated NoteTypeNameID entries = 1; repeated NoteTypeNameID entries = 1;
} }

View file

@ -42,7 +42,7 @@ def findReplace(
def fieldNamesForNotes(col: Collection, nids: List[int]) -> List[str]: def fieldNamesForNotes(col: Collection, nids: List[int]) -> List[str]:
return list(col.backend.field_names_for_note_ids(nids)) return list(col.backend.field_names_for_notes(nids))
# Find duplicates # Find duplicates

View file

@ -5,13 +5,13 @@ from __future__ import annotations
import copy import copy
import time import time
from typing import Any, Dict, List, Optional, Tuple, Union from typing import Any, Dict, List, Optional, Sequence, Tuple, Union
import anki # pylint: disable=unused-import import anki # pylint: disable=unused-import
import anki.backend_pb2 as pb import anki.backend_pb2 as pb
from anki.consts import * from anki.consts import *
from anki.lang import _ from anki.lang import _
from anki.rsbackend import StockNoteType from anki.rsbackend import NotFoundError, StockNoteType, from_json_bytes, to_json_bytes
from anki.utils import checksum, ids2str, intTime, joinFields, splitFields from anki.utils import checksum, ids2str, intTime, joinFields, splitFields
# types # types
@ -109,11 +109,11 @@ class ModelManager:
# Listing note types # Listing note types
############################################################# #############################################################
def all_names_and_ids(self) -> List[pb.NoteTypeNameID]: def all_names_and_ids(self) -> Sequence[pb.NoteTypeNameID]:
return self.col.backend.get_notetype_names_and_ids() return self.col.backend.get_notetype_names()
def all_use_counts(self) -> List[pb.NoteTypeNameIDUseCount]: def all_use_counts(self) -> Sequence[pb.NoteTypeNameIDUseCount]:
return self.col.backend.get_notetype_use_counts() return self.col.backend.get_notetype_names_and_counts()
# legacy # legacy
@ -149,7 +149,10 @@ class ModelManager:
############################################################# #############################################################
def id_for_name(self, name: str) -> Optional[int]: def id_for_name(self, name: str) -> Optional[int]:
return self.col.backend.get_notetype_id_by_name(name) try:
return self.col.backend.get_notetype_id_by_name(name)
except NotFoundError:
return None
def get(self, id: int) -> Optional[NoteType]: def get(self, id: int) -> Optional[NoteType]:
"Get model with ID, or None." "Get model with ID, or None."
@ -161,9 +164,11 @@ class ModelManager:
nt = self._get_cached(id) nt = self._get_cached(id)
if not nt: if not nt:
nt = self.col.backend.get_notetype_legacy(id) try:
if nt: nt = from_json_bytes(self.col.backend.get_notetype_legacy(id))
self._update_cache(nt) self._update_cache(nt)
except NotFoundError:
return None
return nt return nt
def all(self) -> List[NoteType]: def all(self) -> List[NoteType]:
@ -181,8 +186,10 @@ class ModelManager:
def new(self, name: str) -> NoteType: def new(self, name: str) -> NoteType:
"Create a new model, and return it." "Create a new model, and return it."
# caller should call save() after modifying # caller should call save() after modifying
nt = self.col.backend.get_stock_notetype_legacy( nt = from_json_bytes(
StockNoteType.STOCK_NOTE_TYPE_BASIC self.col.backend.get_stock_notetype_legacy(
StockNoteType.STOCK_NOTE_TYPE_BASIC
)
) )
nt["flds"] = [] nt["flds"] = []
nt["tmpls"] = [] nt["tmpls"] = []
@ -215,7 +222,9 @@ class ModelManager:
"Add or update an existing model. Use .save() instead." "Add or update an existing model. Use .save() instead."
self._remove_from_cache(m["id"]) self._remove_from_cache(m["id"])
self.ensureNameUnique(m) self.ensureNameUnique(m)
self.col.backend.add_or_update_notetype(m, preserve_usn=preserve_usn) m["id"] = self.col.backend.add_or_update_notetype(
to_json_bytes(m), preserve_usn_and_mtime=preserve_usn
)
self.setCurrent(m) self.setCurrent(m)
self._mutate_after_write(m) self._mutate_after_write(m)
@ -268,8 +277,10 @@ class ModelManager:
def new_field(self, name: str) -> Field: def new_field(self, name: str) -> Field:
assert isinstance(name, str) assert isinstance(name, str)
nt = self.col.backend.get_stock_notetype_legacy( nt = from_json_bytes(
StockNoteType.STOCK_NOTE_TYPE_BASIC self.col.backend.get_stock_notetype_legacy(
StockNoteType.STOCK_NOTE_TYPE_BASIC
)
) )
field = nt["flds"][0] field = nt["flds"][0]
field["name"] = name field["name"] = name
@ -327,8 +338,10 @@ class ModelManager:
################################################## ##################################################
def new_template(self, name: str) -> Template: def new_template(self, name: str) -> Template:
nt = self.col.backend.get_stock_notetype_legacy( nt = from_json_bytes(
StockNoteType.STOCK_NOTE_TYPE_BASIC self.col.backend.get_stock_notetype_legacy(
StockNoteType.STOCK_NOTE_TYPE_BASIC
)
) )
template = nt["tmpls"][0] template = nt["tmpls"][0]
template["name"] = name template["name"] = name

View file

@ -370,70 +370,6 @@ class RustBackend:
def set_all_config(self, conf: Dict[str, Any]): def set_all_config(self, conf: Dict[str, Any]):
self._run_command(pb.BackendInput(set_all_config=orjson.dumps(conf))) self._run_command(pb.BackendInput(set_all_config=orjson.dumps(conf)))
def get_changed_notetypes(self, usn: int) -> Dict[str, Dict[str, Any]]:
jstr = self._run_command(
pb.BackendInput(get_changed_notetypes=usn)
).get_changed_notetypes
return orjson.loads(jstr)
def get_stock_notetype_legacy(self, kind: StockNoteType) -> Dict[str, Any]:
bytes = self._run_command(
pb.BackendInput(get_stock_notetype_legacy=kind)
).get_stock_notetype_legacy
return orjson.loads(bytes)
def get_notetype_names_and_ids(self) -> List[pb.NoteTypeNameID]:
return list(
self._run_command(
pb.BackendInput(get_notetype_names=pb.Empty())
).get_notetype_names.entries
)
def get_notetype_use_counts(self) -> List[pb.NoteTypeNameIDUseCount]:
return list(
self._run_command(
pb.BackendInput(get_notetype_names_and_counts=pb.Empty())
).get_notetype_names_and_counts.entries
)
def get_notetype_legacy(self, ntid: int) -> Optional[Dict]:
try:
bytes = self._run_command(
pb.BackendInput(get_notetype_legacy=ntid)
).get_notetype_legacy
except NotFoundError:
return None
return orjson.loads(bytes)
def get_notetype_id_by_name(self, name: str) -> Optional[int]:
return (
self._run_command(
pb.BackendInput(get_notetype_id_by_name=name)
).get_notetype_id_by_name
or None
)
def add_or_update_notetype(self, nt: Dict[str, Any], preserve_usn: bool) -> None:
bjson = orjson.dumps(nt)
id = self._run_command(
pb.BackendInput(
add_or_update_notetype=pb.AddOrUpdateNotetypeIn(
json=bjson, preserve_usn_and_mtime=preserve_usn
)
),
release_gil=True,
).add_or_update_notetype
nt["id"] = id
def remove_notetype(self, ntid: int) -> None:
self._run_command(pb.BackendInput(remove_notetype=ntid), release_gil=True)
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)),
release_gil=True,
).field_names_for_notes.fields
def find_and_replace( def find_and_replace(
self, self,
nids: List[int], nids: List[int],
@ -457,20 +393,6 @@ class RustBackend:
release_gil=True, release_gil=True,
).find_and_replace ).find_and_replace
def after_note_updates(
self, nids: List[int], generate_cards: bool, mark_notes_modified: bool
) -> None:
self._run_command(
pb.BackendInput(
after_note_updates=pb.AfterNoteUpdatesIn(
nids=nids,
generate_cards=generate_cards,
mark_notes_modified=mark_notes_modified,
)
),
release_gil=True,
)
def set_local_minutes_west(self, mins: int) -> None: def set_local_minutes_west(self, mins: int) -> None:
self._run_command(pb.BackendInput(set_local_minutes_west=mins)) self._run_command(pb.BackendInput(set_local_minutes_west=mins))
@ -599,15 +521,15 @@ class RustBackend:
def deck_tree_legacy(self) -> bytes: def deck_tree_legacy(self) -> bytes:
input = pb.Empty() input = pb.Empty()
output = pb.Bytes() output = pb.Json()
output.ParseFromString(self._run_command2(16, input)) output.ParseFromString(self._run_command2(16, input))
return output.val return output.json
def get_all_decks_legacy(self) -> bytes: def get_all_decks_legacy(self) -> bytes:
input = pb.Empty() input = pb.Empty()
output = pb.Bytes() output = pb.Json()
output.ParseFromString(self._run_command2(17, input)) output.ParseFromString(self._run_command2(17, input))
return output.val return output.json
def get_deck_id_by_name(self, val: str) -> int: def get_deck_id_by_name(self, val: str) -> int:
input = pb.String(val=val) input = pb.String(val=val)
@ -617,9 +539,9 @@ class RustBackend:
def get_deck_legacy(self, did: int) -> bytes: def get_deck_legacy(self, did: int) -> bytes:
input = pb.DeckID(did=did) input = pb.DeckID(did=did)
output = pb.Bytes() output = pb.Json()
output.ParseFromString(self._run_command2(19, input)) output.ParseFromString(self._run_command2(19, input))
return output.val return output.json
def get_deck_names( def get_deck_names(
self, skip_empty_default: bool, include_filtered: bool self, skip_empty_default: bool, include_filtered: bool
@ -633,9 +555,9 @@ class RustBackend:
def new_deck_legacy(self, val: bool) -> bytes: def new_deck_legacy(self, val: bool) -> bytes:
input = pb.Bool(val=val) input = pb.Bool(val=val)
output = pb.Bytes() output = pb.Json()
output.ParseFromString(self._run_command2(21, input)) output.ParseFromString(self._run_command2(21, input))
return output.val return output.json
def remove_deck(self, did: int) -> pb.Empty: def remove_deck(self, did: int) -> pb.Empty:
input = pb.DeckID(did=did) input = pb.DeckID(did=did)
@ -655,21 +577,21 @@ class RustBackend:
def all_deck_config_legacy(self) -> bytes: def all_deck_config_legacy(self) -> bytes:
input = pb.Empty() input = pb.Empty()
output = pb.Bytes() output = pb.Json()
output.ParseFromString(self._run_command2(24, input)) output.ParseFromString(self._run_command2(24, input))
return output.val return output.json
def get_deck_config_legacy(self, dcid: int) -> bytes: def get_deck_config_legacy(self, dcid: int) -> bytes:
input = pb.DeckConfigID(dcid=dcid) input = pb.DeckConfigID(dcid=dcid)
output = pb.Bytes() output = pb.Json()
output.ParseFromString(self._run_command2(25, input)) output.ParseFromString(self._run_command2(25, input))
return output.val return output.json
def new_deck_config_legacy(self) -> bytes: def new_deck_config_legacy(self) -> bytes:
input = pb.Empty() input = pb.Empty()
output = pb.Bytes() output = pb.Json()
output.ParseFromString(self._run_command2(26, input)) output.ParseFromString(self._run_command2(26, input))
return output.val return output.json
def remove_deck_config(self, dcid: int) -> pb.Empty: def remove_deck_config(self, dcid: int) -> pb.Empty:
input = pb.DeckConfigID(dcid=dcid) input = pb.DeckConfigID(dcid=dcid)
@ -737,10 +659,72 @@ class RustBackend:
output.ParseFromString(self._run_command2(37, input)) output.ParseFromString(self._run_command2(37, input))
return output.numbers return output.numbers
def after_note_updates(
self, nids: Sequence[int], mark_notes_modified: bool, generate_cards: bool
) -> pb.Empty:
input = pb.AfterNoteUpdatesIn(
nids=nids,
mark_notes_modified=mark_notes_modified,
generate_cards=generate_cards,
)
output = pb.Empty()
output.ParseFromString(self._run_command2(38, input))
return output
def field_names_for_notes(self, nids: Sequence[int]) -> Sequence[str]:
input = pb.FieldNamesForNotesIn(nids=nids)
output = pb.FieldNamesForNotesOut()
output.ParseFromString(self._run_command2(39, input))
return output.fields
def add_or_update_notetype(self, json: bytes, preserve_usn_and_mtime: bool) -> int:
input = pb.AddOrUpdateNotetypeIn(
json=json, preserve_usn_and_mtime=preserve_usn_and_mtime
)
output = pb.NoteTypeID()
output.ParseFromString(self._run_command2(40, input))
return output.ntid
def get_stock_notetype_legacy(self, kind: pb.StockNoteType) -> bytes:
input = pb.GetStockNotetypeIn(kind=kind)
output = pb.Json()
output.ParseFromString(self._run_command2(41, input))
return output.json
def get_notetype_legacy(self, ntid: int) -> bytes:
input = pb.NoteTypeID(ntid=ntid)
output = pb.Json()
output.ParseFromString(self._run_command2(42, input))
return output.json
def get_notetype_names(self) -> Sequence[pb.NoteTypeNameID]:
input = pb.Empty()
output = pb.NoteTypeNames()
output.ParseFromString(self._run_command2(43, input))
return output.entries
def get_notetype_names_and_counts(self) -> Sequence[pb.NoteTypeNameIDUseCount]:
input = pb.Empty()
output = pb.NoteTypeUseCounts()
output.ParseFromString(self._run_command2(44, input))
return output.entries
def get_notetype_id_by_name(self, val: str) -> int:
input = pb.String(val=val)
output = pb.NoteTypeID()
output.ParseFromString(self._run_command2(45, input))
return output.ntid
def remove_notetype(self, ntid: int) -> pb.Empty:
input = pb.NoteTypeID(ntid=ntid)
output = pb.Empty()
output.ParseFromString(self._run_command2(46, input))
return output
def check_database(self) -> Sequence[str]: def check_database(self) -> Sequence[str]:
input = pb.Empty() input = pb.Empty()
output = pb.CheckDatabaseOut() output = pb.CheckDatabaseOut()
output.ParseFromString(self._run_command2(38, input)) output.ParseFromString(self._run_command2(47, input))
return output.problems return output.problems
# @@AUTOGEN@@ # @@AUTOGEN@@

View file

@ -5,7 +5,7 @@ from typing import Callable, List, Tuple
from anki.collection import Collection from anki.collection import Collection
from anki.models import NoteType from anki.models import NoteType
from anki.rsbackend import StockNoteType from anki.rsbackend import StockNoteType, from_json_bytes
# add-on authors can add ("note type name", function_like_addBasicModel) # add-on authors can add ("note type name", function_like_addBasicModel)
# to this list to have it shown in the add/clone note type screen # to this list to have it shown in the add/clone note type screen
@ -13,7 +13,7 @@ models: List[Tuple] = []
def add_stock_notetype(col: Collection, kind: StockNoteType) -> NoteType: def add_stock_notetype(col: Collection, kind: StockNoteType) -> NoteType:
m = col.backend.get_stock_notetype_legacy(kind) m = from_json_bytes(col.backend.get_stock_notetype_legacy(kind))
col.models.add(m) col.models.add(m)
return m return m
@ -55,7 +55,7 @@ def get_stock_notetypes(
), ),
(StockNoteType.STOCK_NOTE_TYPE_CLOZE, addClozeModel), (StockNoteType.STOCK_NOTE_TYPE_CLOZE, addClozeModel),
]: ]:
m = col.backend.get_stock_notetype_legacy(kind) m = from_json_bytes(col.backend.get_stock_notetype_legacy(kind))
out.append((m["name"], func)) out.append((m["name"], func))
# add extras from add-ons # add extras from add-ons
for (name_or_func, func) in models: for (name_or_func, func) in models:

View file

@ -49,8 +49,10 @@ def python_type_inner(field):
return "str" return "str"
elif type == TYPE_BYTES: elif type == TYPE_BYTES:
return "bytes" return "bytes"
elif type == 11: elif type == TYPE_MESSAGE:
return "pb." + field.message_type.name return "pb." + field.message_type.name
elif type == TYPE_ENUM:
return "pb." + field.enum_type.name
else: else:
raise Exception(f"unknown type: {type}") raise Exception(f"unknown type: {type}")

View file

@ -623,6 +623,120 @@ impl BackendService for Backend {
}) })
} }
fn field_names_for_notes(
&mut self,
input: pb::FieldNamesForNotesIn,
) -> BackendResult<pb::FieldNamesForNotesOut> {
self.with_col(|col| {
let nids: Vec<_> = input.nids.into_iter().map(NoteID).collect();
col.storage
.field_names_for_notes(&nids)
.map(|fields| pb::FieldNamesForNotesOut { fields })
})
}
fn after_note_updates(&mut self, input: pb::AfterNoteUpdatesIn) -> BackendResult<Empty> {
self.with_col(|col| {
col.transact(None, |col| {
col.after_note_updates(
&to_nids(input.nids),
input.generate_cards,
input.mark_notes_modified,
)?;
Ok(pb::Empty {})
})
})
}
// notetypes
//-------------------------------------------------------------------
fn get_stock_notetype_legacy(
&mut self,
input: pb::GetStockNotetypeIn,
) -> BackendResult<pb::Json> {
// fixme: use individual functions instead of full vec
let mut all = all_stock_notetypes(&self.i18n);
let idx = (input.kind as usize).min(all.len() - 1);
let nt = all.swap_remove(idx);
let schema11: NoteTypeSchema11 = nt.into();
serde_json::to_vec(&schema11)
.map_err(Into::into)
.map(Into::into)
}
fn get_notetype_names(&mut self, _input: Empty) -> BackendResult<pb::NoteTypeNames> {
self.with_col(|col| {
let entries: Vec<_> = col
.storage
.get_all_notetype_names()?
.into_iter()
.map(|(id, name)| pb::NoteTypeNameId { id: id.0, name })
.collect();
Ok(pb::NoteTypeNames { entries })
})
}
fn get_notetype_names_and_counts(
&mut self,
_input: Empty,
) -> BackendResult<pb::NoteTypeUseCounts> {
self.with_col(|col| {
let entries: Vec<_> = col
.storage
.get_notetype_use_counts()?
.into_iter()
.map(|(id, name, use_count)| pb::NoteTypeNameIdUseCount {
id: id.0,
name,
use_count,
})
.collect();
Ok(pb::NoteTypeUseCounts { entries })
})
}
fn get_notetype_legacy(&mut self, input: pb::NoteTypeId) -> BackendResult<pb::Json> {
self.with_col(|col| {
let schema11: NoteTypeSchema11 = col
.storage
.get_notetype(input.into())?
.ok_or(AnkiError::NotFound)?
.into();
Ok(serde_json::to_vec(&schema11)?).map(Into::into)
})
}
fn get_notetype_id_by_name(&mut self, input: pb::String) -> BackendResult<pb::NoteTypeId> {
self.with_col(|col| {
col.storage
.get_notetype_id(&input.val)
.and_then(|nt| nt.ok_or(AnkiError::NotFound))
.map(|ntid| pb::NoteTypeId { ntid: ntid.0 })
})
}
fn add_or_update_notetype(
&mut self,
input: pb::AddOrUpdateNotetypeIn,
) -> BackendResult<pb::NoteTypeId> {
self.with_col(|col| {
let legacy: NoteTypeSchema11 = serde_json::from_slice(&input.json)?;
let mut nt: NoteType = legacy.into();
if nt.id.0 == 0 {
col.add_notetype(&mut nt)?;
} else {
col.update_notetype(&mut nt, input.preserve_usn_and_mtime)?;
}
Ok(pb::NoteTypeId { ntid: nt.id.0 })
})
}
fn remove_notetype(&mut self, input: pb::NoteTypeId) -> BackendResult<Empty> {
self.with_col(|col| col.remove_notetype(input.into()))
.map(Into::into)
}
// media // media
//------------------------------------------------------------------- //-------------------------------------------------------------------
@ -828,37 +942,7 @@ impl Backend {
pb::Empty {} pb::Empty {}
}), }),
Value::GetAllConfig(_) => OValue::GetAllConfig(self.get_all_config()?), Value::GetAllConfig(_) => OValue::GetAllConfig(self.get_all_config()?),
Value::GetChangedNotetypes(_) => {
OValue::GetChangedNotetypes(self.get_changed_notetypes()?)
}
Value::GetStockNotetypeLegacy(kind) => {
OValue::GetStockNotetypeLegacy(self.get_stock_notetype_legacy(kind)?)
}
Value::GetNotetypeLegacy(id) => {
OValue::GetNotetypeLegacy(self.get_notetype_legacy(id)?)
}
Value::GetNotetypeNames(_) => OValue::GetNotetypeNames(self.get_notetype_names()?),
Value::GetNotetypeNamesAndCounts(_) => {
OValue::GetNotetypeNamesAndCounts(self.get_notetype_use_counts()?)
}
Value::GetNotetypeIdByName(name) => {
OValue::GetNotetypeIdByName(self.get_notetype_id_by_name(name)?)
}
Value::AddOrUpdateNotetype(input) => {
OValue::AddOrUpdateNotetype(self.add_or_update_notetype_legacy(input)?)
}
Value::RemoveNotetype(id) => {
self.remove_notetype(id)?;
OValue::RemoveNotetype(pb::Empty {})
}
Value::FieldNamesForNotes(input) => {
OValue::FieldNamesForNotes(self.field_names_for_notes(input)?)
}
Value::FindAndReplace(input) => OValue::FindAndReplace(self.find_and_replace(input)?), Value::FindAndReplace(input) => OValue::FindAndReplace(self.find_and_replace(input)?),
Value::AfterNoteUpdates(input) => {
OValue::AfterNoteUpdates(self.after_note_updates(input)?)
}
Value::SetLocalMinutesWest(mins) => OValue::SetLocalMinutesWest({ Value::SetLocalMinutesWest(mins) => OValue::SetLocalMinutesWest({
self.set_local_mins_west(mins)?; self.set_local_mins_west(mins)?;
pb::Empty {} pb::Empty {}
@ -1125,90 +1209,6 @@ impl Backend {
}) })
} }
fn get_changed_notetypes(&self) -> Result<Vec<u8>> {
todo!("filter by usn");
// self.with_col(|col| {
// let nts = col.storage.get_all_notetypes_as_schema11()?;
// serde_json::to_vec(&nts).map_err(Into::into)
// })
}
fn get_notetype_names(&self) -> Result<pb::NoteTypeNames> {
self.with_col(|col| {
let entries: Vec<_> = col
.storage
.get_all_notetype_names()?
.into_iter()
.map(|(id, name)| pb::NoteTypeNameId { id: id.0, name })
.collect();
Ok(pb::NoteTypeNames { entries })
})
}
fn get_notetype_use_counts(&self) -> Result<pb::NoteTypeUseCounts> {
self.with_col(|col| {
let entries: Vec<_> = col
.storage
.get_notetype_use_counts()?
.into_iter()
.map(|(id, name, use_count)| pb::NoteTypeNameIdUseCount {
id: id.0,
name,
use_count,
})
.collect();
Ok(pb::NoteTypeUseCounts { entries })
})
}
fn get_notetype_legacy(&self, id: i64) -> Result<Vec<u8>> {
self.with_col(|col| {
let schema11: NoteTypeSchema11 = col
.storage
.get_notetype(NoteTypeID(id))?
.ok_or(AnkiError::NotFound)?
.into();
Ok(serde_json::to_vec(&schema11)?)
})
}
fn get_notetype_id_by_name(&self, name: String) -> Result<i64> {
self.with_col(|col| {
col.storage
.get_notetype_id(&name)
.map(|nt| nt.unwrap_or(NoteTypeID(0)).0)
})
}
fn add_or_update_notetype_legacy(&self, input: pb::AddOrUpdateNotetypeIn) -> Result<i64> {
self.with_col(|col| {
let legacy: NoteTypeSchema11 = serde_json::from_slice(&input.json)?;
let mut nt: NoteType = legacy.into();
if nt.id.0 == 0 {
col.add_notetype(&mut nt)?;
} else {
col.update_notetype(&mut nt, input.preserve_usn_and_mtime)?;
}
Ok(nt.id.0)
})
}
fn remove_notetype(&self, id: i64) -> Result<()> {
self.with_col(|col| col.remove_notetype(NoteTypeID(id)))
}
fn field_names_for_notes(
&self,
input: pb::FieldNamesForNotesIn,
) -> Result<pb::FieldNamesForNotesOut> {
self.with_col(|col| {
let nids: Vec<_> = input.nids.into_iter().map(NoteID).collect();
col.storage
.field_names_for_notes(&nids)
.map(|fields| pb::FieldNamesForNotesOut { fields })
})
}
fn find_and_replace(&self, input: pb::FindAndReplaceIn) -> Result<u32> { fn find_and_replace(&self, input: pb::FindAndReplaceIn) -> Result<u32> {
let mut search = if input.regex { let mut search = if input.regex {
input.search input.search
@ -1231,19 +1231,6 @@ impl Backend {
}) })
} }
fn after_note_updates(&self, input: pb::AfterNoteUpdatesIn) -> Result<pb::Empty> {
self.with_col(|col| {
col.transact(None, |col| {
col.after_note_updates(
&to_nids(input.nids),
input.generate_cards,
input.mark_notes_modified,
)?;
Ok(pb::Empty {})
})
})
}
fn set_local_mins_west(&self, mins: i32) -> Result<()> { fn set_local_mins_west(&self, mins: i32) -> Result<()> {
self.with_col(|col| col.transact(None, |col| col.set_local_mins_west(mins))) self.with_col(|col| col.transact(None, |col| col.set_local_mins_west(mins)))
} }
@ -1255,15 +1242,6 @@ impl Backend {
fn set_preferences(&self, prefs: pb::Preferences) -> Result<()> { fn set_preferences(&self, prefs: pb::Preferences) -> Result<()> {
self.with_col(|col| col.transact(None, |col| col.set_preferences(prefs))) self.with_col(|col| col.transact(None, |col| col.set_preferences(prefs)))
} }
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);
let idx = (kind as usize).min(all.len() - 1);
let nt = all.swap_remove(idx);
let schema11: NoteTypeSchema11 = nt.into();
serde_json::to_vec(&schema11).map_err(Into::into)
}
} }
fn to_nids(ids: Vec<i64>) -> Vec<NoteID> { fn to_nids(ids: Vec<i64>) -> Vec<NoteID> {

View file

@ -35,7 +35,53 @@ fn open_backend(init_msg: &PyBytes) -> PyResult<Backend> {
fn want_release_gil(method: u32) -> bool { fn want_release_gil(method: u32) -> bool {
if let Ok(method) = BackendMethod::try_from(method) { if let Ok(method) = BackendMethod::try_from(method) {
match method { match method {
_ => false, BackendMethod::ExtractAVTags => false,
BackendMethod::ExtractLatex => false,
BackendMethod::GetEmptyCards => true,
BackendMethod::RenderExistingCard => false,
BackendMethod::RenderUncommittedCard => false,
BackendMethod::StripAVTags => false,
BackendMethod::SearchCards => true,
BackendMethod::SearchNotes => true,
BackendMethod::LocalMinutesWest => false,
BackendMethod::SchedTimingToday => false,
BackendMethod::CheckMedia => true,
BackendMethod::SyncMedia => true,
BackendMethod::TrashMediaFiles => true,
BackendMethod::AddOrUpdateDeckLegacy => false,
BackendMethod::DeckTree => true,
BackendMethod::DeckTreeLegacy => true,
BackendMethod::GetAllDecksLegacy => true,
BackendMethod::GetDeckIDByName => true,
BackendMethod::GetDeckLegacy => true,
BackendMethod::GetDeckNames => true,
BackendMethod::NewDeckLegacy => false,
BackendMethod::RemoveDeck => true,
BackendMethod::AddOrUpdateDeckConfigLegacy => true,
BackendMethod::AllDeckConfigLegacy => true,
BackendMethod::GetDeckConfigLegacy => true,
BackendMethod::NewDeckConfigLegacy => false,
BackendMethod::RemoveDeckConfig => true,
BackendMethod::GetCard => true,
BackendMethod::UpdateCard => true,
BackendMethod::AddCard => true,
BackendMethod::NewNote => true,
BackendMethod::AddNote => true,
BackendMethod::UpdateNote => true,
BackendMethod::GetNote => true,
BackendMethod::AddNoteTags => true,
BackendMethod::UpdateNoteTags => true,
BackendMethod::ClozeNumbersInNote => true,
BackendMethod::AfterNoteUpdates => true,
BackendMethod::FieldNamesForNotes => true,
BackendMethod::AddOrUpdateNotetype => true,
BackendMethod::GetStockNotetypeLegacy => false,
BackendMethod::GetNotetypeLegacy => true,
BackendMethod::GetNotetypeNames => true,
BackendMethod::GetNotetypeNamesAndCounts => true,
BackendMethod::GetNotetypeIDByName => true,
BackendMethod::RemoveNotetype => true,
BackendMethod::CheckDatabase => true,
} }
} else { } else {
false false