use async_trait::async_trait;
use ciborium::Value as CborValue;
use indexmap::IndexMap;
use vantage_core::Result;
use vantage_dataset::traits::ReadableValueSet;
use vantage_table::conditions::ConditionHandle;
use vantage_table::pagination::Pagination;
use vantage_table::table::Table;
use vantage_types::{EmptyEntity, Record};
use vantage_vista::{
Capability, Condition, Page, Preview, SortDirection, TableShell, Vista, VistaCapabilities,
VistaMetadata, unsupported,
};
use crate::graphql::api::GraphqlApi;
use crate::graphql::types::AnyGraphqlType;
use crate::graphql::vista::lowering::TargetSpecResolver;
const DRIVER: &str = "graphql";
#[derive(Clone)]
pub struct GraphqlApiTableShell {
pub(crate) table: Table<GraphqlApi, EmptyEntity>,
pub(crate) capabilities: VistaCapabilities,
pub(crate) metadata: VistaMetadata,
pub(crate) search_handle: Option<ConditionHandle>,
pub(crate) resolver: Option<TargetSpecResolver>,
}
impl GraphqlApiTableShell {
pub(crate) fn new(
table: Table<GraphqlApi, EmptyEntity>,
capabilities: VistaCapabilities,
metadata: VistaMetadata,
) -> Self {
Self {
table,
capabilities,
metadata,
search_handle: None,
resolver: None,
}
}
pub(crate) fn with_resolver(mut self, resolver: Option<TargetSpecResolver>) -> Self {
self.resolver = resolver;
self
}
pub(crate) fn record_to_cbor(record: Record<AnyGraphqlType>) -> Record<CborValue> {
record
.into_iter()
.map(|(k, v)| (k, CborValue::from(v)))
.collect()
}
}
#[async_trait]
impl TableShell for GraphqlApiTableShell {
fn metadata(&self) -> &VistaMetadata {
&self.metadata
}
fn capabilities(&self) -> &VistaCapabilities {
&self.capabilities
}
fn driver_name(&self) -> &'static str {
DRIVER
}
fn preview(&self) -> Preview {
Preview::new().with_query(format!(
"POST {}\n{}",
self.table.data_source().endpoint(),
self.table.select().preview()
))
}
async fn list(&self) -> Result<IndexMap<String, Record<CborValue>>> {
let raw = self.table.list_values().await?;
Ok(raw
.into_iter()
.map(|(id, rec)| (id, Self::record_to_cbor(rec)))
.collect())
}
async fn get(&self, id: &str) -> Result<Option<Record<CborValue>>> {
Ok(self.table.get_value(id).await?.map(Self::record_to_cbor))
}
async fn count(&self) -> Result<i64> {
self.table.get_count().await
}
async fn fetch_window(&self, offset: usize, limit: usize) -> Result<Page> {
if !self.capabilities.has(Capability::Window) {
return Ok(Page::from_listing(self.list().await?, offset, limit));
}
let rows = self
.list_paginated(Pagination::window(offset as i64, limit as i64))
.await?;
Ok(Page::new(rows))
}
fn add_condition(&mut self, condition: &Condition) -> Result<()> {
self.apply_condition(condition)
}
fn set_search(&mut self, text: Option<&str>) -> Result<()> {
if !self.capabilities.has(Capability::Search) {
return unsupported(Capability::Search);
}
self.apply_search(text)
}
fn set_order(&mut self, order: Option<(&str, SortDirection)>) -> Result<()> {
if !self.capabilities.has(Capability::Order) {
return unsupported(Capability::Order);
}
self.apply_order(order)
}
fn get_ref(&self, relation: &str, row: Option<&Record<CborValue>>) -> Result<Vista> {
self.ref_target(relation, row)
}
}