[couchdb-glib] Added changes notifications:



commit c785237017f9fd152e85f6e13d42c23adeffe2f4
Author: Rodrigo Moya <rodrigo gnome-db org>
Date:   Mon Aug 31 17:48:46 2009 +0200

    Added changes notifications:
    
    * Generate marshallers for CouchDB signals
    * Emit modification signals when doing changes to dbs/documents
    * Added couchdb_listen_for_changes API
    * Added DBWatch object to do the actual watching of changes
    * Added tests for modification API and change signals

 configure.ac                      |    4 +
 couchdb-glib/Makefile.am          |   16 ++++-
 couchdb-glib/couchdb-document.c   |   15 +++-
 couchdb-glib/couchdb-glib.h       |   12 +++-
 couchdb-glib/couchdb-marshal.list |    2 +
 couchdb-glib/couchdb.c            |  114 ++++++++++++++++++++++++++++++
 couchdb-glib/dbwatch.c            |  137 +++++++++++++++++++++++++++++++++++++
 couchdb-glib/dbwatch.h            |   37 ++++++++++
 couchdb-glib/utils.h              |    2 +
 tests/test-couchdb-glib.c         |   87 +++++++++++++++++++++++-
 10 files changed, 419 insertions(+), 7 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 79de145..b00bfca 100644
--- a/configure.ac
+++ b/configure.ac
@@ -15,6 +15,10 @@ AC_DISABLE_STATIC
 AC_PROG_CC
 AC_PROG_LIBTOOL
 
+dnl glib-genmarshal
+AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal)
+
+dnl Look for needed modules
 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)
 AC_SUBST(COUCHDB_GLIB_CFLAGS)
 AC_SUBST(COUCHDB_GLIB_LIBS)
diff --git a/couchdb-glib/Makefile.am b/couchdb-glib/Makefile.am
index f16616f..8fc2209 100644
--- a/couchdb-glib/Makefile.am
+++ b/couchdb-glib/Makefile.am
@@ -3,11 +3,23 @@ INCLUDES =		\
 
 lib_LTLIBRARIES = libcouchdb-glib-1.0.la
 
+# Marshallers
+MARSHAL_GENERATED = couchdb-marshal.c couchdb-marshal.h
+
+couchdb-marshal.h: couchdb-marshal.list $(GLIB_GENMARSHAL)
+	$(GLIB_GENMARSHAL) $< --header --prefix=_couchdb_marshal > $@
+
+couchdb-marshal.c: couchdb-marshal.list $(GLIB_GENMARSHAL)
+	$(GLIB_GENMARSHAL) $< --body --prefix=_couchdb_marshal > $@
+
 libcouchdb_glib_1_0_la_SOURCES =	\
+	$(MARSHAL_GENERATED)		\
 	couchdb.c			\
 	couchdb-document.c		\
 	couchdb-document-contact.c	\
 	couchdb-types.c			\
+	dbwatch.c			\
+	dbwatch.h			\
 	utils.c				\
 	utils.h
 libcouchdb_glib_1_0_la_LIBADD =		\
@@ -22,4 +34,6 @@ h_DATA = 				\
 	couchdb-document-contact.h	\
 	couchdb-types.h
 
-EXTRA_DIST = $(h_DATA)
+EXTRA_DIST = $(h_DATA) $(MARSHAL_GENERATED)
+BUILT_SOURCES = $(MARSHAL_GENERATED)
+CLEANFILES = $(BUILT_SOURCES)
diff --git a/couchdb-glib/couchdb-document.c b/couchdb-glib/couchdb-document.c
index e5dbd36..ffef220 100644
--- a/couchdb-glib/couchdb-document.c
+++ b/couchdb-glib/couchdb-document.c
@@ -137,6 +137,11 @@ couchdb_document_put (CouchDBDocument *document,
 			document->dbname = g_strdup (dbname);
 		}
 
+		if (id)
+			g_signal_emit_by_name (document->couchdb, "document_updated", dbname, document);
+		else
+			g_signal_emit_by_name (document->couchdb, "document_created", dbname, document);
+
 		result = TRUE;
 	}
 
@@ -167,7 +172,7 @@ couchdb_document_delete (CouchDBDocument *document, GError **error)
 	if (parser) {
 		g_object_unref (G_OBJECT (parser));
 
-		result = TRUE;
+		g_signal_emit_by_name (document->couchdb, "document_deleted", document->dbname, id);
 	}
 
 	g_free (url);
