use async_trait::async_trait;
use energyml_core::reflect::TypeInfo;
use energyml_core::registry::DynObject;
use crate::array::{ArrayData, ArrayLocation, ArrayMetadata};
use crate::error::Result;
use crate::resource::{Dataspace, ObjectHeader, ObjectSummary};
#[cfg(target_arch = "wasm32")]
pub use async_trait::async_trait as storage_async_trait;
#[allow(clippy::double_must_use)]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
pub trait EnergymlStorage {
fn store_kind(&self) -> &'static str;
async fn dataspaces(&self) -> Result<Vec<Dataspace>>;
async fn resources(&self) -> Result<Vec<ObjectSummary>>;
async fn headers(&self, uris: &[String]) -> Vec<Result<ObjectHeader>>;
async fn get_objects(&self, uris: &[String]) -> Vec<Result<Box<dyn DynObject>>>;
async fn supported_types(&self) -> Vec<&'static TypeInfo>;
fn arrays_of(&self, object: &dyn energyml_core::value::Reflect) -> Vec<ArrayLocation>;
async fn array_metadata(&self, location: &ArrayLocation) -> Result<ArrayMetadata>;
async fn read_array(&self, location: &ArrayLocation) -> Result<ArrayData>;
fn diagnostics(&self) -> Vec<crate::error::Diagnostic>;
async fn get_object(&self, uri: &str) -> Result<Box<dyn DynObject>> {
let mut results = self.get_objects(std::slice::from_ref(&uri.to_string())).await;
results
.pop()
.unwrap_or_else(|| Err(crate::error::Error::NotFound(uri.to_string())))
}
async fn header(&self, uri: &str) -> Result<ObjectHeader> {
let mut results = self.headers(std::slice::from_ref(&uri.to_string())).await;
results
.pop()
.unwrap_or_else(|| Err(crate::error::Error::NotFound(uri.to_string())))
}
async fn edges(&self, uris: &[String]) -> Result<Vec<crate::graph::Edge>> {
Ok(self.derived_graph(uris).await?.edges)
}
async fn graph(&self, uris: &[String]) -> Result<crate::graph::Graph> {
let all = self.resources().await?;
let wanted: Vec<ObjectSummary> = if uris.is_empty() {
all
} else {
all.into_iter().filter(|s| uris.contains(&s.uri)).collect()
};
let edges = self.edges(uris).await?;
let of_wanted: Vec<String> = wanted.iter().map(|s| s.uri.clone()).collect();
let headers = self.headers(&of_wanted).await;
let titles: std::collections::HashMap<String, String> = headers
.into_iter()
.flatten()
.filter_map(|header| {
header
.title
.filter(|t| !t.trim().is_empty())
.map(|title| (header.summary.uri, title))
})
.collect();
Ok(crate::graph::assemble(
wanted.iter(),
&|uri: &str| titles.get(uri).cloned(),
edges,
))
}
async fn derived_graph(&self, uris: &[String]) -> Result<crate::graph::Graph> {
let all = self.resources().await?;
let wanted: Vec<ObjectSummary> = if uris.is_empty() {
all
} else {
all.into_iter().filter(|s| uris.contains(&s.uri)).collect()
};
let of_wanted: Vec<String> = wanted.iter().map(|s| s.uri.clone()).collect();
let objects = self.get_objects(&of_wanted).await;
let held: Vec<(ObjectSummary, Box<dyn DynObject>)> = wanted
.into_iter()
.zip(objects)
.filter_map(|(summary, object)| object.ok().map(|object| (summary, object)))
.collect();
Ok(crate::graph::build(
held.iter()
.map(|(summary, object)| (summary, object.as_reflect())),
))
}
}
pub trait LocalPackage {
fn attachments(&self) -> Vec<String>;
fn read_attachment(&self, part: &str) -> Result<Vec<u8>>;
fn relationships(&self, part: &str) -> Result<Vec<crate::resource::Relationship>>;
}