jellytau_lib/commands/storage/
people.rs1use serde::{Deserialize, Serialize};
6use std::sync::Arc;
7use tauri::State;
8
9use super::DatabaseWrapper;
10use crate::storage::db_service::{DatabaseService, Query, QueryParam};
11
12#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
14#[serde(rename_all = "camelCase")]
15pub struct CachedPerson {
16 pub id: String,
17 pub server_id: String,
18 pub name: String,
19 pub overview: Option<String>,
20 pub primary_image_tag: Option<String>,
21 pub premiere_date: Option<String>,
22 pub end_date: Option<String>,
23}
24
25#[derive(specta::Type, Debug, Clone, Serialize, Deserialize)]
27#[serde(rename_all = "camelCase")]
28pub struct CachedItemPerson {
29 pub item_id: String,
30 pub person_id: String,
31 pub server_id: String,
32 pub person_type: String,
33 pub role: Option<String>,
34 pub sort_order: i32,
35}
36
37#[tauri::command]
39#[specta::specta]
40pub async fn storage_save_person(
41 db: State<'_, DatabaseWrapper>,
42 person: CachedPerson,
43) -> Result<(), String> {
44 let db_service = {
45 let database = db.0.lock().map_err(|e| e.to_string())?;
46 Arc::new(database.service())
47 };
48
49 let query = Query::with_params(
50 "INSERT INTO people (
58 id, server_id, name, overview, primary_image_tag,
59 premiere_date, end_date, synced_at
60 ) VALUES (?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
61 ON CONFLICT(id) DO UPDATE SET
62 server_id = excluded.server_id,
63 name = excluded.name,
64 overview = excluded.overview,
65 primary_image_tag = excluded.primary_image_tag,
66 premiere_date = excluded.premiere_date,
67 end_date = excluded.end_date,
68 synced_at = CURRENT_TIMESTAMP",
69 vec![
70 QueryParam::String(person.id),
71 QueryParam::String(person.server_id),
72 QueryParam::String(person.name),
73 person
74 .overview
75 .map(QueryParam::String)
76 .unwrap_or(QueryParam::Null),
77 person
78 .primary_image_tag
79 .map(QueryParam::String)
80 .unwrap_or(QueryParam::Null),
81 person
82 .premiere_date
83 .map(QueryParam::String)
84 .unwrap_or(QueryParam::Null),
85 person
86 .end_date
87 .map(QueryParam::String)
88 .unwrap_or(QueryParam::Null),
89 ],
90 );
91
92 db_service.execute(query).await.map_err(|e| e.to_string())?;
93 Ok(())
94}
95
96#[tauri::command]
98#[specta::specta]
99pub async fn storage_get_person(
100 db: State<'_, DatabaseWrapper>,
101 person_id: String,
102) -> Result<Option<CachedPerson>, String> {
103 let db_service = {
104 let database = db.0.lock().map_err(|e| e.to_string())?;
105 Arc::new(database.service())
106 };
107
108 let query = Query::with_params(
109 "SELECT id, server_id, name, overview, primary_image_tag, premiere_date, end_date
110 FROM people WHERE id = ?",
111 vec![QueryParam::String(person_id)],
112 );
113
114 let result = db_service
115 .query_optional(query, |row| {
116 Ok(CachedPerson {
117 id: row.get(0)?,
118 server_id: row.get(1)?,
119 name: row.get(2)?,
120 overview: row.get(3)?,
121 primary_image_tag: row.get(4)?,
122 premiere_date: row.get(5)?,
123 end_date: row.get(6)?,
124 })
125 })
126 .await
127 .map_err(|e| e.to_string())?;
128
129 Ok(result)
130}
131
132#[tauri::command]
134#[specta::specta]
135pub async fn storage_save_item_people(
136 db: State<'_, DatabaseWrapper>,
137 associations: Vec<CachedItemPerson>,
138) -> Result<(), String> {
139 let db_service = {
140 let database = db.0.lock().map_err(|e| e.to_string())?;
141 Arc::new(database.service())
142 };
143
144 let associations_clone = associations.clone();
146
147 db_service
149 .transaction(move |tx| {
150 for assoc in &associations_clone {
151 let query = Query::with_params(
152 "INSERT OR REPLACE INTO item_people (
153 item_id, person_id, server_id, person_type, role, sort_order, synced_at
154 ) VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)",
155 vec![
156 QueryParam::String(assoc.item_id.clone()),
157 QueryParam::String(assoc.person_id.clone()),
158 QueryParam::String(assoc.server_id.clone()),
159 QueryParam::String(assoc.person_type.clone()),
160 assoc
161 .role
162 .clone()
163 .map(QueryParam::String)
164 .unwrap_or(QueryParam::Null),
165 QueryParam::Int(assoc.sort_order),
166 ],
167 );
168 tx.execute(query)?;
169 }
170 Ok(())
171 })
172 .await
173 .map_err(|e| e.to_string())?;
174
175 Ok(())
176}
177
178#[tauri::command]
180#[specta::specta]
181pub async fn storage_get_item_people(
182 db: State<'_, DatabaseWrapper>,
183 item_id: String,
184) -> Result<Vec<CachedItemPerson>, String> {
185 let db_service = {
186 let database = db.0.lock().map_err(|e| e.to_string())?;
187 Arc::new(database.service())
188 };
189
190 let query = Query::with_params(
191 "SELECT ip.item_id, ip.person_id, ip.server_id, ip.person_type, ip.role, ip.sort_order
192 FROM item_people ip
193 WHERE ip.item_id = ?
194 ORDER BY ip.sort_order ASC",
195 vec![QueryParam::String(item_id)],
196 );
197
198 let people = db_service
199 .query_many(query, |row| {
200 Ok(CachedItemPerson {
201 item_id: row.get(0)?,
202 person_id: row.get(1)?,
203 server_id: row.get(2)?,
204 person_type: row.get(3)?,
205 role: row.get(4)?,
206 sort_order: row.get(5)?,
207 })
208 })
209 .await
210 .map_err(|e| e.to_string())?;
211
212 Ok(people)
213}