Merge lp://qastaging/~rodrigo-moya/couchdb-glib/poll-changes into lp://qastaging/couchdb-glib
- poll-changes
- Merge into trunk
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Rodrigo Moya | ||||||||
Approved revision: | 88 | ||||||||
Merge reported by: | Rodrigo Moya | ||||||||
Merged at revision: | not available | ||||||||
Proposed branch: | lp://qastaging/~rodrigo-moya/couchdb-glib/poll-changes | ||||||||
Merge into: | lp://qastaging/couchdb-glib | ||||||||
Diff against target: | None lines | ||||||||
To merge this branch: | bzr merge lp://qastaging/~rodrigo-moya/couchdb-glib/poll-changes | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
dobey (community) | Approve | ||
Review via email:
|
Commit message
Description of the change

Rodrigo Moya (rodrigo-moya) wrote : | # |

dobey (dobey) wrote : | # |
What's the SONAME convention/policy for couchdb-glib? This changes the ABI I think, since the class structure is larger (added signals), and should probably get a SONAME version bump?

Rodrigo Moya (rodrigo-moya) wrote : | # |
> What's the SONAME convention/policy for couchdb-glib? This changes the ABI I
> think, since the class structure is larger (added signals), and should
> probably get a SONAME version bump?
there is no SONAME policy yet, since the ABI/API is still changing almost every week, and since evolution-couchdb is so far the only user of this library, I don't think we want right now to be bumping the soname for every single API/ABI change. I just make sure, when submitting evolution-couchdb packages for karmic, that it asks for the latest couchdb-glib as a build dependency.
Once we are done with this and (maybe) the oAuth stuff, I'll probably start doing the correct soname bumping, but I don't think it's needed right now

