aboutsummaryrefslogtreecommitdiffstats
path: root/crates/atuin/src/command/client/kv.rs
blob: b4db9c177ac3a5d6c57d51140bb0140e4e5c8d2d (plain) (blame)
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
112
113
114
115
116
117
118
119
120
121
122
use clap::Subcommand;
use eyre::{Context, Result, eyre};

use atuin_client::{encryption, record::sqlite_store::SqliteStore, settings::Settings};
use atuin_kv::store::KvStore;

#[derive(Subcommand, Debug)]
#[command(infer_subcommands = true)]
pub enum Cmd {
    /// Set a key-value pair
    Set {
        /// Key to set
        #[arg(long, short)]
        key: String,

        /// Value to store
        value: String,

        /// Namespace for the key-value pair
        #[arg(long, short, default_value = "default")]
        namespace: String,
    },

    /// Delete one or more key-value pairs
    #[command(alias = "rm")]
    Delete {
        /// Keys to delete
        #[arg(required = true)]
        keys: Vec<String>,

        /// Namespace for the key-value pair
        #[arg(long, short, default_value = "default")]
        namespace: String,
    },

    /// Retrieve a saved value
    Get {
        /// Key to retrieve
        key: String,

        /// Namespace for the key-value pair
        #[arg(long, short, default_value = "default")]
        namespace: String,
    },

    /// List all keys in a namespace, or in all namespaces
    #[command(alias = "ls")]
    List {
        /// Namespace to list keys from
        #[arg(long, short, default_value = "default")]
        namespace: String,

        /// List all keys in all namespaces
        #[arg(long, short, alias = "all")]
        all_namespaces: bool,
    },

    /// Rebuild the KV store
    Rebuild,
}

impl Cmd {
    pub async fn run(&self, settings: &Settings, store: &SqliteStore) -> Result<()> {
        let encryption_key: [u8; 32] = encryption::load_key(settings)
            .context("could not load encryption key")?
            .into();

        let host_id = Settings::host_id().expect("failed to get host_id");

        let kv_db = atuin_kv::database::Database::new(settings.kv.db_path.clone(), 1.0).await?;
        let kv_store = KvStore::new(store.clone(), kv_db, host_id, encryption_key);

        match self {
            Self::Set {
                key,
                value,
                namespace,
            } => {
                if namespace.is_empty() {
                    return Err(eyre!("namespace cannot be empty"));
                }

                kv_store.set(namespace, key, value).await
            }

            Self::Delete { keys, namespace } => kv_store.delete(namespace, keys).await,

            Self::Get { key, namespace } => {
                let kv = kv_store.get(namespace, key).await?;

                if let Some(val) = kv {
                    println!("{val}");
                }

                Ok(())
            }

            Self::List {
                namespace,
                all_namespaces,
            } => {
                let entries = if *all_namespaces {
                    kv_store.list(None).await?
                } else {
                    kv_store.list(Some(namespace)).await?
                };

                for entry in entries {
                    if *all_namespaces {
                        println!("{}.{}", entry.namespace, entry.key);
                    } else {
                        println!("{}", entry.key);
                    }
                }

                Ok(())
            }

            Self::Rebuild {} => kv_store.build().await,
        }
    }
}