Merge lp:~thisfred/u1db/fix-get_keys_from_index into lp:u1db
- fix-get_keys_from_index
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Eric Casteleijn |
Approved revision: | 333 |
Merged at revision: | 327 |
Proposed branch: | lp:~thisfred/u1db/fix-get_keys_from_index |
Merge into: | lp:u1db |
Diff against target: |
441 lines (+186/-56) 11 files modified
include/u1db/u1db.h (+4/-2) include/u1db/u1db_internal.h (+10/-0) src/u1db_query.c (+115/-25) u1db/__init__.py (+1/-2) u1db/backends/inmemory.py (+3/-1) u1db/backends/sqlite_backend.py (+18/-14) u1db/commandline/client.py (+3/-2) u1db/tests/c_backend_wrapper.pyx (+13/-7) u1db/tests/test_backends.py (+17/-1) u1db/tests/test_c_backend.py (+1/-1) u1todo/u1todo.py (+1/-1) |
To merge this branch: | bzr merge lp:~thisfred/u1db/fix-get_keys_from_index |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
John A Meinel (community) | Approve | ||
Review via email:
|
Commit message
get_keys_from_index now returns simple values for single column indexes, and tuples for multicolumn ones
Description of the change
get_keys_from_index now returns simple values for single column indexes, and tuples for multicolumn ones
Not ecstatic about the C implementation, so suggestions for improvement welcome.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
John A Meinel (jameinel) wrote : | # |
- 328. By Eric Casteleijn
-
do not unpack single tuples, no matter how tempting
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Eric Casteleijn (thisfred) wrote : | # |
thanks, jam. fixed.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
John A Meinel (jameinel) wrote : | # |
So if I understand the C code correctly, you do a callback for each bit of the key, and then follow it up with a NULL for each run. So if you had a 3 column index (firstname, lastname, irc_nick), then the callback would give you:
Eric
Castelijn
thisfred
NULL
John
Meinel
jam
NULL
...
While this is functional, I really think the users would be better served getting:
Eric, Castelijn, thisfred
John, Meinel, jam
...
Since the C code is now doing the query that way anyway (it is doing the join of document_fields onto itself), I think we should probably just allocate an array to pass the data into the callback.
I would probably do it with const char * stuff. So that we share pointers with the sqlite code, and the callback needs to allocate memory if it wants to hold on to anything (vs allocating the memory, and the callback must free everything/save it into a buffer for later.)
So something like:
typedef int(*u1db_
and then in the function
int
u1db_get_
{
...
char **key = NULL;
...
key = (char**
...
finally:
if (key != NULL) {
free(key)
}
And then the inner loop becomes:
while (status == SQLITE_ROW) {
for (i = 0; i < num_fields; ++i) {
field = (char*)
key[i] = field;
}
if ((status = cb(context, num_fields, key)) != U1DB_OK) {
goto finish;
}
status = sqlite3_
}
Note that I'm intentionally calling the whole tuple a singular 'key' made up of 'fields'.
- 329. By Eric Casteleijn
-
changed callback signature
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Eric Casteleijn (thisfred) wrote : | # |
Fixed, thanks!
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Eric Casteleijn (thisfred) wrote : | # |
now to fix the conflicts :)
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Eric Casteleijn (thisfred) wrote : | # |
resolved
- 330. By Eric Casteleijn
-
merged trunk, resolved conflicts, removed unnecessary intermediate variable
- 331. By Eric Casteleijn
-
rereresolved conflicts
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
John A Meinel (jameinel) wrote : | # |
+ key[i] = (char*)
I think this line we probably want
key[i] = (const char*)...
are you getting a warning about const changing? (I know we need the cast at all because sqlite3 returns an unsigned char*).
You are mixing styles here:
167 + if (key != NULL)
168 + free(key);
169 + if (query_str != NULL) {
170 + free(query_str);
171 + }
Personally, I'm a fan of always using {} and putting it at the end of line like you did for query_str.
366 + a_list.
^ I think you want a tuple(field_list) here.
You are using "GROUP BY" in the query, which was useful when you were counting. I wonder if we would rather use "SELECT DISTINCT" rather than "SELECT ... GROUP BY". Probably best would be to try both and see if one is significantly faster. (SQL means that they could be identical internally).
Overall, I think it looks good, though.
- 332. By Eric Casteleijn
-
added missing const, cosmetic fix
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Eric Casteleijn (thisfred) wrote : | # |
Thanks!
> + key[i] = (char*)
>
> I think this line we probably want
> key[i] = (const char*)...
fixed
> are you getting a warning about const changing? (I know we need the cast at
> all because sqlite3 returns an unsigned char*).
There was no warning.
> You are mixing styles here:
>
> 167 + if (key != NULL)
> 168 + free(key);
> 169 + if (query_str != NULL) {
> 170 + free(query_str);
> 171 + }
Fixed.
> 366 + a_list.
>
> ^ I think you want a tuple(field_list) here.
The tuple cast was done later, but you're right, it's better to do it here and not iterate over the list later. Fixed.
> You are using "GROUP BY" in the query, which was useful when you were
> counting. I wonder if we would rather use "SELECT DISTINCT" rather than
> "SELECT ... GROUP BY". Probably best would be to try both and see if one is
> significantly faster. (SQL means that they could be identical internally).
I will test this, and fix it on a separate branch if necessary.
- 333. By Eric Casteleijn
-
various small fixes
Preview Diff
1 | === modified file 'include/u1db/u1db.h' |
2 | --- include/u1db/u1db.h 2012-06-12 15:17:40 +0000 |
3 | +++ include/u1db/u1db.h 2012-06-13 11:19:23 +0000 |
4 | @@ -40,7 +40,8 @@ |
5 | |
6 | typedef struct _u1query u1query; |
7 | typedef int (*u1db_doc_callback)(void *context, u1db_document *doc); |
8 | -typedef int (*u1db_key_callback)(void *context, const char *key); |
9 | +typedef int (*u1db_key_callback)(void *context, int num_fields, |
10 | + const char **key); |
11 | typedef int (*u1db_doc_gen_callback)(void *context, u1db_document *doc, int gen); |
12 | typedef int (*u1db_doc_id_gen_callback)(void *context, const char *doc_id, int gen); |
13 | typedef int (*u1db_trans_info_callback)(void *context, const char *doc_id, |
14 | @@ -352,7 +353,8 @@ |
15 | * Get keys under which documents are indexed. |
16 | * |
17 | * @param index_name Name of the index for which to get keys. |
18 | - * @param context Will be returned via the document callback |
19 | + * @param context Will be returned via the document callback. cb will be called |
20 | + * once for each column, with a NULL value to separate rows. |
21 | */ |
22 | int u1db_get_index_keys(u1database *db, char *index_name, void *context, |
23 | u1db_key_callback cb); |
24 | |
25 | === modified file 'include/u1db/u1db_internal.h' |
26 | --- include/u1db/u1db_internal.h 2012-06-12 15:17:40 +0000 |
27 | +++ include/u1db/u1db_internal.h 2012-06-13 11:19:23 +0000 |
28 | @@ -368,6 +368,16 @@ |
29 | int *start_wildcard, int *end_wildcard); |
30 | |
31 | /** |
32 | + * Format an index keys query |
33 | + * |
34 | + * @param n_fields The number of fields being passed in, (the number of args |
35 | + * in argp) |
36 | + * @param buf (OUT) The character array. This will be dynamically allocated, |
37 | + * and callers must free() it. |
38 | + */ |
39 | +int u1db__format_index_keys_query(int n_fields, char **buf); |
40 | + |
41 | +/** |
42 | * Given this document content, update the indexed fields in the db. |
43 | */ |
44 | int u1db__update_indexes(u1database *db, const char *doc_id, |
45 | |
46 | === modified file 'src/u1db_query.c' |
47 | --- src/u1db_query.c 2012-06-12 15:17:40 +0000 |
48 | +++ src/u1db_query.c 2012-06-13 11:19:23 +0000 |
49 | @@ -40,7 +40,6 @@ |
50 | int value_type; |
51 | } operation; |
52 | |
53 | - |
54 | typedef struct string_list_item_ |
55 | { |
56 | char *data; |
57 | @@ -78,7 +77,8 @@ |
58 | } transformation; |
59 | |
60 | typedef int(*op_function)(string_list *, const string_list *, |
61 | - const string_list *); |
62 | + const string_list *); |
63 | + |
64 | |
65 | static int |
66 | init_list(string_list **list) |
67 | @@ -749,14 +749,21 @@ |
68 | void *context, u1db_key_callback cb) |
69 | { |
70 | int status = U1DB_OK; |
71 | - char *key = NULL; |
72 | + int num_fields = 0; |
73 | + int bind_arg, i; |
74 | + const char **key = NULL; |
75 | + string_list *field_names = NULL; |
76 | + string_list_item *field_name = NULL; |
77 | + char *query_str = NULL; |
78 | sqlite3_stmt *statement; |
79 | + |
80 | + status = init_list(&field_names); |
81 | + if (status != U1DB_OK) |
82 | + goto finish; |
83 | status = sqlite3_prepare_v2( |
84 | db->sql_handle, |
85 | - "SELECT document_fields.value FROM " |
86 | - "index_definitions INNER JOIN document_fields ON " |
87 | - "index_definitions.field = document_fields.field_name WHERE " |
88 | - "index_definitions.name = ? GROUP BY document_fields.value;", |
89 | + "SELECT field FROM index_definitions WHERE name = ? ORDER BY " |
90 | + "offset;", |
91 | -1, &statement, NULL); |
92 | if (status != SQLITE_OK) { |
93 | goto finish; |
94 | @@ -768,37 +775,64 @@ |
95 | } |
96 | status = sqlite3_step(statement); |
97 | if (status == SQLITE_DONE) { |
98 | - sqlite3_finalize(statement); |
99 | - status = sqlite3_prepare_v2( |
100 | - db->sql_handle, |
101 | - "SELECT field FROM index_definitions WHERE name = ?;", |
102 | - -1, &statement, NULL); |
103 | - if (status != SQLITE_OK) { |
104 | + status = U1DB_INDEX_DOES_NOT_EXIST; |
105 | + goto finish; |
106 | + } |
107 | + while (status == SQLITE_ROW) { |
108 | + num_fields++; |
109 | + status = append(field_names, (char*)sqlite3_column_text(statement, 0)); |
110 | + if (status != U1DB_OK) |
111 | goto finish; |
112 | - } |
113 | + status = sqlite3_step(statement); |
114 | + } |
115 | + if (status != SQLITE_DONE) { |
116 | + goto finish; |
117 | + } |
118 | + sqlite3_finalize(statement); |
119 | + status = u1db__format_index_keys_query(num_fields, &query_str); |
120 | + |
121 | + if (status != U1DB_OK) { |
122 | + goto finish; |
123 | + } |
124 | + status = sqlite3_prepare_v2( |
125 | + db->sql_handle, query_str, -1, &statement, NULL); |
126 | + if (status != SQLITE_OK) { |
127 | + goto finish; |
128 | + } |
129 | + bind_arg = 1; |
130 | + for (field_name = field_names->head; field_name != NULL; field_name = |
131 | + field_name->next) { |
132 | status = sqlite3_bind_text( |
133 | - statement, 1, index_name, -1, SQLITE_TRANSIENT); |
134 | - if (status != SQLITE_OK) { |
135 | + statement, bind_arg++, field_name->data, -1, SQLITE_TRANSIENT); |
136 | + if (status != SQLITE_OK) |
137 | goto finish; |
138 | - } |
139 | - status = sqlite3_step(statement); |
140 | - if (status == SQLITE_DONE) { |
141 | - status = U1DB_INDEX_DOES_NOT_EXIST; |
142 | - } else { |
143 | - status = U1DB_OK; |
144 | - } |
145 | + } |
146 | + status = sqlite3_step(statement); |
147 | + key = (const char**)calloc(num_fields, sizeof(char*)); |
148 | + if (key == NULL) { |
149 | + status = U1DB_NOMEM; |
150 | goto finish; |
151 | } |
152 | while (status == SQLITE_ROW) { |
153 | - key = (char*)sqlite3_column_text(statement, 0); |
154 | - if ((status = cb(context, key)) != U1DB_OK) |
155 | + for (i = 0; i < num_fields; ++i) { |
156 | + key[i] = (const char*)sqlite3_column_text(statement, i); |
157 | + } |
158 | + if ((status = cb(context, num_fields, key)) != U1DB_OK) { |
159 | goto finish; |
160 | + } |
161 | status = sqlite3_step(statement); |
162 | } |
163 | if (status == SQLITE_DONE) { |
164 | status = U1DB_OK; |
165 | } |
166 | finish: |
167 | + if (key != NULL) { |
168 | + free(key); |
169 | + } |
170 | + if (query_str != NULL) { |
171 | + free(query_str); |
172 | + } |
173 | + destroy_list(field_names); |
174 | sqlite3_finalize(statement); |
175 | return status; |
176 | } |
177 | @@ -1007,6 +1041,62 @@ |
178 | return status; |
179 | } |
180 | |
181 | +int |
182 | +u1db__format_index_keys_query(int n_fields, char **buf) |
183 | +{ |
184 | + int status = U1DB_OK; |
185 | + int buf_size, i; |
186 | + char *cur = NULL; |
187 | + |
188 | + if (n_fields < 1) { |
189 | + return U1DB_INVALID_PARAMETER; |
190 | + } |
191 | + // 81 for 1 doc, 166 for 2, 251 for 3 |
192 | + buf_size = (1 + n_fields) * 100; |
193 | + // The first field is treated specially |
194 | + cur = (char*)calloc(buf_size, 1); |
195 | + if (cur == NULL) { |
196 | + return U1DB_NOMEM; |
197 | + } |
198 | + *buf = cur; |
199 | + add_to_buf(&cur, &buf_size, "SELECT "); |
200 | + for (i = 0; i < n_fields; ++i) { |
201 | + if (i != 0) { |
202 | + add_to_buf(&cur, &buf_size, ", "); |
203 | + } |
204 | + add_to_buf(&cur, &buf_size, " d%d.value", i); |
205 | + } |
206 | + add_to_buf(&cur, &buf_size, " FROM "); |
207 | + for (i = 0; i < n_fields; ++i) { |
208 | + if (i != 0) { |
209 | + add_to_buf(&cur, &buf_size, ", "); |
210 | + } |
211 | + add_to_buf(&cur, &buf_size, "document_fields d%d", i); |
212 | + } |
213 | + add_to_buf(&cur, &buf_size, " WHERE d0.field_name = ?"); |
214 | + for (i = 0; i < n_fields; ++i) { |
215 | + if (i != 0) { |
216 | + add_to_buf(&cur, &buf_size, |
217 | + " AND d0.doc_id = d%d.doc_id" |
218 | + " AND d%d.field_name = ?", |
219 | + i, i); |
220 | + } |
221 | + add_to_buf(&cur, &buf_size, " AND d%d.value NOT NULL", i); |
222 | + } |
223 | + add_to_buf(&cur, &buf_size, " GROUP BY "); |
224 | + for (i = 0; i < n_fields; ++i) { |
225 | + if (i != 0) { |
226 | + add_to_buf(&cur, &buf_size, ", "); |
227 | + } |
228 | + add_to_buf(&cur, &buf_size, "d%d.value", i); |
229 | + } |
230 | + if (status != U1DB_OK && *buf != NULL) { |
231 | + free(*buf); |
232 | + *buf = NULL; |
233 | + } |
234 | + return status; |
235 | +} |
236 | + |
237 | struct sqlcb_to_field_cb { |
238 | void *user_context; |
239 | int (*user_cb)(void *, const char*, transformation *tr); |
240 | |
241 | === modified file 'u1db/__init__.py' |
242 | --- u1db/__init__.py 2012-06-12 15:17:40 +0000 |
243 | +++ u1db/__init__.py 2012-06-13 11:19:23 +0000 |
244 | @@ -222,8 +222,7 @@ |
245 | def get_index_keys(self, index_name): |
246 | """Return all keys under which documents are indexed in this index. |
247 | |
248 | - :return: [(key, frequency)] A list of indexed keys and the frequency |
249 | - they occur. |
250 | + :return: [] A list of tuples of indexed keys. |
251 | :param index_name: The index to query |
252 | """ |
253 | raise NotImplementedError(self.get_index_keys) |
254 | |
255 | === modified file 'u1db/backends/inmemory.py' |
256 | --- u1db/backends/inmemory.py 2012-06-05 21:17:09 +0000 |
257 | +++ u1db/backends/inmemory.py 2012-06-13 11:19:23 +0000 |
258 | @@ -250,7 +250,9 @@ |
259 | index = self._indexes[index_name] |
260 | except KeyError: |
261 | raise errors.IndexDoesNotExist |
262 | - return list(set(index.keys())) |
263 | + keys = index.keys() |
264 | + # XXX inefficiency warning |
265 | + return list(set([tuple(key.split('\x01')) for key in keys])) |
266 | |
267 | def whats_changed(self, old_generation=0): |
268 | changes = [] |
269 | |
270 | === modified file 'u1db/backends/sqlite_backend.py' |
271 | --- u1db/backends/sqlite_backend.py 2012-06-06 17:08:22 +0000 |
272 | +++ u1db/backends/sqlite_backend.py 2012-06-13 11:19:23 +0000 |
273 | @@ -34,12 +34,6 @@ |
274 | vectorclock, |
275 | ) |
276 | |
277 | -SQL_INDEX_KEYS = """ |
278 | - SELECT document_fields.value FROM index_definitions INNER JOIN |
279 | - document_fields ON field = field_name WHERE index_definitions.name = ? |
280 | - GROUP BY document_fields.value; |
281 | - """ |
282 | - |
283 | |
284 | class SQLiteDatabase(CommonBackend): |
285 | """A U1DB implementation that uses SQLite as its persistence layer.""" |
286 | @@ -734,18 +728,28 @@ |
287 | res = c.fetchall() |
288 | return [self._factory(r[0], r[1], r[2]) for r in res] |
289 | |
290 | - def get_index_keys(self, index): |
291 | + def get_index_keys(self, index_name): |
292 | c = self._db_handle.cursor() |
293 | + definition = self._get_index_definition(index_name) |
294 | + value_fields = ', '.join([ |
295 | + 'd%d.value' % i for i in range(len(definition))]) |
296 | + tables = ["document_fields d%d" % i for i in range(len(definition))] |
297 | + novalue_where = [ |
298 | + "d.doc_id = d%d.doc_id AND d%d.field_name = ?" % (i, i) for i in |
299 | + range(len(definition))] |
300 | + where = [ |
301 | + novalue_where[i] + (" AND d%d.value NOT NULL" % (i,)) for i in |
302 | + range(len(definition))] |
303 | + statement = ( |
304 | + "SELECT %s FROM document d, %s WHERE %s GROUP BY %s;" % ( |
305 | + value_fields, ', '.join(tables), ' AND '.join(where), |
306 | + value_fields)) |
307 | try: |
308 | - c.execute(SQL_INDEX_KEYS, (index,)) |
309 | + c.execute(statement, tuple(definition)) |
310 | except dbapi2.OperationalError, e: |
311 | raise dbapi2.OperationalError(str(e) + |
312 | - '\nstatement: %s\nargs: %s\n' % (SQL_INDEX_KEYS, (index,))) |
313 | - res = c.fetchall() |
314 | - if not res: |
315 | - # raise IndexDoesNotExist if appropriate |
316 | - self._get_index_definition(index) |
317 | - return [r[0] for r in res] |
318 | + '\nstatement: %s\nargs: %s\n' % (statement, tuple(definition))) |
319 | + return c.fetchall() |
320 | |
321 | def delete_index(self, index_name): |
322 | with self._db_handle: |
323 | |
324 | === modified file 'u1db/commandline/client.py' |
325 | --- u1db/commandline/client.py 2012-06-06 13:28:10 +0000 |
326 | +++ u1db/commandline/client.py 2012-06-13 11:19:23 +0000 |
327 | @@ -401,8 +401,9 @@ |
328 | def run(self, database, index): |
329 | try: |
330 | db = self._open(database, create=False) |
331 | - for i in db.get_index_keys(index): |
332 | - self.stdout.write("%s\n" % (i.encode('utf-8'),)) |
333 | + for key in db.get_index_keys(index): |
334 | + self.stdout.write("%s\n" % (", ".join( |
335 | + [i.encode('utf-8') for i in key],))) |
336 | except errors.DatabaseDoesNotExist: |
337 | self.stderr.write("Database does not exist.\n") |
338 | except errors.IndexDoesNotExist: |
339 | |
340 | === modified file 'u1db/tests/c_backend_wrapper.pyx' |
341 | --- u1db/tests/c_backend_wrapper.pyx 2012-06-12 15:17:40 +0000 |
342 | +++ u1db/tests/c_backend_wrapper.pyx 2012-06-13 11:19:23 +0000 |
343 | @@ -58,7 +58,8 @@ |
344 | |
345 | ctypedef char* const_char_ptr "const char*" |
346 | ctypedef int (*u1db_doc_callback)(void *context, u1db_document *doc) |
347 | - ctypedef int (*u1db_key_callback)(void *context, char *key) |
348 | + ctypedef int (*u1db_key_callback)(void *context, int num_fields, |
349 | + const_char_ptr *key) |
350 | ctypedef int (*u1db_doc_gen_callback)(void *context, |
351 | u1db_document *doc, int gen) |
352 | ctypedef int (*u1db_trans_info_callback)(void *context, |
353 | @@ -283,9 +284,14 @@ |
354 | a_list.append(pydoc) |
355 | return 0 |
356 | |
357 | -cdef int _append_key_to_list(void *context, const_char_ptr key) with gil: |
358 | - a_list = <object>context |
359 | - a_list.append(key) |
360 | +cdef int _append_key_to_list(void *context, int num_fields, |
361 | + const_char_ptr *key) with gil: |
362 | + a_list = <object>(context) |
363 | + field_list = [] |
364 | + for i from 0 <= i < num_fields: |
365 | + field = key[i] |
366 | + field_list.append(field.decode('utf-8')) |
367 | + a_list.append(tuple(field_list)) |
368 | return 0 |
369 | |
370 | cdef _list_to_array(lst, const_char_ptr **res, int *count): |
371 | @@ -1190,12 +1196,12 @@ |
372 | |
373 | def get_index_keys(self, index_name): |
374 | cdef int status |
375 | - result = [] |
376 | + keys = [] |
377 | status = U1DB_OK |
378 | status = u1db_get_index_keys( |
379 | - self._db, index_name, <void*>result, _append_key_to_list) |
380 | + self._db, index_name, <void*>keys, _append_key_to_list) |
381 | handle_status("get_index_keys", status) |
382 | - return result |
383 | + return keys |
384 | |
385 | def _query_init(self, index_name): |
386 | cdef CQuery query |
387 | |
388 | === modified file 'u1db/tests/test_backends.py' |
389 | --- u1db/tests/test_backends.py 2012-06-06 16:59:22 +0000 |
390 | +++ u1db/tests/test_backends.py 2012-06-13 11:19:23 +0000 |
391 | @@ -1300,7 +1300,23 @@ |
392 | self.db.create_doc(content2) |
393 | self.db.create_doc(content3) |
394 | self.assertEqual( |
395 | - ['value1', 'value2'], |
396 | + [('value1',), ('value2',)], |
397 | + sorted(self.db.get_index_keys('test-idx'))) |
398 | + |
399 | + def test_get_index_keys_from_multicolumn_index(self): |
400 | + self.db.create_index('test-idx', 'key1', 'key2') |
401 | + content1 = '{"key1": "value1", "key2": "val2-1"}' |
402 | + content2 = '{"key1": "value2", "key2": "val2-2"}' |
403 | + content3 = '{"key1": "value2", "key2": "val2-2"}' |
404 | + content4 = '{"key1": "value2", "key2": "val3"}' |
405 | + self.db.create_doc(content1) |
406 | + self.db.create_doc(content2) |
407 | + self.db.create_doc(content3) |
408 | + self.db.create_doc(content4) |
409 | + self.assertEqual([ |
410 | + ('value1', 'val2-1'), |
411 | + ('value2', 'val2-2'), |
412 | + ('value2', 'val3')], |
413 | sorted(self.db.get_index_keys('test-idx'))) |
414 | |
415 | |
416 | |
417 | === modified file 'u1db/tests/test_c_backend.py' |
418 | --- u1db/tests/test_c_backend.py 2012-06-12 13:03:18 +0000 |
419 | +++ u1db/tests/test_c_backend.py 2012-06-13 11:19:23 +0000 |
420 | @@ -199,7 +199,7 @@ |
421 | self.db.create_doc(tests.simple_doc) |
422 | self.db.create_index("key-idx", "key") |
423 | keys = self.db.get_index_keys('key-idx') |
424 | - self.assertEqual(["value"], keys) |
425 | + self.assertEqual([("value",)], keys) |
426 | |
427 | def test__query_init_one_field(self): |
428 | self.db = c_backend_wrapper.CDatabase(':memory:') |
429 | |
430 | === modified file 'u1todo/u1todo.py' |
431 | --- u1todo/u1todo.py 2012-05-31 18:51:20 +0000 |
432 | +++ u1todo/u1todo.py 2012-06-13 11:19:23 +0000 |
433 | @@ -78,7 +78,7 @@ |
434 | |
435 | def get_all_tags(self): |
436 | """Get all tags in use in the entire database.""" |
437 | - return self.db.get_index_keys(TAGS_INDEX) |
438 | + return [key[0] for key in self.db.get_index_keys(TAGS_INDEX)] |
439 | |
440 | def get_tasks_by_tags(self, tags): |
441 | """Get all tasks that have every tag in tags.""" |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 6/9/2012 1:11 AM, Eric Casteleijn wrote: from_index is useless for /bugs.launchpad .net/u1db/ +bug/1009505 /code.launchpad .net/~thisfred/ u1db/fix- get_keys_ from_index/ +merge/ 109451
> Eric Casteleijn has proposed merging
> lp:~thisfred/u1db/fix-get_keys_from_index into lp:u1db.
>
> Requested reviews: Ubuntu One hackers (ubuntuone-hackers) Related
> bugs: Bug #1009505 in U1DB: "get_keys_
> multicolumn indexes" https:/
>
> For more details, see:
> https:/
>
> get_keys_from_index now returns simple values for single column
> indexes, and tuples for multicolumn ones
>
> Not ecstatic about the C implementation, so suggestions for
> improvement welcome.
I don't think we should change the type of the return based on the
index. If we need to return tuples than we should always do so. I'm
willing to be convinced otherwise, but this *strongly* feels like you
should have 2 apis if you want to have 2 different return signatures.
John
=:->
-----BEGIN PGP SIGNATURE----- enigmail. mozdev. org/
VnhoACgkQJdeBCY SNAAPT0ACgrYlYY /fokYHlASC27ecQ IXjD oq9nYPxnjvnlPxt A8
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://
iEYEARECAAYFAk/
ZqgAoLQ5dIy83PM
=i/Oc
-----END PGP SIGNATURE-----