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