gel_dsn/gel/
error.rs

1use super::branding::*;
2use crate::{gel::BuildPhase, host::HostParseError};
3use std::{convert::Infallible, num::ParseIntError};
4
5use super::ParamSource;
6
7#[derive(Debug, Clone, PartialEq, Eq, derive_more::Display, PartialOrd, Ord)]
8pub enum CompoundSource {
9    #[display("DSN")]
10    Dsn,
11    #[display("Instance")]
12    Instance,
13    #[display("Credentials file")]
14    CredentialsFile,
15    #[display("Host and port")]
16    HostPort,
17    #[display("Unix socket")]
18    UnixSocket,
19}
20
21#[derive(
22    Debug, Clone, PartialEq, Eq, derive_more::Display, derive_more::Error, PartialOrd, Ord,
23)]
24pub enum TlsSecurityError {
25    IncompatibleSecurityOptions,
26    InvalidValue,
27}
28
29#[derive(
30    Debug, Clone, PartialEq, Eq, derive_more::Display, derive_more::Error, PartialOrd, Ord,
31)]
32pub enum InstanceNameError {
33    InvalidInstanceName,
34    InvalidCloudOrgName,
35    InvalidCloudInstanceName,
36}
37
38#[derive(
39    Debug, Clone, PartialEq, Eq, derive_more::Display, derive_more::Error, PartialOrd, Ord,
40)]
41#[error(ignore)]
42pub enum InvalidCredentialsFileError {
43    FileNotFound,
44    #[display("{}={}, {}={}", _0.0, _0.1, _1.0, _1.1)]
45    ConflictingSettings((String, String), (String, String)),
46    SerializationError(String),
47}
48
49#[derive(
50    Debug, Clone, PartialEq, Eq, derive_more::Display, derive_more::Error, PartialOrd, Ord,
51)]
52pub enum InvalidSecretKeyError {
53    InvalidJwt,
54    MissingIssuer,
55}
56
57#[derive(
58    Debug, Clone, PartialEq, Eq, derive_more::Display, derive_more::Error, PartialOrd, Ord,
59)]
60pub enum InvalidDsnError {
61    InvalidScheme,
62    ParseError,
63    DuplicateOptions(#[error(not(source))] String),
64    BranchAndDatabase,
65}
66
67/// DSN parsing errors.
68///
69/// This is the top-level error type for DSN parsing errors. It is used to
70/// represent errors that may occur when parsing a DSN, accessing environment
71/// variables, files that hold credentials, and any other part of the parsing
72/// process.
73#[derive(
74    Debug,
75    derive_more::Error,
76    derive_more::Display,
77    derive_more::From,
78    PartialEq,
79    Eq,
80    PartialOrd,
81    Ord,
82)]
83pub enum ParseError {
84    #[display("Credentials file not found")]
85    CredentialsFileNotFound,
86    #[display("Environment variable was not set: {_1} (from {_0})")]
87    EnvNotFound(ParamSource, String),
88    #[display("{_0} and {_1} are mutually exclusive and cannot be used together")]
89    ExclusiveOptions(String, String),
90    #[display("File not found")]
91    FileNotFound,
92    #[display("Invalid credentials file: {_0}")]
93    #[from]
94    InvalidCredentialsFile(InvalidCredentialsFileError),
95    #[display("Invalid database")]
96    InvalidDatabase,
97    #[display("Invalid DSN: {_0}")]
98    #[from]
99    InvalidDsn(InvalidDsnError),
100    #[display("Invalid DSN or instance name")]
101    InvalidDsnOrInstanceName,
102    #[display("Invalid host")]
103    InvalidHost,
104    #[display("Invalid instance name: {_0}")]
105    #[from]
106    InvalidInstanceName(InstanceNameError),
107    #[display("Invalid port")]
108    InvalidPort,
109    #[display("Invalid secret key")]
110    #[from]
111    InvalidSecretKey(InvalidSecretKeyError),
112    #[display("Invalid TLS security")]
113    #[from]
114    InvalidTlsSecurity(TlsSecurityError),
115    #[display("Invalid user")]
116    InvalidUser,
117    #[display("Invalid certificate")]
118    InvalidCertificate,
119    #[display("Invalid duration")]
120    InvalidDuration,
121    #[display("Multiple compound options were specified while parsing {_0}: {_1:#?}")]
122    MultipleCompound(BuildPhase, #[error(not(source))] Vec<CompoundSource>),
123    #[display("No connection options specified, and no project manifest file found ({MANIFEST_FILE_DISPLAY_NAME})")]
124    NoOptionsOrToml,
125    #[display("Project not initialized")]
126    ProjectNotInitialised,
127    #[display("Secret key not found")]
128    SecretKeyNotFound,
129    #[display("Unix socket unsupported")]
130    UnixSocketUnsupported,
131}
132
133impl ParseError {
134    pub fn error_type(&self) -> &str {
135        match self {
136            Self::EnvNotFound(..) => "env_not_found",
137            Self::CredentialsFileNotFound => "credentials_file_not_found",
138            Self::ExclusiveOptions(..) => "exclusive_options",
139            Self::FileNotFound => "file_not_found",
140            Self::InvalidCredentialsFile(_) => "invalid_credentials_file",
141            Self::InvalidDatabase => "invalid_database",
142            Self::InvalidDsn(_) => "invalid_dsn",
143            Self::InvalidDsnOrInstanceName => "invalid_dsn_or_instance_name",
144            Self::InvalidHost => "invalid_host",
145            Self::InvalidInstanceName(_) => "invalid_instance_name",
146            Self::InvalidPort => "invalid_port",
147            Self::InvalidSecretKey(_) => "invalid_secret_key",
148            Self::InvalidTlsSecurity(_) => "invalid_tls_security",
149            Self::InvalidUser => "invalid_user",
150            Self::InvalidCertificate => "invalid_certificate",
151            Self::InvalidDuration => "invalid_duration",
152            Self::MultipleCompound(BuildPhase::Environment, _) => "multiple_compound_env",
153            Self::MultipleCompound(BuildPhase::Options, _) => "multiple_compound_opts",
154            Self::MultipleCompound(BuildPhase::Project, _) => "multiple_compound_project",
155            Self::NoOptionsOrToml => "no_options_or_toml",
156            Self::ProjectNotInitialised => "project_not_initialised",
157            Self::SecretKeyNotFound => "secret_key_not_found",
158            Self::UnixSocketUnsupported => "unix_socket_unsupported",
159        }
160    }
161
162    pub fn gel_error(self) -> gel_errors::Error {
163        use gel_errors::ErrorKind;
164
165        match self {
166            Self::EnvNotFound(..)
167            | Self::CredentialsFileNotFound
168            | Self::FileNotFound
169            | Self::InvalidCredentialsFile(_)
170            | Self::InvalidDatabase
171            | Self::InvalidDsn(_)
172            | Self::InvalidDsnOrInstanceName
173            | Self::InvalidHost
174            | Self::InvalidInstanceName(_)
175            | Self::InvalidPort
176            | Self::InvalidSecretKey(_)
177            | Self::InvalidTlsSecurity(_)
178            | Self::InvalidUser
179            | Self::InvalidCertificate
180            | Self::InvalidDuration
181            | Self::UnixSocketUnsupported => {
182                // The argument is invalid
183                gel_errors::InvalidArgumentError::with_source(self)
184            }
185            Self::MultipleCompound(..) | Self::ExclusiveOptions(..) => {
186                // The argument is valid, but the use is invalid
187                gel_errors::InterfaceError::with_source(self)
188            }
189            Self::NoOptionsOrToml | Self::ProjectNotInitialised => {
190                // Credentials are missing
191                gel_errors::ClientNoCredentialsError::with_source(self)
192            }
193            Self::SecretKeyNotFound => {
194                // Required cloud configuration is missing
195                gel_errors::NoCloudConfigFound::with_source(self)
196            }
197        }
198    }
199}
200
201impl From<ParseError> for gel_errors::Error {
202    fn from(val: ParseError) -> Self {
203        val.gel_error()
204    }
205}
206
207impl From<ParseIntError> for ParseError {
208    fn from(_: ParseIntError) -> Self {
209        ParseError::InvalidPort
210    }
211}
212
213impl From<HostParseError> for ParseError {
214    fn from(_: HostParseError) -> Self {
215        ParseError::InvalidHost
216    }
217}
218
219impl From<Infallible> for ParseError {
220    fn from(_: Infallible) -> Self {
221        unreachable!()
222    }
223}
224
225#[derive(Debug, Clone, PartialEq, Eq, derive_more::Display, PartialOrd, Ord)]
226pub enum Warning {
227    #[display("Deprecated credential property: {_0}")]
228    DeprecatedCredentialProperty(String),
229    #[display("Deprecated environment variable: {_0}")]
230    DeprecatedEnvironmentVariable(String, String),
231    #[display("Multiple environment variables set: {}", _0.join(", "))]
232    MultipleEnvironmentVariables(Vec<String>),
233    #[display("{_0} is ignored when using Docker TCP port")]
234    DockerPortIgnored(String),
235    #[display("Database and branch are set to default values")]
236    DefaultDatabaseAndBranch,
237    #[display("Updated out-of-date credentials file")]
238    UpdatedOutdatedCredentials,
239}
240
241#[derive(Debug, Default)]
242pub struct Warnings {
243    warnings: Vec<Warning>,
244}
245
246impl Warnings {
247    pub fn warn(&mut self, warning: Warning) {
248        self.warnings.push(warning);
249    }
250
251    pub fn into_vec(self) -> Vec<Warning> {
252        self.warnings
253    }
254
255    pub fn iter(&self) -> impl Iterator<Item = &Warning> {
256        self.warnings.iter()
257    }
258}
259
260impl<'a> IntoIterator for &'a Warnings {
261    type Item = &'a Warning;
262
263    type IntoIter = std::slice::Iter<'a, Warning>;
264
265    fn into_iter(self) -> Self::IntoIter {
266        self.warnings.iter()
267    }
268}