|
Rex Dieter |
adf30a |
From 059d52845cbbc10e882764f64245c5995af4e741 Mon Sep 17 00:00:00 2001
|
|
Rex Dieter |
adf30a |
From: =?UTF-8?q?Dan=20Vr=C3=A1til?= <dvratil@redhat.com>
|
|
Rex Dieter |
adf30a |
Date: Mon, 8 Dec 2014 13:49:27 +0100
|
|
Rex Dieter |
adf30a |
Subject: [PATCH 26/30] Avoid recursive collection listing in SearchHelper
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
The recursive listing generates one SQL query per collection, and since search
|
|
Rex Dieter |
adf30a |
is invoked rather often (basically whenever you open an email in KMail), we get
|
|
Rex Dieter |
adf30a |
lots of unnecessary queries. This new algorithm does one query to fetch all
|
|
Rex Dieter |
adf30a |
folders with matching mime types, and only falls back to query the parent chain
|
|
Rex Dieter |
adf30a |
when the requested ancestor is not 0 (root), or when the result collection is
|
|
Rex Dieter |
adf30a |
not a direct descendant of the requested ancestor.
|
|
Rex Dieter |
adf30a |
---
|
|
Rex Dieter |
adf30a |
server/src/handler/search.cpp | 4 +-
|
|
Rex Dieter |
adf30a |
server/src/handler/searchhelper.cpp | 111 ++++++++++++++----------
|
|
Rex Dieter |
adf30a |
server/src/handler/searchhelper.h | 2 +-
|
|
Rex Dieter |
adf30a |
server/src/search/searchmanager.cpp | 2 +-
|
|
Rex Dieter |
adf30a |
server/tests/unittest/CMakeLists.txt | 2 +
|
|
Rex Dieter |
adf30a |
server/tests/unittest/searchtest.cpp | 158 +++++++++++++++++++++++++++++++++++
|
|
Rex Dieter |
adf30a |
6 files changed, 230 insertions(+), 49 deletions(-)
|
|
Rex Dieter |
adf30a |
create mode 100644 server/tests/unittest/searchtest.cpp
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
diff --git a/server/src/handler/search.cpp b/server/src/handler/search.cpp
|
|
Rex Dieter |
adf30a |
index 06d172f..00484ff 100644
|
|
Rex Dieter |
adf30a |
--- a/server/src/handler/search.cpp
|
|
Rex Dieter |
adf30a |
+++ b/server/src/handler/search.cpp
|
|
Rex Dieter |
adf30a |
@@ -95,9 +95,7 @@ bool Search::parseStream()
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
if ( recursive ) {
|
|
Rex Dieter |
adf30a |
- Q_FOREACH ( qint64 collection, collectionIds ) {
|
|
Rex Dieter |
adf30a |
- collections << SearchHelper::listCollectionsRecursive( QVector<qint64>() << collection, mimeTypes );
|
|
Rex Dieter |
adf30a |
- }
|
|
Rex Dieter |
adf30a |
+ collections << SearchHelper::matchSubcollectionsByMimeType( collectionIds, mimeTypes );
|
|
Rex Dieter |
adf30a |
} else {
|
|
Rex Dieter |
adf30a |
collections = collectionIds;
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
diff --git a/server/src/handler/searchhelper.cpp b/server/src/handler/searchhelper.cpp
|
|
Rex Dieter |
adf30a |
index aa6694d..1a06c0e 100644
|
|
Rex Dieter |
adf30a |
--- a/server/src/handler/searchhelper.cpp
|
|
Rex Dieter |
adf30a |
+++ b/server/src/handler/searchhelper.cpp
|
|
Rex Dieter |
adf30a |
@@ -20,6 +20,7 @@
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
#include "searchhelper.h"
|
|
Rex Dieter |
adf30a |
#include "storage/countquerybuilder.h"
|
|
Rex Dieter |
adf30a |
+#include <storage/queryhelper.h>
|
|
Rex Dieter |
adf30a |
#include "entities.h"
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
#include <libs/protocol_p.h>
|
|
Rex Dieter |
adf30a |
@@ -89,55 +90,77 @@ QString SearchHelper::extractMimetype( const QList<QByteArray> &junks, int start
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
-QVector<qint64> SearchHelper::listCollectionsRecursive( const QVector<qint64> &ancestors, const QStringList &mimeTypes )
|
|
Rex Dieter |
adf30a |
+static qint64 parentCollectionId(qint64 collectionId)
|
|
Rex Dieter |
adf30a |
{
|
|
Rex Dieter |
adf30a |
- QVector<qint64> recursiveChildren;
|
|
Rex Dieter |
adf30a |
- Q_FOREACH ( qint64 ancestor, ancestors ) {
|
|
Rex Dieter |
adf30a |
- QVector<qint64> searchChildren;
|
|
Rex Dieter |
adf30a |
-
|
|
Rex Dieter |
adf30a |
- { // Free the query before entering recursion to prevent too many opened connections
|
|
Rex Dieter |
adf30a |
-
|
|
Rex Dieter |
adf30a |
- Query::Condition mimeTypeCondition;
|
|
Rex Dieter |
adf30a |
- mimeTypeCondition.addColumnCondition( CollectionMimeTypeRelation::rightFullColumnName(), Query::Equals, MimeType::idFullColumnName() );
|
|
Rex Dieter |
adf30a |
- // Exclude top-level collections and collections that cannot have items!
|
|
Rex Dieter |
adf30a |
- mimeTypeCondition.addValueCondition( MimeType::nameFullColumnName(), Query::NotEquals, QLatin1String( "inode/directory" ) );
|
|
Rex Dieter |
adf30a |
- if ( !mimeTypes.isEmpty() ) {
|
|
Rex Dieter |
adf30a |
- mimeTypeCondition.addValueCondition( MimeType::nameFullColumnName(), Query::In, mimeTypes );
|
|
Rex Dieter |
adf30a |
- }
|
|
Rex Dieter |
adf30a |
+ QueryBuilder qb(Collection::tableName(), QueryBuilder::Select);
|
|
Rex Dieter |
adf30a |
+ qb.addColumn(Collection::parentIdColumn());
|
|
Rex Dieter |
adf30a |
+ qb.addValueCondition(Collection::idColumn(), Query::Equals, collectionId);
|
|
Rex Dieter |
adf30a |
+ if (!qb.exec()) {
|
|
Rex Dieter |
adf30a |
+ return -1;
|
|
Rex Dieter |
adf30a |
+ }
|
|
Rex Dieter |
adf30a |
+ if (!qb.query().next()) {
|
|
Rex Dieter |
adf30a |
+ return -1;
|
|
Rex Dieter |
adf30a |
+ }
|
|
Rex Dieter |
adf30a |
+ return qb.query().value(0).toLongLong();
|
|
Rex Dieter |
adf30a |
+}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
- CountQueryBuilder qb( Collection::tableName(), MimeType::nameFullColumnName(), CountQueryBuilder::All );
|
|
Rex Dieter |
adf30a |
- qb.addColumn( Collection::idFullColumnName() );
|
|
Rex Dieter |
adf30a |
- qb.addJoin( QueryBuilder::LeftJoin, CollectionMimeTypeRelation::tableName(), CollectionMimeTypeRelation::leftFullColumnName(), Collection::idFullColumnName() );
|
|
Rex Dieter |
adf30a |
- qb.addJoin( QueryBuilder::LeftJoin, MimeType::tableName(), mimeTypeCondition );
|
|
Rex Dieter |
adf30a |
- if ( ancestor == 0 ) {
|
|
Rex Dieter |
adf30a |
- qb.addValueCondition( Collection::parentIdFullColumnName(), Query::Is, QVariant() );
|
|
Rex Dieter |
adf30a |
- } else {
|
|
Rex Dieter |
adf30a |
- // Also include current ancestor's result, so that we know whether we should search in the ancestor too
|
|
Rex Dieter |
adf30a |
- Query::Condition idCond( Query::Or );
|
|
Rex Dieter |
adf30a |
- idCond.addValueCondition( Collection::parentIdFullColumnName(), Query::Equals, ancestor );
|
|
Rex Dieter |
adf30a |
- idCond.addValueCondition( Collection::idFullColumnName(), Query::Equals, ancestor );
|
|
Rex Dieter |
adf30a |
- qb.addCondition( idCond );
|
|
Rex Dieter |
adf30a |
- }
|
|
Rex Dieter |
adf30a |
- qb.addValueCondition( Collection::isVirtualFullColumnName(), Query::Equals, false );
|
|
Rex Dieter |
adf30a |
- qb.addGroupColumn( Collection::idFullColumnName() );
|
|
Rex Dieter |
adf30a |
- qb.exec();
|
|
Rex Dieter |
adf30a |
-
|
|
Rex Dieter |
adf30a |
- QSqlQuery query = qb.query();
|
|
Rex Dieter |
adf30a |
- while ( query.next() ) {
|
|
Rex Dieter |
adf30a |
- const qint64 id = query.value( 1 ).toLongLong();
|
|
Rex Dieter |
adf30a |
- // Don't add ancestor into search children, we are resolving it right now
|
|
Rex Dieter |
adf30a |
- if ( id != ancestor ) {
|
|
Rex Dieter |
adf30a |
- searchChildren << id;
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+QVector<qint64> SearchHelper::matchSubcollectionsByMimeType(const QVector<qint64> &ancestors, const QStringList &mimeTypes)
|
|
Rex Dieter |
adf30a |
+{
|
|
Rex Dieter |
adf30a |
+ // Get all collections with given mime types
|
|
Rex Dieter |
adf30a |
+ QueryBuilder qb(Collection::tableName(), QueryBuilder::Select);
|
|
Rex Dieter |
adf30a |
+ qb.setDistinct(true);
|
|
Rex Dieter |
adf30a |
+ qb.addColumn(Collection::idFullColumnName());
|
|
Rex Dieter |
adf30a |
+ qb.addColumn(Collection::parentIdFullColumnName());
|
|
Rex Dieter |
adf30a |
+ qb.addJoin(QueryBuilder::LeftJoin, CollectionMimeTypeRelation::tableName(),
|
|
Rex Dieter |
adf30a |
+ CollectionMimeTypeRelation::leftFullColumnName(), Collection::idFullColumnName());
|
|
Rex Dieter |
adf30a |
+ qb.addJoin(QueryBuilder::LeftJoin, MimeType::tableName(),
|
|
Rex Dieter |
adf30a |
+ CollectionMimeTypeRelation::rightFullColumnName(), MimeType::idFullColumnName());
|
|
Rex Dieter |
adf30a |
+ Query::Condition cond(Query::Or);
|
|
Rex Dieter |
adf30a |
+ Q_FOREACH (const QString &mt, mimeTypes) {
|
|
Rex Dieter |
adf30a |
+ cond.addValueCondition(MimeType::nameFullColumnName(), Query::Equals, mt);
|
|
Rex Dieter |
adf30a |
+ }
|
|
Rex Dieter |
adf30a |
+ qb.addCondition(cond);
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ if (!qb.exec()) {
|
|
Rex Dieter |
adf30a |
+ qWarning() << "Failed to query search collections";
|
|
Rex Dieter |
adf30a |
+ return QVector<qint64>();
|
|
Rex Dieter |
adf30a |
+ }
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ QMap<qint64 /* parentId */, QVector<qint64> /* collectionIds */> candidateCollections;
|
|
Rex Dieter |
adf30a |
+ while (qb.query().next()) {
|
|
Rex Dieter |
adf30a |
+ candidateCollections[qb.query().value(1).toLongLong()].append(qb.query().value(0).toLongLong());
|
|
Rex Dieter |
adf30a |
+ }
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ // If the ancestors list contains root, then return what we got, since everything
|
|
Rex Dieter |
adf30a |
+ // is sub collection of root
|
|
Rex Dieter |
adf30a |
+ QVector<qint64> results;
|
|
Rex Dieter |
adf30a |
+ if (ancestors.contains(0)) {
|
|
Rex Dieter |
adf30a |
+ Q_FOREACH (const QVector<qint64> &res, candidateCollections.values()) {
|
|
Rex Dieter |
adf30a |
+ results += res;
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
- if ( query.value( 0 ).toInt() > 0 ) { // count( mimeTypeTable.name ) > 0
|
|
Rex Dieter |
adf30a |
- recursiveChildren << id;
|
|
Rex Dieter |
adf30a |
+ return results;
|
|
Rex Dieter |
adf30a |
+ }
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ // Try to resolve direct descendants
|
|
Rex Dieter |
adf30a |
+ Q_FOREACH (qint64 ancestor, ancestors) {
|
|
Rex Dieter |
adf30a |
+ const QVector<qint64> cols = candidateCollections.take(ancestor);
|
|
Rex Dieter |
adf30a |
+ if (!cols.isEmpty()) {
|
|
Rex Dieter |
adf30a |
+ results += cols;
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
- }
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
- if ( !searchChildren.isEmpty() ) {
|
|
Rex Dieter |
adf30a |
- recursiveChildren << listCollectionsRecursive( searchChildren, mimeTypes );
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ for (auto iter = candidateCollections.begin(); iter != candidateCollections.end(); ++iter) {
|
|
Rex Dieter |
adf30a |
+ // Traverse the collection chain up to root
|
|
Rex Dieter |
adf30a |
+ qint64 parentId = iter.key();
|
|
Rex Dieter |
adf30a |
+ while (!ancestors.contains(parentId) && parentId > 0) {
|
|
Rex Dieter |
adf30a |
+ parentId = parentCollectionId(parentId);
|
|
Rex Dieter |
adf30a |
+ }
|
|
Rex Dieter |
adf30a |
+ // Ok, we found a requested ancestor in the parent chain
|
|
Rex Dieter |
adf30a |
+ if (parentId > 0) {
|
|
Rex Dieter |
adf30a |
+ results += iter.value();
|
|
Rex Dieter |
adf30a |
+ }
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
- }
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
- return recursiveChildren;
|
|
Rex Dieter |
adf30a |
+ return results;
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
diff --git a/server/src/handler/searchhelper.h b/server/src/handler/searchhelper.h
|
|
Rex Dieter |
adf30a |
index a64bb61..1595501 100644
|
|
Rex Dieter |
adf30a |
--- a/server/src/handler/searchhelper.h
|
|
Rex Dieter |
adf30a |
+++ b/server/src/handler/searchhelper.h
|
|
Rex Dieter |
adf30a |
@@ -33,7 +33,7 @@ class SearchHelper
|
|
Rex Dieter |
adf30a |
public:
|
|
Rex Dieter |
adf30a |
static QList<QByteArray> splitLine( const QByteArray &line );
|
|
Rex Dieter |
adf30a |
static QString extractMimetype( const QList<QByteArray> &junks, int start );
|
|
Rex Dieter |
adf30a |
- static QVector<qint64> listCollectionsRecursive( const QVector<qint64> &ancestors, const QStringList &mimeTypes );
|
|
Rex Dieter |
adf30a |
+ static QVector<qint64> matchSubcollectionsByMimeType( const QVector<qint64> &ancestors, const QStringList &mimeTypes );
|
|
Rex Dieter |
adf30a |
};
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
} // namespace Server
|
|
Rex Dieter |
adf30a |
diff --git a/server/src/search/searchmanager.cpp b/server/src/search/searchmanager.cpp
|
|
Rex Dieter |
adf30a |
index c821aa3..b940fcc 100644
|
|
Rex Dieter |
adf30a |
--- a/server/src/search/searchmanager.cpp
|
|
Rex Dieter |
adf30a |
+++ b/server/src/search/searchmanager.cpp
|
|
Rex Dieter |
adf30a |
@@ -296,7 +296,7 @@ void SearchManager::updateSearchImpl( const Collection &collection, QWaitConditi
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
|
|
Rex Dieter |
adf30a |
if ( recursive ) {
|
|
Rex Dieter |
adf30a |
- queryCollections = SearchHelper::listCollectionsRecursive( queryAncestors, queryMimeTypes );
|
|
Rex Dieter |
adf30a |
+ queryCollections = SearchHelper::matchSubcollectionsByMimeType( queryAncestors, queryMimeTypes );
|
|
Rex Dieter |
adf30a |
} else {
|
|
Rex Dieter |
adf30a |
queryCollections = queryAncestors;
|
|
Rex Dieter |
adf30a |
}
|
|
Rex Dieter |
adf30a |
diff --git a/server/tests/unittest/CMakeLists.txt b/server/tests/unittest/CMakeLists.txt
|
|
Rex Dieter |
adf30a |
index b9744d9..acdc180 100644
|
|
Rex Dieter |
adf30a |
--- a/server/tests/unittest/CMakeLists.txt
|
|
Rex Dieter |
adf30a |
+++ b/server/tests/unittest/CMakeLists.txt
|
|
Rex Dieter |
adf30a |
@@ -77,3 +77,5 @@ add_server_test(listhandlertest.cpp akonadiprivate)
|
|
Rex Dieter |
adf30a |
add_server_test(modifyhandlertest.cpp akonadiprivate)
|
|
Rex Dieter |
adf30a |
add_server_test(createhandlertest.cpp akonadiprivate)
|
|
Rex Dieter |
adf30a |
add_server_test(collectionreferencetest.cpp akonadiprivate)
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+add_server_test(searchtest.cpp akonadiprivate)
|
|
Rex Dieter |
adf30a |
\ No newline at end of file
|
|
Rex Dieter |
adf30a |
diff --git a/server/tests/unittest/searchtest.cpp b/server/tests/unittest/searchtest.cpp
|
|
Rex Dieter |
adf30a |
new file mode 100644
|
|
Rex Dieter |
adf30a |
index 0000000..f523b09
|
|
Rex Dieter |
adf30a |
--- /dev/null
|
|
Rex Dieter |
adf30a |
+++ b/server/tests/unittest/searchtest.cpp
|
|
Rex Dieter |
adf30a |
@@ -0,0 +1,158 @@
|
|
Rex Dieter |
adf30a |
+/*
|
|
Rex Dieter |
adf30a |
+ * Copyright (C) 2014 Daniel Vrátil <dvratil@redhat.com>
|
|
Rex Dieter |
adf30a |
+ *
|
|
Rex Dieter |
adf30a |
+ * This library is free software; you can redistribute it and/or
|
|
Rex Dieter |
adf30a |
+ * modify it under the terms of the GNU Lesser General Public
|
|
Rex Dieter |
adf30a |
+ * License as published by the Free Software Foundation; either
|
|
Rex Dieter |
adf30a |
+ * version 2.1 of the License, or (at your option) any later version.
|
|
Rex Dieter |
adf30a |
+ *
|
|
Rex Dieter |
adf30a |
+ * This library is distributed in the hope that it will be useful,
|
|
Rex Dieter |
adf30a |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Rex Dieter |
adf30a |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Rex Dieter |
adf30a |
+ * Lesser General Public License for more details.
|
|
Rex Dieter |
adf30a |
+ *
|
|
Rex Dieter |
adf30a |
+ * You should have received a copy of the GNU Lesser General Public
|
|
Rex Dieter |
adf30a |
+ * License along with this library; if not, write to the Free Software
|
|
Rex Dieter |
adf30a |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Rex Dieter |
adf30a |
+ *
|
|
Rex Dieter |
adf30a |
+ */
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+#include "fakeakonadiserver.h"
|
|
Rex Dieter |
adf30a |
+#include "searchhelper.h"
|
|
Rex Dieter |
adf30a |
+#include "akdebug.h"
|
|
Rex Dieter |
adf30a |
+#include "aktest.h"
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+#include <entities.h>
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+#include <QTest>
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+using namespace Akonadi::Server;
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+Q_DECLARE_METATYPE(QList<qint64>)
|
|
Rex Dieter |
adf30a |
+Q_DECLARE_METATYPE(QList<QString>)
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+class SearchTest : public QObject
|
|
Rex Dieter |
adf30a |
+{
|
|
Rex Dieter |
adf30a |
+ Q_OBJECT
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+public:
|
|
Rex Dieter |
adf30a |
+ SearchTest()
|
|
Rex Dieter |
adf30a |
+ : QObject()
|
|
Rex Dieter |
adf30a |
+ {
|
|
Rex Dieter |
adf30a |
+ try {
|
|
Rex Dieter |
adf30a |
+ FakeAkonadiServer::instance()->setPopulateDb(false);
|
|
Rex Dieter |
adf30a |
+ FakeAkonadiServer::instance()->init();
|
|
Rex Dieter |
adf30a |
+ } catch (const FakeAkonadiServerException &e) {
|
|
Rex Dieter |
adf30a |
+ akError() << "Server exception: " << e.what();
|
|
Rex Dieter |
adf30a |
+ akFatal() << "Fake Akonadi Server failed to start up, aborting test";
|
|
Rex Dieter |
adf30a |
+ }
|
|
Rex Dieter |
adf30a |
+ }
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ ~SearchTest()
|
|
Rex Dieter |
adf30a |
+ {
|
|
Rex Dieter |
adf30a |
+ FakeAkonadiServer::instance()->quit();
|
|
Rex Dieter |
adf30a |
+ }
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ Collection createCollection(const Resource &res, const QString &name, const Collection &parent, const QStringList &mimetypes)
|
|
Rex Dieter |
adf30a |
+ {
|
|
Rex Dieter |
adf30a |
+ Collection col;
|
|
Rex Dieter |
adf30a |
+ col.setName(name);
|
|
Rex Dieter |
adf30a |
+ col.setResource(res);
|
|
Rex Dieter |
adf30a |
+ col.setParentId(parent.isValid() ? parent.id() : 0);
|
|
Rex Dieter |
adf30a |
+ col.insert();
|
|
Rex Dieter |
adf30a |
+ Q_FOREACH (const QString &mimeType, mimetypes) {
|
|
Rex Dieter |
adf30a |
+ MimeType mt = MimeType::retrieveByName(mimeType);
|
|
Rex Dieter |
adf30a |
+ if (!mt.isValid()) {
|
|
Rex Dieter |
adf30a |
+ mt = MimeType(mimeType);
|
|
Rex Dieter |
adf30a |
+ mt.insert();
|
|
Rex Dieter |
adf30a |
+ }
|
|
Rex Dieter |
adf30a |
+ col.addMimeType(mt);
|
|
Rex Dieter |
adf30a |
+ }
|
|
Rex Dieter |
adf30a |
+ return col;
|
|
Rex Dieter |
adf30a |
+ }
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+private Q_SLOTS:
|
|
Rex Dieter |
adf30a |
+ void testSearchHelperCollectionListing_data()
|
|
Rex Dieter |
adf30a |
+ {
|
|
Rex Dieter |
adf30a |
+ /*
|
|
Rex Dieter |
adf30a |
+ Fake Resource
|
|
Rex Dieter |
adf30a |
+ |- Col 1 (inode/directory)
|
|
Rex Dieter |
adf30a |
+ | |- Col 2 (inode/direcotry, application/octet-stream)
|
|
Rex Dieter |
adf30a |
+ | | |- Col 3(application/octet-stream)
|
|
Rex Dieter |
adf30a |
+ | |- Col 4 (text/plain)
|
|
Rex Dieter |
adf30a |
+ |- Col 5 (inode/directory, text/plain)
|
|
Rex Dieter |
adf30a |
+ |- Col 6 (inode/directory, application/octet-stream)
|
|
Rex Dieter |
adf30a |
+ |- Col 7 (inode/directory, text/plain)
|
|
Rex Dieter |
adf30a |
+ |- Col 8 (inode/directory, application/octet-stream)
|
|
Rex Dieter |
adf30a |
+ |- Col 9 (unique/mime-type)
|
|
Rex Dieter |
adf30a |
+ */
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ Resource res(QLatin1String("Test Resource"), false);
|
|
Rex Dieter |
adf30a |
+ res.insert();
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ Collection col1 = createCollection(res, QLatin1String("Col 1"), Collection(),
|
|
Rex Dieter |
adf30a |
+ QStringList() << QLatin1String("inode/directory"));
|
|
Rex Dieter |
adf30a |
+ Collection col2 = createCollection(res, QLatin1String("Col 2"), col1,
|
|
Rex Dieter |
adf30a |
+ QStringList() << QLatin1String("inode/directory")
|
|
Rex Dieter |
adf30a |
+ << QLatin1String("application/octet-stream"));
|
|
Rex Dieter |
adf30a |
+ Collection col3 = createCollection(res, QLatin1String("Col 3"), col2,
|
|
Rex Dieter |
adf30a |
+ QStringList() << QLatin1String("application/octet-stream"));
|
|
Rex Dieter |
adf30a |
+ Collection col4 = createCollection(res, QLatin1String("Col 4"), col2,
|
|
Rex Dieter |
adf30a |
+ QStringList() << QLatin1String("text/plain"));
|
|
Rex Dieter |
adf30a |
+ Collection col5 = createCollection(res, QLatin1String("Col 5"), Collection(),
|
|
Rex Dieter |
adf30a |
+ QStringList() << QLatin1String("inode/directory")
|
|
Rex Dieter |
adf30a |
+ << QLatin1String("text/plain"));
|
|
Rex Dieter |
adf30a |
+ Collection col6 = createCollection(res, QLatin1String("Col 6"), col5,
|
|
Rex Dieter |
adf30a |
+ QStringList() << QLatin1String("inode/directory")
|
|
Rex Dieter |
adf30a |
+ << QLatin1String("application/octet-stream"));
|
|
Rex Dieter |
adf30a |
+ Collection col7 = createCollection(res, QLatin1String("Col 7"), col5,
|
|
Rex Dieter |
adf30a |
+ QStringList() << QLatin1String("inode/directory")
|
|
Rex Dieter |
adf30a |
+ << QLatin1String("text/plain"));
|
|
Rex Dieter |
adf30a |
+ Collection col8 = createCollection(res, QLatin1String("Col 8"), col7,
|
|
Rex Dieter |
adf30a |
+ QStringList() << QLatin1String("text/directory")
|
|
Rex Dieter |
adf30a |
+ << QLatin1String("application/octet-stream"));
|
|
Rex Dieter |
adf30a |
+ Collection col9 = createCollection(res, QLatin1String("Col 9"), col8,
|
|
Rex Dieter |
adf30a |
+ QStringList() << QLatin1String("unique/mime-type"));
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ QTest::addColumn<QVector<qint64>>("ancestors");
|
|
Rex Dieter |
adf30a |
+ QTest::addColumn<QStringList>("mimetypes");
|
|
Rex Dieter |
adf30a |
+ QTest::addColumn<QVector<qint64>>("expectedResults");
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ QTest::newRow("") << QVector<qint64>({ 0 })
|
|
Rex Dieter |
adf30a |
+ << QStringList({ QLatin1String("text/plain") })
|
|
Rex Dieter |
adf30a |
+ << QVector<qint64>({ col4.id(), col5.id(), col7.id() });
|
|
Rex Dieter |
adf30a |
+ QTest::newRow("") << QVector<qint64>({ 0 })
|
|
Rex Dieter |
adf30a |
+ << QStringList({ QLatin1String("application/octet-stream") })
|
|
Rex Dieter |
adf30a |
+ << QVector<qint64>({ col2.id(), col3.id(), col6.id(), col8.id() });
|
|
Rex Dieter |
adf30a |
+ QTest::newRow("") << QVector<qint64>({ col1.id() })
|
|
Rex Dieter |
adf30a |
+ << QStringList({ QLatin1String("text/plain") })
|
|
Rex Dieter |
adf30a |
+ << QVector<qint64>({ col4.id() });
|
|
Rex Dieter |
adf30a |
+ QTest::newRow("") << QVector<qint64>({ col1.id() })
|
|
Rex Dieter |
adf30a |
+ << QStringList({ QLatin1String("unique/mime-type") })
|
|
Rex Dieter |
adf30a |
+ << QVector<qint64>();
|
|
Rex Dieter |
adf30a |
+ QTest::newRow("") << QVector<qint64>({ col2.id(), col7.id() })
|
|
Rex Dieter |
adf30a |
+ << QStringList({ QLatin1String("application/octet-stream") })
|
|
Rex Dieter |
adf30a |
+ << QVector<qint64>({ col3.id(), col8.id() });
|
|
Rex Dieter |
adf30a |
+ }
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ void testSearchHelperCollectionListing()
|
|
Rex Dieter |
adf30a |
+ {
|
|
Rex Dieter |
adf30a |
+ QFETCH(QVector<qint64>, ancestors);
|
|
Rex Dieter |
adf30a |
+ QFETCH(QStringList, mimetypes);
|
|
Rex Dieter |
adf30a |
+ QFETCH(QVector<qint64>, expectedResults);
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ QVector<qint64> results = SearchHelper::matchSubcollectionsByMimeType(ancestors, mimetypes);
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ qSort(expectedResults);
|
|
Rex Dieter |
adf30a |
+ qSort(results);
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+ QCOMPARE(results.size(), expectedResults.size());
|
|
Rex Dieter |
adf30a |
+ QCOMPARE(results, expectedResults);
|
|
Rex Dieter |
adf30a |
+ }
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+};
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+AKTEST_FAKESERVER_MAIN(SearchTest)
|
|
Rex Dieter |
adf30a |
+
|
|
Rex Dieter |
adf30a |
+#include "searchtest.moc"
|
|
Rex Dieter |
adf30a |
--
|
|
Rex Dieter |
adf30a |
2.1.0
|
|
Rex Dieter |
adf30a |
|