@@ -182,9 +187,11 @@ couchdb_document_get_id (CouchDBDocument *document)
 
 	if (document->root_node &&
 	    json_node_get_node_type (document->root_node) == JSON_NODE_OBJECT) {
-		return json_object_get_string_member (
-			json_node_get_object (document->root_node),
-			"_id");
+		if (json_object_has_member (json_node_get_object (document->root_node),
+					    "_id"))
+			return json_object_get_string_member (
+				json_node_get_object (document->root_node),
+				"_id");
 	}
 
 	return NULL;
diff --git a/couchdb-glib/couchdb-glib.h b/couchdb-glib/couchdb-glib.h
index bc8dc6a..43a84c5 100644
--- a/couchdb-glib/couchdb-glib.h
+++ b/couchdb-glib/couchdb-glib.h
@@ -31,9 +31,18 @@
 #define COUCHDB_IS_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE ((klass), COUCHDB_TYPE))
 #define COUCHDB_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), COUCHDB_TYPE, CouchDBClass))
 
+typedef struct _CouchDBDocument CouchDBDocument;
+
 typedef struct _CouchDB CouchDB;
 typedef struct {
 	GObjectClass parent_class;
+
+	void (* database_created) (CouchDB *couchdb, const char *dbname);
+	void (* database_deleted) (CouchDB *couchdb, const char *dbname);
+
+	void (* document_created) (CouchDB *couchdb, const char *dbname, CouchDBDocument *document);
+	void (* document_updated) (CouchDB *couchdb, const char *dbname, CouchDBDocument *document);
+	void (* document_deleted) (CouchDB *couchdb, const char *dbname, const char *docid);
 } CouchDBClass;
 
 GType       couchdb_get_type (void);
@@ -53,6 +62,8 @@ CouchDBDatabaseInfo *couchdb_get_database_info (CouchDB *couchdb, const char *db
 gboolean             couchdb_create_database (CouchDB *couchdb, const char *dbname, GError **error);
 gboolean             couchdb_delete_database (CouchDB *couchdb, const char *dbname, GError **error);
 
+void                 couchdb_listen_for_changes (CouchDB *couchdb, const char *dbname);
+
 /*
  * Documents API
  */
@@ -64,7 +75,6 @@ gboolean             couchdb_delete_database (CouchDB *couchdb, const char *dbna
 #define COUCHDB_IS_DOCUMENT_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE ((klass), COUCHDB_TYPE_DOCUMENT))
 #define COUCHDB_DOCUMENT_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), COUCHDB_TYPE_DOCUMENT, CouchDBDocumentClass))
 
-typedef struct _CouchDBDocument CouchDBDocument;
 typedef struct {
 	GObjectClass parent_class;
 } CouchDBDocumentClass;
diff --git a/couchdb-glib/couchdb-marshal.list b/couchdb-glib/couchdb-marshal.list
new file mode 100644
index 0000000..991e86b
--- /dev/null
+++ b/couchdb-glib/couchdb-marshal.list
@@ -0,0 +1,2 @@
+NONE:STRING,OBJECT
+NONE:STRING,STRING
diff --git a/couchdb-glib/couchdb.c b/couchdb-glib/couchdb.c
index decc59f..db69c22 100644
--- a/couchdb-glib/couchdb.c
+++ b/couchdb-glib/couchdb.c
@@ -23,15 +23,29 @@
 #include <libsoup/soup-gnome.h>
 #include <json-glib/json-glib.h>
 #include "couchdb-glib.h"
+#include "couchdb-marshal.h"
+#include "dbwatch.h"
 #include "utils.h"
 
 G_DEFINE_TYPE(CouchDB, couchdb, G_TYPE_OBJECT)
 
+enum {
+	DATABASE_CREATED,
+	DATABASE_DELETED,
+	DOCUMENT_CREATED,
+	DOCUMENT_UPDATED,
+	DOCUMENT_DELETED,
+	LAST_SIGNAL
+};
+static guint couchdb_signals[LAST_SIGNAL];
+
 static void
 couchdb_finalize (GObject *object)
 {
 	CouchDB *couchdb = COUCHDB (object);
 
+	g_hash_table_destroy (couchdb->db_watchlist);
+
 	g_free (couchdb->hostname);
 	g_object_unref (couchdb->http_session);
 
@@ -44,11 +58,64 @@ couchdb_class_init (CouchDBClass *klass)
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
 	object_class->finalize = couchdb_finalize;
+
+	/* Signals */
+	couchdb_signals[DATABASE_CREATED] =
+		g_signal_new ("database_created",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (CouchDBClass, database_created),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__STRING,
+			      G_TYPE_NONE, 1,
+			      G_TYPE_STRING);
+	couchdb_signals[DATABASE_DELETED] =
+		g_signal_new ("database_deleted",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (CouchDBClass, database_deleted),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__STRING,
+			      G_TYPE_NONE, 1,
+			      G_TYPE_STRING);
+	couchdb_signals[DOCUMENT_CREATED] =
+		g_signal_new ("document_created",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (CouchDBClass, document_created),
+			      NULL, NULL,
+			      _couchdb_marshal_VOID__STRING_OBJECT,
+			      G_TYPE_NONE, 2,
+			      G_TYPE_STRING,
+			      G_TYPE_OBJECT);
+	couchdb_signals[DOCUMENT_UPDATED] =
+		g_signal_new ("document_updated",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (CouchDBClass, document_updated),
+			      NULL, NULL,
+			      _couchdb_marshal_VOID__STRING_OBJECT,
+			      G_TYPE_NONE, 2,
+			      G_TYPE_STRING,
+			      G_TYPE_OBJECT);
+	couchdb_signals[DOCUMENT_DELETED] =
+		g_signal_new ("document_deleted",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (CouchDBClass, document_deleted),
+			      NULL, NULL,
+			      _couchdb_marshal_VOID__STRING_STRING,
+			      G_TYPE_NONE, 2,
+			      G_TYPE_STRING,
+			      G_TYPE_STRING);
 }
 
 static void
 couchdb_init (CouchDB *couchdb)
 {
+	couchdb->db_watchlist = g_hash_table_new_full (g_str_hash, g_str_equal,
+						       (GDestroyNotify) g_free,
+						       (GDestroyNotify) dbwatch_free);
 }
 
 CouchDB *
@@ -168,6 +235,9 @@ couchdb_create_database (CouchDB *couchdb, const char *dbname, GError **error)
 
 	g_free (url);
 
+	if (result)
+		g_signal_emit_by_name (couchdb, "database_created", dbname);
+
 	return result;
 }
 
@@ -196,6 +266,14 @@ couchdb_delete_database (CouchDB *couchdb, const char *dbname, GError **error)
 
 	g_free (url);
 
+	if (result) {
+		/* If we're listening for changes on this database, stop doing so */
+		if (g_hash_table_lookup (couchdb->db_watchlist, dbname))
+			g_hash_table_remove (couchdb->db_watchlist, dbname);
+
+		g_signal_emit_by_name (couchdb, "database_deleted", dbname);
+	}
+
 	return result;
 }
 
