Skip to main content

storage_kit/databases/config/
common.rs

1use std::time::Duration;
2
3use serde::{Deserialize, Serialize};
4
5use crate::{CapabilitySet, StorageError, StorageLocator};
6
7/// Shared policy applied to every built-in database connection.
8///
9/// Defaults allow writes, require no optional capabilities, and use a 15-second
10/// connect timeout and a 30-second operation deadline. The operation deadline
11/// includes internal preflight and backend-specific retry work. Mutations are
12/// not automatically replayed after uncertain completion.
13/// Configuration is validated by [`DatabaseConfig::validate`](crate::database::config::DatabaseConfig::validate) or
14/// [`crate::Database::connect`]; merely constructing this value performs no I/O.
15///
16/// # Examples
17///
18/// ```
19/// use storage_kit::database::config::{CommonConfig, DatabaseConfig, LanceConfig};
20/// let common = CommonConfig { request_timeout_ms: 5_000, read_only: true,
21///     ..Default::default() };
22/// let config = DatabaseConfig::lance(LanceConfig::embedded_path("memory://"))
23///     .with_common(common);
24/// config.validate()?;
25/// assert!(config.common().read_only);
26/// # Ok::<(), storage_kit::StorageError>(())
27/// ```
28#[derive(Clone, Debug, Serialize, Deserialize)]
29pub struct CommonConfig {
30    /// Default locator used to fill omitted request scope.
31    pub default_locator: Option<StorageLocator>,
32    /// Connection timeout in milliseconds.
33    pub connect_timeout_ms: u64,
34    /// Portable operation timeout in milliseconds.
35    pub request_timeout_ms: u64,
36    /// Rejects mutating operations when set.
37    pub read_only: bool,
38    /// Optional retained capabilities required at connection time.
39    pub required_capabilities: CapabilitySet,
40}
41
42impl Default for CommonConfig {
43    fn default() -> Self {
44        Self {
45            default_locator: None,
46            connect_timeout_ms: 15_000,
47            request_timeout_ms: 30_000,
48            read_only: false,
49            required_capabilities: CapabilitySet::empty(),
50        }
51    }
52}
53
54impl CommonConfig {
55    pub(crate) fn validate(&self) -> Result<(), StorageError> {
56        if self.connect_timeout_ms == 0 {
57            return Err(StorageError::InvalidConfig(
58                "connect_timeout_ms must be greater than zero".into(),
59            ));
60        }
61        if self.request_timeout_ms == 0 {
62            return Err(StorageError::InvalidConfig(
63                "request_timeout_ms must be greater than zero".into(),
64            ));
65        }
66        if let Some(locator) = &self.default_locator {
67            locator.validate_for_config("default_locator")?;
68        }
69        Ok(())
70    }
71
72    pub(crate) fn connect_timeout(&self) -> Duration {
73        Duration::from_millis(self.connect_timeout_ms)
74    }
75
76    pub(crate) fn request_timeout(&self) -> Duration {
77        Duration::from_millis(self.request_timeout_ms)
78    }
79
80    pub(crate) fn ensure_mutable(&self, operation: &'static str) -> Result<(), StorageError> {
81        if self.read_only {
82            return Err(StorageError::backend_op(
83                operation,
84                format!(
85                    "operation `{operation}` is disabled because the database is configured read-only"
86                ),
87            ));
88        }
89        Ok(())
90    }
91}