Changes: Use QSparqlQueryOptions in runQuery
[qtcontacts-tracker:hasselmms-qtcontacts-tracker.git] / src / engine / contactremoverequest.cpp
1 /** This file is part of QtContacts tracker storage plugin
2  **
3  ** Copyright (c) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
4  **
5  ** Contact:  Nokia Corporation (info@qt.nokia.com)
6  **
7  ** GNU Lesser General Public License Usage
8  ** This file may be used under the terms of the GNU Lesser General Public License
9  ** version 2.1 as published by the Free Software Foundation and appearing in the
10  ** file LICENSE.LGPL included in the packaging of this file.  Please review the
11  ** following information to ensure the GNU Lesser General Public License version
12  ** 2.1 requirements will be met:
13  ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
14  **
15  ** In addition, as a special exception, Nokia gives you certain additional rights.
16  ** These rights are described in the Nokia Qt LGPL Exception version 1.1, included
17  ** in the file LGPL_EXCEPTION.txt in this package.
18  **
19  ** Other Usage
20  ** Alternatively, this file may be used in accordance with the terms and
21  ** conditions contained in a signed written agreement between you and Nokia.
22  **/
23
24 #include "contactremoverequest.h"
25 #include "engine.h"
26
27 #include <dao/contactdetailschema.h>
28 #include <dao/sparqlconnectionmanager.h>
29 #include <dao/sparqlresolver.h>
30 #include <dao/subject.h>
31
32 #include <QtSparql>
33
34 QTrackerContactRemoveRequest::QTrackerContactRemoveRequest(QContactAbstractRequest *request,
35                                                            QContactTrackerEngine *engine,
36                                                            QObject *parent)
37     : QTrackerBaseRequest<QContactRemoveRequest>(engine, parent)
38     , m_contactIds(staticCast(request)->contactIds())
39 {
40 }
41
42 QTrackerContactRemoveRequest::~QTrackerContactRemoveRequest()
43 {
44 }
45
46 static QString
47 makeLocalUIDList(const QList<QContactLocalId> &localIdList)
48 {
49     QStringList idStrings;
50
51     foreach(QContactLocalId id, localIdList) {
52         idStrings.append(QString::number(id));
53     }
54
55     return idStrings.join(QString::fromLatin1(", "));
56 }
57
58 QString
59 QTrackerContactRemoveRequest::buildQuery(const QList<QContactLocalId> &localIds) const
60 {
61     static const QString queryTemplate = QLatin1String
62             ("DELETE {\n"
63              "  ?contact a rdfs:Resource\n"
64              "} WHERE {\n"
65              "  ?contact rdf:type nco:Contact .\n"
66              "  FILTER(tracker:id(?contact) IN (%1))\n"
67              "}\n");
68
69     // Taking localIds from argument instead of taking member because remove requests
70     // are split into small chunks to avoid "Too many variables" errors in tracker.
71     return queryTemplate.arg(makeLocalUIDList(localIds));
72 }
73
74 QString
75 QTrackerContactRemoveRequest::buildQuery() const
76 {
77     return buildQuery(m_contactIds);
78 }
79
80 void
81 QTrackerContactRemoveRequest::run()
82 {
83     setCancelable(false);
84
85     if (canceled()) {
86         emitResultLater();
87         return;
88     }
89
90     // We explicitly don't check for contact existance (DoesNotExistError error) because:
91     //
92     // 1) Checking for contact existance costs time.
93     // 2) More importantly checking for contact existance would be entirely racy.
94     //    Therefore such a feature would be entirely random and useless.
95     //
96     // If some customer explicitly asks for that feature we can spend time on how to implement
97     // an atomic contact existance check. Still this check would have to be explicitely requested
98     // per contact manager parameter for first reason.
99
100     QContactManager::Error error = QContactManager::UnspecifiedError;
101     const QContactLocalId selfId = engine()->selfContactId(&error);
102
103     if (error != QContactManager::NoError) {
104         setLastError(error);
105         emitResultLater();
106         return;
107     }
108
109     for (int i = m_contactIds.size() - 1; i >= 0; --i) {
110         if (selfId == m_contactIds[i]) {
111             m_errorMap.insert(i, QContactManager::PermissionsError);
112             m_contactIds.removeAt(i);
113             // This error will bubble up when handleQuerySuccess() emits the result
114             // but does not prevent us from removing the other contacts
115             setLastError(QContactManager::PermissionsError);
116         }
117     }
118
119     // check here for empty list to catch the case where the only id in the list
120     // was the self-id.
121     if (m_contactIds.isEmpty()) {
122         emitResultLater();
123         return;
124     }
125
126     QSparqlConnection &connection = QctSparqlConnectionManager::defaultConnection();
127
128     if (not connection.isValid()) {
129         qctWarn(QString::fromLatin1("Cannot remove contact: No valid QtSparql connection."));
130         setLastError(QContactManager::UnspecifiedError);
131         emitResultLater();
132         return;
133     }
134
135     while(not m_contactIds.isEmpty()) {
136         // split the local id list to avoid "Too many SQL variables" warning
137         const QList<QContactLocalId> nextLocalIds = m_contactIds.mid(0, QctSparqlResolver::ColumnLimit);
138         m_contactIds = m_contactIds.mid(nextLocalIds.count());
139
140         const QSparqlQuery query(buildQuery(nextLocalIds), QSparqlQuery::DeleteStatement);
141         QScopedPointer<QSparqlResult> result(runQuery(query, SyncQueryOptions));
142
143         if (result.isNull()) {
144             // runQuery() called reportError()
145             break;
146         }
147     }
148
149     emitResultLater();
150 }
151
152 void
153 QTrackerContactRemoveRequest::emitResult(QContactManager::Error error)
154 {
155     engine()->updateContactRemoveRequest(staticCast(engine()->request(this).data()),
156                                          error, m_errorMap, QContactAbstractRequest::FinishedState);
157 }
158
159 ///////////////////////////////////////////////////////////////////////////////////////////////////
160
161 #include "moc_contactremoverequest.cpp"