Skip to main content

uqa_sql/result/
labels.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Host-facing results observe deferred physical datums and carry enums as their current labels, through SQL's type-output owners.
8
9use super::SQLResult;
10use crate::expr::datums::contains_datum;
11use crate::expr::enums::{contains_enum_carrier, render_enum_labels, EnumLabelCatalog};
12use crate::SQLError;
13use uqa_core::Value;
14
15/// Read deferred datums and replace enum carriers in named and positional results by their current labels. This output boundary preserves declared column types and recursive carrier metadata.
16pub fn render_result_enum_labels(
17    catalog: Option<&dyn EnumLabelCatalog>,
18    result: &mut SQLResult,
19) -> Result<(), SQLError> {
20    for row in &mut result.rows {
21        for value in row.values_mut() {
22            if contains_datum(value) {
23                *value = read_datums(value, catalog)?;
24            }
25            if contains_enum_carrier(value) {
26                *value = render_enum_labels(catalog, value)?;
27            }
28        }
29    }
30    for row in result.positional_rows.iter_mut().flatten() {
31        for value in row {
32            if contains_datum(value) {
33                *value = read_datums(value, catalog)?;
34            }
35            if contains_enum_carrier(value) {
36                *value = render_enum_labels(catalog, value)?;
37            }
38        }
39    }
40    Ok(())
41}
42
43fn read_datums(value: &Value, catalog: Option<&dyn EnumLabelCatalog>) -> Result<Value, SQLError> {
44    Ok(match value {
45        Value::Datum(datum) => read_datums(
46            &*crate::expr::datums::read_with_value_catalog_and_control(
47                datum,
48                catalog,
49                &uqa_core::memory::ProductionControl::uncontrolled(),
50            )?,
51            catalog,
52        )?,
53        Value::Array(array) => Value::Array(
54            uqa_core::ArrayValue::with_lower_bounds(
55                array
56                    .elements()
57                    .iter()
58                    .map(|value| read_datums(value, catalog))
59                    .collect::<Result<_, _>>()?,
60                array.lower_bounds().to_vec(),
61            )
62            .ok_or_else(|| SQLError::Internal("datum output changed array shape".into()))?
63            .with_element_type_oid(array.element_type_oid()),
64        ),
65        Value::List(values) => Value::List(
66            values
67                .iter()
68                .map(|value| read_datums(value, catalog))
69                .collect::<Result<_, _>>()?,
70        ),
71        Value::Row(values) => Value::Row(
72            values.clone().with_values(
73                values
74                    .iter()
75                    .map(|value| read_datums(value, catalog))
76                    .collect::<Result<_, _>>()?,
77            )?,
78        ),
79        Value::Record(fields) => Value::Record(uqa_core::RecordValue::from_parts(
80            fields
81                .iter()
82                .map(|(name, value)| Ok((name.clone(), read_datums(value, catalog)?)))
83                .collect::<Result<_, SQLError>>()?,
84            fields.type_oid(),
85        )),
86        Value::Map(values) => Value::Map(
87            values
88                .iter()
89                .map(|(name, value)| Ok((name.clone(), read_datums(value, catalog)?)))
90                .collect::<Result<_, SQLError>>()?,
91        ),
92        other => other.clone(),
93    })
94}