use std::rc::Rc;
use hamelin_lib::{
antlr::{
completion_interval,
hamelinparser::{
ColumnReferenceContextAll, ColumnReferenceContextAttrs, ExpressionContextAll,
},
interval,
},
completion::Completion,
err::{TranslationError, TranslationErrors},
sql::expression::{
identifier::{HamelinSimpleIdentifier, Identifier},
literal::{ColumnReference, PatternVariableReference},
SQLExpression,
},
translation::ExpressionTranslation,
};
use super::ExpressionTranslationContext;
pub struct HamelinColumnRef {
pub parent_tree: Rc<ExpressionContextAll<'static>>,
pub column_ref_tree: Option<Rc<ColumnReferenceContextAll<'static>>>,
pub context: Rc<ExpressionTranslationContext>,
}
impl HamelinColumnRef {
pub fn new(
parent_tree: Rc<ExpressionContextAll<'static>>,
column_ref_tree: Option<Rc<ColumnReferenceContextAll<'static>>>,
context: Rc<ExpressionTranslationContext>,
) -> Self {
HamelinColumnRef {
parent_tree,
column_ref_tree,
context,
}
}
pub fn translate(&self) -> Result<ExpressionTranslation, TranslationErrors> {
let ctx = self.column_ref_tree.as_ref().ok_or(TranslationError::msg(
self.parent_tree.as_ref(),
"could not parse column reference",
))?;
let sql_ident = HamelinSimpleIdentifier::new(ctx.simpleIdentifier().unwrap())
.to_sql()?
.into();
let typ = self
.context
.bindings
.lookup(&sql_ident)
.map_err(|e| TranslationError::wrap(ctx.as_ref(), e).single())?;
let sql: SQLExpression = match sql_ident {
Identifier::Simple(si) => self
.context
.bindings
.lookup_pattern_variable(&si)
.map(|v| PatternVariableReference::new(v).into())
.unwrap_or(ColumnReference::new(si.into()).into()),
Identifier::Compound(ci) => ColumnReference::new(ci.into()).into(),
};
Ok(ExpressionTranslation::with_defaults(typ, sql))
}
pub fn append_completions(&self) {
let maybe_guard = self.context.completions.try_borrow_mut();
let range = completion_interval(self.parent_tree.as_ref());
match (&self.column_ref_tree, self.context.at, maybe_guard) {
(Some(cr), Some(at), Ok(mut guard)) if range.contains(&at) && guard.is_none() => {
let insert_interval = interval(cr.as_ref());
let mut completion = Completion::new(insert_interval);
if *range.start() == at {
completion.filter(false);
completion.add_items(self.context.bindings.autocomplete_suggestions(false));
completion.add_items(self.context.registry.autocomplete_suggestions());
*guard = Some(completion);
} else {
let maybe_curr_ident = cr
.simpleIdentifier()
.and_then(|si| HamelinSimpleIdentifier::new(si).to_sql().ok());
if let Some(curr_ident) = maybe_curr_ident {
completion.add_items(
self.context
.bindings
.nested_autocomplete_suggestions(&curr_ident, false),
);
completion.add_items(self.context.registry.autocomplete_suggestions());
}
*guard = Some(completion);
}
}
_ => {}
}
}
}