use sqlx::PgPool;
use uuid::Uuid;
use crate::db::repositories::{
actions as actions_repo, assumptions as assumptions_repo, decisions as decisions_repo,
drift as drift_repo, evidence as evidence_repo, memos as memos_repo, relations as repo,
};
use crate::domain::relations::EntityRelation;
use crate::domain::{EntityType, RelationType};
use crate::error::{AppError, AppResult};
pub struct NewRelationInput {
pub from_entity_id: Uuid,
pub from_entity_type: EntityType,
pub to_entity_id: Uuid,
pub to_entity_type: EntityType,
pub relation_type: RelationType,
}
pub async fn create_relation(
pool: &PgPool,
input: NewRelationInput,
) -> AppResult<EntityRelation> {
if input.from_entity_id == input.to_entity_id {
return Err(AppError::Validation(
"a relation must connect two different entities".into(),
));
}
ensure_entity_exists(pool, input.from_entity_type, input.from_entity_id).await?;
ensure_entity_exists(pool, input.to_entity_type, input.to_entity_id).await?;
Ok(repo::create(
pool,
repo::NewRelation {
from_entity_id: input.from_entity_id,
from_entity_type: input.from_entity_type.as_str(),
to_entity_id: input.to_entity_id,
to_entity_type: input.to_entity_type.as_str(),
relation_type: input.relation_type.as_str(),
},
)
.await?)
}
pub fn default_relation_for(entity_type: EntityType) -> RelationType {
match entity_type {
EntityType::Assumption => RelationType::DependsOn,
EntityType::Action => RelationType::Produces,
EntityType::Evidence => RelationType::Supports,
_ => RelationType::RelatedTo,
}
}
pub async fn ensure_entity_exists(
pool: &PgPool,
entity_type: EntityType,
entity_id: Uuid,
) -> AppResult<()> {
let exists = match entity_type {
EntityType::Decision => decisions_repo::get(pool, entity_id).await?.is_some(),
EntityType::Assumption => assumptions_repo::get(pool, entity_id).await?.is_some(),
EntityType::Action => actions_repo::get(pool, entity_id).await?.is_some(),
EntityType::Evidence => evidence_repo::get(pool, entity_id).await?.is_some(),
EntityType::DriftSignal => drift_repo::get(pool, entity_id).await?.is_some(),
EntityType::Memo => memos_repo::get(pool, entity_id).await?.is_some(),
};
if exists {
Ok(())
} else {
Err(AppError::NotFound(format!(
"{} {entity_id} not found",
entity_type.as_str()
)))
}
}