use crate::{
db::{
Db,
relation::{
for_each_relation_target_value,
metadata::{StrongRelationInfo, strong_relations_for_model_iter},
raw_relation_target_key_from_value,
},
},
error::InternalError,
traits::{EntityKind, EntityValue},
value::Value,
};
pub(in crate::db) fn validate_save_strong_relations<E>(
db: &Db<E::Canister>,
entity: &E,
) -> Result<(), InternalError>
where
E: EntityKind + EntityValue,
{
for relation in strong_relations_for_model_iter(E::MODEL, None) {
let value = entity
.get_value_by_index(relation.field_index)
.ok_or_else(|| {
InternalError::executor_invariant(format!(
"entity field missing: {} field={}",
E::PATH,
relation.field_name
))
})?;
for_each_relation_target_value(&value, |item| {
validate_save_relation_value::<E>(db, relation, item)
})?;
}
Ok(())
}
fn validate_save_relation_value<E>(
db: &Db<E::Canister>,
relation: StrongRelationInfo,
value: &Value,
) -> Result<(), InternalError>
where
E: EntityKind + EntityValue,
{
let raw_key = raw_relation_target_key_from_value(
relation.target_entity_tag,
relation.target_entity_name,
value,
)
.map_err(|err| {
InternalError::relation_target_raw_key_error(
err,
E::PATH,
relation.field_name,
relation.target_path,
relation.target_entity_name,
value,
"strong relation key not storage-compatible",
"strong relation target name invalid",
)
})?;
let store = db
.with_store_registry(|reg| reg.try_get_store(relation.target_store_path))
.map_err(|err| {
InternalError::strong_relation_target_store_missing(
E::PATH,
relation.field_name,
relation.target_path,
relation.target_store_path,
value,
err,
)
})?;
let exists = store.with_data(|s| s.contains_key(&raw_key));
if !exists {
return Err(InternalError::strong_relation_target_missing(
E::PATH,
relation.field_name,
relation.target_path,
value,
));
}
Ok(())
}