|
@@ -1,7 +1,7 @@
|
|
|
use crate::model::{Entity, EntityColumns, EntityID};
|
|
|
use crate::DB;
|
|
|
|
|
|
-pub mod condition;
|
|
|
+// pub mod condition;
|
|
|
|
|
|
/// Wraps an entity with its ID, for example as a query result.
|
|
|
///
|
|
@@ -47,36 +47,157 @@ impl<T: Entity> std::ops::DerefMut for WithID<T> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/// Search for an entity by a property
|
|
|
-pub fn get_one_by<T: Entity<Column = C>, C: EntityColumns<Entity = T>, V: rusqlite::ToSql>(
|
|
|
- db: &DB,
|
|
|
- c: C,
|
|
|
- val: V,
|
|
|
-) -> Option<WithID<T>> {
|
|
|
- let table_name = <T as Entity>::table_name();
|
|
|
- let column_name = <T as Entity>::name(c);
|
|
|
+pub struct QueryInterface<'l> {
|
|
|
+ db: &'l crate::DB,
|
|
|
+}
|
|
|
|
|
|
- let mut prepared = db
|
|
|
- .conn
|
|
|
- .prepare(&format!(
|
|
|
- "SELECT * FROM \"{}\" WHERE \"{}\" = ?1",
|
|
|
- table_name, column_name
|
|
|
- ))
|
|
|
- .ok()?;
|
|
|
+impl<'l> QueryInterface<'l> {
|
|
|
+ pub fn new(db: &'l crate::DB) -> Self {
|
|
|
+ Self { db }
|
|
|
+ }
|
|
|
|
|
|
- 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 id"),
|
|
|
- ))
|
|
|
- });
|
|
|
+ /// Helper function to process an expected one result
|
|
|
+ fn expect_one_result<T>(&self, stmt: &mut sqlite::Statement, with_result: &mut dyn FnMut(&mut sqlite::Statement) -> Option<T>) -> Option<T> {
|
|
|
+ let state = stmt.next();
|
|
|
+ assert!(state.is_ok());
|
|
|
+ assert_eq!(state.ok(), Some(sqlite::State::Row));
|
|
|
+
|
|
|
+ let res = with_result(stmt);
|
|
|
+
|
|
|
+ let state = stmt.next();
|
|
|
+ assert!(state.is_ok());
|
|
|
+ assert_eq!(state.ok(), Some(sqlite::State::Done));
|
|
|
+
|
|
|
+ res
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Search for an entity by a property
|
|
|
+ pub fn get_one_by<T: Entity<Column = C>, C: EntityColumns<Entity = T>, V: crate::model::Modelable>(
|
|
|
+ &self,
|
|
|
+ c: C,
|
|
|
+ val: V,
|
|
|
+ ) -> Option<WithID<T>> {
|
|
|
+ let table_name = <T as Entity>::table_name();
|
|
|
+ let column_name = <T as Entity>::name(c);
|
|
|
+
|
|
|
+ let mut prepared = self.db
|
|
|
+ .conn
|
|
|
+ .prepare(&format!(
|
|
|
+ "SELECT * FROM \"{}\" WHERE \"{}\" = ?",
|
|
|
+ table_name, column_name
|
|
|
+ ))
|
|
|
+ .expect("");
|
|
|
+
|
|
|
+ prepared.reset().ok()?;
|
|
|
+
|
|
|
+ val.bind_to(&mut prepared, 1).ok()?;
|
|
|
+
|
|
|
+ return self.expect_one_result(&mut prepared, &mut |stmt| {
|
|
|
+ let id: i64 = stmt.read(0).ok()?;
|
|
|
+ let mut rd = crate::model::load::RowDeserializer::from_row(&stmt);
|
|
|
+ return Some(WithID::wrap(T::deserialize(&mut rd).ok()?, id))
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Search for an entity by ID
|
|
|
+ pub fn get_one_by_id<I: EntityID<Entity=T>, T: Entity>(&self, id: I) -> Option<WithID<T>> {
|
|
|
+ let table_name = <T as Entity>::table_name();
|
|
|
+ let mut prepared = self.db
|
|
|
+ .conn
|
|
|
+ .prepare(&format!("SELECT * FROM \"{}\" WHERE id = ?", table_name))
|
|
|
+ .ok()?;
|
|
|
+
|
|
|
+ id.bind_to(&mut prepared, 1).ok()?;
|
|
|
+
|
|
|
+ return self.expect_one_result(&mut prepared, &mut |stmt| {
|
|
|
+ let id: i64 = stmt.read(0).ok()?;
|
|
|
+ let mut rd = crate::model::load::RowDeserializer::from_row(&stmt);
|
|
|
+ return Some(WithID::wrap(T::deserialize(&mut rd).ok()?, id))
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Search for all entities matching a property
|
|
|
+ pub fn get_all_by<T: Entity<Column = C>, C: EntityColumns<Entity = T>, V: crate::model::Modelable>(
|
|
|
+ &self,
|
|
|
+ c: C,
|
|
|
+ val: V,
|
|
|
+ ) -> Option<Vec<WithID<T>>> {
|
|
|
+ let table_name = <T as Entity>::table_name();
|
|
|
+ let column_name = <T as Entity>::name(c);
|
|
|
+
|
|
|
+ let mut prepared = self.db
|
|
|
+ .conn
|
|
|
+ .prepare(&format!(
|
|
|
+ "SELECT * FROM \"{}\" WHERE \"{}\" = ?",
|
|
|
+ table_name, column_name
|
|
|
+ ))
|
|
|
+ .ok()?;
|
|
|
+
|
|
|
+ val.bind_to(&mut prepared, 1).ok()?;
|
|
|
|
|
|
- result.ok()
|
|
|
+ todo!();
|
|
|
+
|
|
|
+ /*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())*/
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Add an entity to its table
|
|
|
+ pub fn add<T: Entity + serde::Serialize>(&self, m: &T) -> Option<<T as Entity>::ID> {
|
|
|
+
|
|
|
+ let placeholders = (0..(<T as Entity>::column_count() - 1))
|
|
|
+ .map(|n| "?".to_string())
|
|
|
+ .collect::<Vec<_>>()
|
|
|
+ .join(",");
|
|
|
+
|
|
|
+ let mut prepared = self.db.conn.prepare(&format!(
|
|
|
+ "INSERT INTO \"{}\" VALUES (NULL, {}) RETURNING \"id\"",
|
|
|
+ <T as Entity>::table_name(),
|
|
|
+ placeholders
|
|
|
+ )).ok()?;
|
|
|
+
|
|
|
+ crate::model::store::serialize_into(&mut prepared, m).ok()?;
|
|
|
+
|
|
|
+ let rowid = self.expect_one_result(&mut prepared, &mut |stmt| {
|
|
|
+ stmt.read::<i64>(0).ok()
|
|
|
+ })?;
|
|
|
+
|
|
|
+ Some(<T as Entity>::ID::from_raw_id(rowid))
|
|
|
+
|
|
|
+ /*
|
|
|
+ let row = crate::model::store::serialize_as_row(m);
|
|
|
+
|
|
|
+ let placeholders = (0..(<T as Entity>::column_count() - 1))
|
|
|
+ .map(|n| format!("?{}", n + 1))
|
|
|
+ .collect::<Vec<_>>()
|
|
|
+ .join(",");
|
|
|
+
|
|
|
+ let res = db.conn.prepare(&format!(
|
|
|
+ "INSERT INTO \"{}\" VALUES (NULL, {})",
|
|
|
+ <T as Entity>::table_name(),
|
|
|
+ placeholders
|
|
|
+ ));
|
|
|
+ let mut prepared = res.ok()?;
|
|
|
+
|
|
|
+ // make sure we bound enough things (not including ID column here)
|
|
|
+ assert_eq!(row.len(), <T as Entity>::column_count() - 1);
|
|
|
+ */
|
|
|
+
|
|
|
+ /*let id = prepared.insert(rusqlite::params_from_iter(row)).ok()?;
|
|
|
+ Some(<T as Entity>::ID::from_raw_id(id))*/
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// Search for all entities matching a property
|
|
|
-pub fn get_all_by<T: Entity<Column = C>, C: EntityColumns<Entity = T>, V: rusqlite::ToSql>(
|
|
|
+pub fn get_all_by<T: Entity<Column = C>, C: EntityColumns<Entity = T>, V: sqlite::Bindable>(
|
|
|
db: &DB,
|
|
|
c: C,
|
|
|
val: V,
|
|
@@ -84,6 +205,10 @@ pub fn get_all_by<T: Entity<Column = C>, C: EntityColumns<Entity = T>, V: rusqli
|
|
|
let table_name = <T as Entity>::table_name();
|
|
|
let column_name = <T as Entity>::name(c);
|
|
|
|
|
|
+ todo!();
|
|
|
+
|
|
|
+ /*
|
|
|
+
|
|
|
let mut prepared = db
|
|
|
.conn
|
|
|
.prepare(&format!(
|
|
@@ -103,46 +228,5 @@ pub fn get_all_by<T: Entity<Column = C>, C: EntityColumns<Entity = T>, V: rusqli
|
|
|
.ok()?;
|
|
|
|
|
|
Some(rows.map(|x| x.unwrap()).collect())
|
|
|
-}
|
|
|
-
|
|
|
-/// Search for an entity by ID
|
|
|
-pub fn get_one_by_id<T: Entity>(db: &DB, id: <T as Entity>::ID) -> Option<WithID<T>> {
|
|
|
- let table_name = <T as Entity>::table_name();
|
|
|
- let mut prepared = db
|
|
|
- .conn
|
|
|
- .prepare(&format!("SELECT * FROM \"{}\" WHERE id = ?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: Entity + serde::Serialize>(db: &DB, m: &T) -> Option<<T as Entity>::ID> {
|
|
|
- let row = crate::model::store::serialize_as_row(m);
|
|
|
-
|
|
|
- let placeholders = (0..(<T as Entity>::column_count() - 1))
|
|
|
- .map(|n| format!("?{}", n + 1))
|
|
|
- .collect::<Vec<_>>()
|
|
|
- .join(",");
|
|
|
-
|
|
|
- let res = db.conn.prepare(&format!(
|
|
|
- "INSERT INTO \"{}\" VALUES (NULL, {})",
|
|
|
- <T as Entity>::table_name(),
|
|
|
- placeholders
|
|
|
- ));
|
|
|
- let mut prepared = res.ok()?;
|
|
|
-
|
|
|
- // make sure we bound enough things (not including ID column here)
|
|
|
- assert_eq!(row.len(), <T as Entity>::column_count() - 1);
|
|
|
-
|
|
|
- let id = prepared.insert(rusqlite::params_from_iter(row)).ok()?;
|
|
|
- Some(<T as Entity>::ID::from_raw_id(id))
|
|
|
+ */
|
|
|
}
|