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(super::StoredViewDefinition),
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 let mut oids = BTreeSet::new();
25 for (relation, view) in views {
26 if !object_ids.insert(view.object_id) {
27 return Err(format!(
28 "view `{}` has a duplicate object identity",
29 relation.qualified_name()
30 ));
31 }
32 if let Some(recorded) = view.catalog_oids {
33 if !recorded.is_valid_for(
34 crate::catalog::relation_oids::RelationOidKind::View,
35 &view.object_id,
36 ) || !recorded.claimed().all(|oid| oids.insert(oid))
37 {
38 return Err(format!(
39 "view `{}` records invalid catalog OIDs",
40 relation.qualified_name()
41 ));
42 }
43 }
44 }
45 Ok(())
46}
47
48pub fn validate_restored_view_security(
49 roles: &dyn RoleCatalogGuards,
50 view_name: &str,
51 view: &StoredView,
52) -> Result<(), String> {
53 view.security
54 .validate(view.output_columns.as_deref(), &roles.role_definitions())
55 .map_err(|error| format!("view `{view_name}` has invalid privilege metadata: {error}"))?;
56 Ok(())
57}
58pub fn validate_migrated_view_security(
59 roles: &dyn RoleCatalogGuards,
60 views: &BTreeMap<RelationIdentity, StoredView>,
61) -> Result<(), String> {
62 for (relation, view) in views {
63 let output_columns = view.output_columns.as_deref().ok_or_else(|| {
64 format!(
65 "view `{}` has no public column metadata after catalog migration",
66 relation.qualified_name()
67 )
68 })?;
69 view.security
70 .validate(Some(output_columns), &roles.role_definitions())
71 .map_err(|error| {
72 format!(
73 "view `{}` has invalid privilege metadata after migration: {error}",
74 relation.qualified_name()
75 )
76 })?;
77 }
78 Ok(())
79}
80pub fn restored_view_output_columns(schema: &RowSchema) -> Vec<String> {
81 schema
82 .columns()
83 .iter()
84 .enumerate()
85 .map(|(position, column)| schema.public_name(position).unwrap_or(column).to_string())
86 .collect()
87}
88
89#[cfg(test)]
90mod tests;