diff --git a/src/morethantext/database.rs b/src/morethantext/database.rs index 460be4d..3fd9882 100644 --- a/src/morethantext/database.rs +++ b/src/morethantext/database.rs @@ -1,18 +1,171 @@ +use super::{Data, ErrorCode, MTTError, Table}; +use std::collections::HashMap; + #[derive(Clone, Debug)] -pub struct Database; +pub struct Database { + data: HashMap>, +} impl Database { pub fn new() -> Self { - Self {} + Self { + data: HashMap::new(), + } + } + + pub fn add(&mut self, name: S) -> Result<(), MTTError> + where + S: Into, + { + let db_name = name.into(); + match self.get(&db_name) { + Some(_) => Err(MTTError::from_code(ErrorCode::DuplicateTable(db_name))), + None => { + self.data.insert(db_name, Data::from_data(Table::new())); + Ok(()) + } + } + } + + pub fn add_by_id(&mut self, name: S, id: D) -> Result<(), MTTError> + where + S: Into, + D: Into, + { + let db_name = name.into(); + match self.get(&db_name) { + Some(_) => Err(MTTError::from_code(ErrorCode::DuplicateTable(db_name))), + None => { + self.data.insert(db_name, Data::from_id(id.into())); + Ok(()) + } + } + } + + pub fn get(&self, name: &str) -> Option<&Data> { + self.data.get(name) + } + + pub fn list(&self) -> Vec { + let mut names = Vec::new(); + for name in self.data.keys() { + names.push(name.to_string()); + } + names.sort(); + names } } #[cfg(test)] -mod dbase { +mod databases { use super::*; #[test] fn create_new() { - Database::new(); + let db = Database::new(); + let expected: Vec = Vec::new(); + assert_eq!(db.list(), expected); + } + + #[test] + fn add_db_by_str() { + let mut db = Database::new(); + let name = "Melvin"; + db.add(name).unwrap(); + let output = db.get(name); + assert!(output.is_some(), "Get returned none."); + } + + #[test] + fn add_db_by_string() { + let mut db = Database::new(); + let name = "Marvin"; + db.add(name.to_string()).unwrap(); + let output = db.get(name); + assert!(output.is_some(), "Get returned none."); + } + + #[test] + fn fail_on_duplicates() -> Result<(), MTTError> { + let mut db = Database::new(); + let name = "Mickie"; + db.add(name).unwrap(); + match db.add(name) { + Ok(_) => Err(MTTError::new("duplicates should error")), + Err(err) => match err.code { + ErrorCode::DuplicateTable(db_name) => { + assert_eq!(db_name, name); + Ok(()) + } + _ => Err(MTTError::new(format!("{:?} is not DuplicateTable", err))), + }, + } + } + + #[test] + fn add_using_cache_id() { + let mut db = Database::new(); + let name = "fred"; + let id = "12345"; + db.add_by_id(name, id).unwrap(); + let output = db.get(name).unwrap(); + assert!(output.data.is_none(), "there should be no data"); + assert_eq!(output.id, Some(id.to_string())); + } + + #[test] + fn add_by_cache_id_name_string() { + let mut db = Database::new(); + let name = "barney"; + let id = "67890"; + db.add_by_id(name.to_string(), id).unwrap(); + let output = db.get(name).unwrap(); + assert!(output.data.is_none(), "there should be no data"); + assert_eq!(output.id, Some(id.to_string())); + } + + #[test] + fn no_duplicate_databases_for_add_by_id() { + let mut db = Database::new(); + let name = "betty"; + db.add_by_id(name, "fghij").unwrap(); + match db.add_by_id(name, "klmno") { + Ok(_) => assert!(false, "Duplicates should error."), + Err(err) => match err.code { + ErrorCode::DuplicateTable(db_name) => assert_eq!(db_name, name), + _ => assert!(false, "{:?} is not DuplicateTable", err), + }, + } + } + + #[test] + fn add_by_cache_id_string() { + let mut db = Database::new(); + let name = "wilma"; + let id = "abcdef"; + db.add_by_id(name, id.to_string()).unwrap(); + let output = db.get(name).unwrap(); + assert!(output.data.is_none(), "there should be no data"); + assert_eq!(output.id, Some(id.to_string())); + } + + #[test] + fn get_bad_database() -> Result<(), MTTError> { + let db = Database::new(); + match db.get("missing") { + Some(_) => Err(MTTError::new("Should have returned None.")), + None => Ok(()), + } + } + + #[test] + fn get_list() { + let mut db = Database::new(); + let mut ids = ["one", "two", "three", "four", "five"]; + for name in ids { + db.add(name.to_string()).unwrap(); + } + ids.sort(); + assert_eq!(db.list(), ids); } } diff --git a/src/morethantext/error.rs b/src/morethantext/error.rs index 9297fa0..71894e5 100644 --- a/src/morethantext/error.rs +++ b/src/morethantext/error.rs @@ -8,6 +8,8 @@ pub enum ErrorCode { IDNotFound(String), // Store DuplicateDatabase(String), + // Database + DuplicateTable(String), } impl fmt::Display for ErrorCode { @@ -16,6 +18,7 @@ impl fmt::Display for ErrorCode { ErrorCode::Undefined(msg) => write!(f, "{}", msg), ErrorCode::IDNotFound(id) => write!(f, "ID '{}' not found", id), ErrorCode::DuplicateDatabase(name) => write!(f, "database '{}' already exists", name), + ErrorCode::DuplicateTable(name) => write!(f, "table '{}' already exists", name), } } } @@ -51,6 +54,14 @@ mod errorcodes { ); } } + + #[test] + fn duplicate_table() { + for item in ITEMS { + let err = ErrorCode::DuplicateTable(item.to_string()); + assert_eq!(err.to_string(), format!("table '{}' already exists", item)); + } + } } #[derive(Clone, Debug)] diff --git a/src/morethantext/mod.rs b/src/morethantext/mod.rs index 98157e9..b641027 100644 --- a/src/morethantext/mod.rs +++ b/src/morethantext/mod.rs @@ -2,6 +2,7 @@ mod cache; mod database; mod error; mod store; +mod table; use async_std::{ channel::{unbounded, Sender}, @@ -12,6 +13,7 @@ use cache::Cache; use database::Database; use error::{ErrorCode, MTTError}; use store::Store; +use table::Table; const ENTRY: &str = "EntryPoint"; diff --git a/src/morethantext/table.rs b/src/morethantext/table.rs new file mode 100644 index 0000000..1080c0b --- /dev/null +++ b/src/morethantext/table.rs @@ -0,0 +1,18 @@ +#[derive(Clone, Debug)] +pub struct Table; + +impl Table { + pub fn new() -> Self { + Self {} + } +} + +#[cfg(test)] +mod tables { + use super::*; + + #[test] + fn create_new() { + Table::new(); + } +}