use crate::DB; pub mod condition; #[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize)] pub struct ID { id: i64 } impl rusqlite::ToSql for ID { fn to_sql(&self) -> Result, rusqlite::Error> { self.id.to_sql() } } #[derive(Debug)] pub struct WithID { wrap: T, id: ID, } impl WithID { fn wrap(what: T, raw_id: i64) -> Self { Self { wrap: what, id: ID { id: raw_id } } } } impl WithID { pub fn id(&self) -> ID { self.id } } impl AsRef for WithID { fn as_ref(&self) -> &T { &self.wrap } } impl std::ops::Deref for WithID { type Target = T; fn deref(&self) -> &Self::Target { &self.wrap } } impl std::ops::DerefMut for WithID { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.wrap } } /// Search for an entity by a property pub fn get_one_by, C: crate::model::EntityColumns, V: rusqlite::ToSql>( db: &DB, c: C, val: V, ) -> Option> { let table_name = ::table_name(); let column_name = ::name(c); let mut prepared = db .conn .prepare(&format!( "SELECT rowid, tbl.* FROM {} tbl WHERE {} = ?1", table_name, column_name )) .ok()?; let result = prepared.query_row([&val], |row| { let mut deser = crate::model::load::RowDeserializer::from_row(row); Ok(WithID::wrap( T::deserialize(&mut deser).expect("deserialization works"), row.get(0).expect("can get rowid"), )) }); result.ok() } /// Search for all entities matching a property pub fn get_all_by, C: crate::model::EntityColumns, V: rusqlite::ToSql>( db: &DB, c: C, val: V) -> Option>> { let table_name = ::table_name(); let column_name = ::name(c); let mut prepared = db .conn .prepare(&format!( "SELECT rowid, tbl.* FROM {} tbl WHERE {} = ?1", table_name, column_name )) .ok()?; let rows = prepared.query_map([&val], |row| { let mut deser = crate::model::load::RowDeserializer::from_row(row); Ok(WithID::wrap( T::deserialize(&mut deser)?, row.get(0).expect("can get rowid"), )) }).ok()?; Some(rows.map(|x| x.unwrap()).collect()) } /// Search for an entity by ID pub fn get_one_by_id( db: &DB, id: ID ) -> Option> { let table_name = ::table_name(); let mut prepared = db .conn .prepare(&format!( "SELECT rowid, tbl.* FROM {} tbl WHERE rowid = ?1", table_name )) .ok()?; let result = prepared.query_row([&id], |row| { let mut deser = crate::model::load::RowDeserializer::from_row(row); Ok(WithID::wrap( T::deserialize(&mut deser).expect("deserialization works"), row.get(0).expect("can get rowid"), )) }); result.ok() } /// Add an entity to its table pub fn add(db: &DB, m: &T) -> Option { let row = crate::model::store::serialize_as_row(m); let placeholders = (0..::column_count()) .map(|n| format!("?{}", n + 1)) .collect::>() .join(","); let res = db.conn.prepare(&format!( "INSERT INTO {} VALUES ({})", ::table_name(), placeholders )); let mut prepared = res.ok()?; // make sure we bound enough things assert_eq!(row.len(), ::column_count()); let id = prepared.insert(rusqlite::params_from_iter(row)).ok()?; Some(ID {id}) }