mirror of
https://github.com/atuinsh/atuin.git
synced 2024-12-28 18:09:25 +01:00
Fix a bunch of tests, remove Option<Uuid>
This commit is contained in:
parent
1774ec93eb
commit
f05fe5bd83
@ -8,11 +8,14 @@ use reqwest::{
|
||||
StatusCode, Url,
|
||||
};
|
||||
|
||||
use atuin_common::api::{
|
||||
AddHistoryRequest, CountResponse, DeleteHistoryRequest, ErrorResponse, IndexResponse,
|
||||
LoginRequest, LoginResponse, RegisterResponse, StatusResponse, SyncHistoryResponse,
|
||||
};
|
||||
use atuin_common::record::Record;
|
||||
use atuin_common::{
|
||||
api::{
|
||||
AddHistoryRequest, CountResponse, DeleteHistoryRequest, ErrorResponse, IndexResponse,
|
||||
LoginRequest, LoginResponse, RegisterResponse, StatusResponse, SyncHistoryResponse,
|
||||
},
|
||||
record::RecordIndex,
|
||||
};
|
||||
use semver::Version;
|
||||
|
||||
use crate::{history::History, sync::hash_str};
|
||||
@ -205,6 +208,16 @@ impl<'a> Client<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn record_index(&self) -> Result<RecordIndex> {
|
||||
let url = format!("{}/record", self.sync_addr);
|
||||
let url = Url::parse(url.as_str())?;
|
||||
|
||||
let resp = self.client.get(url).send().await?;
|
||||
let index = resp.json().await?;
|
||||
|
||||
Ok(index)
|
||||
}
|
||||
|
||||
pub async fn delete(&self) -> Result<()> {
|
||||
let url = format!("{}/account", self.sync_addr);
|
||||
let url = Url::parse(url.as_str())?;
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub mod encryption;
|
||||
pub mod sqlite_store;
|
||||
pub mod store;
|
||||
pub mod sync;
|
||||
|
@ -83,7 +83,7 @@ impl SqliteStore {
|
||||
// tbh at this point things are pretty fucked so just panic
|
||||
let id = Uuid::from_str(row.get("id")).expect("invalid id UUID format in sqlite DB");
|
||||
let host = Uuid::from_str(row.get("host")).expect("invalid host UUID format in sqlite DB");
|
||||
let parent: Option<&str> = row.get("host");
|
||||
let parent: Option<&str> = row.get("parent");
|
||||
|
||||
let parent = if let Some(parent) = parent {
|
||||
Some(Uuid::from_str(parent).expect("invalid parent UUID format in sqlite DB"))
|
||||
@ -125,7 +125,7 @@ impl Store for SqliteStore {
|
||||
|
||||
async fn get(&self, id: Uuid) -> Result<Record<EncryptedData>> {
|
||||
let res = sqlx::query("select * from records where id = ?1")
|
||||
.bind(id)
|
||||
.bind(id.as_simple().to_string())
|
||||
.map(Self::query_row)
|
||||
.fetch_one(&self.pool)
|
||||
.await?;
|
||||
@ -136,7 +136,7 @@ impl Store for SqliteStore {
|
||||
async fn len(&self, host: Uuid, tag: &str) -> Result<u64> {
|
||||
let res: (i64,) =
|
||||
sqlx::query_as("select count(1) from records where host = ?1 and tag = ?2")
|
||||
.bind(host)
|
||||
.bind(host.as_simple().to_string())
|
||||
.bind(tag)
|
||||
.fetch_one(&self.pool)
|
||||
.await?;
|
||||
@ -146,7 +146,7 @@ impl Store for SqliteStore {
|
||||
|
||||
async fn next(&self, record: &Record<EncryptedData>) -> Result<Option<Record<EncryptedData>>> {
|
||||
let res = sqlx::query("select * from records where parent = ?1")
|
||||
.bind(record.id.clone())
|
||||
.bind(record.id.as_simple().to_string())
|
||||
.map(Self::query_row)
|
||||
.fetch_one(&self.pool)
|
||||
.await;
|
||||
@ -162,7 +162,7 @@ impl Store for SqliteStore {
|
||||
let res = sqlx::query(
|
||||
"select * from records where host = ?1 and tag = ?2 and parent is null limit 1",
|
||||
)
|
||||
.bind(host)
|
||||
.bind(host.as_simple().to_string())
|
||||
.bind(tag)
|
||||
.map(Self::query_row)
|
||||
.fetch_optional(&self.pool)
|
||||
@ -183,6 +183,23 @@ impl Store for SqliteStore {
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
async fn tail_records(&self) -> Result<Vec<(Uuid, String, Uuid)>> {
|
||||
let res = sqlx::query(
|
||||
"select host, tag, id from records rp where (select count(1) from records where parent=rp.id) = 0;",
|
||||
)
|
||||
.map(|row: SqliteRow| {
|
||||
let host: Uuid= Uuid::from_str(row.get("host")).expect("invalid uuid in db host");
|
||||
let tag: String= row.get("tag");
|
||||
let id: Uuid= Uuid::from_str(row.get("id")).expect("invalid uuid in db id");
|
||||
|
||||
(host, tag, id)
|
||||
})
|
||||
.fetch_all(&self.pool)
|
||||
.await?;
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -31,4 +31,6 @@ pub trait Store {
|
||||
async fn first(&self, host: Uuid, tag: &str) -> Result<Option<Record<EncryptedData>>>;
|
||||
/// Get the last record for a given host and tag
|
||||
async fn last(&self, host: Uuid, tag: &str) -> Result<Option<Record<EncryptedData>>>;
|
||||
|
||||
async fn tail_records(&self) -> Result<Vec<(Uuid, String, Uuid)>>;
|
||||
}
|
||||
|
25
atuin-client/src/record/sync.rs
Normal file
25
atuin-client/src/record/sync.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use atuin_common::record::RecordIndex;
|
||||
// do a sync :O
|
||||
use eyre::Result;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{api_client::Client, settings::Settings};
|
||||
|
||||
use super::store::Store;
|
||||
|
||||
pub async fn diff(
|
||||
settings: &Settings,
|
||||
store: &mut impl Store,
|
||||
) -> Result<Vec<(Uuid, String, Uuid)>> {
|
||||
let client = Client::new(&settings.sync_address, &settings.session_token)?;
|
||||
|
||||
// First, build our own index
|
||||
let local_tail = store.tail_records().await?;
|
||||
let local_index = RecordIndex::from(local_tail);
|
||||
|
||||
let remote_index = client.record_index().await?;
|
||||
|
||||
let diff = local_index.diff(&remote_index);
|
||||
|
||||
Ok(diff)
|
||||
}
|
@ -84,6 +84,17 @@ impl Default for RecordIndex {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<(Uuid, String, Uuid)>> for RecordIndex {
|
||||
fn from(f: Vec<(Uuid, String, Uuid)>) -> RecordIndex {
|
||||
let mut record_index = RecordIndex::new();
|
||||
|
||||
for row in f {
|
||||
record_index.set_raw(row.0, row.1, row.2);
|
||||
}
|
||||
record_index
|
||||
}
|
||||
}
|
||||
|
||||
impl RecordIndex {
|
||||
pub fn new() -> RecordIndex {
|
||||
RecordIndex {
|
||||
@ -114,7 +125,7 @@ impl RecordIndex {
|
||||
/// other machine has a different tail, it will be the differing tail. This is useful to
|
||||
/// check if the other index is ahead of us, or behind.
|
||||
/// If the other index does not have the (host, tag) pair, then the other value will be None.
|
||||
pub fn diff(&self, other: &Self) -> Vec<(Uuid, String, Option<Uuid>)> {
|
||||
pub fn diff(&self, other: &Self) -> Vec<(Uuid, String, Uuid)> {
|
||||
let mut ret = Vec::new();
|
||||
|
||||
// First, we check if other has everything that self has
|
||||
@ -125,10 +136,10 @@ impl RecordIndex {
|
||||
Some(t) if t.eq(tail) => continue,
|
||||
|
||||
// The other store does exist, but it is either ahead or behind us. A diff regardless
|
||||
Some(t) => ret.push((host.clone(), tag.clone(), Some(t))),
|
||||
Some(t) => ret.push((host.clone(), tag.clone(), t)),
|
||||
|
||||
// The other store does not exist :O
|
||||
None => ret.push((host.clone(), tag.clone(), None)),
|
||||
None => ret.push((host.clone(), tag.clone(), tail.clone())),
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -143,7 +154,7 @@ impl RecordIndex {
|
||||
// If we have this host/tag combo, the comparison and diff will have already happened above
|
||||
Some(_) => continue,
|
||||
|
||||
None => ret.push((host.clone(), tag.clone(), Some(tail.clone()))),
|
||||
None => ret.push((host.clone(), tag.clone(), tail.clone())),
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -311,7 +322,7 @@ mod tests {
|
||||
let diff = index1.diff(&index2);
|
||||
|
||||
assert_eq!(1, diff.len(), "expected single diff");
|
||||
assert_eq!(diff[0], (record2.host, record2.tag, Some(record2.id)));
|
||||
assert_eq!(diff[0], (record2.host, record2.tag, record2.id));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1,7 +1,12 @@
|
||||
use clap::Subcommand;
|
||||
use eyre::{Result, WrapErr};
|
||||
|
||||
use atuin_client::{api_client, database::Database, record::store::Store, settings::Settings};
|
||||
use atuin_client::{
|
||||
api_client,
|
||||
database::Database,
|
||||
record::{store::Store, sync},
|
||||
settings::Settings,
|
||||
};
|
||||
|
||||
mod status;
|
||||
|
||||
@ -73,11 +78,14 @@ async fn run(
|
||||
db: &mut impl Database,
|
||||
store: &mut impl Store,
|
||||
) -> Result<()> {
|
||||
let host = Settings::host_id().expect("No host ID found");
|
||||
// FOR TESTING ONLY!
|
||||
let kv_tail = store.last(host, "kv").await?.expect("no kv found");
|
||||
let client = api_client::Client::new(&settings.sync_address, &settings.session_token)?;
|
||||
client.post_records(&[kv_tail]).await?;
|
||||
let diff = sync::diff(settings, store).await?;
|
||||
println!("{:?}", diff);
|
||||
|
||||
atuin_client::sync::sync(settings, force, db).await?;
|
||||
println!(
|
||||
"Sync complete! {} items in database, force: {}",
|
||||
db.history_count().await?,
|
||||
force
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user