diff options
| author | Ellie Huxtable <ellie@elliehuxtable.com> | 2023-06-14 21:18:24 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-06-14 21:18:24 +0100 |
| commit | ae1709dafd22ac3c64441472e90df8799253292e (patch) | |
| tree | 88d1cb17af6af9948d44ffb7242d69be5743785d /atuin-client/src/kv.rs | |
| parent | Bump debian from bullseye-20230502-slim to bullseye-20230612-slim (#1047) (diff) | |
| download | atuin-ae1709dafd22ac3c64441472e90df8799253292e.zip | |
Key values (#1038)
* wip
* Start testing
* Store host IDs, not hostnames
Why? Hostnames can change a lot, and therefore host filtering can be
funky. Really, all we want is a unique ID per machine + do not care what
it might be.
* Mostly just write a fuckload of tests
* Add a v0 kv store I can push to
* Appending works
* Add next() and iterate, test the pointer chain
* Fix sig
* Make clippy happy and thaw the ICE
* Fix tests'
* Fix tests
* typed builder and cleaner db trait
---------
Co-authored-by: Conrad Ludgate <conrad.ludgate@truelayer.com>
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) + } +} |
