123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- 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::types::ToSqlOutput<'_>, rusqlite::Error> {
- self.id.to_sql()
- }
- }
- #[derive(Debug)]
- pub struct WithID<T: crate::model::Entity> {
- wrap: T,
- id: ID,
- }
- impl<T: crate::model::Entity> WithID<T> {
- fn wrap(what: T, raw_id: i64) -> Self {
- Self {
- wrap: what,
- id: ID { id: raw_id }
- }
- }
- }
- impl<T: crate::model::Entity> WithID<T> {
- pub fn id(&self) -> ID {
- self.id
- }
- }
- impl<T: crate::model::Entity> AsRef<T> for WithID<T> {
- fn as_ref(&self) -> &T {
- &self.wrap
- }
- }
- impl<T: crate::model::Entity> std::ops::Deref for WithID<T> {
- type Target = T;
- fn deref(&self) -> &Self::Target {
- &self.wrap
- }
- }
- impl<T: crate::model::Entity> std::ops::DerefMut for WithID<T> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.wrap
- }
- }
- /// Search for an entity by a property
- pub fn get_one_by<T: crate::model::Entity<Column = C>, C: crate::model::EntityColumns<Entity = T>, V: rusqlite::ToSql>(
- db: &DB,
- c: C,
- val: V,
- ) -> Option<WithID<T>> {
- let table_name = <T as crate::model::Entity>::table_name();
- let column_name = <T as crate::model::Entity>::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<T: crate::model::Entity<Column = C>, C: crate::model::EntityColumns<Entity = T>, V: rusqlite::ToSql>(
- db: &DB,
- c: C,
- val: V) -> Option<Vec<WithID<T>>> {
- let table_name = <T as crate::model::Entity>::table_name();
- let column_name = <T as crate::model::Entity>::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<T: crate::model::Entity>(
- db: &DB,
- id: ID
- ) -> Option<WithID<T>> {
- let table_name = <T as crate::model::Entity>::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<T: crate::model::Entity + serde::Serialize>(db: &DB, m: &T) -> Option<ID> {
- let row = crate::model::store::serialize_as_row(m);
- let placeholders = (0..<T as crate::model::Entity>::column_count())
- .map(|n| format!("?{}", n + 1))
- .collect::<Vec<_>>()
- .join(",");
- let res = db.conn.prepare(&format!(
- "INSERT INTO {} VALUES ({})",
- <T as crate::model::Entity>::table_name(),
- placeholders
- ));
- let mut prepared = res.ok()?;
- // make sure we bound enough things
- assert_eq!(row.len(), <T as crate::model::Entity>::column_count());
- let id = prepared.insert(rusqlite::params_from_iter(row)).ok()?;
- Some(ID {id})
- }
|