crypto: Implement the key/value store for the sqlite store.
parent
41529a6bff
commit
af4b00195b
|
@ -172,8 +172,9 @@ impl CryptoStore for MemoryStore {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn remove_value(&self, key: &str) -> Result<Option<String>> {
|
async fn remove_value(&self, key: &str) -> Result<()> {
|
||||||
Ok(self.values.remove(key).map(|(_, v)| v))
|
self.values.remove(key);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_value(&self, key: &str) -> Result<Option<String>> {
|
async fn get_value(&self, key: &str) -> Result<Option<String>> {
|
||||||
|
|
|
@ -300,7 +300,7 @@ pub trait CryptoStore: Debug {
|
||||||
async fn save_value(&self, key: String, value: String) -> Result<()>;
|
async fn save_value(&self, key: String, value: String) -> Result<()>;
|
||||||
|
|
||||||
/// Remove a value from the store.
|
/// Remove a value from the store.
|
||||||
async fn remove_value(&self, key: &str) -> Result<Option<String>>;
|
async fn remove_value(&self, key: &str) -> Result<()>;
|
||||||
|
|
||||||
/// Load a serializeable object from the store.
|
/// Load a serializeable object from the store.
|
||||||
async fn get_value(&self, key: &str) -> Result<Option<String>>;
|
async fn get_value(&self, key: &str) -> Result<Option<String>>;
|
||||||
|
|
|
@ -442,6 +442,24 @@ impl SqliteStore {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
connection
|
||||||
|
.execute(
|
||||||
|
r#"
|
||||||
|
CREATE TABLE IF NOT EXISTS key_value (
|
||||||
|
"id" INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
"account_id" INTEGER NOT NULL,
|
||||||
|
"key" TEXT NOT NULL,
|
||||||
|
"value" TEXT NOT NULL,
|
||||||
|
FOREIGN KEY ("account_id") REFERENCES "accounts" ("id")
|
||||||
|
ON DELETE CASCADE
|
||||||
|
UNIQUE(account_id,key)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS "key_values_index" ON "key_value" ("account_id");
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1372,16 +1390,49 @@ impl CryptoStore for SqliteStore {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn save_value(&self, _key: String, _value: String) -> Result<()> {
|
async fn save_value(&self, key: String, value: String) -> Result<()> {
|
||||||
todo!()
|
let account_id = self.account_id().ok_or(CryptoStoreError::AccountUnset)?;
|
||||||
|
let mut connection = self.connection.lock().await;
|
||||||
|
|
||||||
|
query("REPLACE INTO key_value (account_id, key, value) VALUES (?1, ?2, ?3)")
|
||||||
|
.bind(account_id)
|
||||||
|
.bind(&key)
|
||||||
|
.bind(&value)
|
||||||
|
.execute(&mut *connection)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn remove_value(&self, _key: &str) -> Result<Option<String>> {
|
async fn remove_value(&self, key: &str) -> Result<()> {
|
||||||
todo!()
|
let account_id = self.account_id().ok_or(CryptoStoreError::AccountUnset)?;
|
||||||
|
let mut connection = self.connection.lock().await;
|
||||||
|
|
||||||
|
query(
|
||||||
|
"DELETE FROM key_value
|
||||||
|
WHERE account_id = ?1 and key = ?2
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.bind(account_id)
|
||||||
|
.bind(key)
|
||||||
|
.execute(&mut *connection)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_value(&self, _key: &str) -> Result<Option<String>> {
|
async fn get_value(&self, key: &str) -> Result<Option<String>> {
|
||||||
todo!()
|
let account_id = self.account_id().ok_or(CryptoStoreError::AccountUnset)?;
|
||||||
|
let mut connection = self.connection.lock().await;
|
||||||
|
|
||||||
|
let row: Option<(String,)> =
|
||||||
|
query_as("SELECT value FROM key_value WHERE account_id = ? and key = ?")
|
||||||
|
.bind(account_id)
|
||||||
|
.bind(key)
|
||||||
|
.fetch_optional(&mut *connection)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(row.map(|r| r.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1881,4 +1932,19 @@ mod test {
|
||||||
let loaded_user = store.load_user(&user_id).await.unwrap().unwrap();
|
let loaded_user = store.load_user(&user_id).await.unwrap().unwrap();
|
||||||
assert!(loaded_user.own().unwrap().is_verified())
|
assert!(loaded_user.own().unwrap().is_verified())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn key_value_saving() {
|
||||||
|
let (_, store, _dir) = get_loaded_store().await;
|
||||||
|
let key = "test_key".to_string();
|
||||||
|
let value = "secret value".to_string();
|
||||||
|
|
||||||
|
store.save_value(key.clone(), value.clone()).await.unwrap();
|
||||||
|
let stored_value = store.get_value(&key).await.unwrap().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(value, stored_value);
|
||||||
|
|
||||||
|
store.remove_value(&key).await.unwrap();
|
||||||
|
assert!(store.get_value(&key).await.unwrap().is_none());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue