mod complete;
pub use complete::CompleteInlineRelationWalker;
use super::RelationWalker;
use crate::{
relations::{OneToManyRelationFields, OneToOneRelationFields, Relation, RelationAttributes},
walkers::*,
};
#[derive(Copy, Clone)]
pub struct InlineRelationWalker<'db>(pub(super) RelationWalker<'db>);
impl<'db> InlineRelationWalker<'db> {
fn get(self) -> &'db Relation {
&self.0.db.relations[self.0.id]
}
pub fn is_one_to_one(self) -> bool {
matches!(self.get().attributes, RelationAttributes::OneToOne(_))
}
pub fn referencing_model(self) -> ModelWalker<'db> {
self.0.db.walk(self.get().model_a)
}
pub fn referenced_model(self) -> ModelWalker<'db> {
self.0.db.walk(self.get().model_b)
}
pub fn as_complete(self) -> Option<CompleteInlineRelationWalker<'db>> {
match (self.forward_relation_field(), self.back_relation_field()) {
(Some(field_a), Some(field_b)) => {
let walker = CompleteInlineRelationWalker {
side_a: field_a.id,
side_b: field_b.id,
db: self.0.db,
};
Some(walker)
}
_ => None,
}
}
pub fn referencing_fields(self) -> Option<impl ExactSizeIterator<Item = ScalarFieldWalker<'db>>> {
self.forward_relation_field().and_then(|rf| rf.fields())
}
pub fn referenced_fields(self) -> Box<dyn Iterator<Item = ScalarFieldWalker<'db>> + 'db> {
self.forward_relation_field()
.and_then(
|field: RelationFieldWalker<'db>| -> Option<Box<dyn Iterator<Item = ScalarFieldWalker<'db>>>> {
field
.referenced_fields()
.map(|fields| Box::new(fields) as Box<dyn Iterator<Item = ScalarFieldWalker<'db>>>)
},
)
.unwrap_or_else(move || {
Box::new(
self.referenced_model()
.unique_criterias()
.find(|c| c.is_strict_criteria())
.into_iter()
.flat_map(|c| c.fields())
.filter_map(|f| f.as_scalar_field()),
)
})
}
pub fn forward_relation_field(self) -> Option<RelationFieldWalker<'db>> {
let rel = self.get();
match rel.attributes {
RelationAttributes::OneToOne(OneToOneRelationFields::Forward(a))
| RelationAttributes::OneToOne(OneToOneRelationFields::Both(a, _))
| RelationAttributes::OneToMany(OneToManyRelationFields::Both(a, _))
| RelationAttributes::OneToMany(OneToManyRelationFields::Forward(a)) => Some(self.0.walk(a)),
RelationAttributes::OneToMany(OneToManyRelationFields::Back(_)) => None,
RelationAttributes::ImplicitManyToMany { field_a: _, field_b: _ } => unreachable!(),
RelationAttributes::TwoWayEmbeddedManyToMany { field_a: _, field_b: _ } => unreachable!(),
}
}
pub fn mapped_name(self) -> Option<&'db str> {
self.forward_relation_field().and_then(|field| field.mapped_name())
}
pub fn back_relation_field(self) -> Option<RelationFieldWalker<'db>> {
let rel = self.get();
match rel.attributes {
RelationAttributes::OneToOne(OneToOneRelationFields::Both(_, b))
| RelationAttributes::OneToMany(OneToManyRelationFields::Both(_, b))
| RelationAttributes::OneToMany(OneToManyRelationFields::Back(b)) => Some(self.0.walk(b)),
RelationAttributes::OneToMany(OneToManyRelationFields::Forward(_))
| RelationAttributes::OneToOne(OneToOneRelationFields::Forward(_)) => None,
RelationAttributes::ImplicitManyToMany { field_a: _, field_b: _ } => unreachable!(),
RelationAttributes::TwoWayEmbeddedManyToMany { field_a: _, field_b: _ } => unreachable!(),
}
}
pub fn relation_id(self) -> crate::RelationId {
self.0.id
}
pub fn explicit_relation_name(self) -> Option<&'db str> {
self.0.explicit_relation_name()
}
pub fn relation_name(self) -> RelationName<'db> {
self.explicit_relation_name()
.map(RelationName::Explicit)
.unwrap_or_else(|| RelationName::generated(self.referencing_model().name(), self.referenced_model().name()))
}
}