|
@@ -8,6 +8,8 @@ use crate::model::Modelable;
|
|
|
// pub mod builder;
|
|
|
pub mod build;
|
|
|
|
|
|
+pub use build::{Filterable,Resolvable};
|
|
|
+
|
|
|
/// Wraps an entity with its ID, for example as a query result.
|
|
|
///
|
|
|
/// The wrapped value is accessible via `Deref`, so this should be mostly
|
|
@@ -129,13 +131,14 @@ impl<'l> QueryInterface<'l> {
|
|
|
With: FnMut(&mut sqlite::Statement<'l>) -> Return,
|
|
|
>(
|
|
|
&self,
|
|
|
- ty: std::any::TypeId,
|
|
|
+ hash: u64,
|
|
|
create: Create,
|
|
|
mut with: With) -> Return {
|
|
|
|
|
|
let mut cache = self.cache.lock().expect("Couldn't acquire cache?");
|
|
|
- let key = ("", ty, NO_HASH);
|
|
|
+ let key = ("", std::any::TypeId::of::<()>(), hash);
|
|
|
let query = cache.entry(key).or_insert_with(create);
|
|
|
+ query.reset().expect("Couldn't reset query");
|
|
|
with(query)
|
|
|
}
|
|
|
|
|
@@ -187,34 +190,7 @@ impl<'l> QueryInterface<'l> {
|
|
|
col: C,
|
|
|
val: V,
|
|
|
) -> Option<WithID<C::Entity>> {
|
|
|
- let table_name = <C::Entity>::table_name();
|
|
|
- let column_name = col.name();
|
|
|
-
|
|
|
- self.cached_query_column(
|
|
|
- "get_one_by",
|
|
|
- std::any::TypeId::of::<C::Entity>(),
|
|
|
- &[&col],
|
|
|
- &|| {
|
|
|
- self.db
|
|
|
- .conn
|
|
|
- .prepare(&format!(
|
|
|
- "SELECT * FROM \"{}\" WHERE \"{}\" = ?",
|
|
|
- table_name, column_name
|
|
|
- ))
|
|
|
- .expect("")
|
|
|
- },
|
|
|
- &mut |stmt| {
|
|
|
- val.bind_to(stmt, 1).ok()?;
|
|
|
-
|
|
|
- self.expect_one_result(stmt, &mut |stmt| {
|
|
|
- let id: i64 = stmt.read(0).ok()?;
|
|
|
- Some(WithID::wrap(
|
|
|
- <<C as EntityColumn>::Entity>::build_from(stmt).ok()?,
|
|
|
- id,
|
|
|
- ))
|
|
|
- })
|
|
|
- },
|
|
|
- )
|
|
|
+ self.get().by(col, &val).result()
|
|
|
}
|
|
|
|
|
|
/// Search for an entity by multiple properties
|
|
@@ -260,26 +236,8 @@ impl<'l> QueryInterface<'l> {
|
|
|
|
|
|
/// Delete entities by searching with a single property
|
|
|
pub fn delete_by<C: EntityColumn, V: Modelable>(&self, c: C, val: V) -> Option<()> {
|
|
|
- let table_name = <C::Entity>::table_name();
|
|
|
- let column_name = c.name();
|
|
|
-
|
|
|
- self.cached_query_column(
|
|
|
- "delete_by",
|
|
|
- std::any::TypeId::of::<C::Entity>(),
|
|
|
- &[&c],
|
|
|
- &|| {
|
|
|
- let query = format!("DELETE FROM \"{}\" WHERE {} = ?", table_name, column_name);
|
|
|
- self.db
|
|
|
- .conn
|
|
|
- .prepare(&query)
|
|
|
- .expect(format!("Failed to prepare SQL query: {}", query).as_str())
|
|
|
- },
|
|
|
- &mut |stmt| {
|
|
|
- val.bind_to(stmt, 1).ok()?;
|
|
|
-
|
|
|
- self.expect_no_result(stmt)
|
|
|
- },
|
|
|
- )
|
|
|
+ self.delete().by(c, &val).no_result();
|
|
|
+ Some(())
|
|
|
}
|
|
|
|
|
|
/// Delete entities by searching with a single property
|
|
@@ -410,6 +368,11 @@ impl<'l> QueryInterface<'l> {
|
|
|
)
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ pub fn insert<T: Entity + serde::Serialize>(&self, m: &T) -> Option<<T as Entity>::ID> {
|
|
|
+ self.add(m)
|
|
|
+ }
|
|
|
+
|
|
|
/// Add an entity to its table
|
|
|
pub fn add<T: Entity + serde::Serialize>(&self, m: &T) -> Option<<T as Entity>::ID> {
|
|
|
self.cached_query(
|
|
@@ -445,147 +408,14 @@ impl<'l> QueryInterface<'l> {
|
|
|
pub fn get<'a, 'b, T: Entity>(&'a self) -> build::Select<'b, 'l, T> where 'a: 'b {
|
|
|
build::Select::new(self)
|
|
|
}
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
-qi.get().by(Table::Column, value).by(Table::OtherColumn, value).one()
|
|
|
-qi.get().id(some_id).one()
|
|
|
-qi.get().by(Table::Column, value).all()
|
|
|
-*/
|
|
|
|
|
|
-
|
|
|
-/*
|
|
|
-pub struct BuildResult(String, bool);
|
|
|
-
|
|
|
-pub trait Buildable {
|
|
|
- fn build() -> BuildResult;
|
|
|
-}
|
|
|
-
|
|
|
-pub trait Gettable<'sq, 'l, T: Entity>
|
|
|
-where
|
|
|
- 'l: 'sq,
|
|
|
-{
|
|
|
- type Builder: Buildable;
|
|
|
- fn qi(&self) -> &'sq QueryInterface<'l> {
|
|
|
- todo!()
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-pub struct GetQuery<'sq, 'l, T: Entity>
|
|
|
-where
|
|
|
- 'l: 'sq,
|
|
|
-{
|
|
|
- qi: &'sq QueryInterface<'l>,
|
|
|
- _ghost: std::marker::PhantomData<(T, &'sq str)>,
|
|
|
-}
|
|
|
-
|
|
|
-impl<'sq, 'l, T: Entity> Gettable<'sq, 'l, T> for GetQuery<'sq, 'l, T> {
|
|
|
- type Builder = GetBuild<T>;
|
|
|
-}
|
|
|
-
|
|
|
-pub struct GetBuild<T: Entity> {
|
|
|
- _ghost: std::marker::PhantomData<T>,
|
|
|
-}
|
|
|
-
|
|
|
-impl<T: Entity> Buildable for GetBuild<T> {
|
|
|
- fn build() -> BuildResult {
|
|
|
- todo!()
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-pub struct ByClause<'sq, 'l, T: Entity, Col: EntityColumn<Entity = T>, Wrap: Gettable<'sq, 'l, T>>
|
|
|
-where
|
|
|
- 'l: 'sq,
|
|
|
-{
|
|
|
- wrap: Wrap,
|
|
|
- col: &'sq Col,
|
|
|
- data: &'sq dyn Modelable,
|
|
|
- _ghost: std::marker::PhantomData<(&'sq str, &'l str, T, Col, Wrap)>,
|
|
|
-}
|
|
|
-
|
|
|
-pub struct ByBuild<Col: EntityColumn, Wrap: Buildable> {
|
|
|
- _ghost: std::marker::PhantomData<(Col, Wrap)>,
|
|
|
-}
|
|
|
-
|
|
|
-impl<Col: EntityColumn, Wrap: Buildable> Buildable for ByBuild<Col, Wrap> {
|
|
|
- fn build() -> BuildResult {
|
|
|
- Wrap::build();
|
|
|
- todo!()
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl<'sq, 'l, T: Entity> GetQuery<'sq, 'l, T>
|
|
|
-where
|
|
|
- 'l: 'sq,
|
|
|
-{
|
|
|
- pub fn by<NCol: EntityColumn<Entity = T>>(
|
|
|
- self,
|
|
|
- col: &'sq NCol,
|
|
|
- data: &'sq dyn Modelable,
|
|
|
- ) -> ByClause<'sq, 'l, T, NCol, Self> {
|
|
|
- ByClause {
|
|
|
- wrap: self,
|
|
|
- col,
|
|
|
- data,
|
|
|
- _ghost: std::marker::PhantomData,
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl<'sq, 'l, T: Entity, Col: EntityColumn<Entity = T>, Wrap: Gettable<'sq, 'l, T>>
|
|
|
- Gettable<'sq, 'l, T> for ByClause<'sq, 'l, T, Col, Wrap>
|
|
|
-where
|
|
|
- 'l: 'sq,
|
|
|
-{
|
|
|
- type Builder = ByBuild<Col, Wrap::Builder>;
|
|
|
-}
|
|
|
-
|
|
|
-impl<'sq, 'l, T: Entity, Col: EntityColumn<Entity = T>, Wrap: Gettable<'sq, 'l, T>>
|
|
|
- ByClause<'sq, 'l, T, Col, Wrap>
|
|
|
-where
|
|
|
- 'l: 'sq,
|
|
|
-{
|
|
|
- fn build_query(&self) {
|
|
|
- <<Self as Gettable<T>>::Builder>::build();
|
|
|
- }
|
|
|
-
|
|
|
- pub fn one(self) -> Option<T> {
|
|
|
- // let ty = std::any::TypeId::of::<ByClause<'static, 'static, T, Col, Wrap>>();
|
|
|
- todo!()
|
|
|
- }
|
|
|
-
|
|
|
- pub fn all(self) -> Vec<T> {
|
|
|
- todo!()
|
|
|
- }
|
|
|
-
|
|
|
- pub fn by<NCol: EntityColumn<Entity = T>>(
|
|
|
- self,
|
|
|
- col: &'sq NCol,
|
|
|
- data: &'sq dyn Modelable,
|
|
|
- ) -> ByClause<'sq, 'l, T, NCol, Self> {
|
|
|
- ByClause {
|
|
|
- wrap: self,
|
|
|
- col,
|
|
|
- data,
|
|
|
- _ghost: std::marker::PhantomData,
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl<'l> QueryInterface<'l> {
|
|
|
- pub fn get<'sq, T: Entity>(&'sq self) -> GetQuery<T>
|
|
|
- where
|
|
|
- 'l: 'sq,
|
|
|
- {
|
|
|
- GetQuery::<'sq, 'l, _> {
|
|
|
- qi: self,
|
|
|
- _ghost: std::marker::PhantomData,
|
|
|
- }
|
|
|
+ pub fn delete<'a, 'b, T: Entity>(&'a self) -> build::Delete<'b, 'l, T> where 'a: 'b {
|
|
|
+ build::Delete::new(self)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#[cfg(test)]
|
|
|
-mod get_test {
|
|
|
+mod test_build {
|
|
|
use microrm_macros::Entity;
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
@@ -598,23 +428,12 @@ mod get_test {
|
|
|
value: String,
|
|
|
}
|
|
|
|
|
|
- fn simple_test<'sq, 'l>(qi: &'sq QueryInterface<'l>) {
|
|
|
- // let g = qi.get::<'sq, KVStore>();
|
|
|
- // qi.get::<'l,'_,KVStore>();
|
|
|
-
|
|
|
- // let t = g.by(&KVStore::Key, &"test").one();
|
|
|
-
|
|
|
- //drop(t);
|
|
|
- }
|
|
|
-
|
|
|
#[test]
|
|
|
- fn test_build_query() {
|
|
|
- let db = crate::DB::new_in_memory(crate::Schema::new()).unwrap();
|
|
|
+ fn simple_get() {
|
|
|
+ use super::*;
|
|
|
+ let db = crate::DB::new_in_memory(crate::Schema::new().entity::<KVStore>()).unwrap();
|
|
|
let qi = db.query_interface();
|
|
|
|
|
|
- simple_test(&qi);
|
|
|
-
|
|
|
- {}
|
|
|
+ assert!(qi.get().by(KVStore::Key, "abc").result().is_none());
|
|
|
}
|
|
|
}
|
|
|
-*/
|