File indexing completed on 2024-06-02 05:32:54

0001 /*
0002  * SPDX-FileCopyrightText: 2015 Kevin Ottens <ervin@kde.org>
0003  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004  */
0005 
0006 
0007 #include "akonadilivequeryhelpers.h"
0008 
0009 #include "akonadi/akonadicollectionfetchjobinterface.h"
0010 #include "akonadi/akonadiitemfetchjobinterface.h"
0011 
0012 #include "utils/jobhandler.h"
0013 
0014 using namespace Akonadi;
0015 
0016 LiveQueryHelpers::LiveQueryHelpers(const SerializerInterface::Ptr &serializer,
0017                                    const StorageInterface::Ptr &storage)
0018     : m_serializer(serializer),
0019       m_storage(storage)
0020 {
0021 }
0022 
0023 LiveQueryHelpers::CollectionFetchFunction LiveQueryHelpers::fetchAllCollections(QObject *parent) const
0024 {
0025     auto storage = m_storage;
0026     return [storage, parent] (const Domain::LiveQueryInput<Collection>::AddFunction &add) {
0027         auto job = storage->fetchCollections(Collection::root(), StorageInterface::Recursive, parent);
0028         Utils::JobHandler::install(job->kjob(), [job, add] {
0029             if (job->kjob()->error())
0030                 return;
0031 
0032             foreach (const auto &collection, job->collections())
0033                 add(collection);
0034         });
0035     };
0036 }
0037 
0038 LiveQueryHelpers::CollectionFetchFunction LiveQueryHelpers::fetchCollections(const Collection &root, QObject *parent) const
0039 {
0040     auto storage = m_storage;
0041     return [storage, root, parent] (const Domain::LiveQueryInput<Collection>::AddFunction &add) {
0042         auto job = storage->fetchCollections(root, StorageInterface::Recursive, parent);
0043         Utils::JobHandler::install(job->kjob(), [root, job, add] {
0044             if (job->kjob()->error())
0045                 return;
0046 
0047             auto directChildren = QHash<Collection::Id, Collection>();
0048             foreach (const auto &collection, job->collections()) {
0049                 auto directChild = collection;
0050                 while (directChild.parentCollection() != root)
0051                     directChild = directChild.parentCollection();
0052                 if (!directChildren.contains(directChild.id()))
0053                     directChildren[directChild.id()] = directChild;
0054             }
0055 
0056             foreach (const auto &directChild, directChildren)
0057                 add(directChild);
0058         });
0059     };
0060 }
0061 
0062 LiveQueryHelpers::ItemFetchFunction LiveQueryHelpers::fetchItems(QObject *parent) const
0063 {
0064     auto serializer = m_serializer;
0065     auto storage = m_storage;
0066     return [serializer, storage, parent] (const Domain::LiveQueryInput<Item>::AddFunction &add) {
0067         auto job = storage->fetchCollections(Akonadi::Collection::root(),
0068                                              StorageInterface::Recursive,
0069                                              parent);
0070         Utils::JobHandler::install(job->kjob(), [serializer, storage, job, add, parent] {
0071             if (job->kjob()->error() != KJob::NoError)
0072                 return;
0073 
0074             foreach (const auto &collection, job->collections()) {
0075                 if (!serializer->isSelectedCollection(collection))
0076                     continue;
0077 
0078                 auto job = storage->fetchItems(collection, parent);
0079                 Utils::JobHandler::install(job->kjob(), [job, add] {
0080                     if (job->kjob()->error() != KJob::NoError)
0081                         return;
0082 
0083                     foreach (const auto &item, job->items())
0084                         add(item);
0085                 });
0086             }
0087         });
0088     };
0089 }
0090 
0091 LiveQueryHelpers::ItemFetchFunction LiveQueryHelpers::fetchItems(const Collection &collection, QObject *parent) const
0092 {
0093     auto storage = m_storage;
0094     return [storage, collection, parent] (const Domain::LiveQueryInput<Item>::AddFunction &add) {
0095         auto job = storage->fetchItems(collection, parent);
0096         Utils::JobHandler::install(job->kjob(), [job, add] {
0097             if (job->kjob()->error() != KJob::NoError)
0098                 return;
0099 
0100             foreach (const auto &item, job->items())
0101                 add(item);
0102         });
0103     };
0104 }
0105 
0106 LiveQueryHelpers::ItemFetchFunction LiveQueryHelpers::fetchItemsForContext(const Domain::Context::Ptr &context, QObject *parent) const
0107 {
0108     auto fetchFunction = fetchItems(parent);
0109     auto serializer = m_serializer;
0110 
0111     return [context, fetchFunction, serializer] (const Domain::LiveQueryInput<Item>::AddFunction &add) {
0112         auto filterAdd = [context, add, serializer] (const Item &item) {
0113             if (serializer->isContextChild(context, item))
0114                 add(item);
0115         };
0116         fetchFunction(filterAdd);
0117     };
0118 }
0119 
0120 LiveQueryHelpers::ItemFetchFunction LiveQueryHelpers::fetchTaskAndAncestors(Domain::Task::Ptr task, QObject *parent) const
0121 {
0122     Akonadi::Item childItem = m_serializer->createItemFromTask(task);
0123     Q_ASSERT(childItem.parentCollection().isValid()); // do I really need a fetchItem first, like fetchSiblings does?
0124     // Note: if the task moves to another collection, this live query will then be invalid...
0125 
0126     const Akonadi::Item::Id childId = childItem.id();
0127     auto storage = m_storage;
0128     auto serializer = m_serializer;
0129     return [storage, serializer, childItem, childId, parent] (const Domain::LiveQueryInput<Item>::AddFunction &add) {
0130         auto job = storage->fetchItems(childItem.parentCollection(), parent);
0131         Utils::JobHandler::install(job->kjob(), [job, add, serializer, childId] {
0132             if (job->kjob()->error() != KJob::NoError)
0133                 return;
0134 
0135             const auto items = job->items();
0136             // The item itself is part of the result, we need that in findProject, to react on changes of the item itself
0137             // To return a correct child item in case it got updated, we can't use childItem, we need to find it in the list.
0138             const auto myself = std::find_if(items.cbegin(), items.cend(),
0139                                              [childId] (const Akonadi::Item &item) {
0140                                                  return childId == item.id();
0141                                              });
0142             if (myself == items.cend()) {
0143                 qWarning() << "Did not find item in the listing for its parent collection. Item ID:" << childId;
0144                 return;
0145             }
0146             add(*myself);
0147             auto parentUid = serializer->relatedUidFromItem(*myself);
0148             while (!parentUid.isEmpty()) {
0149                 const auto parent = std::find_if(items.cbegin(), items.cend(),
0150                                                  [serializer, parentUid] (const Akonadi::Item &item) {
0151                                                      return serializer->itemUid(item) == parentUid;
0152                                                  });
0153                 if (parent == items.cend()) {
0154                     break;
0155                 }
0156                 add(*parent);
0157                 parentUid = serializer->relatedUidFromItem(*parent);
0158             }
0159         });
0160     };
0161 }
0162 
0163 LiveQueryHelpers::CollectionFetchFunction LiveQueryHelpers::fetchItemCollection(const Item& item, QObject *parent) const
0164 {
0165     auto storage = m_storage;
0166     return [storage, item, parent] (const Domain::LiveQueryInput<Collection>::AddFunction &add) {
0167         auto job = storage->fetchCollections(item.parentCollection(), StorageInterface::Base, parent);
0168         Utils::JobHandler::install(job->kjob(), [storage, job, add] {
0169             if (job->kjob()->error() != KJob::NoError)
0170                 return;
0171             auto collection = job->collections().at(0);
0172             add(collection);
0173         });
0174     };
0175 }
0176 
0177 
0178 LiveQueryHelpers::ItemFetchFunction LiveQueryHelpers::fetchSiblings(const Item &item, QObject *parent) const
0179 {
0180     auto storage = m_storage;
0181     return [storage, item, parent] (const Domain::LiveQueryInput<Item>::AddFunction &add) {
0182         auto job = storage->fetchItem(item, parent);
0183         Utils::JobHandler::install(job->kjob(), [storage, job, add, parent] {
0184             if (job->kjob()->error() != KJob::NoError)
0185                 return;
0186 
0187             Q_ASSERT(job->items().size() == 1);
0188             auto item = job->items().at(0);
0189             Q_ASSERT(item.parentCollection().isValid());
0190             auto job = storage->fetchItems(item.parentCollection(), parent);
0191             Utils::JobHandler::install(job->kjob(), [job, add] {
0192                 if (job->kjob()->error() != KJob::NoError)
0193                     return;
0194 
0195                 foreach (const auto &item, job->items())
0196                     add(item);
0197             });
0198         });
0199     };
0200 }