use std::path::{Path, PathBuf};
use crate::cache::CacheConfig;
use crate::error::Error;
use crate::transaction::{BatchWriterConfig, TransactionManagerConfig, VectorSyncStrategy};
pub const DEFAULT_MAX_ROWS_IN_MEMORY: usize = 1_000_000;
#[derive(Debug, Clone)]
pub struct Config {
pub path: PathBuf,
pub create_if_missing: bool,
pub cache_size: Option<usize>,
pub max_size: Option<u64>,
pub vector_sync_strategy: VectorSyncStrategy,
pub in_memory: bool,
pub query_cache_config: CacheConfig,
pub batch_writer_config: BatchWriterConfig,
pub max_rows_in_memory: usize,
}
impl Default for Config {
fn default() -> Self {
Self {
path: PathBuf::new(),
create_if_missing: true,
cache_size: None,
max_size: None,
vector_sync_strategy: VectorSyncStrategy::Synchronous,
in_memory: false,
query_cache_config: CacheConfig::default(),
batch_writer_config: BatchWriterConfig::default(),
max_rows_in_memory: DEFAULT_MAX_ROWS_IN_MEMORY,
}
}
}
impl Config {
#[must_use]
pub fn new(path: impl Into<PathBuf>) -> Self {
Self { path: path.into(), ..Default::default() }
}
#[must_use]
pub fn in_memory() -> Self {
Self { in_memory: true, ..Default::default() }
}
#[must_use]
pub const fn create_if_missing(mut self, create: bool) -> Self {
self.create_if_missing = create;
self
}
#[must_use]
pub fn transaction_config(&self) -> TransactionManagerConfig {
TransactionManagerConfig {
vector_sync_strategy: self.vector_sync_strategy,
batch_writer_config: self.batch_writer_config.clone(),
}
}
}
#[derive(Debug, Clone, Default)]
pub struct DatabaseBuilder {
config: Config,
}
impl DatabaseBuilder {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn in_memory() -> Self {
Self { config: Config::in_memory() }
}
#[must_use]
pub fn path(mut self, path: impl AsRef<Path>) -> Self {
self.config.path = path.as_ref().to_path_buf();
self.config.in_memory = false;
self
}
#[must_use]
pub const fn create_if_missing(mut self, create: bool) -> Self {
self.config.create_if_missing = create;
self
}
#[must_use]
pub const fn cache_size(mut self, size: usize) -> Self {
self.config.cache_size = Some(size);
self
}
#[must_use]
pub const fn max_size(mut self, size: u64) -> Self {
self.config.max_size = Some(size);
self
}
#[must_use]
pub const fn vector_sync_strategy(mut self, strategy: VectorSyncStrategy) -> Self {
self.config.vector_sync_strategy = strategy;
self
}
#[must_use]
pub fn query_cache_config(mut self, config: CacheConfig) -> Self {
self.config.query_cache_config = config;
self
}
#[must_use]
pub fn disable_query_cache(mut self) -> Self {
self.config.query_cache_config = CacheConfig::disabled();
self
}
#[must_use]
pub fn batch_writer_config(mut self, config: BatchWriterConfig) -> Self {
self.config.batch_writer_config = config;
self
}
#[must_use]
pub fn disable_write_batching(mut self) -> Self {
self.config.batch_writer_config = BatchWriterConfig::disabled();
self
}
#[must_use]
pub const fn max_rows_in_memory(mut self, limit: usize) -> Self {
self.config.max_rows_in_memory = limit;
self
}
#[must_use]
pub fn config(&self) -> &Config {
&self.config
}
pub fn build(self) -> Result<Config, Error> {
if !self.config.in_memory && self.config.path.as_os_str().is_empty() {
return Err(Error::Config("database path is required".to_string()));
}
Ok(self.config)
}
pub fn open(self) -> Result<crate::database::Database, Error> {
let config = self.build()?;
crate::database::Database::open_with_config(config)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_config_new() {
let config = Config::new("/tmp/test.manifold");
assert_eq!(config.path, PathBuf::from("/tmp/test.manifold"));
assert!(config.create_if_missing);
assert!(!config.in_memory);
}
#[test]
fn test_config_in_memory() {
let config = Config::in_memory();
assert!(config.in_memory);
assert!(config.path.as_os_str().is_empty());
}
#[test]
fn test_builder_path() {
let builder = DatabaseBuilder::new().path("/tmp/test.manifold");
assert_eq!(builder.config.path, PathBuf::from("/tmp/test.manifold"));
assert!(!builder.config.in_memory);
}
#[test]
fn test_builder_in_memory() {
let builder = DatabaseBuilder::in_memory();
assert!(builder.config.in_memory);
}
#[test]
fn test_builder_cache_size() {
let builder = DatabaseBuilder::new().cache_size(1024 * 1024);
assert_eq!(builder.config.cache_size, Some(1024 * 1024));
}
#[test]
fn test_builder_vector_sync_strategy() {
let builder = DatabaseBuilder::new().vector_sync_strategy(VectorSyncStrategy::Async);
assert_eq!(builder.config.vector_sync_strategy, VectorSyncStrategy::Async);
}
#[test]
fn test_builder_build_requires_path() {
let result = DatabaseBuilder::new().build();
assert!(result.is_err());
}
#[test]
fn test_builder_build_with_path() {
let result = DatabaseBuilder::new().path("/tmp/test.manifold").build();
assert!(result.is_ok());
}
#[test]
fn test_builder_build_in_memory() {
let result = DatabaseBuilder::in_memory().build();
assert!(result.is_ok());
}
}