@@ -261,3 +339,39 @@ couchdb_free_document_list (GSList *doclist)
 	g_slist_foreach (doclist, (GFunc) couchdb_document_info_unref, NULL);
 	g_slist_free (doclist);
 }
+
+void
+couchdb_listen_for_changes (CouchDB *couchdb, const char *dbname)
+{
+	DBWatch *watch;
+	CouchDBDatabaseInfo *db_info;
+	GError *error = NULL;
+
+	g_return_if_fail (COUCHDB_IS (couchdb));
+	g_return_if_fail (dbname != NULL);
+
+	watch = g_hash_table_lookup (couchdb->db_watchlist, dbname);
+	if (watch) {
+		g_warning ("Already listening for changes in '%s' database", dbname);
+		return;
+	}
+
+	/* Retrieve information for database, to know the last_update_sequence */
+	db_info = couchdb_get_database_info (couchdb, dbname, &error);
+	if (!db_info) {
+		g_warning ("Could not retrieve information for '%s' database: %s",
+			   dbname, error->message);
+		g_error_free (error);
+
+		return;
+	}
+
+	watch = dbwatch_new (couchdb,
+			     dbname,
+			     couchdb_database_info_get_update_sequence (db_info));
+	if (watch)
+		g_hash_table_insert (couchdb->db_watchlist, g_strdup (dbname), watch);
+
+	/* Free memory */
+	couchdb_database_info_unref (db_info);
+}
diff --git a/couchdb-glib/dbwatch.c b/couchdb-glib/dbwatch.c
new file mode 100644
index 0000000..bb9adc0
--- /dev/null
+++ b/couchdb-glib/dbwatch.c
@@ -0,0 +1,137 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Canonical Services Ltd (www.canonical.com)
+ *
+ * Authors: Rodrigo Moya <rodrigo moya canonical com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "couchdb-glib.h"
+#include "dbwatch.h"
+#include "utils.h"
+
+#define TIMEOUT_SECONDS 300
+
+static void
+process_change (DBWatch *watch, JsonNode *node)
+{
+	JsonObject *this_change;
+	const gchar *id;
+	CouchDBDocument *document;
+	GError *error = NULL;
+
+	if (json_node_get_node_type (node) != JSON_NODE_OBJECT)
+		return;
+
+	this_change = json_node_get_object (node);
+	if (!json_object_has_member (this_change, "id"))
+		return;
+
+	id = json_object_get_string_member (this_change, "id");
+
+	/* We need to try retrieving the document, to check if it's removed or not */
+	document = couchdb_document_get (watch->couchdb, watch->dbname, id, &error);
+	if (document) {
+		const gchar *revision;
+
+		revision = couchdb_document_get_revision (document);
+		if (revision != NULL) {
+			if (revision[0] == '1')
+				g_signal_emit_by_name (watch->couchdb, "document_created",
+						       watch->dbname, document);
+			else
+				g_signal_emit_by_name (watch->couchdb, "document_updated",
+						       watch->dbname, document);
+		}
+
+		g_object_unref (G_OBJECT (document));
+	} else {
+		if (error != NULL) {
+			g_warning ("Error retrieving document '%s': %s", id, error->message);
+			g_error_free (error);
+		} else {
+			/* The document is no longer in the DB, notify */
+			g_signal_emit_by_name (watch->couchdb, "document_deleted", watch->dbname, id);
+		}
+	}
+}
+
+static gboolean
+watch_timeout_cb (gpointer user_data)
+{
+	char *url;
+	JsonParser *parser;
+	GError *error = NULL;
+	DBWatch *watch = (DBWatch *) user_data;
+
+	url = g_strdup_printf ("%s/%s/_changes?since=%d",
+			       watch->couchdb->hostname,
+			       watch->dbname,
+			       watch->last_update_seq);
+	parser = send_message_and_parse (watch->couchdb, SOUP_METHOD_GET, url, NULL, &error);
+	if (parser != NULL) {
+		JsonNode *root_node;
+
+		root_node = json_parser_get_root (parser);
+		if (json_node_get_node_type (root_node) == JSON_NODE_OBJECT) {
+			JsonObject *root_object;
+			JsonArray *results;
+
+			root_object = json_node_get_object (root_node);
+			results = json_object_get_array_member (root_object, "results");
+			if (results) {
+				GList *json_elements, *sl;
+
+				json_elements = json_array_get_elements (results);
+				for (sl = json_elements; sl != NULL; sl = sl->next)
+					process_change (watch, (JsonNode *) sl->data);
+			}
+
+			if (json_object_has_member (root_object, "last_seq"))
+				watch->last_update_seq = json_object_get_int_member (root_object, "last_seq");
+		}
+
+		g_object_unref (G_OBJECT (parser));
+	}
+
+	/* Free memory */
+	g_free (url);
+}
+
+DBWatch *
+dbwatch_new (CouchDB *couchdb, const gchar *dbname, gint update_seq)
+{
+	DBWatch *watch;
+
+	watch = g_new0 (DBWatch, 1);
+	watch->couchdb = couchdb;
+	watch->dbname = g_strdup (dbname);
+	watch->last_update_seq = update_seq;
+
+	/* Set timeout to check for changes every 5 minutes*/
+	watch->timeout_id = g_timeout_add (TIMEOUT_SECONDS * 1000, (GSourceFunc) watch_timeout_cb, watch);
+	
+	return watch;
+}
+
+void
+dbwatch_free (DBWatch *watch)
+{
+	g_free (watch->dbname);
+	g_source_remove (watch->timeout_id);
+
+	g_free (watch);
+}
diff --git a/couchdb-glib/dbwatch.h b/couchdb-glib/dbwatch.h
new file mode 100644
index 0000000..9e9771e
--- /dev/null
+++ b/couchdb-glib/dbwatch.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Canonical Services Ltd (www.canonical.com)
+ *
+ * Authors: Rodrigo Moya <rodrigo moya canonical com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __DBWATCH_H__
+#define __DBWATCH_H__
+
+#include "utils.h"
+
+typedef struct {
+	CouchDB *couchdb;
+	gchar *dbname;
+	gint last_update_seq;
+	guint timeout_id;
+} DBWatch;
+
+DBWatch *dbwatch_new (CouchDB *couchdb, const gchar *dbname, gint update_seq);
+void     dbwatch_free (DBWatch *watch);
+
+#endif
diff --git a/couchdb-glib/utils.h b/couchdb-glib/utils.h
index e79be3f..7157bdf 100644
--- a/couchdb-glib/utils.h
+++ b/couchdb-glib/utils.h
@@ -30,6 +30,8 @@ struct _CouchDB {
 
 	char *hostname;
 	SoupSession *http_session;
+
+	GHashTable *db_watchlist;
 };
 
 struct _CouchDBDocument {
diff --git a/tests/test-couchdb-glib.c b/tests/test-couchdb-glib.c
index 5a6ecd2..277b437 100644
--- a/tests/test-couchdb-glib.c
+++ b/tests/test-couchdb-glib.c
@@ -20,6 +20,7 @@
  */
 
 #include <couchdb-glib.h>
+#include <utils.h>
 
 static CouchDB *couchdb;
 
@@ -47,7 +48,8 @@ test_list_databases (void)
 		doclist = couchdb_list_documents (couchdb, (const char *) dblist->data, &error);
 		g_assert (error == NULL);
 		g_assert (g_slist_length (doclist) == couchdb_database_info_get_documents_count (dbinfo));
-		couchdb_free_document_list (doclist);
+		if (doclist)
+			couchdb_free_document_list (doclist);
 
 		dblist = g_slist_remove (dblist, dblist->data);
 		couchdb_database_info_unref (dbinfo);
@@ -98,6 +100,82 @@ test_list_documents (void)
 	}
 }
 
