uqa_sql/schema/
relation_types.rs1use super::{Arc, ColumnIdentity, ColumnType, HashMap, RowSchema};
10use crate::SQLError;
11
12#[derive(Debug, Default, Clone, PartialEq, Eq)]
14pub(super) struct RelationRowTypes(Option<Arc<NamedRows>>);
15
16#[derive(Debug, Default, Clone, PartialEq, Eq)]
17struct NamedRows {
18 types: HashMap<Box<str>, ColumnType>,
19 source: Option<Box<str>>,
21}
22
23impl RelationRowTypes {
24 pub(super) fn get(&self, qualifier: &str) -> Option<&ColumnType> {
25 self.0.as_ref()?.types.get(qualifier)
26 }
27
28 pub(super) fn qualifiers(&self) -> impl Iterator<Item = &str> {
29 self.0
30 .iter()
31 .flat_map(|rows| rows.types.keys().map(std::convert::AsRef::as_ref))
32 }
33
34 fn insert(&mut self, qualifier: &str, ty: ColumnType) {
35 let rows = self.0.get_or_insert_with(|| Arc::new(NamedRows::default()));
36 Arc::make_mut(rows).types.insert(qualifier.into(), ty);
37 }
38
39 pub(super) fn requalified(&self, input: &RowSchema, qualifier: &str) -> Self {
41 let Some(rows) = self.0.as_ref() else {
42 return Self::default();
43 };
44 let Some(source) = rows.source.as_deref() else {
45 return Self::default();
46 };
47 if input
48 .identities()
49 .iter()
50 .enumerate()
51 .any(|(position, column)| {
52 input.wildcard_position_visible(position) && column.qualifier() != Some(source)
53 })
54 {
55 return Self::default();
56 }
57 let mut result = Self::default();
58 result.insert(qualifier, rows.types[source].clone());
59 Arc::make_mut(result.0.as_mut().unwrap()).source = Some(qualifier.into());
60 result
61 }
62
63 pub(super) fn joined(left: &RowSchema, right: &RowSchema) -> Self {
64 if left.index.cold.row_types.0.is_none() && right.index.cold.row_types.0.is_none() {
65 return Self::default();
66 }
67 let mut result = Self::default();
68 for (source, other) in [(left, right), (right, left)] {
69 if let Some(rows) = &source.index.cold.row_types.0 {
70 for (qualifier, ty) in &rows.types {
71 if !other.has_qualifier(qualifier) {
72 result.insert(qualifier, ty.clone());
73 }
74 }
75 }
76 }
77 result
78 }
79
80 pub(super) fn with_outer(input: &RowSchema, outer: &RowSchema) -> Self {
81 let mut result = input.index.cold.row_types.clone();
82 if let Some(rows) = &outer.index.cold.row_types.0 {
83 for (qualifier, ty) in &rows.types {
84 if !input.has_qualifier(qualifier) {
85 result.insert(qualifier, ty.clone());
86 }
87 }
88 }
89 result
90 }
91}
92
93impl RowSchema {
94 pub(super) fn relation_qualifiers(&self) -> impl Iterator<Item = &str> {
95 self.index
96 .qualified
97 .keys()
98 .chain(self.index.aliases.keys())
99 .filter_map(ColumnIdentity::qualifier)
100 .chain(self.index.cold.row_types.qualifiers())
101 }
102
103 pub fn with_relation_row_type(
105 mut self,
106 qualifier: &str,
107 ty: ColumnType,
108 ) -> Result<Self, SQLError> {
109 if !matches!(ty, ColumnType::Composite(_))
110 || (!self.is_empty() && !self.has_qualifier(qualifier))
111 {
112 return Err(SQLError::Internal(
113 "a relation row type requires its named composite and source namespace".into(),
114 ));
115 }
116 let rows = &mut Arc::make_mut(&mut self.index).cold.row_types;
117 rows.insert(qualifier, ty);
118 let rows = Arc::make_mut(rows.0.as_mut().unwrap());
119 rows.source = (rows.types.len() == 1).then(|| qualifier.into());
120 Ok(self)
121 }
122}
123
124#[cfg(test)]
125mod tests;