use ciborium::Value as CborValue;
use vantage_core::{Context, Result, error};
use vantage_table::table::Table;
use vantage_types::{EmptyEntity, Record};
use vantage_vista::{Vista, unknown_relation};
use crate::graphql::api::GraphqlApi;
use crate::graphql::vista::factory::{GraphqlApiVistaFactory, wrap_spec_table};
use crate::graphql::vista::lowering::{TargetSpec, build_table};
use crate::graphql::vista::source::GraphqlApiTableShell;
pub(crate) type BareTarget = Table<GraphqlApi, EmptyEntity>;
impl GraphqlApiTableShell {
pub(crate) fn spec_target(&self, relation: &str) -> Result<Option<(TargetSpec, BareTarget)>> {
let (Some(resolver), Some(reference)) =
(&self.resolver, self.metadata.references.get(relation))
else {
return Ok(None);
};
let target_name = reference.target.as_str();
let target = resolver.resolve(target_name).ok_or_else(|| {
error!(
"GraphQL reference target has no registered spec; register it with \
`register_yaml` or resolve it through `with_resolver`",
relation = relation,
target = target_name
)
.mark_not_found()
})?;
let bare =
build_table(&target.spec, &target.api, Some(resolver.clone())).with_context(|| {
error!(
"GraphQL reference target spec can't be built",
relation = relation,
target = target_name
)
})?;
Ok(Some((target, bare)))
}
pub(crate) fn ref_target(
&self,
relation: &str,
row: Option<&Record<CborValue>>,
) -> Result<Vista> {
let reference = self
.metadata
.references
.get(relation)
.ok_or_else(|| unknown_relation(relation))?;
let (target_spec, bare) = match self.spec_target(relation)? {
Some((spec, bare)) => (Some(spec), bare),
None => (None, self.table.get_ref_target_erased(relation)?),
};
let target = self.wrap_target(bare, target_spec)?;
match row {
Some(row) => reference.narrow(target, row),
None => Ok(target),
}
}
pub(crate) fn wrap_target(
&self,
table: Table<GraphqlApi, EmptyEntity>,
target: Option<TargetSpec>,
) -> Result<Vista> {
match (target, &self.resolver) {
(Some(target), Some(resolver)) => {
wrap_spec_table(table, &target.spec, resolver.clone())
}
_ => GraphqlApiVistaFactory::new(self.table.data_source().clone()).from_table(table),
}
}
}