This commit connects the previously added keyword / flag handling with the previously refactored regexp to query refactoring. --- lib/parse-sexp.cc | 35 +++++++++++++++-------- lib/regexp-fields.h | 8 +++--- test/T081-sexpr-search.sh | 59 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 16 deletions(-)
diff --git a/lib/parse-sexp.cc b/lib/parse-sexp.cc index 95ee7c99..c0d0b596 100644 --- a/lib/parse-sexp.cc +++ b/lib/parse-sexp.cc @@ -1,8 +1,8 @@ -#include <xapian.h> -#include "notmuch-private.h" +#include "database-private.h" #include "sexp.h" #include "parse-time-vrp.h" #include "query-fp.h" +#include "regexp-fields.h" typedef struct { const char *name; @@ -13,6 +13,7 @@ typedef struct { typedef enum { SEXP_FLAG_NONE = 0, SEXP_FLAG_WILDCARD = 1 << 0, + SEXP_FLAG_REGEXP = 1 << 1, } _sexp_flag_t; /* @@ -51,18 +52,18 @@ static _sexp_field_t fields[] = { "attachment", Xapian::Query::OP_PHRASE, SEXP_FLAG_WILDCARD }, { "body", Xapian::Query::OP_PHRASE, SEXP_FLAG_NONE }, { "date", Xapian::Query::OP_INVALID, SEXP_FLAG_NONE }, - { "from", Xapian::Query::OP_PHRASE, SEXP_FLAG_NONE }, - { "folder", Xapian::Query::OP_OR, SEXP_FLAG_NONE }, - { "id", Xapian::Query::OP_OR, SEXP_FLAG_NONE }, - { "is", Xapian::Query::OP_AND, SEXP_FLAG_WILDCARD }, - { "mid", Xapian::Query::OP_OR, SEXP_FLAG_NONE }, + { "from", Xapian::Query::OP_PHRASE, SEXP_FLAG_REGEXP }, + { "folder", Xapian::Query::OP_OR, SEXP_FLAG_REGEXP }, + { "id", Xapian::Query::OP_OR, SEXP_FLAG_REGEXP }, + { "is", Xapian::Query::OP_AND, SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEXP }, + { "mid", Xapian::Query::OP_OR, SEXP_FLAG_REGEXP }, { "mimetype", Xapian::Query::OP_PHRASE, SEXP_FLAG_NONE }, - { "path", Xapian::Query::OP_OR, SEXP_FLAG_NONE }, - { "property", Xapian::Query::OP_AND, SEXP_FLAG_WILDCARD }, + { "path", Xapian::Query::OP_OR, SEXP_FLAG_REGEXP }, + { "property", Xapian::Query::OP_AND, SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEXP }, { "query", Xapian::Query::OP_INVALID, SEXP_FLAG_NONE }, - { "subject", Xapian::Query::OP_PHRASE, SEXP_FLAG_NONE }, - { "tag", Xapian::Query::OP_AND, SEXP_FLAG_WILDCARD }, - { "thread", Xapian::Query::OP_OR, SEXP_FLAG_NONE }, + { "subject", Xapian::Query::OP_PHRASE, SEXP_FLAG_REGEXP }, + { "tag", Xapian::Query::OP_AND, SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEXP }, + { "thread", Xapian::Query::OP_OR, SEXP_FLAG_REGEXP }, { "to", Xapian::Query::OP_PHRASE, SEXP_FLAG_NONE }, { } }; @@ -76,6 +77,7 @@ static _sexp_keyword_t keywords[] = { { "any", SEXP_FLAG_WILDCARD }, { "*", SEXP_FLAG_WILDCARD }, + { "rx", SEXP_FLAG_REGEXP }, { } }; @@ -305,6 +307,15 @@ _sexp_to_xapian_query (notmuch_database_t *notmuch, const sexp_t *sx, Xapian::Qu } output = Xapian::Query (Xapian::Query::OP_WILDCARD, term_prefix); return NOTMUCH_STATUS_SUCCESS; + } else if (flags & SEXP_FLAG_REGEXP) { + if (! rest || ! rest->val) { + _notmuch_database_log (notmuch, "missing regular expression\n"); + return NOTMUCH_STATUS_BAD_QUERY_SYNTAX; + } else { + std::string msg; /* ignored */ + return _notmuch_regexp_to_query (notmuch, Xapian::BAD_VALUENO, field->name, + rest->val, output, msg); + } } else { return _sexp_combine_field (term_prefix, field->xapian_op, rest, output); diff --git a/lib/regexp-fields.h b/lib/regexp-fields.h index 9c871de7..aa8fd81c 100644 --- a/lib/regexp-fields.h +++ b/lib/regexp-fields.h @@ -27,13 +27,13 @@ #include <sys/types.h> #include <regex.h> -#include "database-private.h" #include "notmuch-private.h" +#include "database-private.h" notmuch_status_t -_notmuch_regex_to_query (notmuch_database_t *notmuch, Xapian::valueno slot, std::string field, - std::string regexp_str, - Xapian::Query &output, std::string &msg); +_notmuch_regexp_to_query (notmuch_database_t *notmuch, Xapian::valueno slot, std::string field, + std::string regexp_str, + Xapian::Query &output, std::string &msg); /* A posting source that returns documents where a value matches a * regexp. diff --git a/test/T081-sexpr-search.sh b/test/T081-sexpr-search.sh index 04eba2c0..281a9bf7 100755 --- a/test/T081-sexpr-search.sh +++ b/test/T081-sexpr-search.sh @@ -377,4 +377,63 @@ output=$(notmuch search --query-syntax=sexp '(subject deleted)' | notmuch_search test_expect_equal "$output" "thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Not deleted (inbox unread) thread:XXX 2001-01-05 [2/2] Notmuch Test Suite; Deleted (deleted inbox unread)" +test_begin_subtest "illegal regexp search" +test_expect_code 1 "notmuch search --query-syntax=sexp '(body :rx foo)'" + +notmuch search --output=messages from:cworth > cworth.msg-ids + +test_begin_subtest "regexp 'folder' search" +notmuch search 'folder:/^bar$/' | notmuch_search_sanitize > EXPECTED +notmuch search --query-syntax=sexp '(folder :rx ^bar$)' | notmuch_search_sanitize > OUTPUT +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "regexp from search" +notmuch search --output=messages --query-syntax=sexp '(from :rx cworth)' > OUTPUT +test_expect_equal_file cworth.msg-ids OUTPUT + +test_begin_subtest "regexp search for 'from' 2" +notmuch search from:/cwo...@cworth.org/ and subject:patch | notmuch_search_sanitize > EXPECTED +notmuch search --query-syntax=sexp '(and (from :rx cwo...@cworth.org) (subject patch))' \ + | notmuch_search_sanitize > OUTPUT +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "regexp 'id' search" +notmuch search --output=messages --query-syntax=sexp '(id :rx yoom)' > OUTPUT +test_expect_equal_file cworth.msg-ids OUTPUT + +test_begin_subtest "unanchored 'is' search" +notmuch search tag:signed or tag:inbox > EXPECTED +notmuch search --query-syntax=sexp '(is :rx i)' > OUTPUT +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "anchored 'is' search" +notmuch search tag:signed > EXPECTED +notmuch search --query-syntax=sexp '(is :rx ^si)' > OUTPUT +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "combine regexp mid and subject" +notmuch search subject:/-C/ and mid:/y..m/ | notmuch_search_sanitize > EXPECTED +notmuch search --query-syntax=sexp '(and (subject :rx -C) (mid :rx y..m))' | notmuch_search_sanitize > OUTPUT +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "regexp 'path' search" +notmuch search 'path:/^bar$/' | notmuch_search_sanitize > EXPECTED +notmuch search --query-syntax=sexp '(path :rx ^bar$)' | notmuch_search_sanitize > OUTPUT +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "regexp 'property' search" +notmuch search property:foo=bar > EXPECTED +notmuch search --query-syntax=sexp '(property :rx foo=.*)' > OUTPUT +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "anchored 'tag' search" +notmuch search tag:signed > EXPECTED +notmuch search --query-syntax=sexp '(tag :rx ^si)' > OUTPUT +test_expect_equal_file EXPECTED OUTPUT + +test_begin_subtest "regexp 'thread' search" +notmuch search --output=threads '*' | grep '7$' > EXPECTED +notmuch search --output=threads --query-syntax=sexp '(thread :rx 7$)' > OUTPUT +test_expect_equal_file EXPECTED OUTPUT + test_done -- 2.30.2 _______________________________________________ notmuch mailing list -- notmuch@notmuchmail.org To unsubscribe send an email to notmuch-le...@notmuchmail.org