reifydb_export/render/
layout.rs1use std::collections::{HashMap, HashSet};
5
6use reifydb_core::interface::catalog::column::Column;
7use reifydb_value::value::constraint::Constraint;
8
9use crate::model::NameResolver;
10
11pub enum LayoutColumn<'a> {
12 Plain(&'a Column),
13 Enum(EnumColumn),
14}
15
16pub struct EnumColumn {
17 pub logical_name: String,
18 pub sumtype_id: u64,
19 pub tag_column: String,
20 pub variants: Vec<EnumVariant>,
21}
22
23pub struct EnumVariant {
24 pub tag: u8,
25 pub name: String,
26 pub fields: Vec<(String, String)>,
27}
28
29pub fn build_layout<'a>(columns: &'a [Column], resolver: &NameResolver) -> Vec<LayoutColumn<'a>> {
30 let mut enum_at: HashMap<usize, EnumColumn> = HashMap::new();
31 let mut absorbed: HashSet<String> = HashSet::new();
32
33 for (idx, col) in columns.iter().enumerate() {
34 let Some(Constraint::SumType(id)) = col.constraint.constraint() else {
35 continue;
36 };
37 let sumtype_id = id.to_u64();
38 let logical_name = col.name.strip_suffix("_tag").unwrap_or(&col.name).to_string();
39
40 let mut variants = Vec::new();
41 if let Some(resolved) = resolver.sumtype(sumtype_id) {
42 for variant in &resolved.variants {
43 let fields: Vec<(String, String)> = variant
44 .fields
45 .iter()
46 .map(|field| {
47 (field.clone(), format!("{logical_name}_{}_{}", variant.name, field))
48 })
49 .collect();
50 for (_, physical) in &fields {
51 absorbed.insert(physical.clone());
52 }
53 variants.push(EnumVariant {
54 tag: variant.tag,
55 name: variant.name.clone(),
56 fields,
57 });
58 }
59 }
60
61 enum_at.insert(
62 idx,
63 EnumColumn {
64 logical_name,
65 sumtype_id,
66 tag_column: col.name.clone(),
67 variants,
68 },
69 );
70 }
71
72 let mut layout = Vec::with_capacity(columns.len());
73 for (idx, col) in columns.iter().enumerate() {
74 if let Some(enum_col) = enum_at.remove(&idx) {
75 layout.push(LayoutColumn::Enum(enum_col));
76 } else if !absorbed.contains(&col.name) {
77 layout.push(LayoutColumn::Plain(col));
78 }
79 }
80 layout
81}