mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 06:22:22 -04:00
update_card()
This commit is contained in:
parent
1acfe7d3cc
commit
47504245dc
6 changed files with 115 additions and 30 deletions
|
@ -48,6 +48,7 @@ message BackendInput {
|
|||
OpenCollectionIn open_collection = 36;
|
||||
Empty close_collection = 37;
|
||||
int64 get_card = 38;
|
||||
Card update_card = 39;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,6 +80,7 @@ message BackendOutput {
|
|||
Empty open_collection = 36;
|
||||
Empty close_collection = 37;
|
||||
GetCardOut get_card = 38;
|
||||
Empty update_card = 39;
|
||||
|
||||
BackendError error = 2047;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ from anki import hooks
|
|||
from anki.consts import *
|
||||
from anki.models import NoteType, Template
|
||||
from anki.notes import Note
|
||||
from anki.rsbackend import BackendCard
|
||||
from anki.sound import AVTag
|
||||
from anki.utils import intTime, joinFields, timestampID
|
||||
|
||||
|
@ -33,9 +34,7 @@ class Card:
|
|||
lastIvl: int
|
||||
ord: int
|
||||
|
||||
def __init__(
|
||||
self, col: anki.storage._Collection, id: Optional[int] = None
|
||||
) -> None:
|
||||
def __init__(self, col: anki.storage._Collection, id: Optional[int] = None) -> None:
|
||||
self.col = col.weakref()
|
||||
self.timerStarted = None
|
||||
self._render_output: Optional[anki.template.TemplateRenderOutput] = None
|
||||
|
@ -98,30 +97,27 @@ class Card:
|
|||
|
||||
def flush(self) -> None:
|
||||
self._preFlush()
|
||||
self.col.db.execute(
|
||||
"""
|
||||
insert or replace into cards values
|
||||
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
|
||||
self.id,
|
||||
self.nid,
|
||||
self.did,
|
||||
self.ord,
|
||||
self.mod,
|
||||
self.usn,
|
||||
self.type,
|
||||
self.queue,
|
||||
self.due,
|
||||
self.ivl,
|
||||
self.factor,
|
||||
self.reps,
|
||||
self.lapses,
|
||||
self.left,
|
||||
self.odue,
|
||||
self.odid,
|
||||
self.flags,
|
||||
self.data,
|
||||
card = BackendCard(
|
||||
id=self.id,
|
||||
nid=self.nid,
|
||||
did=self.did,
|
||||
ord=self.ord,
|
||||
mtime=self.mod,
|
||||
usn=self.usn,
|
||||
ctype=self.type,
|
||||
queue=self.queue,
|
||||
due=self.due,
|
||||
ivl=self.ivl,
|
||||
factor=self.factor,
|
||||
reps=self.reps,
|
||||
lapses=self.lapses,
|
||||
left=self.left,
|
||||
odue=self.odue,
|
||||
odid=self.odid,
|
||||
flags=self.flags,
|
||||
data=self.data,
|
||||
)
|
||||
self.col.log(self)
|
||||
self.col.backend.update_card(card)
|
||||
|
||||
def question(self, reload: bool = False, browser: bool = False) -> str:
|
||||
return self.css() + self.render_output(reload, browser).question_text
|
||||
|
|
|
@ -36,6 +36,7 @@ assert ankirspy.buildhash() == anki.buildinfo.buildhash
|
|||
|
||||
SchedTimingToday = pb.SchedTimingTodayOut
|
||||
BuiltinSortKind = pb.BuiltinSortKind
|
||||
BackendCard = pb.Card
|
||||
|
||||
try:
|
||||
import orjson
|
||||
|
@ -481,9 +482,11 @@ class RustBackend:
|
|||
).search_notes.note_ids
|
||||
|
||||
def get_card(self, cid: int) -> Optional[pb.Card]:
|
||||
return self._run_command(
|
||||
pb.BackendInput(get_card=cid)
|
||||
).get_card.card
|
||||
return self._run_command(pb.BackendInput(get_card=cid)).get_card.card
|
||||
|
||||
def update_card(self, card: BackendCard) -> None:
|
||||
self._run_command(pb.BackendInput(update_card=card))
|
||||
|
||||
|
||||
def translate_string_in(
|
||||
key: TR, **kwargs: Union[str, int, float]
|
||||
|
|
|
@ -5,8 +5,10 @@ use crate::backend::dbproxy::db_command_bytes;
|
|||
use crate::backend_proto::backend_input::Value;
|
||||
use crate::backend_proto::{BuiltinSortKind, Empty, RenderedTemplateReplacement, SyncMediaIn};
|
||||
use crate::card::{Card, CardID};
|
||||
use crate::card::{CardQueue, CardType};
|
||||
use crate::collection::{open_collection, Collection};
|
||||
use crate::config::SortKind;
|
||||
use crate::decks::DeckID;
|
||||
use crate::err::{AnkiError, NetworkErrorKind, Result, SyncErrorKind};
|
||||
use crate::i18n::{tr_args, FString, I18n};
|
||||
use crate::latex::{extract_latex, extract_latex_expanding_clozes, ExtractedLatex};
|
||||
|
@ -14,6 +16,7 @@ use crate::log::{default_logger, Logger};
|
|||
use crate::media::check::MediaChecker;
|
||||
use crate::media::sync::MediaSyncProgress;
|
||||
use crate::media::MediaManager;
|
||||
use crate::notes::NoteID;
|
||||
use crate::sched::cutoff::{local_minutes_west_for_stamp, sched_timing_today};
|
||||
use crate::sched::timespan::{answer_button_time, learning_congrats, studied_today, time_span};
|
||||
use crate::search::{search_cards, search_notes, SortMode};
|
||||
|
@ -22,10 +25,13 @@ use crate::template::{
|
|||
RenderedNode,
|
||||
};
|
||||
use crate::text::{extract_av_tags, strip_av_tags, AVTag};
|
||||
use crate::timestamp::TimestampSecs;
|
||||
use crate::types::Usn;
|
||||
use crate::{backend_proto as pb, log};
|
||||
use fluent::FluentValue;
|
||||
use prost::Message;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::convert::TryFrom;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tokio::runtime::Runtime;
|
||||
|
@ -250,6 +256,10 @@ impl Backend {
|
|||
Value::SearchCards(input) => OValue::SearchCards(self.search_cards(input)?),
|
||||
Value::SearchNotes(input) => OValue::SearchNotes(self.search_notes(input)?),
|
||||
Value::GetCard(cid) => OValue::GetCard(self.get_card(cid)?),
|
||||
Value::UpdateCard(card) => {
|
||||
self.update_card(card)?;
|
||||
OValue::UpdateCard(pb::Empty {})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -625,6 +635,11 @@ impl Backend {
|
|||
card: card.map(card_to_pb),
|
||||
})
|
||||
}
|
||||
|
||||
fn update_card(&self, pbcard: pb::Card) -> Result<()> {
|
||||
let card = pbcard_to_native(pbcard);
|
||||
self.with_col(|col| col.with_ctx(|ctx| ctx.storage.update_card(&card)))
|
||||
}
|
||||
}
|
||||
|
||||
fn translate_arg_to_fluent_val(arg: &pb::TranslateArgValue) -> FluentValue {
|
||||
|
@ -740,3 +755,26 @@ fn card_to_pb(c: Card) -> pb::Card {
|
|||
data: c.data,
|
||||
}
|
||||
}
|
||||
|
||||
fn pbcard_to_native(c: pb::Card) -> Card {
|
||||
Card {
|
||||
id: CardID(c.id),
|
||||
nid: NoteID(c.nid),
|
||||
did: DeckID(c.did),
|
||||
ord: c.ord as u16,
|
||||
mtime: TimestampSecs(c.mtime),
|
||||
usn: Usn(c.usn),
|
||||
ctype: CardType::try_from(c.ctype as u8).unwrap_or(CardType::New),
|
||||
queue: CardQueue::try_from(c.queue as i8).unwrap_or(CardQueue::New),
|
||||
due: c.due,
|
||||
ivl: c.ivl,
|
||||
factor: c.factor as u16,
|
||||
reps: c.reps,
|
||||
lapses: c.lapses,
|
||||
left: c.left,
|
||||
odue: c.odue,
|
||||
odid: DeckID(c.odid),
|
||||
flags: c.flags,
|
||||
data: c.data,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
use crate::cached_sql;
|
||||
use crate::card::{Card, CardID, CardQueue, CardType};
|
||||
use crate::err::Result;
|
||||
use crate::err::{AnkiError, Result};
|
||||
use rusqlite::params;
|
||||
use rusqlite::{
|
||||
types::{FromSql, FromSqlError, ValueRef},
|
||||
|
@ -69,4 +69,48 @@ flags, data from cards where id=?"
|
|||
.optional()
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub(crate) fn update_card(&mut self, card: &Card) -> Result<()> {
|
||||
if card.id.0 == 0 {
|
||||
return Err(AnkiError::invalid_input("card id not set"));
|
||||
}
|
||||
self.flush_card(card)
|
||||
}
|
||||
|
||||
fn flush_card(&mut self, card: &Card) -> Result<()> {
|
||||
let stmt = cached_sql!(
|
||||
self.update_card_stmt,
|
||||
self.db,
|
||||
"
|
||||
insert or replace into cards
|
||||
(id, nid, did, ord, mod, usn, type, queue, due, ivl, factor,
|
||||
reps, lapses, left, odue, odid, flags, data)
|
||||
values
|
||||
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
"
|
||||
);
|
||||
|
||||
stmt.execute(params![
|
||||
card.id,
|
||||
card.nid,
|
||||
card.did,
|
||||
card.ord,
|
||||
card.mtime,
|
||||
card.usn,
|
||||
card.ctype as u8,
|
||||
card.queue as i8,
|
||||
card.due,
|
||||
card.ivl,
|
||||
card.factor,
|
||||
card.reps,
|
||||
card.lapses,
|
||||
card.left,
|
||||
card.odue,
|
||||
card.odid,
|
||||
card.flags,
|
||||
card.data,
|
||||
])?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -224,6 +224,7 @@ pub(crate) struct StorageContext<'a> {
|
|||
|
||||
// cards
|
||||
pub(super) get_card_stmt: Option<rusqlite::CachedStatement<'a>>,
|
||||
pub(super) update_card_stmt: Option<rusqlite::CachedStatement<'a>>,
|
||||
}
|
||||
|
||||
impl StorageContext<'_> {
|
||||
|
@ -234,6 +235,7 @@ impl StorageContext<'_> {
|
|||
usn: None,
|
||||
timing_today: None,
|
||||
get_card_stmt: None,
|
||||
update_card_stmt: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue