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