Merge lp:~kevin-wright-1/u1db-qt/index-query-april-5-i into lp:u1db-qt

Proposed by Kevin Wright
Status: Rejected
Rejected by: Cris Dywan
Proposed branch: lp:~kevin-wright-1/u1db-qt/index-query-april-5-i
Merge into: lp:u1db-qt
Diff against target: 510 lines (+349/-25)
5 files modified
examples/u1db-qt-example-5.qml (+167/-0)
index.cpp (+152/-1)
index.h (+8/-4)
query.cpp (+21/-15)
query.h (+1/-5)
To merge this branch: bzr merge lp:~kevin-wright-1/u1db-qt/index-query-april-5-i
Reviewer Review Type Date Requested Status
Cris Dywan Needs Fixing
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Review via email: mp+157369@code.launchpad.net

Commit message

Created initial index functionality. Modified source for both Index and Query. Within the Index source, QVariantMaps are generated (based on the index expressions), using appropriate data, and put into a QList, which is used by Query::data as its return value. Some known issues: currently will match on any index expression criteria (rather than on all criteria), and will not recognize new databases / documents (but has no problems with existing ones).

Description of the change

Created initial index functionality. Modified source for both Index and Query. Within the Index source, QVariantMaps are generated (based on the index expressions), using appropriate data, and put into a QList, which is used by Query::data as its return value. Some known issues: currently will match on any index expression criteria (rather than on all criteria), and will not recognize new databases / documents (but has no problems with existing ones).

To post a comment you must log in.
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Cris Dywan (kalikiana) wrote :

Please make separate commits for a) the index.cpp code b) the example c) qdoc changes. I see different qdoc changes all over the place, some of which look wrong.

I can't break up the MR on my end unfortunately, so I'm marking this whole as Needs Fixing.

review: Needs Fixing

Unmerged revisions

61. By Kevin Wright

