Преглед изворни кода

Split query::build into separate modules.

Kestrel пре 2 година
родитељ
комит
42db4cd583

+ 1 - 1
microrm/src/lib.rs

@@ -17,7 +17,7 @@ pub use query::{QueryInterface, WithID, build::CompareOp};
 pub use schema::Schema;
 
 pub mod prelude {
-    pub use crate::query::build::{Filterable,Resolvable};
+    pub use crate::query::{Filterable,Resolvable};
 }
 
 use prelude::*;

+ 10 - 5
microrm/src/query.rs

@@ -6,8 +6,13 @@ use crate::model::Modelable;
 
 
 pub mod build;
+pub mod resolve;
+pub mod filter;
+pub mod delete;
+pub mod select;
 
-pub use build::{Filterable, Resolvable};
+pub use resolve::Resolvable;
+pub use filter::Filterable;
 
 /// Wraps an entity with its ID, for example as a query result.
 ///
@@ -174,18 +179,18 @@ impl<'l> QueryInterface<'l> {
 }
 
 impl<'l> QueryInterface<'l> {
-    pub fn get<'a, 'b, T: Entity>(&'a self) -> build::Select<'b, 'l, T>
+    pub fn get<'a, 'b, T: Entity>(&'a self) -> select::Select<'b, 'l, T>
     where
         'a: 'b,
     {
-        build::Select::new(self)
+        select::Select::new(self)
     }
 
-    pub fn delete<'a, 'b, T: Entity>(&'a self) -> build::Delete<'b, 'l, T>
+    pub fn delete<'a, 'b, T: Entity>(&'a self) -> delete::Delete<'b, 'l, T>
     where
         'a: 'b,
     {
-        build::Delete::new(self)
+        delete::Delete::new(self)
     }
 }
 

+ 4 - 284
microrm/src/query/build.rs

@@ -22,16 +22,16 @@ pub enum QueryPart {
 pub struct DerivedQuery(HashMap<QueryPart, Vec<String>>);
 
 impl DerivedQuery {
-    fn new() -> Self {
+    pub(crate) fn new() -> Self {
         Self { 0: HashMap::new() }
     }
 
-    fn add(mut self, to: QueryPart, what: String) -> Self {
+    pub(crate) fn add(mut self, to: QueryPart, what: String) -> Self {
         self.0.entry(to).or_insert_with(|| Vec::new()).push(what);
         self
     }
 
-    fn assemble(mut self) -> String {
+    pub(crate) fn assemble(mut self) -> String {
         let root = self.0.remove(&QueryPart::Root).unwrap().remove(0);
         let where_ = match self.0.remove(&QueryPart::Where) {
             None => String::new(),
@@ -69,85 +69,6 @@ pub trait QueryComponent: StaticVersion {
     fn bind(&self, stmt: &mut sqlite::Statement<'_>) -> Result<usize, Error>;
 }
 
-/// Any query that can be completed/executed
-pub trait Resolvable<'r, 'q, T: Entity>: QueryComponent
-where
-    'q: 'r,
-{
-    fn qi(&self) -> &'r QueryInterface<'q>;
-
-    fn exec(self) -> Result<(), crate::Error> where Self: Sized { self.no_result() }
-    fn one(self) -> Result<Option<WithID<T>>, crate::Error> where Self: Sized { self.result() }
-    fn all(self) -> Result<Vec<WithID<T>>, crate::Error> where Self: Sized { self.results() }
-
-    fn no_result(self) -> Result<(), crate::Error>
-    where
-        Self: Sized,
-    {
-        let mut hasher = std::collections::hash_map::DefaultHasher::new();
-        self.contribute(&mut hasher);
-
-        self.qi().with_cache(
-            hasher.finish(),
-            || self.qi().db.conn.prepare(self.derive().assemble()).unwrap(),
-            |stmt| {
-                self.bind(stmt)?;
-
-                self.qi().expect_no_result(stmt)
-            },
-        )
-    }
-    fn result(self) -> Result<Option<WithID<T>>, crate::Error>
-    where
-        Self: Sized,
-    {
-        let mut hasher = std::collections::hash_map::DefaultHasher::new();
-        self.contribute(&mut hasher);
-        self.qi().with_cache(
-            hasher.finish(),
-            || {
-                let query = self.derive().assemble();
-                self.qi().db.conn.prepare(query).unwrap()
-            },
-            |stmt| {
-                self.bind(stmt)?;
-
-                self.qi().expect_one_result(stmt, &mut |stmt| {
-                    let id: i64 = stmt.read(0)?;
-                    Ok(WithID::wrap(T::build_from(stmt)?, id))
-                })
-            },
-        )
-    }
-    fn results(self) -> Result<Vec<WithID<T>>, crate::Error>
-    where
-        Self: Sized,
-    {
-        let mut hasher = std::collections::hash_map::DefaultHasher::new();
-        self.contribute(&mut hasher);
-        self.qi().with_cache(
-            hasher.finish(),
-            || self.qi().db.conn.prepare(self.derive().assemble()).unwrap(),
-            |stmt| {
-                self.bind(stmt)?;
-
-                let mut res = Vec::new();
-                loop {
-                    let state = stmt.next()?;
-                    if state == sqlite::State::Done {
-                        break;
-                    }
-
-                    let id: i64 = stmt.read(0)?;
-                    res.push(WithID::wrap(T::build_from(stmt)?, id));
-                }
-
-                Ok(res)
-            },
-        )
-    }
-}
-
 #[derive(Debug)]
 pub enum CompareOp {
     LessThan,
@@ -158,7 +79,7 @@ pub enum CompareOp {
 }
 
 impl CompareOp {
-    fn ch(&self) -> &'static str {
+    pub(crate) fn ch(&self) -> &'static str {
         match self {
             Self::LessThan => "<",
             Self::AtMost => "<=",
@@ -168,204 +89,3 @@ impl CompareOp {
         }
     }
 }
-
-/// Any query that can have a WHERE clause attached to it
-pub trait Filterable<'r, 'q>: Resolvable<'r, 'q, Self::Table>
-where
-    'q: 'r,
-{
-    type Table: Entity;
-
-    fn by<C: EntityColumn<Entity = Self::Table>, G: Modelable + ?Sized>(
-        self,
-        col: C,
-        given: &'r G,
-    ) -> Filter<'r, 'q, Self, C, G>
-    where
-        Self: Sized,
-    {
-        Filter {
-            wrap: self,
-            col,
-            op: CompareOp::Equals,
-            given,
-            _ghost: PhantomData,
-        }
-    }
-
-    fn by_op<C: EntityColumn<Entity = Self::Table>, G: Modelable + ?Sized>(
-        self,
-        col: C,
-        op: CompareOp,
-        given: &'r G
-    ) -> Filter<'r, 'q, Self, C, G>
-    where
-        Self: Sized,
-    {
-        Filter {
-            wrap: self,
-            col,
-            op,
-            given,
-            _ghost: PhantomData,
-        }
-    }
-}
-
-pub struct Select<'r, 'q, T: Entity> {
-    qi: &'r QueryInterface<'q>,
-    _ghost: PhantomData<T>,
-}
-
-impl<'r, 'q, T: Entity> Select<'r, 'q, T> {
-    pub fn new(qi: &'r QueryInterface<'q>) -> Self {
-        Self {
-            qi,
-            _ghost: std::marker::PhantomData,
-        }
-    }
-}
-
-impl<'r, 'q, T: Entity> StaticVersion for Select<'r, 'q, T> {
-    type Is = Select<'static, 'static, T>;
-}
-
-impl<'r, 'q, T: Entity> QueryComponent for Select<'r, 'q, T> {
-    fn derive(&self) -> DerivedQuery {
-        DerivedQuery::new().add(
-            QueryPart::Root,
-            format!("SELECT * FROM {}", T::table_name()),
-        )
-    }
-
-    fn contribute<H: Hasher>(&self, hasher: &mut H) {
-        "select".hash(hasher);
-        std::any::TypeId::of::<T>().hash(hasher);
-    }
-
-    // next binding point is the first
-    fn bind(&self, _stmt: &mut sqlite::Statement<'_>) -> Result<usize, Error> {
-        Ok(1)
-    }
-}
-
-impl<'r, 'q, T: Entity> Filterable<'r, 'q> for Select<'r, 'q, T> {
-    type Table = T;
-}
-
-impl<'r, 'q, T: Entity> Resolvable<'r, 'q, T> for Select<'r, 'q, T> {
-    fn qi(&self) -> &'r QueryInterface<'q> {
-        self.qi
-    }
-}
-
-pub struct Delete<'r, 'q, T: Entity> {
-    qi: &'r QueryInterface<'q>,
-    _ghost: PhantomData<T>,
-}
-
-impl<'r, 'q, T: Entity> Delete<'r, 'q, T> {
-    pub fn new(qi: &'r QueryInterface<'q>) -> Self {
-        Self {
-            qi,
-            _ghost: std::marker::PhantomData,
-        }
-    }
-}
-
-impl<'r, 'q, T: Entity> StaticVersion for Delete<'r, 'q, T> {
-    type Is = Select<'static, 'static, T>;
-}
-
-impl<'r, 'q, T: Entity> QueryComponent for Delete<'r, 'q, T> {
-    fn derive(&self) -> DerivedQuery {
-        DerivedQuery::new().add(QueryPart::Root, format!("DELETE FROM {}", T::table_name()))
-    }
-
-    fn contribute<H: Hasher>(&self, hasher: &mut H) {
-        "delete".hash(hasher);
-        std::any::TypeId::of::<T>().hash(hasher);
-    }
-
-    // next binding point is the first
-    fn bind(&self, _stmt: &mut sqlite::Statement<'_>) -> Result<usize, Error> {
-        Ok(1)
-    }
-}
-
-impl<'r, 'q, T: Entity> Filterable<'r, 'q> for Delete<'r, 'q, T> {
-    type Table = T;
-}
-
-impl<'r, 'q, T: Entity> Resolvable<'r, 'q, T> for Delete<'r, 'q, T> {
-    fn qi(&self) -> &'r QueryInterface<'q> {
-        self.qi
-    }
-}
-
-/// A concrete WHERE clause
-pub struct Filter<'r, 'q, F: Filterable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized>
-where
-    'q: 'r,
-{
-    wrap: F,
-    col: C,
-    op: CompareOp,
-    given: &'r G,
-    _ghost: PhantomData<&'q ()>,
-}
-
-impl<'r, 'q, F: Filterable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized> StaticVersion
-    for Filter<'r, 'q, F, C, G>
-where
-    <F as StaticVersion>::Is: Filterable<'static, 'static>,
-{
-    type Is = Filter<'static, 'static, <F as StaticVersion>::Is, C, u64>;
-}
-
-impl<'r, 'q, F: Filterable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized> QueryComponent
-    for Filter<'r, 'q, F, C, G>
-where
-    <F as StaticVersion>::Is: Filterable<'static, 'static>,
-    'q: 'r,
-{
-    fn derive(&self) -> DerivedQuery {
-        self.wrap
-            .derive()
-            .add(QueryPart::Where, format!("{} {} ?", self.col.name(), self.op.ch()))
-    }
-
-    fn contribute<H: Hasher>(&self, hasher: &mut H) {
-        self.wrap.contribute(hasher);
-        std::any::TypeId::of::<Self::Is>().hash(hasher);
-        std::any::TypeId::of::<C>().hash(hasher);
-    }
-
-    fn bind(&self, stmt: &mut sqlite::Statement<'_>) -> Result<usize, crate::Error> {
-        let next_index = self.wrap.bind(stmt)?;
-
-        self.given.bind_to(stmt, next_index)?;
-
-        Ok(next_index + 1)
-    }
-}
-
-impl<'r, 'q, F: Filterable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized>
-    Resolvable<'r, 'q, C::Entity> for Filter<'r, 'q, F, C, G>
-where
-    <F as StaticVersion>::Is: Filterable<'static, 'static>,
-    'q: 'r,
-{
-    fn qi(&self) -> &'r QueryInterface<'q> {
-        self.wrap.qi()
-    }
-}
-
-impl<'r, 'q, F: Filterable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized> Filterable<'r, 'q>
-    for Filter<'r, 'q, F, C, G>
-where
-    <F as StaticVersion>::Is: Filterable<'static, 'static>,
-    'q: 'r,
-{
-    type Table = C::Entity;
-}

+ 49 - 0
microrm/src/query/delete.rs

@@ -0,0 +1,49 @@
+use std::marker::PhantomData;
+use std::hash::{Hash,Hasher};
+use crate::{Error,Entity,QueryInterface};
+use super::build::*;
+use super::{Filterable,Resolvable};
+
+pub struct Delete<'r, 'q, T: Entity> {
+    qi: &'r QueryInterface<'q>,
+    _ghost: PhantomData<T>,
+}
+
+impl<'r, 'q, T: Entity> Delete<'r, 'q, T> {
+    pub fn new(qi: &'r QueryInterface<'q>) -> Self {
+        Self {
+            qi,
+            _ghost: std::marker::PhantomData,
+        }
+    }
+}
+
+impl<'r, 'q, T: Entity> StaticVersion for Delete<'r, 'q, T> {
+    type Is = Delete<'static, 'static, T>;
+}
+
+impl<'r, 'q, T: Entity> QueryComponent for Delete<'r, 'q, T> {
+    fn derive(&self) -> DerivedQuery {
+        DerivedQuery::new().add(QueryPart::Root, format!("DELETE FROM {}", T::table_name()))
+    }
+
+    fn contribute<H: Hasher>(&self, hasher: &mut H) {
+        "delete".hash(hasher);
+        std::any::TypeId::of::<T>().hash(hasher);
+    }
+
+    // next binding point is the first
+    fn bind(&self, _stmt: &mut sqlite::Statement<'_>) -> Result<usize, Error> {
+        Ok(1)
+    }
+}
+
+impl<'r, 'q, T: Entity> Filterable<'r, 'q> for Delete<'r, 'q, T> {
+    type Table = T;
+}
+
+impl<'r, 'q, T: Entity> Resolvable<'r, 'q, T> for Delete<'r, 'q, T> {
+    fn qi(&self) -> &'r QueryInterface<'q> {
+        self.qi
+    }
+}

+ 116 - 0
microrm/src/query/filter.rs

@@ -0,0 +1,116 @@
+use std::marker::PhantomData;
+use std::hash::{Hash,Hasher};
+use crate::{Entity,entity::EntityColumn,WithID,QueryInterface,model::Modelable};
+use super::{Resolvable,build::CompareOp};
+use super::build::*;
+
+/// Any query that can have a WHERE clause attached to it
+pub trait Filterable<'r, 'q>: Resolvable<'r, 'q, Self::Table>
+where
+    'q: 'r,
+{
+    type Table: Entity;
+
+    fn by<C: EntityColumn<Entity = Self::Table>, G: Modelable + ?Sized>(
+        self,
+        col: C,
+        given: &'r G,
+    ) -> Filter<'r, 'q, Self, C, G>
+    where
+        Self: Sized,
+    {
+        Filter {
+            wrap: self,
+            col,
+            op: CompareOp::Equals,
+            given,
+            _ghost: PhantomData,
+        }
+    }
+
+    fn by_op<C: EntityColumn<Entity = Self::Table>, G: Modelable + ?Sized>(
+        self,
+        col: C,
+        op: CompareOp,
+        given: &'r G
+    ) -> Filter<'r, 'q, Self, C, G>
+    where
+        Self: Sized,
+    {
+        Filter {
+            wrap: self,
+            col,
+            op,
+            given,
+            _ghost: PhantomData,
+        }
+    }
+}
+
+/// A concrete WHERE clause
+pub struct Filter<'r, 'q, F: Filterable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized>
+where
+    'q: 'r,
+{
+    wrap: F,
+    col: C,
+    op: CompareOp,
+    given: &'r G,
+    _ghost: PhantomData<&'q ()>,
+}
+
+impl<'r, 'q, F: Filterable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized> StaticVersion
+    for Filter<'r, 'q, F, C, G>
+where
+    <F as StaticVersion>::Is: Filterable<'static, 'static>,
+{
+    type Is = Filter<'static, 'static, <F as StaticVersion>::Is, C, u64>;
+}
+
+impl<'r, 'q, F: Filterable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized> QueryComponent
+    for Filter<'r, 'q, F, C, G>
+where
+    <F as StaticVersion>::Is: Filterable<'static, 'static>,
+    'q: 'r,
+{
+    fn derive(&self) -> DerivedQuery {
+        self.wrap
+            .derive()
+            .add(QueryPart::Where, format!("{} {} ?", self.col.name(), self.op.ch()))
+    }
+
+    fn contribute<H: Hasher>(&self, hasher: &mut H) {
+        self.wrap.contribute(hasher);
+        std::any::TypeId::of::<Self::Is>().hash(hasher);
+        std::any::TypeId::of::<C>().hash(hasher);
+    }
+
+    fn bind(&self, stmt: &mut sqlite::Statement<'_>) -> Result<usize, crate::Error> {
+        let next_index = self.wrap.bind(stmt)?;
+
+        self.given.bind_to(stmt, next_index)?;
+
+        Ok(next_index + 1)
+    }
+}
+
+impl<'r, 'q, F: Filterable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized>
+    Resolvable<'r, 'q, C::Entity> for Filter<'r, 'q, F, C, G>
+where
+    <F as StaticVersion>::Is: Filterable<'static, 'static>,
+    'q: 'r,
+{
+    fn qi(&self) -> &'r QueryInterface<'q> {
+        self.wrap.qi()
+    }
+}
+
+impl<'r, 'q, F: Filterable<'r, 'q>, C: EntityColumn, G: Modelable + ?Sized> Filterable<'r, 'q>
+    for Filter<'r, 'q, F, C, G>
+where
+    <F as StaticVersion>::Is: Filterable<'static, 'static>,
+    'q: 'r,
+{
+    type Table = C::Entity;
+}
+

+ 81 - 0
microrm/src/query/resolve.rs

@@ -0,0 +1,81 @@
+use crate::{Entity,WithID,QueryInterface};
+use std::hash::Hasher;
+
+/// Any query that can be completed/executed
+pub trait Resolvable<'r, 'q, T: Entity>: super::build::QueryComponent
+where
+    'q: 'r,
+{
+    fn qi(&self) -> &'r QueryInterface<'q>;
+
+    fn exec(self) -> Result<(), crate::Error> where Self: Sized { self.no_result() }
+    fn one(self) -> Result<Option<WithID<T>>, crate::Error> where Self: Sized { self.result() }
+    fn all(self) -> Result<Vec<WithID<T>>, crate::Error> where Self: Sized { self.results() }
+
+    fn no_result(self) -> Result<(), crate::Error>
+    where
+        Self: Sized,
+    {
+        let mut hasher = std::collections::hash_map::DefaultHasher::new();
+        self.contribute(&mut hasher);
+
+        self.qi().with_cache(
+            hasher.finish(),
+            || self.qi().db.conn.prepare(self.derive().assemble()).unwrap(),
+            |stmt| {
+                self.bind(stmt)?;
+
+                self.qi().expect_no_result(stmt)
+            },
+        )
+    }
+    fn result(self) -> Result<Option<WithID<T>>, crate::Error>
+    where
+        Self: Sized,
+    {
+        let mut hasher = std::collections::hash_map::DefaultHasher::new();
+        self.contribute(&mut hasher);
+        self.qi().with_cache(
+            hasher.finish(),
+            || {
+                let query = self.derive().assemble();
+                self.qi().db.conn.prepare(query).unwrap()
+            },
+            |stmt| {
+                self.bind(stmt)?;
+
+                self.qi().expect_one_result(stmt, &mut |stmt| {
+                    let id: i64 = stmt.read(0)?;
+                    Ok(WithID::wrap(T::build_from(stmt)?, id))
+                })
+            },
+        )
+    }
+    fn results(self) -> Result<Vec<WithID<T>>, crate::Error>
+    where
+        Self: Sized,
+    {
+        let mut hasher = std::collections::hash_map::DefaultHasher::new();
+        self.contribute(&mut hasher);
+        self.qi().with_cache(
+            hasher.finish(),
+            || self.qi().db.conn.prepare(self.derive().assemble()).unwrap(),
+            |stmt| {
+                self.bind(stmt)?;
+
+                let mut res = Vec::new();
+                loop {
+                    let state = stmt.next()?;
+                    if state == sqlite::State::Done {
+                        break;
+                    }
+
+                    let id: i64 = stmt.read(0)?;
+                    res.push(WithID::wrap(T::build_from(stmt)?, id));
+                }
+
+                Ok(res)
+            },
+        )
+    }
+}

+ 52 - 0
microrm/src/query/select.rs

@@ -0,0 +1,52 @@
+use std::marker::PhantomData;
+use std::hash::{Hash,Hasher};
+use crate::{Entity,QueryInterface,Error};
+use super::build::{QueryComponent,StaticVersion,DerivedQuery,QueryPart};
+use super::{Filterable,Resolvable};
+
+pub struct Select<'r, 'q, T: Entity> {
+    qi: &'r QueryInterface<'q>,
+    _ghost: PhantomData<T>,
+}
+
+impl<'r, 'q, T: Entity> Select<'r, 'q, T> {
+    pub fn new(qi: &'r QueryInterface<'q>) -> Self {
+        Self {
+            qi,
+            _ghost: std::marker::PhantomData,
+        }
+    }
+}
+
+impl<'r, 'q, T: Entity> StaticVersion for Select<'r, 'q, T> {
+    type Is = Select<'static, 'static, T>;
+}
+
+impl<'r, 'q, T: Entity> QueryComponent for Select<'r, 'q, T> {
+    fn derive(&self) -> DerivedQuery {
+        DerivedQuery::new().add(
+            QueryPart::Root,
+            format!("SELECT * FROM {}", T::table_name()),
+        )
+    }
+
+    fn contribute<H: Hasher>(&self, hasher: &mut H) {
+        "select".hash(hasher);
+        std::any::TypeId::of::<T>().hash(hasher);
+    }
+
+    // next binding point is the first
+    fn bind(&self, _stmt: &mut sqlite::Statement<'_>) -> Result<usize, Error> {
+        Ok(1)
+    }
+}
+
+impl<'r, 'q, T: Entity> Filterable<'r, 'q> for Select<'r, 'q, T> {
+    type Table = T;
+}
+
+impl<'r, 'q, T: Entity> Resolvable<'r, 'q, T> for Select<'r, 'q, T> {
+    fn qi(&self) -> &'r QueryInterface<'q> {
+        self.qi
+    }
+}