#deserialize-json #serialize-deserialize #serde-json #database #applications #struct #configuration

struct-to-json-db

A minimalist file-based database designed for straightforward software applications. It leverages the Serde crate to seamlessly serialize and deserialize a HashMap of structured data to and from JSON files, ensuring simplicity and ease of use.

24 releases

0.1.23 Jan 15, 2025
0.1.22 Dec 19, 2024
0.1.20 Aug 29, 2024

#523 in Encoding

Download history 111/week @ 2024-10-02 18/week @ 2024-10-09 4/week @ 2024-10-30 140/week @ 2024-12-04 21/week @ 2024-12-11 104/week @ 2024-12-18 2/week @ 2025-01-08 140/week @ 2025-01-15

142 downloads per month

Apache-2.0

23KB
260 lines

struct-to-json-db

Crates.io Build Status License

struct-to-json-db is a minimalist, file-based database tailored for straightforward Rust applications. Leveraging the power of the Serde crate, it effortlessly serializes and deserializes structured data stored as JSON files. This ensures simplicity, flexibility, and ease of integration for developers seeking a lightweight database solution without the overhead of setting up complex systems.

Table of Contents

Features

  • Automatic ID Generation: Automatically generate unique identifiers for your structs.
  • Serialization & Deserialization: Seamlessly convert structs to and from JSON files.
  • Singleton Support: Manage singleton configurations effortlessly.
  • Unique Keys: Enforce uniqueness on specified fields to maintain data integrity.
  • Big Size Handling: Split large datasets into multiple JSON files for efficient data management.
  • Data Encryption: Protect sensitive data using environment-based encryption keys.
  • Relationship Management: Define and manage relationships between different data structs.

Example Code

For a practical example, visit the example code repository.

Getting Started

Installation

To integrate struct-to-json-db into your project, add it to your Cargo.toml:

[dependencies]
struct-to-json-db = "x.x.x"  # Replace x.x.x with the latest version

Alternatively, you can specify the GitHub repository directly:

[dependencies]
struct-to-json-db = { git = "https://github.com/acscoder/struct-to-json-db.git" }

Note: Always check crates.io for the latest version.

Configuration

Before using the database, configure the directory where your JSON files will be stored:

use struct_to_json_db::set_struct_json_path;

fn main() {
    set_struct_json_path("./db/"); // Ensure the path ends with a slash (/)
}

Important: The path must end with a slash (/). For example, ./db/ is correct, whereas ./db is incorrect.

Usage

Adding the Macro to Your Struct

Use the #[auto_json_db] attribute macro to automatically add functionalities such as unique ID generation and data management methods to your structs.

Basic Usage

use struct_to_json_db::auto_json_db;
use serde::{Deserialize, Serialize};

#[auto_json_db]
#[derive(Serialize, Deserialize, Debug)]
struct YourStruct {
    // Your fields here
}

With Unique Key

Enforce uniqueness on specific fields by specifying the unique attribute:

use struct_to_json_db::auto_json_db;
use serde::{Deserialize, Serialize};

#[auto_json_db(unique = "your_unique_key")]
#[derive(Serialize, Deserialize, Debug)]
struct YourStruct {
    // Your fields here
}

Handling Large Structs

For structs with large datasets, use the bigsize attribute to split data into multiple files, enhancing performance and manageability:

use struct_to_json_db::auto_json_db;
use serde::{Deserialize, Serialize};

#[auto_json_db(bigsize, unique = "your_unique_key")]
#[derive(Serialize, Deserialize, Debug)]
struct YourStruct {
    // Your fields here
}

Singleton Structs

Manage singleton configurations using the singleton attribute:

use struct_to_json_db::auto_json_db;
use serde::{Deserialize, Serialize};

#[auto_json_db(singleton)]
#[derive(Serialize, Deserialize, Debug)]
struct Config {
    // Configuration fields
}

Defining Relationships

Establish relationships between different structs using the json_db_relation! macro. This facilitates relational data management, akin to foreign keys in traditional databases.

use struct_to_json_db::json_db_relation;

// Example: One Post has many Categories
json_db_relation!(Post = categories, Category);

// Example: One-to-One Relationship
json_db_relation!(Post = categories, Category, "1-1");

Encryption Support

Protect sensitive data by encrypting JSON files. Define an environment variable as your encryption key and specify it in the macro:

  1. Set Up Environment Variable:

    Create a .env file in your project root:

    APP_SECRET_KEY=your_secret_key
    
  2. Load Environment Variables:

    Use the dotenv crate to load the .env file:

    use dotenv::dotenv;
    
    fn main() {
        dotenv().ok();
        // Your code here
    }
    
  3. Apply Encryption in Macro:

    use struct_to_json_db::auto_json_db;
    use serde::{Deserialize, Serialize};
    use dotenv::dotenv;
    
    #[auto_json_db(encript = "APP_SECRET_KEY")]
    #[derive(Serialize, Deserialize, Debug)]
    struct SensitiveData {
        // Sensitive fields
    }
    

