From 8852a9569e958af2fa8775e054c15110d2afff08 Mon Sep 17 00:00:00 2001 From: davidemazzocchi Date: Tue, 30 Sep 2025 09:23:32 +0200 Subject: [PATCH] feat: add load_by_id function to catalog --- 01.workspace/heave/src/fun/mod.rs | 3 ++ .../heave/src/fun/sqlite_load_by_id.rs | 36 +++++++++++++++++++ .../src/fun/sqlite_map_row_to_attribute.rs | 25 +++++++++++++ .../heave/src/fun/sqlite_map_row_to_entity.rs | 12 +++++++ 01.workspace/heave/src/lib.rs | 7 ++++ 01.workspace/heave/src/str/catalog.rs | 8 +++++ 01.workspace/heave/src/tst/intended_use.rs | 29 +++++++++++++++ 7 files changed, 120 insertions(+) create mode 100644 01.workspace/heave/src/fun/sqlite_load_by_id.rs create mode 100644 01.workspace/heave/src/fun/sqlite_map_row_to_attribute.rs create mode 100644 01.workspace/heave/src/fun/sqlite_map_row_to_entity.rs diff --git a/01.workspace/heave/src/fun/mod.rs b/01.workspace/heave/src/fun/mod.rs index 5f41027..1227414 100644 --- a/01.workspace/heave/src/fun/mod.rs +++ b/01.workspace/heave/src/fun/mod.rs @@ -1,2 +1,5 @@ pub mod sqlite_init_db; +pub mod sqlite_load_by_id; +pub mod sqlite_map_row_to_attribute; +pub mod sqlite_map_row_to_entity; pub mod sqlite_persist_catalog; diff --git a/01.workspace/heave/src/fun/sqlite_load_by_id.rs b/01.workspace/heave/src/fun/sqlite_load_by_id.rs new file mode 100644 index 0000000..9544a80 --- /dev/null +++ b/01.workspace/heave/src/fun/sqlite_load_by_id.rs @@ -0,0 +1,36 @@ +use crate::*; +use rusqlite::*; + +const SELECT_ENTITY_BY_ID: &str = r#" + SELECT * FROM entity + WHERE id = ?1; +"#; + +const SELECT_ATTRIBUTE_BY_FK: &str = r#" + SELECT * FROM attribute + WHERE entity_id = ?1; +"#; + +pub fn run(path: &path::Path, entity_id: &str) -> Option { + let connection = Connection::open(path).unwrap(); + let result = connection + .query_one(SELECT_ENTITY_BY_ID, [entity_id], sqlite::map::row_to_entity) + .optional(); + let mut entity = result.unwrap(); + if let Some(ref mut entity) = entity { + let mut select_attributes_statement = connection.prepare(SELECT_ATTRIBUTE_BY_FK).unwrap(); + let attributes = select_attributes_statement + .query_map([&entity.id], sqlite::map::row_to_attribute) + .unwrap(); + for attribute in attributes { + let attribute = attribute.unwrap(); + entity.attributes.insert(attribute.id.clone(), attribute); + } + } + entity +} + +// #[cfg(test)] +// mod unit_tests { +// use super::*; +// } diff --git a/01.workspace/heave/src/fun/sqlite_map_row_to_attribute.rs b/01.workspace/heave/src/fun/sqlite_map_row_to_attribute.rs new file mode 100644 index 0000000..f135a91 --- /dev/null +++ b/01.workspace/heave/src/fun/sqlite_map_row_to_attribute.rs @@ -0,0 +1,25 @@ +use crate::*; + +pub fn run(row: &rusqlite::Row) -> rusqlite::Result { + let id: String = row.get(0)?; + let _entity_id: String = row.get(1)?; + let signed_int: Option = row.get(2)?; + let unsigned_int: Option = row.get(3)?; + let real: Option = row.get(4)?; + let text: Option = row.get(5)?; + let bool: Option = row.get(6)?; + let value: Value = match (signed_int, unsigned_int, real, text, bool) { + (Some(value), None, None, None, None) => Value::SignedInt(value), + (None, Some(value), None, None, None) => Value::UnsignedInt(value), + (None, None, Some(value), None, None) => Value::Real(value), + (None, None, None, Some(value), None) => Value::Text(value), + (None, None, None, None, Some(value)) => Value::Bool(value), + _ => panic!(), + }; + Ok(Attribute { id, value }) +} + +// #[cfg(test)] +// mod unit_tests { +// use super::*; +// } diff --git a/01.workspace/heave/src/fun/sqlite_map_row_to_entity.rs b/01.workspace/heave/src/fun/sqlite_map_row_to_entity.rs new file mode 100644 index 0000000..a0512e4 --- /dev/null +++ b/01.workspace/heave/src/fun/sqlite_map_row_to_entity.rs @@ -0,0 +1,12 @@ +use crate::*; + +pub fn run(row: &rusqlite::Row) -> rusqlite::Result { + let id: String = row.get(0)?; + let class: String = row.get(1)?; + Ok(Entity::default().with_id(&id).with_class(&class)) +} + +// #[cfg(test)] +// mod unit_tests { +// use super::*; +// } diff --git a/01.workspace/heave/src/lib.rs b/01.workspace/heave/src/lib.rs index 4edf57b..eb76490 100644 --- a/01.workspace/heave/src/lib.rs +++ b/01.workspace/heave/src/lib.rs @@ -17,6 +17,13 @@ mod sqlite { pub mod init { pub use crate::fun::sqlite_init_db::run as db; } + pub mod load { + pub use crate::fun::sqlite_load_by_id::run as by_id; + } + pub mod map { + pub use crate::fun::sqlite_map_row_to_attribute::run as row_to_attribute; + pub use crate::fun::sqlite_map_row_to_entity::run as row_to_entity; + } pub mod persist { pub use crate::fun::sqlite_persist_catalog::run as catalog; } diff --git a/01.workspace/heave/src/str/catalog.rs b/01.workspace/heave/src/str/catalog.rs index 7a72d16..8c9c33f 100644 --- a/01.workspace/heave/src/str/catalog.rs +++ b/01.workspace/heave/src/str/catalog.rs @@ -38,6 +38,14 @@ impl O { let path = path::Path::new(&self.path); sqlite::persist::catalog(path, self); } + pub fn load_by_id(&mut self, id: &str) { + let path = path::Path::new(&self.path); + let entity = sqlite::load::by_id(path, id); + match entity { + None => (), + Some(entity) => self.insert(entity), + } + } } // impl std::fmt::Display for O { diff --git a/01.workspace/heave/src/tst/intended_use.rs b/01.workspace/heave/src/tst/intended_use.rs index 212f685..2506582 100644 --- a/01.workspace/heave/src/tst/intended_use.rs +++ b/01.workspace/heave/src/tst/intended_use.rs @@ -161,4 +161,33 @@ mod tests { let read_product: Product = catalog.get(&expected_product.id).unwrap(); assert_eq!(read_product, expected_product); } + #[test] + fn check_010() { + // demonstrates load entity by id + let tempfile = tempfile::NamedTempFile::new().unwrap(); + let path = tempfile.path().to_str().unwrap(); + // insert a new entity + let mut catalog = Catalog::new(path); + catalog.init(); + let entity = Entity::new("test") + .with_attribute("int", Value::SignedInt(50)) + .with_attribute("string", Value::Text("text".to_string())); + let id = entity.id.clone(); + catalog.insert(entity); + catalog.persist(); + // read the entity in a new catalog + let mut catalog = Catalog::new(path); + catalog.load_by_id(&id); + let entity: Option = catalog.get(&id); + assert_eq!( + entity, + Some( + Entity::default() + .with_id(&id) + .with_class("test") + .with_attribute("int", Value::SignedInt(50)) + .with_attribute("string", Value::Text("text".to_string())) + ) + ); + } }