Mark Geary.Account.open_search as async and throwing an error
This lets us make the DB stemmer lookup async when constructing a search query async and cancellable. Fix call sites.
This commit is contained in:
parent
7cf9825701
commit
983e8ce74e
6 changed files with 87 additions and 42 deletions
|
|
@ -27,7 +27,7 @@ public class ConversationViewer : Gtk.Stack, Geary.BaseInterface {
|
|||
private Configuration config;
|
||||
|
||||
private Gee.Set<Geary.App.Conversation>? selection_while_composing = null;
|
||||
|
||||
private GLib.Cancellable? find_cancellable = null;
|
||||
|
||||
// Stack pages
|
||||
[GtkChild]
|
||||
|
|
@ -269,8 +269,8 @@ public class ConversationViewer : Gtk.Stack, Geary.BaseInterface {
|
|||
|
||||
// Highlight matching terms from find if active, otherwise
|
||||
// from the search folder if that's where we are at
|
||||
Geary.SearchQuery? query = get_find_search_query(
|
||||
conversation.base_folder.account
|
||||
Geary.SearchQuery? query = yield get_find_search_query(
|
||||
conversation.base_folder.account, null
|
||||
);
|
||||
if (query == null) {
|
||||
Geary.SearchFolder? search_folder =
|
||||
|
|
@ -301,6 +301,11 @@ public class ConversationViewer : Gtk.Stack, Geary.BaseInterface {
|
|||
|
||||
// Remove any existing conversation list, cancelling its loading
|
||||
private void remove_current_list() {
|
||||
if (this.find_cancellable != null) {
|
||||
this.find_cancellable.cancel();
|
||||
this.find_cancellable = null;
|
||||
}
|
||||
|
||||
if (this.current_list != null) {
|
||||
this.current_list.cancel_conversation_load();
|
||||
this.conversation_removed(this.current_list);
|
||||
|
|
@ -357,7 +362,34 @@ public class ConversationViewer : Gtk.Stack, Geary.BaseInterface {
|
|||
base.set_visible_child(widget);
|
||||
}
|
||||
|
||||
private Geary.SearchQuery? get_find_search_query(Geary.Account account) {
|
||||
private async void update_find_results() {
|
||||
ConversationListBox? list = this.current_list;
|
||||
if (list != null) {
|
||||
if (this.find_cancellable != null) {
|
||||
this.find_cancellable.cancel();
|
||||
}
|
||||
GLib.Cancellable cancellable = new GLib.Cancellable();
|
||||
cancellable.cancelled.connect(() => {
|
||||
list.search.cancel();
|
||||
});
|
||||
this.find_cancellable = cancellable;
|
||||
try {
|
||||
Geary.SearchQuery? query = yield get_find_search_query(
|
||||
list.conversation.base_folder.account,
|
||||
cancellable
|
||||
);
|
||||
if (query != null) {
|
||||
yield list.search.highlight_matching_email(query);
|
||||
}
|
||||
} catch (GLib.Error err) {
|
||||
warning("Error updating find results: %s", err.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Geary.SearchQuery? get_find_search_query(Geary.Account account,
|
||||
GLib.Cancellable? cancellable)
|
||||
throws GLib.Error {
|
||||
Geary.SearchQuery? query = null;
|
||||
if (this.conversation_find_bar.get_search_mode()) {
|
||||
string text = this.conversation_find_entry.get_text().strip();
|
||||
|
|
@ -365,8 +397,8 @@ public class ConversationViewer : Gtk.Stack, Geary.BaseInterface {
|
|||
// opening every message in the conversation as soon as
|
||||
// the user presses a key
|
||||
if (text.length >= 2) {
|
||||
query = account.open_search(
|
||||
text, this.config.get_search_strategy()
|
||||
query = yield account.open_search(
|
||||
text, this.config.get_search_strategy(), cancellable
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -412,14 +444,7 @@ public class ConversationViewer : Gtk.Stack, Geary.BaseInterface {
|
|||
private void on_find_text_changed(Gtk.SearchEntry entry) {
|
||||
this.conversation_find_next.set_sensitive(false);
|
||||
this.conversation_find_prev.set_sensitive(false);
|
||||
if (this.current_list != null) {
|
||||
Geary.SearchQuery? query = get_find_search_query(
|
||||
this.current_list.conversation.base_folder.account
|
||||
);
|
||||
if (query != null) {
|
||||
this.current_list.search.highlight_matching_email.begin(query);
|
||||
}
|
||||
}
|
||||
this.update_find_results.begin();
|
||||
}
|
||||
|
||||
[GtkCallback]
|
||||
|
|
|
|||
|
|
@ -457,7 +457,10 @@ public abstract class Geary.Account : BaseObject, Loggable {
|
|||
*
|
||||
* Dropping the last reference to the SearchQuery will close it.
|
||||
*/
|
||||
public abstract Geary.SearchQuery open_search(string query, Geary.SearchQuery.Strategy strategy);
|
||||
public abstract async Geary.SearchQuery open_search(string query,
|
||||
SearchQuery.Strategy strategy,
|
||||
GLib.Cancellable? cancellable)
|
||||
throws GLib.Error;
|
||||
|
||||
/**
|
||||
* Performs a search with the given query. Optionally, a list of folders not to search
|
||||
|
|
|
|||
|
|
@ -159,9 +159,13 @@ private class Geary.ImapDB.SearchFolder : Geary.SearchFolder, Geary.FolderSuppor
|
|||
}
|
||||
}
|
||||
|
||||
private async void set_search_query_async(string query, Geary.SearchQuery.Strategy strategy,
|
||||
Cancellable? cancellable) throws Error {
|
||||
Geary.SearchQuery search_query = account.open_search(query, strategy);
|
||||
private async void set_search_query_async(string query,
|
||||
Geary.SearchQuery.Strategy strategy,
|
||||
Cancellable? cancellable)
|
||||
throws GLib.Error {
|
||||
Geary.SearchQuery search_query = yield account.open_search(
|
||||
query, strategy, cancellable
|
||||
);
|
||||
|
||||
int result_mutex_token = yield result_mutex.claim_async();
|
||||
|
||||
|
|
|
|||
|
|
@ -261,11 +261,11 @@ private class Geary.ImapDB.SearchQuery : Geary.SearchQuery {
|
|||
// A list of all search terms, regardless of search op field name
|
||||
private Gee.ArrayList<SearchTerm> all = new Gee.ArrayList<SearchTerm>();
|
||||
|
||||
public SearchQuery(ImapDB.Account account,
|
||||
string query,
|
||||
Geary.SearchQuery.Strategy strategy) {
|
||||
base (query, strategy);
|
||||
|
||||
public async SearchQuery(ImapDB.Account account,
|
||||
string query,
|
||||
Geary.SearchQuery.Strategy strategy,
|
||||
GLib.Cancellable? cancellable) {
|
||||
base(query, strategy);
|
||||
this.account = account;
|
||||
|
||||
switch (strategy) {
|
||||
|
|
@ -298,7 +298,7 @@ private class Geary.ImapDB.SearchQuery : Geary.SearchQuery {
|
|||
break;
|
||||
}
|
||||
|
||||
prepare();
|
||||
yield prepare(cancellable);
|
||||
}
|
||||
|
||||
public Gee.Collection<string?> get_fields() {
|
||||
|
|
@ -403,7 +403,7 @@ private class Geary.ImapDB.SearchQuery : Geary.SearchQuery {
|
|||
return phrases;
|
||||
}
|
||||
|
||||
private void prepare() {
|
||||
private async void prepare(GLib.Cancellable? cancellable) {
|
||||
// A few goals here:
|
||||
// 1) Append an * after every term so it becomes a prefix search
|
||||
// (see <https://www.sqlite.org/fts3.html#section_3>)
|
||||
|
|
@ -490,7 +490,7 @@ private class Geary.ImapDB.SearchQuery : Geary.SearchQuery {
|
|||
// searching for [archive* OR archiv*] when that's
|
||||
// the same as [archiv*]), otherwise search for
|
||||
// both
|
||||
string? stemmed = stem_search_term(s);
|
||||
string? stemmed = yield stem_search_term(s, cancellable);
|
||||
|
||||
string? sql_stemmed = null;
|
||||
if (stemmed != null) {
|
||||
|
|
@ -580,7 +580,8 @@ private class Geary.ImapDB.SearchQuery : Geary.SearchQuery {
|
|||
*
|
||||
* Otherwise, the stem for the term is returned.
|
||||
*/
|
||||
private string? stem_search_term(string term) {
|
||||
private async string? stem_search_term(string term,
|
||||
GLib.Cancellable? cancellable) {
|
||||
if (!this.allow_stemming)
|
||||
return null;
|
||||
|
||||
|
|
@ -590,19 +591,25 @@ private class Geary.ImapDB.SearchQuery : Geary.SearchQuery {
|
|||
|
||||
string? stemmed = null;
|
||||
try {
|
||||
Db.Statement stmt = this.account.db.prepare("""
|
||||
SELECT token
|
||||
FROM TokenizerTable
|
||||
WHERE input=?
|
||||
""");
|
||||
stmt.bind_string(0, term);
|
||||
yield this.account.db.exec_transaction_async(RO,
|
||||
(cx, cancellable) => {
|
||||
Db.Statement stmt = cx.prepare("""
|
||||
SELECT token
|
||||
FROM TokenizerTable
|
||||
WHERE input=?
|
||||
""");
|
||||
stmt.bind_string(0, term);
|
||||
|
||||
// get stemmed string; if no result, fall through
|
||||
Db.Result result = stmt.exec();
|
||||
if (!result.finished)
|
||||
stemmed = result.string_at(0);
|
||||
else
|
||||
debug("No stemmed term returned for \"%s\"", term);
|
||||
// get stemmed string; if no result, fall through
|
||||
Db.Result result = stmt.exec(cancellable);
|
||||
if (!result.finished) {
|
||||
stemmed = result.string_at(0);
|
||||
} else {
|
||||
debug("No stemmed term returned for \"%s\"", term);
|
||||
}
|
||||
return COMMIT;
|
||||
}, cancellable
|
||||
);
|
||||
} catch (Error err) {
|
||||
debug("Unable to query tokenizer table for stemmed term for \"%s\": %s", term, err.message);
|
||||
|
||||
|
|
|
|||
|
|
@ -547,8 +547,11 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
|
|||
return yield local.fetch_email_async(check_id(email_id), required_fields, cancellable);
|
||||
}
|
||||
|
||||
public override Geary.SearchQuery open_search(string query, SearchQuery.Strategy strategy) {
|
||||
return new ImapDB.SearchQuery(local, query, strategy);
|
||||
public override async Geary.SearchQuery open_search(string query,
|
||||
SearchQuery.Strategy strategy,
|
||||
GLib.Cancellable? cancellable)
|
||||
throws GLib.Error {
|
||||
return yield new ImapDB.SearchQuery(local, query, strategy, cancellable);
|
||||
}
|
||||
|
||||
public override async Gee.Collection<Geary.EmailIdentifier>? local_search_async(Geary.SearchQuery query,
|
||||
|
|
|
|||
|
|
@ -213,7 +213,10 @@ public class Geary.MockAccount : Account, MockObject {
|
|||
);
|
||||
}
|
||||
|
||||
public override SearchQuery open_search(string query, SearchQuery.Strategy strategy) {
|
||||
public override async SearchQuery open_search(string query,
|
||||
SearchQuery.Strategy strategy,
|
||||
GLib.Cancellable? cancellable)
|
||||
throws GLib.Error {
|
||||
return new MockSearchQuery();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue