use prollytree::git::versioned_store::GitNamespacedKvStore;
use std::process::Command;
use tempfile::TempDir;
fn init_git_repo(repo_path: &std::path::Path) -> Result<(), Box<dyn std::error::Error>> {
Command::new("git")
.args(["init"])
.current_dir(repo_path)
.output()?;
Command::new("git")
.args(["config", "user.name", "Namespaced Demo"])
.current_dir(repo_path)
.output()?;
Command::new("git")
.args(["config", "user.email", "demo@example.com"])
.current_dir(repo_path)
.output()?;
Ok(())
}
fn demo_multiple_namespaces() -> Result<(), Box<dyn std::error::Error>> {
println!("\nDemo 1: Two namespaces, one store, one commit");
println!("============================================================");
let temp = TempDir::new()?;
init_git_repo(temp.path())?;
let dataset = temp.path().join("dataset");
std::fs::create_dir_all(&dataset)?;
let mut store = GitNamespacedKvStore::<32>::init(&dataset)?;
{
let mut users = store.namespace("users");
users.insert(b"u:alice".to_vec(), b"Alice <alice@example.com>".to_vec())?;
users.insert(b"u:bob".to_vec(), b"Bob <bob@example.com>".to_vec())?;
}
{
let mut settings = store.namespace("settings");
settings.insert(b"theme".to_vec(), b"dark".to_vec())?;
settings.insert(b"locale".to_vec(), b"en_US".to_vec())?;
}
let commit_id = store.commit("seed users + settings")?;
println!(
"Single commit covering both namespaces: {}",
&commit_id.to_string()[..10]
);
println!("Namespaces in store: {:?}", store.list_namespaces());
println!(
"users/u:alice = {:?}",
store
.namespace("users")
.get(b"u:alice")
.map(|v| String::from_utf8_lossy(&v).into_owned())
);
println!(
"settings/theme = {:?}",
store
.namespace("settings")
.get(b"theme")
.map(|v| String::from_utf8_lossy(&v).into_owned())
);
Ok(())
}
fn demo_branching_per_namespace() -> Result<(), Box<dyn std::error::Error>> {
println!("\nDemo 2: Branching is store-wide; both namespaces follow");
println!("============================================================");
let temp = TempDir::new()?;
init_git_repo(temp.path())?;
let dataset = temp.path().join("dataset");
std::fs::create_dir_all(&dataset)?;
let mut store = GitNamespacedKvStore::<32>::init(&dataset)?;
{
let mut users = store.namespace("users");
users.insert(b"u:alice".to_vec(), b"Alice".to_vec())?;
}
{
let mut settings = store.namespace("settings");
settings.insert(b"theme".to_vec(), b"dark".to_vec())?;
}
store.commit("seed on main")?;
println!(
"main branch seeded; current branch = {}",
store.current_branch()
);
store.create_branch("experiment")?;
{
let mut users = store.namespace("users");
users.insert(b"u:carol".to_vec(), b"Carol".to_vec())?;
}
{
let mut settings = store.namespace("settings");
settings.insert(b"theme".to_vec(), b"light".to_vec())?;
}
store.commit("experiment: add carol, switch to light")?;
println!(
"experiment branch: users = {:?}",
store.namespace("users").list_keys()
);
println!(
"experiment branch: theme = {:?}",
store
.namespace("settings")
.get(b"theme")
.map(|v| String::from_utf8_lossy(&v).into_owned())
);
store.checkout("main")?;
println!(
"\nback on main; users = {:?}",
store.namespace("users").list_keys()
);
println!(
"main branch theme = {:?}",
store
.namespace("settings")
.get(b"theme")
.map(|v| String::from_utf8_lossy(&v).into_owned())
);
println!(
"main does NOT see u:carol = {:?}",
store.namespace("users").get(b"u:carol")
);
Ok(())
}
fn demo_isolation_between_namespaces() -> Result<(), Box<dyn std::error::Error>> {
println!("\nDemo 3: Namespaces are fully isolated");
println!("============================================================");
let temp = TempDir::new()?;
init_git_repo(temp.path())?;
let dataset = temp.path().join("dataset");
std::fs::create_dir_all(&dataset)?;
let mut store = GitNamespacedKvStore::<32>::init(&dataset)?;
{
store
.namespace("users")
.insert(b"name".to_vec(), b"Alice".to_vec())?;
store
.namespace("products")
.insert(b"name".to_vec(), b"Widget".to_vec())?;
}
store.commit("collision-free across namespaces")?;
println!(
"users/name = {:?}",
store
.namespace("users")
.get(b"name")
.map(|v| String::from_utf8_lossy(&v).into_owned())
);
println!(
"products/name = {:?}",
store
.namespace("products")
.get(b"name")
.map(|v| String::from_utf8_lossy(&v).into_owned())
);
println!("Each namespace owns its own key space — no collision.");
Ok(())
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("NamespacedKvStore example");
println!("============================================================");
println!("Multiple isolated prolly trees in one git-versioned store.");
demo_multiple_namespaces()?;
demo_branching_per_namespace()?;
demo_isolation_between_namespaces()?;
println!("\nAll demos completed successfully.");
println!("\nKey takeaways:");
println!("- One NamespacedKvStore holds many independent prolly trees.");
println!("- store.namespace(name) returns a per-namespace handle.");
println!("- A single commit() lands every dirty namespace atomically.");
println!("- create_branch + checkout flip every namespace at once.");
println!("- For text search on a namespace, see the `text_index` example.");
Ok(())
}