mirror of
https://github.com/atuinsh/atuin.git
synced 2025-01-26 00:00:40 +01:00
Add fuzzy text search mode (#142)
This commit is contained in:
parent
f0130571a6
commit
0b9dc6696b
35
Cargo.lock
generated
35
Cargo.lock
generated
@ -37,6 +37,27 @@ version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||
|
||||
[[package]]
|
||||
name = "async-stream"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625"
|
||||
dependencies = [
|
||||
"async-stream-impl",
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream-impl"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.50"
|
||||
@ -129,6 +150,7 @@ dependencies = [
|
||||
"sodiumoxide",
|
||||
"sqlx",
|
||||
"tokio",
|
||||
"tokio-test",
|
||||
"urlencoding",
|
||||
"uuid",
|
||||
"whoami",
|
||||
@ -2323,6 +2345,19 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-test"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53474327ae5e166530d17f2d956afcb4f8a004de581b3cae10f12006bc8163e3"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-tungstenite"
|
||||
version = "0.13.0"
|
||||
|
@ -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 = "*"
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -96,8 +96,8 @@ key = "~/.atuin-session"
|
||||
|
||||
### `search_mode`
|
||||
|
||||
Which search mode to use. Atuin supports both "prefix" and full text search
|
||||
modes. The former will essentially search for "query*", and the latter "*query\*"
|
||||
Which search mode to use. Atuin supports "prefix", full text and "fuzzy" search
|
||||
modes. The prefix search for "query\*", fulltext "\*query\*", and fuzzy "\*q\*u\*e\*r\*y\*"
|
||||
|
||||
Defaults to "prefix"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user