🐛♻️ cli, vanth, vanth tests: Refactor store initialization and add trace logging

- Fixed CLI commands to prevent creating databases unnecessarily by using `StoreParams` with `create_if_not_exists: false` for `get`, `get_all`, `delete`, and `delete_all` commands.
- Refactored `Store::sqlite_from_path` to accept `StoreParams` and dynamically generate SQLite open flags.
- Added trace logging for received JSON content in `handle_write` command.
This commit is contained in:
Markus Scully 2025-08-07 16:27:39 +03:00
parent a91d92b6ff
commit af6bfadff8
Signed by: mascully
GPG key ID: 93CA5814B698101C
3 changed files with 63 additions and 11 deletions

View file

@ -1,9 +1,13 @@
use clap::{Args, Parser, Subcommand};
use tracing::trace;
use std::io::{self, Read};
use std::path::PathBuf;
use std::process;
use vanth::{ContentHash, store::Store, Ty};
use vanth::hash as vanth_hash;
use vanth::{
ContentHash, Ty,
store::{Store, StoreParams},
};
#[derive(Parser, Debug)]
#[command(name = "vanth")]
@ -104,7 +108,7 @@ fn parse_hash(s: &str) -> ContentHash {
}
fn handle_write(args: &WriteArgs) {
let mut store = Store::sqlite_from_path(args.db.clone()).unwrap_or_else(|e| {
let mut store = Store::sqlite_from_path(args.db.clone(), StoreParams::default()).unwrap_or_else(|e| {
eprintln!("Error opening store: {:?}", e);
process::exit(1);
});
@ -120,6 +124,8 @@ fn handle_write(args: &WriteArgs) {
});
}
trace!("Received JSON content: {}", content);
let value: serde_json::Value = serde_json::from_str(&content).unwrap_or_else(|e| {
eprintln!("Invalid JSON: {}", e);
process::exit(1);
@ -134,7 +140,14 @@ fn handle_write(args: &WriteArgs) {
}
fn handle_get(args: &GetArgs) {
let mut store = Store::sqlite_from_path(args.db.clone()).unwrap_or_else(|e| {
let mut store = Store::sqlite_from_path(
args.db.clone(),
StoreParams {
create_if_not_exists: false,
..Default::default()
},
)
.unwrap_or_else(|e| {
eprintln!("Error opening store: {:?}", e);
process::exit(1);
});
@ -160,7 +173,14 @@ fn handle_get(args: &GetArgs) {
}
fn handle_get_all(args: &GetAllArgs) {
let mut store = Store::sqlite_from_path(args.db.clone()).unwrap_or_else(|e| {
let mut store = Store::sqlite_from_path(
args.db.clone(),
StoreParams {
create_if_not_exists: false,
..Default::default()
},
)
.unwrap_or_else(|e| {
eprintln!("Error opening store: {:?}", e);
process::exit(1);
});
@ -180,7 +200,14 @@ fn handle_get_all(args: &GetAllArgs) {
}
fn handle_delete(args: &DeleteArgs) {
let mut store = Store::sqlite_from_path(args.db.clone()).unwrap_or_else(|e| {
let mut store = Store::sqlite_from_path(
args.db.clone(),
StoreParams {
create_if_not_exists: false,
..Default::default()
},
)
.unwrap_or_else(|e| {
eprintln!("Error opening store: {:?}", e);
process::exit(1);
});
@ -188,7 +215,14 @@ fn handle_delete(args: &DeleteArgs) {
}
fn handle_delete_all(args: &DeleteAllArgs) {
let mut store = Store::sqlite_from_path(args.db.clone()).unwrap_or_else(|e| {
let mut store = Store::sqlite_from_path(
args.db.clone(),
StoreParams {
create_if_not_exists: false,
..Default::default()
},
)
.unwrap_or_else(|e| {
eprintln!("Error opening store: {:?}", e);
process::exit(1);
});

View file

@ -58,10 +58,27 @@ impl Default for StoreParams {
impl Store {
/// Use an SQLite backend with a database file at the provided path.
// TODO: Params
pub fn sqlite_from_path(path: PathBuf) -> Result<Self> {
pub fn sqlite_from_path(path: PathBuf, params: StoreParams) -> Result<Self> {
use rusqlite::OpenFlags;
// Base flags for URI handling and disabling mutexes.
let mut flags = OpenFlags::SQLITE_OPEN_URI | OpenFlags::SQLITE_OPEN_NO_MUTEX;
// Readonly takes precedence over readwrite.
if params.read_only {
flags |= OpenFlags::SQLITE_OPEN_READ_ONLY;
} else {
flags |= OpenFlags::SQLITE_OPEN_READ_WRITE;
}
// Create the file if allowed.
if params.create_if_not_exists {
flags |= OpenFlags::SQLITE_OPEN_CREATE;
}
// Open the SQLite connection with the computed flags.
let connection = rusqlite::Connection::open_with_flags(path, flags)?;
Ok(Self {
backend: Box::new(Sqlite::new(path)?),
backend: Box::new(Sqlite { connection }),
})
}
@ -154,6 +171,7 @@ pub struct Sqlite {
}
impl Sqlite {
// TODO: Use this instead of directly constructing the connection in `Store`.
pub fn new(path: PathBuf) -> Result<Self> {
use rusqlite::OpenFlags;
// Remove the `SQLITE_OPEN_CREATE` flag because we do not want to create databases if they don't exist.

View file

@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use tempfile::TempDir;
use vanth::{Vanth, hash, store::Store};
use vanth::{Vanth, hash, store::{Store, StoreParams}};
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Vanth)]
struct Foo {
@ -17,7 +17,7 @@ struct Bar {
fn test_sqlite_store() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("test.db");
let mut store = Store::sqlite_from_path(path.clone()).unwrap();
let mut store = Store::sqlite_from_path(path.clone(), StoreParams::default()).unwrap();
let foo_1 = Foo { inner: 1 };
let foo_2 = Foo { inner: 2 };