diff --git a/src/engine/common/common-fts-search-query.vala b/src/engine/common/common-fts-search-query.vala index 05cee30b..aef2e2df 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>( 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 b575f543..790f8995 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.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.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.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.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(),