mod watch;
use ciborium::Value as CborValue;
use vantage_core::Result;
use vantage_table::column::core::Column;
use vantage_table::sorting::{OrderBy, SortDirection};
use vantage_table::table::Table;
use vantage_types::{EmptyEntity, Entity};
use vantage_vista::{Capability, Vista, VistaChangeStream};
use crate::condition::{PostgresCondition, build_sql_binary};
use crate::postgres::PostgresDB;
use crate::postgres::operation::PostgresOperation;
use crate::postgres::types::AnyPostgresType;
use crate::postgres::vista::factory::PostgresVistaFactory;
use crate::primitives::identifier::ident;
use crate::sql_vista::{Shell, SqlShellDialect, SqlTableShell};
pub type PostgresTableShell<E = EmptyEntity> = SqlTableShell<PostgresDB, E>;
impl SqlShellDialect for PostgresDB {
type Extra = ();
const DRIVER: &'static str = "postgres";
fn cell(value: CborValue) -> AnyPostgresType {
AnyPostgresType::untyped(value)
}
fn cbor(value: AnyPostgresType) -> CborValue {
value.into_value()
}
fn preview<E: Entity<AnyPostgresType>>(table: &Table<Self, E>) -> String {
table.select().preview()
}
fn compare(
column: &Column<AnyPostgresType>,
template: &str,
value: AnyPostgresType,
) -> PostgresCondition {
build_sql_binary::<AnyPostgresType, AnyPostgresType, _>(column, value, template)
}
fn in_list(
column: &Column<AnyPostgresType>,
values: &[AnyPostgresType],
negate: bool,
) -> PostgresCondition {
if negate {
column.not_in_list(values)
} else {
column.in_list(values)
}
}
fn like(field: &str, pattern: String) -> PostgresCondition {
crate::postgres_expr!("{}::text ILIKE {} ESCAPE '$'", (ident(field)), pattern).into()
}
fn order_term(field: &str) -> PostgresCondition {
crate::postgres_expr!("{}", (ident(field))).into()
}
fn ordered_for_paging<E: Entity<AnyPostgresType>>(table: &Table<Self, E>) -> Table<Self, E> {
let mut table = table.clone();
if table.orders().next().is_some() {
return table;
}
let Some(id) = table.id_field().map(|c| c.name().to_string()) else {
return table;
};
if !table.columns().contains_key(&id) {
return table;
}
table.add_order(OrderBy {
expression: Self::order_term(&id),
direction: SortDirection::Ascending,
});
table
}
fn target_factory<E>(
shell: &Shell<Self, E>,
) -> impl Fn(Table<Self, EmptyEntity>) -> Result<Vista> + Send + Sync + 'static
where
E: Entity<AnyPostgresType> + 'static,
{
let factory = PostgresVistaFactory::new(shell.table.data_source().clone())
.with_notify(shell.capabilities.has(Capability::Subscribe));
move |table| factory.from_table(table)
}
fn watch<E>(shell: &Shell<Self, E>) -> Result<VistaChangeStream>
where
E: Entity<AnyPostgresType> + 'static,
{
shell.listen()
}
}