mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-09-11 12:25:42 +03:00
Refactor search result to include total count
This commit refactors the search result to include the total count of matches found, alongside the limited search results (page) for better pagination support. Changes made include: - Modified the return type from `Vec<SearchResult>` to `SearchResults` structure, to include a total count. - Updated the search function implementation to handle the new data structure. - Adapted the test cases to account for the updated search result format. In addition to the previous changes, this commit addresses the issue of not knowing the total number of search results when using pagination, which can now be easily obtained from the `SearchResults` structure.
This commit is contained in:
parent
d2fdecc752
commit
e4f1edfc83
@ -152,7 +152,7 @@ async fn search(
|
||||
offset: Option<usize>,
|
||||
timestamp_ms_gte: Option<u64>,
|
||||
timestamp_ms_lt: Option<u64>,
|
||||
) -> Result<Vec<search::SearchResult>, Error> {
|
||||
) -> Result<search::SearchResults, Error> {
|
||||
let app_state = handle.state::<App>();
|
||||
|
||||
let query = search::SearchQuery {
|
||||
|
@ -88,7 +88,7 @@ impl Deltas {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn search(&self, query: &SearchQuery) -> Result<Vec<SearchResult>> {
|
||||
pub fn search(&self, query: &SearchQuery) -> Result<SearchResults> {
|
||||
search(&self.index, &self.reader, query)
|
||||
}
|
||||
|
||||
@ -171,6 +171,13 @@ pub struct SearchResult {
|
||||
pub highlighted: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SearchResults {
|
||||
pub page: Vec<SearchResult>,
|
||||
pub total: usize,
|
||||
}
|
||||
|
||||
fn index_session(
|
||||
index: &tantivy::Index,
|
||||
writer: &mut IndexWriter,
|
||||
@ -292,7 +299,7 @@ pub fn search(
|
||||
index: &tantivy::Index,
|
||||
reader: &tantivy::IndexReader,
|
||||
q: &SearchQuery,
|
||||
) -> Result<Vec<SearchResult>> {
|
||||
) -> Result<SearchResults> {
|
||||
let query = tantivy::query::QueryParser::for_index(
|
||||
index,
|
||||
vec![
|
||||
@ -311,12 +318,13 @@ pub fn search(
|
||||
reader.reload()?;
|
||||
let searcher = reader.searcher();
|
||||
|
||||
let top_docs = searcher.search(
|
||||
&query,
|
||||
&collector::TopDocs::with_limit(q.limit)
|
||||
let mut collectors = collector::MultiCollector::new();
|
||||
let top_docs_handle = collectors.add_collector(
|
||||
collector::TopDocs::with_limit(q.limit)
|
||||
.and_offset(q.offset.unwrap_or(0))
|
||||
.order_by_u64_field(index.schema().get_field("timestamp_ms").unwrap()),
|
||||
)?;
|
||||
);
|
||||
let count_handle = collectors.add_collector(collector::Count);
|
||||
|
||||
let snippet_generator = tantivy::SnippetGenerator::create(
|
||||
&searcher,
|
||||
@ -324,7 +332,11 @@ pub fn search(
|
||||
index.schema().get_field("diff").unwrap(),
|
||||
)?;
|
||||
|
||||
let results = top_docs
|
||||
let mut result = searcher.search(&query, &collectors)?;
|
||||
let count = count_handle.extract(&mut result);
|
||||
let top_docs = top_docs_handle.extract(&mut result);
|
||||
|
||||
let page = top_docs
|
||||
.iter()
|
||||
.map(|(_score, doc_address)| {
|
||||
let retrieved_doc = searcher.doc(*doc_address)?;
|
||||
@ -366,5 +378,5 @@ pub fn search(
|
||||
})
|
||||
.collect::<Result<Vec<SearchResult>>>()?;
|
||||
|
||||
Ok(results)
|
||||
Ok(SearchResults { page, total: count })
|
||||
}
|
||||
|
@ -68,8 +68,8 @@ fn test_filter_by_timestamp() {
|
||||
});
|
||||
assert!(search_result_from.is_ok());
|
||||
let search_result_from = search_result_from.unwrap();
|
||||
assert_eq!(search_result_from.len(), 1);
|
||||
assert_eq!(search_result_from[0].index, 2);
|
||||
assert_eq!(search_result_from.total, 1);
|
||||
assert_eq!(search_result_from.page[0].index, 2);
|
||||
|
||||
let search_result_to = searcher.search(&super::SearchQuery {
|
||||
project_id: repository.project.id.clone(),
|
||||
@ -80,8 +80,8 @@ fn test_filter_by_timestamp() {
|
||||
});
|
||||
assert!(search_result_to.is_ok());
|
||||
let search_result_to = search_result_to.unwrap();
|
||||
assert_eq!(search_result_to.len(), 1);
|
||||
assert_eq!(search_result_to[0].index, 0);
|
||||
assert_eq!(search_result_to.total, 1);
|
||||
assert_eq!(search_result_to.page[0].index, 0);
|
||||
|
||||
let search_result_from_to = searcher.search(&super::SearchQuery {
|
||||
project_id: repository.project.id.clone(),
|
||||
@ -92,8 +92,8 @@ fn test_filter_by_timestamp() {
|
||||
});
|
||||
assert!(search_result_from_to.is_ok());
|
||||
let search_result_from_to = search_result_from_to.unwrap();
|
||||
assert_eq!(search_result_from_to.len(), 1);
|
||||
assert_eq!(search_result_from_to[0].index, 1);
|
||||
assert_eq!(search_result_from_to.total, 1);
|
||||
assert_eq!(search_result_from_to.page[0].index, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -135,9 +135,9 @@ fn test_sorted_by_timestamp() {
|
||||
assert!(search_result.is_ok());
|
||||
let search_result = search_result.unwrap();
|
||||
println!("{:?}", search_result);
|
||||
assert_eq!(search_result.len(), 2);
|
||||
assert_eq!(search_result[0].index, 1);
|
||||
assert_eq!(search_result[1].index, 0);
|
||||
assert_eq!(search_result.total, 2);
|
||||
assert_eq!(search_result.page[0].index, 1);
|
||||
assert_eq!(search_result.page[1].index, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -179,11 +179,11 @@ fn test_simple() {
|
||||
println!("{:?}", search_result1);
|
||||
assert!(search_result1.is_ok());
|
||||
let search_result1 = search_result1.unwrap();
|
||||
assert_eq!(search_result1.len(), 1);
|
||||
assert_eq!(search_result1[0].session_id, session.id);
|
||||
assert_eq!(search_result1[0].project_id, repository.project.id);
|
||||
assert_eq!(search_result1[0].file_path, "test.txt");
|
||||
assert_eq!(search_result1[0].index, 0);
|
||||
assert_eq!(search_result1.total, 1);
|
||||
assert_eq!(search_result1.page[0].session_id, session.id);
|
||||
assert_eq!(search_result1.page[0].project_id, repository.project.id);
|
||||
assert_eq!(search_result1.page[0].file_path, "test.txt");
|
||||
assert_eq!(search_result1.page[0].index, 0);
|
||||
|
||||
let search_result2 = searcher.search(&super::SearchQuery {
|
||||
project_id: repository.project.id.clone(),
|
||||
@ -193,7 +193,7 @@ fn test_simple() {
|
||||
range: Range { start: 0, end: 10 },
|
||||
});
|
||||
assert!(search_result2.is_ok());
|
||||
let search_result2 = search_result2.unwrap();
|
||||
let search_result2 = search_result2.unwrap().page;
|
||||
assert_eq!(search_result2.len(), 1);
|
||||
assert_eq!(search_result2[0].session_id, session.id);
|
||||
assert_eq!(search_result2[0].project_id, repository.project.id);
|
||||
@ -208,7 +208,7 @@ fn test_simple() {
|
||||
range: Range { start: 0, end: 10 },
|
||||
});
|
||||
assert!(search_result3.is_ok());
|
||||
let search_result3 = search_result3.unwrap();
|
||||
let search_result3 = search_result3.unwrap().page;
|
||||
assert_eq!(search_result3.len(), 2);
|
||||
assert_eq!(search_result3[0].project_id, repository.project.id);
|
||||
assert_eq!(search_result3[0].session_id, session.id);
|
||||
@ -225,7 +225,7 @@ fn test_simple() {
|
||||
range: Range { start: 0, end: 10 },
|
||||
});
|
||||
assert!(search_by_filename_result.is_ok());
|
||||
let search_by_filename_result = search_by_filename_result.unwrap();
|
||||
let search_by_filename_result = search_by_filename_result.unwrap().page;
|
||||
assert_eq!(search_by_filename_result.len(), 2);
|
||||
assert_eq!(search_by_filename_result[0].session_id, session.id);
|
||||
assert_eq!(
|
||||
@ -243,5 +243,5 @@ fn test_simple() {
|
||||
});
|
||||
assert!(not_found_result.is_ok());
|
||||
let not_found_result = not_found_result.unwrap();
|
||||
assert_eq!(not_found_result.len(), 0);
|
||||
assert_eq!(not_found_result.total, 0);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
mod deltas;
|
||||
|
||||
pub use deltas::{Deltas, SearchQuery, SearchResult};
|
||||
pub use deltas::{Deltas, SearchQuery, SearchResults};
|
||||
|
||||
#[cfg(test)]
|
||||
mod deltas_test;
|
||||
|
@ -1,17 +1,18 @@
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
|
||||
export type SearchResult = {
|
||||
projectId: string;
|
||||
sessionId: string;
|
||||
filePath: string;
|
||||
// index of the delta in the session.
|
||||
index: number;
|
||||
highlighted: string[]; // contains the highlighted text
|
||||
projectId: string;
|
||||
sessionId: string;
|
||||
filePath: string;
|
||||
// index of the delta in the session.
|
||||
index: number;
|
||||
// contains the highlighted text snippets.
|
||||
highlighted: string[];
|
||||
};
|
||||
|
||||
export const search = (params: {
|
||||
projectId: string;
|
||||
query: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
}) => invoke<SearchResult[]>('search', params);
|
||||
projectId: string;
|
||||
query: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
}) => invoke<{ total: number; page: SearchResult[] }>('search', params);
|
||||
|
@ -31,7 +31,7 @@
|
||||
const fetchResults = async (projectId: string, query: string) => {
|
||||
const results = await search({ projectId, query });
|
||||
stopProcessing = false;
|
||||
for (const result of results) {
|
||||
for (const result of results.page) {
|
||||
if (stopProcessing) {
|
||||
processedResults = [];
|
||||
stopProcessing = false;
|
||||
|
Loading…
Reference in New Issue
Block a user