Skip to main content

game_manager_lib/database/backup/
import_queries.rs

1//! Módulo responsável por restaurar os dados do backup no banco de dados SQLite.
2//!
3//! Este módulo isola toda a lógica pesada de inserção/restauração dentro de uma transação ACID atômica,
4//! garantindo que o banco de dados permaneça consistente mesmo em caso de falhas durante a operação.
5
6use crate::database::backup::models::BackupData;
7use crate::errors::AppError;
8use chrono::Utc;
9use rusqlite::{params, Connection};
10
11/// Restaura todos os dados do backup no banco de dados usando uma transação única
12pub fn restore_backup_data(conn: &Connection, backup: &BackupData) -> Result<String, AppError> {
13    // Transação única para todas as operações
14    conn.execute("BEGIN IMMEDIATE TRANSACTION", [])?;
15
16    // Prepared statements para melhor desempenho
17    let mut game_stmt = conn.prepare(
18        "INSERT OR REPLACE INTO games (id, name, cover_url, platform, platform_game_id, installed, import_confidence, install_path, executable_path, launch_args, user_rating, favorite, status, playtime, last_played, added_at, alternative_names)
19         VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17)"
20    )?;
21
22    let mut details_stmt = conn.prepare(
23        "INSERT OR REPLACE INTO game_details (
24        game_id, steam_app_id, developer, publisher, release_date, genres, tags, series,
25        description_raw, description_ptbr, background_image, critic_score, steam_review_label,
26        steam_review_count, steam_review_score, steam_review_updated_at, esrb_rating, is_adult,
27        adult_tags, external_links, median_playtime, estimated_playtime, updated_at
28    )
29     VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20, ?21, ?22, ?23)"
30    )?;
31
32    let mut wishlist_stmt = conn.prepare(
33        "INSERT OR REPLACE INTO wishlist (id, name, cover_url, store_url, store_platform, current_price, normal_price, lowest_price, currency, on_sale, voucher, added_at, itad_id)
34         VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13)"
35    )?;
36
37    for game in &backup.games {
38        let alt_names_json = game
39            .alternative_names
40            .as_ref()
41            .and_then(|v| serde_json::to_string(v).ok());
42
43        game_stmt.execute(params![
44            game.id,
45            game.name,
46            game.cover_url,
47            game.platform.to_string(),
48            game.platform_game_id,
49            game.installed,
50            game.import_confidence.as_ref().map(|ic| ic.to_string()),
51            game.install_path,
52            game.executable_path,
53            game.launch_args,
54            game.user_rating,
55            game.favorite,
56            game.status,
57            game.playtime,
58            game.last_played,
59            game.added_at,
60            alt_names_json
61        ])?;
62    }
63
64    for detail in &backup.game_details {
65        let links_json = detail
66            .external_links
67            .as_ref()
68            .and_then(|links| serde_json::to_string(links).ok());
69
70        let tags_json = detail
71            .tags
72            .as_ref()
73            .and_then(|tags| crate::database::serialize_tags(tags).ok());
74
75        details_stmt.execute(params![
76            detail.game_id,
77            detail.steam_app_id,
78            detail.developer,
79            detail.publisher,
80            detail.release_date,
81            detail.genres,
82            tags_json,
83            detail.series,
84            detail.description_raw,
85            detail.description_ptbr,
86            detail.background_image,
87            detail.critic_score,
88            detail.steam_review_label,
89            detail.steam_review_count,
90            detail.steam_review_score,
91            detail.steam_review_updated_at,
92            detail.esrb_rating,
93            detail.is_adult,
94            detail.adult_tags,
95            links_json,
96            detail.median_playtime,
97            detail.estimated_playtime,
98            detail.updated_at
99        ])?;
100    }
101
102    for item in &backup.wishlist_game {
103        wishlist_stmt.execute(params![
104            item.id,
105            item.name,
106            item.cover_url,
107            item.store_url,
108            item.store_platform,
109            item.current_price,
110            item.normal_price,
111            item.lowest_price,
112            item.currency,
113            item.on_sale,
114            item.voucher,
115            item.added_at,
116            item.itad_id
117        ])?;
118    }
119
120    let mut extras_stmt = conn.prepare(
121        "INSERT OR REPLACE INTO game_extras (
122        steam_app_id, pcgw_page_id, pcgw_page_name, engine,
123        available_on,
124        dx_versions, vulkan_versions, opengl_versions,
125        win64, linux64, macos_arm, macos_intel64,
126        ray_tracing, upscaling, frame_gen,
127        ultrawidescreen, four_k_support, hdr, high_fps, fov, borderless_windowed, color_blind,
128        controller_support, full_controller, playstation_controllers, xinput_controllers,
129        surround_sound, subtitles, closed_captions,
130        has_save_data, has_config_data,
131        languages_interface, languages_audio, languages_subtitles,
132        fetched_at
133    ) VALUES (
134        ?1,  ?2,  ?3,  ?4,
135        ?5,
136        ?6,  ?7,  ?8,
137        ?9,  ?10, ?11, ?12,
138        ?13, ?14, ?15,
139        ?16, ?17, ?18, ?19, ?20, ?21, ?22,
140        ?23, ?24, ?25, ?26,
141        ?27, ?28, ?29,
142        ?30, ?31,
143        ?32, ?33, ?34,
144        ?35
145    )",
146    )?;
147
148    let mut sysreq_stmt = conn.prepare(
149        "INSERT INTO system_requirements (
150            steam_app_id, os_family, tier_title, target,
151            min_os, min_cpu, min_cpu2, min_ram, min_gpu, min_gpu2, min_vram, min_dx, min_storage,
152            rec_os, rec_cpu, rec_cpu2, rec_ram, rec_gpu, rec_gpu2, rec_vram, rec_dx, rec_storage,
153            fetched_at
154        ) VALUES (
155            ?1,  ?2,  ?3,  ?4,
156            ?5,  ?6,  ?7,  ?8,  ?9,  ?10, ?11, ?12, ?13,
157            ?14, ?15, ?16, ?17, ?18, ?19, ?20, ?21, ?22,
158            ?23
159        )",
160    )?;
161
162    let mut paths_stmt = conn.prepare(
163        "INSERT INTO game_data_paths (steam_app_id, kind, os, raw_path, fetched_at)
164         VALUES (?1, ?2, ?3, ?4, ?5)",
165    )?;
166
167    let serialize_vec = |v: &Option<Vec<String>>| -> Option<String> {
168        v.as_ref().and_then(|list| serde_json::to_string(list).ok())
169    };
170
171    let now = Utc::now().to_rfc3339();
172
173    // Limpa dados anteriores das tabelas com múltiplas linhas por jogo antes de reinserir
174    conn.execute("DELETE FROM system_requirements", [])?;
175    conn.execute("DELETE FROM game_data_paths", [])?;
176
177    for extras in &backup.game_extras {
178        extras_stmt.execute(params![
179            extras.steam_app_id,
180            extras.pcgw_page_id,
181            extras.pcgw_page_name,
182            extras.engine,
183            extras.available_on,
184            extras.dx_versions,
185            extras.vulkan_versions,
186            extras.opengl_versions,
187            extras.win64,
188            extras.linux64,
189            extras.macos_arm,
190            extras.macos_intel64,
191            extras.ray_tracing,
192            extras.upscaling,
193            extras.frame_gen,
194            extras.ultrawidescreen,
195            extras.four_k_support,
196            extras.hdr,
197            extras.high_fps,
198            extras.fov,
199            extras.borderless_windowed,
200            extras.color_blind,
201            extras.controller_support,
202            extras.full_controller,
203            extras.playstation_controllers,
204            extras.xinput_controllers,
205            extras.surround_sound,
206            extras.subtitles,
207            extras.closed_captions,
208            extras.has_save_data,
209            extras.has_config_data,
210            serialize_vec(&extras.languages_interface),
211            serialize_vec(&extras.languages_audio),
212            serialize_vec(&extras.languages_subtitles),
213            extras.fetched_at,
214        ])?;
215    }
216
217    for req in &backup.system_requirements {
218        sysreq_stmt.execute(params![
219            req.steam_app_id,
220            req.os_family,
221            req.tier_title,
222            req.target,
223            req.min_os,
224            req.min_cpu,
225            req.min_cpu2,
226            req.min_ram,
227            req.min_gpu,
228            req.min_gpu2,
229            req.min_vram,
230            req.min_dx,
231            req.min_storage,
232            req.rec_os,
233            req.rec_cpu,
234            req.rec_cpu2,
235            req.rec_ram,
236            req.rec_gpu,
237            req.rec_gpu2,
238            req.rec_vram,
239            req.rec_dx,
240            req.rec_storage,
241            now,
242        ])?;
243    }
244
245    for path in &backup.game_data_paths {
246        paths_stmt.execute(params![
247            path.steam_app_id,
248            path.kind,
249            path.os,
250            path.raw_path,
251            now,
252        ])?;
253    }
254
255    conn.execute("COMMIT", [])?;
256
257    Ok(format!(
258        "Backup restaurado! {} jogos, {} detalhes, {} itens da wishlist, {} dados técnicos, {} requisitos de sistema e {} caminhos.",
259        backup.games.len(),
260        backup.game_details.len(),
261        backup.wishlist_game.len(),
262        backup.game_extras.len(),
263        backup.system_requirements.len(),
264        backup.game_data_paths.len(),
265    ))
266}