1 /* 2 * SPDX-FileCopyrightText: 2014 Kevin Ottens <ervin@kde.org> 3 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 4 */ 5 6 7 8 #ifndef DOMAIN_LIVEQUERY_H 9 #define DOMAIN_LIVEQUERY_H 10 11 #include "queryresult.h" 12 13 namespace Domain { 14 15 template <typename InputType> 16 class LiveQueryInput 17 { 18 public: 19 typedef QSharedPointer<LiveQueryInput<InputType>> Ptr; 20 typedef QWeakPointer<LiveQueryInput<InputType>> WeakPtr; 21 typedef QList<Ptr> List; 22 typedef QList<WeakPtr> WeakList; 23 24 typedef std::function<void(const InputType &)> AddFunction; 25 typedef std::function<void(const AddFunction &)> FetchFunction; 26 typedef std::function<bool(const InputType &)> PredicateFunction; 27 ~LiveQueryInput()28 virtual ~LiveQueryInput() {} 29 30 virtual void reset() = 0; 31 virtual void onAdded(const InputType &input) = 0; 32 virtual void onChanged(const InputType &input) = 0; 33 virtual void onRemoved(const InputType &input) = 0; 34 }; 35 36 template <typename OutputType> 37 class LiveQueryOutput 38 { 39 public: 40 typedef QSharedPointer<LiveQueryOutput<OutputType>> Ptr; 41 typedef QList<Ptr> List; 42 typedef QueryResult<OutputType> Result; 43 ~LiveQueryOutput()44 virtual ~LiveQueryOutput() {} 45 virtual typename Result::Ptr result() = 0; 46 virtual void reset() = 0; 47 }; 48 49 template<typename InputType, typename OutputType> 50 class LiveQuery : public LiveQueryInput<InputType>, public LiveQueryOutput<OutputType> 51 { 52 public: 53 typedef QSharedPointer<LiveQuery<InputType, OutputType>> Ptr; 54 typedef QList<Ptr> List; 55 56 typedef QueryResultProvider<OutputType> Provider; 57 typedef QueryResult<OutputType> Result; 58 59 typedef typename LiveQueryInput<InputType>::AddFunction AddFunction; 60 typedef typename LiveQueryInput<InputType>::FetchFunction FetchFunction; 61 typedef typename LiveQueryInput<InputType>::PredicateFunction PredicateFunction; 62 63 typedef std::function<OutputType(const InputType &)> ConvertFunction; 64 typedef std::function<void(const InputType &, OutputType &)> UpdateFunction; 65 typedef std::function<bool(const InputType &, const OutputType &)> RepresentsFunction; 66 67 LiveQuery() = default; 68 LiveQuery(const LiveQuery &other) = default; 69 LiveQuery &operator=(const LiveQuery &other) = default; 70 ~LiveQuery()71 ~LiveQuery() 72 { 73 clear(); 74 } 75 result()76 typename Result::Ptr result() override 77 { 78 typename Provider::Ptr provider(m_provider.toStrongRef()); 79 80 if (provider) 81 return Result::create(provider); 82 83 provider = Provider::Ptr::create(); 84 m_provider = provider.toWeakRef(); 85 86 doFetch(); 87 88 return Result::create(provider); 89 } 90 setFetchFunction(const FetchFunction & fetch)91 void setFetchFunction(const FetchFunction &fetch) 92 { 93 m_fetch = fetch; 94 } 95 setPredicateFunction(const PredicateFunction & predicate)96 void setPredicateFunction(const PredicateFunction &predicate) 97 { 98 m_predicate = predicate; 99 } 100 setConvertFunction(const ConvertFunction & convert)101 void setConvertFunction(const ConvertFunction &convert) 102 { 103 m_convert = convert; 104 } 105 setUpdateFunction(const UpdateFunction & update)106 void setUpdateFunction(const UpdateFunction &update) 107 { 108 m_update = update; 109 } 110 setDebugName(const QByteArray & name)111 void setDebugName(const QByteArray &name) 112 { 113 m_debugName = name; 114 } 115 setRepresentsFunction(const RepresentsFunction & represents)116 void setRepresentsFunction(const RepresentsFunction &represents) 117 { 118 m_represents = represents; 119 } 120 reset()121 void reset() override 122 { 123 clear(); 124 doFetch(); 125 } 126 onAdded(const InputType & input)127 void onAdded(const InputType &input) override 128 { 129 typename Provider::Ptr provider(m_provider.toStrongRef()); 130 131 if (!provider) 132 return; 133 134 if (m_predicate(input)) 135 addToProvider(provider, input); 136 } 137 onChanged(const InputType & input)138 void onChanged(const InputType &input) override 139 { 140 typename Provider::Ptr provider(m_provider.toStrongRef()); 141 142 if (!provider) 143 return; 144 145 if (!m_predicate(input)) { 146 for (int i = 0; i < provider->data().size(); i++) { 147 auto output = provider->data().at(i); 148 if (m_represents(input, output)) { 149 provider->removeAt(i); 150 i--; 151 } 152 } 153 } else { 154 bool found = false; 155 156 for (int i = 0; i < provider->data().size(); i++) { 157 auto output = provider->data().at(i); 158 if (m_represents(input, output)) { 159 m_update(input, output); 160 provider->replace(i, output); 161 162 found = true; 163 } 164 } 165 166 if (!found) 167 addToProvider(provider, input); 168 } 169 } 170 onRemoved(const InputType & input)171 void onRemoved(const InputType &input) override 172 { 173 typename Provider::Ptr provider(m_provider.toStrongRef()); 174 175 if (!provider) 176 return; 177 178 for (int i = 0; i < provider->data().size(); i++) { 179 auto output = provider->data().at(i); 180 if (m_represents(input, output)) { 181 provider->removeAt(i); 182 i--; 183 } 184 } 185 } 186 187 private: 188 template<typename T> isValidOutput(const T &)189 bool isValidOutput(const T &/*output*/) 190 { 191 return true; 192 } 193 194 template<typename T> isValidOutput(const QSharedPointer<T> & output)195 bool isValidOutput(const QSharedPointer<T> &output) 196 { 197 return !output.isNull(); 198 } 199 200 template<typename T> isValidOutput(T * output)201 bool isValidOutput(T *output) 202 { 203 return output != nullptr; 204 } 205 addToProvider(const typename Provider::Ptr & provider,const InputType & input)206 void addToProvider(const typename Provider::Ptr &provider, const InputType &input) 207 { 208 auto output = m_convert(input); 209 if (isValidOutput(output)) 210 provider->append(output); 211 } 212 doFetch()213 void doFetch() 214 { 215 typename Provider::Ptr provider(m_provider.toStrongRef()); 216 217 if (!provider) 218 return; 219 220 auto addFunction = [this, provider] (const InputType &input) { 221 if (m_predicate(input)) 222 addToProvider(provider, input); 223 }; 224 225 m_fetch(addFunction); 226 } 227 clear()228 void clear() 229 { 230 typename Provider::Ptr provider(m_provider.toStrongRef()); 231 232 if (!provider) 233 return; 234 235 while (!provider->data().isEmpty()) 236 provider->removeFirst(); 237 } 238 239 FetchFunction m_fetch; 240 PredicateFunction m_predicate; 241 ConvertFunction m_convert; 242 UpdateFunction m_update; 243 RepresentsFunction m_represents; 244 QByteArray m_debugName; 245 246 typename Provider::WeakPtr m_provider; 247 }; 248 249 // A query that stores an intermediate list of results (from the fetch), to react on changes on any item in that list 250 // and then filters that list with the predicate for the final result 251 // When one of the intermediary items changes, a full fetch is done again. 252 template<typename InputType, typename OutputType> 253 class LiveRelationshipQuery : public LiveQueryInput<InputType>, public LiveQueryOutput<OutputType> 254 { 255 public: 256 typedef QSharedPointer<LiveRelationshipQuery<InputType, OutputType>> Ptr; 257 typedef QList<Ptr> List; 258 259 typedef QueryResultProvider<OutputType> Provider; 260 typedef QueryResult<OutputType> Result; 261 262 typedef typename LiveQueryInput<InputType>::AddFunction AddFunction; 263 typedef typename LiveQueryInput<InputType>::FetchFunction FetchFunction; 264 typedef typename LiveQueryInput<InputType>::PredicateFunction PredicateFunction; 265 266 typedef std::function<OutputType(const InputType &)> ConvertFunction; 267 typedef std::function<bool(const InputType &, const OutputType &)> RepresentsFunction; 268 typedef std::function<bool(const InputType &, const InputType &)> CompareFunction; 269 270 LiveRelationshipQuery() = default; 271 LiveRelationshipQuery(const LiveRelationshipQuery &other) = default; 272 LiveRelationshipQuery &operator=(const LiveRelationshipQuery &other) = default; 273 ~LiveRelationshipQuery()274 ~LiveRelationshipQuery() 275 { 276 clear(); 277 } 278 result()279 typename Result::Ptr result() override 280 { 281 typename Provider::Ptr provider(m_provider.toStrongRef()); 282 283 if (provider) 284 return Result::create(provider); 285 provider = Provider::Ptr::create(); 286 m_provider = provider.toWeakRef(); 287 288 doFetch(); 289 290 return Result::create(provider); 291 } 292 setFetchFunction(const FetchFunction & fetch)293 void setFetchFunction(const FetchFunction &fetch) 294 { 295 m_fetch = fetch; 296 } 297 setPredicateFunction(const PredicateFunction & predicate)298 void setPredicateFunction(const PredicateFunction &predicate) 299 { 300 m_predicate = predicate; 301 } 302 setCompareFunction(const CompareFunction & compare)303 void setCompareFunction(const CompareFunction &compare) 304 { 305 m_compare = compare; 306 } 307 setConvertFunction(const ConvertFunction & convert)308 void setConvertFunction(const ConvertFunction &convert) 309 { 310 m_convert = convert; 311 } 312 setDebugName(const QByteArray & name)313 void setDebugName(const QByteArray &name) 314 { 315 m_debugName = name; 316 } 317 setRepresentsFunction(const RepresentsFunction & represents)318 void setRepresentsFunction(const RepresentsFunction &represents) 319 { 320 m_represents = represents; 321 } 322 reset()323 void reset() override 324 { 325 clear(); 326 doFetch(); 327 } 328 onAdded(const InputType & input)329 void onAdded(const InputType &input) override 330 { 331 typename Provider::Ptr provider(m_provider.toStrongRef()); 332 333 if (!provider) 334 return; 335 336 m_intermediaryResults.append(input); 337 if (m_predicate(input)) 338 addToProvider(provider, input); 339 } 340 onChanged(const InputType & input)341 void onChanged(const InputType &input) override 342 { 343 Q_ASSERT(m_compare); 344 const bool found = std::any_of(m_intermediaryResults.constBegin(), m_intermediaryResults.constEnd(), 345 [&input, this](const InputType &existing) { 346 return m_compare(input, existing); 347 }); 348 if (found) 349 reset(); 350 } 351 onRemoved(const InputType & input)352 void onRemoved(const InputType &input) override 353 { 354 onChanged(input); 355 } 356 357 private: 358 template<typename T> isValidOutput(const T &)359 bool isValidOutput(const T &/*output*/) 360 { 361 return true; 362 } 363 364 template<typename T> isValidOutput(const QSharedPointer<T> & output)365 bool isValidOutput(const QSharedPointer<T> &output) 366 { 367 return !output.isNull(); 368 } 369 370 template<typename T> isValidOutput(T * output)371 bool isValidOutput(T *output) 372 { 373 return output != nullptr; 374 } 375 addToProvider(const typename Provider::Ptr & provider,const InputType & input)376 void addToProvider(const typename Provider::Ptr &provider, const InputType &input) 377 { 378 auto output = m_convert(input); 379 if (isValidOutput(output)) 380 provider->append(output); 381 } 382 doFetch()383 void doFetch() 384 { 385 auto addFunction = [this] (const InputType &input) { 386 onAdded(input); 387 }; 388 m_fetch(addFunction); 389 } 390 clear()391 void clear() 392 { 393 m_intermediaryResults.clear(); 394 395 typename Provider::Ptr provider(m_provider.toStrongRef()); 396 397 if (!provider) 398 return; 399 400 while (!provider->data().isEmpty()) 401 provider->removeFirst(); 402 } 403 404 FetchFunction m_fetch; 405 PredicateFunction m_predicate; 406 ConvertFunction m_convert; 407 CompareFunction m_compare; 408 RepresentsFunction m_represents; 409 QByteArray m_debugName; 410 411 typename Provider::WeakPtr m_provider; 412 QList<InputType> m_intermediaryResults; 413 }; 414 415 } 416 417 #endif // DOMAIN_LIVEQUERY_H 418