my_libs\config/mod.rs
1// src/config/mod.rs
2
3// 📦 Zewnętrzne crate'y (odpowiednik importów z npm/deno.land)
4use serde::{Deserialize, Serialize}; // Do zamiany Struct <-> TOML/JSON
5
6// 📦 Biblioteka standardowa (std)
7use std::collections::HashMap; // Jak Map<string, string> w TS
8use std::fs; // System plików
9// use std::path::{Path, PathBuf};
10use std::path::Path;
11
12// 🧩 Moduły własne (nasze lokalne importy)
13// ⚠️ Poprawka: DatabaseConnection jest teraz w db::connect, nie w db::Database
14use crate::db::connect::DatabaseConnection;
15use crate::utils::{load_toml, save_toml};
16
17// --- STRUKTURY DANYCH ---
18
19// 📚 EDU (TypeScript):
20// #[derive(...)] to makro. W TS musiałbyś ręcznie pisać funkcję toJson() i fromJson().
21// Tutaj Rust generuje ten kod za Ciebie podczas kompilacji.
22
23/// 🧱 1. GlobalConfig (./config/config.toml)
24/// Przechowuje informację, gdzie aktualnie szukamy baz (folder data).
25/// Odpowiednik TS: interface GlobalConfig { current_data_path: string | null }
26#[derive(Debug, Serialize, Deserialize, Default)]
27pub struct GlobalConfig {
28 pub current_data_path: Option<String>,
29}
30
31/// 🧱 2. DataIndex (data/data.toml)
32/// Lista dostępnych baz w danym folderze.
33#[derive(Debug, Serialize, Deserialize, Default)]
34pub struct DataIndex {
35 // HashMap<String, String> to w TS: Record<string, string>
36 pub databases: HashMap<String, String>,
37}
38
39/// 🧱 3. CurrentState (data/data_current.toml)
40/// Informacja, która baza jest teraz "otwarta" przez edytor.
41#[derive(Debug, Serialize, Deserialize, Default)]
42pub struct CurrentState {
43 pub active_db_name: Option<String>,
44}
45
46// --- LOGIKA OBSŁUGI ---
47
48/// ⚙️ ConfigManager - Klasa statyczna do zarządzania plikami.
49/// W Rust "metody statyczne" nie mają `&self`. Wywołujemy je ConfigManager::metoda().
50pub struct ConfigManager;
51
52impl ConfigManager {
53 // 📑 === GLOBAL CONFIG (./config/config.toml) ===
54
55 /// 💾 Wczytuje globalną konfigurację.
56 /// Zwraca GlobalConfig. Jeśli plik nie istnieje, zwraca domyślny (pusty).
57 pub fn load_global_config() -> GlobalConfig {
58 load_toml(Path::new("config/config.toml"))
59 }
60
61 /// 💾 Zapisuje globalną konfigurację
62 pub fn save_global_config(config: &GlobalConfig) {
63 save_toml(Path::new("config/config.toml"), config);
64 }
65
66 // --- 🗂️ DATA INDEX (data/data.toml) ---
67
68 /// 🧪 Wczytuje indeks baz i CZYŚCI nieistniejące wpisy (Walidacja)
69 pub fn load_and_clean_data_index(data_folder: &Path) -> DataIndex {
70 let index_path = data_folder.join("data.toml");
71
72 let mut index: DataIndex = load_toml(&index_path);
73
74 // 📚 EDU: Iterujemy i sprawdzamy, czy foldery fizycznie istnieją.
75 // Jeśli usunąłeś folder ręcznie, ten kod naprawi plik toml.
76 let mut clean_dbs = HashMap::new();
77 let mut changes_made = false;
78
79 for (name, relative_path) in index.databases {
80 let db_path = data_folder.join(&relative_path);
81 if db_path.exists() {
82 clean_dbs.insert(name, relative_path);
83 } else {
84 println!("🧹 [AUTO-CLEAN] Baza '{}' nie istnieje. Usuwam wpis.", name);
85 changes_made = true;
86 }
87 }
88
89 index.databases = clean_dbs;
90
91 if changes_made || !index_path.exists() {
92 Self::save_data_index(data_folder, &index);
93 }
94
95 index
96 }
97
98 /// 💾 Zapisuje indeks baz
99 pub fn save_data_index(data_folder: &Path, index: &DataIndex) {
100 save_toml(&data_folder.join("data.toml"), index);
101 }
102
103 // === 🗄️ ZARZĄDZANIE BAZAMI ===
104
105 /// ⚙️ Tworzy nową bazę danych FIZYCZNIE (pliki .clog, .manifest)
106 /// 📚 EDU (Async): `async fn` zwraca `Future` (jak Promise w TS).
107 /// Musisz użyć `.await` żeby to wykonać.
108 pub async fn create_new_db(
109 data_folder: &Path,
110 db_name: &str,
111 ) -> Result<(), Box<dyn std::error::Error>> {
112 let db_path = data_folder.join(db_name);
113
114 // 1. Tworzenie pustego folderu
115 if !db_path.exists() {
116 fs::create_dir_all(&db_path)?;
117 println!("✨ Utworzono folder: {:?}", db_path);
118 }
119
120 // 2. FIZYCZNA INICJALIZACJA SURREALKV
121 println!("⚙️ Inicjalizacja struktury plików SurrealKV...");
122 let db_path_str = db_path.to_str().unwrap();
123
124 // ⚠️ Poprawka: Używamy DatabaseConnection, a nie Database
125 let _temp_conn = DatabaseConnection::init(db_path_str).await?;
126 // Zmienna _temp_conn tutaj "umiera" (jest dropowana), co zamyka połączenie i zwalnia plik.
127
128 // 3. Aktualizacja indeksu
129 let mut index = Self::load_and_clean_data_index(data_folder);
130 index
131 .databases
132 .insert(db_name.to_string(), db_name.to_string());
133 Self::save_data_index(data_folder, &index);
134
135 Ok(())
136 }
137
138 /// 🚦 Ustawia aktywną bazę
139 pub fn set_active_db(data_folder: &Path, db_name: &str) {
140 let state = CurrentState {
141 active_db_name: Some(db_name.to_string()),
142 };
143 save_toml(&data_folder.join("data_current.toml"), &state);
144 }
145
146 /// 🚦 Pobiera nazwę aktywnej bazy
147 pub fn get_active_db(data_folder: &Path) -> Option<String> {
148 // 👇 UŻYWAMY UTILS (Rust sam się domyśli, że T = CurrentState)
149 let state: CurrentState = load_toml(&data_folder.join("data_current.toml"));
150 state.active_db_name
151 }
152}