[geary/mjog/search-update: 21/28] Geary.FtsSearchQuery: Fixes for email text disjunctions




commit 236b22ad50149fc66870c5f158d80312b0514722
Author: Michael Gratton <mike vee net>
Date:   Thu Nov 5 22:52:59 2020 +1100

    Geary.FtsSearchQuery: Fixes for email text disjunctions
    
    Ensure OR is actually used to separate disjuncts, don't prefix match
    non-stemmed terms when a stemmed version exists or when EXACT is
    specified. Ensure column is correctly specified per disjunct.

 src/engine/common/common-fts-search-query.vala     | 22 +++++--
 .../common/common-fts-search-query-test.vala       | 69 +++++++++++++---------
 2 files changed, 58 insertions(+), 33 deletions(-)
---
diff --git a/src/engine/common/common-fts-search-query.vala b/src/engine/common/common-fts-search-query.vala
index 05cee30bf..aef2e2df3 100644
--- a/src/engine/common/common-fts-search-query.vala
+++ b/src/engine/common/common-fts-search-query.vala
@@ -324,23 +324,33 @@ internal class Geary.FtsSearchQuery : Geary.SearchQuery {
             break;
         }
 
+        sql.append(" (");
+
         var values = text.terms;
         var stemmed_values = text.get_data<Gee.List<string?>>(
             EMAIL_TEXT_STEMMED_TERMS
         );
+        var is_first_disjunct = true;
         for (int i = 0; i < values.size; i++) {
+            if (!is_first_disjunct) {
+                sql.append(" OR");
+            }
             if (target != "") {
-                sql.append_printf(" ({%s} :", target);
+                sql.append_printf("{%s} :", target);
             }
             if (stemmed_values != null && stemmed_values[i] != null) {
-                sql.append(" \"' || ? || '\"* OR \"' || ? || '\"*");
-            } else {
+                // Original is not a prefix match, stemmed is
+                sql.append(" \"' || ? || '\" OR \"' || ? || '\"*");
+            } else if (text.matching_strategy != EXACT) {
+                // A regular match, do a suffix match
                 sql.append(" \"' || ? || '\"*");
+            } else {
+                // EXACT is not a prefix match
+                sql.append(" \"' || ? || '\"");
             }
-            if (target != "") {
-                sql.append_c(')');
-            }
+            is_first_disjunct = false;
         }
+        sql.append_c(')');
     }
 
     private int sql_bind_term_conditions(Db.Statement sql,
diff --git a/test/engine/common/common-fts-search-query-test.vala 
b/test/engine/common/common-fts-search-query-test.vala
index b575f5434..790f89954 100644
--- a/test/engine/common/common-fts-search-query-test.vala
+++ b/test/engine/common/common-fts-search-query-test.vala
@@ -19,8 +19,8 @@ public class Geary.FtsSearchQueryTest : TestCase {
         add_test("email_text_terms", email_text_terms);
         add_test("email_text_terms_stemmed", email_text_terms_stemmed);
         add_test("email_text_terms_specific", email_text_terms_specific);
+        add_test("email_text_terms_disjunction", email_text_terms_disjunction);
         add_test("email_flag_terms", email_flag_terms);
-        add_test("excluded_folders", excluded_folders);
     }
 
     public override void set_up() throws GLib.Error {
@@ -156,6 +156,28 @@ public class Geary.FtsSearchQueryTest : TestCase {
         assert_queries(conflicting_property_and_term);
     }
 
+    public void email_text_terms_disjunction() throws GLib.Error {
+        var multiple_all = new_search_query(
+            {
+                new Geary.SearchQuery.EmailTextTerm.disjunction(
+                    ALL, EXACT, new Gee.ArrayList<string>.wrap({ "foo", "bar" })
+                )
+            },
+            "(foo|bar)"
+        );
+        assert_queries(multiple_all);
+
+        var multiple_subject = new_search_query(
+            {
+                new Geary.SearchQuery.EmailTextTerm.disjunction(
+                    ALL, EXACT, new Gee.ArrayList<string>.wrap({ "foo", "bar" })
+                )
+            },
+            "subject:(foo|bar)"
+        );
+        assert_queries(multiple_subject);
+    }
+
     public void email_flag_terms() throws GLib.Error {
         var unread = new_search_query(
             { new Geary.SearchQuery.EmailFlagTerm(Geary.EmailFlags.UNREAD)},
@@ -175,11 +197,26 @@ public class Geary.FtsSearchQueryTest : TestCase {
         assert_queries(flagged);
     }
 
-    public void excluded_folders() throws GLib.Error {
-        var query = new_search_query(
-            { new Geary.SearchQuery.EmailTextTerm(ALL, EXACT, "test")},
-            "test"
+    private FtsSearchQuery new_search_query(Geary.SearchQuery.Term[] ops,
+                                            string raw)
+        throws GLib.Error {
+        return new FtsSearchQuery(
+            new Gee.ArrayList<Geary.SearchQuery.Term>.wrap(ops),
+            raw,
+            this.stemmer
+        );
+    }
+
+    private void assert_queries(FtsSearchQuery query) throws GLib.Error {
+        var search = query.get_search_query(
+            this.account.db.get_primary_connection(),
+            null,
+            null,
+            false,
+            10,
+            0
         );
+        search.exec(null);
 
         var search_with_excluded_ids = query.get_search_query(
             this.account.db.get_primary_connection(),
@@ -210,28 +247,6 @@ public class Geary.FtsSearchQueryTest : TestCase {
             0
         );
         search_with_both.exec(null);
-    }
-
-    private FtsSearchQuery new_search_query(Geary.SearchQuery.Term[] ops,
-                                            string raw)
-        throws GLib.Error {
-        return new FtsSearchQuery(
-            new Gee.ArrayList<Geary.SearchQuery.Term>.wrap(ops),
-            raw,
-            this.stemmer
-        );
-    }
-
-    private void assert_queries(FtsSearchQuery query) throws GLib.Error {
-        var search = query.get_search_query(
-            this.account.db.get_primary_connection(),
-            null,
-            null,
-            false,
-            10,
-            0
-        );
-        search.exec(null);
 
         var match = query.get_match_query(
             this.account.db.get_primary_connection(),


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