Skip to main content

kivis_fs/
lib.rs

1//! File system storage backend for [kivis](https://crates.io/crates/kivis) databases.
2//!
3//! This crate provides a simple, human-readable file-based storage implementation for kivis,
4//! where each record is stored as an individual file using CSV serialization. It's designed
5//! for use cases where data inspection, manual editing, or simple persistence is more
6//! important than raw performance.
7//!
8//! # Features
9//!
10//! - **Human-Readable Storage**: Records are stored as CSV-formatted files that can be
11//!   easily inspected and modified with standard text editors
12//! - **One Record Per File**: Each key-value pair becomes a separate `.dat` file, making
13//!   it trivial to understand the storage structure
14//! - **URL-Encoded Filenames**: Keys are safely encoded as filenames while remaining
15//!   largely human-readable
16//! - **Full kivis Integration**: Implements the `Storage` trait for seamless integration
17//!   with kivis databases, supporting all features including indexes and foreign keys
18//!
19//! # When to Use
20//!
21//! `kivis-fs` is ideal for:
22//!
23//! - **Development and Testing**: Quick prototyping where you want to inspect data easily
24//! - **Configuration Storage**: Persisting application settings or small datasets
25//! - **Data Interchange**: Scenarios requiring manual inspection or editing of stored records
26//! - **Audit Trails**: When having individual files per record aids in version control
27//! - **Educational Purposes**: Learning kivis concepts with transparent storage
28//!
29//! For production systems requiring high performance, consider using more optimized
30//! backends like Sled or RocksDB.
31//!
32//! # Example
33//!
34//! ```rust
35//! use kivis::{Database, Record, manifest};
36//! use kivis_fs::FileStore;
37//!
38//! #[derive(Record, Debug, Clone, serde::Serialize, serde::Deserialize)]
39//! struct User {
40//!     name: String,
41//!     email: String,
42//! }
43//!
44//! manifest![MyApp: User];
45//!
46//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
47//! # let temp_dir = tempfile::tempdir()?;
48//! #
49//! // Create a file-based database in the "./data" directory
50//! let storage = FileStore::new(temp_dir.path())?;
51//! let mut db: Database<_, MyApp> = Database::new(storage)?;
52//!
53//! // Insert a user - creates a new .dat file
54//! let user = User {
55//!     name: "Alice".to_string(),
56//!     email: "alice@example.com".to_string(),
57//! };
58//! let key = db.put(user)?;
59//!
60//! // Retrieve the user - reads from the corresponding .dat file
61//! let retrieved = db.get(&key)?;
62//! assert!(retrieved.is_some());
63//! # Ok(())
64//! # }
65//! ```
66//!
67//! # Storage Format
68//!
69//! Records are stored in the filesystem as follows:
70//!
71//! - Each record is a separate file with a `.dat` extension
72//! - Filenames are derived from URL-encoded keys
73//! - File contents use CSV format for the serialized data
74//! - The storage directory is created automatically if it doesn't exist
75//!
76//! This makes the storage directory easy to navigate, backup, and inspect manually.
77
78mod error;
79mod repository;
80mod serializer;
81
82use kivis::{BufferOp, Storage};
83
84use crate::serializer::CsvSerializer;
85
86pub use crate::repository::FileStore;
87
88impl Storage for FileStore {
89    type Repo = Self;
90    type KeyUnifier = CsvSerializer;
91    type ValueUnifier = CsvSerializer;
92    type Container = Vec<BufferOp>;
93
94    fn repository(&self) -> &Self::Repo {
95        self
96    }
97
98    fn repository_mut(&mut self) -> &mut Self::Repo {
99        self
100    }
101}