File indexing completed on 2024-06-23 05:07:03

0001 /***************************************************************************
0002  *   SPDX-FileCopyrightText: 2006 Tobias Koenig <tokoe@kde.org>            *
0003  *   SPDX-FileCopyrightText: 2014 Daniel Vrátil <dvratil@redhat.com>       *
0004  *                                                                         *
0005  *   SPDX-License-Identifier: LGPL-2.0-or-later                            *
0006  ***************************************************************************/
0007 
0008 #include "searchhelper.h"
0009 
0010 #include "entities.h"
0011 #include "storage/countquerybuilder.h"
0012 
0013 #include "private/protocol_p.h"
0014 
0015 using namespace Akonadi::Server;
0016 
0017 static qint64 parentCollectionId(qint64 collectionId)
0018 {
0019     QueryBuilder qb(Collection::tableName(), QueryBuilder::Select);
0020     qb.addColumn(Collection::parentIdColumn());
0021     qb.addValueCondition(Collection::idColumn(), Query::Equals, collectionId);
0022     if (!qb.exec()) {
0023         return -1;
0024     }
0025     if (!qb.query().next()) {
0026         return -1;
0027     }
0028     const auto parentId = qb.query().value(0).toLongLong();
0029     qb.query().finish();
0030     return parentId;
0031 }
0032 
0033 QList<qint64> SearchHelper::matchSubcollectionsByMimeType(const QList<qint64> &ancestors, const QStringList &mimeTypes)
0034 {
0035     // Get all collections with given mime types
0036     QueryBuilder qb(Collection::tableName(), QueryBuilder::Select);
0037     qb.setDistinct(true);
0038     qb.addColumn(Collection::idFullColumnName());
0039     qb.addColumn(Collection::parentIdFullColumnName());
0040     qb.addJoin(QueryBuilder::LeftJoin,
0041                CollectionMimeTypeRelation::tableName(),
0042                CollectionMimeTypeRelation::leftFullColumnName(),
0043                Collection::idFullColumnName());
0044     qb.addJoin(QueryBuilder::LeftJoin, MimeType::tableName(), CollectionMimeTypeRelation::rightFullColumnName(), MimeType::idFullColumnName());
0045     Query::Condition cond(Query::Or);
0046     for (const QString &mt : mimeTypes) {
0047         cond.addValueCondition(MimeType::nameFullColumnName(), Query::Equals, mt);
0048     }
0049     if (!cond.isEmpty()) {
0050         qb.addCondition(cond);
0051     }
0052 
0053     if (!qb.exec()) {
0054         qCWarning(AKONADISERVER_LOG) << "Failed to query search collections";
0055         return QList<qint64>();
0056     }
0057 
0058     QMap<qint64 /* parentId */, QList<qint64> /* collectionIds */> candidateCollections;
0059     while (qb.query().next()) {
0060         candidateCollections[qb.query().value(1).toLongLong()].append(qb.query().value(0).toLongLong());
0061     }
0062     qb.query().finish();
0063 
0064     // If the ancestors list contains root, then return what we got, since everything
0065     // is sub collection of root
0066     QList<qint64> results;
0067     if (ancestors.contains(0)) {
0068         for (const QList<qint64> &res : std::as_const(candidateCollections)) {
0069             results += res;
0070         }
0071         return results;
0072     }
0073 
0074     // Try to resolve direct descendants
0075     for (qint64 ancestor : ancestors) {
0076         const QList<qint64> cols = candidateCollections.take(ancestor);
0077         if (!cols.isEmpty()) {
0078             results += cols;
0079         }
0080     }
0081 
0082     for (auto iter = candidateCollections.begin(), iterEnd = candidateCollections.end(); iter != iterEnd; ++iter) {
0083         // Traverse the collection chain up to root
0084         qint64 parentId = iter.key();
0085         while (!ancestors.contains(parentId) && parentId > 0) {
0086             parentId = parentCollectionId(parentId);
0087         }
0088         // Ok, we found a requested ancestor in the parent chain
0089         if (parentId > 0) {
0090             results += iter.value();
0091         }
0092     }
0093 
0094     return results;
0095 }