use ifc_model::EntityId;
use crate::view::ClassificationView;
use crate::{ClassificationError, ClassificationResult};
mod classification;
mod document;
mod library;
pub use classification::ClassificationAssignment;
pub use document::DocumentAssignment;
pub use library::LibraryAssignment;
pub(crate) struct AssociationSchema {
pub relation: &'static str,
pub target_attribute: &'static str,
}
pub(crate) fn validate_assignment(
view: ClassificationView<'_>,
relation_id: EntityId,
related: &[EntityId],
target: EntityId,
contract: AssociationSchema,
) -> ClassificationResult<()> {
let AssociationSchema {
relation,
target_attribute,
} = contract;
let release = view.release();
let related_type = release.declared_type(relation, relation_id, "RelatedObjects")?;
for &id in related {
let entity = view
.model()
.get(id)
.ok_or(ClassificationError::DanglingReference {
entity: relation,
id: relation_id,
attribute: "RelatedObjects",
target: id,
})?;
if !release.accepts(relation, relation_id, "RelatedObjects", &entity.type_name)? {
return Err(ClassificationError::ReferenceType {
entity: relation,
id: relation_id,
attribute: "RelatedObjects",
target: id,
expected: related_type,
actual: entity.type_name.to_string(),
});
}
}
let entity = view
.model()
.get(target)
.ok_or(ClassificationError::DanglingReference {
entity: relation,
id: relation_id,
attribute: target_attribute,
target,
})?;
if release.accepts(relation, relation_id, target_attribute, &entity.type_name)? {
Ok(())
} else {
Err(ClassificationError::ReferenceType {
entity: relation,
id: relation_id,
attribute: target_attribute,
target,
expected: release.declared_type(relation, relation_id, target_attribute)?,
actual: entity.type_name.to_string(),
})
}
}