summaryrefslogtreecommitdiff
path: root/src/db.rs
diff options
context:
space:
mode:
authorfxqnlr <[email protected]>2022-11-07 22:29:35 +0100
committerfxqnlr <[email protected]>2022-11-07 22:29:35 +0100
commit889dc4f87b05d838b25428478a8c42dac454a5cf (patch)
treec4b09ae53a74a7f0afc1e095a4b66a1b00e67244 /src/db.rs
parentea50af892c4268ae06f6df40ee435eadd076228d (diff)
downloadmodlist-889dc4f87b05d838b25428478a8c42dac454a5cf.tar
modlist-889dc4f87b05d838b25428478a8c42dac454a5cf.tar.gz
modlist-889dc4f87b05d838b25428478a8c42dac454a5cf.zip
finished rusqlite; added all db tests
Diffstat (limited to 'src/db.rs')
-rw-r--r--src/db.rs406
1 files changed, 171 insertions, 235 deletions
diff --git a/src/db.rs b/src/db.rs
index 86e697e..5d82271 100644
--- a/src/db.rs
+++ b/src/db.rs
@@ -2,9 +2,9 @@ use std::io::{Error, ErrorKind};
2 2
3use rusqlite::Connection; 3use rusqlite::Connection;
4 4
5use crate::{Modloader, config::Cfg, List}; 5use crate::{Modloader, config::Cfg, List, get_modloader};
6 6
7//MODS 7//mods
8pub fn mods_insert(config: Cfg, id: String, name: String, versions: Vec<String>) -> Result<(), Box<dyn std::error::Error>> { 8pub fn mods_insert(config: Cfg, id: String, name: String, versions: Vec<String>) -> Result<(), Box<dyn std::error::Error>> {
9 9
10 println!("Inserting mod {}({}) into database", name, id); 10 println!("Inserting mod {}({}) into database", name, id);
@@ -75,6 +75,43 @@ pub fn mods_remove(config: Cfg, id: String) -> Result<(), Box<dyn std::error::Er
75 Ok(()) 75 Ok(())
76} 76}
77 77
78#[derive(Debug, Clone, PartialEq, Eq)]
79pub struct DBModlistVersions {
80 pub mod_id: String,
81 pub versions: String,
82}
83
84pub fn mods_get_versions(config: Cfg, mods: Vec<String>) -> Result<Vec<DBModlistVersions>, Box<dyn std::error::Error>> {
85 let data = format!("{}/data.db", config.data);
86 let connection = Connection::open(data)?;
87
88 if mods.is_empty() { return Err(Box::new(Error::new(ErrorKind::Other, "MODS_NO_INPUT"))); }
89
90 let mut wherestr = String::from("WHERE");
91 for (i, id) in mods.iter().enumerate() {
92 let mut or = " OR";
93 if i == mods.len() - 1 { or = "" };
94 wherestr = format!("{} id = '{}'{}", wherestr, id, or);
95 }
96
97 let mut versionmaps: Vec<DBModlistVersions> = Vec::new();
98 let mut stmt = connection.prepare(dbg!(format!("SELECT id, versions FROM mods {}", wherestr).as_str()))?;
99 let id_iter = stmt.query_map([], |row| {
100 Ok(vec![row.get::<usize, String>(0)?, row.get::<usize, String>(1)?])
101 })?;
102
103 for ver in id_iter {
104 let version = ver?;
105 println!("Found versions {} for mod {}", version[1], version[0]);
106 versionmaps.push(DBModlistVersions { mod_id: String::from(&version[0]), versions: String::from(&version[1]) })
107 };
108
109 match versionmaps.is_empty() {
110 true => Err(Box::new(Error::new(ErrorKind::NotFound, "MODS_MODS_NOT_FOUND"))),
111 false => Ok(versionmaps),
112 }
113}
114
78//userlist 115//userlist
79pub fn userlist_insert(config: Cfg, list_id: String, mod_id: String, current_version: String, applicable_versions: Vec<String>, current_link: String) -> Result<(), Box<dyn std::error::Error>> { 116pub fn userlist_insert(config: Cfg, list_id: String, mod_id: String, current_version: String, applicable_versions: Vec<String>, current_link: String) -> Result<(), Box<dyn std::error::Error>> {
80 println!("Inserting {} into current list({})", mod_id, list_id); 117 println!("Inserting {} into current list({})", mod_id, list_id);
@@ -119,69 +156,74 @@ pub fn userlist_remove(config: Cfg, list_id: String, mod_id: String) -> Result<(
119} 156}
120 157
121 158
122#[derive(Debug, Clone)] 159pub fn userlist_get_applicable_versions(config: Cfg, list_id: String, mod_id: String) -> Result<String, Box<dyn std::error::Error>> {
123pub struct DBModlistVersions {
124 pub mod_id: String,
125 pub versions: String,
126}
127
128pub fn get_versions(config: Cfg, mods: Vec<String>) -> Result<Vec<DBModlistVersions>, Box<dyn std::error::Error>> {
129 /*
130 let data = format!("{}/data.db", config.data); 160 let data = format!("{}/data.db", config.data);
131 let connection = sqlite::open(data).unwrap(); 161 let connection = Connection::open(data).unwrap();
132 162
133 let mut wherestr = String::from("WHERE"); 163 let mut version: String = String::new();
134 for (i, id) in mods.iter().enumerate() { 164 let mut stmt = connection.prepare(format!("SELECT applicable_versions FROM {} WHERE mod_id = ?", list_id).as_str())?;
135 let mut or = " OR"; 165 let ver_iter = stmt.query_map([mod_id], |row| {
136 if i == mods.len() - 1 { or = "" } 166 row.get::<usize, String>(0)
137 println!("Pushing {}({}) | OR: '{}'", id, i, or); 167 })?;
138 wherestr = format!("{} id = '{}'{}", wherestr, id, or);
139 }
140 168
141 let sql = format!("SELECT id, versions FROM mods {}", wherestr); 169 for ver in ver_iter {
170 println!("Found id {:?}", ver);
171 version = ver?;
172 };
142 173
143 dbg!(&sql); 174 match version.is_empty() {
175 true => Err(Box::new(Error::new(ErrorKind::NotFound, "MOD_NOT_FOUND"))),
176 false => Ok(version),
177 }
178}
144 179
145 let mut versionmaps: Vec<DBModlistVersions> = Vec::new(); 180pub fn userlist_get_all_current_version_ids(config: Cfg, list_id: String) -> Result<Vec<String>, Box<dyn std::error::Error>> {
146 //TODO catch sql errors better 181 let data = format!("{}/data.db", config.data);
147 let mut cursor = connection.prepare(sql).unwrap().into_cursor(); 182 let connection = Connection::open(data)?;
148 183
149 while let Some(Ok(row)) = cursor.next() { 184 let mut versions: Vec<String> = Vec::new();
150 println!("{}: {}", row.get::<String, _>(0), row.get::<String, _>(1)); 185 let mut stmt = connection.prepare(format!("SELECT current_version FROM {}", list_id).as_str())?;
151 versionmaps.push(DBModlistVersions { mod_id: row.get::<String, _>(0), versions: row.get::<String, _>(1) }) 186 let id_iter = stmt.query_map([], |row| {
187 row.get::<usize, String>(0)
188 })?;
189
190 for id in id_iter {
191 versions.push(id?);
152 }; 192 };
153 193
154 if versionmaps.is_empty() { return Err(Box::new(std::io::Error::new(ErrorKind::Other, "NO_MODS_ON_LIST"))); }; 194 if versions.is_empty() { return Err(Box::new(std::io::Error::new(ErrorKind::Other, "NO_MODS_ON_LIST"))); };
155 195
156 Ok(versionmaps) 196 Ok(versions)
157 */
158 Ok(vec![DBModlistVersions { mod_id: String::new(), versions: String::new() }])
159} 197}
160 198
161pub fn get_list_version(config: Cfg, list: List, mod_id: String) -> Result<String, Box<dyn std::error::Error>> { 199pub fn userlist_change_versions(config: Cfg, list_id: String, current_version: String, versions: String, link: String, mod_id: String) -> Result<(), Box<dyn std::error::Error>> {
162 /*
163 let data = format!("{}/data.db", config.data); 200 let data = format!("{}/data.db", config.data);
164 let connection = sqlite::open(data).unwrap(); 201 let connection = Connection::open(data)?;
165
166 let sql = format!("SELECT applicable_versions FROM {} WHERE mod_id = '{}'", list.id, mod_id);
167
168 //TODO catch sql errors better
169 let mut version: String = String::new();
170 connection.iterate(sql, |ver| {
171 if ver.is_empty() { return false; };
172 for &(_column, value) in ver.iter() {
173 version = String::from(value.unwrap());
174 }
175 true
176 }).unwrap();
177
178 if version.is_empty() { return Err(Box::new(std::io::Error::new(ErrorKind::Other, "NO_MODS_ON_LIST"))); };
179 202
180 Ok(version) 203 connection.execute(format!("UPDATE {} SET current_version = ?1, applicable_versions = ?2, current_download = ?3 WHERE mod_id = ?4", list_id).as_str(), [current_version, versions, link, mod_id])?;
181 */ 204 Ok(())
182 Ok(String::new())
183} 205}
184 206
207pub fn userlist_get_all_downloads(config: Cfg, list_id: String) -> Result<Vec<String>, Box<dyn std::error::Error>> {
208 let data = format!("{}/data.db", config.data);
209 let connection = Connection::open(data).unwrap();
210
211 let mut links: Vec<String> = Vec::new();
212 let mut stmt = connection.prepare(format!("SELECT current_download FROM {}", list_id).as_str())?;
213 let link_iter = stmt.query_map([], |row| {
214 row.get::<usize, String>(0)
215 })?;
216
217 for link in link_iter {
218 let l = link?;
219 println!("Found link {}", String::from(&l));
220 links.push(l)
221 };
222
223 if links.is_empty() { return Err(Box::new(std::io::Error::new(ErrorKind::Other, "NO_MODS_ON_LIST"))); };
224
225 Ok(links)
226}
185 227
186//lists 228//lists
187pub fn lists_insert(config: Cfg, id: String, mc_version: String, mod_loader: Modloader) -> Result<(), Box<dyn std::error::Error>> { 229pub fn lists_insert(config: Cfg, id: String, mc_version: String, mod_loader: Modloader) -> Result<(), Box<dyn std::error::Error>> {
@@ -196,222 +238,134 @@ pub fn lists_insert(config: Cfg, id: String, mc_version: String, mod_loader: Mod
196 Ok(()) 238 Ok(())
197} 239}
198 240
199pub fn remove_list(config: Cfg, id: String) -> Result<(), Box<dyn std::error::Error>> { 241pub fn lists_remove(config: Cfg, id: String) -> Result<(), Box<dyn std::error::Error>> {
200 /*
201 let data = format!("{}/data.db", config.data); 242 let data = format!("{}/data.db", config.data);
202 let connection = sqlite::open(data).unwrap(); 243 let connection = Connection::open(data)?;
203
204 let sql_list = format!("DELETE FROM lists WHERE id = '{}'", id);
205 let sql_table = format!("DROP TABLE '{}'", id);
206 let sql = format!("{};{};", sql_list, sql_table);
207 244
208 connection.execute(sql) 245 connection.execute("DELETE FROM lists WHERE id = ?", [&id])?;
209 */ 246 connection.execute(format!("DROP TABLE {}", id).as_str(), [])?;
210 Ok(()) 247 Ok(())
211} 248}
212 249
213pub fn get_lists(config: Cfg) -> Result<Vec<String>, Box<dyn std::error::Error>> { 250pub fn lists_get(config: Cfg, list_id: String) -> Result<List, Box<dyn std::error::Error>> {
214 /*
215 let data = format!("{}/data.db", config.data); 251 let data = format!("{}/data.db", config.data);
216 let connection = sqlite::open(data).unwrap(); 252 let connection = Connection::open(data).unwrap();
217
218 let sql = "SELECT id FROM lists";
219
220 let mut list: Vec<String> = Vec::new();
221 //TODO catch sql errors better
222 connection.iterate(sql, |ids| {
223 if ids.is_empty() { return false; };
224 for &(_column, value) in ids.iter() {
225 list.push(String::from(value.unwrap()));
226 }
227 true
228 }).unwrap();
229 match list.is_empty() {
230 true => Err(Box::new(std::io::Error::new(ErrorKind::NotFound, "NO_LISTS"))),
231 false => Ok(list),
232 }
233 */
234 Ok(vec![String::new()])
235}
236
237pub fn get_current_versions(config: Cfg, list: List) -> Result<Vec<String>, Box<std::io::Error>> {
238 /*
239 let data = format!("{}/data.db", config.data);
240 let connection = sqlite::open(data).unwrap();
241
242 let sql = format!("SELECT current_version FROM {}", list.id);
243 253
244 dbg!(&sql); 254 let mut list = List { id: String::new(), mc_version: String::new(), modloader: Modloader::Fabric };
255 let mut stmt = connection.prepare("SELECT mc_version, modloader FROM lists WHERE id = ?")?;
245 256
246 let mut versions: Vec<String> = Vec::new(); 257 let list_iter = stmt.query_map([&list_id], |row| {
247 //TODO catch sql errors better 258 Ok(vec![row.get::<usize, String>(0)?, row.get::<usize, String>(1)?])
248 let mut cursor = connection.prepare(sql).unwrap().into_cursor(); 259 })?;
249 260
250 while let Some(Ok(row)) = cursor.next() { 261 for l in list_iter {
251 versions.push(row.get::<String, _>(0)); 262 let li = l?;
263 list = List { id: String::from(&list_id), mc_version: String::from(&li[0]), modloader: get_modloader(String::from(&li[1]))? };
252 }; 264 };
253 265
254 if versions.is_empty() { return Err(Box::new(std::io::Error::new(ErrorKind::Other, "NO_MODS_ON_LIST"))); }; 266 if list.id.is_empty() { return Err(Box::new(Error::new(ErrorKind::Other, "LIST_NOT_FOUND"))); }
255
256 Ok(versions)
257 */
258 Ok(vec![String::new()])
259}
260
261pub fn get_list(config: Cfg, id: String) -> Result<List, Box<dyn std::error::Error>> {
262 /*
263 let data = format!("{}/data.db", config.data);
264 let connection = sqlite::open(data).unwrap();
265
266 let sql = format!("SELECT mc_version, modloader FROM lists WHERE id = '{}'", id);
267 267
268 let mut list = vec![]; 268 Ok(list)
269 //TODO catch sql errors better
270 connection.iterate(sql, |ids| {
271 if ids.is_empty() { return false; };
272 for &(_column, value) in ids.iter() {
273 list.push(String::from(value.unwrap()));
274 }
275 true
276 }).unwrap();
277
278 if list.len() != 2 { return Err(Box::new(std::io::Error::new(ErrorKind::InvalidData, "LIST_MISSING_DATA"))) };
279
280 Ok(List { id, mc_version: String::from(&list[0]), modloader: get_modloader(String::from(&list[1]))? })
281 */
282 Ok(List { id: String::new(), mc_version: String::new(), modloader: Modloader::Fabric })
283} 269}
284 270
285pub fn change_list_versions(config: Cfg, list: List, current_version: String, versions: Vec<String>, mod_id: String) -> Result<(), Box<dyn std::error::Error>> { 271pub fn lists_get_all_ids(config: Cfg) -> Result<Vec<String>, Box<dyn std::error::Error>> {
286 /*
287 let data = format!("{}/data.db", config.data); 272 let data = format!("{}/data.db", config.data);
288 let connection = sqlite::open(data).unwrap(); 273 let connection = Connection::open(data).unwrap();
274
275 let mut list_ids: Vec<String> = Vec::new();
276 let mut stmt = connection.prepare("SELECT id FROM lists")?;
277 let id_iter = stmt.query_map([], |row| {
278 row.get::<usize, String>(0)
279 })?;
289 280
290 let sql = format!("UPDATE {} SET current_version = '{}', applicable_versions = '{}' WHERE mod_id = '{}'", list.id, current_version, versions.join("|"), mod_id); 281 for id in id_iter {
282 println!("Found id {:?}", id.as_ref().unwrap());
283 list_ids.push(id?)
284 };
291 285
292 connection.execute(sql) 286 match list_ids.is_empty() {
293 */ 287 true => Err(Box::new(std::io::Error::new(ErrorKind::NotFound, "NO_LISTS"))),
294 Ok(()) 288 false => Ok(list_ids),
289 }
295} 290}
296 291
297//DOWNLOAD 292//config
298 293pub fn config_change_current_list(config: Cfg, id: String) -> Result<(), Box<dyn std::error::Error>> {
299pub fn insert_dl_link(config: Cfg, list: List, mod_id: String, link: String) -> Result<(), Box<dyn std::error::Error>> {
300 /*
301 let data = format!("{}/data.db", config.data); 294 let data = format!("{}/data.db", config.data);
302 let connection = sqlite::open(data).unwrap(); 295 let connection = Connection::open(data)?;
303
304 let sql = format!("UPDATE {} SET current_download = '{}' WHERE mod_id = '{}'", list.id, link, mod_id);
305 296
306 connection.execute(sql) 297 connection.execute("UPDATE user_config SET value = ? WHERE id = 'current_list'", [id])?;
307 */
308 Ok(()) 298 Ok(())
309} 299}
310 300
311pub fn get_dl_links(config: Cfg, list: List) -> Result<Vec<String>, Box<std::io::Error>> { 301pub fn config_get_current_list(config: Cfg) -> Result<String, Box<dyn std::error::Error>> {
312 /*
313 let data = format!("{}/data.db", config.data); 302 let data = format!("{}/data.db", config.data);
314 let connection = sqlite::open(data).unwrap(); 303 let connection = Connection::open(data).unwrap();
315 304
316 let sql = format!("SELECT current_download FROM {}", list.id); 305 let mut list_id = String::new();
317 306 let mut stmt = connection.prepare("SELECT value FROM user_config WHERE id = 'current_list'")?;
318 dbg!(&sql); 307 let list_iter = stmt.query_map([], |row| {
319 308 row.get::<usize, String>(0)
320 let mut links: Vec<String> = Vec::new(); 309 })?;
321 //TODO catch sql errors better
322 let mut cursor = connection.prepare(sql).unwrap().into_cursor();
323 310
324 while let Some(Ok(row)) = cursor.next() { 311 for list in list_iter {
325 links.push(row.get::<String, _>(0)); 312 list_id = list?;
326 }; 313 };
327 314
328 if links.is_empty() { return Err(Box::new(std::io::Error::new(ErrorKind::Other, "NO_MODS_ON_LIST"))); }; 315 if list_id.is_empty() { return Err(Box::new(Error::new(ErrorKind::Other, "NO_CURRENT_LIST"))); }
329 316
330 Ok(links) 317 Ok(list_id)
331 */
332 Ok(vec![String::new()])
333} 318}
334 319
335//config 320//SETUP(UPDATES)
336pub fn change_list(config: Cfg, id: String) -> Result<(), Box<dyn std::error::Error>> { 321pub fn s_userlist_update_download(config: Cfg, list_id: String, mod_id: String, link: String) -> Result<(), Box<dyn std::error::Error>> {
337 /*
338 let data = format!("{}/data.db", config.data); 322 let data = format!("{}/data.db", config.data);
339 let connection = sqlite::open(data).unwrap(); 323 let connection = Connection::open(data)?;
340
341 let sql = format!("UPDATE user_config SET value = '{}' WHERE id = 'current_list'", id);
342 324
343 connection.execute(sql) 325 connection.execute(format!("UPDATE {} SET current_download = ?1 WHERE mod_id = ?2", list_id).as_str(), [link, mod_id])?;
344 */
345 Ok(()) 326 Ok(())
346} 327}
347 328
348pub fn get_current_list_id(config: Cfg) -> Result<String, Box<dyn std::error::Error>> { 329pub fn s_config_create_version(config: Cfg) -> Result<(), Box<dyn std::error::Error>> {
349 /*
350 let data = format!("{}/data.db", config.data); 330 let data = format!("{}/data.db", config.data);
351 let connection = sqlite::open(data).unwrap(); 331 let connection = Connection::open(data)?;
352 332
353 let sql = "SELECT id FROM lists"; 333 connection.execute("INSERT INTO 'user_config' VALUES ( 'db_version', '0.2' )", ())?;
354 334 Ok(())
355 let mut list: String = String::new();
356 //TODO catch sql errors better
357 connection.iterate(sql, |ids| {
358 if ids.is_empty() { return false; };
359 for &(_column, value) in ids.iter() {
360 list = String::from(value.unwrap());
361 }
362 true
363 }).unwrap();
364 if list.is_empty() {
365 get_lists(config)?;
366 panic!("current list field should never be empty if there are other lists");
367 };
368 Ok(list)
369 */
370 Ok(String::new())
371} 335}
372 336
373pub fn update_dbversion(config: Cfg, ver: String) -> Result<(), Box<dyn std::error::Error>> { 337pub fn s_config_update_version(config: Cfg, ver: String) -> Result<(), Box<dyn std::error::Error>> {
374 /*
375 let data = format!("{}/data.db", config.data); 338 let data = format!("{}/data.db", config.data);
376 let connection = sqlite::open(data).unwrap(); 339 let connection = Connection::open(data)?;
377
378 let sql = format!("UPDATE user_config SET value = '{}' WHERE id = 'db_version'", ver);
379 340
380 connection.execute(sql) 341 connection.execute("UPDATE user_config SET value = ? WHERE id = 'db_version'", [ver])?;
381 */
382 Ok(()) 342 Ok(())
383} 343}
384 344
385pub fn create_dbversion(config: Cfg) -> Result<(), Box<dyn std::error::Error>> { 345pub fn s_config_get_version(config: Cfg) -> Result<String, Box<dyn std::error::Error>> {
386 /*
387 let data = format!("{}/data.db", config.data); 346 let data = format!("{}/data.db", config.data);
388 let connection = sqlite::open(data).unwrap(); 347 let connection = Connection::open(data)?;
389 let sql = "INSERT INTO 'user_config' VALUES ( 'db_version', '0.2' );"; 348
390 connection.execute(sql) 349 let mut version: String = String::new();
391 */ 350 let mut stmt = connection.prepare("SELECT value FROM user_config WHERE id = 'db_version'")?;
392 Ok(()) 351 let ver_iter = stmt.query_map([], |row| {
352 row.get::<usize, String>(0)
353 })?;
354
355 for ver in ver_iter {
356 version = ver?;
357 };
358
359 if version.is_empty() { return Err(Box::new(std::io::Error::new(ErrorKind::Other, "NO_DBVERSION"))); };
360 Ok(version)
393} 361}
394 362
395pub fn user_dbversion(config: Cfg) -> Result<String, Box<dyn std::error::Error>> { 363pub fn s_insert_column(config: Cfg, table: String, column: String, c_type: String) -> Result<(), Box<dyn std::error::Error>> {
396 /*
397 let data = format!("{}/data.db", config.data); 364 let data = format!("{}/data.db", config.data);
398 let connection = sqlite::open(data).unwrap(); 365 let connection = Connection::open(data)?;
399 366
400 let sql = "SELECT db_version FROM user_config"; 367 connection.execute(format!("ALTER TABLE {} ADD '{}' {}", table, column, c_type).as_str(), ())?;
401 368 Ok(())
402 let mut ver: String = String::new();
403 //TODO catch sql errors better
404 connection.iterate(sql, |ids| {
405 if ids.is_empty() { return false; };
406 for &(_column, value) in ids.iter() {
407 ver = String::from(value.unwrap());
408 }
409 true
410 })?;
411 if ver.is_empty() { return Err(Box::new(std::io::Error::new(ErrorKind::Other, "NO_DBVERSION"))); };
412 Ok(ver)
413 */
414 Ok(String::from("0.2"))
415} 369}
416 370
417pub fn db_setup(config: Cfg) -> Result<(), Box<dyn std::error::Error>> { 371pub fn db_setup(config: Cfg) -> Result<(), Box<dyn std::error::Error>> {
@@ -432,21 +386,3 @@ pub fn db_setup(config: Cfg) -> Result<(), Box<dyn std::error::Error>> {
432 Ok(()) 386 Ok(())
433} 387}
434 388
435pub fn insert_column(config: Cfg, table: String, column: String, c_type: String) -> Result<(), Box<dyn std::error::Error>> {
436 /*
437 let data = format!("{}/data.db", config.data);
438 let connection = sqlite::open(data).unwrap();
439
440 let ct = match c_type {
441 sqlite::Type::Null => "NULL",
442 sqlite::Type::Float => "FLOAT",
443 sqlite::Type::Binary => "BINARY",
444 sqlite::Type::String => "TEXT",
445 sqlite::Type::Integer => "INT",
446 };
447
448 let sql = format!("ALTER TABLE {} ADD '{}' {}", table, column, ct);
449 connection.execute(sql)
450 */
451 Ok(())
452}