use crate::content_store::{AddContent, GetContent};
use crate::dht::dht_store::DhtStore;
use holochain_core_types::{
chain_header::ChainHeader,
crud_status::{create_crud_link_eav, create_crud_status_eav, CrudStatus},
eav::{Attribute, EaviQuery, EntityAttributeValueIndex},
entry::Entry,
error::{HcResult, HolochainError},
link::link_data::LinkData,
};
use holochain_persistence_api::{
cas::content::{Address, AddressableContent},
eav::IndexFilter,
};
use chrono::{DateTime, FixedOffset};
use std::{collections::BTreeSet, str::FromStr};
pub(crate) enum LinkModification {
Add,
Remove,
}
#[holochain_tracing_macros::newrelic_autotrace(HOLOCHAIN_CORE)]
pub(crate) fn reduce_store_entry_inner(store: &mut DhtStore, entry: &Entry) -> HcResult<()> {
match store.add(entry) {
Ok(()) => create_crud_status_eav(&entry.address(), CrudStatus::Live).map(|status_eav| {
store.add_eavi(&status_eav).map(|_| ()).map_err(|e| {
format!("err/dht: dht::reduce_store_entry_inner() FAILED {:?}", e).into()
})
})?,
Err(e) => Err(format!("err/dht: dht::reduce_store_entry_inner() FAILED {:?}", e).into()),
}
}
#[holochain_tracing_macros::newrelic_autotrace(HOLOCHAIN_CORE)]
pub(crate) fn reduce_add_remove_link_inner(
store: &mut DhtStore,
link: &LinkData,
address: &Address,
link_modification: LinkModification,
header: &ChainHeader,
) -> HcResult<Address> {
if store.contains(link.link().base())? {
let attr = match link_modification {
LinkModification::Add => Attribute::LinkTag(
link.link().link_type().to_string(),
link.link().tag().to_string(),
),
LinkModification::Remove => Attribute::RemovedLink(
header.entry_address().clone(),
link.link().link_type().to_string(),
link.link().tag().to_string(),
),
};
debug!(
"EAVI: Storing {:?} for {} based on link: {:?}",
attr, address, link
);
let link_created_time: DateTime<FixedOffset> = header.timestamp().into();
let eav = EntityAttributeValueIndex::new_with_index(
&link.link().base().clone(),
&attr,
address,
link_created_time.timestamp_nanos(),
)?;
store.add_eavi(&eav)?;
Ok(link.link().base().clone())
} else {
Err(HolochainError::ErrorGeneric(format!(
"Base for link not found: {:?}",
link
)))
}
}
#[holochain_tracing_macros::newrelic_autotrace(HOLOCHAIN_CORE)]
pub(crate) fn reduce_update_entry_inner(
store: &mut DhtStore,
old_address: &Address,
new_address: &Address,
) -> HcResult<Address> {
let new_status_eav = create_crud_status_eav(old_address, CrudStatus::Modified)?;
store.add_eavi(&new_status_eav)?;
let crud_link_eav = create_crud_link_eav(old_address, new_address)?;
store.add_eavi(&crud_link_eav)?;
Ok(new_address.clone())
}
#[holochain_tracing_macros::newrelic_autotrace(HOLOCHAIN_CORE)]
pub(crate) fn reduce_remove_entry_inner(
store: &mut DhtStore,
latest_deleted_address: &Address,
_deletion_address: &Address,
) -> HcResult<Address> {
let entry = store
.get(latest_deleted_address)?
.ok_or_else(|| HolochainError::ErrorGeneric("trying to remove a missing entry".into()))?;
if entry.entry_type().is_sys() {
return Err(HolochainError::ErrorGeneric(
"trying to remove a system entry type".into(),
));
}
let status_eavs = store.fetch_eavi(&EaviQuery::new(
Some(latest_deleted_address.clone()).into(),
Some(Attribute::CrudStatus).into(),
None.into(),
IndexFilter::LatestByAttribute,
None,
))?;
let status_eavs = status_eavs
.into_iter()
.filter(|e| CrudStatus::from_str(String::from(e.value()).as_ref()) != Ok(CrudStatus::Live))
.collect::<BTreeSet<EntityAttributeValueIndex>>();
if !status_eavs.is_empty() {
return Err(HolochainError::ErrorGeneric(
"entry_status != CrudStatus::Live".into(),
));
}
let new_status_eav = create_crud_status_eav(latest_deleted_address, CrudStatus::Deleted)
.map_err(|_| HolochainError::ErrorGeneric("Could not create eav".into()))?;
store.add_eavi(&new_status_eav)?;
Ok(latest_deleted_address.clone())
}