Skip to main content

dkdc_lake/
lib.rs

1//! # DuckLake - Encrypted Data Lake
2//!
3//! `dkdc-lake` provides the core data lake functionality for dkdc,
4//! built on DuckDB with encryption via the DuckLake extension.
5//!
6//! ## Features
7//!
8//! - Encrypted blob storage for files, secrets, and archives
9//! - Virtual filesystem with directory structure
10//! - Secret management with secure storage
11//! - Archive creation and extraction
12
13use anyhow::Result;
14use dkdc_config::{Config, DUCKLAKE_EXTENSION, SQLITE_EXTENSION};
15use duckdb::{Connection, Statement};
16
17pub mod archives;
18pub mod files;
19pub mod secrets;
20
21/// Main interface to the DuckLake data storage
22pub struct Lake {
23    connection: Connection,
24    config: Config,
25}
26
27impl Lake {
28    /// Create a new Lake instance with default configuration
29    pub fn new() -> Result<Self> {
30        let config = Config::new()?;
31        Self::with_config(config)
32    }
33
34    /// Create a new Lake instance with custom configuration
35    pub fn with_config(config: Config) -> Result<Self> {
36        config.ensure_metadata_db()?;
37
38        let connection = Connection::open_in_memory()?;
39
40        connection.execute_batch(&format!("INSTALL {};", DUCKLAKE_EXTENSION))?;
41        connection.execute_batch(&format!("INSTALL {};", SQLITE_EXTENSION))?;
42
43        let metadata_path = config.metadata_path();
44        let data_path = config.data_path();
45
46        connection.execute_batch(&format!(
47            "ATTACH '{}' AS metadata;",
48            metadata_path.display()
49        ))?;
50
51        connection.execute_batch(&format!(
52            "ATTACH 'ducklake:sqlite:{}' AS data (DATA_PATH '{}', ENCRYPTED);",
53            metadata_path.display(),
54            data_path.display()
55        ))?;
56
57        connection.execute_batch("USE data;")?;
58
59        Ok(Self { connection, config })
60    }
61
62    pub fn connection(&self) -> &Connection {
63        &self.connection
64    }
65
66    pub fn config(&self) -> &Config {
67        &self.config
68    }
69
70    pub fn execute(&self, sql: &str) -> Result<()> {
71        self.connection.execute_batch(sql)?;
72        Ok(())
73    }
74
75    pub fn prepare(&self, sql: &str) -> Result<Statement> {
76        Ok(self.connection.prepare(sql)?)
77    }
78
79    pub fn get_sql_commands(&self) -> String {
80        let metadata_path = self.config.metadata_path();
81        let data_path = self.config.data_path();
82
83        format!(
84            r#"INSTALL {};
85INSTALL {};
86
87ATTACH '{}' AS metadata;
88ATTACH 'ducklake:sqlite:{}' AS data (DATA_PATH '{}', ENCRYPTED);
89
90USE data;"#,
91            DUCKLAKE_EXTENSION,
92            SQLITE_EXTENSION,
93            metadata_path.display(),
94            metadata_path.display(),
95            data_path.display()
96        )
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103
104    #[test]
105    fn test_lake_creation() {
106        let lake = Lake::new();
107        assert!(lake.is_ok());
108    }
109}