static char *
-_optimize_tag_query (void *ctx, const char *orig_query_string,
- const tag_op_list_t *list)
+_optimize_tag_query_infix (void *ctx, const char *orig_query_string,
+ const tag_op_list_t *list)
{
/* This is subtler than it looks. Xapian ignores the '-' operator
* at the beginning both queries and parenthesized groups and,
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'
*/
static int
if (! (flags & TAG_FLAG_REMOVE_ALL)) {
/* Optimize the query so it excludes messages that already
* 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) {
fprintf (stderr, "Out of memory.\n");
return 1;
flags |= TAG_FLAG_PRE_OPTIMIZED;
}
- query = notmuch_query_create (notmuch, query_string);
- if (query == NULL) {
- fprintf (stderr, "Out of memory.\n");
+ status = notmuch_query_create_with_syntax (notmuch, query_string,
+ shared_option_query_syntax (),
+ &query);
+ if (print_status_database ("notmuch tag", notmuch, status))
return 1;
- }
/* tagging is not interested in any special sort order */
notmuch_query_set_sort (query, NOTMUCH_SORT_UNSORTED);
test_description='"notmuch tag"'
. $(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]=Two'
chmod u+w ${MAIL_DIR}/.notmuch/xapian/*.*
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