Merge lp:~kalikiana/u1db-qt/wonderiousFields into lp:u1db-qt
- wonderiousFields
- Merge into trunk
Status: | Merged | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Approved by: | Cris Dywan | ||||||||||||
Approved revision: | 119 | ||||||||||||
Merged at revision: | 114 | ||||||||||||
Proposed branch: | lp:~kalikiana/u1db-qt/wonderiousFields | ||||||||||||
Merge into: | lp:u1db-qt | ||||||||||||
Diff against target: |
525 lines (+219/-135) 3 files modified
src/query.cpp (+66/-114) src/query.h (+3/-1) tests/tst_query.qml (+150/-20) |
||||||||||||
To merge this branch: | bzr merge lp:~kalikiana/u1db-qt/wonderiousFields | ||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Benjamin Zeller | Approve | ||
PS Jenkins bot | continuous-integration | Approve | |
Review via email:
|
Commit message
Reverse query logic to check non-matching and internally convert between query syntaxes
Description of the change
- bug 1215898 example works
- bug 1214538 was already fixed before it seems
- bug 1284194 works
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Nekhelesh Ramananthan (nik90) wrote : | # |
On testing, I found the following results,
1. bug #1214538 is fixed
2. bug #1284194 doesn't work with 2 Queries. With 1 Query, the filtering of elements with "show" works as expected.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:119
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Benjamin Zeller (zeller-benjamin) wrote : | # |
3 Mentioned examples work, ready to merge
Preview Diff
1 | === modified file 'src/query.cpp' | |||
2 | --- src/query.cpp 2014-02-19 09:39:07 +0000 | |||
3 | +++ src/query.cpp 2014-03-07 17:54:50 +0000 | |||
4 | @@ -122,6 +122,34 @@ | |||
5 | 122 | void Query::generateQueryResults() | 122 | void Query::generateQueryResults() |
6 | 123 | { | 123 | { |
7 | 124 | QList<QVariantMap> results(m_index->getAllResults()); | 124 | QList<QVariantMap> results(m_index->getAllResults()); |
8 | 125 | |||
9 | 126 | /* Convert "*" or 123 or "aa" into a list */ | ||
10 | 127 | /* Also convert ["aa", 123] into [{foo:"aa", bar:123}] */ | ||
11 | 128 | QVariantList queryList(m_query.toList()); | ||
12 | 129 | if (queryList.empty()) { | ||
13 | 130 | // * is the default if query is empty | ||
14 | 131 | if (!m_query.isValid()) | ||
15 | 132 | queryList.append(QVariant(QString("*"))); | ||
16 | 133 | else | ||
17 | 134 | queryList.append(m_query); | ||
18 | 135 | } | ||
19 | 136 | if (queryList.at(0).type() != QVariant::Map) { | ||
20 | 137 | QVariantList oldQueryList(queryList); | ||
21 | 138 | QListIterator<QVariant> j(oldQueryList); | ||
22 | 139 | QListIterator<QString> k(m_index->getExpression()); | ||
23 | 140 | while(j.hasNext() && k.hasNext()) { | ||
24 | 141 | QVariant j_value = j.next(); | ||
25 | 142 | QString k_value = k.next(); | ||
26 | 143 | QVariantMap valueMap; | ||
27 | 144 | // Strip hierarchical components | ||
28 | 145 | if (k_value.contains(".")) | ||
29 | 146 | valueMap.insert(k_value.split(".").last(), j_value); | ||
30 | 147 | else | ||
31 | 148 | valueMap.insert(k_value, j_value); | ||
32 | 149 | queryList.append(QVariant(valueMap)); | ||
33 | 150 | } | ||
34 | 151 | } | ||
35 | 152 | |||
36 | 125 | Q_FOREACH (QVariantMap mapIdResult, results) { | 153 | Q_FOREACH (QVariantMap mapIdResult, results) { |
37 | 126 | QString docId((mapIdResult["docId"]).toString()); | 154 | QString docId((mapIdResult["docId"]).toString()); |
38 | 127 | QVariant result_variant(mapIdResult["result"]); | 155 | QVariant result_variant(mapIdResult["result"]); |
39 | @@ -135,10 +163,9 @@ | |||
40 | 135 | 163 | ||
41 | 136 | j.next(); | 164 | j.next(); |
42 | 137 | 165 | ||
46 | 138 | bool tmp_match = queryField(j.key(), j.value()); | 166 | if (!iterateQueryList(queryList, j.key(), j.value())) { |
44 | 139 | |||
45 | 140 | if(tmp_match == false){ | ||
47 | 141 | match = false; | 167 | match = false; |
48 | 168 | break; | ||
49 | 142 | } | 169 | } |
50 | 143 | 170 | ||
51 | 144 | } | 171 | } |
52 | @@ -158,7 +185,6 @@ | |||
53 | 158 | 185 | ||
54 | 159 | Q_EMIT documentsChanged(m_documents); | 186 | Q_EMIT documentsChanged(m_documents); |
55 | 160 | Q_EMIT resultsChanged(m_results); | 187 | Q_EMIT resultsChanged(m_results); |
56 | 161 | |||
57 | 162 | } | 188 | } |
58 | 163 | 189 | ||
59 | 164 | /*! | 190 | /*! |
60 | @@ -175,87 +201,41 @@ | |||
61 | 175 | 201 | ||
62 | 176 | /*! | 202 | /*! |
63 | 177 | \internal | 203 | \internal |
64 | 178 | Query a single field. | ||
65 | 179 | */ | ||
66 | 180 | bool Query::queryField(QString field, QVariant value){ | ||
67 | 181 | |||
68 | 182 | bool match = false; | ||
69 | 183 | |||
70 | 184 | QVariant query = getQuery(); | ||
71 | 185 | // * is the default if query is empty | ||
72 | 186 | if (!query.isValid()) | ||
73 | 187 | query = QVariant(QString("*")); | ||
74 | 188 | QString typeName = query.typeName(); | ||
75 | 189 | |||
76 | 190 | if(typeName == "QString") | ||
77 | 191 | { | ||
78 | 192 | QString query_string = query.toString(); | ||
79 | 193 | match = queryString(query_string, value); | ||
80 | 194 | } | ||
81 | 195 | else if(typeName == "int") | ||
82 | 196 | { | ||
83 | 197 | QString query_string = query.toString(); | ||
84 | 198 | match = queryString(query_string, value); | ||
85 | 199 | } | ||
86 | 200 | else if(typeName == "QVariantList") | ||
87 | 201 | { | ||
88 | 202 | match = iterateQueryList(query, field, value); | ||
89 | 203 | } | ||
90 | 204 | else | ||
91 | 205 | { | ||
92 | 206 | m_query = ""; | ||
93 | 207 | qWarning("u1db: Unexpected type %s for query", qPrintable(typeName)); | ||
94 | 208 | } | ||
95 | 209 | |||
96 | 210 | return match; | ||
97 | 211 | |||
98 | 212 | } | ||
99 | 213 | |||
100 | 214 | /*! | ||
101 | 215 | \internal | ||
102 | 216 | Loop through the query assuming it's a list. | 204 | Loop through the query assuming it's a list. |
103 | 205 | |||
104 | 206 | For example: | ||
105 | 207 | queryList: { type: 'show' } | ||
106 | 208 | field: 'type' | ||
107 | 209 | value: 'show' | ||
108 | 217 | */ | 210 | */ |
110 | 218 | bool Query::iterateQueryList(QVariant query, QString field, QVariant value) | 211 | bool Query::iterateQueryList(QVariantList queryList, QString field, QVariant value) |
111 | 219 | { | 212 | { |
117 | 220 | 213 | QListIterator<QVariant> j(queryList); | |
113 | 221 | bool match = false; | ||
114 | 222 | |||
115 | 223 | QList<QVariant> query_list = query.toList(); | ||
116 | 224 | QListIterator<QVariant> j(query_list); | ||
118 | 225 | 214 | ||
119 | 226 | while (j.hasNext()) { | 215 | while (j.hasNext()) { |
120 | 227 | |||
121 | 228 | QVariant j_value = j.next(); | 216 | QVariant j_value = j.next(); |
149 | 229 | 217 | QVariantMap valueMap(j_value.toMap()); | |
150 | 230 | QString typeName = j_value.typeName(); | 218 | if (!queryMap(valueMap, value.toString(), field)) |
151 | 231 | 219 | return false; | |
125 | 232 | if(typeName == "QVariantMap") | ||
126 | 233 | { | ||
127 | 234 | match = queryMap(j_value.toMap(), value.toString(), field); | ||
128 | 235 | |||
129 | 236 | if(match == true){ | ||
130 | 237 | break; | ||
131 | 238 | } | ||
132 | 239 | |||
133 | 240 | } | ||
134 | 241 | else if(typeName == "QString"){ | ||
135 | 242 | |||
136 | 243 | match = queryString(j_value.toString(), value); | ||
137 | 244 | |||
138 | 245 | if(match == true){ | ||
139 | 246 | break; | ||
140 | 247 | } | ||
141 | 248 | |||
142 | 249 | } | ||
143 | 250 | else | ||
144 | 251 | { | ||
145 | 252 | m_query = ""; | ||
146 | 253 | qWarning("u1db: Unexpected type %s for query", qPrintable(typeName)); | ||
147 | 254 | } | ||
148 | 255 | |||
152 | 256 | } | 220 | } |
153 | 257 | 221 | ||
155 | 258 | return match; | 222 | return true; |
156 | 223 | } | ||
157 | 224 | |||
158 | 225 | /*! | ||
159 | 226 | \internal | ||
160 | 227 | Verify that query is an identical or wild card match. | ||
161 | 228 | */ | ||
162 | 229 | bool Query::queryMatchesValue(QString query, QString value) | ||
163 | 230 | { | ||
164 | 231 | if (query == "*") | ||
165 | 232 | return true; | ||
166 | 233 | if (query == value) | ||
167 | 234 | return true; | ||
168 | 235 | if (!query.contains ("*")) | ||
169 | 236 | return false; | ||
170 | 237 | QString prefix(query.split("*")[0]); | ||
171 | 238 | return value.startsWith(prefix, Qt::CaseSensitive); | ||
172 | 259 | } | 239 | } |
173 | 260 | 240 | ||
174 | 261 | /*! | 241 | /*! |
175 | @@ -274,36 +254,20 @@ | |||
176 | 274 | return false; | 254 | return false; |
177 | 275 | } | 255 | } |
178 | 276 | 256 | ||
198 | 277 | bool match = false; | 257 | return queryMatchesValue(query, value.toString()); |
180 | 278 | |||
181 | 279 | if(query == "*"){ | ||
182 | 280 | return true; | ||
183 | 281 | } | ||
184 | 282 | else if(query == value){ | ||
185 | 283 | return true; | ||
186 | 284 | } | ||
187 | 285 | else if(query.contains("*")){ | ||
188 | 286 | QStringList k_string_list = query.split("*"); | ||
189 | 287 | QString k_string = k_string_list[0]; | ||
190 | 288 | match = value.toString().startsWith(k_string,Qt::CaseSensitive); | ||
191 | 289 | |||
192 | 290 | return match; | ||
193 | 291 | |||
194 | 292 | } | ||
195 | 293 | |||
196 | 294 | |||
197 | 295 | return match; | ||
199 | 296 | } | 258 | } |
200 | 297 | 259 | ||
201 | 298 | /*! | 260 | /*! |
202 | 299 | \internal | 261 | \internal |
203 | 300 | Loop through the given map of keys and queries. | 262 | Loop through the given map of keys and queries. |
204 | 263 | |||
205 | 264 | For example: | ||
206 | 265 | map: { type: 'show' } | ||
207 | 266 | value: { 'show' } | ||
208 | 267 | field: 'type' | ||
209 | 301 | */ | 268 | */ |
210 | 302 | bool Query::queryMap(QVariantMap map, QString value, QString field) | 269 | bool Query::queryMap(QVariantMap map, QString value, QString field) |
211 | 303 | { | 270 | { |
212 | 304 | |||
213 | 305 | bool match = false; | ||
214 | 306 | |||
215 | 307 | QMapIterator<QString,QVariant> k(map); | 271 | QMapIterator<QString,QVariant> k(map); |
216 | 308 | 272 | ||
217 | 309 | while(k.hasNext()){ | 273 | while(k.hasNext()){ |
218 | @@ -314,24 +278,12 @@ | |||
219 | 314 | QString query = k_variant.toString(); | 278 | QString query = k_variant.toString(); |
220 | 315 | 279 | ||
221 | 316 | if(field == k_key){ | 280 | if(field == k_key){ |
236 | 317 | 281 | if (!queryMatchesValue(query, value)) | |
237 | 318 | if(query == "*"){ | 282 | return false; |
224 | 319 | return true; | ||
225 | 320 | } | ||
226 | 321 | else if(query == value){ | ||
227 | 322 | return true; | ||
228 | 323 | } | ||
229 | 324 | else if(query.contains("*")){ | ||
230 | 325 | QStringList k_string_list = query.split("*"); | ||
231 | 326 | QString k_string = k_string_list[0]; | ||
232 | 327 | match = value.startsWith(k_string,Qt::CaseSensitive); | ||
233 | 328 | return match; | ||
234 | 329 | } | ||
235 | 330 | |||
238 | 331 | } | 283 | } |
239 | 332 | } | 284 | } |
240 | 333 | 285 | ||
242 | 334 | return match; | 286 | return true; |
243 | 335 | } | 287 | } |
244 | 336 | 288 | ||
245 | 337 | /*! | 289 | /*! |
246 | 338 | 290 | ||
247 | === modified file 'src/query.h' | |||
248 | --- src/query.h 2014-01-31 19:20:07 +0000 | |||
249 | +++ src/query.h 2014-03-07 17:54:50 +0000 | |||
250 | @@ -68,8 +68,10 @@ | |||
251 | 68 | 68 | ||
252 | 69 | void onDataInvalidated(); | 69 | void onDataInvalidated(); |
253 | 70 | 70 | ||
254 | 71 | bool debug(); | ||
255 | 71 | void generateQueryResults(); | 72 | void generateQueryResults(); |
257 | 72 | bool iterateQueryList(QVariant query, QString field, QVariant value); | 73 | bool iterateQueryList(QVariantList list, QString field, QVariant value); |
258 | 74 | bool queryMatchesValue(QString query, QString value); | ||
259 | 73 | bool queryString(QString query, QVariant value); | 75 | bool queryString(QString query, QVariant value); |
260 | 74 | bool queryMap(QVariantMap map, QString value, QString field); | 76 | bool queryMap(QVariantMap map, QString value, QString field); |
261 | 75 | bool queryField(QString field, QVariant value); | 77 | bool queryField(QString field, QVariant value); |
262 | 76 | 78 | ||
263 | === modified file 'tests/tst_query.qml' | |||
264 | --- tests/tst_query.qml 2014-02-19 09:39:07 +0000 | |||
265 | +++ tests/tst_query.qml 2014-03-07 17:54:50 +0000 | |||
266 | @@ -26,7 +26,6 @@ | |||
267 | 26 | 26 | ||
268 | 27 | U1db.Database { | 27 | U1db.Database { |
269 | 28 | id: gents | 28 | id: gents |
270 | 29 | path: 'aDatabaseU' | ||
271 | 30 | } | 29 | } |
272 | 31 | 30 | ||
273 | 32 | U1db.Document { | 31 | U1db.Document { |
274 | @@ -47,6 +46,18 @@ | |||
275 | 47 | contents: { 'misc': { 'software': 'linux', 'sports': [ 'basketball', 'hockey' ] }, 'date': '2014-01-01' , 'gents': [ { 'name': 'Ivanka', 'phone': 00321 }, ] } | 46 | contents: { 'misc': { 'software': 'linux', 'sports': [ 'basketball', 'hockey' ] }, 'date': '2014-01-01' , 'gents': [ { 'name': 'Ivanka', 'phone': 00321 }, ] } |
276 | 48 | } | 47 | } |
277 | 49 | 48 | ||
278 | 49 | U1db.Document { | ||
279 | 50 | database: gents | ||
280 | 51 | docId: 'F' | ||
281 | 52 | contents: { 'details': { 'name': 'spy', 'type': 'hide', 'colour': 'blue' } } | ||
282 | 53 | } | ||
283 | 54 | |||
284 | 55 | U1db.Document { | ||
285 | 56 | database: gents | ||
286 | 57 | docId: 'G' | ||
287 | 58 | contents: { 'details': { 'name': 'kid', 'type': 'show', 'colour': 'green' } } | ||
288 | 59 | } | ||
289 | 60 | |||
290 | 50 | U1db.Index { | 61 | U1db.Index { |
291 | 51 | id: byPhone | 62 | id: byPhone |
292 | 52 | database: gents | 63 | database: gents |
293 | @@ -100,6 +111,12 @@ | |||
294 | 100 | U1db.Query { | 111 | U1db.Query { |
295 | 101 | id: i12345Phone | 112 | id: i12345Phone |
296 | 102 | index: byPhone | 113 | index: byPhone |
297 | 114 | query: [ { 'phone': 12345 } ] | ||
298 | 115 | } | ||
299 | 116 | |||
300 | 117 | U1db.Query { | ||
301 | 118 | id: i12345PhoneSimple | ||
302 | 119 | index: byPhone | ||
303 | 103 | query: 12345 | 120 | query: 12345 |
304 | 104 | } | 121 | } |
305 | 105 | 122 | ||
306 | @@ -112,6 +129,12 @@ | |||
307 | 112 | U1db.Query { | 129 | U1db.Query { |
308 | 113 | id: ivankaAllNamePhone | 130 | id: ivankaAllNamePhone |
309 | 114 | index: byNamePhone | 131 | index: byNamePhone |
310 | 132 | query: [ { name: 'Ivanka', phone: '*' } ] | ||
311 | 133 | } | ||
312 | 134 | |||
313 | 135 | U1db.Query { | ||
314 | 136 | id: ivankaAllNamePhoneSimple | ||
315 | 137 | index: byNamePhone | ||
316 | 115 | query: ['Ivanka', '*'] | 138 | query: ['Ivanka', '*'] |
317 | 116 | } | 139 | } |
318 | 117 | 140 | ||
319 | @@ -122,17 +145,96 @@ | |||
320 | 122 | } | 145 | } |
321 | 123 | 146 | ||
322 | 124 | U1db.Query { | 147 | U1db.Query { |
323 | 125 | id: wrongQuery | ||
324 | 126 | index: byNamePhone | ||
325 | 127 | query: [{ 'name': 'Ivanka', 'phone': '*' }] | ||
326 | 128 | } | ||
327 | 129 | |||
328 | 130 | U1db.Query { | ||
329 | 131 | id: toplevelQuery | 148 | id: toplevelQuery |
330 | 132 | index: byDate | 149 | index: byDate |
331 | 133 | query: [{ 'date': '2014*', 'sports': 'basketball', 'software': 'linux' }] | 150 | query: [{ 'date': '2014*', 'sports': 'basketball', 'software': 'linux' }] |
332 | 134 | } | 151 | } |
333 | 135 | 152 | ||
334 | 153 | U1db.Query { | ||
335 | 154 | id: toplevelQuerySimple | ||
336 | 155 | index: byDate | ||
337 | 156 | query: [ '2014*', 'basketball', 'linux' ] | ||
338 | 157 | } | ||
339 | 158 | |||
340 | 159 | U1db.Query { | ||
341 | 160 | id: queryOne | ||
342 | 161 | index: U1db.Index { | ||
343 | 162 | database: gents | ||
344 | 163 | name: 'one' | ||
345 | 164 | expression: [ 'details.type' ] | ||
346 | 165 | } | ||
347 | 166 | query: [ 'show' ] | ||
348 | 167 | } | ||
349 | 168 | |||
350 | 169 | U1db.Query { | ||
351 | 170 | id: queryBothSimple | ||
352 | 171 | index: U1db.Index { | ||
353 | 172 | database: gents | ||
354 | 173 | name: 'bothSimple' | ||
355 | 174 | expression: [ 'details.type', 'details.colour' ] | ||
356 | 175 | } | ||
357 | 176 | query: [ 'show', '*' ] | ||
358 | 177 | } | ||
359 | 178 | |||
360 | 179 | U1db.Query { | ||
361 | 180 | id: queryBoth | ||
362 | 181 | index: U1db.Index { | ||
363 | 182 | database: gents | ||
364 | 183 | name: 'both' | ||
365 | 184 | expression: [ 'details.type', 'details.colour' ] | ||
366 | 185 | } | ||
367 | 186 | query: [ { type: 'show', colour: '*' } ] | ||
368 | 187 | } | ||
369 | 188 | |||
370 | 189 | U1db.Database { | ||
371 | 190 | id: tokusatsu | ||
372 | 191 | } | ||
373 | 192 | |||
374 | 193 | U1db.Document { | ||
375 | 194 | database: tokusatsu | ||
376 | 195 | docId: 'ooo' | ||
377 | 196 | contents: { 'series': 'ooo', 'type': 'rider' } | ||
378 | 197 | } | ||
379 | 198 | |||
380 | 199 | U1db.Document { | ||
381 | 200 | database: tokusatsu | ||
382 | 201 | docId: 'gokaiger' | ||
383 | 202 | contents: { 'series': 'gokaiger', 'type': 'sentai' } | ||
384 | 203 | } | ||
385 | 204 | |||
386 | 205 | U1db.Document { | ||
387 | 206 | id: tokusatsuDocumentWizard | ||
388 | 207 | docId: 'wizard' | ||
389 | 208 | contents: { 'series': 'wizard', 'type': 'rider', | ||
390 | 209 | 'transformations': ['Flame Style','Water Style'] } | ||
391 | 210 | } | ||
392 | 211 | |||
393 | 212 | U1db.Document { | ||
394 | 213 | id: tokusatsuDocumentDino | ||
395 | 214 | docId: 'dino' | ||
396 | 215 | contents: { 'series': 'zyuranger', 'scarf': false, 'type': 'sentai', | ||
397 | 216 | 'beasts': ['T-Rex', 'Mastodon'] } | ||
398 | 217 | } | ||
399 | 218 | |||
400 | 219 | U1db.Index { | ||
401 | 220 | id: bySeries | ||
402 | 221 | database: tokusatsu | ||
403 | 222 | name: 'by-series' | ||
404 | 223 | expression: ['series', 'type'] | ||
405 | 224 | } | ||
406 | 225 | |||
407 | 226 | U1db.Query { | ||
408 | 227 | id: allHeroesWithType | ||
409 | 228 | index: bySeries | ||
410 | 229 | query: [{ 'series': '*' }, { 'type': '*' }] | ||
411 | 230 | } | ||
412 | 231 | |||
413 | 232 | U1db.Query { | ||
414 | 233 | id: allHeroesSeriesOnly | ||
415 | 234 | index: bySeries | ||
416 | 235 | query: [{ 'series': '*' }] | ||
417 | 236 | } | ||
418 | 237 | |||
419 | 136 | SignalSpy { | 238 | SignalSpy { |
420 | 137 | id: spyDocumentsChanged | 239 | id: spyDocumentsChanged |
421 | 138 | target: defaultPhone | 240 | target: defaultPhone |
422 | @@ -154,7 +256,11 @@ | |||
423 | 154 | return A | 256 | return A |
424 | 155 | } | 257 | } |
425 | 156 | 258 | ||
427 | 157 | function compare (a, b) { | 259 | function compareFail(a, b, msg) { |
428 | 260 | compare(a, b, msg, true) | ||
429 | 261 | } | ||
430 | 262 | |||
431 | 263 | function compare(a, b, msg, willFail) { | ||
432 | 158 | /* Override built-in compare to: | 264 | /* Override built-in compare to: |
433 | 159 | Match different JSON for identical values (number hash versus list) | 265 | Match different JSON for identical values (number hash versus list) |
434 | 160 | Produce readable output for all JSON values | 266 | Produce readable output for all JSON values |
435 | @@ -163,8 +269,14 @@ | |||
436 | 163 | return | 269 | return |
437 | 164 | var A = prettyJson(a), B = prettyJson(b) | 270 | var A = prettyJson(a), B = prettyJson(b) |
438 | 165 | if (A != B) { | 271 | if (A != B) { |
440 | 166 | fail('%1 != %2 (%3 != %4)'.arg(A).arg(B).arg(JSON.stringify(a)).arg(JSON.stringify(b))) | 272 | if (willFail) { |
441 | 273 | console.log('Expected failure: %1%2 != %3'.arg(msg ? msg + ': ' : '').arg(A).arg(B)) | ||
442 | 274 | return | ||
443 | 275 | } | ||
444 | 276 | fail('%5%1 != %2 (%3 != %4)'.arg(A).arg(B).arg(JSON.stringify(a)).arg(JSON.stringify(b)).arg(msg ? msg + ': ' : '')) | ||
445 | 167 | } | 277 | } |
446 | 278 | if (willFail) | ||
447 | 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 + ': ' : '')) | ||
448 | 168 | } | 280 | } |
449 | 169 | 281 | ||
450 | 170 | function workaroundQueryAndWait (buggyQuery) { | 282 | function workaroundQueryAndWait (buggyQuery) { |
451 | @@ -173,21 +285,12 @@ | |||
452 | 173 | spyDocumentsChanged.wait(); | 285 | spyDocumentsChanged.wait(); |
453 | 174 | } | 286 | } |
454 | 175 | 287 | ||
455 | 176 | function test_0_wrongUse () { | ||
456 | 177 | workaroundQueryAndWait(wrongQuery) | ||
457 | 178 | ignoreWarning('u1db: Unexpected type QVariantMap for query') | ||
458 | 179 | wrongQuery.query = { 'name': 'Ivanka' } | ||
459 | 180 | ignoreWarning('u1db: Unexpected type QObject* for query') | ||
460 | 181 | wrongQuery.query = defaultPhone | ||
461 | 182 | } | ||
462 | 183 | |||
463 | 184 | function test_1_defaults () { | 288 | function test_1_defaults () { |
464 | 185 | // We should get all documents | 289 | // We should get all documents |
465 | 186 | workaroundQueryAndWait(defaultPhone) | 290 | workaroundQueryAndWait(defaultPhone) |
466 | 187 | compare(defaultPhone.documents, ['1', '_', 'a'], 'uno') | 291 | compare(defaultPhone.documents, ['1', '_', 'a'], 'uno') |
467 | 188 | compare(defaultPhone.results.length, 3, 'dos') | 292 | compare(defaultPhone.results.length, 3, 'dos') |
468 | 189 | compare(defaultPhone.results.length, defaultPhone.documents.length, 'puntos') | 293 | compare(defaultPhone.results.length, defaultPhone.documents.length, 'puntos') |
469 | 190 | // FIXME: compare(defaultPhone.results, [], 'dos') | ||
470 | 191 | // These queries are functionally equivalent | 294 | // These queries are functionally equivalent |
471 | 192 | compare(defaultPhone.documents, allPhone.documents, 'tres') | 295 | compare(defaultPhone.documents, allPhone.documents, 'tres') |
472 | 193 | compare(defaultPhone.documents, allPhoneList.documents, 'quatro') | 296 | compare(defaultPhone.documents, allPhoneList.documents, 'quatro') |
473 | @@ -205,18 +308,21 @@ | |||
474 | 205 | compare(s12345Phone.documents, ['1'], 'uno') | 308 | compare(s12345Phone.documents, ['1'], 'uno') |
475 | 206 | // It's okay to mix strings and numerical values | 309 | // It's okay to mix strings and numerical values |
476 | 207 | compare(s12345Phone.documents, i12345Phone.documents, 'dos') | 310 | compare(s12345Phone.documents, i12345Phone.documents, 'dos') |
477 | 311 | compare(i12345PhoneSimple.documents, i12345Phone.documents, 'tres') | ||
478 | 208 | } | 312 | } |
479 | 209 | 313 | ||
480 | 210 | function test_3_wildcards () { | 314 | function test_3_wildcards () { |
481 | 211 | // Trailing string wildcard | 315 | // Trailing string wildcard |
482 | 212 | compare(s1wildcardPhone.documents, ['1'], 'uno') | 316 | compare(s1wildcardPhone.documents, ['1'], 'uno') |
483 | 213 | // Last given field can use wildcards | 317 | // Last given field can use wildcards |
485 | 214 | // FIXME: compare(ivankaAllNamePhone.documents, ['_', 'a'], 'dos') | 318 | compare(ivankaAllNamePhoneSimple.documents, ['_', 'a'], 'dos') |
486 | 319 | compare(ivankaAllNamePhone.documents, ['_', 'a'], 'tres') | ||
487 | 215 | // These queries are functionally equivalent | 320 | // These queries are functionally equivalent |
488 | 216 | workaroundQueryAndWait(ivankaAllNamePhoneKeywords) | 321 | workaroundQueryAndWait(ivankaAllNamePhoneKeywords) |
489 | 217 | workaroundQueryAndWait(ivankaAllNamePhone) | 322 | workaroundQueryAndWait(ivankaAllNamePhone) |
491 | 218 | // FIXME: compare(ivankaAllNamePhone.documents, ivankaAllNamePhoneKeywords.documents, 'tres') | 323 | compare(ivankaAllNamePhone.documents, ivankaAllNamePhoneKeywords.documents, 'tres') |
492 | 219 | compare(toplevelQuery.documents, ['_']) | 324 | compare(toplevelQuery.documents, ['_']) |
493 | 325 | compare(toplevelQuerySimple.documents, ['_'], 'cinco') | ||
494 | 220 | } | 326 | } |
495 | 221 | 327 | ||
496 | 222 | function test_4_delete () { | 328 | function test_4_delete () { |
497 | @@ -226,5 +332,29 @@ | |||
498 | 226 | compare(defaultPhone.documents, ['1', 'a'], 'dos') | 332 | compare(defaultPhone.documents, ['1', 'a'], 'dos') |
499 | 227 | } | 333 | } |
500 | 228 | 334 | ||
501 | 335 | function test_5_fields () { | ||
502 | 336 | compare(queryOne.documents, ['G'], 'one field') | ||
503 | 337 | compare(queryBoth.documents, ['G'], 'two fields') | ||
504 | 338 | compare(queryBothSimple.documents, ['G'], 'two fields simple') | ||
505 | 339 | } | ||
506 | 340 | |||
507 | 341 | function test_6_definition () { | ||
508 | 342 | workaroundQueryAndWait(allHeroesWithType) | ||
509 | 343 | compare(allHeroesWithType.documents, ['gokaiger', 'ooo'], 'ichi') | ||
510 | 344 | workaroundQueryAndWait(allHeroesSeriesOnly) | ||
511 | 345 | compare(allHeroesSeriesOnly.documents, ['gokaiger', 'ooo'], 'ni') | ||
512 | 346 | compare(allHeroesWithType.documents, allHeroesSeriesOnly.documents, 'doube-check') | ||
513 | 347 | // Add a document with extra fields | ||
514 | 348 | tokusatsu.putDoc(tokusatsuDocumentWizard.contents, tokusatsuDocumentWizard.docId) | ||
515 | 349 | workaroundQueryAndWait(allHeroesWithType) | ||
516 | 350 | compare(allHeroesWithType.documents, ['gokaiger', 'ooo', 'wizard'], 'san') | ||
517 | 351 | workaroundQueryAndWait(allHeroesSeriesOnly) | ||
518 | 352 | compare(allHeroesWithType.documents, allHeroesSeriesOnly.documents, 'chi') | ||
519 | 353 | // Add a document with mixed custom fields | ||
520 | 354 | tokusatsu.putDoc(tokusatsuDocumentDino.contents, tokusatsuDocumentDino.docId) | ||
521 | 355 | workaroundQueryAndWait(allHeroesWithType) | ||
522 | 356 | compare(allHeroesWithType.documents, ['dino', 'gokaiger', 'ooo', 'wizard'], 'go') | ||
523 | 357 | compare(allHeroesWithType.documents, allHeroesSeriesOnly.documents, 'roku') | ||
524 | 358 | } | ||
525 | 229 | } } | 359 | } } |
526 | 230 | 360 |
PASSED: Continuous integration, rev:116 jenkins. qa.ubuntu. com/job/ u1db-qt- ci/41/ jenkins. qa.ubuntu. com/job/ u1db-qt- precise- amd64-ci/ 41 jenkins. qa.ubuntu. com/job/ u1db-qt- saucy-amd64- ci/43 jenkins. qa.ubuntu. com/job/ u1db-qt- trusty- amd64-ci/ 21 jenkins. qa.ubuntu. com/job/ u1db-qt- trusty- armhf-ci/ 21
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/u1db- qt-ci/41/ rebuild
http://