use ciborium::Value as CborValue;
use vantage_core::{Result, error};
use vantage_dataset::traits::ReadableValueSet;
use vantage_table::column::core::Column;
use vantage_table::pagination::Pagination;
use vantage_table::sorting::{OrderBy, SortDirection};
use vantage_table::table::Table;
use vantage_types::{EmptyEntity, Record};
use crate::graphql::api::GraphqlApi;
use crate::graphql::operation::GraphqlOperation;
use crate::graphql::types::AnyGraphqlType;
use crate::graphql::vista::source::GraphqlApiTableShell;
impl GraphqlApiTableShell {
fn ordered_for_paging(&self) -> Table<GraphqlApi, EmptyEntity> {
let mut table = self.table.clone();
if !table.data_source().can_order() || table.orders().next().is_some() {
return table;
}
let Some(id) = table.id_field().map(|c| c.name().to_string()) else {
return table;
};
if id.contains('.') {
return table;
}
table.add_order(OrderBy {
expression: Column::<AnyGraphqlType>::new(&id).eq(id.as_str()),
direction: SortDirection::Ascending,
});
table
}
pub(crate) async fn list_paginated(
&self,
pagination: Pagination,
) -> Result<Vec<(String, Record<CborValue>)>> {
let mut table = self.ordered_for_paging();
table.set_pagination(Some(pagination));
let raw = table.list_values().await?;
Ok(raw
.into_iter()
.map(|(id, record)| (id, Self::record_to_cbor(record)))
.collect())
}
pub(crate) fn require_page_size(&self, method: &str) -> Result<usize> {
self.page_size.ok_or_else(|| {
error!(
"set_page_size must be called before fetching pages",
method = method
)
})
}
pub(crate) async fn fetch_next_page(
&self,
token: Option<CborValue>,
) -> Result<(Vec<(String, Record<CborValue>)>, Option<CborValue>)> {
let size = self.require_page_size("fetch_next")?;
let page: i64 = match token {
None => 1,
Some(CborValue::Integer(n)) => {
i64::try_from(n).map_err(|_| error!("fetch_next token out of i64 range"))?
}
Some(_) => return Err(error!("invalid fetch_next token type for graphql driver")),
};
if page < 1 {
return Err(error!(
"fetch_next token must be a 1-based page number",
page = page
));
}
let records = self
.list_paginated(Pagination::new(page, size as i64))
.await?;
let next = (records.len() == size).then(|| CborValue::Integer((page + 1).into()));
Ok((records, next))
}
}