Changes: ID fetch request: Forward error code in emulated mode
[qtcontacts-tracker:qtcontacts-tracker.git] / src / engine / contactidfetchrequest.cpp
1 /*********************************************************************************
2  ** This file is part of QtContacts tracker storage plugin
3  **
4  ** Copyright (c) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
5  **
6  ** Contact:  Nokia Corporation (info@qt.nokia.com)
7  **
8  ** GNU Lesser General Public License Usage
9  ** This file may be used under the terms of the GNU Lesser General Public License
10  ** version 2.1 as published by the Free Software Foundation and appearing in the
11  ** file LICENSE.LGPL included in the packaging of this file.  Please review the
12  ** following information to ensure the GNU Lesser General Public License version
13  ** 2.1 requirements will be met:
14  ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
15  **
16  ** In addition, as a special exception, Nokia gives you certain additional rights.
17  ** These rights are described in the Nokia Qt LGPL Exception version 1.1, included
18  ** in the file LGPL_EXCEPTION.txt in this package.
19  **
20  ** Other Usage
21  ** Alternatively, this file may be used in accordance with the terms and
22  ** conditions contained in a signed written agreement between you and Nokia.
23  *********************************************************************************/
24
25 #include "contactidfetchrequest.h"
26
27 #include "dao/contactdetailschema.h"
28 #include "dao/scalarquerybuilder.h"
29 #include "dao/sparqlconnectionmanager.h"
30 #include "engine/contactfetchrequest.h"
31 #include "engine/engine.h"
32
33 #include <ontologies/rdf.h>
34 #include <QtSparql>
35
36 ///////////////////////////////////////////////////////////////////////////////////////////////////
37
38 CUBI_USE_NAMESPACE
39
40 ///////////////////////////////////////////////////////////////////////////////////////////////////
41
42 QTrackerContactIdFetchRequest::QTrackerContactIdFetchRequest(QContactAbstractRequest *request,
43                                                              QContactTrackerEngine *engine,
44                                                              QObject *parent)
45     : QTrackerBaseRequest<QContactLocalIdFetchRequest>(engine, parent)
46     , m_filter(staticCast(request)->filter())
47     , m_sorting(staticCast(request)->sorting())
48 {
49 }
50
51 QTrackerContactIdFetchRequest::~QTrackerContactIdFetchRequest()
52 {
53 }
54
55 QString
56 QTrackerContactIdFetchRequest::buildQuery(QContactManager::Error &error)
57 {
58     Select select;
59     PatternBase base;
60
61     Variable contact = Variable(QLatin1String("contact"));
62     select.addProjection(Functions::trackerId.apply(contact));
63
64     foreach(const QString &contactType, engine()->supportedContactTypes()) {
65         PatternGroup group;
66         Filter filter;
67         const QTrackerContactDetailSchema &schema = engine()->schema(contactType);
68
69         // add restrictions from request filters
70         QTrackerScalarContactQueryBuilder queryBuilder(schema, engine()->managerUri());
71
72         error = queryBuilder.bindFilter(m_filter, filter);
73
74         if (error != QContactManager::NoError) {
75             return QString();
76         }
77
78         foreach(const QString &classIri, schema.contactClassIris()) {
79             ResourceValue iri = ResourceValue(classIri);
80             group.addPattern(contact, Resources::rdf::type::resource(), iri);
81         }
82
83         group.setFilter(filter);
84
85         if (not base.isValid()) {
86             base = group;
87         } else {
88             base = Union(base, group);
89         }
90     }
91
92     error = QContactManager::NoError;
93     select.addRestriction(base);
94
95     return select.sparql();
96 }
97
98 void
99 QTrackerContactIdFetchRequest::run()
100 {
101     if (isCanceled()) {
102         return;
103     }
104
105     if (m_sorting.isEmpty()) {
106         runNative();
107     } else {
108         runEmulated();
109     }
110 }
111
112 void
113 QTrackerContactIdFetchRequest::runNative()
114 {
115     // build the SPARQL query
116     QContactManager::Error error = QContactManager::UnspecifiedError;
117     const QString queryString = buildQuery(error);
118
119     if (error != QContactManager::NoError) {
120         setLastError(error);
121         return;
122     }
123
124     QScopedPointer<QSparqlResult> result(runQuery(QSparqlQuery(queryString), SyncQueryOptions));
125
126     if (result.isNull()) {
127         // runQuery() called reportError()
128         return;
129     }
130
131     // We use a QSet since we want to ensure there are no duplicates
132     QSet<QContactLocalId> localIds;
133
134     // We use a QSet because we want to eliminate duplicates.
135     // In case of unioned QContactDetailFilter (for instance), the same localId
136     // may be included multiple times; this is undesirable.
137     while(not isCanceled() && result->next()) {
138         if (engine()->hasDebugFlag(QContactTrackerEngine::ShowModels)) {
139             qDebug() << result->current();
140         }
141
142         localIds.insert(result->value(0).toUInt());
143     }
144
145     m_localIds = localIds.toList();
146 }
147
148 void
149 QTrackerContactIdFetchRequest::runEmulated()
150 {
151     // We only use emulated version for sorting
152     Q_ASSERT(not m_sorting.isEmpty());
153
154     if (engine()->hasDebugFlag(QContactTrackerEngine::ShowNotes)) {
155         qctWarn(QString::fromLatin1("Warning, using emulated localId fetch request"));
156     }
157
158
159     QContactFetchHint hint;
160     // An empty hint means "all details", therefore we pass at least one detail name here
161     hint.setDetailDefinitionsHint(QStringList() << m_sorting.first().detailDefinitionName());
162
163     QContactFetchRequest request;
164     request.setFetchHint(hint);
165     request.setSorting(m_sorting);
166     request.setFilter(m_filter);
167
168     QScopedPointer<QTrackerAbstractRequest>(engine()->createRequestWorker(&request))->exec();
169
170     if (request.error() != QContactManager::NoError) {
171         setLastError(request.error());
172         return;
173     }
174
175     foreach(const QContact &contact, request.contacts()) {
176         if (engine()->hasDebugFlag(QContactTrackerEngine::ShowModels)) {
177             qDebug() << contact.localId();
178         }
179
180         // Here we do not need to check for duplicate ids, since the fetch request
181         // already does that
182         m_localIds.append(contact.localId());
183     }
184 }
185
186 void
187 QTrackerContactIdFetchRequest::updateRequest(QContactManager::Error error)
188 {
189     engine()->updateContactLocalIdFetchRequest(staticCast(engine()->request(this).data()),
190                                                m_localIds, error,
191                                                QContactAbstractRequest::FinishedState);
192 }
193
194 ///////////////////////////////////////////////////////////////////////////////////////////////////
195
196 #include "moc_contactidfetchrequest.cpp"