storage_kit/databases/config/mod.rs
1//! Built-in database configuration.
2
3mod common;
4mod lance;
5mod surreal;
6
7use serde::{Deserialize, Serialize};
8
9use crate::StorageError;
10
11pub use common::CommonConfig;
12pub use lance::LanceConfig;
13pub use surreal::{SurrealConfig, SurrealModeConfig};
14
15/// Selects and configures one built-in database implementation.
16///
17/// Shared portable connection policy is carried directly by each variant, so
18/// construction has one configuration owner rather than a wrapper around a
19/// second backend-selection enum.
20///
21/// LanceDB is always available. SurrealDB requires `surrealdb`.
22/// Configuration values do not open backend resources.
23/// These constructors create data only; [`crate::Database::connect`] opens it.
24///
25/// # Examples
26///
27/// ```
28/// use storage_kit::database::config::{DatabaseConfig, LanceConfig};
29/// let config = DatabaseConfig::lance(LanceConfig::embedded_path("memory://"));
30/// config.validate()?;
31/// assert_eq!(config.common().request_timeout_ms, 30_000);
32/// # Ok::<(), storage_kit::StorageError>(())
33/// ```
34#[derive(Clone, Debug, Serialize, Deserialize)]
35pub enum DatabaseConfig {
36 /// Opens LanceDB.
37 Lance {
38 /// LanceDB-specific settings.
39 config: LanceConfig,
40 /// Shared portable connection policy.
41 common: CommonConfig,
42 },
43 /// Opens SurrealDB.
44 Surreal {
45 /// SurrealDB-specific settings.
46 config: SurrealConfig,
47 /// Shared portable connection policy.
48 common: CommonConfig,
49 },
50}
51
52impl DatabaseConfig {
53 /// Selects LanceDB with default shared connection policy.
54 ///
55 /// # Examples
56 ///
57 /// ```
58 /// use storage_kit::database::config::{DatabaseConfig, LanceConfig};
59 /// let config = DatabaseConfig::lance(LanceConfig::embedded_path("memory://"));
60 /// config.validate()?;
61 /// # Ok::<(), storage_kit::StorageError>(())
62 /// ```
63 #[must_use]
64 pub fn lance(config: LanceConfig) -> Self {
65 Self::Lance {
66 config,
67 common: CommonConfig::default(),
68 }
69 }
70
71 /// Selects SurrealDB with default shared connection policy.
72 ///
73 /// # Examples
74 ///
75 /// ```
76 /// use storage_kit::database::config::{DatabaseConfig, SurrealConfig};
77 /// let config = DatabaseConfig::surreal(SurrealConfig::default());
78 /// config.validate()?;
79 /// # Ok::<(), storage_kit::StorageError>(())
80 /// ```
81 #[must_use]
82 pub fn surreal(config: SurrealConfig) -> Self {
83 Self::Surreal {
84 config,
85 common: CommonConfig::default(),
86 }
87 }
88
89 /// Replaces the shared connection policy carried by this variant.
90 ///
91 /// # Examples
92 ///
93 /// ```
94 /// use storage_kit::database::config::{CommonConfig, DatabaseConfig, LanceConfig};
95 /// let config = DatabaseConfig::lance(LanceConfig::embedded_path("memory://"))
96 /// .with_common(CommonConfig { read_only: true, ..Default::default() });
97 /// assert!(config.common().read_only);
98 /// # Ok::<(), storage_kit::StorageError>(())
99 /// ```
100 #[must_use]
101 pub fn with_common(self, common: CommonConfig) -> Self {
102 match self {
103 Self::Lance { config, .. } => Self::Lance { config, common },
104 Self::Surreal { config, .. } => Self::Surreal { config, common },
105 }
106 }
107
108 /// Borrows the shared connection policy.
109 ///
110 /// # Examples
111 ///
112 /// ```
113 /// use storage_kit::database::config::{DatabaseConfig, LanceConfig};
114 /// let config = DatabaseConfig::lance(LanceConfig::embedded_path("memory://"));
115 /// assert_eq!(config.common().connect_timeout_ms, 15_000);
116 /// # Ok::<(), storage_kit::StorageError>(())
117 /// ```
118 #[must_use]
119 pub fn common(&self) -> &CommonConfig {
120 match self {
121 Self::Lance { common, .. } | Self::Surreal { common, .. } => common,
122 }
123 }
124
125 /// Validates shared policy and backend-specific settings.
126 ///
127 /// This checks configuration without opening a connection or proving service
128 /// availability or request-specific capability support.
129 ///
130 /// # Errors
131 ///
132 /// Returns [`StorageError::InvalidConfig`] for zero timeouts, invalid default
133 /// locator fragments, or invalid selected backend settings, such as an empty
134 /// embedded path, unsupported URI route, or wrong remote URL scheme.
135 ///
136 /// # Examples
137 ///
138 /// ```
139 /// use storage_kit::database::config::{DatabaseConfig, LanceConfig};
140 /// let valid = DatabaseConfig::lance(LanceConfig::embedded_path("memory://"));
141 /// valid.validate()?;
142 /// let invalid = DatabaseConfig::lance(LanceConfig::embedded_path("s3://bucket/data"));
143 /// assert!(invalid.validate().is_err());
144 /// # Ok::<(), storage_kit::StorageError>(())
145 /// ```
146 pub fn validate(&self) -> Result<(), StorageError> {
147 self.common().validate()?;
148 match self {
149 Self::Lance { config, .. } => config.validate(),
150 Self::Surreal { config, .. } => config.validate(),
151 }
152 }
153}
154
155impl From<LanceConfig> for DatabaseConfig {
156 fn from(config: LanceConfig) -> Self {
157 Self::lance(config)
158 }
159}
160
161impl From<SurrealConfig> for DatabaseConfig {
162 fn from(config: SurrealConfig) -> Self {
163 Self::surreal(config)
164 }
165}