Merge lp:~kalikiana/u1db-qt/indexRoles into lp:u1db-qt

Proposed by Cris Dywan
Status: Needs review
Proposed branch: lp:~kalikiana/u1db-qt/indexRoles
Merge into: lp:u1db-qt
Diff against target: 485 lines (+349/-8)
6 files modified
debian/control (+2/-0)
examples/bookmarks/bookmarks.qml (+6/-3)
examples/movies/movies.qml (+196/-0)
src/query.cpp (+12/-2)
tests/test-database.cpp (+15/-0)
tests/tst_query.qml (+118/-3)
To merge this branch: bzr merge lp:~kalikiana/u1db-qt/indexRoles
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Benjamin Zeller Pending
Review via email: mp+211771@code.launchpad.net

Commit message

Expose index fields as role names

Description of the change

This is aimed to work with lp:~kalikiana/ubuntu-ui-toolkit/sortFilterModel.
TODO: Before merging we should have a unit test for it.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Andrew Hayzen (ahayzen) wrote :

FYI the branch which I was having issues sorting can be found here [0].

0 - https://code.launchpad.net/~andrew-hayzen/+junk/u1db-sortfiltermodel-recent-test

lp:~kalikiana/u1db-qt/indexRoles updated
118. By Cris Dywan

Add sort and filter unit test cases and movies example

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~kalikiana/u1db-qt/indexRoles updated
119. By Cris Dywan

Build and examples should depend on UI toolkit plugin

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~kalikiana/u1db-qt/indexRoles updated
120. By Cris Dywan

Merge lp:u1db-qt

121. By Cris Dywan

Add C++ unit test checking role names of Query

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~kalikiana/u1db-qt/indexRoles updated
122. By Cris Dywan

Work-around for sort.property not correctly re-sorting

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)

Unmerged revisions

122. By Cris Dywan

Work-around for sort.property not correctly re-sorting

121. By Cris Dywan

Add C++ unit test checking role names of Query

120. By Cris Dywan

Merge lp:u1db-qt

119. By Cris Dywan

Build and examples should depend on UI toolkit plugin

118. By Cris Dywan

Add sort and filter unit test cases and movies example

117. By Cris Dywan

