File indexing completed on 2024-05-19 05:11:52

0001 /*
0002  * This file is part of the KDE Akonadi Search Project
0003  * SPDX-FileCopyrightText: 2014 Christian Mollekopf <mollekopf@kolabsys.com>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006  *
0007  */
0008 
0009 #include <xapian.h>
0010 
0011 #include "akonadi_search_pim_debug.h"
0012 #include "collectionquery.h"
0013 #include "resultiterator_p.h"
0014 #include <QFile>
0015 #include <QList>
0016 
0017 #include <QStandardPaths>
0018 
0019 using namespace Akonadi::Search::PIM;
0020 
0021 class Akonadi::Search::PIM::CollectionQueryPrivate
0022 {
0023 public:
0024     QStringList ns;
0025     QStringList mimeType;
0026     QString nameString;
0027     QString identifierString;
0028     QString pathString;
0029     QString databaseDir;
0030     int limit;
0031 };
0032 
0033 CollectionQuery::CollectionQuery()
0034     : Query()
0035     , d(new CollectionQueryPrivate)
0036 {
0037     d->databaseDir = defaultLocation(QStringLiteral("collections"));
0038     d->limit = 0;
0039 }
0040 
0041 CollectionQuery::~CollectionQuery() = default;
0042 
0043 void CollectionQuery::setDatabaseDir(const QString &dir)
0044 {
0045     d->databaseDir = dir;
0046 }
0047 
0048 void CollectionQuery::nameMatches(const QString &match)
0049 {
0050     d->nameString = match;
0051 }
0052 
0053 void CollectionQuery::identifierMatches(const QString &match)
0054 {
0055     d->identifierString = match;
0056 }
0057 
0058 void CollectionQuery::pathMatches(const QString &match)
0059 {
0060     d->pathString = match;
0061 }
0062 
0063 void CollectionQuery::setNamespace(const QStringList &ns)
0064 {
0065     d->ns = ns;
0066 }
0067 
0068 void CollectionQuery::setMimetype(const QStringList &mt)
0069 {
0070     d->mimeType = mt;
0071 }
0072 
0073 void CollectionQuery::setLimit(int limit)
0074 {
0075     d->limit = limit;
0076 }
0077 
0078 ResultIterator CollectionQuery::exec()
0079 {
0080     Xapian::Database db;
0081     try {
0082         db = Xapian::Database(QFile::encodeName(d->databaseDir).toStdString());
0083     } catch (const Xapian::DatabaseError &e) {
0084         qCWarning(AKONADI_SEARCH_PIM_LOG) << "Failed to open Xapian database:" << d->databaseDir << "; error:" << QString::fromStdString(e.get_error_string());
0085         return {};
0086     }
0087 
0088     QList<Xapian::Query> queries;
0089 
0090     if (!d->nameString.isEmpty()) {
0091         // qDebug() << "searching by name";
0092         Xapian::QueryParser parser;
0093         parser.set_database(db);
0094         parser.add_prefix("", "N");
0095         parser.set_default_op(Xapian::Query::OP_AND);
0096         queries << parser.parse_query(d->nameString.toStdString(), Xapian::QueryParser::FLAG_PARTIAL);
0097     }
0098 
0099     if (!d->identifierString.isEmpty()) {
0100         Xapian::QueryParser parser;
0101         parser.set_database(db);
0102         parser.add_prefix("", "I");
0103         parser.set_default_op(Xapian::Query::OP_AND);
0104         queries << parser.parse_query(d->identifierString.toStdString(), Xapian::QueryParser::FLAG_PARTIAL);
0105     }
0106 
0107     if (!d->pathString.isEmpty()) {
0108         Xapian::QueryParser parser;
0109         parser.set_database(db);
0110         parser.add_prefix("", "P");
0111         parser.set_default_op(Xapian::Query::OP_AND);
0112         queries << parser.parse_query(d->pathString.toStdString(), Xapian::QueryParser::FLAG_PARTIAL | Xapian::QueryParser::FLAG_PHRASE);
0113     }
0114 
0115     if (!d->ns.isEmpty()) {
0116         QList<Xapian::Query> queryList;
0117         queryList.reserve(d->ns.count());
0118         for (const QString &n : std::as_const(d->ns)) {
0119             const QByteArray term = "NS" + n.toUtf8();
0120             queryList << Xapian::Query(term.constData());
0121         }
0122         queries << Xapian::Query(Xapian::Query::OP_OR, queryList.begin(), queryList.end());
0123     }
0124 
0125     if (!d->mimeType.isEmpty()) {
0126         QList<Xapian::Query> queryList;
0127         queryList.reserve(d->mimeType.count());
0128         for (const QString &n : std::as_const(d->mimeType)) {
0129             const QByteArray term = "M" + n.toUtf8();
0130             queryList << Xapian::Query(term.constData());
0131         }
0132         queries << Xapian::Query(Xapian::Query::OP_OR, queryList.begin(), queryList.end());
0133     }
0134 
0135     Xapian::Query query = Xapian::Query(Xapian::Query::OP_AND, queries.begin(), queries.end());
0136 
0137     if (d->limit == 0) {
0138         d->limit = 1000000;
0139     }
0140 
0141     Xapian::Enquire enquire(db);
0142     enquire.set_query(query);
0143 
0144     Xapian::MSet mset = enquire.get_mset(0, d->limit);
0145 
0146     ResultIterator iter;
0147     iter.d->init(mset);
0148     return iter;
0149 }