1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
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 namespace: String,
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),
namespace: &str,
key: &str,
value: &str,
) -> Result<()> {
let host_id = Settings::host_id().expect("failed to get host_id");
let record = KvRecord {
namespace: namespace.to_string(),
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,
namespace: &str,
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 && kv.namespace == namespace {
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 && kv.namespace == namespace {
return Ok(Some(kv));
}
}
// if we get here, then... we didn't find the record with that key :(
Ok(None)
}
}
|