use std::fmt;
use glaredb_error::{DbError, Result};
use glaredb_parser::ast::{self};
use glaredb_proto::ProtoConv;
use serde::{Deserialize, Serialize};
use super::resolved_cte::ResolvedCte;
use super::resolved_function::ResolvedFunction;
use super::resolved_table::{ResolvedTableOrCteReference, UnresolvedTableReference};
use super::resolved_table_function::{
ResolvedTableFunctionReference,
UnresolvedTableFunctionReference,
};
use crate::logical::operator::LocationRequirement;
#[derive(Debug, Clone, Default)]
pub struct ResolveContext {
pub tables: ResolveList<ResolvedTableOrCteReference, UnresolvedTableReference>,
pub functions: ResolveList<ResolvedFunction, ast::ObjectReference>,
pub table_functions:
ResolveList<ResolvedTableFunctionReference, UnresolvedTableFunctionReference>,
pub current_depth: usize,
pub ctes: Vec<ResolvedCte>,
}
impl ResolveContext {
pub const fn empty() -> Self {
ResolveContext {
tables: ResolveList::empty(),
functions: ResolveList::empty(),
table_functions: ResolveList::empty(),
current_depth: 0,
ctes: Vec::new(),
}
}
pub fn any_unresolved(&self) -> bool {
self.tables.any_unresolved()
|| self.functions.any_unresolved()
|| self.table_functions.any_unresolved()
}
pub fn find_cte(&self, name: &str) -> Option<&ResolvedCte> {
let mut search_depth = self.current_depth;
for cte in self.ctes.iter().rev() {
if cte.depth > search_depth {
return None;
}
if cte.name == name {
return Some(cte);
}
search_depth = cte.depth;
}
None
}
pub fn inc_depth(&mut self) {
self.current_depth += 1
}
pub fn dec_depth(&mut self) {
self.current_depth -= 1;
}
pub fn push_cte(&mut self, cte: ResolvedCte) {
self.ctes.push(cte);
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MaybeResolved<B, U> {
Resolved(B, LocationRequirement),
Unresolved(U),
}
impl<B, U> MaybeResolved<B, U> {
pub const fn is_resolved(&self) -> bool {
matches!(self, MaybeResolved::Resolved(_, _))
}
pub fn try_unwrap_resolved(self) -> Result<(B, LocationRequirement)> {
match self {
Self::Resolved(b, loc) => Ok((b, loc)),
Self::Unresolved(_) => Err(DbError::new("Reference not resolved")),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ResolveList<B, U> {
pub inner: Vec<MaybeResolved<B, U>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct ResolveListIdx(pub usize);
impl<B, U> ResolveList<B, U> {
pub const fn empty() -> Self {
ResolveList { inner: Vec::new() }
}
pub fn any_unresolved(&self) -> bool {
self.inner
.iter()
.any(|v| matches!(v, MaybeResolved::Unresolved(_)))
}
pub fn try_get_bound(
&self,
ResolveListIdx(idx): ResolveListIdx,
) -> Result<(&B, LocationRequirement)> {
match self.inner.get(idx) {
Some(MaybeResolved::Resolved(b, loc)) => Ok((b, *loc)),
Some(MaybeResolved::Unresolved(_)) => Err(DbError::new("Item not resolved")),
None => Err(DbError::new("Missing reference")),
}
}
pub fn push_maybe_resolved(&mut self, maybe: MaybeResolved<B, U>) -> ResolveListIdx {
let idx = self.inner.len();
self.inner.push(maybe);
ResolveListIdx(idx)
}
pub fn push_resolved(&mut self, bound: B, loc: LocationRequirement) -> ResolveListIdx {
self.push_maybe_resolved(MaybeResolved::Resolved(bound, loc))
}
pub fn push_unresolved(&mut self, unbound: U) -> ResolveListIdx {
self.push_maybe_resolved(MaybeResolved::Unresolved(unbound))
}
}
impl<B, U> Default for ResolveList<B, U> {
fn default() -> Self {
Self { inner: Vec::new() }
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ItemReference(pub Vec<String>);
impl ItemReference {
pub fn pop(&mut self) -> Result<String> {
self.0.pop().ok_or_else(|| DbError::new("End of reference"))
}
pub fn pop_2(&mut self) -> Result<[String; 2]> {
let a = self
.0
.pop()
.ok_or_else(|| DbError::new("Expected 2 identifiers, got 0"))?;
let b = self
.0
.pop()
.ok_or_else(|| DbError::new("Expected 2 identifiers, got 1"))?;
Ok([b, a])
}
pub fn pop_3(&mut self) -> Result<[String; 3]> {
let a = self
.0
.pop()
.ok_or_else(|| DbError::new("Expected 3 identifiers, got 0"))?;
let b = self
.0
.pop()
.ok_or_else(|| DbError::new("Expected 3 identifiers, got 1"))?;
let c = self
.0
.pop()
.ok_or_else(|| DbError::new("Expected 3 identifiers, got 2"))?;
Ok([c, b, a])
}
}
impl From<Vec<String>> for ItemReference {
fn from(value: Vec<String>) -> Self {
ItemReference(value)
}
}
impl fmt::Display for ItemReference {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0.join(","))
}
}
impl ProtoConv for ItemReference {
type ProtoType = glaredb_proto::generated::resolver::ItemReference;
fn to_proto(&self) -> Result<Self::ProtoType> {
Ok(Self::ProtoType {
idents: self.0.clone(),
})
}
fn from_proto(proto: Self::ProtoType) -> Result<Self> {
Ok(Self(proto.idents))
}
}