From 0ea86b8d5489e5e9a90fc285c15bd39ca9a350e4 Mon Sep 17 00:00:00 2001 From: ProofOfConcept Date: Sat, 28 Feb 2026 23:49:43 -0500 Subject: [PATCH] refactor: extract Store methods, clean up shell-outs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Store::upsert() — generic create-or-update, used by cmd_write - Add Store::insert_node() — for pre-constructed nodes (journal entries) - Add Store::delete_node() — soft-delete with version bump - Simplify cmd_write (20 → 8 lines), cmd_node_delete (16 → 7 lines), cmd_journal_write (removes manual append/insert/save boilerplate) - Replace generate_cookie shell-out to head/urandom with direct /dev/urandom read + const alphabet table main.rs: 1137 → 1109 lines. --- src/bin/memory-search.rs | 17 ++++-------- src/capnp_store.rs | 42 +++++++++++++++++++++++++++++ src/main.rs | 58 +++++++++++----------------------------- 3 files changed, 62 insertions(+), 55 deletions(-) diff --git a/src/bin/memory-search.rs b/src/bin/memory-search.rs index cf41804..88ab07c 100644 --- a/src/bin/memory-search.rs +++ b/src/bin/memory-search.rs @@ -150,19 +150,12 @@ fn load_or_create_cookie(dir: &Path, session_id: &str) -> String { } fn generate_cookie() -> String { - let out = Command::new("head") - .args(["-c", "12", "/dev/urandom"]) - .output() + const ALPHA: &[u8] = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let mut buf = [0u8; 16]; + fs::File::open("/dev/urandom") + .and_then(|mut f| io::Read::read_exact(&mut f, &mut buf)) .expect("failed to read urandom"); - out.stdout.iter() - .map(|b| { - let idx = (*b as usize) % 62; - if idx < 10 { (b'0' + idx as u8) as char } - else if idx < 36 { (b'a' + (idx - 10) as u8) as char } - else { (b'A' + (idx - 36) as u8) as char } - }) - .take(16) - .collect() + buf.iter().map(|b| ALPHA[(*b as usize) % ALPHA.len()] as char).collect() } fn load_seen(dir: &Path, session_id: &str) -> HashSet { diff --git a/src/capnp_store.rs b/src/capnp_store.rs index 360cbc2..8578f10 100644 --- a/src/capnp_store.rs +++ b/src/capnp_store.rs @@ -491,6 +491,48 @@ impl Store { Ok(()) } + /// Upsert a node: update if exists (and content changed), create if not. + /// Returns: "created", "updated", or "unchanged". + pub fn upsert(&mut self, key: &str, content: &str) -> Result<&'static str, String> { + if let Some(existing) = self.nodes.get(key) { + if existing.content == content { + return Ok("unchanged"); + } + let mut node = existing.clone(); + node.content = content.to_string(); + node.version += 1; + self.append_nodes(std::slice::from_ref(&node))?; + self.nodes.insert(key.to_string(), node); + Ok("updated") + } else { + let node = Store::new_node(key, content); + self.append_nodes(std::slice::from_ref(&node))?; + self.uuid_to_key.insert(node.uuid, node.key.clone()); + self.nodes.insert(key.to_string(), node); + Ok("created") + } + } + + /// Soft-delete a node (appends deleted version, removes from cache). + pub fn delete_node(&mut self, key: &str) -> Result<(), String> { + let node = self.nodes.get(key) + .ok_or_else(|| format!("No node '{}'", key))?; + let mut deleted = node.clone(); + deleted.deleted = true; + deleted.version += 1; + self.append_nodes(std::slice::from_ref(&deleted))?; + self.nodes.remove(key); + Ok(()) + } + + /// Insert a fully constructed node (for journal entries, imports, etc.) + pub fn insert_node(&mut self, node: Node) -> Result<(), String> { + self.append_nodes(std::slice::from_ref(&node))?; + self.uuid_to_key.insert(node.uuid, node.key.clone()); + self.nodes.insert(node.key.clone(), node); + Ok(()) + } + /// Create a new node with defaults pub fn new_node(key: &str, content: &str) -> Node { Node { diff --git a/src/main.rs b/src/main.rs index ffbc3af..4ab6a87 100644 --- a/src/main.rs +++ b/src/main.rs @@ -793,24 +793,10 @@ fn cmd_node_delete(args: &[String]) -> Result<(), String> { let key = args.join(" "); let mut store = capnp_store::Store::load()?; let resolved = store.resolve_key(&key)?; - - let updated = if let Some(node) = store.nodes.get_mut(&resolved) { - node.deleted = true; - node.version += 1; - Some(node.clone()) - } else { - None - }; - - if let Some(node) = updated { - store.append_nodes(&[node])?; - store.nodes.remove(&resolved); - store.save()?; - println!("Deleted '{}'", resolved); - Ok(()) - } else { - Err(format!("No node '{}'", resolved)) - } + store.delete_node(&resolved)?; + store.save()?; + println!("Deleted '{}'", resolved); + Ok(()) } fn cmd_load_context() -> Result<(), String> { @@ -923,27 +909,15 @@ fn cmd_write(args: &[String]) -> Result<(), String> { } let mut store = capnp_store::Store::load()?; - - if let Some(existing) = store.nodes.get(&key) { - if existing.content == content { - println!("No change: '{}'", key); - return Ok(()); - } - let mut node = existing.clone(); - node.content = content; - node.version += 1; - store.append_nodes(std::slice::from_ref(&node))?; - store.nodes.insert(key.clone(), node); - println!("Updated '{}' (v{})", key, store.nodes[&key].version); - } else { - let node = capnp_store::Store::new_node(&key, &content); - store.append_nodes(std::slice::from_ref(&node))?; - store.uuid_to_key.insert(node.uuid, node.key.clone()); - store.nodes.insert(key.clone(), node); - println!("Created '{}'", key); + let result = store.upsert(&key, &content)?; + match result { + "unchanged" => println!("No change: '{}'", key), + "updated" => println!("Updated '{}' (v{})", key, store.nodes[&key].version), + _ => println!("Created '{}'", key), + } + if result != "unchanged" { + store.save()?; } - - store.save()?; Ok(()) } @@ -1055,13 +1029,11 @@ fn cmd_journal_write(args: &[String]) -> Result<(), String> { let mut node = capnp_store::Store::new_node(&key, &content); node.node_type = capnp_store::NodeType::EpisodicSession; node.provenance = capnp_store::Provenance::Journal; - if let Some(ref src) = source_ref { - node.source_ref = src.clone(); + if let Some(src) = source_ref { + node.source_ref = src; } - store.append_nodes(&[node.clone()])?; - store.uuid_to_key.insert(node.uuid, node.key.clone()); - store.nodes.insert(key.clone(), node); + store.insert_node(node)?; store.save()?; let word_count = text.split_whitespace().count();