diff --git a/autotests/unit/lib/advancedqueryparsertest.cpp b/autotests/unit/lib/advancedqueryparsertest.cpp --- a/autotests/unit/lib/advancedqueryparsertest.cpp +++ b/autotests/unit/lib/advancedqueryparsertest.cpp @@ -160,12 +160,11 @@ Term expectedTerm; term = parser.parse(QStringLiteral("modified:2014-12-02")); - expectedTerm = Term(QStringLiteral("modified"), QDate(2014, 12, 02)); + expectedTerm = Term(QStringLiteral("modified"), "2014-12-02"); QCOMPARE(term, expectedTerm); term = parser.parse(QStringLiteral("modified:\"2014-12-02T23:22:1\"")); - expectedTerm = Term(QStringLiteral("modified"), QDateTime(QDate(2014, 12, 02), QTime(23, 22, 1))); - QEXPECT_FAIL("", "AQP cannot handle datetime", Abort); + expectedTerm = Term(QStringLiteral("modified"), "2014-12-02T23:22:1"); QCOMPARE(term, expectedTerm); } @@ -176,27 +175,27 @@ Term expectedTerm; term = parser.parse(QStringLiteral("width:500")); - expectedTerm = Term(QStringLiteral("width"), 500, Term::Equal); + expectedTerm = Term(QStringLiteral("width"), "500", Term::Contains); QCOMPARE(term, expectedTerm); term = parser.parse(QStringLiteral("width=500")); - expectedTerm = Term(QStringLiteral("width"), 500, Term::Equal); + expectedTerm = Term(QStringLiteral("width"), "500", Term::Equal); QCOMPARE(term, expectedTerm); term = parser.parse(QStringLiteral("width<500")); - expectedTerm = Term(QStringLiteral("width"), 500, Term::Less); + expectedTerm = Term(QStringLiteral("width"), "500", Term::Less); QCOMPARE(term, expectedTerm); term = parser.parse(QStringLiteral("width<=500")); - expectedTerm = Term(QStringLiteral("width"), 500, Term::LessEqual); + expectedTerm = Term(QStringLiteral("width"), "500", Term::LessEqual); QCOMPARE(term, expectedTerm); term = parser.parse(QStringLiteral("width>500")); - expectedTerm = Term(QStringLiteral("width"), 500, Term::Greater); + expectedTerm = Term(QStringLiteral("width"), "500", Term::Greater); QCOMPARE(term, expectedTerm); term = parser.parse(QStringLiteral("width>=500")); - expectedTerm = Term(QStringLiteral("width"), 500, Term::GreaterEqual); + expectedTerm = Term(QStringLiteral("width"), "500", Term::GreaterEqual); QCOMPARE(term, expectedTerm); } diff --git a/src/engine/postingdb.h b/src/engine/postingdb.h --- a/src/engine/postingdb.h +++ b/src/engine/postingdb.h @@ -59,6 +59,7 @@ GreaterEqual }; PostingIterator* compIter(const QByteArray& prefix, qlonglong val, Comparator com); + PostingIterator* compIter(const QByteArray& prefix, const QByteArray& val, Comparator com); QVector fetchTermsStartingWith(const QByteArray& term); diff --git a/src/engine/postingdb.cpp b/src/engine/postingdb.cpp --- a/src/engine/postingdb.cpp +++ b/src/engine/postingdb.cpp @@ -281,6 +281,17 @@ return iter(prefix, validate); } +PostingIterator* PostingDB::compIter(const QByteArray& prefix, const QByteArray& comVal, PostingDB::Comparator com) +{ + int prefixLen = prefix.length(); + auto validate = [prefixLen, comVal, com] (const QByteArray& arr) { + auto val = QByteArray::fromRawData(arr.constData() + prefixLen, arr.length() - prefixLen); + return ((com == LessEqual && val <= comVal) || + (com == GreaterEqual && val >= comVal)); + }; + return iter(prefix, validate); +} + QMap PostingDB::toTestMap() const { MDB_cursor* cursor; diff --git a/src/engine/transaction.h b/src/engine/transaction.h --- a/src/engine/transaction.h +++ b/src/engine/transaction.h @@ -73,6 +73,7 @@ PostingIterator* postingIterator(const EngineQuery& query) const; PostingIterator* postingCompIterator(const QByteArray& prefix, qlonglong value, PostingDB::Comparator com) const; + PostingIterator* postingCompIterator(const QByteArray& prefix, const QByteArray& value, PostingDB::Comparator com) const; PostingIterator* mTimeRangeIter(quint32 beginTime, quint32 endTime) const; PostingIterator* docUrlIter(quint64 id) const; diff --git a/src/engine/transaction.cpp b/src/engine/transaction.cpp --- a/src/engine/transaction.cpp +++ b/src/engine/transaction.cpp @@ -401,6 +401,12 @@ return postingDb.compIter(prefix, value, com); } +PostingIterator* Transaction::postingCompIterator(const QByteArray& prefix, const QByteArray& value, PostingDB::Comparator com) const +{ + PostingDB postingDb(m_dbis.postingDbi, m_txn); + return postingDb.compIter(prefix, value, com); +} + PostingIterator* Transaction::mTimeRangeIter(quint32 beginTime, quint32 endTime) const { MTimeDB mTimeDb(m_dbis.mtimeDbi, m_txn); diff --git a/src/lib/advancedqueryparser.cpp b/src/lib/advancedqueryparser.cpp --- a/src/lib/advancedqueryparser.cpp +++ b/src/lib/advancedqueryparser.cpp @@ -97,26 +97,6 @@ tos = Term(tos, op, termInConstruction); } -static QVariant tokenToVariant(const QString& token) -{ - bool okay = false; - int intValue = token.toInt(&okay); - if (okay) { - return QVariant(intValue); - } - - QDate date = QDate::fromString(token, Qt::ISODate); - if (date.isValid() && !date.isNull()) { - QDateTime dateTime = QDateTime::fromString(token, Qt::ISODate); - if (dateTime.isValid() && !dateTime.isNull()) { - return dateTime; - } - return date; - } - - return token; -} - Term AdvancedQueryParser::parse(const QString& text) { // The parser does not do any look-ahead but has to store some state @@ -142,14 +122,7 @@ } termInConstruction.setProperty(property); - QVariant value = tokenToVariant(token); - if (value.type() != QVariant::String) { - if (termInConstruction.comparator() == Term::Contains) { - termInConstruction.setComparator(Term::Equal); - } - } - - termInConstruction.setValue(value); + termInConstruction.setValue(token); valueExpected = false; continue; } diff --git a/src/lib/searchstore.h b/src/lib/searchstore.h --- a/src/lib/searchstore.h +++ b/src/lib/searchstore.h @@ -25,7 +25,6 @@ #include #include -#include #include "term.h" namespace Baloo { @@ -45,10 +44,7 @@ QStringList exec(const Term& term, uint offset, int limit, bool sortResults); private: - QByteArray fetchPrefix(const QByteArray& property) const; - Database* m_db; - QHash m_prefixes; PostingIterator* constructQuery(Transaction* tr, const Term& term); diff --git a/src/lib/searchstore.cpp b/src/lib/searchstore.cpp --- a/src/lib/searchstore.cpp +++ b/src/lib/searchstore.cpp @@ -24,6 +24,7 @@ #include "searchstore.h" #include "term.h" #include "global.h" +#include "baloodebug.h" #include "database.h" #include "transaction.h" @@ -34,7 +35,6 @@ #include "orpostingiterator.h" #include "idutils.h" -#include #include #include @@ -45,7 +45,7 @@ #include #include -using namespace Baloo; +namespace Baloo { namespace { QPair calculateTimeRange(const QDateTime& dt, Term::Comparator com) @@ -73,6 +73,36 @@ Q_ASSERT_X(0, __func__, "mtime query must contain a valid comparator"); return {0, 0}; } + +struct InternalProperty { + const char* propertyName; + const char* prefix; + QVariant::Type valueType; +}; +constexpr std::array internalProperties {{ + { "filename", "F", QVariant::String }, + { "mimetype", "M", QVariant::String }, + { "rating", "R", QVariant::Int }, + { "tag", "TAG-", QVariant::String }, + { "tags", "TA", QVariant::String }, + { "usercomment", "C", QVariant::String } +}}; + +std::pair propertyInfo(const QByteArray& property) +{ + auto it = std::find_if(std::begin(internalProperties), std::end(internalProperties), + [&property] (const InternalProperty& entry) { return property == entry.propertyName; }); + if (it != std::end(internalProperties)) { + return { (*it).prefix, (*it).valueType }; + } else { + KFileMetaData::PropertyInfo pi = KFileMetaData::PropertyInfo::fromName(property); + if (pi.property() == KFileMetaData::Property::Empty) { + return { QByteArray(), QVariant::Invalid }; + } + int propPrefix = static_cast(pi.property()); + return { 'X' + QByteArray::number(propPrefix) + '-', pi.valueType() }; + } +} } SearchStore::SearchStore() @@ -82,13 +112,6 @@ if (!m_db->open(Database::ReadOnlyDatabase)) { m_db = nullptr; } - - m_prefixes.insert(QByteArray("filename"), QByteArray("F")); - m_prefixes.insert(QByteArray("mimetype"), QByteArray("M")); - m_prefixes.insert(QByteArray("rating"), QByteArray("R")); - m_prefixes.insert(QByteArray("tag"), QByteArray("TAG-")); - m_prefixes.insert(QByteArray("tags"), QByteArray("TA")); - m_prefixes.insert(QByteArray("usercomment"), QByteArray("C")); } SearchStore::~SearchStore() @@ -167,23 +190,6 @@ } } -QByteArray SearchStore::fetchPrefix(const QByteArray& property) const -{ - auto it = m_prefixes.constFind(property.toLower()); - if (it != m_prefixes.constEnd()) { - return it.value(); - } - else { - KFileMetaData::PropertyInfo pi = KFileMetaData::PropertyInfo::fromName(property); - if (pi.property() == KFileMetaData::Property::Empty) { - qDebug() << "Property" << property << "not found"; - return QByteArray(); - } - int propPrefix = static_cast(pi.property()); - return 'X' + QByteArray::number(propPrefix) + '-'; - } -} - PostingIterator* SearchStore::constructQuery(Transaction* tr, const Term& term) { Q_ASSERT(tr); @@ -251,6 +257,7 @@ } else if (property == "modified" || property == "mtime") { if (value.type() == QVariant::ByteArray) { + // Used by Baloo::Query QByteArray ba = value.toByteArray(); Q_ASSERT(ba.size() >= 4); @@ -275,7 +282,7 @@ return tr->mTimeRangeIter(QDateTime(startDate).toSecsSinceEpoch(), QDateTime(endDate, QTime(23, 59, 59)).toSecsSinceEpoch()); } - else if (value.type() == QVariant::Date || value.type() == QVariant::DateTime) { + else if (value.type() == QVariant::String) { const QDateTime dt = value.toDateTime(); QPair timerange = calculateTimeRange(dt, term.comparator()); if ((timerange.first == 0) && (timerange.second == 0)) { @@ -303,14 +310,18 @@ } QByteArray prefix; + QVariant::Type valueType = QVariant::String; if (!property.isEmpty()) { - prefix = fetchPrefix(property); + std::tie(prefix, valueType) = propertyInfo(property); if (prefix.isEmpty()) { return nullptr; } } auto com = term.comparator(); + if (com == Term::Contains && valueType == QVariant::Int) { + com = Term::Equal; + } if (com == Term::Contains) { EngineQuery q = constructContainsQuery(prefix, value.toString()); return tr->postingIterator(q); @@ -321,27 +332,31 @@ return tr->postingIterator(q); } - QVariant val = term.value(); - if (val.type() == QVariant::Int) { + PostingDB::Comparator pcom; + if (com == Term::Greater || com == Term::GreaterEqual) { + pcom = PostingDB::GreaterEqual; + } else if (com == Term::Less || com == Term::LessEqual) { + pcom = PostingDB::LessEqual; + } + + // FIXME -- has to be kept in sync with the code from + // Baloo::Result::add + if (valueType == QVariant::Int) { qlonglong intVal = value.toLongLong(); - PostingDB::Comparator pcom; - if (term.comparator() == Term::Greater || term.comparator() == Term::GreaterEqual) { - pcom = PostingDB::GreaterEqual; - if (term.comparator() == Term::Greater && intVal) - intVal++; - } - else if (term.comparator() == Term::Less || term.comparator() == Term::LessEqual) { - pcom = PostingDB::LessEqual; - if (term.comparator() == Term::Less) - intVal--; - } - else { - Q_ASSERT(0); - return nullptr; + if (term.comparator() == Term::Greater) { + intVal++; + } else if (term.comparator() == Term::Less) { + intVal--; } return tr->postingCompIterator(prefix, intVal, pcom); + + } else if (valueType == QVariant::DateTime) { + QDateTime dt = value.toDateTime(); + const QByteArray ba = dt.toString(Qt::ISODate).toUtf8(); + return tr->postingCompIterator(prefix, ba, pcom); + } else { qCDebug(BALOO) << "Comparison must be with an integer"; } @@ -396,4 +411,4 @@ return EngineQuery('T' + QByteArray::number(num)); } - +} // namespace Baloo