Advertisement
Guest User

First Rust Console Application

a guest
Mar 1st, 2020
553
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 31.59 KB | None | 0 0
  1.    
  2.     ///Module holding all the structs, enumerations,...
  3.     pub mod domain {
  4.        
  5.         use std::string::ToString;
  6.         use serde::{Serialize, Deserialize};
  7.  
  8.         #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
  9.         ///Represents a cat
  10.         pub struct Cat {
  11.             pub name: String,
  12.             pub age: u8,
  13.             pub color: CatColor,
  14.             pub race: CatRace,
  15.         }
  16.         impl Cat {
  17.             ///Constructor to intialize a new cat
  18.             pub fn new(name: String, age: u8, color: CatColor, race: CatRace) -> Cat {
  19.                 Cat {
  20.                     name: name,
  21.                     age: age,
  22.                     color: color,
  23.                     race: race,
  24.                 }
  25.             }
  26.  
  27.             ///Returns the info of the cat in a String
  28.             pub fn to_string(&self) -> String {
  29.                 let s = format!("Name: {name}\nAge: {age}\nColor: {color}\nRace: {race}",
  30.                         name = self.name,
  31.                         age = self.age,
  32.                         color = self.color.to_string(),
  33.                         race = self.race.to_string(),
  34.                     );
  35.  
  36.                 s
  37.             }
  38.         }
  39.  
  40.         #[derive(Display, Serialize, Deserialize, Debug, Clone, EnumString, PartialEq)]
  41.         ///Enumeration of all the possible colors a cat can have
  42.         pub enum CatColor {
  43.             Black,
  44.             White,
  45.             Orange,
  46.             Gray,
  47.         }
  48.         impl CatColor {
  49.             pub fn from_u8(value: u8) -> CatColor {
  50.                 match value {
  51.                     1 => CatColor::Black,
  52.                     2 => CatColor::White,
  53.                     3 => CatColor::Orange,
  54.                     4 => CatColor::Gray,
  55.                     _ => {
  56.                         eprintln!("Invalid CatColor selected!");
  57.                         std::process::exit(0);
  58.                     }
  59.                 }
  60.             }
  61.            
  62.         }
  63.  
  64.         #[derive(Display, Serialize, Deserialize, Debug, Clone, EnumString, PartialEq)]
  65.         ///Enumeration of all the possible races a cat can have
  66.         pub enum CatRace {
  67.             Streetcat,
  68.             AmericanShorthair,
  69.             BritishShorthair,
  70.             Bengal,
  71.             EgyptianMau,
  72.         }
  73.         impl CatRace {
  74.             pub fn from_u8(value: u8) -> CatRace {
  75.                 match value {
  76.                     1 => CatRace::Streetcat,
  77.                     2 => CatRace::AmericanShorthair,
  78.                     3 => CatRace::BritishShorthair,
  79.                     4 => CatRace::Bengal,
  80.                     5 => CatRace::EgyptianMau,
  81.                     _ => {
  82.                         eprintln!("Invalid CatRace selected!");
  83.                         std::process::exit(0);
  84.                     }
  85.                 }
  86.             }
  87.         }
  88.     }
  89.  
  90.     //Module holding functions necessary for the userinterface
  91.     pub mod user_interface {
  92.  
  93.         pub mod display {
  94.             use std::io;
  95.            
  96.             ///Function to display the start menu
  97.             pub fn display_start_menu() {
  98.                 println!("Welcome to the cat database!");
  99.                 println!("1) Add cat");
  100.                 println!("2) View all cats");
  101.                 println!("3) View one cat");
  102.                 println!("4) Delete one cat");
  103.             }
  104.  
  105.             ///Function to display add-cat-menu
  106.             pub fn display_add_cat_menu() {
  107.                 println!("Give all the info about the cat!");
  108.             }
  109.  
  110.             ///Function to display view-all-cats-menu
  111.             pub fn display_view_all_cats_menu() {
  112.                 println!("List of all the cats:");
  113.             }
  114.  
  115.             ///Function to display view-one-cat-menu
  116.             pub fn display_view_one_cat_menu() {
  117.                 println!("Reading a cat...");
  118.             }
  119.  
  120.             ///Function to display delete-one-cat-menu
  121.             pub fn display_delete_one_cat_menu() {
  122.                 println!("Deleting a cat...");
  123.             }
  124.  
  125.             ///Function to flush std output
  126.             pub fn flush() {
  127.                 io::Write::flush(&mut io::stdout()).expect("Flush failed...");
  128.             }
  129.         }
  130.  
  131.         pub mod input {
  132.             use std::io;
  133.             use std::io::stdin;
  134.             use std::str::FromStr;
  135.  
  136.             ///Function to get user input
  137.             pub fn get<T: FromStr>() -> T {
  138.                 print!(">");
  139.                 //Flush display
  140.                 io::Write::flush(&mut io::stdout()).expect("Flush failed...");
  141.  
  142.                 //Get input and put it in mutable string
  143.                 let mut input = String::new();
  144.                 stdin()
  145.                     .read_line(&mut input)
  146.                     .expect("No valid input given...");
  147.        
  148.                 match input.trim().parse() {
  149.                     Ok(i) => i,
  150.                     Err(..) => {
  151.                         eprintln!("Corrupted input '{}' given!", input);
  152.                         std::process::exit(0);
  153.                     }
  154.                 }
  155.             }
  156.         }
  157.     }
  158.  
  159.     //Module to access, read, and write data
  160.     pub mod data_layer {
  161.         use std::vec::Vec;
  162.         use crate::domain::*;
  163.  
  164.         /// Trait to generalize the different type of data management options
  165.         pub trait DataManager {
  166.             /// Add to the database
  167.             ///
  168.             /// #Arguments
  169.             ///
  170.             /// * 'cat' - A Cat object
  171.             fn add(&mut self, cat: Cat) -> bool;
  172.  
  173.             /// Read from the database
  174.             fn read(&mut self) -> &Vec<Cat>;
  175.  
  176.             /// Delete specific cat from the database
  177.             ///
  178.             /// #Arguments
  179.             ///
  180.             /// * 'name' - Name of the cat to delete
  181.             fn delete(&mut self, name : &String) -> bool;
  182.  
  183.             /// Read specific cat from the database
  184.             ///
  185.             /// #Arguments
  186.             ///
  187.             /// * 'name' - Name of the cat to retrieve
  188.             fn get(&mut self, name : &String) -> Option<&Cat>;
  189.         }
  190.  
  191.         //To manage data in memory
  192.         pub struct MemoryData {
  193.             cats: Vec<Cat>,
  194.         }
  195.         impl MemoryData {
  196.             pub fn new() -> MemoryData {
  197.                 MemoryData { cats: Vec::new() }
  198.             }
  199.         }
  200.         impl DataManager for MemoryData {
  201.             fn add(&mut self, cat: Cat) -> bool {
  202.                 self.cats.push(cat);
  203.                 true
  204.             }
  205.             fn read(&mut self) -> &Vec<Cat> {
  206.                 &self.cats
  207.             }
  208.             fn delete(&mut self, name : &String) -> bool {
  209.                 let length_before_deletion : usize = self.cats.len();
  210.                 self.cats.retain(|cat| &cat.name != name);
  211.                
  212.                 length_before_deletion > self.cats.len()
  213.             }
  214.             fn get(&mut self, name : &String) -> Option<&Cat> {
  215.                 self.cats.iter().find(|cat| &cat.name == name)
  216.             }
  217.         }
  218.  
  219.         use std::fs::File;
  220.         use std::fs::OpenOptions;
  221.         use std::io::prelude::*;
  222.         use std::io::SeekFrom;
  223.         use std::error::Error;
  224.         //To manage data in file
  225.         pub struct FileData {
  226.             path: String,
  227.             file: File,
  228.             cats: Vec<Cat>,
  229.         }
  230.         impl FileData {
  231.             pub fn new(file_name : String) -> FileData {
  232.                 let path : String = format!("data/{}", file_name);
  233.  
  234.                 FileData {
  235.                     path: path.to_string(),
  236.                     file: FileData::init_file(&path),
  237.                     cats: Vec::new(),
  238.                 }
  239.             }
  240.            
  241.             fn init_file(path : &String) -> File {
  242.                 OpenOptions::new()
  243.                     .create(true)
  244.                     .append(true)
  245.                     .read(true)
  246.                     .open(path)
  247.                     .unwrap()
  248.             }
  249.  
  250.             pub fn empty_file(file : &mut File) {
  251.                 file.set_len(0).expect("Failed to empty file...");
  252.                 file.seek(SeekFrom::Start(0)).expect("Failed to empty file...");
  253.             }
  254.         }
  255.         impl DataManager for FileData {
  256.             //Add cat-data to file
  257.             fn add (&mut self, cat: Cat) -> bool {
  258.                 //Serialize to JSON String using Serde
  259.                 let mut json : String = serde_json::to_string(&cat).unwrap();
  260.                 if self.read().len() > 0 {
  261.                     json = format!(",{}", json);
  262.                 }
  263.  
  264.                 match self.file.write_all(json.as_bytes()) {
  265.                     Err(err) => {
  266.                         eprintln!("Couldn't write to file '{}:' {}!", self.path, err.description());
  267.                         false
  268.                     }
  269.                     Ok(_) => {
  270.                         println!("Succesfully saved data of cat '{}' in {}...", cat.name, self.path);
  271.  
  272.                         //Re-intializing file to keep data up-to-date while program is running
  273.                         self.file = FileData::init_file(&self.path);
  274.                         true
  275.                     }
  276.                 }
  277.             }
  278.  
  279.             //Read all cats saved in file
  280.             fn read(&mut self) -> &Vec<Cat> {
  281.                 let mut json : String = String::new();
  282.                 self.file.read_to_string(&mut json).expect("Failed to read file...");
  283.  
  284.                 //Re-intialize file to keep data up-to-date while program is running
  285.                 self.file = FileData::init_file(&self.path);
  286.  
  287.                 json = format!("[{}]", json);
  288.                
  289.                 self.cats = serde_json::from_str(&json).unwrap();
  290.                 &self.cats
  291.             }
  292.  
  293.             //Delete a specific cat in file
  294.             fn delete(&mut self, name: &String) -> bool {
  295.                 //Read all cats in a vector except cat matching specified name
  296.                 let mut cats_temp : Vec<Cat> = self.read().to_vec();
  297.                 let length_before_deleting : usize = cats_temp.len();
  298.                 cats_temp.retain(|cat| &cat.name != name);
  299.  
  300.                 //Empty the file
  301.                 FileData::empty_file(&mut self.file);
  302.  
  303.                 //Read all cats from vector back to file using our add-method
  304.                 for cat in cats_temp {
  305.                     self.add(cat);
  306.                 }
  307.  
  308.                 self.cats = self.read().to_vec();
  309.  
  310.                 length_before_deleting > self.cats.len()
  311.             }
  312.  
  313.             //Get the cat with the matching name
  314.             fn get(&mut self, name : &String) -> Option<&Cat> {
  315.                 self.read().iter().find(|cat| &cat.name == name)
  316.             }
  317.         }
  318.  
  319.         //To manage data in MySql-Database
  320.         pub struct MySQLData {
  321.             conn : mysql::Pool,
  322.             cats: Vec<Cat>,
  323.         }
  324.         impl MySQLData {
  325.             /// Use this function to intialize a MySQLData object and initialize a database connection
  326.             /// with it
  327.             ///
  328.             /// #Arguments
  329.             ///
  330.             /// * 'database_name' - Name of the database to connect to
  331.             /// * 'database_user' - Username to use for authentication
  332.             /// * 'database_pass' - Password to use for authentication
  333.             ///
  334.             /// #Example
  335.             ///
  336.             /// ```
  337.             /// let ref mut db = data_layer::MySQLData::new(&String::from("myDatabase"), &String::from("user"), &String::from("pass"));
  338.             /// ```
  339.             pub fn new(database_name : &String, database_user : &String, database_pass : &String) -> MySQLData {
  340.                 let mut mysql = MySQLData {
  341.                     conn: MySQLData::init_connection(&String::from(database_name), &String::from(database_user), &String::from(database_pass)).unwrap(),
  342.                     cats: std::vec::Vec::<Cat>::new(),
  343.                 };
  344.  
  345.                 mysql.init_tables();
  346.                 mysql
  347.            
  348.             }
  349.            
  350.             /// Function to establish (a pooled) connection with the MySQL database. This connection
  351.             /// is stored in self.conn
  352.             ///
  353.             /// # Arguments
  354.             ///
  355.             /// * 'database_name' - Name of the database to connect to
  356.             /// * 'database_user' - Username to use for authentication
  357.             /// * 'database_pass' - Password to use for authentication
  358.             pub fn init_connection(database_name : &String, database_user : &String, database_pass : &String) -> std::result::Result<mysql::Pool, mysql::Error> {
  359.                 //Create connection with database
  360.                 let conn_str : String = format!("mysql://{user}:{pass}@localhost/{name}", user=database_user, pass=database_pass, name=database_name);
  361.                 let conn : std::result::Result<mysql::Pool, mysql::Error> = mysql::Pool::new(conn_str);
  362.  
  363.                 //Check if connection was succesful
  364.                 match conn {
  365.                     Ok(_) => {
  366.                         println!("Connection to {} succesfully made...", database_name);
  367.                         conn
  368.                     },
  369.                     Err(e) => {
  370.                         eprintln!("Connection to {} failed: {}", database_name, e.description());
  371.                         std::process::exit(-1);
  372.                     },
  373.                 }
  374.             }
  375.  
  376.             /// Function to create tables needed for this application if they
  377.             /// don't already exist
  378.             pub fn init_tables(&mut self) {
  379.                 //Create tables if they don't exist
  380.                 //Table holding all the cat-races we know
  381.                 self.conn.prep_exec(
  382.                     "CREATE TABLE IF NOT EXISTS races (
  383.                    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  384.                    race_name varchar(256) NOT NULL
  385.                )", ()).expect("Failed to create races table...");
  386.  
  387.                 //Table holding all the colours our cats have
  388.                 self.conn.prep_exec("
  389.                    CREATE TABLE IF NOT EXISTS colors (
  390.                    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  391.                    color_name varchar(256) NOT NULL
  392.                )", ()).expect("Failed to create colors table...");
  393.                
  394.                 //Table holding all the info about the cats
  395.                 self.conn.prep_exec(
  396.                     "CREATE TABLE IF NOT EXISTS cats (
  397.                    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  398.                    name VARCHAR(256) NOT NULL,
  399.                    age INT,
  400.                    color_id INT,
  401.                    race_id INT,
  402.                    FOREIGN KEY (color_id) REFERENCES colors(id),
  403.                    FOREIGN KEY (race_id) REFERENCES races(id)
  404.                )", ()).expect("Failed to create cats table...");
  405.             }
  406.  
  407.             /// Fill database with some dummy data
  408.             fn seed(&mut self) {
  409.                 let seed_a : Cat = Cat {
  410.                     name: "Cat A".to_string(),
  411.                     age: 4,
  412.                     race: CatRace::Streetcat,
  413.                     color: CatColor::Black,
  414.                 };
  415.                 let seed_b : Cat = Cat {
  416.                     name: "Cat B".to_string(),
  417.                     age: 1,
  418.                     race: CatRace::AmericanShorthair,
  419.                     color: CatColor::Orange,
  420.                 };
  421.                 let seed_c : Cat = Cat {
  422.                     name: "Cat C".to_string(),
  423.                     age: 1,
  424.                     race: CatRace::Bengal,
  425.                     color: CatColor::Gray,
  426.                 };
  427.  
  428.                 self.add(seed_a);
  429.                 self.add(seed_b);
  430.                 self.add(seed_c);
  431.             }
  432.         }
  433.  
  434.         impl DataManager for MySQLData {
  435.             fn add(&mut self, cat : Cat) -> bool {
  436.                 //Check if race of cat is already known in database
  437.                 let selected_race_rows : std::vec::Vec<std::result::Result<mysql::Row, mysql::Error>> =
  438.                     self.conn.prep_exec("SELECT id FROM races WHERE race_name = :race_name", params!("race_name" => cat.race.to_string())).unwrap().collect();
  439.  
  440.                 let mut results : std::vec::Vec<u16> = std::vec::Vec::new();
  441.                 for row in selected_race_rows {
  442.                     results.push(row.unwrap().take("id").unwrap());
  443.                 }
  444.  
  445.                 let race_id : u64;
  446.                 if results.len() == 0 {
  447.                     //Race not yet known in database, so add that first
  448.                     race_id = self.conn.prep_exec("INSERT INTO races (race_name) VALUES (:race_name)", params!("race_name" => cat.race.to_string())).unwrap().last_insert_id();
  449.                 } else {
  450.                     race_id = results[0].into();
  451.                 }
  452.  
  453.  
  454.                 //Check if color of cat is already known in database
  455.                 let selected_color_rows : std::vec::Vec<std::result::Result<mysql::Row, mysql::Error>> =
  456.                     self.conn.prep_exec("SELECT id from colors WHERE color_name = :color_name", params!("color_name" => cat.color.to_string())).unwrap().collect();
  457.  
  458.                 results = std::vec::Vec::new();
  459.                 for row in selected_color_rows {
  460.                     results.push(row.unwrap().take("id").unwrap());
  461.                 }
  462.  
  463.                 let color_id : u64;
  464.                 if results.len() == 0 {
  465.                     //Color not yet known in database, so add that first
  466.                     color_id = self.conn.prep_exec("INSERT INTO colors (color_name) VALUES (:color_name)", params!("color_name" => cat.color.to_string())).unwrap().last_insert_id();
  467.                 } else {
  468.                     color_id = results[0].into();
  469.                 }
  470.  
  471.                 //Add the cat now
  472.                 let add_query = self.conn.prep_exec("INSERT INTO cats (name, age, color_id, race_id) VALUES (:name, :age, :color_id, :race_id)", params!(
  473.                             "name" => &cat.name,
  474.                             "age" => cat.age,
  475.                             "color_id" => color_id,
  476.                             "race_id" => race_id,
  477.                         ));
  478.  
  479.                 match add_query {
  480.                     Ok(_) => {
  481.                         true
  482.                     },
  483.                     Err(e) => {
  484.                         eprintln!("Error occured while inserting cat in MySQL database: {}", e.description());
  485.                         false
  486.                     },
  487.                 }
  488.  
  489.             }
  490.  
  491.             fn read(&mut self) -> &std::vec::Vec<Cat> {
  492.                 self.cats = std::vec::Vec::new();
  493.  
  494.                 let selected_cat_rows : std::vec::Vec<std::result::Result<mysql::Row, mysql::Error>> =
  495.                     self.conn.prep_exec("SELECT name, age, color_id, race_id FROM cats", ()).unwrap().collect();
  496.  
  497.                 for row in &selected_cat_rows {
  498.                     //Retrieve color name from color-table by color_id
  499.                     let color_id : u64 = row.as_ref().unwrap().get("color_id").unwrap();
  500.                     let mut color : std::vec::Vec<String> = std::vec::Vec::<String>::new();
  501.                     let color_rows : std::vec::Vec<std::result::Result<mysql::Row, mysql::Error>> = self.conn.prep_exec("SELECT color_name FROM colors WHERE id = :color_id", params!("color_id" => color_id)).unwrap().collect();
  502.                     for subrow in &color_rows {
  503.                         color.push(subrow.as_ref().unwrap().get("color_name").unwrap());
  504.                     }
  505.  
  506.                     //Retrieve race name from race-table by race_id
  507.                     let race_id : u64 = row.as_ref().unwrap().get("race_id").unwrap();
  508.                     let mut race : std::vec::Vec<String> = std::vec::Vec::<String>::new();
  509.                     let race_rows : std::vec::Vec<std::result::Result<mysql::Row, mysql::Error>> = self.conn.prep_exec("SELECT race_name FROM races WHERE id = :race_id", params!("race_id" => race_id)).unwrap().collect();
  510.                     for subrow in &race_rows {
  511.                         race.push(subrow.as_ref().unwrap().get("race_name").unwrap());
  512.                     }
  513.  
  514.                     let cat : Cat = Cat {
  515.                         name: row.as_ref().unwrap().get("name").unwrap(),
  516.                         age: row.as_ref().unwrap().get("age").unwrap(),
  517.                         color: color[0].parse().unwrap(),
  518.                         race: race[0].parse().unwrap(),
  519.                     };
  520.  
  521.                     self.cats.push(cat);
  522.                 }
  523.  
  524.                 &self.cats
  525.             }
  526.             fn delete(&mut self, name : &String) -> bool {
  527.                 let delete_query = self.conn.prep_exec("DELETE FROM cats WHERE name = :name",
  528.                     params!("name" => name));
  529.  
  530.                 match delete_query {
  531.                     Ok(_) => {
  532.                         true
  533.                     },
  534.                     Err(e) => {
  535.                         eprintln!("Failed to delete cat {} from database: {}", name, e.description());
  536.                         false
  537.                     }
  538.                 }
  539.             }
  540.             fn get(&mut self, name : &String) -> Option<&Cat> {
  541.                 self.cats = std::vec::Vec::new();
  542.  
  543.                 let selected_cat_rows : std::vec::Vec<std::result::Result<mysql::Row, mysql::Error>> =
  544.                     self.conn.prep_exec("SELECT name, age, color_id, race_id FROM cats WHERE name = :name", params!("name" => name)).unwrap().collect();
  545.  
  546.                 for row in &selected_cat_rows {
  547.                     //Retrieve color name from color-table by color_id
  548.                     let color_id : u64 = row.as_ref().unwrap().get("color_id").unwrap();
  549.                     let mut color : std::vec::Vec<String> = std::vec::Vec::<String>::new();
  550.                     let color_rows : std::vec::Vec<std::result::Result<mysql::Row, mysql::Error>> = self.conn.prep_exec("SELECT color_name FROM colors WHERE id = :color_id", params!("color_id" => color_id)).unwrap().collect();
  551.                     for subrow in &color_rows {
  552.                         color.push(subrow.as_ref().unwrap().get("color_name").unwrap());
  553.                     }
  554.  
  555.                     //Retrieve race name from race-table by race_id
  556.                     let race_id : u64 = row.as_ref().unwrap().get("race_id").unwrap();
  557.                     let mut race : std::vec::Vec<String> = std::vec::Vec::<String>::new();
  558.                     let race_rows : std::vec::Vec<std::result::Result<mysql::Row, mysql::Error>> = self.conn.prep_exec("SELECT race_name FROM races WHERE id = :race_id", params!("race_id" => race_id)).unwrap().collect();
  559.                     for subrow in &race_rows {
  560.                         race.push(subrow.as_ref().unwrap().get("race_name").unwrap());
  561.                     }
  562.  
  563.                     let cat : Cat = Cat {
  564.                         name: row.as_ref().unwrap().get("name").unwrap(),
  565.                         age: row.as_ref().unwrap().get("age").unwrap(),
  566.                         color: color[0].parse().unwrap(),
  567.                         race: race[0].parse().unwrap(),
  568.                     };
  569.  
  570.                     self.cats.push(cat);
  571.                 }
  572.  
  573.                 Some(&self.cats[0])
  574.             }
  575.         }
  576.     }
  577.  
  578.     //Module holding logic and binding everything together
  579.     pub mod app {
  580.         use crate::user_interface;
  581.         use crate::data_layer;
  582.         use crate::domain::*;
  583.  
  584.         //Run the application
  585.         pub fn run<D: data_layer::DataManager>(db: &mut D) {
  586.             user_interface::display::display_start_menu();
  587.             let option: u8 = user_interface::input::get();
  588.             execute_option(option, db);
  589.         }
  590.  
  591.         //Execute the selected option with corresponding function
  592.         pub fn execute_option<D: data_layer::DataManager>(option: u8, db: &mut D) {
  593.             match option {
  594.                 1 => {
  595.                    add_cat(db);
  596.                 }
  597.                 2 => {
  598.                     view_all_cats(db);
  599.                 }
  600.                 3 => {
  601.                     view_one_cat(db);
  602.                 }
  603.                 4 => {
  604.                     delete_one_cat(db);
  605.                 }
  606.                 _ => {
  607.                     eprintln!("Invalid option '{}' selected...", option);
  608.                 }
  609.             }
  610.  
  611.             println!("\n");
  612.         }
  613.  
  614.         //Function to add a cat
  615.         pub fn add_cat<D: data_layer::DataManager>(db: &mut D) {
  616.             //Displaying menu header
  617.             user_interface::display::display_add_cat_menu();
  618.  
  619.             //Getting al the info
  620.             println!("Name:");
  621.             let name: String = user_interface::input::get();
  622.  
  623.             println!("Age:");
  624.             let age: u8 = user_interface::input::get();
  625.  
  626.             println!("Color:\n1) Black 2) White 3) Orange 4) Gray");
  627.             let color: CatColor = CatColor::from_u8(user_interface::input::get());
  628.            
  629.             println!("Race:\n1) Streetcat 2) American Shorthair 3) British Shorthair 4) Bengal 5) Egyptian Mau");
  630.             let race: CatRace = CatRace::from_u8(user_interface::input::get());
  631.  
  632.             //Create cat object
  633.             let cat: Cat = Cat::new(name, age, color, race);
  634.  
  635.             //Save cat object
  636.             db.add(cat);
  637.  
  638.             println!("Cat added...");
  639.         }
  640.  
  641.         //Function to view all cats
  642.         pub fn view_all_cats<D: data_layer::DataManager>(db: &mut D) {
  643.             //Displaying menu header
  644.             user_interface::display::display_view_all_cats_menu();
  645.             //user_interface::display::flush();
  646.             std::io::Write::flush(&mut std::io::stdout()).expect("Flush failed...");
  647.  
  648.             //Reading, iterating over, and outputting all the cats
  649.             for cat in db.read() {
  650.                 println!("{}\n", cat.to_string());
  651.             }
  652.  
  653.         }
  654.  
  655.         //Function to view one specific cat
  656.         pub fn view_one_cat<D: data_layer::DataManager>(db: &mut D) {
  657.             //Displaying menu header
  658.             user_interface::display::display_view_one_cat_menu();
  659.             std::io::Write::flush(&mut std::io::stdout()).expect("Flush failed...");
  660.  
  661.             //Get name of cat user wants to read
  662.             println!("Give name of the cat:");
  663.             let name : String = user_interface::input::get();
  664.  
  665.             //Get the cat out of data
  666.             let cat : &Cat = db.get(&name).unwrap();
  667.  
  668.             //Output cat info
  669.             println!("{}\n", cat.to_string());
  670.         }
  671.  
  672.         //Function to delete one specific cat
  673.         pub fn delete_one_cat<D: data_layer::DataManager>(db: &mut D) {
  674.             //Displaying menu header
  675.             user_interface::display::display_delete_one_cat_menu();
  676.             std::io::Write::flush(&mut std::io::stdout()).expect("Flush failed...");
  677.  
  678.             //Get name of the cat user wants to delete
  679.             println!("Give name of the cat:");
  680.             let name : String = user_interface::input::get();
  681.  
  682.             //Delete the cat
  683.             match db.delete(&name) {
  684.                 true => {
  685.                     println!("{} succesfully deleted!", name);
  686.                 },
  687.                 false => {
  688.                     eprintln!("Error deleting {}!", name);
  689.                 },
  690.             }
  691.         }
  692.     }
  693.  
  694.     //Unit tests
  695.     #[cfg(test)]
  696.     mod tests {
  697.         use super::*;
  698.         use super::domain::*;
  699.         use super::data_layer::DataManager;
  700.  
  701.         fn get_cat_for_test(cat_letter : String) -> Cat {
  702.             //Cat objects to perform tests with
  703.             let cat_a : Cat = Cat::new("Mr. Cat A".to_string(), 1, CatColor::Black, CatRace::Streetcat);
  704.             let cat_b : Cat = Cat::new("Mr. Cat B".to_string(), 5, CatColor::Orange, CatRace::EgyptianMau);
  705.             let cat_c : Cat = Cat::new("Mr. Cat C".to_string(), 7, CatColor::Gray, CatRace::BritishShorthair);
  706.            
  707.             match cat_letter.as_str() {
  708.                 "A" => cat_a,
  709.                 "B" => cat_b,
  710.                 "C" => cat_c,
  711.                 _ => cat_a,
  712.             }
  713.         }
  714.  
  715.         //Testing memory data module
  716.         #[test]
  717.         fn test_memory_data() {
  718.  
  719.             let ref mut mem = data_layer::MemoryData::new();
  720.            
  721.             //Adding cat_a
  722.             assert!(mem.add(get_cat_for_test("A".to_string())));
  723.             assert_eq!(*mem.get(&String::from("Mr. Cat A")).unwrap(), get_cat_for_test("A".to_string()));
  724.             assert_ne!(*mem.get(&String::from("Mr. Cat A")).unwrap(), get_cat_for_test("B".to_string()));
  725.  
  726.             //Adding another one
  727.             assert!(mem.add(get_cat_for_test("B".to_string())));
  728.             assert_eq!(mem.read().len(), 2);
  729.  
  730.             //Deleting one
  731.             assert!(mem.delete(&String::from("Mr. Cat A")));
  732.             assert_eq!(mem.read().len(), 1);
  733.            
  734.             assert_eq!(mem.delete(&String::from("Random String")), false);
  735.             assert_eq!(mem.read().len(), 1);
  736.  
  737.             assert_eq!(mem.read()[0], get_cat_for_test("B".to_string()));
  738.         }
  739.        
  740.         //Testing file data module
  741.         #[test]
  742.         fn test_file_data() {
  743.             let ref mut file = data_layer::FileData::new("cat_test_database.txt".to_string());
  744.            
  745.             //Adding cat_a
  746.             assert!(file.add(get_cat_for_test("A".to_string())));
  747.             assert_eq!(*file.get(&String::from("Mr. Cat A")).unwrap(), get_cat_for_test("A".to_string()));
  748.             assert_ne!(*file.get(&String::from("Mr. Cat A")).unwrap(), get_cat_for_test("B".to_string()));
  749.  
  750.             //Adding another one
  751.             assert!(file.add(get_cat_for_test("B".to_string())));
  752.             assert_eq!(file.read().len(), 2);
  753.  
  754.             //Deleting one
  755.             assert!(file.delete(&String::from("Mr. Cat A")));
  756.             assert_eq!(file.read().len(), 1);
  757.            
  758.             assert_eq!(file.delete(&String::from("Random String")), false);
  759.             assert_eq!(file.read().len(), 1);
  760.  
  761.             assert_eq!(file.read()[0], get_cat_for_test("B".to_string()));
  762.         }
  763.        
  764.         //Testing file data module
  765.         #[test]
  766.         fn test_mysql_data() {
  767.             let ref mut mysql = data_layer::MySQLData::new(&String::from("catdatabase_test"), &String::from("root"), &String::from("toor"));
  768.            
  769.             //Adding cat_a
  770.             assert!(mysql.add(get_cat_for_test("A".to_string())));
  771.             assert_eq!(*mysql.get(&String::from("Mr. Cat A")).unwrap(), get_cat_for_test("A".to_string()));
  772.             assert_ne!(*mysql.get(&String::from("Mr. Cat A")).unwrap(), get_cat_for_test("B".to_string()));
  773.  
  774.             //Adding another one
  775.             assert!(mysql.add(get_cat_for_test("B".to_string())));
  776.             assert_eq!(mysql.read().len(), 2);
  777.  
  778.             //Deleting one
  779.             assert!(mysql.delete(&String::from("Mr. Cat A")));
  780.             assert_eq!(mysql.read().len(), 1);
  781.            
  782.             assert_eq!(mysql.delete(&String::from("Random String")), false);
  783.             assert_eq!(mysql.read().len(), 1);
  784.  
  785.             assert_eq!(mysql.read()[0], get_cat_for_test("B".to_string()));
  786.         }
  787.        
  788.     }
  789.  
  790.     //Crates
  791.     extern crate strum;
  792.     #[macro_use]
  793.     extern crate strum_macros;
  794.     extern crate serde;
  795.     extern crate serde_json;
  796.  
  797.     #[macro_use]
  798.     extern crate mysql;
  799.  
  800.     fn main() {
  801.         //Initialize database
  802.         //let ref mut db = data_layer::MySQLData::new(&String::from("catdatabase"), &String::from("root"), &String::from("toor"));
  803.         //let ref mut db = data_layer::FileData::new("catdatabase.txt".to_string());
  804.  
  805.         let ref mut db = data_layer::MemoryData::new();
  806.  
  807.         loop {
  808.             app::run(db);
  809.         }
  810.     }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement