diff options
Diffstat (limited to 'atuin-client/src/kv.rs')
| -rw-r--r-- | atuin-client/src/kv.rs | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/atuin-client/src/kv.rs b/atuin-client/src/kv.rs new file mode 100644 index 00000000..87149275 --- /dev/null +++ b/atuin-client/src/kv.rs @@ -0,0 +1,103 @@ +use eyre::Result; +use serde::{Deserialize, Serialize}; + +use crate::record::store::Store; +use crate::settings::Settings; + +const KV_VERSION: &str = "v0"; +const KV_TAG: &str = "kv"; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct KvRecord { + pub key: String, + pub value: String, +} + +impl KvRecord { + pub fn serialize(&self) -> Result<Vec<u8>> { + let buf = rmp_serde::to_vec(self)?; + + Ok(buf) + } +} + +pub struct KvStore; + +impl Default for KvStore { + fn default() -> Self { + Self::new() + } +} + +impl KvStore { + // will want to init the actual kv store when that is done + pub fn new() -> KvStore { + KvStore {} + } + + pub async fn set( + &self, + store: &mut (impl Store + Send + Sync), + key: &str, + value: &str, + ) -> Result<()> { + let host_id = Settings::host_id().expect("failed to get host_id"); + + let record = KvRecord { + key: key.to_string(), + value: value.to_string(), + }; + + let bytes = record.serialize()?; + + let parent = store + .last(host_id.as_str(), KV_TAG) + .await? + .map(|entry| entry.id); + + let record = atuin_common::record::Record::builder() + .host(host_id) + .version(KV_VERSION.to_string()) + .tag(KV_TAG.to_string()) + .parent(parent) + .data(bytes) + .build(); + + store.push(&record).await?; + + Ok(()) + } + + // TODO: setup an actual kv store, rebuild func, and do not pass the main store in here as + // well. + pub async fn get(&self, store: &impl Store, key: &str) -> Result<Option<KvRecord>> { + // TODO: don't load this from disk so much + let host_id = Settings::host_id().expect("failed to get host_id"); + + // Currently, this is O(n). When we have an actual KV store, it can be better + // Just a poc for now! + + // iterate records to find the value we want + // start at the end, so we get the most recent version + let Some(mut record) = store.last(host_id.as_str(), KV_TAG).await? else { + return Ok(None); + }; + let kv: KvRecord = rmp_serde::from_slice(&record.data)?; + + if kv.key == key { + return Ok(Some(kv)); + } + + while let Some(parent) = record.parent { + record = store.get(parent.as_str()).await?; + let kv: KvRecord = rmp_serde::from_slice(&record.data)?; + + if kv.key == key { + return Ok(Some(kv)); + } + } + + // if we get here, then... we didn't find the record with that key :( + Ok(None) + } +} |