Created initial index functionality. Modified source for both Index and Query. Within the Index source, QVariantMaps are generated (based on the index expressions), using appropriate data, and put into a QList, which is used by Query::data as its return value. Some known issues: currently will match on any index expression criteria (rather than on all criteria), and will not recognize new databases / documents (but has no problems with existing ones).

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'examples/u1db-qt-example-5.qml'
2--- examples/u1db-qt-example-5.qml 1970-01-01 00:00:00 +0000
3+++ examples/u1db-qt-example-5.qml 2013-04-05 14:01:48 +0000
4@@ -0,0 +1,167 @@
5+/*
6+ * Copyright (C) 2013 Canonical, Ltd.
7+ *
8+ * Authors:
9+ * Kevin Wright <kevin.wright@canonical.com>
10+ *
11+ * This program is free software; you can redistribute it and/or modify
12+ * it under the terms of the GNU Lesser General Public License as published by
13+ * the Free Software Foundation; version 3.
14+ *
15+ * This program is distributed in the hope that it will be useful,
16+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
17+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+ * GNU Lesser General Public License for more details.
19+ *
20+ * You should have received a copy of the GNU Lesser General Public License
21+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
22+ */
23+
24+import QtQuick 2.0
25+import U1db 1.0 as U1db
26+import Ubuntu.Components 0.1
27+
28+/*!
29+
30+This example and tutorial is designed to show a wide variety of U1Db-Qt functionality and usage. The example demonstrates:
31+
32+\list 1
33+ \li Using Index and Query elements
34+\endlist
35+
36+ */
37+
38+Item {
39+
40+ width: units.gu(45)
41+ height: units.gu(80)
42+
43+ /*!
44+
45+ A Database is very simple to create. It only needs an id and a path where the file will be created. A Database is a model, which can be used by elements, such as the ListView further in this example.
46+
47+ U1db.Database {
48+ id: aDatabase
49+ path: "aDatabase4"
50+ }
51+
52+ */
53+
54+ U1db.Database {
55+ id: aDatabase
56+ path: "aDatabase5"
57+ }
58+
59+ /*!
60+
61+ A Document can be declared at runtime. It requires at the very least a unique 'docId', but that alone won't do anything special. The snipet below snippet demonstrates the basic requirements.
62+
63+ In addition to this, this example displays text from the database for a specific docId and id key in a text area called 'documentContent. To update the text area at startup with either the default value or a value from the database the onCompleted function is utilized, which is also demonstrated below.
64+
65+ U1db.Document {
66+ id: aDocument
67+ database: aDatabase
68+ docId: 'helloworld'
69+ create: true
70+ defaults: { "helloworld":"Hello World" }
71+
72+ Component.onCompleted: {
73+ documentContent.text = aDocument.contents.helloworld
74+ }
75+
76+ }
77+
78+ */
79+
80+
81+ U1db.Document {
82+ id: aDocument
83+ database: aDatabase
84+ docId: 'helloworld'
85+ create: true
86+ defaults:{"hello": { "world": [{ "message":"Hello World", "id": 1 }] } }
87+
88+ }
89+ U1db.Document {
90+ id: aDocument2
91+ database: aDatabase
92+ docId: 'helloworld2'
93+ create: true
94+ defaults:{"hello": { "world": [{ "message":"Hello World", "id": 2 }] } }
95+
96+ }
97+
98+ U1db.Index{
99+ database: aDatabase
100+ id: by_helloworld
101+ name: "by-helloworld"
102+ expression: ["hello.world.id","hello.world.message"]
103+ }
104+ U1db.Query{
105+ id: helloListModel
106+ index: by_helloworld
107+ //query: "*"
108+ }
109+
110+ MainView {
111+
112+ id: u1dbView
113+ width: units.gu(45)
114+ height: units.gu(80)
115+ anchors.top: parent.top;
116+
117+ Tabs {
118+ id: tabs
119+ anchors.fill: parent
120+
121+ Tab {
122+ objectName: "Tab1"
123+
124+ title: i18n.tr("Hello U1Db!")
125+
126+ page: Page {
127+ id: helloPage
128+ ListView {
129+ width: units.gu(45)
130+ height: units.gu(80)
131+
132+ /*
133+ Here is the reference to the Database model mentioned earlier.
134+ */
135+ model: helloListModel
136+
137+ /* A delegate will be created for each Document retrieved from the Database */
138+ delegate: Text {
139+ x: 66; y: 77
140+ text: {
141+ /*!
142+ The object called 'contents' contains a string as demonstrated here. In this example 'hello' is our search string.
143+
144+ text: contents.hello
145+ */
146+
147+ text: contents.id + " " + contents.message
148+ }
149+ }
150+ }
151+ }
152+
153+
154+ }
155+
156+ }
157+
158+
159+
160+
161+ }
162+
163+
164+
165+
166+
167+
168+
169+ }
170+
171+
172
173=== modified file 'index.cpp'
174--- index.cpp 2013-04-03 15:36:45 +0000
175+++ index.cpp 2013-04-05 14:01:48 +0000
176@@ -32,7 +32,6 @@
177
178 /*!
179 \class Index
180- \inmodule U1db
181
182 \brief The Index class defines an index to be stored in the database and
183 queried using Query. Changes in documents affected by the index also update
184@@ -89,6 +88,7 @@
185 QObject::connect(m_database, &Database::docChanged, this, &Index::onDocChanged);
186 Q_EMIT dataInvalidated();
187 }
188+
189 }
190
191 QString
192@@ -126,10 +126,14 @@
193 /*!
194 Sets the expression used. Both an expression and a name must be specified
195 for an index to be created.
196+
197+ Also starts the process of creating the Index result list, which can then be queried or populate the Query model as is.
198+
199 */
200 void
201 Index::setExpression(QStringList expression)
202 {
203+
204 if (m_expression == expression)
205 return;
206
207@@ -140,7 +144,154 @@
208 }
209
210 m_expression = expression;
211+
212+ generateIndexResults();
213+
214 Q_EMIT expressionChanged(expression);
215+ Q_EMIT dataIndexed();
216+}
217+
218+/*!
219+ * \brief Index::generateIndexResults
220+ *
221+ * Iterates through the documents stored in the database and creates the list of results based on the Index expressions.
222+ */
223+
224+void Index::generateIndexResults()
225+{
226+
227+ Database *db(getDatabase());
228+
229+ if(db){
230+
231+ QList<QString> documents = db->listDocs();
232+
233+ Q_FOREACH (QString docId, documents){
234+
235+ QVariant document = db->getDocUnchecked(docId);
236+
237+ QStringList fieldsList;
238+
239+ appendResultsFromMap(fieldsList, document.toMap(),"");
240+
241+ }
242+
243+ }
244+
245+}
246+/*!
247+ * \brief Index::getAllResults
248+ * \return
249+ */
250+
251+QList<QVariantMap> Index::getAllResults(){
252+ return m_results;
253+}
254+
255+/*!
256+ * \brief Index::getResult
257+ * \param index
258+ * \return
259+ */
260+QVariantMap Index::getResult(int index){
261+ return m_results[index];
262+}
263+
264+/*!
265+ * \brief Index::appendResultsFromMap
266+ * \param fieldsList
267+ * \param current_section
268+ * \param current_field
269+ * \return
270+ *
271+ *This method is desinged to recursively iterate through a document, or section of a document, which represents a QVariantMap. As it iterates through the entire document, the method keeps track of the current index expression, and populates a local QVariantMap should the current expression be found in the Index's list of expressions.
272+ *
273+ *If that QVariantMap contains more than one entry it is added to the global results, which can then be utilized by a Query. This needs to be modified to ensure all expressions are found, whereas at the moment if more than one expressions are defined and any of them are found then the map is added to the results list.
274+ *
275+ */
276+QStringList Index::appendResultsFromMap(QStringList fieldsList, QVariantMap current_section, QString current_field)
277+{
278+
279+ QMapIterator<QString, QVariant> i(current_section);
280+
281+ QString original_field = current_field;
282+
283+ QVariantMap results_map;
284+
285+ while (i.hasNext()) {
286+
287+ i.next();
288+
289+ if(fieldsList.count()>0){
290+ current_field = original_field + "." + i.key();
291+ }
292+ else{
293+ current_field = i.key();
294+ }
295+
296+ fieldsList.append(current_field);
297+
298+ QVariant value = i.value();
299+
300+ if(value.userType()==8) // QVariantMap
301+ {
302+ fieldsList = appendResultsFromMap(fieldsList, value.toMap(),current_field);
303+ }
304+ else if(value.userType()==9) // QVariantList
305+ {
306+ fieldsList = getFieldsFromList(fieldsList, value.toList(),current_field);
307+ }
308+ else
309+ {
310+ if(m_expression.contains(current_field)==true){
311+ results_map.insert(i.key(),value);
312+ }
313+
314+ }
315+ }
316+
317+ if(results_map.count()>0){
318+ m_results.append(results_map);
319+ }
320+
321+ return fieldsList;
322+}
323+/*!
324+ * \brief Index::getFieldsFromList
325+ * \param fieldsList
326+ * \param current_section
327+ * \param current_field
328+ * \return
329+ *
330+ *This recursive method is used in conjuntion with Index::appendResultsFromMap, to aid in iterating through a document when an embedded list is found.
331+ *
332+ */
333+
334+
335+QStringList Index::getFieldsFromList(QStringList fieldsList, QVariantList current_section, QString current_field)
336+{
337+
338+ QListIterator<QVariant> i(current_section);
339+
340+ while (i.hasNext()) {
341+
342+ QVariant value = i.next();
343+
344+ if(value.userType()==8) // QVariantMap
345+ {
346+ fieldsList = appendResultsFromMap(fieldsList, value.toMap(),current_field);
347+ }
348+ else if(value.userType()==9) // QVariantList
349+ {
350+ fieldsList = getFieldsFromList(fieldsList, value.toList(),current_field);
351+ }
352+ else
353+ {
354+
355+ }
356+ }
357+
358+ return fieldsList;
359 }
360
361 QT_END_NAMESPACE_U1DB
362
363=== modified file 'index.h'
364--- index.h 2013-04-03 15:36:45 +0000
365+++ index.h 2013-04-05 14:01:48 +0000
366@@ -30,11 +30,7 @@
367
368 class Q_DECL_EXPORT Index : public QObject {
369 Q_OBJECT
370-#ifdef Q_QDOC
371- Q_PROPERTY(Database* database READ getDatabase WRITE setDatabase NOTIFY databaseChanged)
372-#else
373 Q_PROPERTY(QT_PREPEND_NAMESPACE_U1DB(Database*) database READ getDatabase WRITE setDatabase NOTIFY databaseChanged)
374-#endif
375 Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameChanged)
376 Q_PROPERTY(QStringList expression READ getExpression WRITE setExpression NOTIFY expressionChanged)
377 public:
378@@ -47,17 +43,25 @@
379 void setName(const QString& name);
380 QStringList getExpression();
381 void setExpression(QStringList expression);
382+ void generateIndexResults();
383+ QStringList appendResultsFromMap(QStringList fieldsList, QVariantMap current_section, QString current_field);
384+ QStringList getFieldsFromList(QStringList fieldsList, QVariantList current_section, QString current_field);
385+ QVariantMap getResult(int index);
386+ QList<QVariantMap> getAllResults();
387+
388 Q_SIGNALS:
389 void databaseChanged(Database* database);
390 void nameChanged(const QString& name);
391 void expressionChanged(QVariant expression);
392 // Either of the above has changed:
393 void dataInvalidated();
394+ void dataIndexed();
395 private:
396 Q_DISABLE_COPY(Index)
397 Database* m_database;
398 QString m_name;
399 QStringList m_expression;
400+ QList<QVariantMap> m_results;
401
402 void onPathChanged(const QString& path);
403 void onDocChanged(const QString& docId, QVariant content);
404
405=== modified file 'query.cpp'
406--- query.cpp 2013-04-03 15:36:45 +0000
407+++ query.cpp 2013-04-05 14:01:48 +0000
408@@ -33,7 +33,6 @@
409
410 /*!
411 \class Query
412- \inmodule U1db
413
414 \brief The Query class generates a filtered list of documents based on either
415 a query or a range, and using the given Index.
416@@ -47,27 +46,27 @@
417 }
418
419 /*!
420- Used to implement QAbstractListModel
421- Implements the variables exposed to the Delegate in a model
422- QVariant contents
423- QString docId
424- int index (built-in)
425+ * \brief Query::data
426+ * \param index
427+ * \param role
428+ * \return
429+ *Used to implement QAbstractListModel
430+ *Implements the variables exposed to the Delegate in a model
431 */
432 QVariant
433 Query::data(const QModelIndex & index, int role) const
434 {
435- QString docId(m_hash.value(index.row()));
436+ QVariantMap result(m_hash.value(index.row()));
437 if (role == 0) // contents
438 {
439 Database* db(m_index->getDatabase());
440 if (db)
441 {
442- qDebug() << "Query::getData" << docId;
443- return db->getDocUnchecked(docId);
444+ return result;
445 }
446 }
447 if (role == 1) // docId
448- return docId;
449+ //return docId;
450 return QVariant();
451 }
452
453@@ -105,10 +104,14 @@
454 Query::onDataInvalidated()
455 {
456 m_hash.clear();
457- Database* db(m_index->getDatabase());
458- if (db)
459- ;
460- // TODO
461+
462+ QListIterator<QVariantMap> i(m_index->getAllResults());
463+
464+ while (i.hasNext()) {
465+ QVariantMap result = i.next();
466+ m_hash.insert(m_hash.count(),result);
467+ }
468+
469 }
470
471 /*!
472@@ -124,10 +127,13 @@
473 if (m_index)
474 QObject::disconnect(m_index, 0, this, 0);
475 m_index = index;
476- if (m_index)
477+ if (m_index){
478 QObject::connect(m_index, &Index::dataInvalidated, this, &Query::onDataInvalidated);
479+ QObject::connect(m_index, &Index::dataIndexed, this, &Query::onDataInvalidated);
480+ }
481 Q_EMIT indexChanged(index);
482 onDataInvalidated();
483+
484 }
485
486 QVariant
487
488=== modified file 'query.h'
489--- query.h 2013-04-03 15:36:45 +0000
490+++ query.h 2013-04-05 14:01:48 +0000
491@@ -29,11 +29,7 @@
492
493 class Q_DECL_EXPORT Query : public QAbstractListModel {
494 Q_OBJECT
495-#ifdef Q_QDOC
496- Q_PROPERTY(Index* index READ getIndex WRITE setIndex NOTIFY indexChanged)
497-#else
498 Q_PROPERTY(QT_PREPEND_NAMESPACE_U1DB(Index*) index READ getIndex WRITE setIndex NOTIFY indexChanged)
499-#endif
500 Q_PROPERTY(QVariant query READ getQuery WRITE setQuery NOTIFY queryChanged)
501 Q_PROPERTY(QVariant range READ getRange WRITE setRange NOTIFY rangeChanged)
502 public:
503@@ -58,7 +54,7 @@
504 private:
505 Q_DISABLE_COPY(Query)
506 Index* m_index;
507- QHash<int, QString> m_hash;
508+ QHash<int, QVariantMap> m_hash;
509 QVariant m_query;
510 QVariant m_range;
511

Subscribers

People subscribed via source and target branches

to all changes: