use std::sync::Arc;
use super::pipeline::{FieldState, build_field_state_raw, filter_field_state_for_projection};
use crate::catalog::{DatabaseId, NamespaceId, TableDefinition};
use crate::err::Error;
use crate::exec::permission::{PhysicalPermission, convert_permission_to_physical};
use crate::exec::planner::Planner;
use crate::val::TableName;
#[derive(Debug, Clone)]
pub(crate) struct ResolvedTableContext {
pub table_def: Arc<TableDefinition>,
pub select_permission: PhysicalPermission,
pub field_state: Arc<FieldState>,
}
impl ResolvedTableContext {
pub fn field_state_for_projection(
&self,
needed_fields: Option<&std::collections::HashSet<String>>,
) -> FieldState {
filter_field_state_for_projection(&self.field_state, needed_fields)
}
pub fn select_permission(&self, check_perms: bool) -> PhysicalPermission {
if check_perms {
self.select_permission.clone()
} else {
PhysicalPermission::Allow
}
}
}
pub(crate) async fn resolve_table_context(
planner: &Planner<'_>,
ns: &str,
db: &str,
ns_id: NamespaceId,
db_id: DatabaseId,
table_name: &TableName,
) -> Result<Option<ResolvedTableContext>, Error> {
use crate::catalog::providers::TableProvider;
let txn = planner.txn().ok_or_else(|| {
Error::Internal("resolve_table_context requires a planner with txn".into())
})?;
let table_def = match txn
.get_tb_by_name(ns, db, table_name, None)
.await
.map_err(|e| Error::Internal(e.to_string()))?
{
Some(def) => def,
None => return Ok(None),
};
let select_permission =
convert_permission_to_physical(&table_def.permissions.select, planner).await?;
let field_state = build_field_state_raw(planner, ns_id, db_id, table_name, true, None)
.await
.map_err(|cf| match cf {
crate::expr::ControlFlow::Err(e) => Error::Internal(e.to_string()),
_ => Error::Internal("Unexpected control flow in field state resolution".into()),
})?;
Ok(Some(ResolvedTableContext {
table_def,
select_permission,
field_state: Arc::new(field_state),
}))
}