use crate::Partitioning;
use crate::catalog::Catalog;
use crate::describe::{Described, argv, b, flag, n, order};
use crate::table::{OrderPath, TableIndex, TableSpec, dotted};
pub fn describe_table(t: &TableSpec) -> Described {
describe_table_partitioned(t, &Catalog::new())
}
pub fn describe_table_partitioned(t: &TableSpec, cat: &Catalog) -> Described {
let columns = t.columns.iter().map(|(c, ty)| Described::Array(vec![b(c), b(ty.tag())]));
let window = match &t.window {
None => b("-"),
Some(w) => Described::Array(vec![
b("column"),
b(&w.column),
b("span"),
n(w.span),
b("bucket"),
n(w.bucket),
]),
};
Described::Array(vec![
b("name"),
b(&t.name),
b("prefix"),
b(&t.prefix),
b("pk"),
b(&t.pk),
b("columns"),
Described::Array(columns.collect()),
b("indexes"),
table_indexes(t),
b("orderpaths"),
table_orderpaths(t),
b("window"),
window,
b("autodeclare"),
n(t.autodeclare),
b("declaration"),
argv(table_declaration_partitioned(&t.sans_auto(), cat)),
])
}
fn table_indexes(t: &TableSpec) -> Described {
let rows = t.indexes.iter().map(|ix| {
let path = dotted(&t.name, &ix.column);
Described::Array(vec![
b("path"),
b(&path),
b("column"),
b(&ix.column),
b("kind"),
b(ix.kind.tag()),
b("values"),
argv(ix.values.clone()),
b("auto"),
flag(t.auto_added.contains(&path)),
])
});
Described::Array(rows.collect())
}
fn table_orderpaths(t: &TableSpec) -> Described {
let rows = t.orderpaths.iter().map(|op| {
let path = dotted(&t.name, &op.name);
let on = op.on.iter().map(|(c, o)| Described::Array(vec![b(c), b(order(*o))]));
Described::Array(vec![
b("path"),
b(&path),
b("name"),
b(&op.name),
b("on"),
Described::Array(on.collect()),
b("auto"),
flag(t.auto_added.contains(&path)),
])
});
Described::Array(rows.collect())
}
pub fn table_declaration(t: &TableSpec) -> Vec<Vec<u8>> {
table_declaration_partitioned(t, &Catalog::new())
}
pub fn table_declaration_partitioned(t: &TableSpec, cat: &Catalog) -> Vec<Vec<u8>> {
let mut w: Vec<Vec<u8>> = vec![
b"TABLE.DECLARE".to_vec(),
t.name.clone(),
b"PREFIX".to_vec(),
t.prefix.clone(),
b"PK".to_vec(),
t.pk.clone(),
];
for (c, ty) in &t.columns {
w.extend([b"COLUMN".to_vec(), c.clone(), ty.tag().into()]);
}
for ix in &t.indexes {
index_clause(t, ix, cat, &mut w);
}
for op in &t.orderpaths {
orderpath_clause(t, op, cat, &mut w);
}
if let Some(win) = &t.window {
w.extend([b"WINDOW".to_vec(), win.column.clone(), b"SPAN".to_vec()]);
w.extend([win.span.to_string().into(), b"BUCKET".to_vec(), win.bucket.to_string().into()]);
}
if t.autodeclare != 0 {
w.extend([b"AUTODECLARE".to_vec(), t.autodeclare.to_string().into()]);
}
w
}
fn index_clause(t: &TableSpec, ix: &TableIndex, cat: &Catalog, w: &mut Vec<Vec<u8>>) {
w.extend([b"INDEX".to_vec(), ix.column.clone(), ix.kind.tag().into()]);
if !ix.values.is_empty() {
w.push(b"VALUES".to_vec());
w.extend(ix.values.iter().cloned());
}
global_clause(cat, &dotted(&t.name, &ix.column), w);
}
fn global_clause(cat: &Catalog, name: &[u8], w: &mut Vec<Vec<u8>>) {
let (Partitioning::Global { splits }, Some((spec, _))) =
(cat.partitioning(name), cat.get(name))
else {
return;
};
w.push(b"GLOBAL".to_vec());
if !splits.is_empty() {
w.extend([b"SPLIT".to_vec(), b"AT".to_vec()]);
w.extend(splits.iter().map(|p| spec.split_point_text(p)));
}
}
fn orderpath_clause(t: &TableSpec, op: &OrderPath, cat: &Catalog, w: &mut Vec<Vec<u8>>) {
w.extend([b"ORDERPATH".to_vec(), op.name.clone(), b"ON".to_vec()]);
for (i, (c, o)) in op.on.iter().enumerate() {
if i > 0 {
w.push(b"THEN".to_vec());
}
w.push(c.clone());
if *o == kevy_text::SortOrder::Desc {
w.push(b"DESC".to_vec());
}
}
global_clause(cat, &dotted(&t.name, &op.name), w);
}