Akonadi

collectionqueryhelper.cpp
1 /*
2  SPDX-FileCopyrightText: 2009 Volker Krause <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "collectionqueryhelper.h"
8 
9 #include "connection.h"
10 #include "handler.h"
11 #include "queryhelper.h"
12 #include "storage/querybuilder.h"
13 #include "storage/selectquerybuilder.h"
14 
15 #include <private/imapset_p.h>
16 
17 using namespace Akonadi;
18 using namespace Akonadi::Server;
19 
20 void CollectionQueryHelper::remoteIdToQuery(const QStringList &rids, const CommandContext &context, QueryBuilder &qb)
21 {
22  if (rids.size() == 1) {
23  qb.addValueCondition(Collection::remoteIdFullColumnName(), Query::Equals, rids.first());
24  } else {
25  qb.addValueCondition(Collection::remoteIdFullColumnName(), Query::In, rids);
26  }
27 
28  if (context.resource().isValid()) {
29  qb.addValueCondition(Collection::resourceIdFullColumnName(), Query::Equals, context.resource().id());
30  }
31 }
32 
33 void CollectionQueryHelper::scopeToQuery(const Scope &scope, const CommandContext &context, QueryBuilder &qb)
34 {
35  if (scope.scope() == Scope::Uid) {
36  QueryHelper::setToQuery(scope.uidSet(), Collection::idFullColumnName(), qb);
37  } else if (scope.scope() == Scope::Rid) {
38  if (context.collectionId() <= 0 && !context.resource().isValid()) {
39  throw HandlerException("Operations based on remote identifiers require a resource or collection context");
40  }
41  CollectionQueryHelper::remoteIdToQuery(scope.ridSet(), context, qb);
42  } else if (scope.scope() == Scope::HierarchicalRid) {
43  if (!context.resource().isValid()) {
44  throw HandlerException("Operations based on hierarchical remote identifiers require a resource or collection context");
45  }
46  const Collection c = CollectionQueryHelper::resolveHierarchicalRID(scope.hridChain(), context.resource().id());
47  qb.addValueCondition(Collection::idFullColumnName(), Query::Equals, c.id());
48  } else {
49  throw HandlerException("WTF?");
50  }
51 }
52 
53 bool CollectionQueryHelper::hasAllowedName(const Collection &collection, const QString &name, Collection::Id parent)
54 {
55  Q_UNUSED(collection)
57  if (parent > 0) {
58  qb.addValueCondition(Collection::parentIdColumn(), Query::Equals, parent);
59  } else {
60  qb.addValueCondition(Collection::parentIdColumn(), Query::Is, QVariant());
61  }
62  qb.addValueCondition(Collection::nameColumn(), Query::Equals, name);
63  if (!qb.exec()) {
64  return false;
65  }
66  const QVector<Collection> result = qb.result();
67  if (!result.isEmpty()) {
68  return result.first().id() == collection.id();
69  }
70  return true;
71 }
72 
73 bool CollectionQueryHelper::canBeMovedTo(const Collection &collection, const Collection &_parent)
74 {
75  if (_parent.isValid()) {
76  Collection parent = _parent;
77  for (;;) {
78  if (parent.id() == collection.id()) {
79  return false; // target is child of source
80  }
81  if (parent.parentId() == 0) {
82  break;
83  }
84  parent = parent.parent();
85  }
86  }
87  return hasAllowedName(collection, collection.name(), _parent.id());
88 }
89 
91 {
92  if (ridChain.size() < 2) {
93  throw HandlerException("Empty or incomplete hierarchical RID chain");
94  }
95  if (!ridChain.last().isEmpty()) {
96  throw HandlerException("Hierarchical RID chain is not root-terminated");
97  }
98  Collection::Id parentId = 0;
99  Collection result;
100  for (int i = ridChain.size() - 2; i >= 0; --i) {
102  if (parentId > 0) {
103  qb.addValueCondition(Collection::parentIdColumn(), Query::Equals, parentId);
104  } else {
105  qb.addValueCondition(Collection::parentIdColumn(), Query::Is, QVariant());
106  }
107  qb.addValueCondition(Collection::remoteIdColumn(), Query::Equals, ridChain.at(i).remoteId);
108  qb.addValueCondition(Collection::resourceIdColumn(), Query::Equals, resId);
109  if (!qb.exec()) {
110  throw HandlerException("Unable to execute query");
111  }
112  const Collection::List results = qb.result();
113  const int resultSize = results.size();
114  if (resultSize == 0) {
115  throw HandlerException("Hierarchical RID does not specify an existing collection");
116  } else if (resultSize > 1) {
117  throw HandlerException("Hierarchical RID does not specify a unique collection");
118  }
119  result = results.first();
120  parentId = result.id();
121  }
122  return result;
123 }
124 
125 Collection CollectionQueryHelper::singleCollectionFromScope(const Scope &scope, const CommandContext &context)
126 {
127  // root
128  if (scope.scope() == Scope::Uid && scope.uidSet().intervals().count() == 1) {
129  const ImapInterval i = scope.uidSet().intervals().at(0);
130  if (!i.size()) { // ### why do we need this hack for 0, shouldn't that be size() == 1?
131  Collection root;
132  root.setId(0);
133  return root;
134  }
135  }
137  scopeToQuery(scope, context, qb);
138  if (!qb.exec()) {
139  throw HandlerException("Unable to execute query");
140  }
141  const Collection::List cols = qb.result();
142  if (cols.isEmpty()) {
143  throw HandlerException("No collection found");
144  } else if (cols.size() > 1) {
145  throw HandlerException("Collection cannot be uniquely identified");
146  }
147  return cols.first();
148 }
T & first()
bool isEmpty() const const
void setId(Id identifier)
Sets the unique identifier of the collection.
Definition: collection.cpp:91
T & last()
Represents a collection of PIM items.
Definition: collection.h:61
void setToQuery(const ImapSet &set, const QString &column, QueryBuilder &qb)
Add conditions to qb for the given uid set set applied to column.
Definition: queryhelper.cpp:16
Collection resolveHierarchicalRID(const QVector< Scope::HRID > &hridChain, Resource::Id resId)
Retrieve the collection referred to by the given hierarchical RID chain.
Collection singleCollectionFromScope(const Scope &scope, const CommandContext &context)
Returns an existing collection specified by the given scope.
T & first()
int size() const const
const T & at(int i) const const
QVector< T > result()
Returns the result of this SELECT query.
bool hasAllowedName(const Collection &collection, const QString &name, Collection::Id parent)
Checks if a collection could exist in the given parent folder with the given name.
void addValueCondition(const QString &column, Query::CompareOperator op, const QVariant &value, ConditionType type=WhereCondition)
Add a WHERE or HAVING condition which compares a column with a given value.
void scopeToQuery(const Scope &scope, const CommandContext &context, QueryBuilder &qb)
Add conditions to qb for the given collection operation scope scope.
bool exec()
Executes the query, returns true on success.
bool canBeMovedTo(const Collection &collection, const Collection &parent)
Checks if a collection could be moved from its current parent into the given one.
Helper class for creating and executing database SELECT queries.
void remoteIdToQuery(const QStringList &rids, const CommandContext &context, QueryBuilder &qb)
Add conditions to qb for the given remote identifier rid.
int size() const const
qint64 Id
Describes the unique id type.
Definition: collection.h:79
Helper class to construct arbitrary SQL queries.
Definition: querybuilder.h:31
Helper integration between Akonadi and Qt.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sat Jun 25 2022 06:00:31 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.