Expose index fields as role names

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/control'
--- debian/control 2014-01-22 13:14:22 +0000
+++ debian/control 2014-11-12 17:08:18 +0000
@@ -14,6 +14,7 @@
14 qtdeclarative5-qtquick2-plugin,14 qtdeclarative5-qtquick2-plugin,
15 qtdeclarative5-test-plugin,15 qtdeclarative5-test-plugin,
16 qttools5-dev-tools,16 qttools5-dev-tools,
17 qtdeclarative5-ubuntu-ui-toolkit-plugin,
17 ubuntu-ui-toolkit-doc,18 ubuntu-ui-toolkit-doc,
18 xvfb,19 xvfb,
19 libgl1-mesa-dri,20 libgl1-mesa-dri,
@@ -65,6 +66,7 @@
65Section: doc66Section: doc
66Architecture: all67Architecture: all
67Depends: libu1db-qt5-3 (>= ${source:Version}),68Depends: libu1db-qt5-3 (>= ${source:Version}),
69 qtdeclarative5-ubuntu-ui-toolkit-plugin,
68 ${misc:Depends},70 ${misc:Depends},
69Description: Qt5 binding and QtQuick2 plugin for U1DB - examples71Description: Qt5 binding and QtQuick2 plugin for U1DB - examples
70 Simple Qt5 binding and QtQuick2 plugin for U1DB (https://launchpad.net/u1db).72 Simple Qt5 binding and QtQuick2 plugin for U1DB (https://launchpad.net/u1db).
7173
=== modified file 'examples/bookmarks/bookmarks.qml'
--- examples/bookmarks/bookmarks.qml 2014-02-17 17:40:42 +0000
+++ examples/bookmarks/bookmarks.qml 2014-11-12 17:08:18 +0000
@@ -123,8 +123,8 @@
123 property string detailsDocId: ""123 property string detailsDocId: ""
124 property string detailsContents: ""124 property string detailsContents: ""
125 delegate: ListItem.Subtitled {125 delegate: ListItem.Subtitled {
126 text: contents.title || '[title:%1]'.arg(docId)126 text: title
127 subText: contents.uri || '[uri:%1]'.arg(docId)127 subText: uri
128 // iconSource: contents.uri + "/favicon.ico"128 // iconSource: contents.uri + "/favicon.ico"
129 fallbackIconName: "favorite-unselected,text-html"129 fallbackIconName: "favorite-unselected,text-html"
130 iconFrame: false130 iconFrame: false
@@ -147,7 +147,7 @@
147 ListElement { label: 'Ubuntu'; expression: "[ 'uri' ]"; query: "[ 'http://www.ubuntu*' ]" }147 ListElement { label: 'Ubuntu'; expression: "[ 'uri' ]"; query: "[ 'http://www.ubuntu*' ]" }
148 ListElement { label: 'Search'; expression: "[ 'meta.title' ]"; query: "[ 'Search*' ]" }148 ListElement { label: 'Search'; expression: "[ 'meta.title' ]"; query: "[ 'Search*' ]" }
149 ListElement { label: 'Engine'; expression: "[ 'meta.tags' ]"; query: "[ 'engine' ]" }149 ListElement { label: 'Engine'; expression: "[ 'meta.tags' ]"; query: "[ 'engine' ]" }
150 ListElement { label: 'All'; expression: "[ 'meta.visits', 'meta.title' ]"; query: "[ '*', '*' ]" }150 ListElement { label: 'All'; expression: "[ 'meta.visits', 'meta.title', 'uri' ]"; query: "[ '*', '*', '*' ]" }
151 }151 }
152 delegate: OptionSelectorDelegate {152 delegate: OptionSelectorDelegate {
153 text: i18n.tr(label)153 text: i18n.tr(label)
@@ -156,8 +156,11 @@
156 onSelectedIndexChanged: {156 onSelectedIndexChanged: {
157 var d = model.get(selectedIndex)157 var d = model.get(selectedIndex)
158 text = '%1 - %2'.arg(d.expression).arg(d.query)158 text = '%1 - %2'.arg(d.expression).arg(d.query)
159 bookmarksList.model = null
159 allBookmarks.index.expression = eval(d.expression)160 allBookmarks.index.expression = eval(d.expression)
160 allBookmarks.query = eval(d.query)161 allBookmarks.query = eval(d.query)
162 // Force update of delegates and role names
163 bookmarksList.model = allBookmarks
161 }164 }
162 }165 }
163 }166 }
164167
=== added directory 'examples/movies'
=== added file 'examples/movies/movies.qml'
--- examples/movies/movies.qml 1970-01-01 00:00:00 +0000
+++ examples/movies/movies.qml 2014-11-12 17:08:18 +0000
@@ -0,0 +1,196 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * Authors:
5 * Christian Dywan <christian.dywan@canonical.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; version 3.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20import QtQuick 2.0
21import U1db 1.0 as U1db
22import Ubuntu.Components 1.1
23import Ubuntu.Components.ListItems 0.1 as ListItem
24import Ubuntu.Components.Popups 0.1
25
26MainView {
27 id: root
28 applicationName: "com.ubuntu.developer.foobar.movies"
29
30 width: units.gu(45)
31 height: units.gu(80)
32
33 /*
34 Movie database
35 */
36
37 U1db.Database {
38 id: db
39 // path: "movies.db"
40 }
41
42 // Defaults taken from http://archive.blender.org/features-gallery/movies/index.html
43
44 U1db.Document {
45 database: db
46 docId: 'yBigBuckBunny'
47 create: true
48 defaults: {
49 'title': 'Big Buck Bunny (Short film)',
50 producer: 'Blender Foundation',
51 year: 2008, duration: '10min', website: 'https://www.bigbugckbunny.org'
52 }
53 }
54
55 U1db.Document {
56 database: db
57 docId: 'zElephantsDream'
58 create: true
59 defaults: {
60 'title': 'Elephants Dream (Short film)',
61 producer: 'Blender Foundation',
62 year: 2006, duration: '10min', website: 'https://www.elephantsdream.org'
63 }
64 }
65
66 U1db.Document {
67 database: db
68 docId: 'cProjectLondon'
69 create: true
70 defaults: {
71 'title': 'Project London Trailer',
72 producer: 'Independent',
73 year: 2009, duration: '22sec', website: 'https://www.projectlondonmovie.com'
74 }
75 }
76
77 U1db.Document {
78 database: db
79 docId: 'aSoftBoy'
80 create: true
81 defaults: {
82 'title': 'Soft Boy (Animation)',
83 producer: 'Andy Goralczyk',
84 year: 2005, duration: '17sec'
85 }
86 }
87
88 U1db.Document {
89 database: db
90 docId: 'bEsign'
91 create: true
92 defaults: {
93 'title': 'Esign (Animation)',
94 producer: 'Chris Larkee',
95 year: 2005, duration: '4min'
96 }
97 }
98
99 U1db.Query {
100 id: allMovies
101 index: blacklist
102 query: [ { year: '*', producer: '*', duration: '*', title: '*' } ]
103 }
104
105 U1db.Index {
106 id: blacklist
107 database: db
108 expression: [ 'year', 'duration', 'title', 'producer' ]
109 }
110
111 SortFilterModel {
112 id: sortedMovies
113 model: allMovies
114 filter.pattern: RegExp(searchProducer.text)
115 filter.property: 'producer'
116 sort.property: sortBy.role
117 sort.order: Qt.DescendingOrder
118 }
119
120 /*
121 UI: list view, filters
122 */
123
124 Page {
125 id: page
126 title: i18n.tr('Movies')
127
128 Column {
129 id: container
130 anchors.margins: units.gu(1)
131 anchors.fill: parent
132
133 ListView {
134 id: movieList
135 width: parent.width
136 height: parent.height - pillar.height
137 model: sortedMovies
138 delegate: ListItem.Subtitled {
139 text: '<b>%1</b> %2'.arg(title).arg(year)
140 subText: '%1 <b>%2</b>'.arg(duration).arg(producer)
141 fallbackIconName: "favorite-unselected,text-html"
142 iconFrame: false
143 }
144 }
145
146 Column {
147 id: pillar
148 spacing: units.gu(1)
149 width: parent.width
150
151 Label {
152 text: sortBy.role
153 }
154
155 OptionSelector {
156 id: sortBy
157 StateSaver.properties: 'selectedIndex'
158 model: ListModel {
159 ListElement { label: 'Title'; role: 'title' }
160 ListElement { label: 'Year'; role: 'year' }
161 ListElement { label: 'Length'; role: 'duration' }
162 }
163 delegate: OptionSelectorDelegate {
164 text: i18n.tr(label)
165 }
166 property string role: 'title'
167 onDelegateClicked: {
168 var selectedIndex = index
169 role = model.get(selectedIndex).role
170 // Work-around for sort.property not correctly re-sorting
171 var m = movieList.model
172 movieList.model = null
173 movieList.model = m
174 }
175 }
176
177 TextField {
178 id: searchProducer
179 StateSaver.properties: 'text'
180 placeholderText: i18n.tr('Search Producer…')
181 }
182
183 OptionSelector {
184 id: selectYear
185 StateSaver.properties: 'selectedIndex'
186 model: [ '*', 2005, 2006, 2007, 2008, 2009 ]
187 delegate: OptionSelectorDelegate {
188 text: modelData == '*' ? 'All Years' : modelData
189 }
190 property var year: model[selectedIndex]
191 }
192 }
193 }
194 }
195}
196
0197
=== modified file 'src/query.cpp'
--- src/query.cpp 2014-03-13 19:31:58 +0000
+++ src/query.cpp 2014-11-12 17:08:18 +0000
@@ -17,7 +17,6 @@
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */18 */
1919
20#include <QDebug>
21#include <QSqlQuery>20#include <QSqlQuery>
22#include <QFile>21#include <QFile>
23#include <QSqlError>22#include <QSqlError>
@@ -64,7 +63,11 @@
64 return m_results.at(index.row());63 return m_results.at(index.row());
65 if (role == 1) // docId64 if (role == 1) // docId
66 return m_documents.at(index.row());65 return m_documents.at(index.row());
67 return QVariant();66
67 int indexForRole = role - 2;
68 QVariantMap result(m_results.at(index.row()).toMap());
69 QString field(m_index->getExpression().at(indexForRole).split(".").last());
70 return result.value(field);
68}71}
6972
70/*!73/*!
@@ -79,6 +82,13 @@
79 QHash<int, QByteArray> roles;82 QHash<int, QByteArray> roles;
80 roles.insert(0, "contents");83 roles.insert(0, "contents");
81 roles.insert(1, "docId");84 roles.insert(1, "docId");
85 if (!m_index)
86 return roles;
87
88 // A role name for each field in the index
89 uint fieldRole = 2;
90 Q_FOREACH(QString field, m_index->getExpression())
91 roles.insert(fieldRole++, field.split(".").last().toUtf8());
82 return roles;92 return roles;
83}93}
8494
8595
=== modified file 'tests/test-database.cpp'
--- tests/test-database.cpp 2014-11-07 14:30:31 +0000
+++ tests/test-database.cpp 2014-11-12 17:08:18 +0000
@@ -82,6 +82,21 @@
82 query.setQuery(QStringList() << "2014*" << "basketball" << "linux");82 query.setQuery(QStringList() << "2014*" << "basketball" << "linux");
83 }83 }
8484
85 void testRoleNames()
86 {
87 Database db;
88 Index index;
89 index.setDatabase(&db);
90 index.setExpression(QStringList() << "species" << "traits.spots");
91 Query query;
92 query.setIndex(&index);
93 QStringList expected(QStringList() << "docId" << "contents" << "species" << "spots");
94 Q_FOREACH(QString roleName, expected)
95 QVERIFY2(query.roleNames().values().contains(roleName.toUtf8()),
96 qPrintable(QString("Expected role name \"%1\" not in Query").arg(roleName)));
97 QVERIFY(db.lastError().isEmpty());
98 }
99
85 void cleanupTestCase()100 void cleanupTestCase()
86 {101 {
87 }102 }
88103
=== modified file 'tests/tst_query.qml'
--- tests/tst_query.qml 2014-03-13 19:31:58 +0000
+++ tests/tst_query.qml 2014-11-12 17:08:18 +0000
@@ -20,6 +20,8 @@
20import QtQuick 2.020import QtQuick 2.0
21import QtTest 1.021import QtTest 1.0
22import U1db 1.0 as U1db22import U1db 1.0 as U1db
23import Ubuntu.Components 1.1
24import Ubuntu.Test 0.1
2325
24Item {26Item {
25 width: 200; height: 20027 width: 200; height: 200
@@ -241,13 +243,79 @@
241 signalName: "documentsChanged"243 signalName: "documentsChanged"
242 }244 }
243245
244TestCase {246 U1db.Database {
247 id: animals
248 }
249
250 // Note: docId's intentionally chosen for wrong alphabetic order
251 U1db.Document {
252 database: animals
253 docId: 'k_cow'
254 contents: { 'species': 'cow', 'traits': [ { 'spots': true } ] }
255 }
256 U1db.Document {
257 database: animals
258 docId: 'z_ant'
259 contents: { 'species': 'ant' }
260 }
261
262 U1db.Document {
263 database: animals
264 docId: 'a_bee'
265 contents: { 'species': 'bee' }
266 }
267
268 U1db.Document {
269 database: animals
270 docId: 'n_cat'
271 contents: { 'species': 'cat' }
272 }
273 U1db.Index {
274 id: bySpecies
275 database: animals
276 name: 'by-species'
277 expression: [ 'species' ]
278 }
279
280 U1db.Query {
281 id: allAnimals
282 index: bySpecies
283 query: [{ 'species': '*' }]
284 }
285
286 // To double-check failures aren't due to SortFilterModel itself
287 ListModel {
288 id: fakeAnimals
289 ListElement { species: 'cow'; docId: 'k_cow' }
290 ListElement { species: 'ant'; docId: 'z_ant' }
291 ListElement { species: 'bee'; docId: 'a_bee' }
292 ListElement { species: 'cat'; docId: 'n_cat' }
293 }
294
295 SortFilterModel {
296 id: mixedAnimals
297 model: allAnimals
298 }
299
300 SortFilterModel {
301 id: sortedAnimals
302 sort.property: 'species'
303 sort.order: Qt.AscendingOrder
304 }
305
306 SortFilterModel {
307 id: filteredAnimals
308 filter.property: 'species'
309 filter.pattern: /ant/
310 }
311
312UbuntuTestCase {
245 name: "U1dbDatabase"313 name: "U1dbDatabase"
246 when: windowShown314 when: windowShown
247315
248 function prettyJson(j) {316 function prettyJson(j) {
249 var A = JSON.stringify(j)317 var A = JSON.stringify(j)
250 if (A['0'] && A != '{}') {318 if (A != undefined && A['0'] && A != '{}') {
251 var A = '['319 var A = '['
252 for(var i in j)320 for(var i in j)
253 A += JSON.stringify(j[i]) + ','321 A += JSON.stringify(j[i]) + ','
@@ -260,6 +328,8 @@
260 compare(a, b, msg, true)328 compare(a, b, msg, true)
261 }329 }
262330
331 TestUtil { id: util }
332
263 function compare(a, b, msg, willFail) {333 function compare(a, b, msg, willFail) {
264 /* Override built-in compare to:334 /* Override built-in compare to:
265 Match different JSON for identical values (number hash versus list)335 Match different JSON for identical values (number hash versus list)
@@ -273,7 +343,12 @@
273 console.log('Expected failure: %1%2 != %3'.arg(msg ? msg + ': ' : '').arg(A).arg(B))343 console.log('Expected failure: %1%2 != %3'.arg(msg ? msg + ': ' : '').arg(A).arg(B))
274 return344 return
275 }345 }
276 fail('%5%1 != %2 (%3 != %4)'.arg(A).arg(B).arg(JSON.stringify(a)).arg(JSON.stringify(b)).arg(msg ? msg + ': ' : ''))346 if (!qtest_results.compare (false,
347 msg ? msg : "Comparison failed",
348 A + " ~ " + JSON.stringify(a),
349 B + " ~ " + JSON.stringify(b),
350 util.callerFile(), util.callerLine()))
351 throw new Error("QtQuickTest::fail")
277 }352 }
278 if (willFail)353 if (willFail)
279 fail('Expected to fail, but passed: %5%1 != %2 (%3 != %4)'.arg(A).arg(B).arg(JSON.stringify(a)).arg(JSON.stringify(b)).arg(msg ? msg + ': ' : ''))354 fail('Expected to fail, but passed: %5%1 != %2 (%3 != %4)'.arg(A).arg(B).arg(JSON.stringify(a)).arg(JSON.stringify(b)).arg(msg ? msg + ': ' : ''))
@@ -359,5 +434,45 @@
359 compare(allHeroesWithType.documents, ['dino', 'gokaiger', 'ooo', 'wizard'], 'go')434 compare(allHeroesWithType.documents, ['dino', 'gokaiger', 'ooo', 'wizard'], 'go')
360 compare(allHeroesWithType.documents, allHeroesSeriesOnly.documents, 'roku')435 compare(allHeroesWithType.documents, allHeroesSeriesOnly.documents, 'roku')
361 }436 }
437
438 function test_7_sort_data () {
439 return [ { tag: 'Reference ListModel', model: fakeAnimals },
440 { tag: 'U1db.Query', model: allAnimals } ]
441 }
442
443 function test_7_sort (data) {
444 // Sanity checks
445 compare(allAnimals.documents, ["a_bee", "k_cow", "n_cat", "z_ant"])
446 tryCompareFunction(function(){return mixedAnimals.get(0).docId}, "a_bee")
447
448 sortedAnimals.model = data.model
449 compare(sortedAnimals.count, 4, "number of animals")
450 sortedAnimals.sort.property = 'species'
451 compare(sortedAnimals.get(0).docId, "z_ant", "ants document sorted first")
452 compare(sortedAnimals.get(0).species, "ant", "ants species sorted first")
453
454 sortedAnimals.sort.order = Qt.DescendingOrder
455 compare(sortedAnimals.get(0).species, "cow", "cow sorted first descending")
456
457 sortedAnimals.sort.property = 'docId'
458 sortedAnimals.sort.order = Qt.AscendingOrder
459 compare(sortedAnimals.get(0).docId, "a_bee", "bee sorted first by docId")
460 }
461
462 function test_8_filter_data () {
463 return [ { tag: 'Reference ListModel', model: fakeAnimals },
464 { tag: 'U1db.Query', model: allAnimals } ]
465 }
466
467 function test_8_filter (data) {
468 // Sanity checks
469 compare(allAnimals.documents, ["a_bee", "k_cow", "n_cat", "z_ant"])
470 tryCompareFunction(function(){return mixedAnimals.get(0).docId}, "a_bee")
471
472 filteredAnimals.model = data.model
473 compare(filteredAnimals.count, 1, "number of animals")
474 compare(filteredAnimals.get(0).species, "ant", "ants species role available")
475 compare(filteredAnimals.get(0).docId, "z_ant", "ants included in filter")
476 }
362} }477} }
363478

Subscribers

People subscribed via source and target branches

to all changes: