pub struct Morph { /* private fields */ }Expand description
A polymorphic relation: a child row that belongs to one of several parent tables, through a type column holding the parent’s table name and an id column, e.g. comments on both posts and videos:
use renox::db::relations::Morph;
#[derive(Model, serde::Serialize, Default, Clone)]
struct Comment { id: i64, commentable_type: String, commentable_id: i64, body: String }
const COMMENTABLE: Morph = Morph::new("commentable_type", "commentable_id");
Comment::create(&db, Comment {
commentable_type: Post::TABLE.into(), // "posts"
commentable_id: post.id,
body: "Nice".into(),
..Default::default()
}).await?;
let posts = Post::query().latest().limit(20).get(&db).await?;
let comments = COMMENTABLE.load_many(&db, &posts, Comment::query(), |c| c.commentable_id).await?;
let on_this_post = COMMENTABLE.of(&post, Comment::query()).count(&db).await?;
// The other way: each comment's parent, one query per parent type.
let recent = Comment::query().latest().limit(50).get(&db).await?;
let parent = |c: &Comment| (c.commentable_type.clone(), c.commentable_id);
let post_parents = COMMENTABLE.parents::<Post, _>(&db, &recent, parent).await?;
let video_parents = COMMENTABLE.parents::<Video, _>(&db, &recent, parent).await?;There’s no foreign key to the parents, so deleting a parent doesn’t
delete its children: do it in the parent’s deleting hook
(ModelHooks) or its delete handler.
Implementations§
Source§impl Morph
impl Morph
Sourcepub const fn new(type_column: &'static str, id_column: &'static str) -> Self
pub const fn new(type_column: &'static str, id_column: &'static str) -> Self
A polymorphic relation stored in type_column (the parent’s table) and id_column.
Sourcepub fn of<C: Model, P: Model>(&self, parent: &P, children: Query<C>) -> Query<C>
pub fn of<C: Model, P: Model>(&self, parent: &P, children: Query<C>) -> Query<C>
children narrowed to those of parent.
Sourcepub fn load_many<'a, C: Model, P: Model>(
&self,
db: &'a Db,
parents: &[P],
children: Query<C>,
foreign_key: impl Fn(&C) -> P::Key + Send + 'a,
) -> impl Future<Output = Result<HashMap<P::Key, Vec<C>>>> + Send + 'a
pub fn load_many<'a, C: Model, P: Model>( &self, db: &'a Db, parents: &[P], children: Query<C>, foreign_key: impl Fn(&C) -> P::Key + Send + 'a, ) -> impl Future<Output = Result<HashMap<P::Key, Vec<C>>>> + Send + 'a
The children of each parent, grouped by the parent’s id, in one
query (has_many for a polymorphic relation). foreign_key reads
the id column.
Sourcepub fn count_many<'a, C: Model, P: Model>(
&self,
db: &'a Db,
parents: &[P],
children: Query<C>,
) -> impl Future<Output = Result<HashMap<P::Key, i64>>> + Send + 'a
pub fn count_many<'a, C: Model, P: Model>( &self, db: &'a Db, parents: &[P], children: Query<C>, ) -> impl Future<Output = Result<HashMap<P::Key, i64>>> + Send + 'a
How many children each parent has, in one GROUP BY query (0 for
parents without any): withCount for a polymorphic relation.
Sourcepub fn parents<'a, P: Model, C>(
&self,
db: &'a Db,
children: &[C],
parent: impl Fn(&C) -> (String, P::Key),
) -> impl Future<Output = Result<HashMap<P::Key, P>>> + Send + 'a
pub fn parents<'a, P: Model, C>( &self, db: &'a Db, children: &[C], parent: impl Fn(&C) -> (String, P::Key), ) -> impl Future<Output = Result<HashMap<P::Key, P>>> + Send + 'a
The parents of type P of these children, by id, in one query;
parent reads a child’s type and id columns. Children of other
parent types are skipped: call it once per type.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Morph
impl RefUnwindSafe for Morph
impl Send for Morph
impl Sync for Morph
impl Unpin for Morph
impl UnsafeUnpin for Morph
impl UnwindSafe for Morph
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<A, B, T> HttpServerConnExec<A, B> for Twhere
B: Body,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more