uqa_sql/routines/lifecycle/
restoration.rs1use super::routine_signature_label;
10use crate::{
11 ast::{CreateFunction, FunctionBody},
12 routines::routine_signature_types,
13};
14use std::collections::{BTreeMap, BTreeSet};
15use uqa_core::RelationIdentity;
16
17pub fn persisted_registry_relation(stored_name: &str) -> Result<RelationIdentity, String> {
18 RelationIdentity::from_legacy_name(stored_name)
19 .map_err(|error| format!("invalid persisted routine registry key `{stored_name}`: {error}"))
20}
21pub fn validate_persisted_routine_schema(
22 stored_name: &str,
23 relation: &RelationIdentity,
24 exists: bool,
25) -> Result<(), String> {
26 if !exists {
27 return Err(format!(
28 "persisted routine `{stored_name}` references missing schema `{}`",
29 relation.schema
30 ));
31 }
32 Ok(())
33}
34
35#[derive(Default)]
36pub struct RoutineRestoreBuilder {
37 definitions: BTreeMap<String, Vec<CreateFunction>>,
38 object_ids: BTreeSet<[u8; 16]>,
39}
40impl RoutineRestoreBuilder {
41 pub fn insert(
42 &mut self,
43 stored_name: &str,
44 stored_relation: &RelationIdentity,
45 mut def: CreateFunction,
46 ) -> Result<bool, String> {
47 let object_id = def
48 .object_id
49 .ok_or_else(|| format!("persisted routine `{stored_name}` has no object identity"))?;
50 if !self.object_ids.insert(object_id) {
51 return Err(format!(
52 "duplicate persisted routine object identity for `{stored_name}`"
53 ));
54 }
55 let mut migrated = false;
56 for parameter in &mut def.params {
57 if let Some(default) = &mut parameter.default {
58 migrated |= default.upgrade_legacy_serialized_dispatches();
59 }
60 }
61 if let FunctionBody::Statements(statements) = &mut def.body {
62 for statement in statements {
63 migrated |= statement.upgrade_legacy_serialized_dispatches();
64 }
65 }
66 let definition_relation =
67 RelationIdentity::from_legacy_name(&def.name).map_err(|error| {
68 format!(
69 "invalid persisted routine definition name `{}`: {error}",
70 def.name
71 )
72 })?;
73 if &definition_relation != stored_relation {
74 return Err(format!(
75 "persisted routine registry key `{stored_name}` does not match definition `{}`",
76 def.name
77 ));
78 }
79 let canonical_name = stored_relation.qualified_name();
80 def.name.clone_from(&canonical_name);
81 let signature = routine_signature_types(&def);
82 let definitions = self.definitions.entry(canonical_name.clone()).or_default();
83 if definitions
84 .iter()
85 .any(|existing| routine_signature_types(existing) == signature)
86 {
87 return Err(format!(
88 "duplicate persisted routine identity `{}`",
89 routine_signature_label(&canonical_name, &signature)
90 ));
91 }
92 definitions.push(def);
93 Ok(migrated)
94 }
95 pub fn into_definitions(self) -> BTreeMap<String, Vec<CreateFunction>> {
96 self.definitions
97 }
98}