feat: upgrade needed ressources and fight for each quest
This commit is contained in:
@ -2,6 +2,9 @@ use rusqlite::{Connection, Result, params};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use chrono::Utc;
|
||||
use uuid::Uuid;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::parser::CombatIndicator;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct Profile {
|
||||
@ -76,10 +79,125 @@ pub fn migrate(conn: &Connection) -> Result<()> {
|
||||
PRIMARY KEY (profile_id, resource_name),
|
||||
FOREIGN KEY (profile_id) REFERENCES profiles(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS quest_previews (
|
||||
quest_url TEXT PRIMARY KEY,
|
||||
indicators_json TEXT NOT NULL,
|
||||
cached_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_cached_previews(conn: &Connection, urls: &[String]) -> HashMap<String, Vec<CombatIndicator>> {
|
||||
if urls.is_empty() {
|
||||
return HashMap::new();
|
||||
}
|
||||
|
||||
// Construit les placeholders : (?1, ?2, …)
|
||||
let placeholders: String = (1..=urls.len())
|
||||
.map(|i| format!("?{}", i))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
let sql = format!(
|
||||
"SELECT quest_url, indicators_json FROM quest_previews WHERE quest_url IN ({})",
|
||||
placeholders
|
||||
);
|
||||
|
||||
let mut stmt = match conn.prepare(&sql) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return HashMap::new(),
|
||||
};
|
||||
|
||||
// rusqlite attend &dyn ToSql — on construit un vecteur de références
|
||||
let params_vec: Vec<&dyn rusqlite::types::ToSql> = urls
|
||||
.iter()
|
||||
.map(|u| u as &dyn rusqlite::types::ToSql)
|
||||
.collect();
|
||||
|
||||
let rows = match stmt.query_map(params_vec.as_slice(), |row| {
|
||||
Ok((row.get::<_, String>(0)?, row.get::<_, String>(1)?))
|
||||
}) {
|
||||
Ok(r) => r,
|
||||
Err(_) => return HashMap::new(),
|
||||
};
|
||||
|
||||
let mut map = HashMap::new();
|
||||
for row in rows.flatten() {
|
||||
let (url, json) = row;
|
||||
if let Ok(indicators) = serde_json::from_str::<Vec<CombatIndicator>>(&json) {
|
||||
map.insert(url, indicators);
|
||||
}
|
||||
}
|
||||
map
|
||||
}
|
||||
|
||||
pub fn upsert_preview(conn: &Connection, url: &str, indicators: &[CombatIndicator]) -> Result<()> {
|
||||
let json = serde_json::to_string(indicators).unwrap_or_else(|_| "[]".to_string());
|
||||
let now = Utc::now().to_rfc3339();
|
||||
conn.execute(
|
||||
"INSERT INTO quest_previews (quest_url, indicators_json, cached_at) VALUES (?1, ?2, ?3)
|
||||
ON CONFLICT(quest_url) DO UPDATE SET indicators_json=excluded.indicators_json, cached_at=excluded.cached_at",
|
||||
params![url, json, now],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Retourne l'ensemble des URLs déjà présentes dans quest_previews parmi celles fournies.
|
||||
pub fn get_cached_urls(conn: &Connection, urls: &[String]) -> std::collections::HashSet<String> {
|
||||
if urls.is_empty() {
|
||||
return std::collections::HashSet::new();
|
||||
}
|
||||
|
||||
let placeholders: String = (1..=urls.len())
|
||||
.map(|i| format!("?{}", i))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
let sql = format!(
|
||||
"SELECT quest_url FROM quest_previews WHERE quest_url IN ({})",
|
||||
placeholders
|
||||
);
|
||||
|
||||
let mut stmt = match conn.prepare(&sql) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return std::collections::HashSet::new(),
|
||||
};
|
||||
|
||||
let params_vec: Vec<&dyn rusqlite::types::ToSql> = urls
|
||||
.iter()
|
||||
.map(|u| u as &dyn rusqlite::types::ToSql)
|
||||
.collect();
|
||||
|
||||
let rows = match stmt.query_map(params_vec.as_slice(), |row| row.get::<_, String>(0)) {
|
||||
Ok(r) => r,
|
||||
Err(_) => return std::collections::HashSet::new(),
|
||||
};
|
||||
|
||||
rows.flatten().collect()
|
||||
}
|
||||
|
||||
/// Charge un guide depuis la DB à partir de son gid.
|
||||
pub fn get_guide(conn: &Connection, gid: &str) -> Result<Option<crate::parser::GuideData>> {
|
||||
let result = conn.query_row(
|
||||
"SELECT data FROM guides WHERE gid = ?1",
|
||||
params![gid],
|
||||
|row| row.get::<_, String>(0),
|
||||
);
|
||||
match result {
|
||||
Ok(json) => {
|
||||
let data = serde_json::from_str(&json)
|
||||
.map_err(|e| rusqlite::Error::FromSqlConversionFailure(
|
||||
0,
|
||||
rusqlite::types::Type::Text,
|
||||
Box::new(e),
|
||||
))?;
|
||||
Ok(Some(data))
|
||||
}
|
||||
Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_profiles(conn: &Connection) -> Result<Vec<Profile>> {
|
||||
let mut stmt = conn.prepare("SELECT id, name, created_at FROM profiles ORDER BY created_at ASC")?;
|
||||
let rows = stmt.query_map([], |row| {
|
||||
|
||||
Reference in New Issue
Block a user