[geary/wip/search-fixes: 2/10] Mark Geary.Account.open_search as async and throwing an error



commit b51da6314f22c9324087f4f97bfba5b4149630ae
Author: Michael Gratton <mike vee net>
Date:   Sun Aug 4 21:35:46 2019 +1000

    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.

 .../conversation-viewer/conversation-viewer.vala   | 54 ++++++++++++++++------
 src/engine/api/geary-account.vala                  |  5 +-
 .../imap-db/search/imap-db-search-folder.vala      | 10 ++--
 .../imap-db/search/imap-db-search-query.vala       | 51 +++++++++++---------
 .../imap-engine/imap-engine-generic-account.vala   |  7 ++-
 test/engine/api/geary-account-mock.vala            |  5 +-
 6 files changed, 90 insertions(+), 42 deletions(-)
---
diff --git a/src/client/conversation-viewer/conversation-viewer.vala 
b/src/client/conversation-viewer/conversation-viewer.vala
index 1e4cf178..9c1da6f5 100644
--- a/src/client/conversation-viewer/conversation-viewer.vala
+++ b/src/client/conversation-viewer/conversation-viewer.vala
@@ -28,6 +28,9 @@ public class ConversationViewer : Gtk.Stack, Geary.BaseInterface {
 
     private Configuration config;
 
+    private GLib.Cancellable? find_cancellable = null;
+
+
     // Stack pages
     [GtkChild]
     private Gtk.Spinner loading_page;
@@ -267,8 +270,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 =
@@ -299,6 +302,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);
@@ -355,7 +363,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();
@@ -363,8 +398,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
                 );
             }
         }
@@ -410,14 +445,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]
diff --git a/src/engine/api/geary-account.vala b/src/engine/api/geary-account.vala
index ad368170..af97bfb1 100644
--- a/src/engine/api/geary-account.vala
+++ b/src/engine/api/geary-account.vala
@@ -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
diff --git a/src/engine/imap-db/search/imap-db-search-folder.vala 
b/src/engine/imap-db/search/imap-db-search-folder.vala
index d387e0fa..b01d2575 100644
--- a/src/engine/imap-db/search/imap-db-search-folder.vala
+++ b/src/engine/imap-db/search/imap-db-search-folder.vala
@@ -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();
 
diff --git a/src/engine/imap-db/search/imap-db-search-query.vala 
b/src/engine/imap-db/search/imap-db-search-query.vala
index 543eec18..35c71d7c 100644
--- a/src/engine/imap-db/search/imap-db-search-query.vala
+++ b/src/engine/imap-db/search/imap-db-search-query.vala
@@ -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);
-
-            // 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);
+            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(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);
 
diff --git a/src/engine/imap-engine/imap-engine-generic-account.vala 
b/src/engine/imap-engine/imap-engine-generic-account.vala
index 19c97f67..c5ada125 100644
--- a/src/engine/imap-engine/imap-engine-generic-account.vala
+++ b/src/engine/imap-engine/imap-engine-generic-account.vala
@@ -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,
diff --git a/test/engine/api/geary-account-mock.vala b/test/engine/api/geary-account-mock.vala
index 2159df5a..e2fc7f4f 100644
--- a/test/engine/api/geary-account-mock.vala
+++ b/test/engine/api/geary-account-mock.vala
@@ -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();
     }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]