129 lines
4.7 KiB
Markdown
129 lines
4.7 KiB
Markdown
# 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.
|
|
|
|
## 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](https://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model).
|
|
|
|
## 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.
|
|
|
|
```rust
|
|
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.insert(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:
|
|
|
|
1. Fork the repository.
|
|
2. Create a new branch for your feature (feature/my_awesome_feature) or bug fix (fix/my_awesome_fix).
|
|
3. Make your changes and commit them with a clear message.
|
|
4. Push your branch to your fork.
|
|
5. 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](https://www.flaticon.com/authors/smashicons)
|