lib/parse-sexp: support saved s-expression queries

It turns out there is not really much code in query-fp.cc useful for
supporting the new syntax. The code we could potentially factor out
amounts to calling notmuch_database_get_config; both the key
construction and the parsing of the results are specific to the query
syntax involved.
This commit is contained in:
David Bremner 2021-08-24 08:17:39 -07:00
parent 81b9dbd110
commit 9b9eb1d8bd
2 changed files with 81 additions and 1 deletions

View file

@ -291,6 +291,49 @@ _sexp_parse_header (notmuch_database_t *notmuch, const _sexp_prefix_t *parent,
sx->list->next, output); sx->list->next, output);
} }
static notmuch_status_t
maybe_saved_squery (notmuch_database_t *notmuch, const _sexp_prefix_t *parent, const sexp_t *sx,
Xapian::Query &output)
{
char *key;
char *expansion = NULL;
notmuch_status_t status;
sexp_t *saved_sexp;
void *local = talloc_new (notmuch);
char *buf;
key = talloc_asprintf (local, "squery.%s", sx->list->val);
if (! key) {
status = NOTMUCH_STATUS_OUT_OF_MEMORY;
goto DONE;
}
status = notmuch_database_get_config (notmuch, key, &expansion);
if (status)
goto DONE;
if (EMPTY_STRING (expansion)) {
status = NOTMUCH_STATUS_IGNORED;
goto DONE;
}
buf = talloc_strdup (local, expansion);
/* XXX TODO: free this memory */
saved_sexp = parse_sexp (buf, strlen (expansion));
if (! saved_sexp) {
_notmuch_database_log (notmuch, "invalid saved s-expression query: '%s'\n", expansion);
status = NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
goto DONE;
}
status = _sexp_to_xapian_query (notmuch, parent, saved_sexp, output);
DONE:
if (local)
talloc_free (local);
return status;
}
/* Here we expect the s-expression to be a proper list, with first /* Here we expect the s-expression to be a proper list, with first
* element defining and operation, or as a special case the empty * element defining and operation, or as a special case the empty
* list */ * list */
@ -299,6 +342,8 @@ static notmuch_status_t
_sexp_to_xapian_query (notmuch_database_t *notmuch, const _sexp_prefix_t *parent, const sexp_t *sx, _sexp_to_xapian_query (notmuch_database_t *notmuch, const _sexp_prefix_t *parent, const sexp_t *sx,
Xapian::Query &output) Xapian::Query &output)
{ {
notmuch_status_t status;
if (sx->ty == SEXP_VALUE) { if (sx->ty == SEXP_VALUE) {
std::string term_prefix = parent ? _notmuch_database_prefix (notmuch, parent->name) : ""; std::string term_prefix = parent ? _notmuch_database_prefix (notmuch, parent->name) : "";
@ -317,7 +362,6 @@ _sexp_to_xapian_query (notmuch_database_t *notmuch, const _sexp_prefix_t *parent
Xapian::Query accumulator; Xapian::Query accumulator;
for (_sexp_prefix_t *prefix = prefixes; prefix->name; prefix++) { for (_sexp_prefix_t *prefix = prefixes; prefix->name; prefix++) {
if (prefix->flags & SEXP_FLAG_FIELD) { if (prefix->flags & SEXP_FLAG_FIELD) {
notmuch_status_t status;
Xapian::Query subquery; Xapian::Query subquery;
term_prefix = _notmuch_database_prefix (notmuch, prefix->name); term_prefix = _notmuch_database_prefix (notmuch, prefix->name);
status = _sexp_parse_one_term (notmuch, term_prefix, sx, subquery); status = _sexp_parse_one_term (notmuch, term_prefix, sx, subquery);
@ -343,6 +387,10 @@ _sexp_to_xapian_query (notmuch_database_t *notmuch, const _sexp_prefix_t *parent
return NOTMUCH_STATUS_BAD_QUERY_SYNTAX; return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
} }
status = maybe_saved_squery (notmuch, parent, sx, output);
if (status != NOTMUCH_STATUS_IGNORED)
return status;
/* Check for user defined field */ /* Check for user defined field */
if (_notmuch_string_map_get (notmuch->user_prefix, sx->list->val)) { if (_notmuch_string_map_get (notmuch->user_prefix, sx->list->val)) {
return _sexp_parse_header (notmuch, parent, sx, output); return _sexp_parse_header (notmuch, parent, sx, output);

View file

@ -825,4 +825,36 @@ notmuch config set squery.Test '(subject override subject)'
output=$(notmuch config get squery.Test) output=$(notmuch config get squery.Test)
test_expect_equal "$output" '(subject override subject)' test_expect_equal "$output" '(subject override subject)'
test_begin_subtest "unknown saved query"
notmuch search --query=sexp '(Unknown foo bar)' >OUTPUT 2>&1
cat <<EOF > EXPECTED
notmuch search: Syntax error in query
unknown prefix 'Unknown'
EOF
test_expect_equal_file EXPECTED OUTPUT
test_begin_subtest "syntax error in saved query"
notmuch config set squery.Bad '(Bad'
notmuch search --query=sexp '(Bad foo bar)' >OUTPUT 2>&1
cat <<EOF > EXPECTED
notmuch search: Syntax error in query
invalid saved s-expression query: '(Bad'
EOF
test_expect_equal_file EXPECTED OUTPUT
test_begin_subtest "Saved Search by 'tag' and 'subject'"
notmuch search tag:inbox and subject:maildir | notmuch_search_sanitize > EXPECTED
notmuch config set squery.TagSubject '(and (tag inbox) (subject maildir))'
notmuch search --query=sexp '(TagSubject)' | notmuch_search_sanitize > OUTPUT
test_expect_equal_file EXPECTED OUTPUT
test_begin_subtest "Saved Search: illegal nesting"
notmuch config set squery.TagSubject '(and (tag inbox) (subject maildir))'
notmuch search --query=sexp '(subject (TagSubject))' >OUTPUT 2>&1
cat <<EOF > EXPECTED
notmuch search: Syntax error in query
nested field: 'tag' inside 'subject'
EOF
test_expect_equal_file EXPECTED OUTPUT
test_done test_done