mod implicit_many_to_many;
mod inline;
mod two_way_embedded_many_to_many;
pub use implicit_many_to_many::{ImplicitManyToManyRelationTableName, ImplicitManyToManyRelationWalker};
pub use inline::{CompleteInlineRelationWalker, InlineRelationWalker};
pub use two_way_embedded_many_to_many::TwoWayEmbeddedManyToManyRelationWalker;
use crate::{ast, relations::*, walkers::*};
pub type RelationWalker<'db> = Walker<'db, RelationId>;
impl<'db> RelationWalker<'db> {
pub fn models(self) -> [ast::ModelId; 2] {
let rel = self.get();
[rel.model_a, rel.model_b]
}
pub fn relation_fields(self) -> impl Iterator<Item = RelationFieldWalker<'db>> {
let (a, b) = self.get().attributes.fields();
[a, b].into_iter().flatten().map(move |field| self.walk(field))
}
pub fn is_ignored(self) -> bool {
self.relation_fields().any(|f| {
f.is_ignored()
|| f.referencing_fields()
.into_iter()
.flatten()
.any(|scalar_field| scalar_field.is_ignored() || scalar_field.is_unsupported())
})
}
pub fn is_self_relation(self) -> bool {
let r = self.get();
r.model_a == r.model_b
}
pub fn refine(self) -> RefinedRelationWalker<'db> {
if self.get().is_implicit_many_to_many() {
RefinedRelationWalker::ImplicitManyToMany(self.walk(ManyToManyRelationId(self.id)))
} else if self.get().is_two_way_embedded_many_to_many() {
RefinedRelationWalker::TwoWayEmbeddedManyToMany(TwoWayEmbeddedManyToManyRelationWalker(self))
} else {
RefinedRelationWalker::Inline(InlineRelationWalker(self))
}
}
pub fn explicit_relation_name(self) -> Option<&'db str> {
self.get().relation_name.map(|string_id| &self.db[string_id])
}
pub fn relation_name(self) -> RelationName<'db> {
let relation = self.get();
relation
.relation_name
.map(|s| RelationName::Explicit(&self.db[s]))
.unwrap_or_else(|| {
RelationName::generated(self.walk(relation.model_a).name(), self.walk(relation.model_b).name())
})
}
fn get(self) -> &'db Relation {
&self.db.relations[self.id]
}
}
pub enum RefinedRelationWalker<'db> {
Inline(InlineRelationWalker<'db>),
ImplicitManyToMany(ImplicitManyToManyRelationWalker<'db>),
TwoWayEmbeddedManyToMany(TwoWayEmbeddedManyToManyRelationWalker<'db>),
}
impl<'db> RefinedRelationWalker<'db> {
pub fn as_inline(&self) -> Option<InlineRelationWalker<'db>> {
match self {
RefinedRelationWalker::Inline(inline) => Some(*inline),
_ => None,
}
}
pub fn as_many_to_many(&self) -> Option<ImplicitManyToManyRelationWalker<'db>> {
match self {
RefinedRelationWalker::ImplicitManyToMany(m2m) => Some(*m2m),
_ => None,
}
}
}