use std::io::{Error, ErrorKind}; use rusqlite::Connection; use crate::{Modloader, config::Cfg, List}; //MODS pub fn mods_insert(config: Cfg, id: String, name: String, versions: Vec) -> Result<(), Box> { println!("Inserting mod {}({}) into database", name, id); let data = format!("{}/data.db", config.data); let connection = Connection::open(data)?; connection.execute( "INSERT INTO mods (id, name, versions) VALUES (?1, ?2, ?3)", [id, name.replace('\'', ""), versions.join("|")] )?; Ok(()) } pub fn mods_get_all_ids(config: Cfg) -> Result, Box> { let data = format!("{}/data.db", config.data); let connection = Connection::open(data).unwrap(); let mut mods: Vec = Vec::new(); let mut stmt = connection.prepare("SELECT id FROM mods")?; let id_iter = stmt.query_map([], |row| { row.get::(0) })?; for id in id_iter { println!("Found id {:?}", id.as_ref().unwrap()); mods.push(id?); } match mods.is_empty() { true => Err(Box::new(Error::new(ErrorKind::NotFound, "NO_MODS"))), false => Ok(mods), } } pub fn mods_get_id(config: Cfg, name: String) -> Result> { let data = format!("{}/data.db", config.data); let connection = Connection::open(data)?; let mut mod_id = String::new(); let mut stmt = connection.prepare("SELECT id FROM mods WHERE name = ?")?; let id_iter = stmt.query_map([name], |row| { row.get::(0) })?; for id in id_iter { println!("Found id {:?}", id.as_ref().unwrap()); mod_id = id?; }; match mod_id.is_empty() { true => Err(Box::new(Error::new(ErrorKind::NotFound, "MOD_NOT_FOUND"))), false => Ok(mod_id), } } pub fn mods_remove(config: Cfg, id: String) -> Result<(), Box> { println!("Removing mod {} from database", id); let data = format!("{}/data.db", config.data); let connection = Connection::open(data)?; connection.execute("DELETE FROM mods WHERE id = ?", [id])?; Ok(()) } //userlist pub fn userlist_insert(config: Cfg, list_id: String, mod_id: String, current_version: String, applicable_versions: Vec, current_link: String) -> Result<(), Box> { println!("Inserting {} into current list({})", mod_id, list_id); let data = format!("{}/data.db", config.data); let connection = Connection::open(data)?; connection.execute(format!("INSERT INTO {} VALUES (?1, ?2, ?3, ?4)", list_id).as_str(), [mod_id, current_version, applicable_versions.join("|"), current_link])?; Ok(()) } pub fn userlist_get_all_ids(config: Cfg, list_id: String) -> Result, Box> { let data = format!("{}/data.db", config.data); let connection = Connection::open(data).unwrap(); let mut mod_ids: Vec = Vec::new(); let mut stmt = connection.prepare(format!("SELECT mod_id FROM {}", list_id).as_str())?; let id_iter = stmt.query_map([], |row| { row.get::(0) })?; for id in id_iter { println!("Found id {:?}", id.as_ref().unwrap()); mod_ids.push(id?) }; match mod_ids.is_empty() { true => Err(Box::new(std::io::Error::new(ErrorKind::NotFound, "NO_MODS"))), false => Ok(mod_ids), } } pub fn userlist_remove(config: Cfg, list_id: String, mod_id: String) -> Result<(), Box> { let data = format!("{}/data.db", config.data); let connection = Connection::open(data)?; connection.execute(format!("DELETE FROM {} WHERE mod_id = ?", list_id).as_str(), [mod_id])?; Ok(()) } #[derive(Debug, Clone)] pub struct DBModlistVersions { pub mod_id: String, pub versions: String, } pub fn get_versions(config: Cfg, mods: Vec) -> Result, Box> { /* let data = format!("{}/data.db", config.data); let connection = sqlite::open(data).unwrap(); let mut wherestr = String::from("WHERE"); for (i, id) in mods.iter().enumerate() { let mut or = " OR"; if i == mods.len() - 1 { or = "" } println!("Pushing {}({}) | OR: '{}'", id, i, or); wherestr = format!("{} id = '{}'{}", wherestr, id, or); } let sql = format!("SELECT id, versions FROM mods {}", wherestr); dbg!(&sql); let mut versionmaps: Vec = Vec::new(); //TODO catch sql errors better let mut cursor = connection.prepare(sql).unwrap().into_cursor(); while let Some(Ok(row)) = cursor.next() { println!("{}: {}", row.get::(0), row.get::(1)); versionmaps.push(DBModlistVersions { mod_id: row.get::(0), versions: row.get::(1) }) }; if versionmaps.is_empty() { return Err(Box::new(std::io::Error::new(ErrorKind::Other, "NO_MODS_ON_LIST"))); }; Ok(versionmaps) */ Ok(vec![DBModlistVersions { mod_id: String::new(), versions: String::new() }]) } pub fn get_list_version(config: Cfg, list: List, mod_id: String) -> Result> { /* let data = format!("{}/data.db", config.data); let connection = sqlite::open(data).unwrap(); let sql = format!("SELECT applicable_versions FROM {} WHERE mod_id = '{}'", list.id, mod_id); //TODO catch sql errors better let mut version: String = String::new(); connection.iterate(sql, |ver| { if ver.is_empty() { return false; }; for &(_column, value) in ver.iter() { version = String::from(value.unwrap()); } true }).unwrap(); if version.is_empty() { return Err(Box::new(std::io::Error::new(ErrorKind::Other, "NO_MODS_ON_LIST"))); }; Ok(version) */ Ok(String::new()) } //lists pub fn lists_insert(config: Cfg, id: String, mc_version: String, mod_loader: Modloader) -> Result<(), Box> { println!("Creating list {}", id); let data = format!("{}/data.db", config.data); let connection = Connection::open(data)?; connection.execute("INSERT INTO lists VALUES (?1, ?2, ?3)", [id.clone(), mc_version, mod_loader.stringify()])?; connection.execute(format!("CREATE TABLE {}( 'mod_id' TEXT, 'current_version' TEXT, 'applicable_versions' BLOB, 'current_download' TEXT)", id).as_str(), [])?; Ok(()) } pub fn remove_list(config: Cfg, id: String) -> Result<(), Box> { /* let data = format!("{}/data.db", config.data); let connection = sqlite::open(data).unwrap(); let sql_list = format!("DELETE FROM lists WHERE id = '{}'", id); let sql_table = format!("DROP TABLE '{}'", id); let sql = format!("{};{};", sql_list, sql_table); connection.execute(sql) */ Ok(()) } pub fn get_lists(config: Cfg) -> Result, Box> { /* let data = format!("{}/data.db", config.data); let connection = sqlite::open(data).unwrap(); let sql = "SELECT id FROM lists"; let mut list: Vec = Vec::new(); //TODO catch sql errors better connection.iterate(sql, |ids| { if ids.is_empty() { return false; }; for &(_column, value) in ids.iter() { list.push(String::from(value.unwrap())); } true }).unwrap(); match list.is_empty() { true => Err(Box::new(std::io::Error::new(ErrorKind::NotFound, "NO_LISTS"))), false => Ok(list), } */ Ok(vec![String::new()]) } pub fn get_current_versions(config: Cfg, list: List) -> Result, Box> { /* let data = format!("{}/data.db", config.data); let connection = sqlite::open(data).unwrap(); let sql = format!("SELECT current_version FROM {}", list.id); dbg!(&sql); let mut versions: Vec = Vec::new(); //TODO catch sql errors better let mut cursor = connection.prepare(sql).unwrap().into_cursor(); while let Some(Ok(row)) = cursor.next() { versions.push(row.get::(0)); }; if versions.is_empty() { return Err(Box::new(std::io::Error::new(ErrorKind::Other, "NO_MODS_ON_LIST"))); }; Ok(versions) */ Ok(vec![String::new()]) } pub fn get_list(config: Cfg, id: String) -> Result> { /* let data = format!("{}/data.db", config.data); let connection = sqlite::open(data).unwrap(); let sql = format!("SELECT mc_version, modloader FROM lists WHERE id = '{}'", id); let mut list = vec![]; //TODO catch sql errors better connection.iterate(sql, |ids| { if ids.is_empty() { return false; }; for &(_column, value) in ids.iter() { list.push(String::from(value.unwrap())); } true }).unwrap(); if list.len() != 2 { return Err(Box::new(std::io::Error::new(ErrorKind::InvalidData, "LIST_MISSING_DATA"))) }; Ok(List { id, mc_version: String::from(&list[0]), modloader: get_modloader(String::from(&list[1]))? }) */ Ok(List { id: String::new(), mc_version: String::new(), modloader: Modloader::Fabric }) } pub fn change_list_versions(config: Cfg, list: List, current_version: String, versions: Vec, mod_id: String) -> Result<(), Box> { /* let data = format!("{}/data.db", config.data); let connection = sqlite::open(data).unwrap(); let sql = format!("UPDATE {} SET current_version = '{}', applicable_versions = '{}' WHERE mod_id = '{}'", list.id, current_version, versions.join("|"), mod_id); connection.execute(sql) */ Ok(()) } //DOWNLOAD pub fn insert_dl_link(config: Cfg, list: List, mod_id: String, link: String) -> Result<(), Box> { /* let data = format!("{}/data.db", config.data); let connection = sqlite::open(data).unwrap(); let sql = format!("UPDATE {} SET current_download = '{}' WHERE mod_id = '{}'", list.id, link, mod_id); connection.execute(sql) */ Ok(()) } pub fn get_dl_links(config: Cfg, list: List) -> Result, Box> { /* let data = format!("{}/data.db", config.data); let connection = sqlite::open(data).unwrap(); let sql = format!("SELECT current_download FROM {}", list.id); dbg!(&sql); let mut links: Vec = Vec::new(); //TODO catch sql errors better let mut cursor = connection.prepare(sql).unwrap().into_cursor(); while let Some(Ok(row)) = cursor.next() { links.push(row.get::(0)); }; if links.is_empty() { return Err(Box::new(std::io::Error::new(ErrorKind::Other, "NO_MODS_ON_LIST"))); }; Ok(links) */ Ok(vec![String::new()]) } //config pub fn change_list(config: Cfg, id: String) -> Result<(), Box> { /* let data = format!("{}/data.db", config.data); let connection = sqlite::open(data).unwrap(); let sql = format!("UPDATE user_config SET value = '{}' WHERE id = 'current_list'", id); connection.execute(sql) */ Ok(()) } pub fn get_current_list_id(config: Cfg) -> Result> { /* let data = format!("{}/data.db", config.data); let connection = sqlite::open(data).unwrap(); let sql = "SELECT id FROM lists"; let mut list: String = String::new(); //TODO catch sql errors better connection.iterate(sql, |ids| { if ids.is_empty() { return false; }; for &(_column, value) in ids.iter() { list = String::from(value.unwrap()); } true }).unwrap(); if list.is_empty() { get_lists(config)?; panic!("current list field should never be empty if there are other lists"); }; Ok(list) */ Ok(String::new()) } pub fn update_dbversion(config: Cfg, ver: String) -> Result<(), Box> { /* let data = format!("{}/data.db", config.data); let connection = sqlite::open(data).unwrap(); let sql = format!("UPDATE user_config SET value = '{}' WHERE id = 'db_version'", ver); connection.execute(sql) */ Ok(()) } pub fn create_dbversion(config: Cfg) -> Result<(), Box> { /* let data = format!("{}/data.db", config.data); let connection = sqlite::open(data).unwrap(); let sql = "INSERT INTO 'user_config' VALUES ( 'db_version', '0.2' );"; connection.execute(sql) */ Ok(()) } pub fn user_dbversion(config: Cfg) -> Result> { /* let data = format!("{}/data.db", config.data); let connection = sqlite::open(data).unwrap(); let sql = "SELECT db_version FROM user_config"; let mut ver: String = String::new(); //TODO catch sql errors better connection.iterate(sql, |ids| { if ids.is_empty() { return false; }; for &(_column, value) in ids.iter() { ver = String::from(value.unwrap()); } true })?; if ver.is_empty() { return Err(Box::new(std::io::Error::new(ErrorKind::Other, "NO_DBVERSION"))); }; Ok(ver) */ Ok(String::from("0.2")) } pub fn db_setup(config: Cfg) -> Result<(), Box> { println!("Initiating database"); let data = format!("{}/data.db", config.data); let connection = Connection::open(data)?; connection.execute_batch( "CREATE TABLE 'user_config' ( 'id' TEXT, 'value' TEXT ); CREATE TABLE 'mods' ( 'id' TEXT, 'name' TEXT, 'versions' TEXT ); CREATE TABLE 'lists' ( 'id' TEXT, 'mc_version' TEXT, 'modloader' TEXT ); INSERT INTO 'user_config' VALUES ( 'db_version', '0.2' ); INSERT INTO 'user_config' VALUES ( 'current_list', '...' )", )?; Ok(()) } pub fn insert_column(config: Cfg, table: String, column: String, c_type: String) -> Result<(), Box> { /* let data = format!("{}/data.db", config.data); let connection = sqlite::open(data).unwrap(); let ct = match c_type { sqlite::Type::Null => "NULL", sqlite::Type::Float => "FLOAT", sqlite::Type::Binary => "BINARY", sqlite::Type::String => "TEXT", sqlite::Type::Integer => "INT", }; let sql = format!("ALTER TABLE {} ADD '{}' {}", table, column, ct); connection.execute(sql) */ Ok(()) }