dobey (dobey) wrote : | # |
OK. The code looks generally OK to me. I just wasn't sure if we were bumping SONAME or not, but if not then I'll go ahead and approve.
Preview Diff
1 | === modified file 'configure.ac' |
2 | --- configure.ac 2009-08-26 10:47:15 +0000 |
3 | +++ configure.ac 2009-08-28 15:44:20 +0000 |
4 | @@ -15,6 +15,10 @@ |
5 | AC_PROG_CC |
6 | AC_PROG_LIBTOOL |
7 | |
8 | +dnl glib-genmarshal |
9 | +AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal) |
10 | + |
11 | +dnl Look for needed modules |
12 | PKG_CHECK_MODULES(COUCHDB_GLIB, glib-2.0 gobject-2.0 json-glib-1.0 >= 0.7.4 libsoup-2.4 libsoup-gnome-2.4 uuid) |
13 | AC_SUBST(COUCHDB_GLIB_CFLAGS) |
14 | AC_SUBST(COUCHDB_GLIB_LIBS) |
15 | |
16 | === modified file 'couchdb-glib/Makefile.am' |
17 | --- couchdb-glib/Makefile.am 2009-08-05 14:45:07 +0000 |
18 | +++ couchdb-glib/Makefile.am 2009-08-28 15:44:20 +0000 |
19 | @@ -3,11 +3,23 @@ |
20 | |
21 | lib_LTLIBRARIES = libcouchdb-glib-1.0.la |
22 | |
23 | +# Marshallers |
24 | +MARSHAL_GENERATED = couchdb-marshal.c couchdb-marshal.h |
25 | + |
26 | +couchdb-marshal.h: couchdb-marshal.list $(GLIB_GENMARSHAL) |
27 | + $(GLIB_GENMARSHAL) $< --header --prefix=_couchdb_marshal > $@ |
28 | + |
29 | +couchdb-marshal.c: couchdb-marshal.list $(GLIB_GENMARSHAL) |
30 | + $(GLIB_GENMARSHAL) $< --body --prefix=_couchdb_marshal > $@ |
31 | + |
32 | libcouchdb_glib_1_0_la_SOURCES = \ |
33 | + $(MARSHAL_GENERATED) \ |
34 | couchdb.c \ |
35 | couchdb-document.c \ |
36 | couchdb-document-contact.c \ |
37 | couchdb-types.c \ |
38 | + dbwatch.c \ |
39 | + dbwatch.h \ |
40 | utils.c \ |
41 | utils.h |
42 | libcouchdb_glib_1_0_la_LIBADD = \ |
43 | @@ -22,4 +34,6 @@ |
44 | couchdb-document-contact.h \ |
45 | couchdb-types.h |
46 | |
47 | -EXTRA_DIST = $(h_DATA) |
48 | +EXTRA_DIST = $(h_DATA) $(MARSHAL_GENERATED) |
49 | +BUILT_SOURCES = $(MARSHAL_GENERATED) |
50 | +CLEANFILES = $(BUILT_SOURCES) |
51 | |
52 | === modified file 'couchdb-glib/couchdb-document.c' |
53 | --- couchdb-glib/couchdb-document.c 2009-08-21 15:47:32 +0000 |
54 | +++ couchdb-glib/couchdb-document.c 2009-08-28 15:44:20 +0000 |
55 | @@ -137,6 +137,11 @@ |
56 | document->dbname = g_strdup (dbname); |
57 | } |
58 | |
59 | + if (id) |
60 | + g_signal_emit_by_name (document->couchdb, "document_updated", dbname, document); |
61 | + else |
62 | + g_signal_emit_by_name (document->couchdb, "document_created", dbname, document); |
63 | + |
64 | result = TRUE; |
65 | } |
66 | |
67 | @@ -167,7 +172,7 @@ |
68 | if (parser) { |
69 | g_object_unref (G_OBJECT (parser)); |
70 | |
71 | - result = TRUE; |
72 | + g_signal_emit_by_name (document->couchdb, "document_deleted", document->dbname, id); |
73 | } |
74 | |
75 | g_free (url); |
76 | @@ -182,9 +187,11 @@ |
77 | |
78 | if (document->root_node && |
79 | json_node_get_node_type (document->root_node) == JSON_NODE_OBJECT) { |
80 | - return json_object_get_string_member ( |
81 | - json_node_get_object (document->root_node), |
82 | - "_id"); |
83 | + if (json_object_has_member (json_node_get_object (document->root_node), |
84 | + "_id")) |
85 | + return json_object_get_string_member ( |
86 | + json_node_get_object (document->root_node), |
87 | + "_id"); |
88 | } |
89 | |
90 | return NULL; |
91 | |
92 | === modified file 'couchdb-glib/couchdb-glib.h' |
93 | --- couchdb-glib/couchdb-glib.h 2009-08-19 16:43:24 +0000 |
94 | +++ couchdb-glib/couchdb-glib.h 2009-08-28 15:44:20 +0000 |
95 | @@ -31,9 +31,18 @@ |
96 | #define COUCHDB_IS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), COUCHDB_TYPE)) |
97 | #define COUCHDB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), COUCHDB_TYPE, CouchDBClass)) |
98 | |
99 | +typedef struct _CouchDBDocument CouchDBDocument; |
100 | + |
101 | typedef struct _CouchDB CouchDB; |
102 | typedef struct { |
103 | GObjectClass parent_class; |
104 | + |
105 | + void (* database_created) (CouchDB *couchdb, const char *dbname); |
106 | + void (* database_deleted) (CouchDB *couchdb, const char *dbname); |
107 | + |
108 | + void (* document_created) (CouchDB *couchdb, const char *dbname, CouchDBDocument *document); |
109 | + void (* document_updated) (CouchDB *couchdb, const char *dbname, CouchDBDocument *document); |
110 | + void (* document_deleted) (CouchDB *couchdb, const char *dbname, const char *docid); |
111 | } CouchDBClass; |
112 | |
113 | GType couchdb_get_type (void); |
114 | @@ -53,6 +62,8 @@ |
115 | gboolean couchdb_create_database (CouchDB *couchdb, const char *dbname, GError **error); |
116 | gboolean couchdb_delete_database (CouchDB *couchdb, const char *dbname, GError **error); |
117 | |
118 | +void couchdb_listen_for_changes (CouchDB *couchdb, const char *dbname); |
119 | + |
120 | /* |
121 | * Documents API |
122 | */ |
123 | @@ -64,7 +75,6 @@ |
124 | #define COUCHDB_IS_DOCUMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), COUCHDB_TYPE_DOCUMENT)) |
125 | #define COUCHDB_DOCUMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), COUCHDB_TYPE_DOCUMENT, CouchDBDocumentClass)) |
126 | |
127 | -typedef struct _CouchDBDocument CouchDBDocument; |
128 | typedef struct { |
129 | GObjectClass parent_class; |
130 | } CouchDBDocumentClass; |
131 | |
132 | === added file 'couchdb-glib/couchdb-marshal.list' |
133 | --- couchdb-glib/couchdb-marshal.list 1970-01-01 00:00:00 +0000 |
134 | +++ couchdb-glib/couchdb-marshal.list 2009-08-28 15:44:20 +0000 |
135 | @@ -0,0 +1,2 @@ |
136 | +NONE:STRING,OBJECT |
137 | +NONE:STRING,STRING |
138 | |
139 | === modified file 'couchdb-glib/couchdb.c' |
140 | --- couchdb-glib/couchdb.c 2009-08-13 10:59:59 +0000 |
141 | +++ couchdb-glib/couchdb.c 2009-08-28 15:44:20 +0000 |
142 | @@ -23,15 +23,29 @@ |
143 | #include <libsoup/soup-gnome.h> |
144 | #include <json-glib/json-glib.h> |
145 | #include "couchdb-glib.h" |
146 | +#include "couchdb-marshal.h" |
147 | +#include "dbwatch.h" |
148 | #include "utils.h" |
149 | |
150 | G_DEFINE_TYPE(CouchDB, couchdb, G_TYPE_OBJECT) |
151 | |
152 | +enum { |
153 | + DATABASE_CREATED, |
154 | + DATABASE_DELETED, |
155 | + DOCUMENT_CREATED, |
156 | + DOCUMENT_UPDATED, |
157 | + DOCUMENT_DELETED, |
158 | + LAST_SIGNAL |
159 | +}; |
160 | +static guint couchdb_signals[LAST_SIGNAL]; |
161 | + |
162 | static void |
163 | couchdb_finalize (GObject *object) |
164 | { |
165 | CouchDB *couchdb = COUCHDB (object); |
166 | |
167 | + g_hash_table_destroy (couchdb->db_watchlist); |
168 | + |
169 | g_free (couchdb->hostname); |
170 | g_object_unref (couchdb->http_session); |
171 | |
172 | @@ -44,11 +58,64 @@ |
173 | GObjectClass *object_class = G_OBJECT_CLASS (klass); |
174 | |
175 | object_class->finalize = couchdb_finalize; |
176 | + |
177 | + /* Signals */ |
178 | + couchdb_signals[DATABASE_CREATED] = |
179 | + g_signal_new ("database_created", |
180 | + G_OBJECT_CLASS_TYPE (object_class), |
181 | + G_SIGNAL_RUN_LAST, |
182 | + G_STRUCT_OFFSET (CouchDBClass, database_created), |
183 | + NULL, NULL, |
184 | + g_cclosure_marshal_VOID__STRING, |
185 | + G_TYPE_NONE, 1, |
186 | + G_TYPE_STRING); |
187 | + couchdb_signals[DATABASE_DELETED] = |
188 | + g_signal_new ("database_deleted", |
189 | + G_OBJECT_CLASS_TYPE (object_class), |
190 | + G_SIGNAL_RUN_LAST, |
191 | + G_STRUCT_OFFSET (CouchDBClass, database_deleted), |
192 | + NULL, NULL, |
193 | + g_cclosure_marshal_VOID__STRING, |
194 | + G_TYPE_NONE, 1, |
195 | + G_TYPE_STRING); |
196 | + couchdb_signals[DOCUMENT_CREATED] = |
197 | + g_signal_new ("document_created", |
198 | + G_OBJECT_CLASS_TYPE (object_class), |
199 | + G_SIGNAL_RUN_LAST, |
200 | + G_STRUCT_OFFSET (CouchDBClass, document_created), |
201 | + NULL, NULL, |
202 | + _couchdb_marshal_VOID__STRING_OBJECT, |
203 | + G_TYPE_NONE, 2, |
204 | + G_TYPE_STRING, |
205 | + G_TYPE_OBJECT); |
206 | + couchdb_signals[DOCUMENT_UPDATED] = |
207 | + g_signal_new ("document_updated", |
208 | + G_OBJECT_CLASS_TYPE (object_class), |
209 | + G_SIGNAL_RUN_LAST, |
210 | + G_STRUCT_OFFSET (CouchDBClass, document_updated), |
211 | + NULL, NULL, |
212 | + _couchdb_marshal_VOID__STRING_OBJECT, |
213 | + G_TYPE_NONE, 2, |
214 | + G_TYPE_STRING, |
215 | + G_TYPE_OBJECT); |
216 | + couchdb_signals[DOCUMENT_DELETED] = |
217 | + g_signal_new ("document_deleted", |
218 | + G_OBJECT_CLASS_TYPE (object_class), |
219 | + G_SIGNAL_RUN_LAST, |
220 | + G_STRUCT_OFFSET (CouchDBClass, document_deleted), |
221 | + NULL, NULL, |
222 | + _couchdb_marshal_VOID__STRING_STRING, |
223 | + G_TYPE_NONE, 2, |
224 | + G_TYPE_STRING, |
225 | + G_TYPE_STRING); |
226 | } |
227 | |
228 | static void |
229 | couchdb_init (CouchDB *couchdb) |
230 | { |
231 | + couchdb->db_watchlist = g_hash_table_new_full (g_str_hash, g_str_equal, |
232 | + (GDestroyNotify) g_free, |
233 | + (GDestroyNotify) dbwatch_free); |
234 | } |
235 | |
236 | CouchDB * |
237 | @@ -168,6 +235,9 @@ |
238 | |
239 | g_free (url); |
240 | |
241 | + if (result) |
242 | + g_signal_emit_by_name (couchdb, "database_created", dbname); |
243 | + |
244 | return result; |
245 | } |
246 | |
247 | @@ -196,6 +266,14 @@ |
248 | |
249 | g_free (url); |
250 | |
251 | + if (result) { |
252 | + /* If we're listening for changes on this database, stop doing so */ |
253 | + if (g_hash_table_lookup (couchdb->db_watchlist, dbname)) |
254 | + g_hash_table_remove (couchdb->db_watchlist, dbname); |
255 | + |
256 | + g_signal_emit_by_name (couchdb, "database_deleted", dbname); |
257 | + } |
258 | + |
259 | return result; |
260 | } |
261 | |
262 | @@ -261,3 +339,39 @@ |
263 | g_slist_foreach (doclist, (GFunc) couchdb_document_info_unref, NULL); |
264 | g_slist_free (doclist); |
265 | } |
266 | + |
267 | +void |
268 | +couchdb_listen_for_changes (CouchDB *couchdb, const char *dbname) |
269 | +{ |
270 | + DBWatch *watch; |
271 | + CouchDBDatabaseInfo *db_info; |
272 | + GError *error = NULL; |
273 | + |
274 | + g_return_if_fail (COUCHDB_IS (couchdb)); |
275 | + g_return_if_fail (dbname != NULL); |
276 | + |
277 | + watch = g_hash_table_lookup (couchdb->db_watchlist, dbname); |
278 | + if (watch) { |
279 | + g_warning ("Already listening for changes in '%s' database", dbname); |
280 | + return; |
281 | + } |
282 | + |
283 | + /* Retrieve information for database, to know the last_update_sequence */ |
284 | + db_info = couchdb_get_database_info (couchdb, dbname, &error); |
285 | + if (!db_info) { |
286 | + g_warning ("Could not retrieve information for '%s' database: %s", |
287 | + dbname, error->message); |
288 | + g_error_free (error); |
289 | + |
290 | + return; |
291 | + } |
292 | + |
293 | + watch = dbwatch_new (couchdb, |
294 | + dbname, |
295 | + couchdb_database_info_get_update_sequence (db_info)); |
296 | + if (watch) |
297 | + g_hash_table_insert (couchdb->db_watchlist, g_strdup (dbname), watch); |
298 | + |
299 | + /* Free memory */ |
300 | + couchdb_database_info_unref (db_info); |
301 | +} |
302 | |
303 | === added file 'couchdb-glib/dbwatch.c' |
304 | --- couchdb-glib/dbwatch.c 1970-01-01 00:00:00 +0000 |
305 | +++ couchdb-glib/dbwatch.c 2009-08-28 15:44:20 +0000 |
306 | @@ -0,0 +1,137 @@ |
307 | +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ |
308 | +/* |
309 | + * Copyright (C) 2009 Canonical Services Ltd (www.canonical.com) |
310 | + * |
311 | + * Authors: Rodrigo Moya <rodrigo.moya@canonical.com> |
312 | + * |
313 | + * This library is free software; you can redistribute it and/or |
314 | + * modify it under the terms of version 2 of the GNU Lesser General Public |
315 | + * License as published by the Free Software Foundation. |
316 | + * |
317 | + * This program is distributed in the hope that it will be useful, |
318 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
319 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
320 | + * General Public License for more details. |
321 | + * |
322 | + * You should have received a copy of the GNU Lesser General Public |
323 | + * License along with this library; if not, write to the |
324 | + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
325 | + * Boston, MA 02110-1301, USA. |
326 | + */ |
327 | + |
328 | +#include "couchdb-glib.h" |
329 | +#include "dbwatch.h" |
330 | +#include "utils.h" |
331 | + |
332 | +#define TIMEOUT_SECONDS 300 |
333 | + |
334 | +static void |
335 | +process_change (DBWatch *watch, JsonNode *node) |
336 | +{ |
337 | + JsonObject *this_change; |
338 | + const gchar *id; |
339 | + CouchDBDocument *document; |
340 | + GError *error = NULL; |
341 | + |
342 | + if (json_node_get_node_type (node) != JSON_NODE_OBJECT) |
343 | + return; |
344 | + |
345 | + this_change = json_node_get_object (node); |
346 | + if (!json_object_has_member (this_change, "id")) |
347 | + return; |
348 | + |
349 | + id = json_object_get_string_member (this_change, "id"); |
350 | + |
351 | + /* We need to try retrieving the document, to check if it's removed or not */ |
352 | + document = couchdb_document_get (watch->couchdb, watch->dbname, id, &error); |
353 | + if (document) { |
354 | + const gchar *revision; |
355 | + |
356 | + revision = couchdb_document_get_revision (document); |
357 | + if (revision != NULL) { |
358 | + if (revision[0] == '1') |
359 | + g_signal_emit_by_name (watch->couchdb, "document_created", |
360 | + watch->dbname, document); |
361 | + else |
362 | + g_signal_emit_by_name (watch->couchdb, "document_updated", |
363 | + watch->dbname, document); |
364 | + } |
365 | + |
366 | + g_object_unref (G_OBJECT (document)); |
367 | + } else { |
368 | + if (error != NULL) { |
369 | + g_warning ("Error retrieving document '%s': %s", id, error->message); |
370 | + g_error_free (error); |
371 | + } else { |
372 | + /* The document is no longer in the DB, notify */ |
373 | + g_signal_emit_by_name (watch->couchdb, "document_deleted", watch->dbname, id); |
374 | + } |
375 | + } |
376 | +} |
377 | + |
378 | +static gboolean |
379 | +watch_timeout_cb (gpointer user_data) |
380 | +{ |
381 | + char *url; |
382 | + JsonParser *parser; |
383 | + GError *error = NULL; |
384 | + DBWatch *watch = (DBWatch *) user_data; |
385 | + |
386 | + url = g_strdup_printf ("%s/%s/_changes?since=%d", |
387 | + watch->couchdb->hostname, |
388 | + watch->dbname, |
389 | + watch->last_update_seq); |
390 | + parser = send_message_and_parse (watch->couchdb, SOUP_METHOD_GET, url, NULL, &error); |
391 | + if (parser != NULL) { |
392 | + JsonNode *root_node; |
393 | + |
394 | + root_node = json_parser_get_root (parser); |
395 | + if (json_node_get_node_type (root_node) == JSON_NODE_OBJECT) { |
396 | + JsonObject *root_object; |
397 | + JsonArray *results; |
398 | + |
399 | + root_object = json_node_get_object (root_node); |
400 | + results = json_object_get_array_member (root_object, "results"); |
401 | + if (results) { |
402 | + GList *json_elements, *sl; |
403 | + |
404 | + json_elements = json_array_get_elements (results); |
405 | + for (sl = json_elements; sl != NULL; sl = sl->next) |
406 | + process_change (watch, (JsonNode *) sl->data); |
407 | + } |
408 | + |
409 | + if (json_object_has_member (root_object, "last_seq")) |
410 | + watch->last_update_seq = json_object_get_int_member (root_object, "last_seq"); |
411 | + } |
412 | + |
413 | + g_object_unref (G_OBJECT (parser)); |
414 | + } |
415 | + |
416 | + /* Free memory */ |
417 | + g_free (url); |
418 | +} |
419 | + |
420 | +DBWatch * |
421 | +dbwatch_new (CouchDB *couchdb, const gchar *dbname, gint update_seq) |
422 | +{ |
423 | + DBWatch *watch; |
424 | + |
425 | + watch = g_new0 (DBWatch, 1); |
426 | + watch->couchdb = couchdb; |
427 | + watch->dbname = g_strdup (dbname); |
428 | + watch->last_update_seq = update_seq; |
429 | + |
430 | + /* Set timeout to check for changes every 5 minutes*/ |
431 | + watch->timeout_id = g_timeout_add (TIMEOUT_SECONDS * 1000, (GSourceFunc) watch_timeout_cb, watch); |
432 | + |
433 | + return watch; |
434 | +} |
435 | + |
436 | +void |
437 | +dbwatch_free (DBWatch *watch) |
438 | +{ |
439 | + g_free (watch->dbname); |
440 | + g_source_remove (watch->timeout_id); |
441 | + |
442 | + g_free (watch); |
443 | +} |
444 | |
445 | === added file 'couchdb-glib/dbwatch.h' |
446 | --- couchdb-glib/dbwatch.h 1970-01-01 00:00:00 +0000 |
447 | +++ couchdb-glib/dbwatch.h 2009-08-28 15:44:20 +0000 |
448 | @@ -0,0 +1,37 @@ |
449 | +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ |
450 | +/* |
451 | + * Copyright (C) 2009 Canonical Services Ltd (www.canonical.com) |
452 | + * |
453 | + * Authors: Rodrigo Moya <rodrigo.moya@canonical.com> |
454 | + * |
455 | + * This library is free software; you can redistribute it and/or |
456 | + * modify it under the terms of version 2 of the GNU Lesser General Public |
457 | + * License as published by the Free Software Foundation. |
458 | + * |
459 | + * This program is distributed in the hope that it will be useful, |
460 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
461 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
462 | + * General Public License for more details. |
463 | + * |
464 | + * You should have received a copy of the GNU Lesser General Public |
465 | + * License along with this library; if not, write to the |
466 | + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
467 | + * Boston, MA 02110-1301, USA. |
468 | + */ |
469 | + |
470 | +#ifndef __DBWATCH_H__ |
471 | +#define __DBWATCH_H__ |
472 | + |
473 | +#include "utils.h" |
474 | + |
475 | +typedef struct { |
476 | + CouchDB *couchdb; |
477 | + gchar *dbname; |
478 | + gint last_update_seq; |
479 | + guint timeout_id; |
480 | +} DBWatch; |
481 | + |
482 | +DBWatch *dbwatch_new (CouchDB *couchdb, const gchar *dbname, gint update_seq); |
483 | +void dbwatch_free (DBWatch *watch); |
484 | + |
485 | +#endif |
486 | |
487 | === modified file 'couchdb-glib/utils.h' |
488 | --- couchdb-glib/utils.h 2009-08-17 22:26:51 +0000 |
489 | +++ couchdb-glib/utils.h 2009-08-28 15:44:20 +0000 |
490 | @@ -30,6 +30,8 @@ |
491 | |
492 | char *hostname; |
493 | SoupSession *http_session; |
494 | + |
495 | + GHashTable *db_watchlist; |
496 | }; |
497 | |
498 | struct _CouchDBDocument { |
499 | |
500 | === modified file 'tests/test-couchdb-glib.c' |
501 | --- tests/test-couchdb-glib.c 2009-07-27 21:49:15 +0000 |
502 | +++ tests/test-couchdb-glib.c 2009-08-28 15:44:20 +0000 |
503 | @@ -20,6 +20,7 @@ |
504 | */ |
505 | |
506 | #include <couchdb-glib.h> |
507 | +#include <utils.h> |
508 | |
509 | static CouchDB *couchdb; |
510 | |
511 | @@ -47,7 +48,8 @@ |
512 | doclist = couchdb_list_documents (couchdb, (const char *) dblist->data, &error); |
513 | g_assert (error == NULL); |
514 | g_assert (g_slist_length (doclist) == couchdb_database_info_get_documents_count (dbinfo)); |
515 | - couchdb_free_document_list (doclist); |
516 | + if (doclist) |
517 | + couchdb_free_document_list (doclist); |
518 | |
519 | dblist = g_slist_remove (dblist, dblist->data); |
520 | couchdb_database_info_unref (dbinfo); |
521 | @@ -98,6 +100,82 @@ |
522 | } |
523 | } |
524 | |
525 | +static void |
526 | +test_change_databases (void) |
527 | +{ |
528 | + char *dbname; |
529 | + gint i; |
530 | + GError *error = NULL; |
531 | + |
532 | + dbname = generate_uuid (); |
533 | + g_assert (dbname != NULL); |
534 | + |
535 | + /* Create database */ |
536 | + couchdb_create_database (couchdb, dbname, &error); |
537 | + g_assert (error == NULL); |
538 | + |
539 | + couchdb_listen_for_changes (couchdb, dbname); |
540 | + |
541 | + /* Create some documents */ |
542 | + for (i = 0; i < 10; i++) { |
543 | + CouchDBDocument *document; |
544 | + char *str; |
545 | + |
546 | + document = couchdb_document_new (couchdb); |
547 | + g_assert (document != NULL); |
548 | + |
549 | + couchdb_document_set_boolean_field (document, "boolean", TRUE); |
550 | + couchdb_document_set_int_field (document, "int", i); |
551 | + couchdb_document_set_double_field (document, "double", (gdouble) i); |
552 | + |
553 | + str = g_strdup_printf ("value%d", i); |
554 | + couchdb_document_set_string_field (document, "string", str); |
555 | + g_free (str); |
556 | + |
557 | + g_assert (couchdb_document_put (document, dbname, &error)); |
558 | + g_assert (error == NULL); |
559 | + } |
560 | + |
561 | + /* Delete database */ |
562 | + g_assert (couchdb_delete_database (couchdb, dbname, &error)); |
563 | + g_assert (error == NULL); |
564 | + |
565 | + /* Free memory */ |
566 | + g_free (dbname); |
567 | +} |
568 | + |
569 | +static void |
570 | +db_created_cb (CouchDB *couchdb, const char *dbname, gpointer user_data) |
571 | +{ |
572 | + g_print ("Database %s has been created\n", dbname); |
573 | +} |
574 | + |
575 | +static void |
576 | +db_deleted_cb (CouchDB *couchdb, const char *dbname, gpointer user_data) |
577 | +{ |
578 | + g_print ("Database %s has been deleted\n", dbname); |
579 | +} |
580 | + |
581 | +static void |
582 | +doc_changed_cb (CouchDB *couchdb, const char *dbname, CouchDBDocument *document, gpointer user_data) |
583 | +{ |
584 | + char *doc_str; |
585 | + |
586 | + doc_str = couchdb_document_to_string (document); |
587 | + g_print ("Document %s has been %s: %s\n", |
588 | + couchdb_document_get_id (document), |
589 | + (const gchar *) user_data, |
590 | + doc_str); |
591 | + |
592 | + g_free (doc_str); |
593 | +} |
594 | + |
595 | +static void |
596 | +doc_deleted_cb (CouchDB *couchdb, const char *dbname, const char *docid, gpointer user_data) |
597 | +{ |
598 | + g_print ("Document %s in database %s has been deleted\n", docid, dbname); |
599 | +} |
600 | + |
601 | int |
602 | main (int argc, char *argv[]) |
603 | { |
604 | @@ -112,9 +190,16 @@ |
605 | return -1; |
606 | } |
607 | |
608 | + g_signal_connect (G_OBJECT (couchdb), "database_created", G_CALLBACK (db_created_cb), NULL); |
609 | + g_signal_connect (G_OBJECT (couchdb), "database_deleted", G_CALLBACK (db_deleted_cb), NULL); |
610 | + g_signal_connect (G_OBJECT (couchdb), "document_created", G_CALLBACK (doc_changed_cb), "created"); |
611 | + g_signal_connect (G_OBJECT (couchdb), "document_updated", G_CALLBACK (doc_changed_cb), "updated"); |
612 | + g_signal_connect (G_OBJECT (couchdb), "document_deleted", G_CALLBACK (doc_deleted_cb), NULL); |
613 | + |
614 | /* Setup test functions */ |
615 | g_test_add_func ("/testcouchdbglib/ListDatabases", test_list_databases); |
616 | g_test_add_func ("/testcouchdbglib/ListDocuments", test_list_documents); |
617 | + g_test_add_func ("/testcouchdbglib/ChangeDatabases", test_change_databases); |
618 | |
619 | return g_test_run (); |
620 | } |
Added changes notifications:
* Generate marshallers for CouchDB signals listen_ for_changes API
* Emit modification signals when doing changes to dbs/documents
* Added couchdb_
* Added DBWatch object to do the actual watching of changes
* Added tests for modification API and change signals