Note: The encript attribute requires the specified environment variable (APP_SECRET_KEY in this case) to be set. It uses this key to encrypt and decrypt your JSON data.

API Overview

The #[auto_json_db] macro enriches your structs with a suite of methods to facilitate data management:

  • Unique ID (idx): Automatically adds a unique identifier (u64 or String) to the struct.
  • Constructor (new): Creates new instances of the struct.
  • CRUD Operations:
    • get_all(): Retrieves all saved instances as a HashMap<idx, Struct>.
    • save(): Saves a single instance to the JSON file.
    • save_vec(v: Vec<Struct>): Saves multiple instances at once.
    • get_by_id(id: idx): Fetches an instance by its unique ID.
    • remove_by_id(id: idx): Removes an instance by its unique ID.
    • clear(): Deletes all instances from the JSON file.
  • Relationship Methods: Manage relations between different structs as defined by json_db_relation!.
  • Encryption Handling:
    • set_data_string(file_path, db_string): Encrypts and writes data if encryption is enabled.
    • get_data_string(file_path): Decrypts and reads data if encryption is enabled.

Example

Below is a comprehensive example demonstrating the usage of struct-to-json-db with encryption, unique keys, big size handling, and relationships.

use struct_to_json_db::*;
use serde::{Deserialize, Serialize};
use dotenv::dotenv;

#[auto_json_db(singleton, encript = "APP_SECRET_KEY")]
#[derive(Serialize, Deserialize, Debug)]
struct SiteConfig {
    url: String,
    limit: i32,
}

impl SiteConfig {
    fn default() -> Self {
        Self::new("".to_owned(), 0)
    }
}

#[auto_json_db(bigsize, unique = "title")]
#[derive(Serialize, Deserialize, Debug)]
struct Post {
    title: String,
    description: String,
    categories: Vec<u64>,
}

#[auto_json_db(unique = "name")]
#[derive(Serialize, Deserialize, Debug)]
struct Category {
    name: String,
}

json_db_relation!(Post = categories, Category);

fn main() {
    // Load environment variables from .env file
    dotenv().ok();

    // Set the directory for JSON database files
    set_struct_json_path("./db/");

    // Load the singleton SiteConfig
    let mut config = SiteConfig::load();
    println!("Site Config: {:?}", config);

    // Retrieve all posts
    let all_posts = Post::get_all();
    println!("Number of posts: {}", all_posts.len());

    // Create and save categories
    let category1 = Category::new("Technology".to_owned());
    let category2 = Category::new("Health".to_owned());
    category1.save();
    category2.save();

    // Add a new post with assigned categories
    let post_id = add_post(
        "Rust Programming".to_owned(),
        "An introduction to Rust.".to_owned(),
        &vec![category1, category2],
    );
    println!("New Post ID: {:?}", post_id);
}

fn add_post(title: String, description: String, categories: &Vec<Category>) -> Option<u64> {
    let mut post = Post::new(title, description, vec![]);
    if !categories.is_empty() {
        post.set_categories(categories);
    }
    post.save()
}

Explanation

  1. SiteConfig Struct:

    • Marked as a singleton with encryption enabled.
    • Automatically loads and saves the configuration to ./db/SiteConfig.json.
  2. Post Struct:

    • Configured with bigsize to handle large datasets by splitting into multiple files.
    • Enforces uniqueness on the title field.
  3. Category Struct:

    • Enforces uniqueness on the name field.
  4. Relationships:

    • Defined a one-to-many relationship where a Post can have multiple Categories.
  5. Main Function:

    • Initializes environment variables and sets the database path.
    • Loads the singleton configuration.
    • Retrieves and prints the number of posts.
    • Creates and saves new categories.
    • Adds a new post associated with the created categories.

Contributing

Contributions are highly encouraged! Whether it's reporting bugs, suggesting features, or submitting pull requests, your input helps make struct-to-json-db better for everyone.

  1. Fork the Repository: Click the Fork button at the top right of the repository page.

  2. Clone Your Fork:

    git clone https://github.com/your-username/struct-to-json-db.git
    cd struct-to-json-db
    
  3. Create a Feature Branch:

    git checkout -b feature/your-feature-name
    
  4. Commit Your Changes:

    git commit -m "Add your message here"
    
  5. Push to Your Fork:

    git push origin feature/your-feature-name
    
  6. Create a Pull Request: Navigate to your fork on GitHub, switch to your feature branch, and click the New Pull Request button.

License

This project is licensed under the Apache License 2.0. You are free to use, modify, and distribute this software as per the terms of the license.


Happy Coding! 🚀

Dependencies

~4–5.5MB
~104K SLoC