use super::op_error::ContractOpError;
use super::view::{ContractClaim, ContractSchemaState, RetrievedContract};
use crate::contracts::availability::{SchemaAvailability, SchemaFreshness};
use crate::contracts::conflict::conflicts_for;
use crate::contracts::knowledge_validity::item_validity_for;
use crate::contracts::retrieval::RetrievalPolicy;
use saya_store::{KnowledgeItem, KnowledgeItemStore, SqliteStateStore};
use saya_types::{DatabaseObjectRef, KnowledgeState};
pub(crate) async fn show(
store: &SqliteStateStore,
object: &DatabaseObjectRef,
schema: &SchemaAvailability,
policy: RetrievalPolicy,
now_unix_ms: i64,
) -> Result<Option<RetrievedContract>, ContractOpError> {
let items = store.knowledge_for_object(object).await?;
let kept: Vec<&KnowledgeItem> = items
.iter()
.filter(|it| !matches!(it.state, KnowledgeState::Dismissed))
.collect();
if kept.is_empty() {
return Ok(None);
}
let freshness = match policy {
RetrievalPolicy::ForModel => SchemaFreshness::for_model(now_unix_ms),
RetrievalPolicy::ForHumanReview => SchemaFreshness::Unbounded,
};
let mut state = ContractSchemaState::Current;
let mut claims: Vec<ContractClaim> = Vec::with_capacity(kept.len());
for item in &kept {
let validity = item_validity_for(item, schema, freshness);
state = state.aggregate(validity.into());
if let Some(carrier) = ContractClaim::from_knowledge_item(item) {
claims.push(carrier);
}
}
let conflicts = conflicts_for(&claims);
let (claims, conflicts) =
if policy == RetrievalPolicy::ForModel && state == ContractSchemaState::Stale {
(Vec::new(), Vec::new())
} else {
(claims, conflicts)
};
Ok(Some(RetrievedContract {
object: object.clone(),
schema_state: state,
claims,
conflicts,
truncated: false,
}))
}