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::table::Table;
use vantage_types::{EmptyEntity, Record};
use vantage_vista::{
Column as VistaColumn, Reference as VistaReference, ReferenceKind, TableShell, Vista,
VistaCapabilities, VistaMetadata,
};
use crate::AwsAccount;
use crate::condition::AwsCondition;
pub struct AwsTableShell {
pub(crate) table: Table<AwsAccount, EmptyEntity>,
pub(crate) capabilities: VistaCapabilities,
pub(crate) metadata: VistaMetadata,
}
impl AwsTableShell {
pub(crate) fn new(
table: Table<AwsAccount, EmptyEntity>,
capabilities: VistaCapabilities,
metadata: VistaMetadata,
) -> Self {
Self {
table,
capabilities,
metadata,
}
}
}
#[async_trait]
impl TableShell for AwsTableShell {
fn columns(&self) -> &IndexMap<String, VistaColumn> {
&self.metadata.columns
}
fn references(&self) -> &IndexMap<String, VistaReference> {
&self.metadata.references
}
fn id_column(&self) -> Option<&str> {
self.metadata.id_column.as_deref()
}
async fn list_vista_values(
&self,
_vista: &Vista,
) -> Result<IndexMap<String, Record<CborValue>>> {
self.table.list_values().await
}
async fn get_vista_value(
&self,
_vista: &Vista,
id: &String,
) -> Result<Option<Record<CborValue>>> {
let mut data = self.table.list_values().await?;
Ok(data.shift_remove(id))
}
async fn get_vista_some_value(
&self,
_vista: &Vista,
) -> Result<Option<(String, Record<CborValue>)>> {
let data = self.table.list_values().await?;
Ok(data.into_iter().next())
}
async fn get_vista_count(&self, _vista: &Vista) -> Result<i64> {
Ok(self.table.list_values().await?.len() as i64)
}
fn add_eq_condition(&mut self, field: &str, value: &CborValue) -> Result<()> {
self.table
.add_condition(AwsCondition::eq(field.to_string(), value.clone()));
Ok(())
}
fn get_ref(&self, relation: &str, row: &Record<CborValue>) -> Result<Vista> {
let target = self.table.get_ref_from_row::<EmptyEntity>(relation, row)?;
let factory = crate::vista::factory::AwsVistaFactory::new(self.table.data_source().clone());
factory.from_table(target)
}
fn get_ref_kinds(&self) -> Vec<(String, ReferenceKind)> {
self.table.ref_kinds()
}
fn capabilities(&self) -> &VistaCapabilities {
&self.capabilities
}
fn driver_name(&self) -> &'static str {
"aws"
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::AwsAccount;
use crate::models::iam;
use crate::vista::factory::metadata_from_table;
use vantage_types::EmptyEntity;
fn shell_for_iam_users() -> AwsTableShell {
let aws = AwsAccount::new("AKIATEST", "secret", "eu-west-2");
let table = iam::users_table(aws).into_entity::<EmptyEntity>();
let metadata = metadata_from_table(&table);
let capabilities = VistaCapabilities {
can_count: true,
..VistaCapabilities::default()
};
AwsTableShell::new(table, capabilities, metadata)
}
#[test]
fn add_eq_condition_pushes_aws_condition_eq_onto_wrapped_table() {
let mut shell = shell_for_iam_users();
shell
.add_eq_condition("PathPrefix", &CborValue::Text("/admin/".into()))
.expect("add_eq_condition");
let conditions: Vec<&AwsCondition> = shell.table.conditions().collect();
assert_eq!(conditions.len(), 1);
match conditions[0] {
AwsCondition::Eq { field, value } => {
assert_eq!(field, "PathPrefix");
assert_eq!(value, &CborValue::Text("/admin/".into()));
}
other => panic!("expected AwsCondition::Eq, got {other:?}"),
}
}
}