use linkrs_core::DataType;
use std::collections::HashMap;
pub type SlotId = usize;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum SlotOrigin {
StorageColumn(String),
Computed,
System,
JoinOutput,
AggregationOutput,
TraversalResult,
}
#[derive(Debug, Clone)]
pub struct SlotInfo {
pub slot_id: SlotId,
pub name: String,
pub alias: Option<String>,
pub data_type: Option<DataType>,
pub nullable: bool,
pub origin: Option<SlotOrigin>,
}
#[derive(Debug, Clone)]
pub struct SlotLayout {
pub slots: Vec<SlotInfo>,
pub name_to_slot: HashMap<String, SlotId>,
}
impl SlotLayout {
pub fn new(slots: Vec<SlotInfo>) -> Self {
let name_to_slot = slots
.iter()
.enumerate()
.map(|(i, info)| (info.name.clone(), i))
.collect();
Self {
slots,
name_to_slot,
}
}
pub fn from_names(names: &[String]) -> Self {
let slots: Vec<SlotInfo> = names
.iter()
.enumerate()
.map(|(i, name)| SlotInfo {
slot_id: i,
name: name.clone(),
alias: None,
data_type: None,
nullable: true,
origin: None,
})
.collect();
Self::new(slots)
}
pub fn from_names_and_types(names: &[String], types: &[Option<DataType>]) -> Self {
let slots: Vec<SlotInfo> = names
.iter()
.enumerate()
.map(|(i, name)| SlotInfo {
slot_id: i,
name: name.clone(),
alias: None,
data_type: types.get(i).cloned().unwrap_or(None),
nullable: true,
origin: None,
})
.collect();
Self::new(slots)
}
pub fn from_slots(slots: Vec<SlotInfo>) -> Self {
Self::new(slots)
}
pub fn len(&self) -> usize {
self.slots.len()
}
pub fn is_empty(&self) -> bool {
self.slots.is_empty()
}
pub fn slot_id(&self, name: &str) -> Option<SlotId> {
self.name_to_slot.get(name).copied()
}
pub fn slot_info(&self, id: SlotId) -> Option<&SlotInfo> {
self.slots.get(id)
}
pub fn names(&self) -> Vec<String> {
self.slots.iter().map(|s| s.name.clone()).collect()
}
pub fn resolve(&self, name_or_alias: &str) -> Option<SlotId> {
if let Some(&id) = self.name_to_slot.get(name_or_alias) {
return Some(id);
}
self.slots
.iter()
.find(|s| s.alias.as_deref() == Some(name_or_alias))
.map(|s| s.slot_id)
}
}
pub fn combine_layouts(left: &SlotLayout, right: &SlotLayout) -> SlotLayout {
let mut slots = left.slots.clone();
let offset = slots.len();
for info in &right.slots {
slots.push(SlotInfo {
slot_id: info.slot_id + offset,
name: info.name.clone(),
alias: info.alias.clone(),
data_type: info.data_type.clone(),
nullable: info.nullable,
origin: info.origin.clone(),
});
}
SlotLayout::new(slots)
}
pub fn combine_layouts_with_dedup(left: &SlotLayout, right: &SlotLayout) -> SlotLayout {
let mut slots = left.slots.clone();
let offset = slots.len();
let left_names: std::collections::HashSet<&str> =
left.slots.iter().map(|s| s.name.as_str()).collect();
for info in &right.slots {
let name = if left_names.contains(info.name.as_str()) {
format!("{}_{}", info.name, "right")
} else {
info.name.clone()
};
slots.push(SlotInfo {
slot_id: info.slot_id + offset,
name,
alias: info.alias.clone(),
data_type: info.data_type.clone(),
nullable: info.nullable,
origin: info.origin.clone(),
});
}
SlotLayout::new(slots)
}