|
@@ -12,7 +12,7 @@ use crate::{
|
|
},
|
|
},
|
|
};
|
|
};
|
|
|
|
|
|
-use super::Query;
|
|
|
|
|
|
+use super::{ContainerEntityChange, Query};
|
|
|
|
|
|
/// Allow manipulation of an entire table.
|
|
/// Allow manipulation of an entire table.
|
|
pub(crate) struct TableComponent<E: Entity> {
|
|
pub(crate) struct TableComponent<E: Entity> {
|
|
@@ -76,7 +76,7 @@ impl<WEP: EntityPart, Parent: Queryable, QE: QueryEquivalent<WEP::Datum>>
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-/// this workaround is needed because we very explicitly would like EL to not be a
|
|
|
|
|
|
+/// this workaround is needed because we very explicitly would like QE to not be a
|
|
/// 'static-restricted type, and it doesn't matter for the purposes of actually distinguishing
|
|
/// 'static-restricted type, and it doesn't matter for the purposes of actually distinguishing
|
|
/// between queries.
|
|
/// between queries.
|
|
#[derive(Clone)]
|
|
#[derive(Clone)]
|
|
@@ -416,42 +416,90 @@ impl<
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-/*
|
|
|
|
-SQL mapping:
|
|
|
|
-
|
|
|
|
-MapQueryable<E>::get()
|
|
|
|
- -> SELECT * FROM {E::entity_name()}
|
|
|
|
-
|
|
|
|
-UniqueComponent<E, MapQueryable<E>>::get()
|
|
|
|
- -> SELECT * FROM {E::entity_name()} WHERE `col1` = ? AND `col2` = ? AND ...
|
|
|
|
-
|
|
|
|
-WithComponent<E, EP, MapQueryable<E>>::get()
|
|
|
|
- -> SELECT * FROM {E::entity_name()} WHERE `col1` = ?
|
|
|
|
-
|
|
|
|
-RelationQueryable<AI>::get()
|
|
|
|
- -> SELECT
|
|
|
|
- `{AI::RemoteEntity::entity_name()}`.*
|
|
|
|
- FROM `{relation_table_name}`
|
|
|
|
- LEFT JOIN `{AI::RemoteEntity::entity_name()}`.id = `{relation_table_name}`.`{remote_field}`
|
|
|
|
- WHERE `{relation_table_name}`.`{local_field}` = ?
|
|
|
|
-
|
|
|
|
-UniqueComponent<E, RelationQueryable<AI>>::get()
|
|
|
|
- -> SELECT
|
|
|
|
- `{AI::RemoteEntity::entity_name()}`.*
|
|
|
|
- FROM `{relation_table_name}`
|
|
|
|
- LEFT JOIN `{AI::RemoteEntity::entity_name()}`.id = `{relation_table_name}`.`{remote_field}`
|
|
|
|
- WHERE
|
|
|
|
- `{relation_table_name}`.`{local_field}` = ?
|
|
|
|
- AND `{AI::RemoteEntity::entity_name()}`.`col1` = ?
|
|
|
|
- AND `{AI::RemoteEntity::entity_name()}`.`col2` = ?
|
|
|
|
- ...
|
|
|
|
-
|
|
|
|
-JoinComponent<R, E, EP, MapQueryable<E>>::get()
|
|
|
|
- -> SELECT DISTINCT
|
|
|
|
- `{R::entity_name()}`.*
|
|
|
|
- FROM
|
|
|
|
- `{E::entity_name()}`
|
|
|
|
- LEFT JOIN `{relation_table_name}` ON `{E::entity_name()}`.`id` = `{relation_table_name}`.`{local_field}`
|
|
|
|
- LEFT JOIN `{R::entity_name()}` ON `{relation_table_name}`.`{remote_field}` = `{R::entity_name()}`.`id`
|
|
|
|
-
|
|
|
|
-*/
|
|
|
|
|
|
+/// Get an entity via a foreign key
|
|
|
|
+pub(crate) struct ForeignComponent<FE: Entity, EP: EntityPart, Parent: Queryable> {
|
|
|
|
+ parent: Parent,
|
|
|
|
+ _ghost: std::marker::PhantomData<(FE, EP)>,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<FE: Entity, EP: EntityPart, Parent: Queryable> ForeignComponent<FE, EP, Parent> {
|
|
|
|
+ pub fn new(parent: Parent, _part: EP) -> Self {
|
|
|
|
+ Self {
|
|
|
|
+ parent,
|
|
|
|
+ _ghost: Default::default(),
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<FE: Entity, EP: EntityPart, Parent: Queryable> Clone for ForeignComponent<FE, EP, Parent> {
|
|
|
|
+ fn clone(&self) -> Self {
|
|
|
|
+ Self {
|
|
|
|
+ parent: self.parent.clone(),
|
|
|
|
+ _ghost: Default::default(),
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+pub(crate) struct CanonicalForeignComponent<FE: Entity, EP: EntityPart, Parent: Queryable> {
|
|
|
|
+ _ghost: std::marker::PhantomData<(FE, EP, Parent)>,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<FE: Entity, EP: EntityPart, Parent: Queryable> Clone
|
|
|
|
+ for CanonicalForeignComponent<FE, EP, Parent>
|
|
|
|
+{
|
|
|
|
+ fn clone(&self) -> Self {
|
|
|
|
+ Self {
|
|
|
|
+ _ghost: Default::default(),
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<FE: Entity, EP: EntityPart, Parent: Queryable> Queryable
|
|
|
|
+ for CanonicalForeignComponent<FE, EP, Parent>
|
|
|
|
+{
|
|
|
|
+ type EntityOutput = FE;
|
|
|
|
+ type OutputContainer = Option<Stored<FE>>;
|
|
|
|
+ type StaticVersion = CanonicalForeignComponent<FE, EP, Parent::StaticVersion>;
|
|
|
|
+
|
|
|
|
+ fn build(&self) -> Query {
|
|
|
|
+ unreachable!()
|
|
|
|
+ }
|
|
|
|
+ fn bind(&self, _stmt: &mut StatementContext, _index: &mut i32) {
|
|
|
|
+ unreachable!()
|
|
|
|
+ }
|
|
|
|
+ fn conn(&self) -> &Connection {
|
|
|
|
+ unreachable!()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<FE: Entity, EP: EntityPart, Parent: Queryable> Queryable for ForeignComponent<FE, EP, Parent>
|
|
|
|
+where
|
|
|
|
+ Parent::OutputContainer: ContainerEntityChange<Parent::EntityOutput, FE>,
|
|
|
|
+{
|
|
|
|
+ type EntityOutput = FE;
|
|
|
|
+ type StaticVersion = CanonicalForeignComponent<FE, EP, Parent::StaticVersion>;
|
|
|
|
+ type OutputContainer =
|
|
|
|
+ <Parent::OutputContainer as ContainerEntityChange<Parent::EntityOutput, FE>>::Container;
|
|
|
|
+
|
|
|
|
+ fn build(&self) -> Query {
|
|
|
|
+ let subquery = self.parent.build().replace(
|
|
|
|
+ QueryPart::Columns,
|
|
|
|
+ format!("`{}`.`id`", EP::Entity::entity_name()),
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ Query::new()
|
|
|
|
+ .attach(QueryPart::Root, "SELECT DISTINCT".into())
|
|
|
|
+ .attach(QueryPart::Columns, "*".into())
|
|
|
|
+ .attach(QueryPart::From, FE::entity_name().into())
|
|
|
|
+ .attach(
|
|
|
|
+ QueryPart::Where,
|
|
|
|
+ format!("`{}`.`id` = ({})", FE::entity_name(), subquery.assemble()),
|
|
|
|
+ )
|
|
|
|
+ }
|
|
|
|
+ fn bind(&self, stmt: &mut StatementContext, index: &mut i32) {
|
|
|
|
+ self.parent.bind(stmt, index)
|
|
|
|
+ }
|
|
|
|
+ fn conn(&self) -> &Connection {
|
|
|
|
+ self.parent.conn()
|
|
|
|
+ }
|
|
|
|
+}
|