Skip to main content

spin_key_value_spin/
lib.rs

1mod store;
2
3use std::{fs, path::PathBuf};
4
5use anyhow::Context as _;
6use serde::{Deserialize, Serialize};
7use spin_factor_key_value::runtime_config::spin::MakeKeyValueStore;
8use store::{DatabaseLocation, KeyValueSqlite};
9
10/// A key-value store that uses SQLite as the backend.
11pub struct SpinKeyValueStore {
12    /// The base path or directory for the SQLite database file.
13    base_path: Option<PathBuf>,
14}
15
16impl SpinKeyValueStore {
17    /// Create a new SpinKeyValueStore with the given base path.
18    ///
19    /// If the database directory is None, the database will always be in-memory.
20    /// If it's `Some`, the database will be stored at the combined `base_path` and
21    /// the `path` specified in the runtime configuration.
22    pub fn new(base_path: Option<PathBuf>) -> Self {
23        Self { base_path }
24    }
25}
26
27impl MakeKeyValueStore for SpinKeyValueStore {
28    const RUNTIME_CONFIG_TYPE: &'static str = "spin";
29
30    type RuntimeConfig = SpinKeyValueRuntimeConfig;
31
32    type StoreManager = KeyValueSqlite;
33
34    fn make_store(
35        &self,
36        runtime_config: Self::RuntimeConfig,
37    ) -> anyhow::Result<Self::StoreManager> {
38        let location = match (&self.base_path, &runtime_config.path) {
39            // If both the base path and the path are specified, resolve the path against the base path
40            (Some(base_path), Some(path)) => DatabaseLocation::Path(base_path.join(path)),
41            // If the base path is `None` but use the path without resolving relative to the base path.
42            (None, Some(path)) => DatabaseLocation::Path(path.clone()),
43            // Otherwise, use an in-memory database
44            (None | Some(_), None) => DatabaseLocation::InMemory,
45        };
46        if let DatabaseLocation::Path(path) = &location {
47            // Create the store's parent directory if necessary
48            if let Some(parent) = path.parent().filter(|p| !p.exists()) {
49                fs::create_dir_all(parent).with_context(|| {
50                    format!(
51                        "failed to create key value store's parent directory: '{}",
52                        parent.display()
53                    )
54                })?;
55            }
56        }
57        Ok(KeyValueSqlite::new(location))
58    }
59}
60
61/// The serialized runtime configuration for the SQLite key-value store.
62#[derive(Deserialize, Serialize)]
63pub struct SpinKeyValueRuntimeConfig {
64    /// The path to the SQLite database file.
65    path: Option<PathBuf>,
66}
67
68impl SpinKeyValueRuntimeConfig {
69    /// Create a new SpinKeyValueRuntimeConfig with the given parent directory
70    /// where the key-value store will live.
71    pub fn new(path: Option<PathBuf>) -> Self {
72        Self { path }
73    }
74}