From c2cb3a19a9ca70a53e59ff727878e605116213fa Mon Sep 17 00:00:00 2001 From: Daniil Ermolaev Date: Thu, 24 Oct 2024 16:04:19 +0500 Subject: [PATCH 1/8] to files --- Plugins/Alice-Database/Cargo.toml | 2 +- Plugins/Alice-Database/src/json_engine.rs | 312 +++++++++++++++- Plugins/Alice-Database/src/main.rs | 421 +++++++--------------- Plugins/Alice-Database/src/tests.rs | 89 ----- 4 files changed, 428 insertions(+), 396 deletions(-) delete mode 100644 Plugins/Alice-Database/src/tests.rs diff --git a/Plugins/Alice-Database/Cargo.toml b/Plugins/Alice-Database/Cargo.toml index a761657..080fe2a 100644 --- a/Plugins/Alice-Database/Cargo.toml +++ b/Plugins/Alice-Database/Cargo.toml @@ -19,4 +19,4 @@ simplelog = "0.12.2" [[test]] name = "tests" -path = "src/tests.rs" +path = "src/main.rs" diff --git a/Plugins/Alice-Database/src/json_engine.rs b/Plugins/Alice-Database/src/json_engine.rs index c7a31b7..9843aa7 100644 --- a/Plugins/Alice-Database/src/json_engine.rs +++ b/Plugins/Alice-Database/src/json_engine.rs @@ -1,15 +1,313 @@ -use uuid::Uuid; +use std::fs; +use std::io::{self, Read, Write}; +use std::env; +use std::path::{PathBuf, Path}; +use serde_json::{json, Value, Result as JsonResult}; -pub fn get_files_in_dir() -> Vec<> +use log::{info, error, trace}; +use simplelog::*; -#[derive(Debug, Clone)] -pub struct JSONEngine { +use chrono::Local; + +const ROOT_DIR: &str = "Alice-Database-Data"; +const ADB_DATA_DIR: &str = "ADB_Data"; +const JSON_ENGINE_DIR: &str = "json_engine"; + + +/// A struct representing a document in the database. +/// +/// A `Document` contains its name, file path, and its content stored as a JSON `Value`. +#[derive(Debug)] +pub struct Document { pub name: String, - pub tables: Vec, + pub path: PathBuf, + pub json_value: Option, +} + +/// A struct representing a collection of documents. +/// +/// A `Collection` holds a name and a list of associated `Document`s. +#[derive(Debug)] +pub struct Collection { + pub name: String, + pub documents: Vec, +} + +impl Collection { + // Method to get a document by name + pub fn get_document(&self, name: &str) -> Option<&Document> { + self.documents.iter().find(|doc| doc.name == name) + } + + /// Retrieve a mutable reference to a document by its name. + /// + /// # Parameters + /// - `name`: The name of the document to retrieve. + /// + /// # Returns + /// An `Option` containing a mutable reference to the `Document` if found, + /// or `None` if not found. + pub fn get_document_mut(&mut self, name: &str) -> Option<&mut Document> { + self.documents.iter_mut().find(|doc| doc.name == name) + } + + // Method to add a new document to the collection + pub fn add_document(&mut self, name: &str, content: &str) -> io::Result<()> { + let collection_path = Path::new(&self.path()).join(&self.name); + fs::create_dir_all(&collection_path)?; + + let doc_path = collection_path.join(name); // Correctly construct the document path + let mut file = fs::File::create(&doc_path)?; + file.write_all(content.as_bytes())?; + + // Create a new Document instance + let new_document = Document { + name: name.to_string(), + path: doc_path.clone(), + json_value: parse_json_data(content).ok(), + }; + self.documents.push(new_document); + Ok(()) + } + + // Method to delete a document from the collection + pub fn delete_document(&mut self, name: &str) -> io::Result<()> { + if let Some(doc) = self.documents.iter().find(|doc| doc.name == name) { + fs::remove_file(&doc.path)?; + self.documents.retain(|doc| doc.name != name); + Ok(()) + } else { + Err(io::Error::new(io::ErrorKind::NotFound, "Document not found")) + } + } + + fn path(&self) -> PathBuf { + let home_dir = env::home_dir().expect("Failed to get home directory"); + home_dir.join(ROOT_DIR).join(ADB_DATA_DIR).join(JSON_ENGINE_DIR) + } +} + +/// A struct to manage multiple collections of documents. +pub struct JSONEngine { + collections: Vec, +} + +impl JSONEngine { + /// Create a new `JSONEngine`. + /// + /// # Parameters + /// - `root`: The path to the root directory for data storage. + /// + /// # Returns + /// A new instance of `JSONEngine`. + pub fn new(root: &Path) -> Self { + let collections = get_exists_collections(root); + JSONEngine { collections } + } + + /// Retrieve a mutable reference to a collection by its name. + /// + /// # Parameters + /// - `name`: The name of the collection to retrieve. + /// + /// # Returns + /// An `Option` containing a mutable reference to the `Collection`, if found. + pub fn get_collection_mut(&mut self, name: &str) -> Option<&mut Collection> { + self.collections.iter_mut().find(|col| col.name == name) + } + + /// Add a new collection. + /// + /// # Parameters + /// - `name`: The name of the collection to create. + /// + /// # Returns + /// An `Option` containing a mutable reference to the newly added `Collection`. + pub fn add_collection(&mut self, name: &str) -> Option<&mut Collection> { + let collection_path = Path::new(&self.root_path()).join(name); + fs::create_dir_all(&collection_path).ok()?; // Create the directory for new collection + + let new_collection = Collection { + name: name.to_string(), + documents: vec![], + }; + + self.collections.push(new_collection); + self.collections.last_mut() // Return a mutable reference to the newly added collection + } + + /// Get a collection by name. + /// + /// # Parameters + /// - `name`: The name of the collection to retrieve. + /// + /// # Returns + /// An `Option` containing a reference to the `Collection`, if found. + pub fn get_collection(&self, name: &str) -> Option<&Collection> { + self.collections.iter().find(|col| col.name == name) + } + + /// Get a document from a specific collection. + /// + /// # Parameters + /// - `collection_name`: The name of the collection the document belongs to. + /// - `document_name`: The name of the document to retrieve. + /// + /// # Returns + /// An `Option` containing a reference to the `Document`, if found. + pub fn get_document(&self, collection_name: &str, document_name: &str) -> Option<&Document> { + self.get_collection(collection_name)?.get_document(document_name) + } + + fn root_path(&self) -> PathBuf { + let home_dir = env::home_dir().expect("Failed to get home directory"); + home_dir.join(ROOT_DIR).join(ADB_DATA_DIR).join(JSON_ENGINE_DIR) + } } +impl Document { + /// Update a field in the document. + /// + /// # Parameters + /// - `key`: The key of the field to update. + /// - `value`: The new value for the field. + /// + /// # Returns + /// A result indicating success or failure. + pub fn update_rows(&mut self, key: &str, value: &Value) -> io::Result<()> { + if let Some(json_value) = &mut self.json_value { + if let Some(obj) = json_value.as_object_mut() { + obj.insert(key.to_string(), value.clone()); + let updated_content = serde_json::to_string_pretty(json_value)?; + let mut file = fs::File::create(&self.path)?; + file.write_all(updated_content.as_bytes())?; + Ok(()) + } else { + Err(io::Error::new(io::ErrorKind::InvalidData, "JSON is not an object")) + } + } else { + Err(io::Error::new(io::ErrorKind::InvalidData, "Document does not contain valid JSON")) + } + } + + /// Delete a field in the document. + /// + /// # Parameters + /// - `key`: The key of the field to delete. + /// + /// # Returns + /// A result indicating success or failure. + pub fn delete_rows(&mut self, key: &str) -> io::Result<()> { + if let Some(json_value) = &mut self.json_value { + if let Some(obj) = json_value.as_object_mut() { + obj.remove(key); + let updated_content = serde_json::to_string_pretty(json_value)?; + let mut file = fs::File::create(&self.path)?; + file.write_all(updated_content.as_bytes())?; + Ok(()) + } else { + Err(io::Error::new(io::ErrorKind::InvalidData, "JSON is not an object")) + } + } else { + Err(io::Error::new(io::ErrorKind::InvalidData, "Document does not contain valid JSON")) + } + } + + /// Update a field in a nested JSON object. + /// + /// # Parameters + /// - `parent_key`: The parent key of the nested field. + /// - `key`: The key of the field to update within the parent key. + /// - `value`: The new value for the nested field. + /// + /// # Returns + /// A result indicating success or failure. + pub fn update_nested_field(&mut self, parent_key: &str, key: &str, value: &Value) -> io::Result<()> { + if let Some(json_value) = &mut self.json_value { + if let Some(parent) = json_value.get_mut(parent_key) { + if let Some(obj) = parent.as_object_mut() { + obj.insert(key.to_string(), value.clone()); + let updated_content = serde_json::to_string_pretty(json_value)?; + let mut file = fs::File::create(&self.path)?; + file.write_all(updated_content.as_bytes())?; + Ok(()) + } else { + Err(io::Error::new(io::ErrorKind::InvalidData, "Parent key is not an object")) + } + } else { + Err(io::Error::new(io::ErrorKind::NotFound, "Parent key not found")) + } + } else { + Err(io::Error::new(io::ErrorKind::InvalidData, "Document does not contain valid JSON")) + } + } +} + +// Functions for handling file operations and collections +fn get_documents_in_collection(path: &Path) -> Vec { + let entries = fs::read_dir(path).unwrap(); + let mut documents: Vec = vec![]; + + for entry in entries { + let entry = entry.unwrap(); + let entry_path = entry.path(); + if entry_path.is_file() { + let name = entry_path.file_name().unwrap().to_string_lossy().into_owned(); + let data = read_file_data(&entry_path).unwrap_or_default(); + let json_value = parse_json_data(&data).ok(); + let document = Document { + name, + path: entry_path.clone(), + json_value, + }; + documents.push(document); + } + } + documents +} + +fn read_file_data(path: &Path) -> io::Result { + let mut file = fs::File::open(path)?; + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + Ok(contents) +} + +fn parse_json_data(data: &str) -> JsonResult { + serde_json::from_str(data) +} + +fn get_exists_collections(path: &Path) -> Vec { + let mut collections: Vec = vec![]; + + if path.exists() && path.is_dir() { + let entries = fs::read_dir(path).unwrap(); + + for entry in entries { + let entry = entry.unwrap(); + let entry_path = entry.path(); + + if entry_path.is_dir() { + let documents = get_documents_in_collection(&entry_path); + let collection_name = entry_path.file_name().unwrap().to_string_lossy().into_owned(); + let collection = Collection { + name: collection_name, + documents, + }; + collections.push(collection); + } + } + } else { + error!("The specified path does not exist or is not a directory: {:?}", path); + } + + collections +} + +// Helper method to get a mutable reference to a document impl JSONEngine { - pub fn init() -> Self { - let name = Uuid::new_v4().to_string(); + pub fn get_document_mut(&mut self, collection_name: &str, document_name: &str) -> Option<&mut Document> { + self.get_collection_mut(collection_name)?.documents.iter_mut().find(|doc| doc.name == document_name) } } + diff --git a/Plugins/Alice-Database/src/main.rs b/Plugins/Alice-Database/src/main.rs index 37b4f89..a4e5023 100644 --- a/Plugins/Alice-Database/src/main.rs +++ b/Plugins/Alice-Database/src/main.rs @@ -7,6 +7,8 @@ use simplelog::*; use chrono::Local; use std::env; // Import this for getting the home directory +pub mod json_engine; +use json_engine::*; // Define constants for the root path and log path const ROOT_DIR: &str = "Alice-Database-Data"; @@ -14,298 +16,7 @@ const ADB_DATA_DIR: &str = "ADB_Data"; const JSON_ENGINE_DIR: &str = "json_engine"; const ADB_LOGS_DIR: &str = "ADB_Logs"; -/// A struct representing a document in the database. -/// -/// A `Document` contains its name, file path, and its content stored as a JSON `Value`. -#[derive(Debug)] -pub struct Document { - pub name: String, - pub path: PathBuf, - pub json_value: Option, -} - -/// A struct representing a collection of documents. -/// -/// A `Collection` holds a name and a list of associated `Document`s. -#[derive(Debug)] -pub struct Collection { - pub name: String, - pub documents: Vec, -} - -impl Collection { - // Method to get a document by name - pub fn get_document(&self, name: &str) -> Option<&Document> { - self.documents.iter().find(|doc| doc.name == name) - } - - /// Retrieve a mutable reference to a document by its name. - /// - /// # Parameters - /// - `name`: The name of the document to retrieve. - /// - /// # Returns - /// An `Option` containing a mutable reference to the `Document` if found, - /// or `None` if not found. - pub fn get_document_mut(&mut self, name: &str) -> Option<&mut Document> { - self.documents.iter_mut().find(|doc| doc.name == name) - } - - // Method to add a new document to the collection - pub fn add_document(&mut self, name: &str, content: &str) -> io::Result<()> { - let collection_path = Path::new(&self.path()).join(&self.name); - fs::create_dir_all(&collection_path)?; - - let doc_path = collection_path.join(name); // Correctly construct the document path - let mut file = fs::File::create(&doc_path)?; - file.write_all(content.as_bytes())?; - - // Create a new Document instance - let new_document = Document { - name: name.to_string(), - path: doc_path.clone(), - json_value: parse_json_data(content).ok(), - }; - self.documents.push(new_document); - Ok(()) - } - - // Method to delete a document from the collection - pub fn delete_document(&mut self, name: &str) -> io::Result<()> { - if let Some(doc) = self.documents.iter().find(|doc| doc.name == name) { - fs::remove_file(&doc.path)?; - self.documents.retain(|doc| doc.name != name); - Ok(()) - } else { - Err(io::Error::new(io::ErrorKind::NotFound, "Document not found")) - } - } - - fn path(&self) -> PathBuf { - let home_dir = env::home_dir().expect("Failed to get home directory"); - home_dir.join(ROOT_DIR).join(ADB_DATA_DIR).join(JSON_ENGINE_DIR) - } -} - -/// A struct to manage multiple collections of documents. -pub struct CollectionManager { - collections: Vec, -} - -impl CollectionManager { - /// Create a new `CollectionManager`. - /// - /// # Parameters - /// - `root`: The path to the root directory for data storage. - /// - /// # Returns - /// A new instance of `CollectionManager`. - pub fn new(root: &Path) -> Self { - let collections = get_exists_collections(root); - CollectionManager { collections } - } - - /// Retrieve a mutable reference to a collection by its name. - /// - /// # Parameters - /// - `name`: The name of the collection to retrieve. - /// - /// # Returns - /// An `Option` containing a mutable reference to the `Collection`, if found. - pub fn get_collection_mut(&mut self, name: &str) -> Option<&mut Collection> { - self.collections.iter_mut().find(|col| col.name == name) - } - - /// Add a new collection. - /// - /// # Parameters - /// - `name`: The name of the collection to create. - /// - /// # Returns - /// An `Option` containing a mutable reference to the newly added `Collection`. - pub fn add_collection(&mut self, name: &str) -> Option<&mut Collection> { - let collection_path = Path::new(&self.root_path()).join(name); - fs::create_dir_all(&collection_path).ok()?; // Create the directory for new collection - - let new_collection = Collection { - name: name.to_string(), - documents: vec![], - }; - - self.collections.push(new_collection); - self.collections.last_mut() // Return a mutable reference to the newly added collection - } - - /// Get a collection by name. - /// - /// # Parameters - /// - `name`: The name of the collection to retrieve. - /// - /// # Returns - /// An `Option` containing a reference to the `Collection`, if found. - pub fn get_collection(&self, name: &str) -> Option<&Collection> { - self.collections.iter().find(|col| col.name == name) - } - - /// Get a document from a specific collection. - /// - /// # Parameters - /// - `collection_name`: The name of the collection the document belongs to. - /// - `document_name`: The name of the document to retrieve. - /// - /// # Returns - /// An `Option` containing a reference to the `Document`, if found. - pub fn get_document(&self, collection_name: &str, document_name: &str) -> Option<&Document> { - self.get_collection(collection_name)?.get_document(document_name) - } - - fn root_path(&self) -> PathBuf { - let home_dir = env::home_dir().expect("Failed to get home directory"); - home_dir.join(ROOT_DIR).join(ADB_DATA_DIR).join(JSON_ENGINE_DIR) - } -} - -impl Document { - /// Update a field in the document. - /// - /// # Parameters - /// - `key`: The key of the field to update. - /// - `value`: The new value for the field. - /// - /// # Returns - /// A result indicating success or failure. - pub fn update_rows(&mut self, key: &str, value: &Value) -> io::Result<()> { - if let Some(json_value) = &mut self.json_value { - if let Some(obj) = json_value.as_object_mut() { - obj.insert(key.to_string(), value.clone()); - let updated_content = serde_json::to_string_pretty(json_value)?; - let mut file = fs::File::create(&self.path)?; - file.write_all(updated_content.as_bytes())?; - Ok(()) - } else { - Err(io::Error::new(io::ErrorKind::InvalidData, "JSON is not an object")) - } - } else { - Err(io::Error::new(io::ErrorKind::InvalidData, "Document does not contain valid JSON")) - } - } - - /// Delete a field in the document. - /// - /// # Parameters - /// - `key`: The key of the field to delete. - /// - /// # Returns - /// A result indicating success or failure. - pub fn delete_rows(&mut self, key: &str) -> io::Result<()> { - if let Some(json_value) = &mut self.json_value { - if let Some(obj) = json_value.as_object_mut() { - obj.remove(key); - let updated_content = serde_json::to_string_pretty(json_value)?; - let mut file = fs::File::create(&self.path)?; - file.write_all(updated_content.as_bytes())?; - Ok(()) - } else { - Err(io::Error::new(io::ErrorKind::InvalidData, "JSON is not an object")) - } - } else { - Err(io::Error::new(io::ErrorKind::InvalidData, "Document does not contain valid JSON")) - } - } - - /// Update a field in a nested JSON object. - /// - /// # Parameters - /// - `parent_key`: The parent key of the nested field. - /// - `key`: The key of the field to update within the parent key. - /// - `value`: The new value for the nested field. - /// - /// # Returns - /// A result indicating success or failure. - pub fn update_nested_field(&mut self, parent_key: &str, key: &str, value: &Value) -> io::Result<()> { - if let Some(json_value) = &mut self.json_value { - if let Some(parent) = json_value.get_mut(parent_key) { - if let Some(obj) = parent.as_object_mut() { - obj.insert(key.to_string(), value.clone()); - let updated_content = serde_json::to_string_pretty(json_value)?; - let mut file = fs::File::create(&self.path)?; - file.write_all(updated_content.as_bytes())?; - Ok(()) - } else { - Err(io::Error::new(io::ErrorKind::InvalidData, "Parent key is not an object")) - } - } else { - Err(io::Error::new(io::ErrorKind::NotFound, "Parent key not found")) - } - } else { - Err(io::Error::new(io::ErrorKind::InvalidData, "Document does not contain valid JSON")) - } - } -} - -// Functions for handling file operations and collections -fn get_documents_in_collection(path: &Path) -> Vec { - let entries = fs::read_dir(path).unwrap(); - let mut documents: Vec = vec![]; - - for entry in entries { - let entry = entry.unwrap(); - let entry_path = entry.path(); - if entry_path.is_file() { - let name = entry_path.file_name().unwrap().to_string_lossy().into_owned(); - let data = read_file_data(&entry_path).unwrap_or_default(); - let json_value = parse_json_data(&data).ok(); - let document = Document { - name, - path: entry_path.clone(), - json_value, - }; - documents.push(document); - } - } - documents -} - -fn read_file_data(path: &Path) -> io::Result { - let mut file = fs::File::open(path)?; - let mut contents = String::new(); - file.read_to_string(&mut contents)?; - Ok(contents) -} - -fn parse_json_data(data: &str) -> JsonResult { - serde_json::from_str(data) -} - -fn get_exists_collections(path: &Path) -> Vec { - let mut collections: Vec = vec![]; - - if path.exists() && path.is_dir() { - let entries = fs::read_dir(path).unwrap(); - - for entry in entries { - let entry = entry.unwrap(); - let entry_path = entry.path(); - - if entry_path.is_dir() { - let documents = get_documents_in_collection(&entry_path); - let collection_name = entry_path.file_name().unwrap().to_string_lossy().into_owned(); - let collection = Collection { - name: collection_name, - documents, - }; - collections.push(collection); - } - } - } else { - error!("The specified path does not exist or is not a directory: {:?}", path); - } - - collections -} - -/// The main entry point for the application. -fn main() -> std::io::Result<()> { +fn prepare() -> std::io::Result { // Get the home directory let home_dir = env::home_dir().expect("Failed to get home directory"); let base_path = home_dir.join(ROOT_DIR); @@ -321,7 +32,6 @@ fn main() -> std::io::Result<()> { // Ensure the JSON engine directory exists fs::create_dir_all(&root_path).expect("Failed to create json_engine directory"); - // Generate a unique log filename using timestamp let timestamp = Local::now().format("%Y-%m-%d_%H-%M-%S").to_string(); let log_file_path = format!("{}/{}.adb.log", adb_logs_path.display(), timestamp); @@ -332,13 +42,44 @@ fn main() -> std::io::Result<()> { CombinedLogger::init( vec![ TermLogger::new(LevelFilter::Trace, log_config.clone(), TerminalMode::Mixed, ColorChoice::Auto), - WriteLogger::new(LevelFilter::Trace, log_config.clone(), fs::File::create(log_file_path).unwrap()), + WriteLogger::new(LevelFilter::Trace, log_config.clone(), fs::File::create(log_file_path).unwrap()), ] ).unwrap(); + Ok(root_path.clone()) + +} + +fn print_ascii() { + println!(r" + @---------------------------------------------------------------@ + | ______ __ __ ______ ______ | + | /\ __ \ /\ \ /\ \ /\ ___\ /\ ___\ | + | \ \ __ \ \ \ \____ \ \ \ \ \ \____ \ \ __\ | + | \ \_\ \_\ \ \_____\ \ \_\ \ \_____\ \ \_____\ | + | \/_/\/_/ \/_____/ \/_/ \/_____/ \/_____/ | + | | + | _____ ______ | + | /\ __-. /\ == \ | + | \ \ \/\ \ \ \ __< | + | \ \____- \ \_____\ | + | \/____/ \/_____/ | + | | + @---------------------------------------------------------------@ + ") +} + +/// The main entry point for the application. +fn main() -> std::io::Result<()> { + print_ascii(); + let root_path = match prepare() { + Ok(k) => k, + _ => panic!("Errors in prepare function."), + }; + trace!("Starting Collection Manager..."); - let mut manager = CollectionManager::new(&root_path); + let mut manager = JSONEngine::new(&root_path); // Create a new collection let collection_name = "collection1"; // Example collection name @@ -395,9 +136,91 @@ fn main() -> std::io::Result<()> { Ok(()) } -// Helper method to get a mutable reference to a document -impl CollectionManager { - pub fn get_document_mut(&mut self, collection_name: &str, document_name: &str) -> Option<&mut Document> { - self.get_collection_mut(collection_name)?.documents.iter_mut().find(|doc| doc.name == document_name) +#[cfg(test)] +mod tests { + use super::*; + use std::env; + use std::fs; + use std::path::{Path, PathBuf}; + use serde_json::json; + const TEST_ROOT_DIR: &str = "Alice-Database-Data-Test"; + const TEST_ADB_DATA_DIR: &str = "ADB_Data"; + const TEST_JSON_ENGINE_DIR: &str = "json_engine"; + + // Setup a temporary test directory + fn setup_test_dir() -> PathBuf { + let home_dir = env::temp_dir(); + let test_dir = home_dir.join(TEST_ROOT_DIR); + fs::create_dir_all(&test_dir).expect("Failed to create test directory"); + test_dir + } + + #[test] + fn test_create_and_add_document() { + let root_path = setup_test_dir(); + let mut manager = JSONEngine::new(&root_path); + + // Create a collection + manager.add_collection("test_collection").unwrap(); + let collection = manager.get_collection_mut("test_collection").unwrap(); + + // Add a document + let doc_content = json!({"code": 200, "success": true}).to_string(); + let result = collection.add_document("test_document.json", &doc_content); + assert!(result.is_ok()); + + // Verify the document is added + assert_eq!(collection.documents.len(), 1); + assert_eq!(collection.documents[0].name, "test_document.json"); + } + + #[test] + fn test_update_document() { + let root_path = setup_test_dir(); + let mut manager = JSONEngine::new(&root_path); + + // Create a collection and add a document + manager.add_collection("test_collection").unwrap(); + let collection = manager.get_collection_mut("test_collection").unwrap(); + let doc_content = json!({ + "code": 200, + "success": true, + "payload": { + "homepage": null + } + }).to_string(); + collection.add_document("test_document.json", &doc_content).unwrap(); + + // Update the homepage field + let doc = collection.get_document_mut("test_document.json").unwrap(); + let new_homepage_value = json!("https://new-homepage-url.com"); + + let update_result = doc.update_nested_field("payload", "homepage", &new_homepage_value); + assert!(update_result.is_ok()); + + // Check the updated value + assert_eq!(doc.json_value.as_ref().unwrap()["payload"]["homepage"], new_homepage_value); + } + + #[test] + fn test_delete_document() { + let root_path = setup_test_dir(); + let mut manager = JSONEngine::new(&root_path); + + // Create a collection and add a document + manager.add_collection("test_collection").unwrap(); + let collection = manager.get_collection_mut("test_collection").unwrap(); + collection.add_document("test_document.json", "{\"key\":\"value\"}").unwrap(); + + // Ensure the document exists before deletion + assert_eq!(collection.documents.len(), 1); + + // Delete the document + let delete_result = collection.delete_document("test_document.json"); + assert!(delete_result.is_ok()); + + // Verify the document was deleted + assert_eq!(collection.documents.len(), 0); } + } diff --git a/Plugins/Alice-Database/src/tests.rs b/Plugins/Alice-Database/src/tests.rs deleted file mode 100644 index 9aa6dc5..0000000 --- a/Plugins/Alice-Database/src/tests.rs +++ /dev/null @@ -1,89 +0,0 @@ -#[cfg(test)] -mod tests { - use super::*; - use std::env; - use std::fs; - use std::path::Path; - use serde_json::json; - use super::*; - const TEST_ROOT_DIR: &str = "Alice-Database-Data-Test"; - const TEST_ADB_DATA_DIR: &str = "ADB_Data"; - const TEST_JSON_ENGINE_DIR: &str = "json_engine"; - - // Setup a temporary test directory - fn setup_test_dir() -> PathBuf { - let home_dir = env::temp_dir(); - let test_dir = home_dir.join(TEST_ROOT_DIR); - fs::create_dir_all(&test_dir).expect("Failed to create test directory"); - test_dir - } - - #[test] - fn test_create_and_add_document() { - let root_path = setup_test_dir(); - let mut manager = CollectionManager::new(&root_path); - - // Create a collection - manager.add_collection("test_collection").unwrap(); - let collection = manager.get_collection_mut("test_collection").unwrap(); - - // Add a document - let doc_content = json!({"code": 200, "success": true}).to_string(); - let result = collection.add_document("test_document.json", &doc_content); - assert!(result.is_ok()); - - // Verify the document is added - assert_eq!(collection.documents.len(), 1); - assert_eq!(collection.documents[0].name, "test_document.json"); - } - - #[test] - fn test_update_document() { - let root_path = setup_test_dir(); - let mut manager = CollectionManager::new(&root_path); - - // Create a collection and add a document - manager.add_collection("test_collection").unwrap(); - let collection = manager.get_collection_mut("test_collection").unwrap(); - let doc_content = json!({ - "code": 200, - "success": true, - "payload": { - "homepage": null - } - }).to_string(); - collection.add_document("test_document.json", &doc_content).unwrap(); - - // Update the homepage field - let doc = collection.get_document_mut("test_document.json").unwrap(); - let new_homepage_value = json!("https://new-homepage-url.com"); - - let update_result = doc.update_nested_field("payload", "homepage", &new_homepage_value); - assert!(update_result.is_ok()); - - // Check the updated value - assert_eq!(doc.json_value.as_ref().unwrap()["payload"]["homepage"], new_homepage_value); - } - - #[test] - fn test_delete_document() { - let root_path = setup_test_dir(); - let mut manager = CollectionManager::new(&root_path); - - // Create a collection and add a document - manager.add_collection("test_collection").unwrap(); - let collection = manager.get_collection_mut("test_collection").unwrap(); - collection.add_document("test_document.json", "{\"key\":\"value\"}").unwrap(); - - // Ensure the document exists before deletion - assert_eq!(collection.documents.len(), 1); - - // Delete the document - let delete_result = collection.delete_document("test_document.json"); - assert!(delete_result.is_ok()); - - // Verify the document was deleted - assert_eq!(collection.documents.len(), 0); - } - -} From e5524764c8e1831d512fb9bb4c81b32f7d4ddf7a Mon Sep 17 00:00:00 2001 From: Daniil Ermolaev Date: Thu, 24 Oct 2024 16:04:57 +0500 Subject: [PATCH 2/8] new lib.rs --- Plugins/Alice-Database/src/lib.rs | 421 +++++++++--------------------- 1 file changed, 122 insertions(+), 299 deletions(-) diff --git a/Plugins/Alice-Database/src/lib.rs b/Plugins/Alice-Database/src/lib.rs index 37b4f89..a4e5023 100644 --- a/Plugins/Alice-Database/src/lib.rs +++ b/Plugins/Alice-Database/src/lib.rs @@ -7,6 +7,8 @@ use simplelog::*; use chrono::Local; use std::env; // Import this for getting the home directory +pub mod json_engine; +use json_engine::*; // Define constants for the root path and log path const ROOT_DIR: &str = "Alice-Database-Data"; @@ -14,298 +16,7 @@ const ADB_DATA_DIR: &str = "ADB_Data"; const JSON_ENGINE_DIR: &str = "json_engine"; const ADB_LOGS_DIR: &str = "ADB_Logs"; -/// A struct representing a document in the database. -/// -/// A `Document` contains its name, file path, and its content stored as a JSON `Value`. -#[derive(Debug)] -pub struct Document { - pub name: String, - pub path: PathBuf, - pub json_value: Option, -} - -/// A struct representing a collection of documents. -/// -/// A `Collection` holds a name and a list of associated `Document`s. -#[derive(Debug)] -pub struct Collection { - pub name: String, - pub documents: Vec, -} - -impl Collection { - // Method to get a document by name - pub fn get_document(&self, name: &str) -> Option<&Document> { - self.documents.iter().find(|doc| doc.name == name) - } - - /// Retrieve a mutable reference to a document by its name. - /// - /// # Parameters - /// - `name`: The name of the document to retrieve. - /// - /// # Returns - /// An `Option` containing a mutable reference to the `Document` if found, - /// or `None` if not found. - pub fn get_document_mut(&mut self, name: &str) -> Option<&mut Document> { - self.documents.iter_mut().find(|doc| doc.name == name) - } - - // Method to add a new document to the collection - pub fn add_document(&mut self, name: &str, content: &str) -> io::Result<()> { - let collection_path = Path::new(&self.path()).join(&self.name); - fs::create_dir_all(&collection_path)?; - - let doc_path = collection_path.join(name); // Correctly construct the document path - let mut file = fs::File::create(&doc_path)?; - file.write_all(content.as_bytes())?; - - // Create a new Document instance - let new_document = Document { - name: name.to_string(), - path: doc_path.clone(), - json_value: parse_json_data(content).ok(), - }; - self.documents.push(new_document); - Ok(()) - } - - // Method to delete a document from the collection - pub fn delete_document(&mut self, name: &str) -> io::Result<()> { - if let Some(doc) = self.documents.iter().find(|doc| doc.name == name) { - fs::remove_file(&doc.path)?; - self.documents.retain(|doc| doc.name != name); - Ok(()) - } else { - Err(io::Error::new(io::ErrorKind::NotFound, "Document not found")) - } - } - - fn path(&self) -> PathBuf { - let home_dir = env::home_dir().expect("Failed to get home directory"); - home_dir.join(ROOT_DIR).join(ADB_DATA_DIR).join(JSON_ENGINE_DIR) - } -} - -/// A struct to manage multiple collections of documents. -pub struct CollectionManager { - collections: Vec, -} - -impl CollectionManager { - /// Create a new `CollectionManager`. - /// - /// # Parameters - /// - `root`: The path to the root directory for data storage. - /// - /// # Returns - /// A new instance of `CollectionManager`. - pub fn new(root: &Path) -> Self { - let collections = get_exists_collections(root); - CollectionManager { collections } - } - - /// Retrieve a mutable reference to a collection by its name. - /// - /// # Parameters - /// - `name`: The name of the collection to retrieve. - /// - /// # Returns - /// An `Option` containing a mutable reference to the `Collection`, if found. - pub fn get_collection_mut(&mut self, name: &str) -> Option<&mut Collection> { - self.collections.iter_mut().find(|col| col.name == name) - } - - /// Add a new collection. - /// - /// # Parameters - /// - `name`: The name of the collection to create. - /// - /// # Returns - /// An `Option` containing a mutable reference to the newly added `Collection`. - pub fn add_collection(&mut self, name: &str) -> Option<&mut Collection> { - let collection_path = Path::new(&self.root_path()).join(name); - fs::create_dir_all(&collection_path).ok()?; // Create the directory for new collection - - let new_collection = Collection { - name: name.to_string(), - documents: vec![], - }; - - self.collections.push(new_collection); - self.collections.last_mut() // Return a mutable reference to the newly added collection - } - - /// Get a collection by name. - /// - /// # Parameters - /// - `name`: The name of the collection to retrieve. - /// - /// # Returns - /// An `Option` containing a reference to the `Collection`, if found. - pub fn get_collection(&self, name: &str) -> Option<&Collection> { - self.collections.iter().find(|col| col.name == name) - } - - /// Get a document from a specific collection. - /// - /// # Parameters - /// - `collection_name`: The name of the collection the document belongs to. - /// - `document_name`: The name of the document to retrieve. - /// - /// # Returns - /// An `Option` containing a reference to the `Document`, if found. - pub fn get_document(&self, collection_name: &str, document_name: &str) -> Option<&Document> { - self.get_collection(collection_name)?.get_document(document_name) - } - - fn root_path(&self) -> PathBuf { - let home_dir = env::home_dir().expect("Failed to get home directory"); - home_dir.join(ROOT_DIR).join(ADB_DATA_DIR).join(JSON_ENGINE_DIR) - } -} - -impl Document { - /// Update a field in the document. - /// - /// # Parameters - /// - `key`: The key of the field to update. - /// - `value`: The new value for the field. - /// - /// # Returns - /// A result indicating success or failure. - pub fn update_rows(&mut self, key: &str, value: &Value) -> io::Result<()> { - if let Some(json_value) = &mut self.json_value { - if let Some(obj) = json_value.as_object_mut() { - obj.insert(key.to_string(), value.clone()); - let updated_content = serde_json::to_string_pretty(json_value)?; - let mut file = fs::File::create(&self.path)?; - file.write_all(updated_content.as_bytes())?; - Ok(()) - } else { - Err(io::Error::new(io::ErrorKind::InvalidData, "JSON is not an object")) - } - } else { - Err(io::Error::new(io::ErrorKind::InvalidData, "Document does not contain valid JSON")) - } - } - - /// Delete a field in the document. - /// - /// # Parameters - /// - `key`: The key of the field to delete. - /// - /// # Returns - /// A result indicating success or failure. - pub fn delete_rows(&mut self, key: &str) -> io::Result<()> { - if let Some(json_value) = &mut self.json_value { - if let Some(obj) = json_value.as_object_mut() { - obj.remove(key); - let updated_content = serde_json::to_string_pretty(json_value)?; - let mut file = fs::File::create(&self.path)?; - file.write_all(updated_content.as_bytes())?; - Ok(()) - } else { - Err(io::Error::new(io::ErrorKind::InvalidData, "JSON is not an object")) - } - } else { - Err(io::Error::new(io::ErrorKind::InvalidData, "Document does not contain valid JSON")) - } - } - - /// Update a field in a nested JSON object. - /// - /// # Parameters - /// - `parent_key`: The parent key of the nested field. - /// - `key`: The key of the field to update within the parent key. - /// - `value`: The new value for the nested field. - /// - /// # Returns - /// A result indicating success or failure. - pub fn update_nested_field(&mut self, parent_key: &str, key: &str, value: &Value) -> io::Result<()> { - if let Some(json_value) = &mut self.json_value { - if let Some(parent) = json_value.get_mut(parent_key) { - if let Some(obj) = parent.as_object_mut() { - obj.insert(key.to_string(), value.clone()); - let updated_content = serde_json::to_string_pretty(json_value)?; - let mut file = fs::File::create(&self.path)?; - file.write_all(updated_content.as_bytes())?; - Ok(()) - } else { - Err(io::Error::new(io::ErrorKind::InvalidData, "Parent key is not an object")) - } - } else { - Err(io::Error::new(io::ErrorKind::NotFound, "Parent key not found")) - } - } else { - Err(io::Error::new(io::ErrorKind::InvalidData, "Document does not contain valid JSON")) - } - } -} - -// Functions for handling file operations and collections -fn get_documents_in_collection(path: &Path) -> Vec { - let entries = fs::read_dir(path).unwrap(); - let mut documents: Vec = vec![]; - - for entry in entries { - let entry = entry.unwrap(); - let entry_path = entry.path(); - if entry_path.is_file() { - let name = entry_path.file_name().unwrap().to_string_lossy().into_owned(); - let data = read_file_data(&entry_path).unwrap_or_default(); - let json_value = parse_json_data(&data).ok(); - let document = Document { - name, - path: entry_path.clone(), - json_value, - }; - documents.push(document); - } - } - documents -} - -fn read_file_data(path: &Path) -> io::Result { - let mut file = fs::File::open(path)?; - let mut contents = String::new(); - file.read_to_string(&mut contents)?; - Ok(contents) -} - -fn parse_json_data(data: &str) -> JsonResult { - serde_json::from_str(data) -} - -fn get_exists_collections(path: &Path) -> Vec { - let mut collections: Vec = vec![]; - - if path.exists() && path.is_dir() { - let entries = fs::read_dir(path).unwrap(); - - for entry in entries { - let entry = entry.unwrap(); - let entry_path = entry.path(); - - if entry_path.is_dir() { - let documents = get_documents_in_collection(&entry_path); - let collection_name = entry_path.file_name().unwrap().to_string_lossy().into_owned(); - let collection = Collection { - name: collection_name, - documents, - }; - collections.push(collection); - } - } - } else { - error!("The specified path does not exist or is not a directory: {:?}", path); - } - - collections -} - -/// The main entry point for the application. -fn main() -> std::io::Result<()> { +fn prepare() -> std::io::Result { // Get the home directory let home_dir = env::home_dir().expect("Failed to get home directory"); let base_path = home_dir.join(ROOT_DIR); @@ -321,7 +32,6 @@ fn main() -> std::io::Result<()> { // Ensure the JSON engine directory exists fs::create_dir_all(&root_path).expect("Failed to create json_engine directory"); - // Generate a unique log filename using timestamp let timestamp = Local::now().format("%Y-%m-%d_%H-%M-%S").to_string(); let log_file_path = format!("{}/{}.adb.log", adb_logs_path.display(), timestamp); @@ -332,13 +42,44 @@ fn main() -> std::io::Result<()> { CombinedLogger::init( vec![ TermLogger::new(LevelFilter::Trace, log_config.clone(), TerminalMode::Mixed, ColorChoice::Auto), - WriteLogger::new(LevelFilter::Trace, log_config.clone(), fs::File::create(log_file_path).unwrap()), + WriteLogger::new(LevelFilter::Trace, log_config.clone(), fs::File::create(log_file_path).unwrap()), ] ).unwrap(); + Ok(root_path.clone()) + +} + +fn print_ascii() { + println!(r" + @---------------------------------------------------------------@ + | ______ __ __ ______ ______ | + | /\ __ \ /\ \ /\ \ /\ ___\ /\ ___\ | + | \ \ __ \ \ \ \____ \ \ \ \ \ \____ \ \ __\ | + | \ \_\ \_\ \ \_____\ \ \_\ \ \_____\ \ \_____\ | + | \/_/\/_/ \/_____/ \/_/ \/_____/ \/_____/ | + | | + | _____ ______ | + | /\ __-. /\ == \ | + | \ \ \/\ \ \ \ __< | + | \ \____- \ \_____\ | + | \/____/ \/_____/ | + | | + @---------------------------------------------------------------@ + ") +} + +/// The main entry point for the application. +fn main() -> std::io::Result<()> { + print_ascii(); + let root_path = match prepare() { + Ok(k) => k, + _ => panic!("Errors in prepare function."), + }; + trace!("Starting Collection Manager..."); - let mut manager = CollectionManager::new(&root_path); + let mut manager = JSONEngine::new(&root_path); // Create a new collection let collection_name = "collection1"; // Example collection name @@ -395,9 +136,91 @@ fn main() -> std::io::Result<()> { Ok(()) } -// Helper method to get a mutable reference to a document -impl CollectionManager { - pub fn get_document_mut(&mut self, collection_name: &str, document_name: &str) -> Option<&mut Document> { - self.get_collection_mut(collection_name)?.documents.iter_mut().find(|doc| doc.name == document_name) +#[cfg(test)] +mod tests { + use super::*; + use std::env; + use std::fs; + use std::path::{Path, PathBuf}; + use serde_json::json; + const TEST_ROOT_DIR: &str = "Alice-Database-Data-Test"; + const TEST_ADB_DATA_DIR: &str = "ADB_Data"; + const TEST_JSON_ENGINE_DIR: &str = "json_engine"; + + // Setup a temporary test directory + fn setup_test_dir() -> PathBuf { + let home_dir = env::temp_dir(); + let test_dir = home_dir.join(TEST_ROOT_DIR); + fs::create_dir_all(&test_dir).expect("Failed to create test directory"); + test_dir + } + + #[test] + fn test_create_and_add_document() { + let root_path = setup_test_dir(); + let mut manager = JSONEngine::new(&root_path); + + // Create a collection + manager.add_collection("test_collection").unwrap(); + let collection = manager.get_collection_mut("test_collection").unwrap(); + + // Add a document + let doc_content = json!({"code": 200, "success": true}).to_string(); + let result = collection.add_document("test_document.json", &doc_content); + assert!(result.is_ok()); + + // Verify the document is added + assert_eq!(collection.documents.len(), 1); + assert_eq!(collection.documents[0].name, "test_document.json"); + } + + #[test] + fn test_update_document() { + let root_path = setup_test_dir(); + let mut manager = JSONEngine::new(&root_path); + + // Create a collection and add a document + manager.add_collection("test_collection").unwrap(); + let collection = manager.get_collection_mut("test_collection").unwrap(); + let doc_content = json!({ + "code": 200, + "success": true, + "payload": { + "homepage": null + } + }).to_string(); + collection.add_document("test_document.json", &doc_content).unwrap(); + + // Update the homepage field + let doc = collection.get_document_mut("test_document.json").unwrap(); + let new_homepage_value = json!("https://new-homepage-url.com"); + + let update_result = doc.update_nested_field("payload", "homepage", &new_homepage_value); + assert!(update_result.is_ok()); + + // Check the updated value + assert_eq!(doc.json_value.as_ref().unwrap()["payload"]["homepage"], new_homepage_value); + } + + #[test] + fn test_delete_document() { + let root_path = setup_test_dir(); + let mut manager = JSONEngine::new(&root_path); + + // Create a collection and add a document + manager.add_collection("test_collection").unwrap(); + let collection = manager.get_collection_mut("test_collection").unwrap(); + collection.add_document("test_document.json", "{\"key\":\"value\"}").unwrap(); + + // Ensure the document exists before deletion + assert_eq!(collection.documents.len(), 1); + + // Delete the document + let delete_result = collection.delete_document("test_document.json"); + assert!(delete_result.is_ok()); + + // Verify the document was deleted + assert_eq!(collection.documents.len(), 0); } + } From 7e259e7d5a365e88fba636b93464a722c8caf06b Mon Sep 17 00:00:00 2001 From: Daniil Ermolaev Date: Thu, 24 Oct 2024 16:06:38 +0500 Subject: [PATCH 3/8] new version --- Plugins/Alice-Database/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Alice-Database/Cargo.toml b/Plugins/Alice-Database/Cargo.toml index 080fe2a..8ee6943 100644 --- a/Plugins/Alice-Database/Cargo.toml +++ b/Plugins/Alice-Database/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "Alice-Database_DBMS" -version = "1.0.0" +version = "1.0.1" edition = "2021" include = ["**/*.rs", "Cargo.toml"] license = "MIT" From 746fbd14d2e0ed67aa3fc23f4fa4b23b847195c1 Mon Sep 17 00:00:00 2001 From: Daniil Ermolaev Date: Thu, 24 Oct 2024 16:36:12 +0500 Subject: [PATCH 4/8] Bazel support and InstanceManager --- Plugins/Alice-Database/BUILD | 24 +++++++++++ Plugins/Alice-Database/Cargo.toml | 3 +- Plugins/Alice-Database/WORKSPACE.bazel | 40 ++++++++++++++++++ Plugins/Alice-Database/src/engines.rs | 6 +++ Plugins/Alice-Database/src/instance.rs | 47 +++++++++++++++++++++ Plugins/Alice-Database/src/json_engine.rs | 7 +-- Plugins/Alice-Database/src/main.rs | 24 +++++++++-- Plugins/Alice-Database/src/sqlite_engine.rs | 1 + 8 files changed, 145 insertions(+), 7 deletions(-) create mode 100644 Plugins/Alice-Database/BUILD create mode 100644 Plugins/Alice-Database/WORKSPACE.bazel create mode 100644 Plugins/Alice-Database/src/engines.rs create mode 100644 Plugins/Alice-Database/src/sqlite_engine.rs diff --git a/Plugins/Alice-Database/BUILD b/Plugins/Alice-Database/BUILD new file mode 100644 index 0000000..7a9acef --- /dev/null +++ b/Plugins/Alice-Database/BUILD @@ -0,0 +1,24 @@ +visibility = ["//visibility:public"] + +load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_test", "rust_library") +load("@crate_index//:defs.bzl", "aliases", "all_crate_deps") + + +rust_library( + name = "alice_db_lib", + + # Specifies the source file for the binary. + srcs = glob([ + "src/*.rs", + "src/**/*.rs", + ]), + aliases = aliases(), + #proc_macro_deps = all_crate_deps(), + #deps = [ + # all_crate_deps(normal=True) + #], + deps = all_crate_deps(normal = True), + # Specifies the Rust edition to use for this binary. + edition = "2021" +) + diff --git a/Plugins/Alice-Database/Cargo.toml b/Plugins/Alice-Database/Cargo.toml index 8ee6943..b04cc38 100644 --- a/Plugins/Alice-Database/Cargo.toml +++ b/Plugins/Alice-Database/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "Alice-Database_DBMS" -version = "1.0.1" +version = "1.1.0" edition = "2021" include = ["**/*.rs", "Cargo.toml"] license = "MIT" @@ -16,6 +16,7 @@ log = "0.4.22" serde = { version = "1.0.213", features = ["derive"] } serde_json = "1.0.132" simplelog = "0.12.2" +uuid = { version = "1.11.0", features = ["v4"] } [[test]] name = "tests" diff --git a/Plugins/Alice-Database/WORKSPACE.bazel b/Plugins/Alice-Database/WORKSPACE.bazel new file mode 100644 index 0000000..6c17f66 --- /dev/null +++ b/Plugins/Alice-Database/WORKSPACE.bazel @@ -0,0 +1,40 @@ +# Загрузка необходимых внешних репозиториев +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +# <========== Настройка Rust для проекта =================== +http_archive( + name = "rules_rust", + integrity = "sha256-Weev1uz2QztBlDA88JX6A1N72SucD1V8lBsaliM0TTg=", + urls = ["https://github.com/bazelbuild/rules_rust/releases/download/0.48.0/rules_rust-v0.48.0.tar.gz"], +) + +# Загрузка зависимостей для Rust +load("@rules_rust//rust:repositories.bzl", "rules_rust_dependencies", "rust_register_toolchains") +rules_rust_dependencies() +rust_register_toolchains() + +# Загрузка зависимостей для Rust Analyzer для улучшенной разработки +load("@rules_rust//tools/rust_analyzer:deps.bzl", "rust_analyzer_dependencies") +rust_analyzer_dependencies() + +# Загрузка зависимостей для управления версиями crate +load("@rules_rust//crate_universe:repositories.bzl", "crate_universe_dependencies") +crate_universe_dependencies() + +# Определение репозитория для crate +load("@rules_rust//crate_universe:defs.bzl", "crates_repository", "crate") +crates_repository( + name = "crate_index", + cargo_lockfile = "//:Cargo.lock", # Путь к вашему Cargo.lock + lockfile = "//:Cargo.Bazel.lock", # Путь к вашему замороженному файлу Bazel + manifests = [ + "//:Cargo.toml", # Путь к вашему Cargo.toml + ], + # Должен соответствовать версии, представленной текущим зарегистрированным `rust_toolchain`. + rust_version = "1.81.0", +) + +# Загрузка всех crated из crate_index +load("@crate_index//:defs.bzl", "crate_repositories") +crate_repositories() + diff --git a/Plugins/Alice-Database/src/engines.rs b/Plugins/Alice-Database/src/engines.rs new file mode 100644 index 0000000..79c509e --- /dev/null +++ b/Plugins/Alice-Database/src/engines.rs @@ -0,0 +1,6 @@ +use crate::json_engine::JSONEngine; + +#[derive(Debug, Clone)] +pub enum Engines { + JSONEngine(JSONEngine), +} \ No newline at end of file diff --git a/Plugins/Alice-Database/src/instance.rs b/Plugins/Alice-Database/src/instance.rs index 063fa5a..9e46d43 100644 --- a/Plugins/Alice-Database/src/instance.rs +++ b/Plugins/Alice-Database/src/instance.rs @@ -1,2 +1,49 @@ +use crate::Engines; +use uuid::Uuid; +use std::path::PathBuf; +use crate::JSONEngine; #[derive(Debug, Clone)] +pub struct Instance { + pub name: String, + pub engine: Engines, +} + +#[derive(Debug, Clone)] +pub struct InstanceManger { + pub name: String, + pub instances: Vec +} + + +impl InstanceManger { + pub fn new() -> Self { + let name = Uuid::new_v4().to_string(); + let mut instances: Vec = vec![]; + Self {name, instances} + } + + pub fn create_instance(&mut self, engine_type: &str, root_path: &PathBuf) -> String { + let instance_name: String = Uuid::new_v4().to_string(); + + let mut engine = match engine_type { + "json_engine" => Engines::JSONEngine(JSONEngine::new(&root_path)), + _ => panic!("Engine not found"), + }; + let mut instance = Instance {engine, name: instance_name.clone()}; + self.instances.push(instance); + instance_name + } + // Method to mutate the engine of an existing instance + + pub fn get_mutable_engine(&mut self, instance_name: &str) -> Option<&mut JSONEngine> { + for instance in &mut self.instances { + if instance.name == instance_name { + if let Engines::JSONEngine(ref mut engine) = instance.engine { + return Some(engine); + } + } + } + None + } +} \ No newline at end of file diff --git a/Plugins/Alice-Database/src/json_engine.rs b/Plugins/Alice-Database/src/json_engine.rs index 9843aa7..165f551 100644 --- a/Plugins/Alice-Database/src/json_engine.rs +++ b/Plugins/Alice-Database/src/json_engine.rs @@ -17,7 +17,7 @@ const JSON_ENGINE_DIR: &str = "json_engine"; /// A struct representing a document in the database. /// /// A `Document` contains its name, file path, and its content stored as a JSON `Value`. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Document { pub name: String, pub path: PathBuf, @@ -27,7 +27,7 @@ pub struct Document { /// A struct representing a collection of documents. /// /// A `Collection` holds a name and a list of associated `Document`s. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Collection { pub name: String, pub documents: Vec, @@ -88,6 +88,7 @@ impl Collection { } /// A struct to manage multiple collections of documents. +#[derive(Debug, Clone)] pub struct JSONEngine { collections: Vec, } @@ -100,7 +101,7 @@ impl JSONEngine { /// /// # Returns /// A new instance of `JSONEngine`. - pub fn new(root: &Path) -> Self { + pub fn new(root: &Path, ) -> Self { let collections = get_exists_collections(root); JSONEngine { collections } } diff --git a/Plugins/Alice-Database/src/main.rs b/Plugins/Alice-Database/src/main.rs index a4e5023..fc867ec 100644 --- a/Plugins/Alice-Database/src/main.rs +++ b/Plugins/Alice-Database/src/main.rs @@ -9,7 +9,10 @@ use std::env; // Import this for getting the home directory pub mod json_engine; use json_engine::*; - +pub mod engines; +use engines::Engines; +pub mod instance; +use instance::*; // Define constants for the root path and log path const ROOT_DIR: &str = "Alice-Database-Data"; const ADB_DATA_DIR: &str = "ADB_Data"; @@ -69,13 +72,27 @@ fn print_ascii() { } -/// The main entry point for the application. -fn main() -> std::io::Result<()> { + +/* Usage example via InstanceManager; +fn main() { print_ascii(); let root_path = match prepare() { Ok(k) => k, _ => panic!("Errors in prepare function."), }; + + let mut im = InstanceManger::new(); + let instance_name = im.create_instance("json_engine", &root_path); + //println!("{:#?}", im); + let mut engine = im.get_mutable_engine(instance_name.as_str()); + println!("{:#?}", im); + +} + +/// The main entry point for the application. +fn main() -> std::io::Result<()> { + print_ascii(); + trace!("Starting Collection Manager..."); @@ -135,6 +152,7 @@ fn main() -> std::io::Result<()> { Ok(()) } +*/ #[cfg(test)] mod tests { diff --git a/Plugins/Alice-Database/src/sqlite_engine.rs b/Plugins/Alice-Database/src/sqlite_engine.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/Plugins/Alice-Database/src/sqlite_engine.rs @@ -0,0 +1 @@ + From d9b929561fb5a724cb217bdfbbbf3c7216b98a62 Mon Sep 17 00:00:00 2001 From: Daniil Ermolaev Date: Thu, 24 Oct 2024 16:36:41 +0500 Subject: [PATCH 5/8] forgot main function xD --- Plugins/Alice-Database/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Plugins/Alice-Database/src/main.rs b/Plugins/Alice-Database/src/main.rs index fc867ec..bfa39a8 100644 --- a/Plugins/Alice-Database/src/main.rs +++ b/Plugins/Alice-Database/src/main.rs @@ -73,7 +73,7 @@ fn print_ascii() { -/* Usage example via InstanceManager; + Usage example via InstanceManager; fn main() { print_ascii(); let root_path = match prepare() { @@ -88,7 +88,7 @@ fn main() { println!("{:#?}", im); } - +/* /// The main entry point for the application. fn main() -> std::io::Result<()> { print_ascii(); From 572843cdce6b6c5b240e45211a5f0fc3a250e09d Mon Sep 17 00:00:00 2001 From: Daniil Ermolaev Date: Thu, 24 Oct 2024 16:37:26 +0500 Subject: [PATCH 6/8] no comments... --- Plugins/Alice-Database/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Alice-Database/src/main.rs b/Plugins/Alice-Database/src/main.rs index bfa39a8..1fb3a2c 100644 --- a/Plugins/Alice-Database/src/main.rs +++ b/Plugins/Alice-Database/src/main.rs @@ -73,7 +73,7 @@ fn print_ascii() { - Usage example via InstanceManager; + fn main() { print_ascii(); let root_path = match prepare() { From 41a447dbde4ce8d49f55247eefb75f05564711b1 Mon Sep 17 00:00:00 2001 From: Daniil Ermolaev Date: Thu, 24 Oct 2024 17:38:29 +0500 Subject: [PATCH 7/8] gRPC connected! --- Plugins/Alice-Database/Cargo.toml | 7 ++ Plugins/Alice-Database/build.rs | 4 + Plugins/Alice-Database/proto/instance.proto | 40 +++++++++ Plugins/Alice-Database/src/grpc.rs | 71 ++++++++++++++++ Plugins/Alice-Database/src/instance.rs | 9 +- Plugins/Alice-Database/src/main.rs | 91 ++++++++++++++++++++- 6 files changed, 218 insertions(+), 4 deletions(-) create mode 100644 Plugins/Alice-Database/build.rs create mode 100644 Plugins/Alice-Database/proto/instance.proto create mode 100644 Plugins/Alice-Database/src/grpc.rs diff --git a/Plugins/Alice-Database/Cargo.toml b/Plugins/Alice-Database/Cargo.toml index b04cc38..5292534 100644 --- a/Plugins/Alice-Database/Cargo.toml +++ b/Plugins/Alice-Database/Cargo.toml @@ -13,11 +13,18 @@ homepage = "https://github.com/0xBLCKLPTN/Kingdom-System" chrono = "0.4.38" env_logger = "0.11.5" log = "0.4.22" +prost = "0.13.3" serde = { version = "1.0.213", features = ["derive"] } serde_json = "1.0.132" simplelog = "0.12.2" +tokio = { version = "1.41.0", features = ["full"] } +tonic = "0.12.3" uuid = { version = "1.11.0", features = ["v4"] } [[test]] name = "tests" path = "src/main.rs" + + +[build-dependencies] +tonic-build = "0.12.3" diff --git a/Plugins/Alice-Database/build.rs b/Plugins/Alice-Database/build.rs new file mode 100644 index 0000000..163bdbd --- /dev/null +++ b/Plugins/Alice-Database/build.rs @@ -0,0 +1,4 @@ + +fn main() { + tonic_build::compile_protos("proto/instance.proto").unwrap(); +} diff --git a/Plugins/Alice-Database/proto/instance.proto b/Plugins/Alice-Database/proto/instance.proto new file mode 100644 index 0000000..682771e --- /dev/null +++ b/Plugins/Alice-Database/proto/instance.proto @@ -0,0 +1,40 @@ +syntax = "proto3"; + +package instance; + +// Message definitions +message Instance { + string name = 1; + string engine = 2; +} + +message CreateInstanceRequest { + string engine_type = 1; + string root_path = 2; +} + +message CreateInstanceResponse { + string instance = 1; +} + +message GetInstanceRequest { + string instance_name = 1; +} + +message GetInstanceResponse { + string instance = 1; // Returning the instance +} + +message GetAllInstancesRequest { + string message = 1; +} + +message GetAllInstancesResponse { + repeated Instance instances = 1; +} + +service InstanceService { + rpc CreateInstance(CreateInstanceRequest) returns (CreateInstanceResponse); + rpc GetInstance(GetInstanceRequest) returns (GetInstanceResponse); + rpc GetAllInstances(GetAllInstancesRequest) returns (GetAllInstancesResponse); +} diff --git a/Plugins/Alice-Database/src/grpc.rs b/Plugins/Alice-Database/src/grpc.rs new file mode 100644 index 0000000..d2b7996 --- /dev/null +++ b/Plugins/Alice-Database/src/grpc.rs @@ -0,0 +1,71 @@ +use tonic::{transport::Server, Request, Response, Status}; +use uuid::Uuid; +use std::path::PathBuf; +use std::sync::{Arc, Mutex}; + +// Import generated gRPC code +pub mod instance { + tonic::include_proto!("instance"); +} + +use instance::{InstanceService, CreateInstanceRequest, CreateInstanceResponse, + GetInstanceRequest, GetInstanceResponse, Instance}; + +// Engines enum represents the types of engines +#[derive(Debug, Clone)] +pub enum Engines { + JSONEngine(JSONEngine), +} + +// Your JSONEngine structure +#[derive(Debug, Clone)] +pub struct JSONEngine { + // Add fields necessary for your JSON engine +} + +impl JSONEngine { + pub fn new(_root_path: &PathBuf) -> Self { + // Initialize your JSONEngine as needed + Self {} + } +} + +// Instance structure +#[derive(Debug, Clone, Default)] +pub struct Instance { + pub name: String, + pub engine: Engines, +} + +// InstanceManager struct to manage instances +#[derive(Debug, Default)] +pub struct InstanceManager { + pub name: String, + pub instances: Vec, +} + +impl InstanceManager { + pub fn new() -> Self { + let name = Uuid::new_v4().to_string(); + let instances: Vec = vec![]; + Self { name, instances } + } + + pub fn create_instance(&mut self, engine_type: &str, root_path: &PathBuf) -> String { + let instance_name: String = Uuid::new_v4().to_string(); + + let engine = match engine_type { + "json_engine" => Engines::JSONEngine(JSONEngine::new(root_path)), + _ => panic!("Engine not found"), + }; + + let instance = Instance { engine, name: instance_name.clone() }; + self.instances.push(instance); + instance_name + } + + pub fn get_instance(&self, instance_name: &str) -> Option<&Instance> { + self.instances.iter().find(|i| i.name == instance_name) + } +} + diff --git a/Plugins/Alice-Database/src/instance.rs b/Plugins/Alice-Database/src/instance.rs index 9e46d43..3f9f7a7 100644 --- a/Plugins/Alice-Database/src/instance.rs +++ b/Plugins/Alice-Database/src/instance.rs @@ -9,14 +9,14 @@ pub struct Instance { pub engine: Engines, } -#[derive(Debug, Clone)] -pub struct InstanceManger { +#[derive(Debug, Clone, Default)] +pub struct InstanceManager { pub name: String, pub instances: Vec } -impl InstanceManger { +impl InstanceManager { pub fn new() -> Self { let name = Uuid::new_v4().to_string(); let mut instances: Vec = vec![]; @@ -34,6 +34,9 @@ impl InstanceManger { self.instances.push(instance); instance_name } + pub fn get_instance(&self, instance_name: &str) -> Option<&Instance> { + self.instances.iter().find(|i| i.name == instance_name) + } // Method to mutate the engine of an existing instance pub fn get_mutable_engine(&mut self, instance_name: &str) -> Option<&mut JSONEngine> { diff --git a/Plugins/Alice-Database/src/main.rs b/Plugins/Alice-Database/src/main.rs index 1fb3a2c..e2148b1 100644 --- a/Plugins/Alice-Database/src/main.rs +++ b/Plugins/Alice-Database/src/main.rs @@ -13,6 +13,23 @@ pub mod engines; use engines::Engines; pub mod instance; use instance::*; + +use crate::instance::InstanceManager; + + +use tonic::{transport::Server, Request, Response, Status}; +use uuid::Uuid; +use std::sync::{Arc, Mutex}; + +pub mod instance_g { + tonic::include_proto!("instance"); +} +pub use instance_g::{CreateInstanceRequest, CreateInstanceResponse, + GetInstanceRequest, GetInstanceResponse, GetAllInstancesRequest, GetAllInstancesResponse}; + +use crate::instance_g::instance_service_server::InstanceServiceServer; +use crate::instance_g::instance_service_server::InstanceService; + // Define constants for the root path and log path const ROOT_DIR: &str = "Alice-Database-Data"; const ADB_DATA_DIR: &str = "ADB_Data"; @@ -71,9 +88,81 @@ fn print_ascii() { ") } +// Define the gRPC service +#[derive(Debug, Default)] +pub struct MyInstanceManager { + pub instances: Arc>, +} + +#[tonic::async_trait] +impl InstanceService for MyInstanceManager { + + async fn create_instance( + &self, + request: Request, + ) -> Result, Status> { + let inner = request.into_inner(); + let engine_type = inner.engine_type; + let root_path = PathBuf::from(inner.root_path); // assuming root_path is a string path + let mut manager = self.instances.lock().unwrap(); + let id = manager.create_instance(&engine_type,&root_path); + + let response = CreateInstanceResponse { instance: id }; + Ok(Response::new(response)) + } + + /// Get an existing instance by name + + async fn get_instance( + &self, + request: Request, + ) -> Result, Status> { + let instance_name = request.into_inner().instance_name; + // Lock the mutex to safely access the manager + let manager = self.instances.lock().unwrap(); + // Retrieve the instance by name + if let Some(instance) = manager.get_instance(&instance_name) { + return Ok(Response::new(GetInstanceResponse { + instance: instance.name.clone(), // Clone the entire instance + })); + } + Err(Status::not_found("Instance not found")) + } + + async fn get_all_instances( + &self, + request: Request, + ) -> Result, Status> { + let manager = self.instances.lock().unwrap(); + let mut re_instances: Vec = vec![]; + for i in &manager.instances { + re_instances.push(instance_g::Instance {name: i.name.clone(), engine: "unknown".into()} ); + } + let response = GetAllInstancesResponse { instances: re_instances }; + Ok(Response::new(response)) + + } +} + + +// Main function to start the gRPC server +#[tokio::main] +async fn main() -> Result<(), Box> { + let instance_manager = MyInstanceManager { + instances: Arc::new(Mutex::new(InstanceManager::new())), + }; + + println!("Starting gRPC server..."); + Server::builder() + .add_service(InstanceServiceServer::new(instance_manager)) + .serve("[::1]:50051".parse()?) + .await?; + Ok(()) +} +/* fn main() { print_ascii(); let root_path = match prepare() { @@ -88,7 +177,7 @@ fn main() { println!("{:#?}", im); } -/* + /// The main entry point for the application. fn main() -> std::io::Result<()> { print_ascii(); From 7522fe5c2c49c8bfe7fd866d55b413bca0560be9 Mon Sep 17 00:00:00 2001 From: Daniil Ermolaev Date: Thu, 24 Oct 2024 17:39:14 +0500 Subject: [PATCH 8/8] save --- Plugins/Alice-Database/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Alice-Database/Cargo.toml b/Plugins/Alice-Database/Cargo.toml index 5292534..4e7c197 100644 --- a/Plugins/Alice-Database/Cargo.toml +++ b/Plugins/Alice-Database/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "Alice-Database_DBMS" -version = "1.1.0" +version = "1.2.0" edition = "2021" include = ["**/*.rs", "Cargo.toml"] license = "MIT"