use std::collections::HashSet;
use std::fmt::{Debug, Display, Formatter};
use enum_as_inner::EnumAsInner;
use itertools::{Itertools, Position};
use serde::{Deserialize, Serialize};
use super::Ident;
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct Lineage {
pub columns: Vec<LineageColumn>,
pub inputs: Vec<LineageInput>,
#[serde(skip)]
pub prev_columns: Vec<LineageColumn>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct LineageInput {
pub id: usize,
pub name: String,
pub table: Ident,
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, EnumAsInner)]
pub enum LineageColumn {
Single {
name: Option<Ident>,
target_id: usize,
target_name: Option<String>,
},
All {
input_id: usize,
except: HashSet<String>,
},
}
impl Display for Lineage {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
display_lineage(self, f, false)
}
}
fn display_lineage(lineage: &Lineage, f: &mut Formatter, display_ids: bool) -> std::fmt::Result {
write!(f, "[")?;
for (pos, col) in lineage.columns.iter().with_position() {
let is_last = matches!(pos, Position::Last | Position::Only);
display_lineage_column(col, f, display_ids)?;
if !is_last {
write!(f, ", ")?;
}
}
write!(f, "]")
}
fn display_lineage_column(
col: &LineageColumn,
f: &mut Formatter,
display_ids: bool,
) -> std::fmt::Result {
match col {
LineageColumn::All { input_id, .. } => {
write!(f, "{input_id}.*")?;
}
LineageColumn::Single {
name, target_id, ..
} => {
if let Some(name) = name {
write!(f, "{name}")?
} else {
write!(f, "?")?
}
if display_ids {
write!(f, ":{target_id}")?
}
}
}
Ok(())
}