Added fields to table.
This commit is contained in:
		@@ -1,31 +1,62 @@
 | 
			
		||||
use async_std::sync::{Arc, RwLock};
 | 
			
		||||
use std::{collections::HashMap, fmt, str::FromStr};
 | 
			
		||||
use std::{collections::HashMap, error::Error, fmt, str::FromStr};
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, PartialEq)]
 | 
			
		||||
pub enum Field {
 | 
			
		||||
    Table,
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct DBError {
 | 
			
		||||
    detail: String,
 | 
			
		||||
    source: Option<Box<DBError>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for Field {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            Field::Table => write!(f, "table"),
 | 
			
		||||
impl DBError {
 | 
			
		||||
    fn new(detail: String) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            detail: detail.to_string(),
 | 
			
		||||
            source: None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl FromStr for Field {
 | 
			
		||||
    type Err = ();
 | 
			
		||||
    fn from_str(input: &str) -> Result<Field, Self::Err> {
 | 
			
		||||
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<FieldType, Self::Err> {
 | 
			
		||||
        match input {
 | 
			
		||||
            "table" => Ok(Field::Table),
 | 
			
		||||
            _ => Err(()),
 | 
			
		||||
            "table" => Ok(FieldType::Table),
 | 
			
		||||
            _ => Err(DBError::new(format!("field type {} does not exist", input))),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Table {
 | 
			
		||||
    fields: Arc<RwLock<HashMap<String, Field>>>,
 | 
			
		||||
    fields: Arc<RwLock<HashMap<String, FieldType>>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Table {
 | 
			
		||||
@@ -35,12 +66,29 @@ impl Table {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn add_field(&self, name: &str, ftype: &str) {
 | 
			
		||||
    pub async fn add_field(&self, name: &str, ftype: &str) -> Result<(), Box<dyn Error>> {
 | 
			
		||||
        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;
 | 
			
		||||
        fmap.insert(name.to_string(), Field::from_str(ftype).unwrap());
 | 
			
		||||
        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<String, Field> {
 | 
			
		||||
    pub async fn fields(&self) -> HashMap<String, FieldType> {
 | 
			
		||||
        let fmap = self.fields.read().await;
 | 
			
		||||
        fmap.clone()
 | 
			
		||||
    }
 | 
			
		||||
@@ -70,14 +118,57 @@ mod tables {
 | 
			
		||||
    #[async_std::test]
 | 
			
		||||
    async fn add_field() {
 | 
			
		||||
        let table = Table::new().await;
 | 
			
		||||
        let mut expected: HashMap<String, Field> =  HashMap::new();
 | 
			
		||||
        expected.insert("stan".to_string(), Field::Table);
 | 
			
		||||
        expected.insert("lee".to_string(), Field::Table);
 | 
			
		||||
        table.add_field("stan", "table").await;
 | 
			
		||||
        table.add_field("lee", "table").await;
 | 
			
		||||
        let mut expected: HashMap<String, FieldType> = HashMap::new();
 | 
			
		||||
        expected.insert("stan".to_string(), FieldType::Table);
 | 
			
		||||
        expected.insert("lee".to_string(), FieldType::Table);
 | 
			
		||||
        table.add_field("stan", "table").await.unwrap();
 | 
			
		||||
        table.add_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.add_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.add_field(name, "table").await.unwrap();
 | 
			
		||||
        match table.add_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)]
 | 
			
		||||
@@ -97,34 +188,51 @@ mod databases {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod fields {
 | 
			
		||||
mod fieldtypes {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    fn get_field_map() -> HashMap<String, Field> {
 | 
			
		||||
        let mut fields: HashMap<String, Field> = HashMap::new();
 | 
			
		||||
        fields.insert("table".to_string(), Field::Table);
 | 
			
		||||
    fn get_field_map() -> HashMap<String, FieldType> {
 | 
			
		||||
        let mut fields: HashMap<String, FieldType> = 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);
 | 
			
		||||
            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!(&Field::from_str(key).unwrap() == value, "\n\nDid not return a Field::{}", key);
 | 
			
		||||
            assert!(
 | 
			
		||||
                &FieldType::from_str(key).unwrap() == value,
 | 
			
		||||
                "\n\nDid not return a FieldType::{}",
 | 
			
		||||
                key
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn convert_from_string_error() -> Result<(), String> {
 | 
			
		||||
        match Field::from_str("jkljkl") {
 | 
			
		||||
            Ok(_) => Err("Field jkljkl should not exist.".to_string()),
 | 
			
		||||
            Err(_) => Ok(()),
 | 
			
		||||
        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))
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user