use crate::Result;
use ankit::AnkiClient;
use serde::Serialize;
#[derive(Debug, Clone, Serialize)]
pub struct ExportedNote {
pub note_id: i64,
pub model_name: String,
pub deck_name: String,
pub fields: std::collections::HashMap<String, String>,
pub tags: Vec<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct ExportedCard {
pub card_id: i64,
pub note_id: i64,
pub deck_name: String,
pub reps: i64,
pub lapses: i64,
pub interval: i64,
pub due: i64,
pub ease_factor: i64,
pub card_type: i32,
pub queue: i32,
pub mod_time: i64,
}
#[derive(Debug, Clone, Serialize)]
pub struct DeckExport {
pub deck_name: String,
pub notes: Vec<ExportedNote>,
pub cards: Vec<ExportedCard>,
}
#[derive(Debug)]
pub struct ExportEngine<'a> {
client: &'a AnkiClient,
}
impl<'a> ExportEngine<'a> {
pub(crate) fn new(client: &'a AnkiClient) -> Self {
Self { client }
}
pub async fn deck(&self, deck_name: &str) -> Result<DeckExport> {
let query = format!("deck:\"{}\"", deck_name);
let note_ids = self.client.notes().find(&query).await?;
let note_infos = self.client.notes().info(¬e_ids).await?;
let card_ids = self.client.cards().find(&query).await?;
let card_infos = self.client.cards().info(&card_ids).await?;
let notes = note_infos
.into_iter()
.map(|info| ExportedNote {
note_id: info.note_id,
model_name: info.model_name,
deck_name: deck_name.to_string(),
fields: info.fields.into_iter().map(|(k, v)| (k, v.value)).collect(),
tags: info.tags,
})
.collect();
let cards = card_infos
.into_iter()
.map(|info| ExportedCard {
card_id: info.card_id,
note_id: info.note_id,
deck_name: info.deck_name,
reps: info.reps,
lapses: info.lapses,
interval: info.interval,
due: info.due,
ease_factor: info.ease_factor,
card_type: info.card_type,
queue: info.queue,
mod_time: info.mod_time,
})
.collect();
Ok(DeckExport {
deck_name: deck_name.to_string(),
notes,
cards,
})
}
pub async fn reviews(&self, query: &str) -> Result<Vec<CardReviewHistory>> {
let card_ids = self.client.cards().find(query).await?;
if card_ids.is_empty() {
return Ok(Vec::new());
}
let reviews = self
.client
.statistics()
.reviews_for_cards(&card_ids)
.await?;
let mut result = Vec::new();
for (card_id_str, card_reviews) in reviews {
let card_id: i64 = card_id_str.parse().unwrap_or(0);
let entries: Vec<ExportedReviewEntry> = card_reviews
.iter()
.map(|r| ExportedReviewEntry {
timestamp: r.review_id,
ease: r.ease,
interval: r.interval,
last_interval: r.last_interval,
time_ms: r.time,
})
.collect();
result.push(CardReviewHistory {
card_id,
reviews: entries,
});
}
Ok(result)
}
}
#[derive(Debug, Clone, Serialize)]
pub struct CardReviewHistory {
pub card_id: i64,
pub reviews: Vec<ExportedReviewEntry>,
}
#[derive(Debug, Clone, Serialize)]
pub struct ExportedReviewEntry {
pub timestamp: i64,
pub ease: i32,
pub interval: i64,
pub last_interval: i64,
pub time_ms: i64,
}