+static void
+test_change_databases (void)
+{
+	char *dbname;
+	gint i;
+	GError *error = NULL;
+
+	dbname = generate_uuid ();
+	g_assert (dbname != NULL);
+
+	/* Create database */
+	couchdb_create_database (couchdb, dbname, &error);
+	g_assert (error == NULL);
+
+	couchdb_listen_for_changes (couchdb, dbname);
+
+	/* Create some documents */
+	for (i = 0; i < 10; i++) {
+		CouchDBDocument *document;
+		char *str;
+
+		document = couchdb_document_new (couchdb);
+		g_assert (document != NULL);
+
+		couchdb_document_set_boolean_field (document, "boolean", TRUE);
+		couchdb_document_set_int_field (document, "int", i);
+		couchdb_document_set_double_field (document, "double", (gdouble) i);
+
+		str = g_strdup_printf ("value%d", i);
+		couchdb_document_set_string_field (document, "string", str);
+		g_free (str);
+
+		g_assert (couchdb_document_put (document, dbname, &error));
+		g_assert (error == NULL);
+	}
+	
+	/* Delete database */
+	g_assert (couchdb_delete_database (couchdb, dbname, &error));
+	g_assert (error == NULL);
+
+	/* Free memory */
+	g_free (dbname);
+}
+
+static void
+db_created_cb (CouchDB *couchdb, const char *dbname, gpointer user_data)
+{
+	g_print ("Database %s has been created\n", dbname);
+}
+
+static void
+db_deleted_cb (CouchDB *couchdb, const char *dbname, gpointer user_data)
+{
+	g_print ("Database %s has been deleted\n", dbname);
+}
+
+static void
+doc_changed_cb (CouchDB *couchdb, const char *dbname, CouchDBDocument *document, gpointer user_data)
+{
+	char *doc_str;
+
+	doc_str = couchdb_document_to_string (document);
+	g_print ("Document %s has been %s: %s\n",
+		 couchdb_document_get_id (document),
+		 (const gchar *) user_data,
+		 doc_str);
+
+	g_free (doc_str);
+}
+
+static void
+doc_deleted_cb (CouchDB *couchdb, const char *dbname, const char *docid, gpointer user_data)
+{
+	g_print ("Document %s in database %s has been deleted\n", docid, dbname);
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -112,9 +190,16 @@ main (int argc, char *argv[])
 		return -1;
 	}
 
+	g_signal_connect (G_OBJECT (couchdb), "database_created", G_CALLBACK (db_created_cb), NULL);
+	g_signal_connect (G_OBJECT (couchdb), "database_deleted", G_CALLBACK (db_deleted_cb), NULL);
+	g_signal_connect (G_OBJECT (couchdb), "document_created", G_CALLBACK (doc_changed_cb), "created");
+	g_signal_connect (G_OBJECT (couchdb), "document_updated", G_CALLBACK (doc_changed_cb), "updated");
+	g_signal_connect (G_OBJECT (couchdb), "document_deleted", G_CALLBACK (doc_deleted_cb), NULL);
+
 	/* Setup test functions */
 	g_test_add_func ("/testcouchdbglib/ListDatabases", test_list_databases);
 	g_test_add_func ("/testcouchdbglib/ListDocuments", test_list_documents);
+	g_test_add_func ("/testcouchdbglib/ChangeDatabases", test_change_databases);
 
 	return g_test_run ();
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]