File indexing completed on 2025-02-16 04:59:36

0001 /*
0002  * SPDX-FileCopyrightText: 2014 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 
0008 #ifndef DOMAIN_LIVEQUERY_H
0009 #define DOMAIN_LIVEQUERY_H
0010 
0011 #include "queryresult.h"
0012 
0013 namespace Domain {
0014 
0015 template <typename InputType>
0016 class LiveQueryInput
0017 {
0018 public:
0019     typedef QSharedPointer<LiveQueryInput<InputType>> Ptr;
0020     typedef QWeakPointer<LiveQueryInput<InputType>> WeakPtr;
0021     typedef QList<Ptr> List;
0022     typedef QList<WeakPtr> WeakList;
0023 
0024     typedef std::function<void(const InputType &)> AddFunction;
0025     typedef std::function<void(const AddFunction &)> FetchFunction;
0026     typedef std::function<bool(const InputType &)> PredicateFunction;
0027 
0028     virtual ~LiveQueryInput() {}
0029 
0030     virtual void reset() = 0;
0031     virtual void onAdded(const InputType &input) = 0;
0032     virtual void onChanged(const InputType &input) = 0;
0033     virtual void onRemoved(const InputType &input) = 0;
0034 };
0035 
0036 template <typename OutputType>
0037 class LiveQueryOutput
0038 {
0039 public:
0040     typedef QSharedPointer<LiveQueryOutput<OutputType>> Ptr;
0041     typedef QList<Ptr> List;
0042     typedef QueryResult<OutputType> Result;
0043 
0044     virtual ~LiveQueryOutput() {}
0045     virtual typename Result::Ptr result() = 0;
0046     virtual void reset() = 0;
0047 };
0048 
0049 template<typename InputType, typename OutputType>
0050 class LiveQuery : public LiveQueryInput<InputType>, public LiveQueryOutput<OutputType>
0051 {
0052 public:
0053     typedef QSharedPointer<LiveQuery<InputType, OutputType>> Ptr;
0054     typedef QList<Ptr> List;
0055 
0056     typedef QueryResultProvider<OutputType> Provider;
0057     typedef QueryResult<OutputType> Result;
0058 
0059     typedef typename LiveQueryInput<InputType>::AddFunction AddFunction;
0060     typedef typename LiveQueryInput<InputType>::FetchFunction FetchFunction;
0061     typedef typename LiveQueryInput<InputType>::PredicateFunction PredicateFunction;
0062 
0063     typedef std::function<OutputType(const InputType &)> ConvertFunction;
0064     typedef std::function<void(const InputType &, OutputType &)> UpdateFunction;
0065     typedef std::function<bool(const InputType &, const OutputType &)> RepresentsFunction;
0066 
0067     LiveQuery() = default;
0068     LiveQuery(const LiveQuery &other) = default;
0069     LiveQuery &operator=(const LiveQuery &other) = default;
0070 
0071     ~LiveQuery()
0072     {
0073         clear();
0074     }
0075 
0076     typename Result::Ptr result() override
0077     {
0078         typename Provider::Ptr provider(m_provider.toStrongRef());
0079 
0080         if (provider)
0081             return Result::create(provider);
0082 
0083         provider = Provider::Ptr::create();
0084         m_provider = provider.toWeakRef();
0085 
0086         doFetch();
0087 
0088         return Result::create(provider);
0089     }
0090 
0091     void setFetchFunction(const FetchFunction &fetch)
0092     {
0093         m_fetch = fetch;
0094     }
0095 
0096     void setPredicateFunction(const PredicateFunction &predicate)
0097     {
0098         m_predicate = predicate;
0099     }
0100 
0101     void setConvertFunction(const ConvertFunction &convert)
0102     {
0103         m_convert = convert;
0104     }
0105 
0106     void setUpdateFunction(const UpdateFunction &update)
0107     {
0108         m_update = update;
0109     }
0110 
0111     void setDebugName(const QByteArray &name)
0112     {
0113         m_debugName = name;
0114     }
0115 
0116     void setRepresentsFunction(const RepresentsFunction &represents)
0117     {
0118         m_represents = represents;
0119     }
0120 
0121     void reset() override
0122     {
0123         clear();
0124         doFetch();
0125     }
0126 
0127     void onAdded(const InputType &input) override
0128     {
0129         typename Provider::Ptr provider(m_provider.toStrongRef());
0130 
0131         if (!provider)
0132             return;
0133 
0134         if (m_predicate(input))
0135             addToProvider(provider, input);
0136     }
0137 
0138     void onChanged(const InputType &input) override
0139     {
0140         typename Provider::Ptr provider(m_provider.toStrongRef());
0141 
0142         if (!provider)
0143             return;
0144 
0145         if (!m_predicate(input)) {
0146             for (int i = 0; i < provider->data().size(); i++) {
0147                 auto output = provider->data().at(i);
0148                 if (m_represents(input, output)) {
0149                     provider->removeAt(i);
0150                     i--;
0151                 }
0152             }
0153         } else {
0154             bool found = false;
0155 
0156             for (int i = 0; i < provider->data().size(); i++) {
0157                 auto output = provider->data().at(i);
0158                 if (m_represents(input, output)) {
0159                     m_update(input, output);
0160                     provider->replace(i, output);
0161 
0162                     found = true;
0163                 }
0164             }
0165 
0166             if (!found)
0167                 addToProvider(provider, input);
0168         }
0169     }
0170 
0171     void onRemoved(const InputType &input) override
0172     {
0173         typename Provider::Ptr provider(m_provider.toStrongRef());
0174 
0175         if (!provider)
0176             return;
0177 
0178         for (int i = 0; i < provider->data().size(); i++) {
0179             auto output = provider->data().at(i);
0180             if (m_represents(input, output)) {
0181                 provider->removeAt(i);
0182                 i--;
0183             }
0184         }
0185     }
0186 
0187 private:
0188     template<typename T>
0189     bool isValidOutput(const T &/*output*/)
0190     {
0191         return true;
0192     }
0193 
0194     template<typename T>
0195     bool isValidOutput(const QSharedPointer<T> &output)
0196     {
0197         return !output.isNull();
0198     }
0199 
0200     template<typename T>
0201     bool isValidOutput(T *output)
0202     {
0203         return output != nullptr;
0204     }
0205 
0206     void addToProvider(const typename Provider::Ptr &provider, const InputType &input)
0207     {
0208         auto output = m_convert(input);
0209         if (isValidOutput(output))
0210             provider->append(output);
0211     }
0212 
0213     void doFetch()
0214     {
0215         typename Provider::Ptr provider(m_provider.toStrongRef());
0216 
0217         if (!provider)
0218             return;
0219 
0220         auto addFunction = [this, provider] (const InputType &input) {
0221             if (m_predicate(input))
0222                 addToProvider(provider, input);
0223         };
0224 
0225         m_fetch(addFunction);
0226     }
0227 
0228     void clear()
0229     {
0230         typename Provider::Ptr provider(m_provider.toStrongRef());
0231 
0232         if (!provider)
0233             return;
0234 
0235         while (!provider->data().isEmpty())
0236             provider->removeFirst();
0237     }
0238 
0239     FetchFunction m_fetch;
0240     PredicateFunction m_predicate;
0241     ConvertFunction m_convert;
0242     UpdateFunction m_update;
0243     RepresentsFunction m_represents;
0244     QByteArray m_debugName;
0245 
0246     typename Provider::WeakPtr m_provider;
0247 };
0248 
0249 // A query that stores an intermediate list of results (from the fetch), to react on changes on any item in that list
0250 // and then filters that list with the predicate for the final result
0251 // When one of the intermediary items changes, a full fetch is done again.
0252 template<typename InputType, typename OutputType>
0253 class LiveRelationshipQuery : public LiveQueryInput<InputType>, public LiveQueryOutput<OutputType>
0254 {
0255 public:
0256     typedef QSharedPointer<LiveRelationshipQuery<InputType, OutputType>> Ptr;
0257     typedef QList<Ptr> List;
0258 
0259     typedef QueryResultProvider<OutputType> Provider;
0260     typedef QueryResult<OutputType> Result;
0261 
0262     typedef typename LiveQueryInput<InputType>::AddFunction AddFunction;
0263     typedef typename LiveQueryInput<InputType>::FetchFunction FetchFunction;
0264     typedef typename LiveQueryInput<InputType>::PredicateFunction PredicateFunction;
0265 
0266     typedef std::function<OutputType(const InputType &)> ConvertFunction;
0267     typedef std::function<bool(const InputType &, const OutputType &)> RepresentsFunction;
0268     typedef std::function<bool(const InputType &, const InputType &)> CompareFunction;
0269 
0270     LiveRelationshipQuery() = default;
0271     LiveRelationshipQuery(const LiveRelationshipQuery &other) = default;
0272     LiveRelationshipQuery &operator=(const LiveRelationshipQuery &other) = default;
0273 
0274     ~LiveRelationshipQuery()
0275     {
0276         clear();
0277     }
0278 
0279     typename Result::Ptr result() override
0280     {
0281         typename Provider::Ptr provider(m_provider.toStrongRef());
0282 
0283         if (provider)
0284             return Result::create(provider);
0285         provider = Provider::Ptr::create();
0286         m_provider = provider.toWeakRef();
0287 
0288         doFetch();
0289 
0290         return Result::create(provider);
0291     }
0292 
0293     void setFetchFunction(const FetchFunction &fetch)
0294     {
0295         m_fetch = fetch;
0296     }
0297 
0298     void setPredicateFunction(const PredicateFunction &predicate)
0299     {
0300         m_predicate = predicate;
0301     }
0302 
0303     void setCompareFunction(const CompareFunction &compare)
0304     {
0305         m_compare = compare;
0306     }
0307 
0308     void setConvertFunction(const ConvertFunction &convert)
0309     {
0310         m_convert = convert;
0311     }
0312 
0313     void setDebugName(const QByteArray &name)
0314     {
0315         m_debugName = name;
0316     }
0317 
0318     void setRepresentsFunction(const RepresentsFunction &represents)
0319     {
0320         m_represents = represents;
0321     }
0322 
0323     void reset() override
0324     {
0325         clear();
0326         doFetch();
0327     }
0328 
0329     void onAdded(const InputType &input) override
0330     {
0331         typename Provider::Ptr provider(m_provider.toStrongRef());
0332 
0333         if (!provider)
0334             return;
0335 
0336         m_intermediaryResults.append(input);
0337         if (m_predicate(input))
0338             addToProvider(provider, input);
0339     }
0340 
0341     void onChanged(const InputType &input) override
0342     {
0343         Q_ASSERT(m_compare);
0344         const bool found = std::any_of(m_intermediaryResults.constBegin(), m_intermediaryResults.constEnd(),
0345                                        [&input, this](const InputType &existing) {
0346                                            return m_compare(input, existing);
0347                                        });
0348         if (found)
0349             reset();
0350     }
0351 
0352     void onRemoved(const InputType &input) override
0353     {
0354         onChanged(input);
0355     }
0356 
0357 private:
0358     template<typename T>
0359     bool isValidOutput(const T &/*output*/)
0360     {
0361         return true;
0362     }
0363 
0364     template<typename T>
0365     bool isValidOutput(const QSharedPointer<T> &output)
0366     {
0367         return !output.isNull();
0368     }
0369 
0370     template<typename T>
0371     bool isValidOutput(T *output)
0372     {
0373         return output != nullptr;
0374     }
0375 
0376     void addToProvider(const typename Provider::Ptr &provider, const InputType &input)
0377     {
0378         auto output = m_convert(input);
0379         if (isValidOutput(output))
0380             provider->append(output);
0381     }
0382 
0383     void doFetch()
0384     {
0385         auto addFunction = [this] (const InputType &input) {
0386             onAdded(input);
0387         };
0388         m_fetch(addFunction);
0389     }
0390 
0391     void clear()
0392     {
0393         m_intermediaryResults.clear();
0394 
0395         typename Provider::Ptr provider(m_provider.toStrongRef());
0396 
0397         if (!provider)
0398             return;
0399 
0400         while (!provider->data().isEmpty())
0401             provider->removeFirst();
0402     }
0403 
0404     FetchFunction m_fetch;
0405     PredicateFunction m_predicate;
0406     ConvertFunction m_convert;
0407     CompareFunction m_compare;
0408     RepresentsFunction m_represents;
0409     QByteArray m_debugName;
0410 
0411     typename Provider::WeakPtr m_provider;
0412     QList<InputType> m_intermediaryResults;
0413 };
0414 
0415 }
0416 
0417 #endif // DOMAIN_LIVEQUERY_H