wip: add a thread safe way to access items; change upsert wip: change catalog.delete to be thread safe wip: change catalog.load_by_* to be thread safe wip: add a thread safe way to access items in readonly mode; change catalog.get wip: change catalog.persist to be thread safe wip: disable examples temprarily wip: remove catalog_new.rs file wip: ignore result of iteration wip: disable lib example wip: enable catalog.delete tests wip: enable catalog.get tests wip enalbe catalog.init tests wip: enable catalog.insert_many tests wip: enable catalog.load_by_class tests wip: enable catalog.load_by_id tests wip: add len() and is_empty() convenience thread safe method to catalog wip: use convenience methods for len and is_empty checks wip: enable catalog.load_by_id and catalog.new tests wip: enable catalog.upsert tests wip: enable catalog.persist test; add catalog.contains_key wip: enable catalog.load_by_filter tests wip: enable sqlite_* tests wip: enable list_by_class with tests wip: enable list_by_class_and_subclass with tests wip: enable integration tests wip: switch iter to into_iter for tests
heave
A Rust EAV data model implementation.
Heave is a Rust library that provides a flexible and extensible implementation of the Entity-Attribute-Value (EAV) data model. It allows you to manage data with a dynamic schema, making it suitable for scenarios where attributes of entities are not known at compile time. The library includes support for persisting the EAV data to a SQLite database.
🚧 A Note From the Developer 🚧
Thank you for checking out Heave! I'm so excited you're here and interested in my project at this early stage.
I want to be upfront: this is my work-in-progress, and I'm still building and experimenting a lot. This means things are changing constantly. As you dive in, please keep in mind:
- I'll be making frequent breaking changes. I'm still shaping the core API, so I'll be refactoring things often. Your code will likely break between updates.
- You'll find bugs. I'm working hard, but things might not always work as expected. I'd be incredibly grateful if you reported any issues you find!
- Features are incomplete. Many parts of the project are still on my drawing board or only partially implemented.
Because of all this, I'm asking you to use Heave for evaluation and feedback only. I strongly recommend not using it in a production environment just yet.
Your feedback is invaluable in helping me shape the future of Heave. I'd love to hear from you, so please feel free to open an issue!
Typed Entities
Typed entities may be used leveraging the EAV trait to map to and from schemaless entities.
EAV
Learn more on EAV data model here.
Workspace Structure
- 01.workspace: this folder contains all workspace crates
heave crate structure
- src/fun: contains all functions
- src/imp: contains all implementation (impl blocks)
- src/mcr: contains all macros
- src/str: contains all structures
- src/trt: contains all traits
- src/tst: contains all tests
- lib.rs: renames and re-exports code compnents
Example
Here is an example of how to define a typed entity, persist it to a SQLite database, and load it back.
use heave::*;
// Define a struct named `Product` to represent a product.
struct Product {
// `id` is a public field of type `String` to uniquely identify the product.
pub id: String,
// `name` is a public field of type `String` for the product's name.
pub name: String,
// `model` is a public optional field of type `String` for the product's model.
pub model: Option<String>,
// `price` is a public field of type `i64` for the product's price.
pub price: i64,
}
// Implement the `EAV` trait for the `Product` struct.
impl EAV for Product {
// `class` is a function that returns the class name of the entity.
fn class() -> &'static str {
"product"
}
}
// Implement the `From<Product>` trait for the `Entity` struct.
impl From<Product> for Entity {
// `from` is a function that converts a `Product` into an `Entity`.
fn from(value: Product) -> Entity {
// Create a new `Entity` for the `Product` class.
Entity::new::<Product>()
// Set the entity's ID from the product's ID.
.with_id(&value.id)
// Add the "name" attribute with the product's name.
.with_attribute("name", value.name)
// Add the optional "model" attribute with the product's model.
.with_opt_attribute("model", value.model)
// Add the "price" attribute with the product's price.
.with_attribute("price", value.price)
}
}
// Implement the `From<Entity>` trait for the `Product` struct.
impl From<Entity> for Product {
// `from` is a function that converts an `Entity` into a `Product`.
fn from(value: Entity) -> Self {
// Create a new `Product` from the entity's attributes.
Self {
// Set the product's ID from the entity's ID.
id: value.id.clone(),
// Unwrap the "name" attribute to get the product's name.
name: value.unwrap("name"),
// Unwrap the optional "model" attribute to get the product's model.
model: value.unwrap_opt("model"),
// Unwrap the "price" attribute to get the product's price.
price: value.unwrap("price"),
}
}
}
fn main() {
// Define the path for the SQLite database file.
let db_path = "./simple_product.sqlite3";
// Create a new `Catalog` instance with the specified database path.
let mut catalog = Catalog::new(db_path);
// Initialize the catalog, which sets up the database.
catalog.init().unwrap();
// Create a new `Product` instance representing a laptop.
let new_laptop = Product {
id: "LT001".to_string(),
name: "SuperPenguin".to_string(),
model: Some("Mark III.2".to_string()),
price: 125000,
};
// Insert the new laptop into the catalog. Note that at this time the product is in memory.
catalog.upsert(new_laptop);
// Persist the changes in the catalog to the database.
catalog.persist().unwrap();
// Remove the SQLite database file.
std::fs::remove_file(db_path).unwrap();
}
Contributing
Contributions are welcome! If you'd like to contribute to heave, please follow these steps:
- Fork the repository.
- Create a new branch for your feature (feature/my_awesome_feature) or bug fix (fix/my_awesome_fix).
- Make your changes and commit them with a clear message.
- Push your branch to your fork.
- Open a pull request to the main repository.
Please ensure that your code adheres to the existing style and that all tests pass before submitting a pull request.
Credits
- Project Icon: by SmashIcons