|
@@ -1,36 +1,161 @@
|
|
|
-use crate::{Entity, model::Modelable};
|
|
|
+use crate::{Entity, model::Modelable, entity::EntityColumn};
|
|
|
|
|
|
use std::marker::PhantomData;
|
|
|
|
|
|
+pub trait BuildingBlock {
|
|
|
+ fn build_query(&self) -> String { String::new() }
|
|
|
+}
|
|
|
+
|
|
|
pub struct Builder { }
|
|
|
|
|
|
impl Builder {
|
|
|
pub fn get<T: Entity>() -> Select<T> { Select { _ghost: PhantomData } }
|
|
|
+ pub fn update<T: Entity>() -> Update<T> { Update { _ghost: PhantomData } }
|
|
|
}
|
|
|
|
|
|
pub struct Select<T: Entity> {
|
|
|
_ghost: PhantomData<T>,
|
|
|
}
|
|
|
|
|
|
-/*impl<T: Entity> Select<T> {
|
|
|
-}*/
|
|
|
+pub trait Conditionable: BuildingBlock {
|
|
|
+ type Table: Entity;
|
|
|
+
|
|
|
+ fn with<G: Modelable, Col: EntityColumn<Entity = Self::Table>>(self, column: Col, _given: G) -> WhereClause<Self, Col, Self::Table, G> where Self: Sized {
|
|
|
+ WhereClause { conditionable: self, column, _ghost: PhantomData }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: Entity> Conditionable for Select<T> {
|
|
|
+ type Table = T;
|
|
|
+}
|
|
|
+
|
|
|
+pub struct WhereClause<S: Conditionable<Table = T>, Col: EntityColumn<Entity = T>, T: Entity, Given: Modelable> {
|
|
|
+ conditionable: S,
|
|
|
+ column: Col,
|
|
|
+ _ghost: PhantomData<(S,Col,Given)>
|
|
|
+}
|
|
|
+
|
|
|
+impl<S: Conditionable<Table = T>, Col: EntityColumn<Entity = T>, T: Entity, Given: Modelable> Conditionable for WhereClause<S, Col, T, Given> {
|
|
|
+ type Table = T;
|
|
|
+}
|
|
|
|
|
|
-pub trait Selectable {
|
|
|
+pub trait Joinable: BuildingBlock {
|
|
|
type Table: Entity;
|
|
|
|
|
|
- fn given<G: Modelable>(self, column: <Self::Table as Entity>::Column, given: G) -> SelectGiven<Self, Self::Table, G> where Self: Sized;
|
|
|
- // fn given_id(self, id: <Self::Table as Entity>::ID) -> SelectGiven<Table = Self::Table> where Self: Sized;
|
|
|
+ fn join<BaseColumn: EntityColumn<Entity = Self::Table>, Target: Entity, TargetColumn: EntityColumn<Entity = Target>>(self, base_column: BaseColumn, target_column: TargetColumn) -> JoinClause<Self::Table, Self, BaseColumn, Target, TargetColumn> where Self: Sized {
|
|
|
+ JoinClause { joinable: self, base_column, target_column, _ghost: PhantomData }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-pub struct SelectGiven<S: Selectable<Table = T>, T: Entity, Given: Modelable> {
|
|
|
- column: <T as Entity>::Column,
|
|
|
- _ghost: (PhantomData<S>, PhantomData<Given>)
|
|
|
+pub struct JoinClause<T: Entity, Base: Joinable<Table = T>, BaseColumn: EntityColumn<Entity = T>, Target: Entity, TargetColumn: EntityColumn<Entity = Target>> {
|
|
|
+ joinable: Base,
|
|
|
+ base_column: BaseColumn,
|
|
|
+ target_column: TargetColumn,
|
|
|
+ _ghost: PhantomData<(Base, BaseColumn, Target, TargetColumn)>
|
|
|
}
|
|
|
|
|
|
-impl<S: Selectable<Table = T>, T: Entity, Given: Modelable> Selectable for SelectGiven<S, T, Given> {
|
|
|
+impl<T: Entity> Joinable for Select<T> {
|
|
|
type Table = T;
|
|
|
+}
|
|
|
+
|
|
|
+impl<S: Joinable + Conditionable<Table = T>, T: Entity, Col: EntityColumn<Entity = T>, Given: Modelable> Joinable for WhereClause<S, Col, T, Given> {
|
|
|
+ type Table = T;
|
|
|
+}
|
|
|
+
|
|
|
+pub struct Update<T: Entity> {
|
|
|
+ _ghost: PhantomData<T>,
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: Entity> Conditionable for Update<T> {
|
|
|
+ type Table = T;
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: Entity> Settable for Update<T> {
|
|
|
+ type Table = T;
|
|
|
+}
|
|
|
+
|
|
|
+pub trait Settable {
|
|
|
+ type Table: Entity;
|
|
|
+
|
|
|
+ fn update<G: Modelable, Col: EntityColumn<Entity = Self::Table>>(self, column: Col, _given: G) -> SetClause<Self, Col, Self::Table, G> where Self: Sized {
|
|
|
+ SetClause { settable: self, column, _ghost: (PhantomData, PhantomData, PhantomData) }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub struct SetClause<S: Settable<Table = T>, Col: EntityColumn<Entity = T>, T: Entity, Given: Modelable> {
|
|
|
+ settable: S,
|
|
|
+ column: Col,
|
|
|
+ _ghost: (PhantomData<S>, PhantomData<Col>, PhantomData<Given>)
|
|
|
+}
|
|
|
+
|
|
|
+impl<S: Settable<Table = T>, Col: EntityColumn<Entity = T>, T: Entity, Given: Modelable> Conditionable for SetClause<S, Col, T, Given> {
|
|
|
+ type Table = T;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+// BuildingBlock implementations
|
|
|
+impl<T: Entity> BuildingBlock for Select<T> {
|
|
|
+ fn build_query(&self) -> String {
|
|
|
+ format!("SELECT * FROM {} WHERE true", T::table_name())
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<S: Conditionable<Table = T>, Col: EntityColumn<Entity = T>, T: Entity, Given: Modelable> BuildingBlock for WhereClause<S, Col, T, Given> {
|
|
|
+ fn build_query(&self) -> String {
|
|
|
+ format!("{} AND {} = ?", self.conditionable.build_query(), self.column.name())
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: Entity, Base: Joinable<Table = T>, BaseColumn: EntityColumn<Entity = T>, Target: Entity, TargetColumn: EntityColumn<Entity = Target>> BuildingBlock for JoinClause<T, Base, BaseColumn, Target, TargetColumn> {
|
|
|
+ fn build_query(&self) -> String {
|
|
|
+ format!("{} JOIN {} ON {}.{} = {}.{}",
|
|
|
+ self.joinable.build_query(),
|
|
|
+ self.target_column.table_name(),
|
|
|
+ self.base_column.table_name(),
|
|
|
+ self.base_column.name(),
|
|
|
+ self.target_column.table_name(),
|
|
|
+ self.target_column.name())
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: Entity> BuildingBlock for Update<T> {
|
|
|
+ fn build_query(&self) -> String {
|
|
|
+ format!("update?")
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<S: Settable<Table = T>, Col: EntityColumn<Entity = T>, T: Entity, Given: Modelable> BuildingBlock for SetClause<S, Col, T, Given> {
|
|
|
+ fn build_query(&self) -> String {
|
|
|
+ //format!("UPDATE {} SET {} = ? WHERE true", T::table_name(), self.column.name())
|
|
|
+ format!("<>")
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[cfg(test)]
|
|
|
+mod builder_test {
|
|
|
+ use super::*;
|
|
|
+
|
|
|
+ #[derive(crate::Entity, serde::Deserialize, serde::Serialize)]
|
|
|
+ #[microrm_internal]
|
|
|
+ pub struct SimpleEntity {
|
|
|
+ a: usize,
|
|
|
+ b: usize
|
|
|
+ }
|
|
|
+
|
|
|
+ #[derive(crate::Entity, serde::Deserialize, serde::Serialize)]
|
|
|
+ #[microrm_internal]
|
|
|
+ pub struct ChildType {
|
|
|
+ r: SimpleEntityID,
|
|
|
+ b: usize
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn simple_builder_select_test() {
|
|
|
+ println!("{}", Builder::get::<SimpleEntity>().build_query());
|
|
|
+ println!("{}", Builder::get::<SimpleEntity>().with(SimpleEntity::A, 0u8).with(SimpleEntity::B, 1u8).build_query());
|
|
|
+
|
|
|
+ println!("{}", Builder::get::<SimpleEntity>().with(SimpleEntity::A, 0u8).join(SimpleEntity::ID, ChildType::R).build_query());
|
|
|
|
|
|
- fn given<G: Modelable>(self, column: <Self::Table as Entity>::Column, given: G) -> SelectGiven<Self, Self::Table, G> where Self: Sized {
|
|
|
- todo!()
|
|
|
+ println!("{}", Builder::update::<SimpleEntity>().update(SimpleEntity::A, 1u8).with(SimpleEntity::ID, 1u8).build_query());
|
|
|
}
|
|
|
}
|