Alice_DBMS/
log_engine.rs

1
2use std::fs::*;
3use std::io::{self, Read, Write};
4use std::path::{Path, PathBuf};
5use std::fs;
6use std::env;
7use log::error;
8
9const ROOT_DIR: &str = "Alice-Database-Data";
10const ADB_DATA_DIR: &str = "ADB_Data";
11const LOG_ENGINE_DIR: &str = "log_engine";
12
13#[derive(Debug, Clone)]
14pub struct Document {
15    pub name: String,
16    pub path: PathBuf,
17    pub data: String,
18}
19
20#[derive(Debug, Clone)]
21pub struct Collection {
22    pub name: String,
23    pub documents: Vec<Document>,
24}
25
26impl Collection {
27    // Method to get a document by name
28    pub fn get_document(&self, name: &str) -> Option<&Document> {
29        self.documents.iter().find(|doc| doc.name == name)
30    }
31
32    /// Retrieve a mutable reference to a document by its name.
33    ///
34    /// # Parameters
35    /// - `name`: The name of the document to retrieve.
36    ///
37    /// # Returns
38    /// An `Option` containing a mutable reference to the `Document` if found,
39    /// or `None` if not found.
40    pub fn get_document_mut(&mut self, name: &str) -> Option<&mut Document> {
41        self.documents.iter_mut().find(|doc| doc.name == name)
42    }
43
44    // Method to add a new document to the collection
45    pub fn add_document(&mut self, name: &str, content: &str) -> io::Result<()> {
46        let collection_path = Path::new(&self.path()).join(&self.name);
47        fs::create_dir_all(&collection_path)?;
48
49        let doc_path = collection_path.join(&name.clone()); // Correctly construct the document path
50
51        let mut file = fs::File::create(&doc_path)?;
52        file.write_all(content.as_bytes())?;
53
54        // Create a new Document instance
55        let new_document = Document {
56            name: name.to_string(),
57            path: doc_path.clone(),
58            data: content.to_string(),
59        };
60        self.documents.push(new_document);
61        Ok(())
62    }
63
64    // Method to delete a document from the collection
65    pub fn delete_document(&mut self, name: &str) -> io::Result<()> {
66        if let Some(doc) = self.documents.iter().find(|doc| doc.name == name) {
67            fs::remove_file(&doc.path)?;
68            self.documents.retain(|doc| doc.name != name);
69            Ok(())
70        } else {
71            Err(io::Error::new(io::ErrorKind::NotFound, "Document not found"))
72        }
73    }
74
75    fn path(&self) -> PathBuf {
76        let home_dir = env::home_dir().expect("Failed to get home directory");
77        home_dir.join(ROOT_DIR).join(ADB_DATA_DIR).join(LOG_ENGINE_DIR)
78    }
79}
80
81#[derive(Debug, Clone)]
82pub struct LOGEngine {
83    pub collections: Vec<Collection>,
84}
85impl LOGEngine {
86    /// Create a new `JSONEngine`.
87    ///
88    /// # Parameters
89    /// - `root`: The path to the root directory for data storage.
90    ///
91    /// # Returns
92    /// A new instance of `JSONEngine`.
93    pub fn new(root: &Path, ) -> Self {
94        let collections = get_exists_collections(root);
95        LOGEngine { collections }
96    }
97
98
99    /// Retrieve a mutable reference to a collection by its name.
100    ///
101    /// # Parameters
102    /// - `name`: The name of the collection to retrieve.
103    ///
104    /// # Returns
105    /// An `Option` containing a mutable reference to the `Collection`, if found.
106    pub fn get_collection_mut(&mut self, name: &str) -> Option<&mut Collection> {
107        self.collections.iter_mut().find(|col| col.name == name)
108    }
109
110    /// Add a new collection.
111    ///
112    /// # Parameters
113    /// - `name`: The name of the collection to create.
114    ///
115    /// # Returns
116    /// An `Option` containing a mutable reference to the newly added `Collection`.
117    pub fn add_collection(&mut self, name: &str) -> Option<&mut Collection> {
118        let collection_path = Path::new(&self.root_path()).join(name);
119        fs::create_dir_all(&collection_path).ok()?; // Create the directory for new collection
120
121        let new_collection = Collection {
122            name: name.to_string(),
123            documents: vec![],
124        };
125
126        self.collections.push(new_collection);
127        self.collections.last_mut() // Return a mutable reference to the newly added collection
128    }
129
130    /// Get a collection by name.
131    ///
132    /// # Parameters
133    /// - `name`: The name of the collection to retrieve.
134    ///
135    /// # Returns
136    /// An `Option` containing a reference to the `Collection`, if found.
137    pub fn get_collection(&self, name: &str) -> Option<&Collection> {
138        self.collections.iter().find(|col| col.name == name)
139    }
140
141    /// Get a document from a specific collection.
142    ///
143    /// # Parameters
144    /// - `collection_name`: The name of the collection the document belongs to.
145    /// - `document_name`: The name of the document to retrieve.
146    ///
147    /// # Returns
148    /// An `Option` containing a reference to the `Document`, if found.
149    pub fn get_document(&self, collection_name: &str, document_name: &str) -> Option<&Document> {
150        self.get_collection(collection_name)?.get_document(document_name)
151    }
152
153    fn root_path(&self) -> PathBuf {
154        let home_dir = env::home_dir().expect("Failed to get home directory");
155        home_dir.join(ROOT_DIR).join(ADB_DATA_DIR).join(LOG_ENGINE_DIR)
156    }
157}
158
159
160// Functions for handling file operations and collections
161fn get_documents_in_collection(path: &Path) -> Vec<Document> {
162    let entries = fs::read_dir(path).unwrap();
163    let mut documents: Vec<Document> = vec![];
164
165    for entry in entries {
166        let entry = entry.unwrap();
167        let entry_path = entry.path();
168        if entry_path.is_file() {
169            let name = entry_path.file_name().unwrap().to_string_lossy().into_owned();
170            let data = read_file_data(&entry_path).unwrap_or_default();
171            let document = Document {
172                name,
173                path: entry_path.clone(),
174                data,
175            };
176            documents.push(document);
177        }
178    }
179    documents
180}
181
182fn read_file_data(path: &Path) -> io::Result<String> {
183    let mut file = fs::File::open(path)?;
184    let mut contents = String::new();
185    file.read_to_string(&mut contents)?;
186    Ok(contents)
187}
188
189fn get_exists_collections(path: &Path) -> Vec<Collection> {
190    let mut collections: Vec<Collection> = vec![];
191
192    if path.exists() && path.is_dir() {
193        let entries = fs::read_dir(path).unwrap();
194
195        for entry in entries {
196            let entry = entry.unwrap();
197            let entry_path = entry.path();
198
199            if entry_path.is_dir() {
200                let documents = get_documents_in_collection(&entry_path);
201                let collection_name = entry_path.file_name().unwrap().to_string_lossy().into_owned();
202                let collection = Collection {
203                    name: collection_name,
204                    documents,
205                };
206                collections.push(collection);
207            }
208        }
209    } else {
210        error!("The specified path does not exist or is not a directory: {:?}", path);
211    }
212
213    collections
214}