From e1178f712645e28edfa76fcf430e39b4f84fcaca Mon Sep 17 00:00:00 2001 From: davidemazzocchi Date: Wed, 29 Oct 2025 11:29:36 +0100 Subject: [PATCH] chore: restore examples after thread safety feature --- 01.workspace/heave/examples/using_filters.rs | 321 ++++++------ .../heave/examples/working_with_many_types.rs | 464 +++++++++--------- 2 files changed, 397 insertions(+), 388 deletions(-) diff --git a/01.workspace/heave/examples/using_filters.rs b/01.workspace/heave/examples/using_filters.rs index 4d9b02f..d5ae6c9 100644 --- a/01.workspace/heave/examples/using_filters.rs +++ b/01.workspace/heave/examples/using_filters.rs @@ -1,160 +1,161 @@ -fn main() {} -// use heave::*; -// -// // Define a struct named `Component` to represent an electronic component. -// #[derive(Debug, Clone, PartialEq)] -// struct Component { -// pub id: String, -// pub part_number: String, -// pub kind: String, -// pub value: u64, -// pub package: String, -// pub in_stock: bool, -// } -// // Implement the `EAV` trait for the `Component` struct. -// impl EAV for Component { -// // `class` is a function that returns the class name of the entity. -// fn class() -> &'static str { -// "component" -// } -// } -// // Implement the `From` trait for the `Entity` struct. -// impl From for Entity { -// // `from` is a function that converts a `Component` into an `Entity`. -// fn from(value: Component) -> Entity { -// Entity::new::() -// .with_id(&value.id) -// .with_attribute("part_number", value.part_number) -// .with_attribute("kind", value.kind) -// .with_attribute("value", value.value) -// .with_attribute("package", value.package) -// .with_attribute("in_stock", value.in_stock) -// } -// } -// // Implement the `From` trait for the `Component` struct. -// impl From for Component { -// // `from` is a function that converts an `Entity` into a `Component`. -// fn from(value: Entity) -> Self { -// Self { -// id: value.id.clone(), -// part_number: value -// .unwrap("part_number") -// .expect("part_number is always present"), -// kind: value.unwrap("kind").expect("kind is always present"), -// value: value.unwrap("value").expect("value is always present"), -// package: value.unwrap("package").expect("package is always present"), -// in_stock: value -// .unwrap("in_stock") -// .expect("in_stock is always present"), -// } -// } -// } -// -// fn main() { -// // Define the path for the SQLite database file. -// let db_path = "./using_filters.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 some component instances. -// let components_to_add = vec![ -// // This one should be found -// Component { -// id: "R1".to_string(), -// part_number: "R-10K-0805".to_string(), -// kind: "resistor".to_string(), -// value: 10000, -// package: "smd-0805".to_string(), -// in_stock: true, -// }, -// // This one should be found -// Component { -// id: "R2".to_string(), -// part_number: "R-4K7-0805".to_string(), -// kind: "resistor".to_string(), -// value: 4700, -// package: "smd-0805".to_string(), -// in_stock: true, -// }, -// // This one should NOT be found (wrong kind) -// Component { -// id: "C1".to_string(), -// part_number: "C-100n-0603".to_string(), -// kind: "capacitor".to_string(), -// value: 100, -// package: "smd-0603".to_string(), -// in_stock: true, -// }, -// // This one should NOT be found (value too low) -// Component { -// id: "R3".to_string(), -// part_number: "R-100-0805".to_string(), -// kind: "resistor".to_string(), -// value: 100, -// package: "smd-0805".to_string(), -// in_stock: true, -// }, -// // This one should NOT be found (not in stock) -// Component { -// id: "R4".to_string(), -// part_number: "R-22K-TH".to_string(), -// kind: "resistor".to_string(), -// value: 22000, -// package: "through-hole".to_string(), -// in_stock: false, -// }, -// // This one should NOT be found (wrong kind, even if other fields match) -// Component { -// id: "L1".to_string(), -// part_number: "L-10mH-TH".to_string(), -// kind: "inductor".to_string(), -// value: 10000, -// package: "through-hole".to_string(), -// in_stock: true, -// }, -// ]; -// // Insert the components into the catalog. -// catalog.insert_many(components_to_add.clone()).unwrap(); -// // Persist the changes to the database. -// catalog.persist().unwrap(); -// // Create a new catalog to ensure we are loading from the database. -// let mut new_catalog = Catalog::new(db_path); -// // Create a composite filter. -// // We are looking for resistors with a value greater than 1000 that are in stock. -// let filter = Filter::new() -// .with_text("kind", Comparison::IsExactly, "resistor") -// .with_unsigned_int("value", Comparison::Greater, 1000) -// .with_bool("in_stock", true); -// // Load entities from the database using the filter. -// new_catalog.load_by_filter(&filter).unwrap(); -// // Get the list of loaded components. -// let loaded_components: Vec = new_catalog -// .list_by_class::() -// .map(|c| c.unwrap()) -// .collect(); -// // Print the loaded components -// println!( -// "Found {} components matching the filter:", -// loaded_components.len() -// ); -// for component in &loaded_components { -// println!( -// "- ID: {}, Part Number: {}, Kind: {}, Value: {}, Package: {}, In Stock: {}", -// component.id, -// component.part_number, -// component.kind, -// component.value, -// component.package, -// component.in_stock -// ); -// } -// // Verify that we have loaded the correct number of components. -// assert_eq!(loaded_components.len(), 2); -// // Verify that the correct components were loaded. -// let ids: Vec = loaded_components.iter().map(|c| c.id.clone()).collect(); -// assert!(ids.contains(&"R1".to_string())); -// assert!(ids.contains(&"R2".to_string())); -// // Clean up the database file. -// std::fs::remove_file(db_path).unwrap(); -// } +use heave::*; + +// Define a struct named `Component` to represent an electronic component. +#[derive(Debug, Clone, PartialEq)] +struct Component { + pub id: String, + pub part_number: String, + pub kind: String, + pub value: u64, + pub package: String, + pub in_stock: bool, +} +// Implement the `EAV` trait for the `Component` struct. +impl EAV for Component { + // `class` is a function that returns the class name of the entity. + fn class() -> &'static str { + "component" + } +} +// Implement the `From` trait for the `Entity` struct. +impl From for Entity { + // `from` is a function that converts a `Component` into an `Entity`. + fn from(value: Component) -> Entity { + Entity::new::() + .with_id(&value.id) + .with_attribute("part_number", value.part_number) + .with_attribute("kind", value.kind) + .with_attribute("value", value.value) + .with_attribute("package", value.package) + .with_attribute("in_stock", value.in_stock) + } +} +// Implement the `From` trait for the `Component` struct. +impl From for Component { + // `from` is a function that converts an `Entity` into a `Component`. + fn from(value: Entity) -> Self { + Self { + id: value.id.clone(), + part_number: value + .unwrap("part_number") + .expect("part_number is always present"), + kind: value.unwrap("kind").expect("kind is always present"), + value: value.unwrap("value").expect("value is always present"), + package: value.unwrap("package").expect("package is always present"), + in_stock: value + .unwrap("in_stock") + .expect("in_stock is always present"), + } + } +} + +fn main() { + // Define the path for the SQLite database file. + let db_path = "./using_filters.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 some component instances. + let components_to_add = vec![ + // This one should be found + Component { + id: "R1".to_string(), + part_number: "R-10K-0805".to_string(), + kind: "resistor".to_string(), + value: 10000, + package: "smd-0805".to_string(), + in_stock: true, + }, + // This one should be found + Component { + id: "R2".to_string(), + part_number: "R-4K7-0805".to_string(), + kind: "resistor".to_string(), + value: 4700, + package: "smd-0805".to_string(), + in_stock: true, + }, + // This one should NOT be found (wrong kind) + Component { + id: "C1".to_string(), + part_number: "C-100n-0603".to_string(), + kind: "capacitor".to_string(), + value: 100, + package: "smd-0603".to_string(), + in_stock: true, + }, + // This one should NOT be found (value too low) + Component { + id: "R3".to_string(), + part_number: "R-100-0805".to_string(), + kind: "resistor".to_string(), + value: 100, + package: "smd-0805".to_string(), + in_stock: true, + }, + // This one should NOT be found (not in stock) + Component { + id: "R4".to_string(), + part_number: "R-22K-TH".to_string(), + kind: "resistor".to_string(), + value: 22000, + package: "through-hole".to_string(), + in_stock: false, + }, + // This one should NOT be found (wrong kind, even if other fields match) + Component { + id: "L1".to_string(), + part_number: "L-10mH-TH".to_string(), + kind: "inductor".to_string(), + value: 10000, + package: "through-hole".to_string(), + in_stock: true, + }, + ]; + // Insert the components into the catalog. + catalog.insert_many(components_to_add.clone()).unwrap(); + // Persist the changes to the database. + catalog.persist().unwrap(); + // Create a new catalog to ensure we are loading from the database. + let mut new_catalog = Catalog::new(db_path); + // Create a composite filter. + // We are looking for resistors with a value greater than 1000 that are in stock. + let filter = Filter::new() + .with_text("kind", Comparison::IsExactly, "resistor") + .with_unsigned_int("value", Comparison::Greater, 1000) + .with_bool("in_stock", true); + // Load entities from the database using the filter. + new_catalog.load_by_filter(&filter).unwrap(); + // Get the list of loaded components. + let loaded_components: Vec = new_catalog + .list_by_class::() + .unwrap() + .into_iter() + .map(|c| c.unwrap()) + .collect(); + // Print the loaded components + println!( + "Found {} components matching the filter:", + loaded_components.len() + ); + for component in &loaded_components { + println!( + "- ID: {}, Part Number: {}, Kind: {}, Value: {}, Package: {}, In Stock: {}", + component.id, + component.part_number, + component.kind, + component.value, + component.package, + component.in_stock + ); + } + // Verify that we have loaded the correct number of components. + assert_eq!(loaded_components.len(), 2); + // Verify that the correct components were loaded. + let ids: Vec = loaded_components.iter().map(|c| c.id.clone()).collect(); + assert!(ids.contains(&"R1".to_string())); + assert!(ids.contains(&"R2".to_string())); + // Clean up the database file. + std::fs::remove_file(db_path).unwrap(); +} diff --git a/01.workspace/heave/examples/working_with_many_types.rs b/01.workspace/heave/examples/working_with_many_types.rs index 72dbca1..6263f5b 100644 --- a/01.workspace/heave/examples/working_with_many_types.rs +++ b/01.workspace/heave/examples/working_with_many_types.rs @@ -1,228 +1,236 @@ -fn main() {} -// use heave::*; -// use std::path::Path; -// -// struct Laptop { -// pub id: String, -// pub model: String, -// pub price: u64, -// } -// struct Display { -// pub id: String, -// pub model: String, -// pub resolution: f64, -// pub price: u64, -// } -// struct Mouse { -// pub id: String, -// pub model: String, -// pub wireless: bool, -// pub price: u64, -// } -// enum Product { -// None, -// Laptop(Laptop), -// Display(Display), -// Mouse(Mouse), -// } -// impl EAV for Product { -// fn class() -> &'static str { -// "product" -// } -// } -// impl From for Product { -// fn from(value: Entity) -> Self { -// if let Some(ref subclass) = value.subclass { -// match subclass.as_ref() { -// "laptop" => Product::Laptop(Laptop { -// id: value.id.clone(), -// model: value.unwrap("model").expect("model is mandatory"), -// price: value.unwrap("price").expect("price is mandatory"), -// }), -// "display" => Product::Display(Display { -// id: value.id.clone(), -// model: value.unwrap("model").expect("model is mandatory"), -// price: value.unwrap("price").expect("price is mandatory"), -// resolution: value.unwrap("resolution").expect("resolution is mandatory"), -// }), -// "mouse" => Product::Mouse(Mouse { -// id: value.id.clone(), -// model: value.unwrap("model").expect("model is mandatory"), -// price: value.unwrap("price").expect("price is mandatory"), -// wireless: value.unwrap("wireless").expect("wireless is mandatory"), -// }), -// _ => unreachable!(), -// } -// } else { -// Product::None -// } -// } -// } -// impl From for Entity { -// fn from(value: Product) -> Self { -// match value { -// Product::Laptop(value) => Entity::new::() -// .with_id(&value.id) -// .with_subclass("laptop") -// .with_attribute("model", value.model) -// .with_attribute("price", value.price), -// Product::Display(value) => Entity::new::() -// .with_id(&value.id) -// .with_subclass("display") -// .with_attribute("model", value.model) -// .with_attribute("resolution", value.resolution) -// .with_attribute("price", value.price), -// Product::Mouse(value) => Entity::new::() -// .with_id(&value.id) -// .with_subclass("mouse") -// .with_attribute("model", value.model) -// .with_attribute("wireless", value.wireless) -// .with_attribute("price", value.price), -// _ => unreachable!(), -// } -// } -// } -// fn main() -> Result<(), FailedTo> { -// let db_path = "working_with_many_types.db"; -// -// // Clean up previous runs if file exists -// if Path::new(db_path).exists() { -// std::fs::remove_file(db_path).unwrap(); -// } -// -// // 1. Initialize and Persist Data -// println!("== 1. Storing different product types =="); -// let mut catalog = Catalog::new(db_path); -// catalog.init()?; -// -// let products_to_add = vec![ -// Product::Laptop(Laptop { -// id: "laptop_01".to_string(), -// model: "Titan".to_string(), -// price: 1500, -// }), -// Product::Display(Display { -// id: "display_01".to_string(), -// model: "CrystalClear".to_string(), -// resolution: 4.0, // 4K -// price: 600, -// }), -// Product::Mouse(Mouse { -// id: "mouse_01".to_string(), -// model: "SwiftClick".to_string(), -// wireless: true, -// price: 80, -// }), -// Product::Laptop(Laptop { -// id: "laptop_02".to_string(), -// model: "Nomad".to_string(), -// price: 950, -// }), -// ]; -// -// catalog.insert_many(products_to_add)?; -// catalog.persist()?; -// println!("✅ 4 products saved to the database.\n"); -// -// // 2. Load data using filters -// println!("== 2. Loading products using class and subclass filters =="); -// -// // Load only laptops -// let mut laptop_catalog = Catalog::new(db_path); -// let laptop_filter = Filter::new() -// .with_class(Product::class()) -// .with_subclass("laptop"); -// -// laptop_catalog.load_by_filter(&laptop_filter)?; -// -// let laptops: Vec = laptop_catalog.list_by_class().map(|p| p.unwrap()).collect(); -// -// println!("✅ Loaded {} laptop(s) using filter.", laptops.len()); -// assert_eq!(laptops.len(), 2); -// for p in laptops { -// if let Product::Laptop(laptop) = p { -// println!( -// " - Laptop: {} ({}) - ${}", -// laptop.id, laptop.model, laptop.price -// ); -// } -// } -// println!(); -// -// println!("== 3. Loading products using attribute filters =="); -// // Load expensive products (price > 1000) -// let mut expensive_catalog = Catalog::new(db_path); -// let expensive_filter = Filter::new() -// .with_class(Product::class()) -// .with_unsigned_int("price", Comparison::Greater, 1000); -// -// expensive_catalog.load_by_filter(&expensive_filter)?; -// -// let expensive_products: Vec = expensive_catalog -// .list_by_class() -// .map(|p| p.unwrap()) -// .collect(); -// -// println!( -// "✅ Loaded {} product(s) with price > $1000.", -// expensive_products.len() -// ); -// assert_eq!(expensive_products.len(), 1); -// -// for p in expensive_products { -// match p { -// Product::Laptop(laptop) => { -// println!( -// " - Found Laptop: {} ({}) - ${}", -// laptop.id, laptop.model, laptop.price -// ); -// assert_eq!(laptop.id, "laptop_01"); -// } -// _ => panic!("Expected a laptop!"), -// } -// } -// println!(); -// -// println!("== 4. Loading all product types =="); -// let mut all_products_catalog = Catalog::new(db_path); -// let all_products_filter = Filter::new().with_class(Product::class()); -// all_products_catalog.load_by_filter(&all_products_filter)?; -// -// let all_products: Vec = all_products_catalog -// .list_by_class() -// .map(|p| p.unwrap()) -// .collect(); -// -// println!("✅ Loaded {} total products.", all_products.len()); -// assert_eq!(all_products.len(), 4); -// -// for p in all_products { -// match p { -// Product::Laptop(laptop) => { -// println!( -// " - Found Laptop: {} ({}) - ${}", -// laptop.id, laptop.model, laptop.price -// ); -// } -// Product::Display(display) => { -// println!( -// " - Found Display: {} ({}) - ${}", -// display.id, display.model, display.price -// ); -// } -// Product::Mouse(mouse) => { -// println!( -// " - Found Mouse: {} ({}) - ${}", -// mouse.id, mouse.model, mouse.price -// ); -// } -// Product::None => panic!("Product::None should not be loaded"), -// } -// } -// println!(); -// -// // Clean up the created database file -// std::fs::remove_file(db_path).unwrap(); -// -// Ok(()) -// } +use heave::*; +use std::path::Path; + +struct Laptop { + pub id: String, + pub model: String, + pub price: u64, +} +struct Display { + pub id: String, + pub model: String, + pub resolution: f64, + pub price: u64, +} +struct Mouse { + pub id: String, + pub model: String, + pub wireless: bool, + pub price: u64, +} +enum Product { + None, + Laptop(Laptop), + Display(Display), + Mouse(Mouse), +} +impl EAV for Product { + fn class() -> &'static str { + "product" + } +} +impl From for Product { + fn from(value: Entity) -> Self { + if let Some(ref subclass) = value.subclass { + match subclass.as_ref() { + "laptop" => Product::Laptop(Laptop { + id: value.id.clone(), + model: value.unwrap("model").expect("model is mandatory"), + price: value.unwrap("price").expect("price is mandatory"), + }), + "display" => Product::Display(Display { + id: value.id.clone(), + model: value.unwrap("model").expect("model is mandatory"), + price: value.unwrap("price").expect("price is mandatory"), + resolution: value.unwrap("resolution").expect("resolution is mandatory"), + }), + "mouse" => Product::Mouse(Mouse { + id: value.id.clone(), + model: value.unwrap("model").expect("model is mandatory"), + price: value.unwrap("price").expect("price is mandatory"), + wireless: value.unwrap("wireless").expect("wireless is mandatory"), + }), + _ => unreachable!(), + } + } else { + Product::None + } + } +} +impl From for Entity { + fn from(value: Product) -> Self { + match value { + Product::Laptop(value) => Entity::new::() + .with_id(&value.id) + .with_subclass("laptop") + .with_attribute("model", value.model) + .with_attribute("price", value.price), + Product::Display(value) => Entity::new::() + .with_id(&value.id) + .with_subclass("display") + .with_attribute("model", value.model) + .with_attribute("resolution", value.resolution) + .with_attribute("price", value.price), + Product::Mouse(value) => Entity::new::() + .with_id(&value.id) + .with_subclass("mouse") + .with_attribute("model", value.model) + .with_attribute("wireless", value.wireless) + .with_attribute("price", value.price), + _ => unreachable!(), + } + } +} +fn main() -> Result<(), FailedTo> { + let db_path = "working_with_many_types.db"; + + // Clean up previous runs if file exists + if Path::new(db_path).exists() { + std::fs::remove_file(db_path).unwrap(); + } + + // 1. Initialize and Persist Data + println!("== 1. Storing different product types =="); + let mut catalog = Catalog::new(db_path); + catalog.init()?; + + let products_to_add = vec![ + Product::Laptop(Laptop { + id: "laptop_01".to_string(), + model: "Titan".to_string(), + price: 1500, + }), + Product::Display(Display { + id: "display_01".to_string(), + model: "CrystalClear".to_string(), + resolution: 4.0, // 4K + price: 600, + }), + Product::Mouse(Mouse { + id: "mouse_01".to_string(), + model: "SwiftClick".to_string(), + wireless: true, + price: 80, + }), + Product::Laptop(Laptop { + id: "laptop_02".to_string(), + model: "Nomad".to_string(), + price: 950, + }), + ]; + + catalog.insert_many(products_to_add)?; + catalog.persist()?; + println!("✅ 4 products saved to the database.\n"); + + // 2. Load data using filters + println!("== 2. Loading products using class and subclass filters =="); + + // Load only laptops + let mut laptop_catalog = Catalog::new(db_path); + let laptop_filter = Filter::new() + .with_class(Product::class()) + .with_subclass("laptop"); + + laptop_catalog.load_by_filter(&laptop_filter)?; + + let laptops: Vec = laptop_catalog + .list_by_class() + .unwrap() + .into_iter() + .map(|p| p.unwrap()) + .collect(); + + println!("✅ Loaded {} laptop(s) using filter.", laptops.len()); + assert_eq!(laptops.len(), 2); + for p in laptops { + if let Product::Laptop(laptop) = p { + println!( + " - Laptop: {} ({}) - ${}", + laptop.id, laptop.model, laptop.price + ); + } + } + println!(); + + println!("== 3. Loading products using attribute filters =="); + // Load expensive products (price > 1000) + let mut expensive_catalog = Catalog::new(db_path); + let expensive_filter = Filter::new() + .with_class(Product::class()) + .with_unsigned_int("price", Comparison::Greater, 1000); + + expensive_catalog.load_by_filter(&expensive_filter)?; + + let expensive_products: Vec = expensive_catalog + .list_by_class() + .unwrap() + .into_iter() + .map(|p| p.unwrap()) + .collect(); + + println!( + "✅ Loaded {} product(s) with price > $1000.", + expensive_products.len() + ); + assert_eq!(expensive_products.len(), 1); + + for p in expensive_products { + match p { + Product::Laptop(laptop) => { + println!( + " - Found Laptop: {} ({}) - ${}", + laptop.id, laptop.model, laptop.price + ); + assert_eq!(laptop.id, "laptop_01"); + } + _ => panic!("Expected a laptop!"), + } + } + println!(); + + println!("== 4. Loading all product types =="); + let mut all_products_catalog = Catalog::new(db_path); + let all_products_filter = Filter::new().with_class(Product::class()); + all_products_catalog.load_by_filter(&all_products_filter)?; + + let all_products: Vec = all_products_catalog + .list_by_class() + .unwrap() + .into_iter() + .map(|p| p.unwrap()) + .collect(); + + println!("✅ Loaded {} total products.", all_products.len()); + assert_eq!(all_products.len(), 4); + + for p in all_products { + match p { + Product::Laptop(laptop) => { + println!( + " - Found Laptop: {} ({}) - ${}", + laptop.id, laptop.model, laptop.price + ); + } + Product::Display(display) => { + println!( + " - Found Display: {} ({}) - ${}", + display.id, display.model, display.price + ); + } + Product::Mouse(mouse) => { + println!( + " - Found Mouse: {} ({}) - ${}", + mouse.id, mouse.model, mouse.price + ); + } + Product::None => panic!("Product::None should not be loaded"), + } + } + println!(); + + // Clean up the created database file + std::fs::remove_file(db_path).unwrap(); + + Ok(()) +}