CLI/tag: enable sexp queries

We have to rewrite _optimize_tag_query here because it is generating
a query string in the infix Xapian syntax. Luckily this is easy to do
with the sexp query syntax.
This commit is contained in:
David Bremner 2021-08-24 08:17:44 -07:00
parent 2944d59133
commit 4595a814c2
2 changed files with 79 additions and 7 deletions

View file

@ -39,8 +39,8 @@ handle_sigint (unused (int sig))
static char * static char *
_optimize_tag_query (void *ctx, const char *orig_query_string, _optimize_tag_query_infix (void *ctx, const char *orig_query_string,
const tag_op_list_t *list) const tag_op_list_t *list)
{ {
/* This is subtler than it looks. Xapian ignores the '-' operator /* This is subtler than it looks. Xapian ignores the '-' operator
* at the beginning both queries and parenthesized groups and, * at the beginning both queries and parenthesized groups and,
@ -88,6 +88,33 @@ _optimize_tag_query (void *ctx, const char *orig_query_string,
return query_string; return query_string;
} }
static char *
_optimize_tag_query (void *ctx, const char *orig_query_string,
notmuch_query_syntax_t stx,
const tag_op_list_t *list)
{
char *query_string;
if (stx == NOTMUCH_QUERY_SYNTAX_XAPIAN)
return _optimize_tag_query_infix (ctx, orig_query_string, list);
/* Don't optimize if there are no tag changes. */
if (tag_op_list_size (list) == 0)
return talloc_strdup (ctx, orig_query_string);
query_string = talloc_asprintf (ctx, "(and %s", orig_query_string);
for (size_t i = 0; i < tag_op_list_size (list) && query_string; i++) {
query_string = talloc_asprintf_append_buffer (
query_string, tag_op_list_isremove (list, i) ? " (tag \"%s\")" : " (not (tag \"%s\"))",
tag_op_list_tag (list, i));
}
if (query_string)
query_string = talloc_strdup_append_buffer (query_string, ")");
return query_string;
}
/* Tag messages matching 'query_string' according to 'tag_ops' /* Tag messages matching 'query_string' according to 'tag_ops'
*/ */
static int static int
@ -104,7 +131,9 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string,
if (! (flags & TAG_FLAG_REMOVE_ALL)) { if (! (flags & TAG_FLAG_REMOVE_ALL)) {
/* Optimize the query so it excludes messages that already /* Optimize the query so it excludes messages that already
* have the specified set of tags. */ * have the specified set of tags. */
query_string = _optimize_tag_query (ctx, query_string, tag_ops); query_string = _optimize_tag_query (ctx, query_string,
shared_option_query_syntax (),
tag_ops);
if (query_string == NULL) { if (query_string == NULL) {
fprintf (stderr, "Out of memory.\n"); fprintf (stderr, "Out of memory.\n");
return 1; return 1;
@ -112,11 +141,11 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string,
flags |= TAG_FLAG_PRE_OPTIMIZED; flags |= TAG_FLAG_PRE_OPTIMIZED;
} }
query = notmuch_query_create (notmuch, query_string); status = notmuch_query_create_with_syntax (notmuch, query_string,
if (query == NULL) { shared_option_query_syntax (),
fprintf (stderr, "Out of memory.\n"); &query);
if (print_status_database ("notmuch tag", notmuch, status))
return 1; return 1;
}
/* tagging is not interested in any special sort order */ /* tagging is not interested in any special sort order */
notmuch_query_set_sort (query, NOTMUCH_SORT_UNSORTED); notmuch_query_set_sort (query, NOTMUCH_SORT_UNSORTED);

View file

@ -2,6 +2,21 @@
test_description='"notmuch tag"' test_description='"notmuch tag"'
. $(dirname "$0")/test-lib.sh || exit 1 . $(dirname "$0")/test-lib.sh || exit 1
test_query_syntax () {
# use a tag with a space to stress the query string munging code.
local new_tag="${RANDOM} ${RANDOM}"
test_begin_subtest "sexpr query: $1"
backup_database
notmuch tag --query=sexp "+${new_tag}" -- "$1"
notmuch dump > OUTPUT
restore_database
backup_database
notmuch tag "+${new_tag}" -- "$2"
notmuch dump > EXPECTED
restore_database
test_expect_equal_file_nonempty EXPECTED OUTPUT
}
add_message '[subject]=One' add_message '[subject]=One'
add_message '[subject]=Two' add_message '[subject]=Two'
@ -310,4 +325,32 @@ output=$(notmuch tag +something '*' 2>&1 | sed 's/: .*$//' )
chmod u+w ${MAIL_DIR}/.notmuch/xapian/*.* chmod u+w ${MAIL_DIR}/.notmuch/xapian/*.*
test_expect_equal "$output" "A Xapian exception occurred opening database" test_expect_equal "$output" "A Xapian exception occurred opening database"
add_email_corpus
if [ $NOTMUCH_HAVE_SFSEXP -eq 1 ]; then
test_query_syntax '(and "wonderful" "wizard")' 'wonderful and wizard'
test_query_syntax '(or "php" "wizard")' 'php or wizard'
test_query_syntax 'wizard' 'wizard'
test_query_syntax 'Wizard' 'Wizard'
test_query_syntax '(attachment notmuch-help.patch)' 'attachment:notmuch-help.patch'
test_query_syntax '(mimetype text/html)' 'mimetype:text/html'
test_begin_subtest "--batch --query=sexp"
notmuch dump --format=batch-tag > backup.tags
notmuch tag --batch --query=sexp <<EOF
+all -- (or One Two)
+none -- (and One Two)
EOF
notmuch dump > OUTPUT
cat <<EOF > EXPECTED
#notmuch-dump batch-tag:3 config,properties,tags
+all +inbox +tag5 +unread -- id:msg-001@notmuch-test-suite
+all +inbox +tag4 +tag5 +unread -- id:msg-002@notmuch-test-suite
EOF
notmuch restore --format=batch-tag < backup.tags
test_expect_equal_file EXPECTED OUTPUT
fi
test_done test_done