use crate::ast::{SelectItem, View};
use crate::catalog::CatalogColumn;
use crate::error::HolocronError;
use crate::resolve::scope::Scope;
pub(crate) fn resolve_columns(
view: &View,
scope: &Scope,
) -> Result<Vec<CatalogColumn>, HolocronError> {
let mut columns = Vec::with_capacity(view.select.len());
for item in &view.select {
columns.push(resolve_item(view, item, scope)?);
}
Ok(columns)
}
fn resolve_item(
view: &View,
item: &SelectItem,
scope: &Scope,
) -> Result<CatalogColumn, HolocronError> {
let select = match item {
SelectItem::Column(select) => select,
SelectItem::Expression(expression) => {
return Err(HolocronError::unsupported(
"expression select items are not yet supported",
expression.span,
));
}
};
let relation = match &select.from {
Some(alias) => scope.relation(&alias.value).ok_or_else(|| {
HolocronError::unknown_alias(
&view.name.value,
&alias.value,
scope.alias_names(),
alias.span,
)
})?,
None => scope.sole_relation().ok_or_else(|| {
HolocronError::ambiguous_source(
&view.name.value,
&select.column.value,
scope.alias_names(),
select.column.span,
)
})?,
};
let source = relation.column(&select.column.value).ok_or_else(|| {
let candidates = relation
.columns
.iter()
.map(|column| column.name.clone())
.collect();
HolocronError::unknown_column(
&relation.name,
&select.column.value,
candidates,
select.column.span,
)
})?;
let name = select
.r#as
.clone()
.unwrap_or_else(|| select.column.value.clone());
Ok(CatalogColumn {
name,
data_type: source.data_type.clone(),
nullable: source.nullable,
filterable: select.filterable,
searchable: select.searchable,
})
}