Skip to main content

reifydb_export/render/
layout.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use 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}