From e0cada86d692756ca57cd8eaee025a566c9e4794 Mon Sep 17 00:00:00 2001 From: "Dirk-Jan C. Binnema" Date: Sun, 21 Nov 2010 18:12:01 +0200 Subject: [PATCH] * add date-range searches using date:/d: --- man/mu-find.1 | 11 +++++++++ src/mu-msg-fields.c | 2 +- src/mu-msg-fields.h | 9 ++++--- src/mu-query.cc | 40 ++++++++++++++++++++++++++----- src/mu-store.cc | 57 ++++++++++++++++++++++++++++----------------- 5 files changed, 88 insertions(+), 31 deletions(-) diff --git a/man/mu-find.1 b/man/mu-find.1 index dc5e850c..c72ec82d 100644 --- a/man/mu-find.1 +++ b/man/mu-find.1 @@ -104,6 +104,7 @@ search fields and their abbreviations: msgid,i Message-ID prio,p Message priority ('low', 'normal' or 'high') flag,g Message Flags + date,d Date-Range .fi For clarity, this man-page uses the longer versions. @@ -159,6 +160,16 @@ can do with a single '/': (and of course you can use the \fBm:\fR shortcut instead of \fBmaildir:\fR) +The date:/d: search parameter is 'special' in the fact that it takes a range +of dates. For now, these dates are in ISO 8601 format (YYYYMMDD). To get all +messages between (inclusive) the 5th of May 2009 and the 2nd of June 2010, you +could use: + +.nf + mu find date:20090505..20100602 +.fi + + .SH OPTIONS Note, some of the important options are described in the \fBmu(1)\fR man-page diff --git a/src/mu-msg-fields.c b/src/mu-msg-fields.c index 6062206e..2bb948d5 100644 --- a/src/mu-msg-fields.c +++ b/src/mu-msg-fields.c @@ -81,7 +81,7 @@ static const MuMsgField FIELD_DATA[] = { MU_MSG_FIELD_ID_DATE, MU_MSG_FIELD_TYPE_TIME_T, "date", 'd', 'D', - FLAG_GMIME | FLAG_XAPIAN_VALUE + FLAG_GMIME | FLAG_XAPIAN_TERM | FLAG_XAPIAN_VALUE }, { diff --git a/src/mu-msg-fields.h b/src/mu-msg-fields.h index 18f515a5..f0daae38 100644 --- a/src/mu-msg-fields.h +++ b/src/mu-msg-fields.h @@ -41,12 +41,15 @@ enum _MuMsgFieldId { MU_MSG_FIELD_ID_TO, MU_MSG_FIELD_ID_MSGID, MU_MSG_FIELD_ID_TIMESTAMP, - + MU_MSG_FIELD_ID_NUM }; +typedef enum _MuMsgFieldId MuMsgFieldId; -static const guint MU_MSG_FIELD_ID_NONE = (guint)-1; -typedef guint MuMsgFieldId; +/* some specials... */ +static const MuMsgFieldId MU_MSG_FIELD_ID_NONE = (MuMsgFieldId)-1; +static const MuMsgFieldId MU_MSG_FIELD_ID_DATESTR = + (MuMsgFieldId) (MU_MSG_FIELD_ID_NUM + 1); #define mu_msg_field_id_is_valid(MFID) \ ((MFID) < MU_MSG_FIELD_ID_NUM) diff --git a/src/mu-query.cc b/src/mu-query.cc index 7a0e93ba..1666cde9 100644 --- a/src/mu-query.cc +++ b/src/mu-query.cc @@ -1,4 +1,4 @@ -/* +make/* ** Copyright (C) 2008-2010 Dirk-Jan C. Binnema ** ** This program is free software; you can redistribute it and/or modify @@ -32,12 +32,36 @@ #include "mu-util-db.h" #include "mu-msg-str.h" + +struct ISODateRangeProcessor : public Xapian::ValueRangeProcessor { + ISODateRangeProcessor() {} + + Xapian::valueno operator()(std::string &begin, std::string &end) { + static const std::string colon (":"); + static const std::string name ( + mu_msg_field_name (MU_MSG_FIELD_ID_DATE) + colon); + static const std::string shortcut ( + std::string(1, mu_msg_field_shortcut + (MU_MSG_FIELD_ID_DATE)) + colon); + + if (begin.find (name) == 0) + begin.erase (0, name.length()); + else if (begin.find (shortcut) == 0) + begin.erase (0, shortcut.length()); + else + return Xapian::BAD_VALUENO; + + return (Xapian::valueno)MU_MSG_FIELD_ID_DATESTR; + } +}; + static void add_prefix (MuMsgFieldId field, Xapian::QueryParser* qparser); struct _MuQuery { - Xapian::Database* _db; - Xapian::QueryParser* _qparser; - Xapian::Sorter* _sorters[MU_MSG_FIELD_TYPE_NUM]; + Xapian::Database* _db; + Xapian::QueryParser* _qparser; + Xapian::Sorter* _sorters[MU_MSG_FIELD_TYPE_NUM]; + Xapian::ValueRangeProcessor* _range_processor; }; gboolean @@ -52,8 +76,11 @@ init_mu_query (MuQuery *mqx, const char* dbpath) mqx->_qparser->set_database (*mqx->_db); mqx->_qparser->set_default_op (Xapian::Query::OP_AND); - //mqx->_qparser->set_stemming_strategy (Xapian::QueryParser::STEM_NONE); + mqx->_range_processor = new ISODateRangeProcessor (); + mqx->_qparser->add_valuerangeprocessor + (mqx->_range_processor); + memset (mqx->_sorters, 0, sizeof(mqx->_sorters)); mu_msg_field_foreach ((MuMsgFieldForEachFunc)add_prefix, (gpointer)mqx->_qparser); @@ -88,7 +115,8 @@ uninit_mu_query (MuQuery *mqx) try { delete mqx->_db; delete mqx->_qparser; - + delete mqx->_range_processor; + for (int i = 0; i != MU_MSG_FIELD_TYPE_NUM; ++i) delete mqx->_sorters[i]; diff --git a/src/mu-store.cc b/src/mu-store.cc index 86083708..f41dcf41 100644 --- a/src/mu-store.cc +++ b/src/mu-store.cc @@ -266,6 +266,24 @@ mu_store_flush (MuStore *store) } +static void +add_terms_values_date (Xapian::Document& doc, MuMsg *msg, + MuMsgFieldId mfid) +{ + char datebuf[9]; + static const std::string pfx (1, mu_msg_field_xapian_prefix(mfid)); + gint64 num = mu_msg_get_field_numeric (msg, mfid); + + if (G_UNLIKELY(strftime(datebuf, sizeof(datebuf), "%Y%m%d", + gmtime((const time_t*)&num)) == 0)) + g_return_if_reached(); + + const std::string numstr (Xapian::sortable_serialise((double)num)); + doc.add_value ((Xapian::valueno)mfid, numstr); + doc.add_value ((Xapian::valueno)MU_MSG_FIELD_ID_DATESTR, datebuf); +} + + static void add_terms_values_number (Xapian::Document& doc, MuMsg *msg, MuMsgFieldId mfid) @@ -288,6 +306,7 @@ add_terms_values_number (Xapian::Document& doc, MuMsg *msg, } else if (mfid == MU_MSG_FIELD_ID_PRIO) { doc.add_term (pfx + std::string(1, mu_msg_prio_char((MuMsgPrio)num))); + } else doc.add_term (pfx + numstr); } @@ -364,36 +383,32 @@ typedef struct _MsgDoc MsgDoc; static void add_terms_values (MuMsgFieldId mfid, MsgDoc* msgdoc) { - MuMsgFieldType type; - /* note: contact-stuff (To/Cc/From) will handled in * add_contact_info, not here */ if (!mu_msg_field_xapian_index(mfid) && !mu_msg_field_xapian_term(mfid) && !mu_msg_field_xapian_value(mfid)) return; - - type = mu_msg_field_type (mfid); - if (type == MU_MSG_FIELD_TYPE_STRING) { - if (mfid == MU_MSG_FIELD_ID_BODY_TEXT) - add_terms_values_body (*msgdoc->_doc, msgdoc->_msg, - mfid); + switch (mfid) { + case MU_MSG_FIELD_ID_DATE: + add_terms_values_date (*msgdoc->_doc, msgdoc->_msg, mfid); + break; + case MU_MSG_FIELD_ID_BODY_TEXT: + add_terms_values_body (*msgdoc->_doc, msgdoc->_msg, mfid); + break; + default: + if (mu_msg_field_is_numeric (mfid)) + add_terms_values_number (*msgdoc->_doc, msgdoc->_msg, + mfid); + else if (mu_msg_field_type (mfid) == + MU_MSG_FIELD_TYPE_STRING) + add_terms_values_string (*msgdoc->_doc, + msgdoc->_msg, + mfid); else - add_terms_values_string (*msgdoc->_doc, msgdoc->_msg, - mfid); - return; + g_return_if_reached (); } - - if (type == MU_MSG_FIELD_TYPE_BYTESIZE || - type == MU_MSG_FIELD_TYPE_TIME_T || - type == MU_MSG_FIELD_TYPE_INT) { - add_terms_values_number (*msgdoc->_doc, msgdoc->_msg, - mfid); - return; - } - - g_return_if_reached (); }