/* use async_std::sync::{Arc, RwLock}; use std::{collections::HashMap, error::Error, fmt, str::FromStr}; #[derive(Debug)] pub struct DBError { detail: String, source: Option>, } impl DBError { fn new(detail: String) -> Self { Self { detail: detail.to_string(), source: None, } } } impl fmt::Display for DBError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", &self.detail) } } impl Error for DBError { fn source(&self) -> Option<&(dyn Error + 'static)> { match &self.source { Some(err) => Some(err), None => None, } } } #[derive(Clone, PartialEq)] pub enum FieldType { Table, } impl fmt::Display for FieldType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { FieldType::Table => write!(f, "table"), } } } impl FromStr for FieldType { type Err = DBError; fn from_str(input: &str) -> Result { match input { "table" => Ok(FieldType::Table), _ => Err(DBError::new(format!("field type {} does not exist", input))), } } } pub struct Table { fields: Arc>>, } impl Table { pub async fn new() -> Self { Self { fields: Arc::new(RwLock::new(HashMap::new())), } } pub async fn update_field(&self, name: &str, ftype: &str) -> Result<(), Box> { let ftype = match FieldType::from_str(ftype) { Ok(field) => field, Err(err) => { let mut error = DBError::new(format!("failed to add field {}", name)); error.source = Some(Box::new(err)); return Err(Box::new(error)); } }; let mut fmap = self.fields.write().await; match fmap.get(name) { Some(_) => Err(Box::new(DBError::new(format!( "field {} already exists", name )))), None => { fmap.insert(name.to_string(), ftype); Ok(()) } } } pub async fn fields(&self) -> HashMap { let fmap = self.fields.read().await; fmap.clone() } } */ use async_std::sync::{Arc, RwLock}; use std::collections::HashMap; pub mod error; mod fieldtype; use error::MTTError; use fieldtype::FieldType; #[derive(Clone)] pub struct MoreThanText; impl MoreThanText { pub async fn new() -> Self { Self {} } pub async fn add_table(&self, name: &str) -> Table { Table::new() } pub async fn get_table(&self, name: &str) -> Table { Table::new() } } #[derive(Clone, PartialEq)] struct FieldDef; pub struct Table { fields: Arc>>, } impl Table { fn new() -> Self { Self { fields: Arc::new(RwLock::new(HashMap::new())), } } async fn add_field(&self, name: &str) { let mut field_defs = self.fields.write().await; field_defs.insert(name.to_string(), FieldDef {}); } async fn get_field(&self, name: &str) -> Option { let field_defs = self.fields.read().await; match field_defs.get(name) { Some(def) => Some(def.clone()), None => None, } } async fn new_record(&self) -> Record { Record::new() } } struct Record { data: Arc>>, } impl Record { fn new() -> Self { Self { data: Arc::new(RwLock::new(HashMap::new())), } } /* async fn update_field(&self, name: String, data: FieldType) { let mut map = self.data.write().await; map.insert(name, data); } async fn get_field(&self, name: &str) -> Option { let map = self.data.read().await; match map.get(name) { Some(field) => Some(field.clone()), None => None, } } */ } #[cfg(test)] mod databases { use super::*; #[async_std::test] async fn new_database() { MoreThanText::new().await; } async fn add_table() { let db = MoreThanText::new().await; let name = "table"; db.add_table(name).await; db.get_table(name).await; } } #[cfg(test)] mod tables { use super::*; #[test] fn new_table() { Table::new(); } #[async_std::test] async fn add_field_definition() { let tbl = Table::new(); let name = "field"; let expected = FieldDef {}; tbl.add_field(name).await; let output = tbl.get_field(name).await.unwrap(); assert!(output == expected, "Did not return a field definition."); } #[async_std::test] async fn missing_field_definition() { let tbl = Table::new(); let output = tbl.get_field("missing").await; assert!( output == None, "Should return None if field does not exist." ); } #[async_std::test] async fn get_empty_record() { let tbl = Table::new(); tbl.new_record().await; } } #[cfg(test)] mod records { use super::*; /* #[async_std::test] async fn update_fields() { let rec = Record::new(); let name = "elephant"; let data = ""; let sstr = StaticString::new(); rec.update_field(name.to_string(), sstr).await; let output = rec.get_field(name).await.unwrap(); assert!( output.to_string() == data, "\n\nGot: {}\nWant: {}\n\n", output.to_string(), data ) } #[async_std::test] async fn empty_field() { let rec = Record::new(); let name = "mull"; let output = rec.get_field(name).await; assert!(output == None, "Should return an option."); } */ } /* #[cfg(test)] mod tables { use super::*; #[async_std::test] async fn new_table() { Table::new().await; } #[async_std::test] async fn update_field() { let table = Table::new().await; let mut expected: HashMap = HashMap::new(); expected.insert("stan".to_string(), FieldType::Table); expected.insert("lee".to_string(), FieldType::Table); table.update_field("stan", "table").await.unwrap(); table.update_field("lee", "table").await.unwrap(); let output = table.fields().await; assert!(output == expected, "Table did not get the fields added."); } #[async_std::test] async fn add_bad_field() -> Result<(), String> { let table = Table::new().await; let name = "failure"; let bad_type = "ljksdbtt"; let expected = format!("failed to add field {}", name); let source = format!("field type {} does not exist", bad_type); match table.update_field(name, bad_type).await { Ok(_) => Err("A bad field type should not return successfully".to_string()), Err(err) => { if format!("{}", err) != expected { Err(format!("Got: '{}' - Want: '{}'", err, expected)) } else if format!("{}", err.source().unwrap()) != source { Err(format!( "Got: '{}' - Want: '{}'", err.source().unwrap(), source )) } else { Ok(()) } } } } #[async_std::test] async fn add_duplicate_field() -> Result<(), String> { let table = Table::new().await; let name = "twice"; let expected = format!("field {} already exists", name); table.update_field(name, "table").await.unwrap(); match table.update_field(name, "table").await { Ok(_) => Err(format!("Cannot have two fields with named '{}'", name)), Err(err) => { if format!("{}", err) == expected { Ok(()) } else { Err(format!("Got: '{}' - Want: '{}'", err, expected)) } } } } } #[cfg(test)] mod databases { use super::*; #[async_std::test] async fn new_database() { MoreThanText::new().await; } #[async_std::test] async fn add_table() { let db = MoreThanText::new().await; db.add_table("fred".to_string()).await; } } #[cfg(test)] mod fieldtypes { use super::*; fn get_field_map() -> HashMap { let mut fields: HashMap = HashMap::new(); fields.insert("table".to_string(), FieldType::Table); return fields; } #[test] fn convert_to_string() { for (key, value) in get_field_map().iter() { assert!( key == &value.to_string(), "\n\nGot: {}\nWant: {}\n\n", value.to_string(), key ); } } #[test] fn convert_from_string() { for (key, value) in get_field_map().iter() { assert!( &FieldType::from_str(key).unwrap() == value, "\n\nDid not return a FieldType::{}", key ); } } #[test] fn convert_from_string_error() -> Result<(), String> { let ftype = "lkjsdfh"; let expected = format!("field type {} does not exist", ftype); match FieldType::from_str(ftype) { Ok(_) => Err(format!("Found field type {}", ftype)), Err(err) => { if format!("{}", err) == expected { Ok(()) } else { Err(format!("Got: '{}' - Want: '{}'", err, expected)) } } } } } */