about summary refs log blame commit diff stats
path: root/src/db.rs
blob: 20ad5a199d622de965813f55248ff91f8bb1c61b (plain) (tree)
1
2
3
4
5
6
7
8
9




                                    
 
                
                 
 




                                                       
 
                                               
                 


                       

 

                                        
                     

 
                
                 
                                    

 
           
                                     
                         
                                              

         
                                                                                
 




                                    
 

                                        
                         
                                              
         
 





                                                                                                    

     



                                                     

                                         
























                                                   
     



                                      
 



                 
                    

           

                                           
                                       
 



                                                                               


































                                                  

     
use fd_lock::FdLock;
use serde::{Deserialize, Serialize};

use std::fs;
use std::fs::File;

use crate::conf;
use crate::error;

#[cfg(test)]
pub const PATH: &str = "clinte.json";

#[cfg(not(test))]
pub const PATH: &str = "/usr/local/clinte/clinte.json";

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Post {
    pub title: String,
    pub author: String,
    pub body: String,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Posts {
    posts: Vec<Post>,
}

#[derive(Debug)]
pub struct Conn {
    pub conn: FdLock<std::fs::File>,
}

impl Conn {
    pub fn init(path: &str) -> Self {
        if *conf::DEBUG {
            log::info!("Opening clinte.json");
        }

        let file = error::helper(File::open(path), "Couldn't open clinte.json");

        Self {
            conn: FdLock::new(file),
        }
    }
}

impl Posts {
    pub fn get_all(path: &str) -> Self {
        if *conf::DEBUG {
            log::info!("Retrieving posts...");
        }

        let mut db = Conn::init(path);
        let _guard = error::helper(db.conn.try_lock(), "Couldn't acquire lock on clinte.json");
        let strdata = error::helper(fs::read_to_string(PATH), "Couldn't read clinte.json");
        let out: Self = error::helper(serde_json::from_str(&strdata), "Couldn't parse clinte.json");

        out
    }

    pub fn replace(&mut self, n: usize, post: Post) {
        self.posts[n] = post;
    }

    pub fn get(&self, n: usize) -> Post {
        self.posts[n].clone()
    }

    pub fn append(&mut self, post: Post) {
        self.posts.push(post);
    }

    pub fn delete(&mut self, n: usize) {
        self.posts.remove(n);
    }

    pub fn write(&self) {
        let strdata = error::helper(
            serde_json::to_string_pretty(&self),
            "Couldn't serialize posts",
        );

        let mut db_fd = Conn::init(PATH);
        let _guard = error::helper(
            db_fd.conn.try_lock(),
            "Couldn't acquire lock on clinte.json",
        );
        error::helper(
            fs::write(PATH, &strdata),
            "Couldn't write data to clinte.json",
        );
    }

    pub fn posts(&self) -> Vec<Post> {
        self.posts.clone()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::user;

    #[test]
    fn retrieve_posts_and_crud() {
        let mut all = Posts::get_all(PATH);
        assert_eq!(all.posts.len(), 1);

        let post = all.get(0);
        assert_eq!(post.title, "Welcome to CLI NoTEs!");
        assert_eq!(post.author, "clinte!");
        assert_eq!(post.body, "Welcome to clinte! For usage, run 'clinte -h'");

        let user = &*user::NAME;

        all.append(Post {
            author: user.into(),
            title: String::from("TITLE_HERE"),
            body: String::from("BODY_HERE"),
        });

        all.write();
        let mut all = Posts::get_all(PATH);

        let post = all.get(1);
        assert_eq!(post.title, "TITLE_HERE");
        assert_eq!(post.author, *user);
        assert_eq!(post.body, "BODY_HERE");

        let post = Post {
            author: user.into(),
            title: "TITLE_GOES_HERE".into(),
            body: "BODY_GOES_HERE".into(),
        };

        all.replace(1, post);

        all.write();
        let mut all = Posts::get_all(PATH);

        let post = all.get(1);
        assert_eq!(post.title, "TITLE_GOES_HERE");
        assert_eq!(post.author, *user);
        assert_eq!(post.body, "BODY_GOES_HERE");

        all.delete(1);
        all.write();
    }
}