File indexing completed on 2024-05-12 05:11:20

0001 /*
0002  * This file is part of the KDE Akonadi Search Project
0003  * SPDX-FileCopyrightText: 2013 Vishesh Handa <me@vhanda.in>
0004  * SPDX-FileCopyrightText: 2014 Christian Mollekopf <mollekopf@kolabsys.com>
0005  *
0006  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007  *
0008  */
0009 #include "pimsearchstore.h"
0010 #include "query.h"
0011 #include "term.h"
0012 
0013 #include <Akonadi/ServerManager>
0014 #include <QDir>
0015 #include <QStandardPaths>
0016 #include <QUrl>
0017 #include <QUrlQuery>
0018 
0019 using namespace Akonadi::Search;
0020 
0021 PIMSearchStore::PIMSearchStore(QObject *parent)
0022     : XapianSearchStore(parent)
0023 {
0024 }
0025 
0026 QStringList PIMSearchStore::types()
0027 {
0028     return QStringList() << QStringLiteral("Akonadi");
0029 }
0030 
0031 QString PIMSearchStore::findDatabase(const QString &dbName) const
0032 {
0033     // First look into the old location from Baloo times in ~/.local/share/baloo,
0034     // because we don't migrate the database files automatically.
0035     QString basePath;
0036     bool hasInstanceIdentifier = Akonadi::ServerManager::hasInstanceIdentifier();
0037     if (hasInstanceIdentifier) {
0038         basePath = QStringLiteral("baloo/instances/%1").arg(Akonadi::ServerManager::instanceIdentifier());
0039     } else {
0040         basePath = QStringLiteral("baloo");
0041     }
0042     QString dbPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/%1/%2/").arg(basePath, dbName);
0043     if (QDir(dbPath).exists()) {
0044         return dbPath;
0045     }
0046 
0047     // If the database does not exist in old Baloo folders, than use the new
0048     // location in Akonadi's datadir in ~/.local/share/akonadi/search_db.
0049     if (hasInstanceIdentifier) {
0050         basePath = QStringLiteral("akonadi/instance/%1/search_db").arg(Akonadi::ServerManager::instanceIdentifier());
0051     } else {
0052         basePath = QStringLiteral("akonadi/search_db");
0053     }
0054     dbPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/%1/%2/").arg(basePath, dbName);
0055     QDir().mkpath(dbPath);
0056     return dbPath;
0057 }
0058 
0059 Xapian::Query PIMSearchStore::constructQuery(const QString &property, const QVariant &value, Term::Comparator com)
0060 {
0061     if (value.isNull()) {
0062         return {};
0063     }
0064 
0065     QString prop = property.toLower();
0066     if (m_boolProperties.contains(prop)) {
0067         QString p = m_prefix.value(prop);
0068         if (p.isEmpty()) {
0069             return {};
0070         }
0071 
0072         std::string term("B");
0073         bool isTrue = false;
0074 
0075         if (value.isNull()) {
0076             isTrue = true;
0077         }
0078         if (value.userType() == QMetaType::Bool) {
0079             isTrue = value.toBool();
0080         }
0081 
0082         if (isTrue) {
0083             term += p.toStdString();
0084         } else {
0085             term += 'N' + p.toStdString();
0086         }
0087 
0088         return Xapian::Query(term);
0089     }
0090 
0091     if (m_boolWithValue.contains(prop)) {
0092         std::string term(m_prefix.value(prop).toStdString());
0093         std::string val(value.toString().toStdString());
0094         return Xapian::Query(term + val);
0095     }
0096 
0097     if (m_valueProperties.contains(prop)
0098         && (com == Term::Equal || com == Term::Greater || com == Term::GreaterEqual || com == Term::Less || com == Term::LessEqual)) {
0099         qlonglong numVal = value.toLongLong();
0100         if (com == Term::Greater) {
0101             ++numVal;
0102         }
0103         if (com == Term::Less) {
0104             --numVal;
0105         }
0106         int valueNumber = m_valueProperties.value(prop);
0107         if (com == Term::GreaterEqual || com == Term::Greater) {
0108             return Xapian::Query(Xapian::Query::OP_VALUE_GE, valueNumber, QString::number(numVal).toStdString());
0109         } else if (com == Term::LessEqual || com == Term::Less) {
0110             return Xapian::Query(Xapian::Query::OP_VALUE_LE, valueNumber, QString::number(numVal).toStdString());
0111         } else if (com == Term::Equal) {
0112             const Xapian::Query gtQuery(Xapian::Query::OP_VALUE_GE, valueNumber, QString::number(numVal).toStdString());
0113             const Xapian::Query ltQuery(Xapian::Query::OP_VALUE_LE, valueNumber, QString::number(numVal).toStdString());
0114             return Xapian::Query(Xapian::Query::OP_AND, gtQuery, ltQuery);
0115         }
0116     } else if ((com == Term::Contains || com == Term::Equal) && m_prefix.contains(prop)) {
0117         Xapian::QueryParser parser;
0118         parser.set_database(*xapianDb());
0119 
0120         std::string p = m_prefix.value(prop).toStdString();
0121         std::string str(value.toString().toStdString());
0122         int flags = Xapian::QueryParser::FLAG_DEFAULT;
0123         if (com == Term::Contains) {
0124             flags |= Xapian::QueryParser::FLAG_PARTIAL;
0125         }
0126         return parser.parse_query(str, flags, p);
0127     }
0128     return Xapian::Query(value.toString().toStdString());
0129 }
0130 
0131 QUrl PIMSearchStore::constructUrl(const Xapian::docid &docid)
0132 {
0133     QUrl url;
0134     url.setScheme(QStringLiteral("akonadi"));
0135 
0136     QUrlQuery query;
0137     query.addQueryItem(QStringLiteral("item"), QString::number(docid));
0138     url.setQuery(query);
0139 
0140     return url;
0141 }
0142 
0143 #include "moc_pimsearchstore.cpp"