summaryrefslogtreecommitdiffstats
path: root/atuin-client
diff options
context:
space:
mode:
Diffstat (limited to 'atuin-client')
-rw-r--r--atuin-client/Cargo.toml3
-rw-r--r--atuin-client/config.toml2
-rw-r--r--atuin-client/src/database.rs88
-rw-r--r--atuin-client/src/settings.rs3
4 files changed, 95 insertions, 1 deletions
diff --git a/atuin-client/Cargo.toml b/atuin-client/Cargo.toml
index 09bccaa0..b4c9c13e 100644
--- a/atuin-client/Cargo.toml
+++ b/atuin-client/Cargo.toml
@@ -40,3 +40,6 @@ humantime = "2.1.0"
itertools = "0.10.0"
shellexpand = "2"
sqlx = { version = "0.5", features = [ "runtime-tokio-rustls", "uuid", "chrono", "sqlite" ] }
+
+[dev-dependencies]
+tokio-test = "*"
diff --git a/atuin-client/config.toml b/atuin-client/config.toml
index c8926297..bfb51149 100644
--- a/atuin-client/config.toml
+++ b/atuin-client/config.toml
@@ -24,5 +24,5 @@
# sync_address = "https://api.atuin.sh"
## which search mode to use
-## possible values: prefix, fulltext
+## possible values: prefix, fulltext, fuzzy
# search_mode = "prefix"
diff --git a/atuin-client/src/database.rs b/atuin-client/src/database.rs
index 160c6054..6a70ae33 100644
--- a/atuin-client/src/database.rs
+++ b/atuin-client/src/database.rs
@@ -6,6 +6,7 @@ use chrono::prelude::*;
use chrono::Utc;
use eyre::Result;
+use itertools::Itertools;
use sqlx::sqlite::{
SqliteConnectOptions, SqliteJournalMode, SqlitePool, SqlitePoolOptions, SqliteRow,
@@ -286,6 +287,7 @@ impl Database for Sqlite {
let query = match search_mode {
SearchMode::Prefix => query,
SearchMode::FullText => format!("%{}", query),
+ SearchMode::Fuzzy => query.split("").join("%"),
};
let res = sqlx::query(
@@ -318,3 +320,89 @@ impl Database for Sqlite {
Ok(res)
}
}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ async fn new_history_item(db: &mut impl Database, cmd: &str) -> Result<()> {
+ let history = History::new(
+ chrono::Utc::now(),
+ cmd.to_string(),
+ "/home/ellie".to_string(),
+ 0,
+ 1,
+ Some("beep boop".to_string()),
+ Some("booop".to_string()),
+ );
+ return db.save(&history).await;
+ }
+
+ #[tokio::test(flavor = "multi_thread")]
+ async fn test_search_prefix() {
+ let mut db = Sqlite::new("sqlite::memory:").await.unwrap();
+ new_history_item(&mut db, "ls /home/ellie").await.unwrap();
+
+ let mut results = db.search(None, SearchMode::Prefix, "ls").await.unwrap();
+ assert_eq!(results.len(), 1);
+
+ results = db.search(None, SearchMode::Prefix, "/home").await.unwrap();
+ assert_eq!(results.len(), 0);
+
+ results = db.search(None, SearchMode::Prefix, "ls ").await.unwrap();
+ assert_eq!(results.len(), 0);
+ }
+
+ #[tokio::test(flavor = "multi_thread")]
+ async fn test_search_fulltext() {
+ let mut db = Sqlite::new("sqlite::memory:").await.unwrap();
+ new_history_item(&mut db, "ls /home/ellie").await.unwrap();
+
+ let mut results = db.search(None, SearchMode::FullText, "ls").await.unwrap();
+ assert_eq!(results.len(), 1);
+
+ results = db
+ .search(None, SearchMode::FullText, "/home")
+ .await
+ .unwrap();
+ assert_eq!(results.len(), 1);
+
+ results = db.search(None, SearchMode::FullText, "ls ").await.unwrap();
+ assert_eq!(results.len(), 0);
+ }
+
+ #[tokio::test(flavor = "multi_thread")]
+ async fn test_search_fuzzy() {
+ let mut db = Sqlite::new("sqlite::memory:").await.unwrap();
+ new_history_item(&mut db, "ls /home/ellie").await.unwrap();
+ new_history_item(&mut db, "ls /home/frank").await.unwrap();
+ new_history_item(&mut db, "cd /home/ellie").await.unwrap();
+ new_history_item(&mut db, "/home/ellie/.bin/rustup")
+ .await
+ .unwrap();
+
+ let mut results = db.search(None, SearchMode::Fuzzy, "ls /").await.unwrap();
+ assert_eq!(results.len(), 2);
+
+ results = db.search(None, SearchMode::Fuzzy, "l/h/").await.unwrap();
+ assert_eq!(results.len(), 2);
+
+ results = db.search(None, SearchMode::Fuzzy, "/h/e").await.unwrap();
+ assert_eq!(results.len(), 3);
+
+ results = db.search(None, SearchMode::Fuzzy, "/hmoe/").await.unwrap();
+ assert_eq!(results.len(), 0);
+
+ results = db
+ .search(None, SearchMode::Fuzzy, "ellie/home")
+ .await
+ .unwrap();
+ assert_eq!(results.len(), 0);
+
+ results = db.search(None, SearchMode::Fuzzy, "lsellie").await.unwrap();
+ assert_eq!(results.len(), 1);
+
+ results = db.search(None, SearchMode::Fuzzy, " ").await.unwrap();
+ assert_eq!(results.len(), 3);
+ }
+}
diff --git a/atuin-client/src/settings.rs b/atuin-client/src/settings.rs
index 1d7e9a5f..0cb845c3 100644
--- a/atuin-client/src/settings.rs
+++ b/atuin-client/src/settings.rs
@@ -17,6 +17,9 @@ pub enum SearchMode {
#[serde(rename = "fulltext")]
FullText,
+
+ #[serde(rename = "fuzzy")]
+ Fuzzy,
}
// FIXME: Can use upstream Dialect enum if https://github.com/stevedonovan/chrono-english/pull/16 is merged