Skip to main content

radixdb_executor/pipeline/
shape.rs

1//! Explicit physical and public row-shape contract.
2
3use radixdb_core::{CompactArc, Error, Result};
4use radixdb_storage::traits::QueryResult;
5
6use crate::result::ProjectedResult;
7
8/// Describes the row crossing relational operators.
9///
10/// `physical_columns` can include private ORDER BY or DISTINCT ON keys. Only
11/// the leading `public_width` columns may cross the SQL result boundary.
12#[derive(Clone, Debug, PartialEq, Eq)]
13pub struct RowShape {
14    physical_columns: CompactArc<Vec<String>>,
15    public_width: usize,
16}
17
18impl RowShape {
19    pub fn new(physical_columns: CompactArc<Vec<String>>, public_width: usize) -> Result<Self> {
20        if public_width > physical_columns.len() {
21            return Err(Error::internal(format!(
22                "public row width {public_width} exceeds physical width {}",
23                physical_columns.len()
24            )));
25        }
26        Ok(Self {
27            physical_columns,
28            public_width,
29        })
30    }
31
32    pub fn physical_columns(&self) -> &CompactArc<Vec<String>> {
33        &self.physical_columns
34    }
35
36    pub fn physical_width(&self) -> usize {
37        self.physical_columns.len()
38    }
39
40    pub fn public_width(&self) -> usize {
41        self.public_width
42    }
43
44    pub fn has_private_tail(&self) -> bool {
45        self.public_width > 0 && self.physical_width() > self.public_width
46    }
47
48    pub fn project_public(&self, result: Box<dyn QueryResult>) -> Box<dyn QueryResult> {
49        if self.has_private_tail() {
50            Box::new(ProjectedResult::new(result, self.public_width))
51        } else {
52            result
53        }
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60
61    #[test]
62    fn private_tail_is_explicit_and_bounded_by_physical_width() {
63        let shape = RowShape::new(
64            CompactArc::new(vec!["public".into(), "order-key".into()]),
65            1,
66        )
67        .unwrap();
68        assert_eq!(shape.public_width(), 1);
69        assert_eq!(shape.physical_width(), 2);
70        assert!(shape.has_private_tail());
71
72        assert!(RowShape::new(CompactArc::new(vec!["only".into()]), 2).is_err());
73    }
74}