mirror of
https://git.notmuchmail.org/git/notmuch
synced 2024-12-22 09:24:54 +01:00
lib/parse-sexp: support infix subqueries
This is necessary so that programs can take infix syntax queries from a user and use the sexp query syntax to construct e.g. a refinement of that query.
This commit is contained in:
parent
afe85e6578
commit
cc5992a304
3 changed files with 84 additions and 0 deletions
|
@ -144,6 +144,10 @@ MODIFIERS
|
|||
*Modifiers* refer to any prefixes (first elements of compound queries)
|
||||
that are neither operators nor fields.
|
||||
|
||||
``(infix`` *atom* ``)``
|
||||
Interpret *atom* as an infix notmuch query (see
|
||||
:any:`notmuch-search-terms(7)`). Not supported inside fields.
|
||||
|
||||
``(matching`` |q1| |q2| ... |qn| ``)`` ``(of`` |q1| |q2| ... |qn| ``)``
|
||||
Match all messages have the same values of the current field as
|
||||
those matching all of |q1| ... |qn|. Supported in most term [#not-path]_ or
|
||||
|
@ -187,6 +191,9 @@ EXAMPLES
|
|||
``(id 1234@invalid blah@test)``
|
||||
Matches Message-Id "1234@invalid" *or* Message-Id "blah@test"
|
||||
|
||||
``(and (infix "date:2009-11-18..2009-11-18") (tag unread))``
|
||||
Match messages in the given date range with tag unread.
|
||||
|
||||
``(starts-with prelim)``
|
||||
Match any words starting with "prelim".
|
||||
|
||||
|
|
|
@ -57,6 +57,8 @@ static _sexp_prefix_t prefixes[] =
|
|||
SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX | SEXP_FLAG_EXPAND },
|
||||
{ "id", Xapian::Query::OP_OR, Xapian::Query::MatchNothing,
|
||||
SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX },
|
||||
{ "infix", Xapian::Query::OP_INVALID, Xapian::Query::MatchAll,
|
||||
SEXP_FLAG_SINGLE },
|
||||
{ "is", Xapian::Query::OP_AND, Xapian::Query::MatchAll,
|
||||
SEXP_FLAG_FIELD | SEXP_FLAG_BOOLEAN | SEXP_FLAG_WILDCARD | SEXP_FLAG_REGEX | SEXP_FLAG_EXPAND },
|
||||
{ "matching", Xapian::Query::OP_AND, Xapian::Query::MatchAll,
|
||||
|
@ -242,6 +244,34 @@ _sexp_expand_query (notmuch_database_t *notmuch,
|
|||
return status;
|
||||
}
|
||||
|
||||
static notmuch_status_t
|
||||
_sexp_parse_infix (notmuch_database_t *notmuch, const _sexp_prefix_t *parent,
|
||||
const sexp_t *sx, Xapian::Query &output)
|
||||
{
|
||||
if (parent) {
|
||||
_notmuch_database_log (notmuch, "'infix' not supported inside '%s'\n", parent->name);
|
||||
return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
|
||||
}
|
||||
try {
|
||||
output = notmuch->query_parser->parse_query (sx->val, NOTMUCH_QUERY_PARSER_FLAGS);
|
||||
} catch (const Xapian::QueryParserError &error) {
|
||||
_notmuch_database_log (notmuch, "Syntax error in infix query: %s\n", sx->val);
|
||||
return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
|
||||
} catch (const Xapian::Error &error) {
|
||||
if (! notmuch->exception_reported) {
|
||||
_notmuch_database_log (notmuch,
|
||||
"A Xapian exception occurred parsing query: %s\n",
|
||||
error.get_msg ().c_str ());
|
||||
_notmuch_database_log_append (notmuch,
|
||||
"Query string was: %s\n",
|
||||
sx->val);
|
||||
notmuch->exception_reported = true;
|
||||
return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
|
||||
}
|
||||
}
|
||||
return NOTMUCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Here we expect the s-expression to be a proper list, with first
|
||||
* element defining and operation, or as a special case the empty
|
||||
* list */
|
||||
|
@ -311,6 +341,10 @@ _sexp_to_xapian_query (notmuch_database_t *notmuch, const _sexp_prefix_t *parent
|
|||
return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
|
||||
}
|
||||
|
||||
if (strcmp (prefix->name, "infix") == 0) {
|
||||
return _sexp_parse_infix (notmuch, parent, sx->list->next, output);
|
||||
}
|
||||
|
||||
if (prefix->xapian_op == Xapian::Query::OP_WILDCARD)
|
||||
return _sexp_parse_wildcard (notmuch, parent, sx->list->next->val, output);
|
||||
|
||||
|
|
|
@ -689,4 +689,47 @@ id:cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com
|
|||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "infix query"
|
||||
notmuch search to:searchbyto | notmuch_search_sanitize > EXPECTED
|
||||
notmuch search --query=sexp '(infix "to:searchbyto")' | notmuch_search_sanitize > OUTPUT
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "bad infix query 1"
|
||||
notmuch search --query=sexp '(infix "from:/unbalanced")' 2>&1| notmuch_search_sanitize > OUTPUT
|
||||
cat <<EOF > EXPECTED
|
||||
notmuch search: Syntax error in query
|
||||
Syntax error in infix query: from:/unbalanced
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "bad infix query 2"
|
||||
notmuch search --query=sexp '(infix "thread:{unbalanced")' 2>&1| notmuch_search_sanitize > OUTPUT
|
||||
cat <<EOF > EXPECTED
|
||||
notmuch search: Syntax error in query
|
||||
Syntax error in infix query: thread:{unbalanced
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "bad infix query 3: bad nesting"
|
||||
notmuch search --query=sexp '(subject (infix "tag:inbox"))' 2>&1| notmuch_search_sanitize > OUTPUT
|
||||
cat <<EOF > EXPECTED
|
||||
notmuch search: Syntax error in query
|
||||
'infix' not supported inside 'subject'
|
||||
EOF
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "infix query that matches no messages"
|
||||
notmuch search --query=sexp '(and (infix "from:keithp") (infix "to:keithp"))' > OUTPUT
|
||||
test_expect_equal_file /dev/null OUTPUT
|
||||
|
||||
test_begin_subtest "compound infix query"
|
||||
notmuch search date:2009-11-18..2009-11-18 and tag:unread > EXPECTED
|
||||
notmuch search --query=sexp '(infix "date:2009-11-18..2009-11-18 and tag:unread")' > OUTPUT
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_begin_subtest "compound infix query 2"
|
||||
notmuch search date:2009-11-18..2009-11-18 and tag:unread > EXPECTED
|
||||
notmuch search --query=sexp '(and (infix "date:2009-11-18..2009-11-18") (infix "tag:unread"))' > OUTPUT
|
||||
test_expect_equal_file EXPECTED OUTPUT
|
||||
|
||||
test_done
|
||||
|
|
Loading…
Reference in a new issue