decision_cockpit 0.1.0

Layer — product decision memory with MCP tools and an embedded review dashboard
Documentation
use sqlx::PgPool;
use uuid::Uuid;

use crate::domain::relations::EntityRelation;

pub struct NewRelation<'a> {
    pub from_entity_id: Uuid,
    pub from_entity_type: &'a str,
    pub to_entity_id: Uuid,
    pub to_entity_type: &'a str,
    pub relation_type: &'a str,
}

pub async fn create(pool: &PgPool, new: NewRelation<'_>) -> Result<EntityRelation, sqlx::Error> {
    let id = Uuid::new_v4();
    sqlx::query_as::<_, EntityRelation>(
        r#"
        INSERT INTO entity_relations
            (id, from_entity_id, from_entity_type, to_entity_id, to_entity_type, relation_type)
        VALUES ($1, $2, $3, $4, $5, $6)
        RETURNING id, from_entity_id, from_entity_type, to_entity_id, to_entity_type,
                  relation_type, created_at
        "#,
    )
    .bind(id)
    .bind(new.from_entity_id)
    .bind(new.from_entity_type)
    .bind(new.to_entity_id)
    .bind(new.to_entity_type)
    .bind(new.relation_type)
    .fetch_one(pool)
    .await
}

pub async fn list_all(pool: &PgPool) -> Result<Vec<EntityRelation>, sqlx::Error> {
    sqlx::query_as::<_, EntityRelation>(
        r#"
        SELECT id, from_entity_id, from_entity_type, to_entity_id, to_entity_type,
               relation_type, created_at
        FROM entity_relations
        ORDER BY created_at DESC
        "#,
    )
    .fetch_all(pool)
    .await
}

/// All relations that touch a given entity (as either endpoint).
pub async fn list_for_entity(
    pool: &PgPool,
    entity_id: Uuid,
) -> Result<Vec<EntityRelation>, sqlx::Error> {
    sqlx::query_as::<_, EntityRelation>(
        r#"
        SELECT id, from_entity_id, from_entity_type, to_entity_id, to_entity_type,
               relation_type, created_at
        FROM entity_relations
        WHERE from_entity_id = $1 OR to_entity_id = $1
        ORDER BY created_at DESC
        "#,
    )
    .bind(entity_id)
    .fetch_all(pool)
    .await
}