* mu-query: implement MU_QUERY_FLAG_INCLUDE_RELATED, make threading non-optional
This commit is contained in:
128
lib/mu-query.cc
128
lib/mu-query.cc
@ -357,17 +357,31 @@ try_requery (MuQuery *self, const char* searchexpr, MuMsgFieldId sortfieldid,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static MuMsgIterFlags
|
||||||
|
msg_iter_flags (MuQueryFlags flags)
|
||||||
|
{
|
||||||
|
MuMsgIterFlags iflags;
|
||||||
|
|
||||||
|
iflags = MU_MSG_ITER_FLAG_NONE;
|
||||||
|
|
||||||
|
if (flags & MU_QUERY_FLAG_DESCENDING)
|
||||||
|
iflags |= MU_MSG_ITER_FLAG_DESCENDING;
|
||||||
|
if (flags & MU_QUERY_FLAG_SKIP_UNREADABLE)
|
||||||
|
iflags |= MU_MSG_ITER_FLAG_SKIP_UNREADABLE;
|
||||||
|
if (flags & MU_QUERY_FLAG_SKIP_DUPS)
|
||||||
|
iflags |= MU_MSG_ITER_FLAG_SKIP_DUPS;
|
||||||
|
|
||||||
|
return iflags;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static Xapian::Enquire
|
static Xapian::Enquire
|
||||||
get_enquire (MuQuery *self, const char *searchexpr, MuMsgFieldId sortfieldid,
|
get_enquire (MuQuery *self, const char *searchexpr, MuMsgFieldId sortfieldid,
|
||||||
MuQueryFlags flags, GError **err)
|
bool descending, GError **err)
|
||||||
{
|
{
|
||||||
Xapian::Enquire enq (self->db());
|
Xapian::Enquire enq (self->db());
|
||||||
|
|
||||||
if (sortfieldid != MU_MSG_FIELD_ID_NONE)
|
|
||||||
enq.set_sort_by_value
|
|
||||||
((Xapian::valueno)sortfieldid,
|
|
||||||
(flags & MU_QUERY_FLAG_DESCENDING) ? true : false);
|
|
||||||
|
|
||||||
/* empty or "" means "matchall" */
|
/* empty or "" means "matchall" */
|
||||||
if (!mu_str_is_empty(searchexpr) &&
|
if (!mu_str_is_empty(searchexpr) &&
|
||||||
g_strcmp0 (searchexpr, "\"\"") != 0) /* NULL or "" or """" */
|
g_strcmp0 (searchexpr, "\"\"") != 0) /* NULL or "" or """" */
|
||||||
@ -380,24 +394,83 @@ get_enquire (MuQuery *self, const char *searchexpr, MuMsgFieldId sortfieldid,
|
|||||||
return enq;
|
return enq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
static MuMsgIterFlags
|
* record all threadids for the messages
|
||||||
msg_iter_flags (MuQueryFlags flags)
|
*/
|
||||||
|
static GHashTable*
|
||||||
|
get_thread_ids (MuMsgIter *iter)
|
||||||
{
|
{
|
||||||
MuMsgIterFlags iflags;
|
GHashTable *ids;
|
||||||
|
|
||||||
iflags = MU_MSG_ITER_FLAG_NONE;
|
ids = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||||
|
(GDestroyNotify)g_free, NULL);
|
||||||
|
|
||||||
if (flags & MU_QUERY_FLAG_THREADS)
|
while (!mu_msg_iter_is_done (iter)) {
|
||||||
iflags |= MU_MSG_ITER_FLAG_THREADS;
|
const char *thread_id;
|
||||||
if (flags & MU_QUERY_FLAG_DESCENDING)
|
if ((thread_id = mu_msg_iter_get_thread_id (iter)))
|
||||||
iflags |= MU_MSG_ITER_FLAG_DESCENDING;
|
g_hash_table_insert (ids, g_strdup (thread_id),
|
||||||
if (flags & MU_QUERY_FLAG_SKIP_UNREADABLE)
|
GSIZE_TO_POINTER(TRUE));
|
||||||
iflags |= MU_MSG_ITER_FLAG_SKIP_UNREADABLE;
|
// g_print ("tid:'%s'\n", thread_id ? thread_id : "<none>");
|
||||||
if (flags & MU_QUERY_FLAG_SKIP_DUPS)
|
|
||||||
iflags |= MU_MSG_ITER_FLAG_SKIP_DUPS;
|
|
||||||
|
|
||||||
return iflags;
|
if (!mu_msg_iter_next (iter))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Xapian::Query
|
||||||
|
get_related_query (MuMsgIter *iter)
|
||||||
|
{
|
||||||
|
GHashTable *hash;
|
||||||
|
GList *id_list, *cur;
|
||||||
|
Xapian::Query query;
|
||||||
|
static std::string pfx (1, mu_msg_field_xapian_prefix
|
||||||
|
(MU_MSG_FIELD_ID_THREAD_ID));
|
||||||
|
|
||||||
|
hash = get_thread_ids (iter);
|
||||||
|
/* id_list now gets a list of all thread-ids seen in the query
|
||||||
|
* results; either in the Message-Id field or in
|
||||||
|
* References. */
|
||||||
|
id_list = g_hash_table_get_keys (hash);
|
||||||
|
|
||||||
|
/* now, let's create a new query matching all of those */
|
||||||
|
// g_print ("list: %u\n", (unsigned) g_list_length (id_list));
|
||||||
|
for (cur = id_list; cur; cur = g_list_next(cur)) {
|
||||||
|
query = Xapian::Query (Xapian::Query::OP_OR,
|
||||||
|
query,
|
||||||
|
Xapian::Query((std::string
|
||||||
|
(pfx + (char*)cur->data))));
|
||||||
|
}
|
||||||
|
|
||||||
|
g_hash_table_destroy (hash);
|
||||||
|
g_list_free (id_list);
|
||||||
|
|
||||||
|
/* now, `query' should match all related messages */
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
include_related (MuQuery *self, MuMsgIter **iter, int maxnum,
|
||||||
|
MuMsgFieldId sortfieldid, MuQueryFlags flags)
|
||||||
|
{
|
||||||
|
Xapian::Enquire enq (self->db());
|
||||||
|
MuMsgIter *rel_iter;
|
||||||
|
|
||||||
|
enq.set_query(get_related_query (*iter));
|
||||||
|
enq.set_cutoff(0,0);
|
||||||
|
|
||||||
|
rel_iter= mu_msg_iter_new (
|
||||||
|
reinterpret_cast<XapianEnquire*>(&enq),
|
||||||
|
maxnum,
|
||||||
|
sortfieldid,
|
||||||
|
msg_iter_flags (flags),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
mu_msg_iter_destroy (*iter);
|
||||||
|
*iter = rel_iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -412,21 +485,24 @@ mu_query_run (MuQuery *self, const char* searchexpr, MuMsgFieldId sortfieldid,
|
|||||||
NULL);
|
NULL);
|
||||||
try {
|
try {
|
||||||
MuMsgIter *iter;
|
MuMsgIter *iter;
|
||||||
|
bool descending = flags & MU_QUERY_FLAG_DESCENDING;
|
||||||
Xapian::Enquire enq (get_enquire(self, searchexpr, sortfieldid,
|
Xapian::Enquire enq (get_enquire(self, searchexpr, sortfieldid,
|
||||||
flags, err));
|
descending, err));
|
||||||
|
|
||||||
/* get the 'real' maxnum if it was specified as < 0 */
|
/* get the 'real' maxnum if it was specified as < 0 */
|
||||||
maxnum = maxnum <= 0 ? self->db().get_doccount() : maxnum;
|
maxnum = maxnum <= 0 ? self->db().get_doccount() : maxnum;
|
||||||
|
|
||||||
iter = mu_msg_iter_new (
|
iter = mu_msg_iter_new (
|
||||||
reinterpret_cast<XapianEnquire*>(&enq),
|
reinterpret_cast<XapianEnquire*>(&enq),
|
||||||
maxnum,
|
maxnum,
|
||||||
/* in we were *not* using threads, no further sorting
|
sortfieldid,
|
||||||
* is needed since Xapian already sorted */
|
|
||||||
(flags & MU_QUERY_FLAG_THREADS)
|
|
||||||
? sortfieldid : MU_MSG_FIELD_ID_NONE,
|
|
||||||
msg_iter_flags (flags),
|
msg_iter_flags (flags),
|
||||||
err);
|
err);
|
||||||
|
/*
|
||||||
|
* if we want related messages, do a second query,
|
||||||
|
* based on the message ids / refs of the first one
|
||||||
|
* */
|
||||||
|
if (flags & MU_QUERY_FLAG_INCLUDE_RELATED)
|
||||||
|
include_related (self, &iter, maxnum, sortfieldid, flags);
|
||||||
|
|
||||||
if (err && *err && (*err)->code == MU_ERROR_XAPIAN_MODIFIED) {
|
if (err && *err && (*err)->code == MU_ERROR_XAPIAN_MODIFIED) {
|
||||||
g_clear_error (err);
|
g_clear_error (err);
|
||||||
|
|||||||
@ -68,11 +68,10 @@ char* mu_query_version (MuQuery *store)
|
|||||||
enum _MuQueryFlags {
|
enum _MuQueryFlags {
|
||||||
MU_QUERY_FLAG_NONE = 0,
|
MU_QUERY_FLAG_NONE = 0,
|
||||||
|
|
||||||
MU_QUERY_FLAG_THREADS = 1 << 0, /**< add threading info */
|
MU_QUERY_FLAG_DESCENDING = 1 << 0, /**< sort z->a */
|
||||||
MU_QUERY_FLAG_DESCENDING = 1 << 1, /**< sort z->a */
|
MU_QUERY_FLAG_SKIP_UNREADABLE = 1 << 1, /**< skip unreadable msgs */
|
||||||
MU_QUERY_FLAG_SKIP_UNREADABLE = 1 << 2, /**< skip unreadable msgs */
|
MU_QUERY_FLAG_SKIP_DUPS = 1 << 2, /**< skip duplicate msgs */
|
||||||
MU_QUERY_FLAG_SKIP_DUPS = 1 << 3, /**< skip duplicate msgs */
|
MU_QUERY_FLAG_INCLUDE_RELATED = 1 << 3 /**< include related msgs */
|
||||||
MU_QUERY_FLAG_INCLUDE_RELATED = 1 << 4 /**< include related msgs */
|
|
||||||
};
|
};
|
||||||
typedef enum _MuQueryFlags MuQueryFlags;
|
typedef enum _MuQueryFlags MuQueryFlags;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user