Skip to main content

uqa_sql/catalog/stored_view/
restoration.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Decode and validate durable view definitions and migrated public metadata.
8use 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;