mz_storage_types/connections/
string_or_secret.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10use std::sync::Arc;
11
12use mz_ore::future::InTask;
13use mz_proto::{RustType, TryFromProtoError};
14use mz_repr::CatalogItemId;
15use mz_secrets::SecretsReader;
16use proptest_derive::Arbitrary;
17use serde::{Deserialize, Serialize};
18
19use crate::connections::SecretsReaderExt;
20
21include!(concat!(
22    env!("OUT_DIR"),
23    "/mz_storage_types.connections.string_or_secret.rs"
24));
25
26#[derive(Arbitrary, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
27pub enum StringOrSecret {
28    String(String),
29    Secret(CatalogItemId),
30}
31
32impl StringOrSecret {
33    /// Gets the value as a string, reading the secret if necessary.
34    pub async fn get_string(
35        &self,
36        in_task: InTask,
37        secrets_reader: &Arc<dyn SecretsReader>,
38    ) -> anyhow::Result<String> {
39        match self {
40            StringOrSecret::String(s) => Ok(s.clone()),
41            StringOrSecret::Secret(id) => secrets_reader.read_string_in_task_if(in_task, *id).await,
42        }
43    }
44
45    /// Asserts that this string or secret is a string and returns its contents.
46    pub fn unwrap_string(&self) -> &str {
47        match self {
48            StringOrSecret::String(s) => s,
49            StringOrSecret::Secret(_) => panic!("StringOrSecret::unwrap_string called on a secret"),
50        }
51    }
52
53    /// Asserts that this string or secret is a secret and returns its global
54    /// ID.
55    pub fn unwrap_secret(&self) -> CatalogItemId {
56        match self {
57            StringOrSecret::String(_) => panic!("StringOrSecret::unwrap_secret called on a string"),
58            StringOrSecret::Secret(id) => *id,
59        }
60    }
61}
62
63impl RustType<ProtoStringOrSecret> for StringOrSecret {
64    fn into_proto(&self) -> ProtoStringOrSecret {
65        use proto_string_or_secret::Kind;
66        ProtoStringOrSecret {
67            kind: Some(match self {
68                StringOrSecret::String(s) => Kind::String(s.clone()),
69                StringOrSecret::Secret(id) => Kind::Secret(id.into_proto()),
70            }),
71        }
72    }
73
74    fn from_proto(proto: ProtoStringOrSecret) -> Result<Self, TryFromProtoError> {
75        use proto_string_or_secret::Kind;
76        let kind = proto
77            .kind
78            .ok_or_else(|| TryFromProtoError::missing_field("ProtoStringOrSecret::kind"))?;
79        Ok(match kind {
80            Kind::String(s) => StringOrSecret::String(s),
81            Kind::Secret(id) => StringOrSecret::Secret(CatalogItemId::from_proto(id)?),
82        })
83    }
84}
85
86impl<V: std::fmt::Display> From<V> for StringOrSecret {
87    fn from(v: V) -> StringOrSecret {
88        StringOrSecret::String(format!("{}", v))
89    }
90}