uqa_sql/catalog/stored_view/
restoration.rs1use super::StoredView;
9use crate::{catalog::roles::guards::RoleCatalogGuards, plan::QueryPlan, RowSchema};
10use std::collections::{BTreeMap, BTreeSet};
11use uqa_core::RelationIdentity;
12
13#[derive(serde::Deserialize)]
14#[serde(untagged)]
15pub enum RestoredView {
16 Current(StoredView),
17 Legacy(QueryPlan),
18}
19
20pub fn validate_restored_view_object_ids(
21 views: &BTreeMap<RelationIdentity, StoredView>,
22) -> Result<(), String> {
23 let mut object_ids = BTreeSet::new();
24 for (relation, view) in views {
25 if !object_ids.insert(view.object_id) {
26 return Err(format!(
27 "view `{}` has a duplicate object identity",
28 relation.qualified_name()
29 ));
30 }
31 }
32 Ok(())
33}
34
35pub fn validate_restored_view_security(
36 roles: &dyn RoleCatalogGuards,
37 view_name: &str,
38 view: &StoredView,
39) -> Result<(), String> {
40 if !roles.role_definitions().contains_key(&view.role_owner) {
41 return Err(format!(
42 "view `{view_name}` is owned by missing role `{}`",
43 view.role_owner
44 ));
45 }
46 crate::catalog::security::table::validate_table_security_invariants(
47 &view.security(),
48 view.output_columns.as_deref(),
49 &roles.role_definitions(),
50 )
51 .map_err(|error| format!("view `{view_name}` has invalid privilege metadata: {error}"))?;
52 Ok(())
53}
54pub fn validate_migrated_view_security(
55 roles: &dyn RoleCatalogGuards,
56 views: &BTreeMap<RelationIdentity, StoredView>,
57) -> Result<(), String> {
58 for (relation, view) in views {
59 let output_columns = view.output_columns.as_deref().ok_or_else(|| {
60 format!(
61 "view `{}` has no public column metadata after catalog migration",
62 relation.qualified_name()
63 )
64 })?;
65 crate::catalog::security::table::validate_table_security_invariants(
66 &view.security(),
67 Some(output_columns),
68 &roles.role_definitions(),
69 )
70 .map_err(|error| {
71 format!(
72 "view `{}` has invalid privilege metadata after migration: {error}",
73 relation.qualified_name()
74 )
75 })?;
76 }
77 Ok(())
78}
79pub fn restored_view_output_columns(schema: &RowSchema) -> Vec<String> {
80 schema
81 .columns()
82 .iter()
83 .enumerate()
84 .map(|(position, column)| schema.public_name(position).unwrap_or(column).to_string())
85 .collect()
86}
87
88#[cfg(test)]
89mod tests;