Akonadi

collectionqueryhelper.cpp
1 /*
2  Copyright (c) 2009 Volker Krause <[email protected]>
3 
4  This library is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Library General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or (at your
7  option) any later version.
8 
9  This library is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12  License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to the
16  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  02110-1301, USA.
18 */
19 
20 #include "collectionqueryhelper.h"
21 
22 #include "connection.h"
23 #include "entities.h"
24 #include "storage/querybuilder.h"
25 #include "storage/selectquerybuilder.h"
26 #include "handler.h"
27 #include "queryhelper.h"
28 
29 #include <private/scope_p.h>
30 #include <private/imapset_p.h>
31 
32 using namespace Akonadi;
33 using namespace Akonadi::Server;
34 
35 void CollectionQueryHelper::remoteIdToQuery(const QStringList &rids, const CommandContext &context, QueryBuilder &qb)
36 {
37  if (rids.size() == 1) {
38  qb.addValueCondition(Collection::remoteIdFullColumnName(), Query::Equals, rids.first());
39  } else {
40  qb.addValueCondition(Collection::remoteIdFullColumnName(), Query::In, rids);
41  }
42 
43  if (context.resource().isValid()) {
44  qb.addValueCondition(Collection::resourceIdFullColumnName(), Query::Equals, context.resource().id());
45  }
46 }
47 
48 void CollectionQueryHelper::scopeToQuery(const Scope &scope, const CommandContext &context, QueryBuilder &qb)
49 {
50  if (scope.scope() == Scope::Uid) {
51  QueryHelper::setToQuery(scope.uidSet(), Collection::idFullColumnName(), qb);
52  } else if (scope.scope() == Scope::Rid) {
53  if (context.collectionId() <= 0 && !context.resource().isValid()) {
54  throw HandlerException("Operations based on remote identifiers require a resource or collection context");
55  }
56  CollectionQueryHelper::remoteIdToQuery(scope.ridSet(), context, qb);
57  } else if (scope.scope() == Scope::HierarchicalRid) {
58  if (!context.resource().isValid()) {
59  throw HandlerException("Operations based on hierarchical remote identifiers require a resource or collection context");
60  }
61  const Collection c = CollectionQueryHelper::resolveHierarchicalRID(scope.hridChain(), context.resource().id());
62  qb.addValueCondition(Collection::idFullColumnName(), Query::Equals, c.id());
63  } else {
64  throw HandlerException("WTF?");
65  }
66 }
67 
68 bool CollectionQueryHelper::hasAllowedName(const Collection &collection, const QString &name, Collection::Id parent)
69 {
70  Q_UNUSED(collection);
72  if (parent > 0) {
73  qb.addValueCondition(Collection::parentIdColumn(), Query::Equals, parent);
74  } else {
75  qb.addValueCondition(Collection::parentIdColumn(), Query::Is, QVariant());
76  }
77  qb.addValueCondition(Collection::nameColumn(), Query::Equals, name);
78  if (!qb.exec()) {
79  return false;
80  }
81  const QVector<Collection> result = qb.result();
82  if (!result.isEmpty()) {
83  if (result.first().id() == collection.id()) {
84  return true;
85  }
86  return false;
87  }
88  return true;
89 }
90 
91 bool CollectionQueryHelper::canBeMovedTo(const Collection &collection, const Collection &_parent)
92 {
93  if (_parent.isValid()) {
94  Collection parent = _parent;
95  Q_FOREVER {
96  if (parent.id() == collection.id()) {
97  return false; // target is child of source
98  }
99  if (parent.parentId() == 0) {
100  break;
101  }
102  parent = parent.parent();
103  }
104  }
105  return hasAllowedName(collection, collection.name(), _parent.id());
106 }
107 
109 {
110  if (ridChain.size() < 2) {
111  throw HandlerException("Empty or incomplete hierarchical RID chain");
112  }
113  if (!ridChain.last().isEmpty()) {
114  throw HandlerException("Hierarchical RID chain is not root-terminated");
115  }
116  Collection::Id parentId = 0;
117  Collection result;
118  for (int i = ridChain.size() - 2; i >= 0; --i) {
120  if (parentId > 0) {
121  qb.addValueCondition(Collection::parentIdColumn(), Query::Equals, parentId);
122  } else {
123  qb.addValueCondition(Collection::parentIdColumn(), Query::Is, QVariant());
124  }
125  qb.addValueCondition(Collection::remoteIdColumn(), Query::Equals, ridChain.at(i).remoteId);
126  qb.addValueCondition(Collection::resourceIdColumn(), Query::Equals, resId);
127  if (!qb.exec()) {
128  throw HandlerException("Unable to execute query");
129  }
130  const Collection::List results = qb.result();
131  const int resultSize = results.size();
132  if (resultSize == 0) {
133  throw HandlerException("Hierarchical RID does not specify an existing collection");
134  } else if (resultSize > 1) {
135  throw HandlerException("Hierarchical RID does not specify a unique collection");
136  }
137  result = results.first();
138  parentId = result.id();
139  }
140  return result;
141 }
142 
143 Collection CollectionQueryHelper::singleCollectionFromScope(const Scope &scope, const CommandContext &context)
144 {
145  // root
146  if (scope.scope() == Scope::Uid && scope.uidSet().intervals().count() == 1) {
147  const ImapInterval i = scope.uidSet().intervals().at(0);
148  if (!i.size()) { // ### why do we need this hack for 0, shouldn't that be size() == 1?
149  Collection root;
150  root.setId(0);
151  return root;
152  }
153  }
155  scopeToQuery(scope, context, qb);
156  if (!qb.exec()) {
157  throw HandlerException("Unable to execute query");
158  }
159  const Collection::List cols = qb.result();
160  if (cols.isEmpty()) {
161  throw HandlerException("No collection found");
162  } else if (cols.size() > 1) {
163  throw HandlerException("Collection cannot be uniquely identified");
164  }
165  return cols.first();
166 }
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.
qint64 Id
Describes the unique id type.
Definition: collection.h:82
T & last()
T & first()
qint64 parentId() const
Returns the value of the parentId column of this record.
Definition: entities.cpp:1442
Collection resolveHierarchicalRID(const QVector< Scope::HRID > &hridChain, Resource::Id resId)
Retrieve the collection referred to by the given hierarchical RID chain.
int size() const const
bool canBeMovedTo(const Collection &collection, const Collection &parent)
Checks if a collection could be moved from its current parent into the given one. ...
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.
Collection singleCollectionFromScope(const Scope &scope, const CommandContext &context)
Returns an existing collection specified by the given scope.
void remoteIdToQuery(const QStringList &rids, const CommandContext &context, QueryBuilder &qb)
Add conditions to qb for the given remote identifier rid.
QVector< T > result()
Returns the result of this SELECT query.
T & first()
void scopeToQuery(const Scope &scope, const CommandContext &context, QueryBuilder &qb)
Add conditions to qb for the given collection operation scope scope.
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:29
const T & at(int i) const const
Helper class for creating and executing database SELECT queries.
QString name() const
Returns the value of the name column of this record.
bool isEmpty() const const
Helper integration between Akonadi and Qt.
int size() const const
Helper class to construct arbitrary SQL queries.
Definition: querybuilder.h:45
Collection parent() const
Retrieve the Collection record referred to by the parentId column of this record. ...
Definition: entities.cpp:2552
bool exec()
Executes the query, returns true on success.
Representation of a record in the Collection table.
Definition: entities.h:451
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon May 25 2020 22:46:08 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.