mirror of
https://github.com/atuinsh/atuin.git
synced 2025-01-25 15:50:22 +01:00
104 lines
2.6 KiB
Rust
104 lines
2.6 KiB
Rust
|
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)
|
||
|
}
|
||
|
}
|