uqa_sql/schema/
record_fields.rs1use super::{Arc, ColumnType, HashMap, RowSchema};
10
11pub type RecordFields = Arc<[Option<ColumnType>]>;
13
14impl RowSchema {
15 pub fn record_fields(&self, logical: usize) -> Option<&RecordFields> {
16 self.slot(logical)
17 .and_then(|slot| self.physical_record_fields(slot))
18 }
19
20 pub fn physical_record_fields(&self, slot: usize) -> Option<&RecordFields> {
21 self.index.cold.record_fields.get(&slot)
22 }
23
24 pub fn with_record_fields(
26 mut self,
27 fields: impl IntoIterator<Item = (usize, RecordFields)>,
28 ) -> Self {
29 for (logical, fields) in fields {
30 if let Some(slot) = self.slot(logical) {
31 Arc::make_mut(&mut self.index)
32 .cold
33 .record_fields
34 .insert(slot, fields);
35 }
36 }
37 self
38 }
39
40 pub fn with_record_fields_from(self, input: &Self) -> Self {
42 let width = self.len().min(input.len());
43 self.with_record_fields((0..width).filter_map(|index| {
44 input
45 .record_fields(index)
46 .cloned()
47 .map(|fields| (index, fields))
48 }))
49 }
50
51 pub(super) fn joined_record_fields(
52 left: &Self,
53 right: &Self,
54 right_base: usize,
55 ) -> HashMap<usize, RecordFields> {
56 let mut fields = left.index.cold.record_fields.clone();
57 fields.extend(
58 right
59 .index
60 .cold
61 .record_fields
62 .iter()
63 .map(|(slot, fields)| (right_base + slot, fields.clone())),
64 );
65 fields
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn projection_alias_join_and_compaction_preserve_record_field_slots() {
75 let fields: RecordFields =
76 vec![Some(ColumnType::Integer), Some(ColumnType::BigInteger)].into();
77 let input = RowSchema::with_types(
78 vec!["discard".into(), "value".into()],
79 vec![Some(ColumnType::Text), Some(ColumnType::Record)],
80 )
81 .with_record_fields([(1, fields.clone())]);
82 let selected = RowSchema::select(&input, &[("renamed".into(), "value".into())]);
83 assert_eq!(selected.record_fields(0), Some(&fields));
84 let qualified = RowSchema::with_relation_qualifier(&selected, "r");
85 assert_eq!(
86 qualified.physical_record_fields(qualified.qualified_slot("r", "renamed").unwrap()),
87 Some(&fields)
88 );
89 let (compact, _) = qualified.canonical_projection();
90 assert_eq!(compact.record_fields(0), Some(&fields));
91 let outer = RowSchema::with_outer_schema(&RowSchema::default(), &compact);
92 assert_eq!(
93 outer.physical_record_fields(outer.qualified_slot("r", "renamed").unwrap()),
94 Some(&fields)
95 );
96 }
97}