Migrate from window.electron to tauri IPC functions across components
- Replaced `window.electron.invoke` calls with equivalent `tauri` function calls for all IPC interactions. - Removed `electron.d.ts` TypeScript definitions as they are no longer needed. - Updated related logic for offline/online state synchronization. - Added `types.rs` and `shared/mod.rs` modules to support Tauri IPC integration with Rust enums and shared logic. - Refactored IPC request queues to use updated handler names for consistency with Tauri.
This commit is contained in:
663
src-tauri/src/domains/character/repo.rs
Normal file
663
src-tauri/src/domains/character/repo.rs
Normal file
@@ -0,0 +1,663 @@
|
||||
use rusqlite::{params, Connection};
|
||||
|
||||
use crate::error::{AppError, AppResult};
|
||||
use crate::shared::types::Lang;
|
||||
|
||||
pub struct BookCharactersTable {
|
||||
pub character_id: String,
|
||||
pub book_id: String,
|
||||
pub user_id: String,
|
||||
pub first_name: String,
|
||||
pub last_name: Option<String>,
|
||||
pub nickname: Option<String>,
|
||||
pub age: Option<String>,
|
||||
pub gender: Option<String>,
|
||||
pub species: Option<String>,
|
||||
pub nationality: Option<String>,
|
||||
pub status: Option<String>,
|
||||
pub category: String,
|
||||
pub title: Option<String>,
|
||||
pub image: Option<String>,
|
||||
pub role: Option<String>,
|
||||
pub biography: Option<String>,
|
||||
pub history: Option<String>,
|
||||
pub speech_pattern: Option<String>,
|
||||
pub catchphrase: Option<String>,
|
||||
pub residence: Option<String>,
|
||||
pub notes: Option<String>,
|
||||
pub color: Option<String>,
|
||||
pub last_update: i64,
|
||||
}
|
||||
|
||||
pub struct SyncedCharacterResult {
|
||||
pub character_id: String,
|
||||
pub book_id: String,
|
||||
pub first_name: String,
|
||||
pub last_update: i64,
|
||||
}
|
||||
|
||||
pub struct SyncedCharacterAttributeResult {
|
||||
pub attr_id: String,
|
||||
pub character_id: String,
|
||||
pub attribute_name: String,
|
||||
pub last_update: i64,
|
||||
}
|
||||
|
||||
pub struct BookCharactersAttributesTable {
|
||||
pub attr_id: String,
|
||||
pub character_id: String,
|
||||
pub user_id: String,
|
||||
pub attribute_name: String,
|
||||
pub attribute_value: String,
|
||||
pub last_update: i64,
|
||||
}
|
||||
|
||||
pub struct CharacterResult {
|
||||
pub character_id: String,
|
||||
pub first_name: String,
|
||||
pub last_name: String,
|
||||
pub nickname: Option<String>,
|
||||
pub age: Option<String>,
|
||||
pub gender: Option<String>,
|
||||
pub species: Option<String>,
|
||||
pub nationality: Option<String>,
|
||||
pub status: Option<String>,
|
||||
pub title: String,
|
||||
pub category: String,
|
||||
pub image: String,
|
||||
pub role: String,
|
||||
pub biography: String,
|
||||
pub history: String,
|
||||
pub speech_pattern: Option<String>,
|
||||
pub catchphrase: Option<String>,
|
||||
pub residence: Option<String>,
|
||||
pub notes: Option<String>,
|
||||
pub color: Option<String>,
|
||||
pub series_character_id: Option<String>,
|
||||
}
|
||||
|
||||
pub struct AttributeResult {
|
||||
pub attr_id: String,
|
||||
pub attribute_name: String,
|
||||
pub attribute_value: String,
|
||||
}
|
||||
|
||||
pub struct CompleteCharacterResult {
|
||||
pub character_id: String,
|
||||
pub first_name: String,
|
||||
pub last_name: String,
|
||||
pub nickname: Option<String>,
|
||||
pub age: Option<String>,
|
||||
pub gender: Option<String>,
|
||||
pub species: Option<String>,
|
||||
pub nationality: Option<String>,
|
||||
pub status: Option<String>,
|
||||
pub category: String,
|
||||
pub title: String,
|
||||
pub role: String,
|
||||
pub biography: String,
|
||||
pub history: String,
|
||||
pub speech_pattern: Option<String>,
|
||||
pub catchphrase: Option<String>,
|
||||
pub residence: Option<String>,
|
||||
pub notes: Option<String>,
|
||||
pub color: Option<String>,
|
||||
pub attribute_name: String,
|
||||
pub attribute_value: String,
|
||||
}
|
||||
|
||||
pub struct CharacterData {
|
||||
pub first_name: String,
|
||||
pub last_name: Option<String>,
|
||||
pub nickname: Option<String>,
|
||||
pub age: Option<String>,
|
||||
pub gender: Option<String>,
|
||||
pub species: Option<String>,
|
||||
pub nationality: Option<String>,
|
||||
pub status: Option<String>,
|
||||
pub title: Option<String>,
|
||||
pub category: Option<String>,
|
||||
pub image: Option<String>,
|
||||
pub role: Option<String>,
|
||||
pub biography: Option<String>,
|
||||
pub history: Option<String>,
|
||||
pub speech_pattern: Option<String>,
|
||||
pub catchphrase: Option<String>,
|
||||
pub residence: Option<String>,
|
||||
pub notes: Option<String>,
|
||||
pub color: Option<String>,
|
||||
}
|
||||
|
||||
pub struct SyncCharacterData {
|
||||
pub first_name: String,
|
||||
pub last_name: Option<String>,
|
||||
pub nickname: Option<String>,
|
||||
pub age: Option<String>,
|
||||
pub gender: Option<String>,
|
||||
pub species: Option<String>,
|
||||
pub nationality: Option<String>,
|
||||
pub status: Option<String>,
|
||||
pub category: String,
|
||||
pub title: Option<String>,
|
||||
pub image: Option<String>,
|
||||
pub role: Option<String>,
|
||||
pub biography: Option<String>,
|
||||
pub history: Option<String>,
|
||||
pub speech_pattern: Option<String>,
|
||||
pub catchphrase: Option<String>,
|
||||
pub residence: Option<String>,
|
||||
pub notes: Option<String>,
|
||||
pub color: Option<String>,
|
||||
}
|
||||
|
||||
/// Fetches all characters for a specific book and user.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `book_id` - The unique identifier of the book
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns an array of character results.
|
||||
pub fn fetch_characters(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<Vec<CharacterResult>> {
|
||||
let mut statement = conn
|
||||
.prepare("SELECT character_id, first_name, last_name, nickname, age, gender, species, nationality, status, title, category, image, role, biography, history, speech_pattern, catchphrase, residence, notes, color, series_character_id FROM book_characters WHERE book_id=?1 AND user_id=?2")
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les personnages.".to_string() } else { "Unable to retrieve characters.".to_string() }))?;
|
||||
|
||||
let characters = statement
|
||||
.query_map(params![book_id, user_id], |query_row| {
|
||||
Ok(CharacterResult {
|
||||
character_id: query_row.get(0)?, first_name: query_row.get(1)?,
|
||||
last_name: query_row.get(2)?, nickname: query_row.get(3)?,
|
||||
age: query_row.get(4)?, gender: query_row.get(5)?,
|
||||
species: query_row.get(6)?, nationality: query_row.get(7)?,
|
||||
status: query_row.get(8)?, title: query_row.get(9)?,
|
||||
category: query_row.get(10)?, image: query_row.get(11)?,
|
||||
role: query_row.get(12)?, biography: query_row.get(13)?,
|
||||
history: query_row.get(14)?, speech_pattern: query_row.get(15)?,
|
||||
catchphrase: query_row.get(16)?, residence: query_row.get(17)?,
|
||||
notes: query_row.get(18)?, color: query_row.get(19)?,
|
||||
series_character_id: query_row.get(20)?,
|
||||
})
|
||||
})
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les personnages.".to_string() } else { "Unable to retrieve characters.".to_string() }))?
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les personnages.".to_string() } else { "Unable to retrieve characters.".to_string() }))?;
|
||||
|
||||
Ok(characters)
|
||||
}
|
||||
|
||||
/// Adds a new character to the database.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `character_id` - The unique identifier for the new character
|
||||
/// * `character_data` - Object containing all encrypted character fields
|
||||
/// * `book_id` - The unique identifier of the book
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// * `series_character_id` - Optional series character identifier
|
||||
/// Returns the character ID if successful.
|
||||
pub fn add_new_character(
|
||||
conn: &Connection, user_id: &str, character_id: &str, character_data: &CharacterData,
|
||||
book_id: &str, lang: Lang, series_character_id: Option<&str>, last_update: i64,
|
||||
) -> AppResult<String> {
|
||||
let insert_result = if let Some(series_id) = series_character_id {
|
||||
conn.execute(
|
||||
"INSERT INTO book_characters (character_id, book_id, user_id, first_name, last_name, nickname, age, gender, species, nationality, status, category, title, image, role, biography, history, speech_pattern, catchphrase, residence, notes, color, series_character_id, last_update) VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12,?13,?14,?15,?16,?17,?18,?19,?20,?21,?22,?23,?24)",
|
||||
params![character_id, book_id, user_id, character_data.first_name, character_data.last_name, character_data.nickname, character_data.age, character_data.gender, character_data.species, character_data.nationality, character_data.status, character_data.category, character_data.title, character_data.image, character_data.role, character_data.biography, character_data.history, character_data.speech_pattern, character_data.catchphrase, character_data.residence, character_data.notes, character_data.color, series_id, last_update],
|
||||
)
|
||||
} else {
|
||||
conn.execute(
|
||||
"INSERT INTO book_characters (character_id, book_id, user_id, first_name, last_name, nickname, age, gender, species, nationality, status, category, title, image, role, biography, history, speech_pattern, catchphrase, residence, notes, color, last_update) VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12,?13,?14,?15,?16,?17,?18,?19,?20,?21,?22,?23)",
|
||||
params![character_id, book_id, user_id, character_data.first_name, character_data.last_name, character_data.nickname, character_data.age, character_data.gender, character_data.species, character_data.nationality, character_data.status, character_data.category, character_data.title, character_data.image, character_data.role, character_data.biography, character_data.history, character_data.speech_pattern, character_data.catchphrase, character_data.residence, character_data.notes, character_data.color, last_update],
|
||||
)
|
||||
};
|
||||
|
||||
let insert_result = insert_result
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'ajouter le personnage.".to_string() } else { "Unable to add character.".to_string() }))?;
|
||||
|
||||
if insert_result > 0 {
|
||||
Ok(character_id.to_string())
|
||||
} else {
|
||||
Err(AppError::Internal(if lang == Lang::Fr { "Une erreur s'est produite lors de l'ajout du personnage.".to_string() } else { "Error adding character.".to_string() }))
|
||||
}
|
||||
}
|
||||
|
||||
/// Inserts a new attribute for a character.
|
||||
/// * `conn` - Database connection
|
||||
/// * `attribute_id` - The unique identifier for the new attribute
|
||||
/// * `character_id` - The unique identifier of the character
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `attribute_type` - The attribute name/type
|
||||
/// * `name` - The attribute value
|
||||
/// * `last_update` - The timestamp of the last update
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns the attribute ID if successful.
|
||||
pub fn insert_attribute(
|
||||
conn: &Connection, attribute_id: &str, character_id: &str, user_id: &str,
|
||||
attribute_type: &str, name: &str, last_update: i64, lang: Lang,
|
||||
) -> AppResult<String> {
|
||||
let insert_result = conn
|
||||
.execute(
|
||||
"INSERT INTO book_characters_attributes (attr_id, character_id, user_id, attribute_name, attribute_value, last_update) VALUES (?1,?2,?3,?4,?5,?6)",
|
||||
params![attribute_id, character_id, user_id, attribute_type, name, last_update],
|
||||
)
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'ajouter l'attribut.".to_string() } else { "Unable to add attribute.".to_string() }))?;
|
||||
|
||||
if insert_result > 0 {
|
||||
Ok(attribute_id.to_string())
|
||||
} else {
|
||||
Err(AppError::Internal(if lang == Lang::Fr { "Une erreur s'est produite lors de l'ajout de l'attribut.".to_string() } else { "Error adding attribute.".to_string() }))
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates an existing character's information.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `id` - The unique identifier of the character to update
|
||||
/// * `character_data` - Object containing all encrypted character fields
|
||||
/// * `last_update` - The timestamp of the last update
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// * `series_character_id` - Optional series character identifier
|
||||
/// Returns true if the update was successful, false otherwise.
|
||||
pub fn update_character(
|
||||
conn: &Connection, user_id: &str, id: &str, character_data: &CharacterData,
|
||||
last_update: i64, lang: Lang, series_character_id: Option<&str>,
|
||||
) -> AppResult<bool> {
|
||||
let update_result = if let Some(series_id) = series_character_id {
|
||||
conn.execute(
|
||||
"UPDATE book_characters SET first_name=?1, last_name=?2, nickname=?3, age=?4, gender=?5, species=?6, nationality=?7, status=?8, title=?9, category=?10, image=?11, role=?12, biography=?13, history=?14, speech_pattern=?15, catchphrase=?16, residence=?17, notes=?18, color=?19, series_character_id=?20, last_update=?21 WHERE character_id=?22 AND user_id=?23",
|
||||
params![character_data.first_name, character_data.last_name, character_data.nickname, character_data.age, character_data.gender, character_data.species, character_data.nationality, character_data.status, character_data.title, character_data.category, character_data.image, character_data.role, character_data.biography, character_data.history, character_data.speech_pattern, character_data.catchphrase, character_data.residence, character_data.notes, character_data.color, series_id, last_update, id, user_id],
|
||||
)
|
||||
} else {
|
||||
conn.execute(
|
||||
"UPDATE book_characters SET first_name=?1, last_name=?2, nickname=?3, age=?4, gender=?5, species=?6, nationality=?7, status=?8, title=?9, category=?10, image=?11, role=?12, biography=?13, history=?14, speech_pattern=?15, catchphrase=?16, residence=?17, notes=?18, color=?19, last_update=?20 WHERE character_id=?21 AND user_id=?22",
|
||||
params![character_data.first_name, character_data.last_name, character_data.nickname, character_data.age, character_data.gender, character_data.species, character_data.nationality, character_data.status, character_data.title, character_data.category, character_data.image, character_data.role, character_data.biography, character_data.history, character_data.speech_pattern, character_data.catchphrase, character_data.residence, character_data.notes, character_data.color, last_update, id, user_id],
|
||||
)
|
||||
};
|
||||
|
||||
let update_result = update_result
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de mettre à jour le personnage.".to_string() } else { "Unable to update character.".to_string() }))?;
|
||||
|
||||
Ok(update_result > 0)
|
||||
}
|
||||
|
||||
/// Deletes a character and all its related data (attributes) from the database.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `character_id` - The unique identifier of the character to delete
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns true if the deletion was successful, false otherwise.
|
||||
pub fn delete_character(conn: &Connection, user_id: &str, character_id: &str, lang: Lang) -> AppResult<bool> {
|
||||
conn.execute(
|
||||
"DELETE FROM book_characters_attributes WHERE character_id=?1 AND user_id=?2",
|
||||
params![character_id, user_id],
|
||||
)
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de supprimer le personnage.".to_string() } else { "Unable to delete character.".to_string() }))?;
|
||||
|
||||
let delete_result = conn
|
||||
.execute(
|
||||
"DELETE FROM book_characters WHERE character_id=?1 AND user_id=?2",
|
||||
params![character_id, user_id],
|
||||
)
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de supprimer le personnage.".to_string() } else { "Unable to delete character.".to_string() }))?;
|
||||
|
||||
Ok(delete_result > 0)
|
||||
}
|
||||
|
||||
/// Deletes a character attribute from the database.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `attribute_id` - The unique identifier of the attribute to delete
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns true if the deletion was successful, false otherwise.
|
||||
pub fn delete_attribute(conn: &Connection, user_id: &str, attribute_id: &str, lang: Lang) -> AppResult<bool> {
|
||||
let delete_result = conn
|
||||
.execute(
|
||||
"DELETE FROM book_characters_attributes WHERE attr_id=?1 AND user_id=?2",
|
||||
params![attribute_id, user_id],
|
||||
)
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de supprimer l'attribut.".to_string() } else { "Unable to delete attribute.".to_string() }))?;
|
||||
|
||||
Ok(delete_result > 0)
|
||||
}
|
||||
|
||||
/// Fetches all attributes for a specific character.
|
||||
/// * `conn` - Database connection
|
||||
/// * `character_id` - The unique identifier of the character
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns an array of attribute results.
|
||||
pub fn fetch_attributes(conn: &Connection, character_id: &str, user_id: &str, lang: Lang) -> AppResult<Vec<AttributeResult>> {
|
||||
let mut statement = conn
|
||||
.prepare("SELECT attr_id, attribute_name, attribute_value FROM book_characters_attributes WHERE character_id=?1 AND user_id=?2")
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les attributs.".to_string() } else { "Unable to retrieve attributes.".to_string() }))?;
|
||||
|
||||
let attributes = statement
|
||||
.query_map(params![character_id, user_id], |query_row| {
|
||||
Ok(AttributeResult { attr_id: query_row.get(0)?, attribute_name: query_row.get(1)?, attribute_value: query_row.get(2)? })
|
||||
})
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les attributs.".to_string() } else { "Unable to retrieve attributes.".to_string() }))?
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les attributs.".to_string() } else { "Unable to retrieve attributes.".to_string() }))?;
|
||||
|
||||
Ok(attributes)
|
||||
}
|
||||
|
||||
/// Fetches complete character information including attributes, optionally filtered by character IDs.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `book_id` - The unique identifier of the book
|
||||
/// * `tags` - An optional array of character IDs to filter by
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns an array of complete character results with attributes.
|
||||
pub fn fetch_complete_characters(conn: &Connection, user_id: &str, book_id: &str, tags: &[String], lang: Lang) -> AppResult<Vec<CompleteCharacterResult>> {
|
||||
let mut query = "SELECT charac.character_id, first_name, last_name, nickname, age, gender, species, nationality, status, category, title, role, biography, history, speech_pattern, catchphrase, residence, notes, color, attribute_name, attribute_value FROM book_characters AS charac LEFT JOIN book_characters_attributes AS attr ON charac.character_id=attr.character_id WHERE charac.user_id=?1 AND charac.book_id=?2".to_string();
|
||||
let mut param_values: Vec<Box<dyn rusqlite::types::ToSql>> = Vec::new();
|
||||
param_values.push(Box::new(user_id.to_string()));
|
||||
param_values.push(Box::new(book_id.to_string()));
|
||||
|
||||
if !tags.is_empty() {
|
||||
let placeholders: String = tags.iter().enumerate().map(|(index, _)| format!("?{}", index + 3)).collect::<Vec<_>>().join(",");
|
||||
query += &format!(" AND charac.character_id IN ({})", placeholders);
|
||||
for tag in tags {
|
||||
param_values.push(Box::new(tag.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
let param_refs: Vec<&dyn rusqlite::types::ToSql> = param_values.iter().map(|param| param.as_ref()).collect();
|
||||
|
||||
let mut statement = conn
|
||||
.prepare(&query)
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les personnages complets.".to_string() } else { "Unable to retrieve complete characters.".to_string() }))?;
|
||||
|
||||
let characters = statement
|
||||
.query_map(param_refs.as_slice(), |query_row| {
|
||||
Ok(CompleteCharacterResult {
|
||||
character_id: query_row.get(0)?, first_name: query_row.get(1)?,
|
||||
last_name: query_row.get(2)?, nickname: query_row.get(3)?,
|
||||
age: query_row.get(4)?, gender: query_row.get(5)?,
|
||||
species: query_row.get(6)?, nationality: query_row.get(7)?,
|
||||
status: query_row.get(8)?, category: query_row.get(9)?,
|
||||
title: query_row.get(10)?, role: query_row.get(11)?,
|
||||
biography: query_row.get(12)?, history: query_row.get(13)?,
|
||||
speech_pattern: query_row.get(14)?, catchphrase: query_row.get(15)?,
|
||||
residence: query_row.get(16)?, notes: query_row.get(17)?,
|
||||
color: query_row.get(18)?, attribute_name: query_row.get(19)?,
|
||||
attribute_value: query_row.get(20)?,
|
||||
})
|
||||
})
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les personnages complets.".to_string() } else { "Unable to retrieve complete characters.".to_string() }))?
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les personnages complets.".to_string() } else { "Unable to retrieve complete characters.".to_string() }))?;
|
||||
|
||||
if characters.is_empty() {
|
||||
return Err(AppError::NotFound(if lang == Lang::Fr { "Aucun personnage complet trouvé.".to_string() } else { "No complete characters found.".to_string() }));
|
||||
}
|
||||
|
||||
Ok(characters)
|
||||
}
|
||||
|
||||
/// Updates an existing character attribute.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `character_attribute_id` - The unique identifier of the attribute to update
|
||||
/// * `attribute_name` - The new attribute name
|
||||
/// * `attribute_value` - The new attribute value
|
||||
/// * `last_update` - The timestamp of the last update
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns true if the update was successful, false otherwise.
|
||||
pub fn update_character_attribute(
|
||||
conn: &Connection, user_id: &str, character_attribute_id: &str,
|
||||
attribute_name: &str, attribute_value: &str, last_update: i64, lang: Lang,
|
||||
) -> AppResult<bool> {
|
||||
let update_result = conn
|
||||
.execute(
|
||||
"UPDATE book_characters_attributes SET attribute_name=?1, attribute_value=?2, last_update=?3 WHERE attr_id=?4 AND user_id=?5",
|
||||
params![attribute_name, attribute_value, last_update, character_attribute_id, user_id],
|
||||
)
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de mettre à jour l'attribut du personnage.".to_string() } else { "Unable to update character attribute.".to_string() }))?;
|
||||
|
||||
Ok(update_result > 0)
|
||||
}
|
||||
|
||||
/// Checks if a character exists in the database.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `character_id` - The unique identifier of the character to check
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns true if the character exists, false otherwise.
|
||||
pub fn is_character_exist(conn: &Connection, user_id: &str, character_id: &str, lang: Lang) -> AppResult<bool> {
|
||||
let mut statement = conn
|
||||
.prepare("SELECT 1 FROM book_characters WHERE character_id=?1 AND user_id=?2")
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de vérifier l'existence du personnage.".to_string() } else { "Unable to check character existence.".to_string() }))?;
|
||||
|
||||
let exists = statement
|
||||
.query_row(params![character_id, user_id], |_query_row| Ok(true))
|
||||
.unwrap_or(false);
|
||||
|
||||
Ok(exists)
|
||||
}
|
||||
|
||||
/// Checks if a character attribute exists in the database.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `character_attribute_id` - The unique identifier of the attribute to check
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns true if the attribute exists, false otherwise.
|
||||
pub fn is_character_attribute_exist(conn: &Connection, user_id: &str, character_attribute_id: &str, lang: Lang) -> AppResult<bool> {
|
||||
let mut statement = conn
|
||||
.prepare("SELECT 1 FROM book_characters_attributes WHERE attr_id=?1 AND user_id=?2")
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de vérifier l'existence de l'attribut du personnage.".to_string() } else { "Unable to check character attribute existence.".to_string() }))?;
|
||||
|
||||
let exists = statement
|
||||
.query_row(params![character_attribute_id, user_id], |_query_row| Ok(true))
|
||||
.unwrap_or(false);
|
||||
|
||||
Ok(exists)
|
||||
}
|
||||
|
||||
/// Fetches all characters for a specific book.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `book_id` - The unique identifier of the book
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns an array of book characters.
|
||||
pub fn fetch_book_characters(conn: &Connection, user_id: &str, book_id: &str, lang: Lang) -> AppResult<Vec<BookCharactersTable>> {
|
||||
let mut statement = conn
|
||||
.prepare("SELECT character_id, book_id, user_id, first_name, last_name, nickname, age, gender, species, nationality, status, category, title, image, role, biography, history, speech_pattern, catchphrase, residence, notes, color, last_update FROM book_characters WHERE user_id=?1 AND book_id=?2")
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les personnages.".to_string() } else { "Unable to retrieve characters.".to_string() }))?;
|
||||
|
||||
let characters = statement
|
||||
.query_map(params![user_id, book_id], |query_row| {
|
||||
Ok(BookCharactersTable {
|
||||
character_id: query_row.get(0)?, book_id: query_row.get(1)?,
|
||||
user_id: query_row.get(2)?, first_name: query_row.get(3)?,
|
||||
last_name: query_row.get(4)?, nickname: query_row.get(5)?,
|
||||
age: query_row.get(6)?, gender: query_row.get(7)?,
|
||||
species: query_row.get(8)?, nationality: query_row.get(9)?,
|
||||
status: query_row.get(10)?, category: query_row.get(11)?,
|
||||
title: query_row.get(12)?, image: query_row.get(13)?,
|
||||
role: query_row.get(14)?, biography: query_row.get(15)?,
|
||||
history: query_row.get(16)?, speech_pattern: query_row.get(17)?,
|
||||
catchphrase: query_row.get(18)?, residence: query_row.get(19)?,
|
||||
notes: query_row.get(20)?, color: query_row.get(21)?,
|
||||
last_update: query_row.get(22)?,
|
||||
})
|
||||
})
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les personnages.".to_string() } else { "Unable to retrieve characters.".to_string() }))?
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les personnages.".to_string() } else { "Unable to retrieve characters.".to_string() }))?;
|
||||
|
||||
Ok(characters)
|
||||
}
|
||||
|
||||
/// Fetches all attributes for a specific character.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `character_id` - The unique identifier of the character
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns an array of character attributes.
|
||||
pub fn fetch_book_characters_attributes(conn: &Connection, user_id: &str, character_id: &str, lang: Lang) -> AppResult<Vec<BookCharactersAttributesTable>> {
|
||||
let mut statement = conn
|
||||
.prepare("SELECT attr_id, character_id, user_id, attribute_name, attribute_value, last_update FROM book_characters_attributes WHERE user_id=?1 AND character_id=?2")
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les attributs des personnages.".to_string() } else { "Unable to retrieve character attributes.".to_string() }))?;
|
||||
|
||||
let attributes = statement
|
||||
.query_map(params![user_id, character_id], |query_row| {
|
||||
Ok(BookCharactersAttributesTable {
|
||||
attr_id: query_row.get(0)?, character_id: query_row.get(1)?,
|
||||
user_id: query_row.get(2)?, attribute_name: query_row.get(3)?,
|
||||
attribute_value: query_row.get(4)?, last_update: query_row.get(5)?,
|
||||
})
|
||||
})
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les attributs des personnages.".to_string() } else { "Unable to retrieve character attributes.".to_string() }))?
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les attributs des personnages.".to_string() } else { "Unable to retrieve character attributes.".to_string() }))?;
|
||||
|
||||
Ok(attributes)
|
||||
}
|
||||
|
||||
/// Fetches all synced characters for a user.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns an array of synced character results.
|
||||
pub fn fetch_synced_characters(conn: &Connection, user_id: &str, lang: Lang) -> AppResult<Vec<SyncedCharacterResult>> {
|
||||
let mut statement = conn
|
||||
.prepare("SELECT character_id, book_id, first_name, last_update FROM book_characters WHERE user_id = ?1")
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les personnages synchronisés.".to_string() } else { "Unable to retrieve synced characters.".to_string() }))?;
|
||||
|
||||
let synced_characters = statement
|
||||
.query_map(params![user_id], |query_row| {
|
||||
Ok(SyncedCharacterResult { character_id: query_row.get(0)?, book_id: query_row.get(1)?, first_name: query_row.get(2)?, last_update: query_row.get(3)? })
|
||||
})
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les personnages synchronisés.".to_string() } else { "Unable to retrieve synced characters.".to_string() }))?
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les personnages synchronisés.".to_string() } else { "Unable to retrieve synced characters.".to_string() }))?;
|
||||
|
||||
Ok(synced_characters)
|
||||
}
|
||||
|
||||
/// Fetches all synced character attributes for a user.
|
||||
/// * `conn` - Database connection
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns an array of synced character attribute results.
|
||||
pub fn fetch_synced_character_attributes(conn: &Connection, user_id: &str, lang: Lang) -> AppResult<Vec<SyncedCharacterAttributeResult>> {
|
||||
let mut statement = conn
|
||||
.prepare("SELECT attr_id, character_id, attribute_name, last_update FROM book_characters_attributes WHERE user_id = ?1")
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les attributs des personnages synchronisés.".to_string() } else { "Unable to retrieve synced character attributes.".to_string() }))?;
|
||||
|
||||
let synced_attributes = statement
|
||||
.query_map(params![user_id], |query_row| {
|
||||
Ok(SyncedCharacterAttributeResult { attr_id: query_row.get(0)?, character_id: query_row.get(1)?, attribute_name: query_row.get(2)?, last_update: query_row.get(3)? })
|
||||
})
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les attributs des personnages synchronisés.".to_string() } else { "Unable to retrieve synced character attributes.".to_string() }))?
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer les attributs des personnages synchronisés.".to_string() } else { "Unable to retrieve synced character attributes.".to_string() }))?;
|
||||
|
||||
Ok(synced_attributes)
|
||||
}
|
||||
|
||||
/// Inserts a synced character into the database.
|
||||
/// * `conn` - Database connection
|
||||
/// * `character_id` - The unique identifier of the character
|
||||
/// * `book_id` - The unique identifier of the book
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `character_data` - Object containing all character fields
|
||||
/// * `last_update` - The timestamp of the last update
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns true if the insertion was successful, false otherwise.
|
||||
pub fn insert_sync_character(
|
||||
conn: &Connection, character_id: &str, book_id: &str, user_id: &str,
|
||||
character_data: &SyncCharacterData, last_update: i64, lang: Lang,
|
||||
) -> AppResult<bool> {
|
||||
let insert_result = conn
|
||||
.execute(
|
||||
"INSERT INTO book_characters (character_id, book_id, user_id, first_name, last_name, nickname, age, gender, species, nationality, status, category, title, image, role, biography, history, speech_pattern, catchphrase, residence, notes, color, last_update) VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12,?13,?14,?15,?16,?17,?18,?19,?20,?21,?22,?23)",
|
||||
params![character_id, book_id, user_id, character_data.first_name, character_data.last_name, character_data.nickname, character_data.age, character_data.gender, character_data.species, character_data.nationality, character_data.status, character_data.category, character_data.title, character_data.image, character_data.role, character_data.biography, character_data.history, character_data.speech_pattern, character_data.catchphrase, character_data.residence, character_data.notes, character_data.color, last_update],
|
||||
)
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'insérer le personnage.".to_string() } else { "Unable to insert character.".to_string() }))?;
|
||||
|
||||
Ok(insert_result > 0)
|
||||
}
|
||||
|
||||
/// Inserts a synced character attribute into the database.
|
||||
/// * `conn` - Database connection
|
||||
/// * `attr_id` - The unique identifier of the attribute
|
||||
/// * `character_id` - The unique identifier of the character
|
||||
/// * `user_id` - The unique identifier of the user
|
||||
/// * `attribute_name` - The name of the attribute
|
||||
/// * `attribute_value` - The value of the attribute
|
||||
/// * `last_update` - The timestamp of the last update
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns true if the insertion was successful, false otherwise.
|
||||
pub fn insert_sync_character_attribute(
|
||||
conn: &Connection, attr_id: &str, character_id: &str, user_id: &str,
|
||||
attribute_name: &str, attribute_value: &str, last_update: i64, lang: Lang,
|
||||
) -> AppResult<bool> {
|
||||
let insert_result = conn
|
||||
.execute(
|
||||
"INSERT INTO book_characters_attributes (attr_id, character_id, user_id, attribute_name, attribute_value, last_update) VALUES (?1,?2,?3,?4,?5,?6)",
|
||||
params![attr_id, character_id, user_id, attribute_name, attribute_value, last_update],
|
||||
)
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible d'insérer l'attribut du personnage.".to_string() } else { "Unable to insert character attribute.".to_string() }))?;
|
||||
|
||||
Ok(insert_result > 0)
|
||||
}
|
||||
|
||||
/// Fetches a complete character by its ID.
|
||||
/// * `conn` - Database connection
|
||||
/// * `id` - The unique identifier of the character
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns an array of book characters (typically one).
|
||||
pub fn fetch_complete_character_by_id(conn: &Connection, id: &str, lang: Lang) -> AppResult<Vec<BookCharactersTable>> {
|
||||
let mut statement = conn
|
||||
.prepare("SELECT character_id, book_id, user_id, first_name, last_name, nickname, age, gender, species, nationality, status, category, title, image, role, biography, history, speech_pattern, catchphrase, residence, notes, color, last_update FROM book_characters WHERE character_id = ?1")
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer le personnage complet.".to_string() } else { "Unable to retrieve complete character.".to_string() }))?;
|
||||
|
||||
let character = statement
|
||||
.query_map(params![id], |query_row| {
|
||||
Ok(BookCharactersTable {
|
||||
character_id: query_row.get(0)?, book_id: query_row.get(1)?,
|
||||
user_id: query_row.get(2)?, first_name: query_row.get(3)?,
|
||||
last_name: query_row.get(4)?, nickname: query_row.get(5)?,
|
||||
age: query_row.get(6)?, gender: query_row.get(7)?,
|
||||
species: query_row.get(8)?, nationality: query_row.get(9)?,
|
||||
status: query_row.get(10)?, category: query_row.get(11)?,
|
||||
title: query_row.get(12)?, image: query_row.get(13)?,
|
||||
role: query_row.get(14)?, biography: query_row.get(15)?,
|
||||
history: query_row.get(16)?, speech_pattern: query_row.get(17)?,
|
||||
catchphrase: query_row.get(18)?, residence: query_row.get(19)?,
|
||||
notes: query_row.get(20)?, color: query_row.get(21)?,
|
||||
last_update: query_row.get(22)?,
|
||||
})
|
||||
})
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer le personnage complet.".to_string() } else { "Unable to retrieve complete character.".to_string() }))?
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer le personnage complet.".to_string() } else { "Unable to retrieve complete character.".to_string() }))?;
|
||||
|
||||
Ok(character)
|
||||
}
|
||||
|
||||
/// Fetches a complete character attribute by its ID.
|
||||
/// * `conn` - Database connection
|
||||
/// * `id` - The unique identifier of the attribute
|
||||
/// * `lang` - The language for error messages ("fr" or "en")
|
||||
/// Returns an array of character attributes (typically one).
|
||||
pub fn fetch_complete_character_attribute_by_id(conn: &Connection, id: &str, lang: Lang) -> AppResult<Vec<BookCharactersAttributesTable>> {
|
||||
let mut statement = conn
|
||||
.prepare("SELECT attr_id, character_id, user_id, attribute_name, attribute_value, last_update FROM book_characters_attributes WHERE attr_id = ?1")
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer l'attribut de personnage complet.".to_string() } else { "Unable to retrieve complete character attribute.".to_string() }))?;
|
||||
|
||||
let attribute = statement
|
||||
.query_map(params![id], |query_row| {
|
||||
Ok(BookCharactersAttributesTable {
|
||||
attr_id: query_row.get(0)?, character_id: query_row.get(1)?,
|
||||
user_id: query_row.get(2)?, attribute_name: query_row.get(3)?,
|
||||
attribute_value: query_row.get(4)?, last_update: query_row.get(5)?,
|
||||
})
|
||||
})
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer l'attribut de personnage complet.".to_string() } else { "Unable to retrieve complete character attribute.".to_string() }))?
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|_| AppError::Internal(if lang == Lang::Fr { "Impossible de récupérer l'attribut de personnage complet.".to_string() } else { "Unable to retrieve complete character attribute.".to_string() }))?;
|
||||
|
||||
Ok(attribute)
|
||||
}
|
||||
Reference in New Issue
Block a user