use geth_types::{DbId, ResourceId}; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct DbResource { pub id: DbId, pub resource: ResourceId, pub name: String, pub path: String, pub path_exists: bool, pub size_bytes: Option, pub schema_metadata: String, pub sync_status: String, } #[derive(Debug, thiserror::Error)] pub enum DbError { #[error("invalid db resource name: {0}")] InvalidName(String), } pub fn validate_db_name(name: &str) -> Result<(), DbError> { if name.is_empty() || !name .bytes() .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b'-')) { return Err(DbError::InvalidName(name.to_owned())); } Ok(()) } #[must_use] pub fn crsqlite_sync_roadmap() -> &'static str { "future db sync reads crsql_changes, exchanges changes over Iroh, and applies through crsql_changes" } #[cfg(test)] mod tests { use super::*; #[test] fn db_name_validation_rejects_paths_and_empty_names() { assert!(validate_db_name("notes").is_ok()); assert!(validate_db_name("notes.v1").is_ok()); assert!(validate_db_name("").is_err()); assert!(validate_db_name("../notes").is_err()); assert!(validate_db_name("notes/main").is_err()); assert!(validate_db_name("notes main").is_err()); } }