[couchdb-glib] Refactor API to adapt to new CouchdbDatabase object



commit 3d5de3a968c3565ed61bea42c3ad8ad0d912172b
Author: Rodrigo Moya <rodrigo gnome-db org>
Date:   Mon May 17 16:55:39 2010 +0200

    Refactor API to adapt to new CouchdbDatabase object

 couchdb-glib/couchdb-database.c                   |  455 ++++++++++++++++++++-
 couchdb-glib/couchdb-database.h                   |   25 ++-
 couchdb-glib/couchdb-document.c                   |  282 +++-----------
 couchdb-glib/couchdb-document.h                   |   31 +-
 couchdb-glib/couchdb-glib.h                       |    1 +
 couchdb-glib/couchdb-session.c                    |  249 +-----------
 couchdb-glib/couchdb-session.h                    |   10 -
 couchdb-glib/couchdb-types.h                      |    1 -
 couchdb-glib/dbwatch.c                            |   25 +-
 couchdb-glib/dbwatch.h                            |    7 +-
 couchdb-glib/utils.h                              |    3 +-
 desktopcouch-glib/desktopcouch-document-contact.c |  376 +++++++++---------
 desktopcouch-glib/desktopcouch-document-contact.h |  122 +++---
 desktopcouch-glib/desktopcouch-document.c         |   46 ++-
 desktopcouch-glib/desktopcouch-document.h         |   29 ++-
 desktopcouch-glib/desktopcouch-session.c          |   39 ++
 tests/test-couchdb-glib.c                         |   38 ++-
 tests/test-list-databases.c                       |   16 +-
 18 files changed, 958 insertions(+), 797 deletions(-)
---
diff --git a/couchdb-glib/couchdb-database.c b/couchdb-glib/couchdb-database.c
index 5de07ce..e8cbc0d 100644
--- a/couchdb-glib/couchdb-database.c
+++ b/couchdb-glib/couchdb-database.c
@@ -19,14 +19,31 @@
  * Boston, MA 02110-1301, USA.
  */
 
+#include <libsoup/soup-message.h>
+#include <libsoup/soup-uri.h>
 #include "couchdb-database.h"
+#include "couchdb-document-info.h"
+#include "couchdb-document.h"
+#include "couchdb-marshal.h"
+#include "couchdb-types.h"
+#include "dbwatch.h"
+#include "utils.h"
 
 struct _CouchdbDatabasePrivate {
 	CouchdbSession *session;
 	char *dbname;
+	DBWatch *db_watch;
 };
 
 enum {
+	DOCUMENT_CREATED,
+	DOCUMENT_UPDATED,
+	DOCUMENT_DELETED,
+	LAST_SIGNAL
+};
+static guint couchdb_database_signals[LAST_SIGNAL];
+
+enum {
     PROP_0,
     PROP_SESSION,
     PROP_DATABASE_NAME
@@ -49,6 +66,11 @@ couchdb_database_finalize (GObject *object)
 		database->priv->dbname = NULL;
 	}
 
+	if (database->priv->db_watch != NULL) {
+		dbwatch_free (database->priv->db_watch);
+		database->priv->db_watch = NULL;
+	}
+
 	g_free (database->priv);
 
 	G_OBJECT_CLASS (couchdb_database_parent_class)->finalize (object);
@@ -106,13 +128,14 @@ couchdb_database_class_init (CouchdbDatabaseClass *klass)
 	object_class->finalize = couchdb_database_finalize;
 	object_class->set_property = couchdb_database_set_property;
 	object_class->get_property = couchdb_database_get_property;
+	klass->create_document_from_json = NULL;
 
 	g_object_class_install_property (object_class,
         	                         PROP_SESSION,
                 	                 g_param_spec_object ("session",
                         	                              "Session",
 							      "CouchDB session associated with this database",
-							      NULL,
+							      COUCHDB_TYPE_DATABASE,
 							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 	g_object_class_install_property (object_class,
         	                         PROP_DATABASE_NAME,
@@ -121,6 +144,38 @@ couchdb_database_class_init (CouchdbDatabaseClass *klass)
 							      "Name of the database",
 							      NULL,
 							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+	/* Signals */
+	couchdb_database_signals[DOCUMENT_CREATED] =
+		g_signal_new ("document_created",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (CouchdbDatabaseClass, document_created),
+			      NULL, NULL,
+			      _couchdb_marshal_VOID__STRING_OBJECT,
+			      G_TYPE_NONE, 2,
+			      G_TYPE_STRING,
+			      G_TYPE_OBJECT);
+	couchdb_database_signals[DOCUMENT_UPDATED] =
+		g_signal_new ("document_updated",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (CouchdbDatabaseClass, document_updated),
+			      NULL, NULL,
+			      _couchdb_marshal_VOID__STRING_OBJECT,
+			      G_TYPE_NONE, 2,
+			      G_TYPE_STRING,
+			      G_TYPE_OBJECT);
+	couchdb_database_signals[DOCUMENT_DELETED] =
+		g_signal_new ("document_deleted",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (CouchdbDatabaseClass, document_deleted),
+			      NULL, NULL,
+			      _couchdb_marshal_VOID__STRING_STRING,
+			      G_TYPE_NONE, 2,
+			      G_TYPE_STRING,
+			      G_TYPE_STRING);
 }
 
 static void
@@ -148,3 +203,401 @@ couchdb_database_new (CouchdbSession *session, const char *dbname)
 			     NULL);
 }
 
+static JsonArray *
+call_all_docs_uri (CouchdbSession *session, const char *url, JsonParser *parser, GError **error)
+{
+	JsonArray *rows = NULL;
+
+	if (couchdb_session_send_message (session, SOUP_METHOD_GET, url, NULL, parser, error)) {
+		JsonNode *root_node;
+
+		root_node = json_parser_get_root (parser);
+		if (json_node_get_node_type (root_node) == JSON_NODE_OBJECT) {
+			rows = json_object_get_array_member (
+				json_node_get_object (root_node), "rows");
+		}
+	}
+
+	return rows;
+}
+
+/**
+ * couchdb_database_list_documents:
+ * @database: A #CouchdbDatabase object
+ * @error: Placeholder for error information
+ *
+ * Retrieve the list of all documents from a database on a running CouchDB instance.
+ * For each document, a #CouchdbDocumentInfo object is returned on the list, which
+ * can then be used for retrieving specific information for each document.
+ *
+ * Return Value: a list of #CouchdbDocumentInfo objects, or NULL if there are none
+ * or there was an error (in which case the error argument will contain information
+ * about the error). Once no longer needed, the list should be freed by calling
+ * #couchdb_database_free_document_list.
+ */
+GSList *
+couchdb_database_list_documents (CouchdbDatabase *database, GError **error)
+{
+	char *url;
+	JsonParser *parser;
+	JsonArray *rows;
+	GSList *doclist = NULL;
+
+	g_return_val_if_fail (COUCHDB_IS_DATABASE (database), NULL);
+
+	url = g_strdup_printf ("%s/%s/_all_docs",
+			       couchdb_session_get_uri (database->priv->session),
+			       database->priv->dbname);
+	parser = json_parser_new ();
+
+	rows = call_all_docs_uri (database->priv->session, url, parser, error);
+	if (rows != NULL) {
+		gint i;
+		for (i = 0; i < json_array_get_length (rows); i++) {
+			JsonObject *doc;
+			CouchdbDocumentInfo *doc_info;
+
+			doc = json_array_get_object_element (rows, i);
+			if (!doc)
+				continue;
+
+			doc_info = couchdb_document_info_new (
+				json_object_get_string_member (doc, "id"),
+				json_object_get_string_member (
+					json_object_get_object_member (doc, "value"),
+					"rev"));
+			doclist = g_slist_append (doclist, doc_info);
+		}
+	}
+
+	g_object_unref (G_OBJECT (parser));
+	g_free (url);
+
+	return doclist;
+}
+
+/**
+ * couchdb_database_get_all_documents:
+ * @database: A #CouchdbDatabase object
+ * @error: Placeholder for error information
+ *
+ * Retrieve all documents from a database on a running CouchDB instance. For
+ * each document found in the database, a #CouchdbDocument object is returned
+ * on the list, which represents the document's contents as found on the
+ * underlying database.
+ *
+ * Return value: a list of #CouchdbDocument objects, or NULL if there are none
+ * or there was an error (in which case the error argument will contain information
+ * about the error). Once no longer needed, the list should be freed by calling
+ * #couchdb_database_free_document_list.
+ */
+GSList *
+couchdb_database_get_all_documents (CouchdbDatabase *database, GError **error)
+{
+	char *url;
+	JsonParser *parser;
+	JsonArray *rows;
+	GSList *doclist = NULL;
+
+	g_return_val_if_fail (COUCHDB_IS_DATABASE (database), NULL);
+
+	url = g_strdup_printf ("%s/%s/_all_docs?include_docs=true",
+			       couchdb_session_get_uri (database->priv->session),
+			       database->priv->dbname);
+	parser = json_parser_new ();
+
+	rows = call_all_docs_uri (database->priv->session, url, parser, error);
+	if (rows != NULL) {
+		gint i;
+		for (i = 0; i < json_array_get_length (rows); i++) {
+			JsonObject *obj;
+			CouchdbDocument *document;
+
+			obj = json_array_get_object_element (rows, i);
+			if (!obj)
+				continue;
+
+			if (COUCHDB_DATABASE_GET_CLASS (database)->create_document_from_json != NULL) {
+				document = COUCHDB_DATABASE_GET_CLASS (database)->create_document_from_json (
+					database,
+					json_object_get_object_member (obj, "doc"));
+			} else {
+				document = couchdb_document_new_from_json_object (
+					json_object_get_object_member (obj, "doc"));
+			}
+			if (document != NULL)
+				doclist = g_slist_append (doclist, document);
+		}
+	}
+
+	g_object_unref (G_OBJECT (parser));
+	g_free (url);
+
+	return doclist;
+}
+
+/**
+ * couchdb_session_free_document_list:
+ * @doclist: A list of #CouchdbDocumentInfo or #CouchdbDocument objects, as returned by
+ * #couchdb_database_list_documents or #couchdb_database_get_all_documents
+ *
+ * Free the list of documents returned by #couchdb_database_list_documents or
+ * #couchdb_database_get_all_documents
+ */
+void
+couchdb_database_free_document_list (GSList *doclist)
+{
+	g_return_if_fail (doclist != NULL);
+
+	while (doclist != NULL) {
+		gpointer data = doclist->data;
+
+		doclist = g_slist_remove (doclist, data);
+
+		if (COUCHDB_IS_DOCUMENT (data))
+			g_object_unref (G_OBJECT (data));
+		else
+			couchdb_document_info_unref (data);
+	}
+}
+
+/**
+ * couchdb_database_get_document:
+ * @database: A #CouchdbDatabase object
+ * @docid: Unique ID of the document to be retrieved
+ * @error: Placeholder for error information
+ *
+ * Retrieve the last revision of a document from the given database.
+ *
+ * Return value: A #CouchdbDocument object if successful, NULL otherwise, in
+ * which case, the error argument will contain information about the error.
+ */
+CouchdbDocument *
+couchdb_database_get_document (CouchdbDatabase *database,
+			       const char *docid,
+			       GError **error)
+{
+	char *url, *encoded_docid;
+	JsonParser *parser;
+	CouchdbDocument *document = NULL;
+
+	g_return_val_if_fail (COUCHDB_IS_DATABASE (database), NULL);
+	g_return_val_if_fail (docid != NULL, NULL);
+
+	encoded_docid = soup_uri_encode (docid, NULL);
+	url = g_strdup_printf ("%s/%s/%s", couchdb_session_get_uri (database->priv->session),
+			       database->priv->dbname, encoded_docid);
+	parser = json_parser_new ();
+	if (couchdb_session_send_message (database->priv->session, SOUP_METHOD_GET, url, NULL, parser, error)) {
+		if (COUCHDB_DATABASE_GET_CLASS (database)->create_document_from_json != NULL) {
+			document = COUCHDB_DATABASE_GET_CLASS (database)->create_document_from_json (
+				database, json_node_get_object (json_parser_get_root (parser)));
+		} else {
+			document = couchdb_document_new_from_json_object (json_node_get_object (json_parser_get_root (parser)));
+		}
+
+	}
+
+	g_object_unref (G_OBJECT (parser));
+	g_free (encoded_docid);
+	g_free (url);
+
+	return document;
+}
+
+/**
+ * couchdb_database_put_document:
+ * @database: A #CouchdbDatabase object
+ * @document: A #CouchdbDocument object
+ * @error: Placeholder for error information
+ *
+ * Store a document on a CouchDB database.
+ *
+ * If it is a new document, and hence does not have a unique ID, a unique ID
+ * will be generated and stored on the #CouchdbDocument object. Likewise,
+ * whether the document is new or just an update to an existing one, the
+ * #CouchdbDocument object passed to this function will be updated to contain
+ * the latest revision of the document, as returned by CouchDB (revision that
+ * can be retrieved by calling #couchdb_document_get_revision).
+ *
+ * Return value: TRUE if successful, FALSE otherwise, in which case the error
+ * argument will contain information about the error.
+ */
+gboolean
+couchdb_database_put_document (CouchdbDatabase *database,
+			       CouchdbDocument *document,
+			       GError **error)
+{
+	char *url, *body;
+	const char *id;
+	JsonParser *parser;
+	gboolean result = FALSE;
+	gboolean send_ok;
+
+	g_return_val_if_fail (COUCHDB_IS_DATABASE (database), FALSE);
+	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), FALSE);
+
+	id = couchdb_document_get_id (document);
+	body = couchdb_document_to_string (document);
+	parser = json_parser_new ();
+	if (id) {
+		char *encoded_docid;
+
+		encoded_docid = soup_uri_encode (id, NULL);
+		url = g_strdup_printf ("%s/%s/%s", couchdb_session_get_uri (database->priv->session), database->priv->dbname, encoded_docid);		
+		send_ok = couchdb_session_send_message (database->priv->session, SOUP_METHOD_PUT, url, body, parser, error);
+
+		g_free (encoded_docid);
+	} else {
+		url = g_strdup_printf ("%s/%s/", couchdb_session_get_uri (database->priv->session), database->priv->dbname);
+		send_ok = couchdb_session_send_message (database->priv->session, SOUP_METHOD_POST, url, body, parser, error);
+	}
+
+	if (send_ok) {
+		JsonObject *object;
+
+		object = json_node_get_object (json_parser_get_root (parser));
+		couchdb_document_set_id (document, json_object_get_string_member (object, "id"));
+		couchdb_document_set_revision (document, json_object_get_string_member (object, "rev"));
+
+		if (id)
+			g_signal_emit_by_name (database, "document_updated", document);
+		else
+			g_signal_emit_by_name (database, "document_created", document);
+
+		result = TRUE;
+	}
+
+	/* free memory */
+	g_free (url);
+	g_free (body);
+	g_object_unref (G_OBJECT (parser));
+
+	return result;
+}
+
+/**
+ * couchdb_database_delete_document:
+ * @database: A #CouchdbDatabase object
+ * @document: A #CouchdbDocument object
+ * @error: Placeholder for error information
+ *
+ * Delete an existing document from a CouchDB instance.
+ *
+ * Please take note that this operation can fail if there was an update to the
+ * document and that last revision was not retrieved by the calling application.
+ * This is due to the fact that, to remove a document from CouchDB, the latest
+ * revision needs to be sent, so if the #CouchdbDocument object passed to this
+ * function does not contain the last revision, the operation will fail. In that
+ * case, retrieving the latest revision from CouchDB (with #couchdb_database_get_document)
+ * and trying the delete operation again should fix the issue.
+ *
+ * Return value: TRUE if successful, FALSE otherwise, in which case the error
+ * argument will contain information about the error.
+ */
+gboolean
+couchdb_database_delete_document (CouchdbDatabase *database, CouchdbDocument *document, GError **error)
+{
+	const char *id, *revision;
+	char *url;
+	JsonParser *parser;
+	gboolean result = FALSE;
+
+	g_return_val_if_fail (COUCHDB_IS_DATABASE (database), FALSE);
+	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), FALSE);
+
+	id = couchdb_document_get_id (document);
+	revision = couchdb_document_get_revision (document);
+	if (!id || !revision) /* we can't remove a document without an ID and/or a REVISION */
+		return FALSE;
+
+	url = g_strdup_printf ("%s/%s/%s?rev=%s", couchdb_session_get_uri (database->priv->session), database->priv->dbname, id, revision);
+	
+	/* We don't parse the http response, therefore the parser arg is NULL */
+	if (couchdb_session_send_message (database->priv->session, SOUP_METHOD_DELETE, url, NULL, NULL, error)) {
+		result = TRUE;		
+		g_signal_emit_by_name (database, "document_deleted", id);
+	}
+
+	g_free (url);
+
+	return result;
+}
+
+/**
+ * couchdb_database_listen_for_changes:
+ * @database: A #CouchdbDatabase object
+ * @dbname: Name of the database to poll changes for
+ *
+ * Setup a listener to get information about changes done to a specific database. Please
+ * note that changes done in the application using couchdb-glib will be notified
+ * without the need of calling this function. But if the application wants to receive
+ * notifications of changes done externally (by another application, or by any other
+ * means, like replication with a remote database), it needs to call this function.
+ *
+ * For each change, one of the signals on the #CouchdbDatabase object will be emitted,
+ * so applications just have to connect to those signals before calling this function.
+ */
+void
+couchdb_database_listen_for_changes (CouchdbDatabase *database)
+{
+	CouchdbDatabaseInfo *db_info;
+	GError *error = NULL;
+
+	g_return_if_fail (COUCHDB_IS_DATABASE (database));
+
+	if (database->priv->db_watch != NULL) {
+		g_warning ("Already listening for changes in '%s' database", database->priv->dbname);
+		return;
+	}
+
+	/* Retrieve information for database, to know the last_update_sequence */
+	db_info = couchdb_session_get_database_info (database->priv->session,
+						     database->priv->dbname,
+						     &error);
+	if (!db_info) {
+		g_warning ("Could not retrieve information for '%s' database: %s",
+			   database->priv->dbname, error->message);
+		g_error_free (error);
+
+		return;
+	}
+
+	database->priv->db_watch = dbwatch_new (database,
+						couchdb_database_info_get_update_sequence (db_info));
+
+	/* Free memory */
+	couchdb_database_info_unref (db_info);
+}
+
+/**
+ * couchdb_database_get_session:
+ * @database: A #CouchdbDatabase object
+ *
+ * Retrieve the #CouchdbSession associated with the given database object.
+ *
+ * Return value: A #CouchdbSession object.
+ */
+CouchdbSession *
+couchdb_database_get_session (CouchdbDatabase *database)
+{
+	g_return_val_if_fail (COUCHDB_IS_DATABASE (database), NULL);
+
+	return database->priv->session;
+}
+
+/**
+ * couchdb_database_get_name:
+ * @database: A #CouchdbDatabase object
+ *
+ * Retrieve the name of the database the given #CouchdbDatabase object maps to.
+ *
+ * Return value: The name of the database
+ */
+const char *
+couchdb_database_get_name (CouchdbDatabase *database)
+{
+	g_return_val_if_fail (COUCHDB_IS_DATABASE (database), NULL);
+
+	return database->priv->dbname;
+}
diff --git a/couchdb-glib/couchdb-database.h b/couchdb-glib/couchdb-database.h
index 7073c35..bb6a3bf 100644
--- a/couchdb-glib/couchdb-database.h
+++ b/couchdb-glib/couchdb-database.h
@@ -25,6 +25,7 @@
 #define __COUCHDB_DATABASE_H__
 
 #include <glib-object.h>
+#include "couchdb-document.h"
 #include "couchdb-session.h"
 
 G_BEGIN_DECLS
@@ -45,13 +46,35 @@ struct _CouchdbDatabase {
 
 typedef struct {
 	GObjectClass parent_class;
+
+	/* Signals */
+	void (* document_created) (CouchdbSession *session, CouchdbDocument *document);
+	void (* document_updated) (CouchdbSession *session, CouchdbDocument *document);
+	void (* document_deleted) (CouchdbSession *session, const char *docid);
+
+	/* Virtual methods */
+	CouchdbDocument * (* create_document_from_json) (CouchdbDatabase *database, gpointer json_data);
 } CouchdbDatabaseClass;
 
 GType            couchdb_database_get_type (void);
 CouchdbDatabase *couchdb_database_new (CouchdbSession *session, const char *dbname);
 
+GSList          *couchdb_database_list_documents (CouchdbDatabase *database, GError **error);
+GSList          *couchdb_database_get_all_documents (CouchdbDatabase *database, GError **error);
+void             couchdb_database_free_document_list (GSList *doclist);
+
+CouchdbDocument *couchdb_database_get_document (CouchdbDatabase *database,
+						const char *docid,
+						GError **error);
+gboolean         couchdb_database_put_document (CouchdbDatabase *database,
+						CouchdbDocument *document,
+						GError **error);
+gboolean         couchdb_database_delete_document (CouchdbDatabase *database, CouchdbDocument *document, GError **error);
+
+void             couchdb_database_listen_for_changes (CouchdbDatabase *database);
+
 CouchdbSession  *couchdb_database_get_session (CouchdbDatabase *database);
-void             couchdb_database_set_session (CouchdbDatabase *database, CouchdbSession *session);
+const char      *couchdb_database_get_name (CouchdbDatabase *database);
 
 G_END_DECLS
 
diff --git a/couchdb-glib/couchdb-document.c b/couchdb-glib/couchdb-document.c
index 75a29d8..2bdadf2 100644
--- a/couchdb-glib/couchdb-document.c
+++ b/couchdb-glib/couchdb-document.c
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * Copyright (C) 2009 Canonical Services Ltd (www.canonical.com)
+ * Copyright (C) 2009-2010 Canonical Services Ltd (www.canonical.com)
  *               2009 Mikkel Kamstrup Erlandsen
  *
  * Authors: Rodrigo Moya <rodrigo moya canonical com>
@@ -28,12 +28,8 @@
 #include "couchdb-document.h"
 #include "utils.h"
 
-struct _CouchdbDocument {
-	GObject		parent;
-
-	CouchdbSession  *session;
-	char		*dbname;
-	JsonNode	*root_node;
+struct _CouchdbDocumentPrivate {
+	JsonObject *root_object;
 };
 
 G_DEFINE_TYPE(CouchdbDocument, couchdb_document, G_TYPE_OBJECT);
@@ -43,8 +39,8 @@ couchdb_document_finalize (GObject *object)
 {
 	CouchdbDocument *document = COUCHDB_DOCUMENT (object);
 
-	g_free (document->dbname);
-	json_node_free (document->root_node);
+	json_object_unref (document->priv->root_object);
+	g_free (document->priv);
 
 	G_OBJECT_CLASS (couchdb_document_parent_class)->finalize (object);
 }
@@ -60,214 +56,52 @@ couchdb_document_class_init (CouchdbDocumentClass *klass)
 static void
 couchdb_document_init (CouchdbDocument *document)
 {
-	document->session = NULL;
-	document->root_node = NULL;
-	document->dbname = NULL;
+	document->priv = g_new0 (CouchdbDocumentPrivate, 1);
 }
 
 /**
  * couchdb_document_new:
- * @couchdb: A #CouchdbSession object
  *
  * Create an empty #CouchdbDocument object, which can then be populated with data
- * and added to a database on the specified CouchDB instance.
+ * and added to a database.
  *
  * Return value: A newly-created #CouchdbDocument object, with no data on it.
  */
 CouchdbDocument *
-couchdb_document_new (CouchdbSession *session)
+couchdb_document_new (void)
 {
 	CouchdbDocument *document;
 
 	document = g_object_new (COUCHDB_TYPE_DOCUMENT, NULL);
-	document->session = session;
-	document->dbname = NULL;
 
-	document->root_node = json_node_new (JSON_NODE_OBJECT);
-	json_node_set_object (document->root_node, json_object_new ());
+	document->priv->root_object = json_object_new ();
 
 	return document;
 }
 
 CouchdbDocument *
-couchdb_document_new_from_json_object (CouchdbSession *session, JsonObject *json_object)
+couchdb_document_new_from_json_object (JsonObject *json_object)
 {
 	CouchdbDocument *document;
 
 	document = g_object_new (COUCHDB_TYPE_DOCUMENT, NULL);
-	document->session = session;
-	document->dbname = NULL;
-
-	document->root_node = json_node_new (JSON_NODE_OBJECT);
-	json_node_set_object (document->root_node, json_object_ref (json_object));
 
-	return document;
-}
-
-/**
- * couchdb_document_get:
- * @couchdb: A #CouchdbSession object
- * @dbname: Name of the database to retrieve the document from
- * @docid: Unique ID of the document to be retrieved
- * @error: Placeholder for error information
- *
- * Retrieve the last revision of a document from the given database.
- *
- * Return value: A #CouchdbDocument object if successful, NULL otherwise, in
- * which case, the error argument will contain information about the error.
- */
-CouchdbDocument *
-couchdb_document_get (CouchdbSession *session,
-		      const char *dbname,
-		      const char *docid,
-		      GError **error)
-{
-	char *url, *encoded_docid;
-	JsonParser *parser;
-	CouchdbDocument *document = NULL;
-
-	g_return_val_if_fail (COUCHDB_IS_SESSION (session), NULL);
-	g_return_val_if_fail (dbname != NULL, NULL);
-	g_return_val_if_fail (docid != NULL, NULL);
-
-	encoded_docid = soup_uri_encode (docid, NULL);
-	url = g_strdup_printf ("%s/%s/%s", couchdb_session_get_uri (session), dbname, encoded_docid);
-	parser = json_parser_new ();
-	if (couchdb_session_send_message (session, SOUP_METHOD_GET, url, NULL, parser, error)) {
-		document = g_object_new (COUCHDB_TYPE_DOCUMENT, NULL);
-		document->session = session;
-		document->dbname = g_strdup (dbname);
-
-		document->root_node = json_node_copy (json_parser_get_root (parser));		
-	}
-	g_object_unref (G_OBJECT (parser));
-	g_free (encoded_docid);
-	g_free (url);
+	document->priv->root_object = json_object_ref (json_object);
 
 	return document;
 }
 
-/**
- * couchdb_document_put:
- * @document: A #CouchdbDocument object
- * @dbname: Name of the database where the document will be stored
- * @error: Placeholder for error information
- *
- * Store a document on a CouchDB database.
- *
- * If it is a new document, and hence does not have a unique ID, a unique ID
- * will be generated and stored on the #CouchdbDocument object. Likewise,
- * whether the document is new or just an update to an existing one, the
- * #CouchdbDocument object passed to this function will be updated to contain
- * the latest revision of the document, as returned by CouchDB (revision that
- * can be retrieved by calling #couchdb_document_get_revision).
- *
- * Return value: TRUE if successful, FALSE otherwise, in which case the error
- * argument will contain information about the error.
- */
-gboolean
-couchdb_document_put (CouchdbDocument *document,
-		      const char *dbname,
-		      GError **error)
+void
+couchdb_document_set_from_json_object (CouchdbDocument *document, JsonObject *json_object)
 {
-	char *url, *body;
-	const char *id;
-	JsonParser *parser;
-	gboolean result = FALSE;
-	gboolean send_ok;
-
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), FALSE);
-	g_return_val_if_fail (dbname != NULL, FALSE);
-
-	id = couchdb_document_get_id (document);
-	body = couchdb_document_to_string (document);
-	parser = json_parser_new ();
-	if (id) {
-		char *encoded_docid;
-
-		encoded_docid = soup_uri_encode (id, NULL);
-		url = g_strdup_printf ("%s/%s/%s", couchdb_session_get_uri (document->session), dbname, encoded_docid);		
-		send_ok = couchdb_session_send_message (document->session, SOUP_METHOD_PUT, url, body, parser, error);
-
-		g_free (encoded_docid);
-	} else {
-		url = g_strdup_printf ("%s/%s/", couchdb_session_get_uri (document->session), dbname);
-		send_ok = couchdb_session_send_message (document->session, SOUP_METHOD_POST, url, body, parser, error);
-	}
-
-	if (send_ok) {
-		JsonObject *object;
-
-		object = json_node_get_object (json_parser_get_root (parser));
-		couchdb_document_set_id (document, json_object_get_string_member (object, "id"));
-		couchdb_document_set_revision (document, json_object_get_string_member (object, "rev"));
-
-		if (document->dbname) {
-			g_free (document->dbname);
-			document->dbname = g_strdup (dbname);
-		}
-
-		if (id)
-			g_signal_emit_by_name (document->session, "document_updated", dbname, document);
-		else
-			g_signal_emit_by_name (document->session, "document_created", dbname, document);
-
-		result = TRUE;
-	}
+	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
 
-	/* free memory */
-	g_free (url);
-	g_free (body);
-	g_object_unref (G_OBJECT (parser));
+	if (document->priv->root_object != NULL)
+		json_object_unref (document->priv->root_object);
 
-	return result;
+	document->priv->root_object = json_object_ref (json_object);
 }
 
-/**
- * couchdb_document_delete:
- * @document: A #CouchdbDocument object
- * @error: Placeholder for error information
- *
- * Delete an existing document from a CouchDB instance.
- *
- * Please take note that this operation can fail if there was an update to the
- * document and that last revision was not retrieved by the calling application.
- * This is due to the fact that, to remove a document from CouchDB, the latest
- * revision needs to be sent, so if the #CouchdbDocument object passed to this
- * function does not contain the last revision, the operation will fail. In that
- * case, retrieving the latest revision from CouchDB (with #couchdb_document_get)
- * and trying the delete operation again should fix the issue.
- *
- * Return value: TRUE if successful, FALSE otherwise, in which case the error
- * argument will contain information about the error.
- */
-gboolean
-couchdb_document_delete (CouchdbDocument *document, GError **error)
-{
-	const char *id, *revision;
-	char *url;
-	JsonParser *parser;
-	gboolean result = FALSE;
-
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), FALSE);
-
-	id = couchdb_document_get_id (document);
-	revision = couchdb_document_get_revision (document);
-	if (!id || !revision) /* we can't remove a document without an ID and/or a REVISION */
-		return FALSE;
-
-	url = g_strdup_printf ("%s/%s/%s?rev=%s", couchdb_session_get_uri (document->session), document->dbname, id, revision);
-	
-	/* We don't parse the http response, therefore the parser arg is NULL */
-	if (couchdb_session_send_message (document->session, SOUP_METHOD_DELETE, url, NULL, NULL, error)) {
-		result = TRUE;		
-		g_signal_emit_by_name (document->session, "document_deleted", document->dbname, id);
-	}
-
-	g_free (url);
-
-	return result;
-}
 
 /**
  * couchdb_document_get_id:
@@ -282,12 +116,10 @@ couchdb_document_get_id (CouchdbDocument *document)
 {
 	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
 
-	if (document->root_node &&
-	    json_node_get_node_type (document->root_node) == JSON_NODE_OBJECT) {
-		if (json_object_has_member (json_node_get_object (document->root_node),
-					    "_id"))
+	if (document->priv->root_object != NULL) {
+		if (json_object_has_member (document->priv->root_object, "_id"))
 			return json_object_get_string_member (
-				json_node_get_object (document->root_node),
+				document->priv->root_object,
 				"_id");
 	}
 
@@ -313,9 +145,7 @@ couchdb_document_set_id (CouchdbDocument *document, const char *id)
 	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
 	g_return_if_fail (id != NULL);
 
-	json_object_set_string_member (json_node_get_object (document->root_node),
-				       "_id",
-				       id);
+	json_object_set_string_member (document->priv->root_object, "_id", id);
 }
 
 /**
@@ -337,10 +167,9 @@ couchdb_document_get_revision (CouchdbDocument *document)
 {
 	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
 
-	if (document->root_node &&
-	    json_node_get_node_type (document->root_node) == JSON_NODE_OBJECT) {
+	if (document->priv->root_object != NULL) {
 		return json_object_get_string_member (
-			json_node_get_object (document->root_node),
+			document->priv->root_object,
 			"_rev");
 	}
 
@@ -362,9 +191,7 @@ couchdb_document_set_revision (CouchdbDocument *document, const char *revision)
 	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
 	g_return_if_fail (revision != NULL);
 
-	json_object_set_string_member (json_node_get_object (document->root_node),
-				       "_rev",
-				       revision);
+	json_object_set_string_member (document->priv->root_object, "_rev", revision);
 }
 
 /**
@@ -384,7 +211,7 @@ couchdb_document_has_field (CouchdbDocument *document, const char *field)
 	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), FALSE);
 	g_return_val_if_fail (field != NULL, FALSE);
 
-	return json_object_has_member (json_node_get_object (document->root_node), field);
+	return json_object_has_member (document->priv->root_object, field);
 }
 
 /**
@@ -400,7 +227,7 @@ couchdb_document_remove_field (CouchdbDocument *document, const char *field)
 	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
 	g_return_if_fail (field != NULL);
 
-	json_object_remove_member (json_node_get_object (document->root_node), field);
+	json_object_remove_member (document->priv->root_object, field);
 }
 
 /**
@@ -418,12 +245,12 @@ couchdb_document_get_array_field (CouchdbDocument *document, const char *field)
 	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
 	g_return_val_if_fail (field != NULL, NULL);
 
-	if (!json_object_has_member (json_node_get_object (document->root_node), field))
+	if (!json_object_has_member (document->priv->root_object, field))
 		return NULL;
 
 	return couchdb_array_field_new_from_json_array (
-		json_array_ref (json_object_get_array_member (json_node_get_object (document->root_node),
-							       field)));
+		json_array_ref (json_object_get_array_member (document->priv->root_object,
+							      field)));
 }
 
 /**
@@ -441,7 +268,7 @@ couchdb_document_set_array_field (CouchdbDocument *document, const char *field,
 	g_return_if_fail (field != NULL);
 	g_return_if_fail (value != NULL);
 
-	json_object_set_array_member (json_node_get_object (document->root_node),
+	json_object_set_array_member (document->priv->root_object,
 				      field,
 				      json_array_ref (couchdb_array_field_get_json_array (value)));
 }
@@ -461,10 +288,10 @@ couchdb_document_get_boolean_field (CouchdbDocument *document, const char *field
 	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), FALSE);
 	g_return_val_if_fail (field != NULL, FALSE);
 
-	if (!json_object_has_member (json_node_get_object (document->root_node), field))
+	if (!json_object_has_member (document->priv->root_object, field))
 		return FALSE;
 
-	return json_object_get_boolean_member (json_node_get_object (document->root_node),
+	return json_object_get_boolean_member (document->priv->root_object,
 					       field);
 }
 
@@ -482,9 +309,7 @@ couchdb_document_set_boolean_field (CouchdbDocument *document, const char *field
 	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
 	g_return_if_fail (field != NULL);
 
-	json_object_set_boolean_member (json_node_get_object (document->root_node),
-					field,
-					value);
+	json_object_set_boolean_member (document->priv->root_object, field, value);
 }
 
 /**
@@ -502,10 +327,10 @@ couchdb_document_get_int_field (CouchdbDocument *document, const char *field)
 	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), -1);
 	g_return_val_if_fail (field != NULL, -1);
 
-	if (!json_object_has_member (json_node_get_object (document->root_node), field))
+	if (!json_object_has_member (document->priv->root_object, field))
 		return 0;
 
-	return json_object_get_int_member (json_node_get_object (document->root_node),
+	return json_object_get_int_member (document->priv->root_object,
 					   field);
 }
 
@@ -523,9 +348,7 @@ couchdb_document_set_int_field (CouchdbDocument *document, const char *field, gi
 	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
 	g_return_if_fail (field != NULL);
 
-	json_object_set_int_member (json_node_get_object (document->root_node),
-				    field,
-				    value);
+	json_object_set_int_member (document->priv->root_object, field, value);
 }
 
 /**
@@ -543,10 +366,10 @@ couchdb_document_get_double_field (CouchdbDocument *document, const char *field)
 	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), -1);
 	g_return_val_if_fail (field != NULL, -1);
 
-	if (!json_object_has_member (json_node_get_object (document->root_node), field))
+	if (!json_object_has_member (document->priv->root_object, field))
 		return 0.0;
-	return json_object_get_double_member (json_node_get_object (document->root_node),
-					      field);
+
+	return json_object_get_double_member (document->priv->root_object, field);
 }
 
 /**
@@ -563,9 +386,7 @@ couchdb_document_set_double_field (CouchdbDocument *document, const char *field,
 	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
 	g_return_if_fail (field != NULL);
 
-	json_object_set_double_member (json_node_get_object (document->root_node),
-				       field,
-				       value);
+	json_object_set_double_member (document->priv->root_object, field, value);
 }
 
 /**
@@ -583,11 +404,10 @@ couchdb_document_get_string_field (CouchdbDocument *document, const char *field)
 	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
 	g_return_val_if_fail (field != NULL, NULL);
 
-	if (!json_object_has_member (json_node_get_object (document->root_node), field))
+	if (!json_object_has_member (document->priv->root_object, field))
 		return NULL;
 
-	return json_object_get_string_member (json_node_get_object (document->root_node),
-					      field);
+	return json_object_get_string_member (document->priv->root_object, field);
 }
 
 /**
@@ -605,7 +425,7 @@ couchdb_document_set_string_field (CouchdbDocument *document, const char *field,
 	g_return_if_fail (field != NULL);
 
 	if (value) {
-		json_object_set_string_member (json_node_get_object (document->root_node),
+		json_object_set_string_member (document->priv->root_object,
 					       field,
 					       value);
 	} else {
@@ -629,11 +449,11 @@ couchdb_document_get_struct_field (CouchdbDocument *document, const char *field)
 	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
 	g_return_val_if_fail (field != NULL, NULL);
 
-	if (!json_object_has_member (json_node_get_object (document->root_node), field))
+	if (!json_object_has_member (document->priv->root_object, field))
 		return NULL;
 
 	return couchdb_struct_field_new_from_json_object (
-		json_object_ref (json_object_get_object_member (json_node_get_object (document->root_node),
+		json_object_ref (json_object_get_object_member (document->priv->root_object,
 								field)));
 }
 
@@ -652,7 +472,7 @@ couchdb_document_set_struct_field (CouchdbDocument *document, const char *field,
 	g_return_if_fail (field != NULL);
 	g_return_if_fail (value != NULL);
 
-	json_object_set_object_member (json_node_get_object (document->root_node),
+	json_object_set_object_member (document->priv->root_object,
 				       field,
 				       json_object_ref (couchdb_struct_field_get_json_object (value)));
 }
@@ -670,16 +490,20 @@ couchdb_document_to_string (CouchdbDocument *document)
 {
 	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
 
-	if (document->root_node) {
+	if (document->priv->root_object) {
 		JsonGenerator *generator;
 		char *str;
 		gsize size;
+		JsonNode *root_node;
 
 		generator = json_generator_new ();
-		json_generator_set_root (generator, document->root_node);
+		root_node = json_node_new (JSON_NODE_OBJECT);
+		json_node_set_object (root_node, json_object_ref (document->priv->root_object));
+		json_generator_set_root (generator, root_node);
 
 		str = json_generator_to_data (generator, &size);
 		g_object_unref (G_OBJECT (generator));
+		json_node_free (root_node);
 
 		return str;
 	}
@@ -692,5 +516,5 @@ couchdb_document_get_json_object (CouchdbDocument *document)
 {
 	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
 	
-	return json_node_get_object (document->root_node);
+	return document->priv->root_object;
 }
diff --git a/couchdb-glib/couchdb-document.h b/couchdb-glib/couchdb-document.h
index 1479973..a7ca5d0 100644
--- a/couchdb-glib/couchdb-document.h
+++ b/couchdb-glib/couchdb-document.h
@@ -40,30 +40,29 @@ G_BEGIN_DECLS
 #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 _CouchdbDocumentPrivate CouchdbDocumentPrivate;
+
+typedef struct {
+	GObject parent;
+	CouchdbDocumentPrivate *priv;
+} CouchdbDocument;
+
 typedef struct {
 	GObjectClass parent_class;
 } CouchdbDocumentClass;
 
 
-GType            couchdb_document_get_type (void);
+GType               couchdb_document_get_type (void);
 
-CouchdbDocument *couchdb_document_new (CouchdbSession  *session);
-CouchdbDocument *couchdb_document_get (CouchdbSession  *session,
-				       const char      *dbname,
-				       const char      *docid,
-				       GError          **error);
-gboolean         couchdb_document_put (CouchdbDocument *document,
-				       const char      *dbname,
-				       GError **error);
-gboolean         couchdb_document_delete (CouchdbDocument *document, GError **error);
+CouchdbDocument    *couchdb_document_new (void);
 
-const char      *couchdb_document_get_id (CouchdbDocument *document);
-void             couchdb_document_set_id (CouchdbDocument *document, const char *id);
-const char      *couchdb_document_get_revision (CouchdbDocument *document);
-void             couchdb_document_set_revision (CouchdbDocument *document, const char *revision);
+const char         *couchdb_document_get_id (CouchdbDocument *document);
+void                couchdb_document_set_id (CouchdbDocument *document, const char *id);
+const char         *couchdb_document_get_revision (CouchdbDocument *document);
+void                couchdb_document_set_revision (CouchdbDocument *document, const char *revision);
 
-gboolean         couchdb_document_has_field (CouchdbDocument *document, const char *field);
-void             couchdb_document_remove_field (CouchdbDocument *document, const char *field);
+gboolean            couchdb_document_has_field (CouchdbDocument *document, const char *field);
+void                couchdb_document_remove_field (CouchdbDocument *document, const char *field);
 
 CouchdbArrayField  *couchdb_document_get_array_field (CouchdbDocument *document, const char *field);
 void                couchdb_document_set_array_field (CouchdbDocument *document, const char *field, CouchdbArrayField *value);
diff --git a/couchdb-glib/couchdb-glib.h b/couchdb-glib/couchdb-glib.h
index 20674a8..fd214cc 100644
--- a/couchdb-glib/couchdb-glib.h
+++ b/couchdb-glib/couchdb-glib.h
@@ -28,6 +28,7 @@
 #include <couchdb-array-field.h>
 #include <couchdb-credentials.h>
 #include <couchdb-database-info.h>
+#include <couchdb-database.h>
 #include <couchdb-document.h>
 #include <couchdb-document-info.h>
 #include <couchdb-session.h>
diff --git a/couchdb-glib/couchdb-session.c b/couchdb-glib/couchdb-session.c
index d0a580a..6f8d212 100644
--- a/couchdb-glib/couchdb-session.c
+++ b/couchdb-glib/couchdb-session.c
@@ -25,10 +25,10 @@
 #include <libsoup/soup-gnome.h>
 #include <libsoup/soup-message.h>
 #include "couchdb-session.h"
+#include "couchdb-database.h"
 #include "couchdb-document.h"
 #include "couchdb-document-info.h"
 #include "couchdb-marshal.h"
-#include "dbwatch.h"
 #include "utils.h"
 #include <string.h>
 #ifdef HAVE_OAUTH
@@ -42,7 +42,6 @@
 struct _CouchdbSessionPrivate {
 	char *uri;
 	SoupSession *http_session;
-	GHashTable *db_watchlist;
 	CouchdbCredentials *credentials;
 };
 
@@ -52,9 +51,6 @@ enum {
 	AUTHENTICATION_FAILED,
 	DATABASE_CREATED,
 	DATABASE_DELETED,
-	DOCUMENT_CREATED,
-	DOCUMENT_UPDATED,
-	DOCUMENT_DELETED,
 	LAST_SIGNAL
 };
 static guint couchdb_session_signals[LAST_SIGNAL];
@@ -86,8 +82,6 @@ couchdb_session_finalize (GObject *object)
 {
 	CouchdbSession *session = COUCHDB_SESSION (object);
 
-	g_hash_table_destroy (session->priv->db_watchlist);
-
 	g_free (session->priv->uri);
 	g_object_unref (session->priv->http_session);
 
@@ -183,36 +177,6 @@ couchdb_session_class_init (CouchdbSessionClass *klass)
 			      g_cclosure_marshal_VOID__STRING,
 			      G_TYPE_NONE, 1,
 			      G_TYPE_STRING);
-	couchdb_session_signals[DOCUMENT_CREATED] =
-		g_signal_new ("document_created",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (CouchdbSessionClass, document_created),
-			      NULL, NULL,
-			      _couchdb_marshal_VOID__STRING_OBJECT,
-			      G_TYPE_NONE, 2,
-			      G_TYPE_STRING,
-			      G_TYPE_OBJECT);
-	couchdb_session_signals[DOCUMENT_UPDATED] =
-		g_signal_new ("document_updated",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (CouchdbSessionClass, document_updated),
-			      NULL, NULL,
-			      _couchdb_marshal_VOID__STRING_OBJECT,
-			      G_TYPE_NONE, 2,
-			      G_TYPE_STRING,
-			      G_TYPE_OBJECT);
-	couchdb_session_signals[DOCUMENT_DELETED] =
-		g_signal_new ("document_deleted",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (CouchdbSessionClass, document_deleted),
-			      NULL, NULL,
-			      _couchdb_marshal_VOID__STRING_STRING,
-			      G_TYPE_NONE, 2,
-			      G_TYPE_STRING,
-			      G_TYPE_STRING);
 }
 
 static void
@@ -220,9 +184,6 @@ couchdb_session_init (CouchdbSession *session)
 {
 	session->priv = g_new0 (CouchdbSessionPrivate, 1);
 
-	session->priv->db_watchlist = g_hash_table_new_full (g_str_hash, g_str_equal,
-							     (GDestroyNotify) g_free,
-							     (GDestroyNotify) dbwatch_free);
 	if (session->priv->uri == NULL)
 		session->priv->uri = g_strdup("http://127.0.0.1:5984";);
 
@@ -465,10 +426,6 @@ couchdb_session_delete_database (CouchdbSession *session, const char *dbname, GE
 	g_free (url);
 
 	if (result) {
-		/* If we're listening for changes on this database, stop doing so */
-		if (g_hash_table_lookup (session->priv->db_watchlist, dbname))
-			g_hash_table_remove (session->priv->db_watchlist, dbname);
-
 		g_signal_emit_by_name (session, "database_deleted", dbname);
 	}
 
@@ -529,208 +486,6 @@ couchdb_session_free_database_list (GSList *dblist)
 	g_slist_free (dblist);
 }
 
-static JsonArray *
-call_all_docs_uri (CouchdbSession *session, const char *url, JsonParser *parser, GError **error)
-{
-	JsonArray *rows = NULL;
-
-	if (couchdb_session_send_message (session, SOUP_METHOD_GET, url, NULL, parser, error)) {
-		JsonNode *root_node;
-
-		root_node = json_parser_get_root (parser);
-		if (json_node_get_node_type (root_node) == JSON_NODE_OBJECT) {
-			rows = json_object_get_array_member (
-				json_node_get_object (root_node), "rows");
-		}
-	}
-
-	return rows;
-}
-
-/**
- * couchdb_session_list_documents:
- * @session: A #CouchdbSession object
- * @dbname: Name of the databases to retrieve documents from
- * @error: Placeholder for error information
- *
- * Retrieve the list of all documents from a database on a running CouchDB instance.
- * For each document, a #CouchdbDocumentInfo object is returned on the list, which
- * can then be used for retrieving specific information for each document.
- *
- * Return Value: a list of #CouchdbDocumentInfo objects, or NULL if there are none
- * or there was an error (in which case the error argument will contain information
- * about the error). Once no longer needed, the list should be freed by calling
- * #couchdb_session_free_document_list.
- */
-GSList *
-couchdb_session_list_documents (CouchdbSession *session, const char *dbname, GError **error)
-{
-	char *url;
-	JsonParser *parser;
-	JsonArray *rows;
-	GSList *doclist = NULL;
-
-	g_return_val_if_fail (COUCHDB_IS_SESSION (session), NULL);
-	g_return_val_if_fail (dbname != NULL, NULL);
-
-	url = g_strdup_printf ("%s/%s/_all_docs", session->priv->uri, dbname);
-	parser = json_parser_new ();
-
-	rows = call_all_docs_uri (session, url, parser, error);
-	if (rows != NULL) {
-		gint i;
-		for (i = 0; i < json_array_get_length (rows); i++) {
-			JsonObject *doc;
-			CouchdbDocumentInfo *doc_info;
-
-			doc = json_array_get_object_element (rows, i);
-			if (!doc)
-				continue;
-
-			doc_info = couchdb_document_info_new (
-				json_object_get_string_member (doc, "id"),
-				json_object_get_string_member (
-					json_object_get_object_member (doc, "value"),
-					"rev"));
-			doclist = g_slist_append (doclist, doc_info);
-		}
-	}
-
-	g_object_unref (G_OBJECT (parser));
-	g_free (url);
-
-	return doclist;
-}
-
-/**
- * couchdb_session_get_all_documents:
- * @session: A #CouchdbSession object
- * @dbname: Name of the databases to retrieve documents from
- * @error: Placeholder for error information
- *
- * Retrieve all documents from a database on a running CouchDB instance. For
- * each document found in the database, a #CouchdbDocument object is returned
- * on the list, which represents the document's contents as found on the
- * underlying database.
- *
- * Return value: a list of #CouchdbDocument objects, or NULL if there are none
- * or there was an error (in which case the error argument will contain information
- * about the error). Once no longer needed, the list should be freed by calling
- * #couchdb_session_free_document_list.
- */
-GSList *
-couchdb_session_get_all_documents (CouchdbSession *session, const char *dbname, GError **error)
-{
-	char *url;
-	JsonParser *parser;
-	JsonArray *rows;
-	GSList *doclist = NULL;
-
-	g_return_val_if_fail (COUCHDB_IS_SESSION (session), NULL);
-	g_return_val_if_fail (dbname != NULL, NULL);
-
-	url = g_strdup_printf ("%s/%s/_all_docs?include_docs=true", session->priv->uri, dbname);
-	parser = json_parser_new ();
-
-	rows = call_all_docs_uri (session, url, parser, error);
-	if (rows != NULL) {
-		gint i;
-		for (i = 0; i < json_array_get_length (rows); i++) {
-			JsonObject *obj;
-			CouchdbDocument *document;
-
-			obj = json_array_get_object_element (rows, i);
-			if (!obj)
-				continue;
-
-			document = couchdb_document_new_from_json_object (
-				session,
-				json_object_get_object_member (obj, "doc"));
-			if (document != NULL)
-				doclist = g_slist_append (doclist, document);
-		}
-	}
-
-	g_object_unref (G_OBJECT (parser));
-	g_free (url);
-
-	return doclist;
-}
-
-/**
- * couchdb_session_free_document_list:
- * @doclist: A list of #CouchdbDocumentInfo objects, as returned by
- * #couchdb_session_list_documents
- *
- * Free the list of documents returned by #couchdb_session_list_documents.
- */
-void
-couchdb_session_free_document_list (GSList *doclist)
-{
-	g_return_if_fail (doclist != NULL);
-
-	while (doclist != NULL) {
-		gpointer data = doclist->data;
-
-		doclist = g_slist_remove (doclist, data);
-
-		if (COUCHDB_IS_DOCUMENT (data))
-			g_object_unref (G_OBJECT (data));
-		else
-			couchdb_document_info_unref (data);
-	}
-}
-
-/**
- * couchdb_session_listen_for_changes:
- * @session: A #CouchdbSession object
- * @dbname: Name of the database to poll changes for
- *
- * Setup a listener to get information about changes done to a specific database. Please
- * note that changes done in the application using couchdb-glib will be notified
- * without the need of calling this function. But if the application wants to receive
- * notifications of changes done externally (by another application, or by any other
- * means, like replication with a remote database), it needs to call this function.
- *
- * For each change, one of the signals on the #CouchdbSession object will be emitted,
- * so applications just have to connect to those signals before calling this function.
- */
-void
-couchdb_session_listen_for_changes (CouchdbSession *session, const char *dbname)
-{
-	DBWatch *watch;
-	CouchdbDatabaseInfo *db_info;
-	GError *error = NULL;
-
-	g_return_if_fail (COUCHDB_IS_SESSION (session));
-	g_return_if_fail (dbname != NULL);
-
-	watch = g_hash_table_lookup (session->priv->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_session_get_database_info (session, 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 (session,
-			     dbname,
-			     couchdb_database_info_get_update_sequence (db_info));
-	if (watch)
-		g_hash_table_insert (session->priv->db_watchlist, g_strdup (dbname), watch);
-
-	/* Free memory */
-	couchdb_database_info_unref (db_info);
-}
-
 /**
  * couchdb_session_enable_authentication:
  * @session: A #CouchdbSession object
@@ -1046,7 +801,7 @@ couchdb_session_replicate (CouchdbSession *session,
 	g_return_val_if_fail (target != NULL, FALSE);
 
 	/* Build the input document */
-	input = couchdb_document_new (session);
+	input = couchdb_document_new ();
 	couchdb_document_set_string_field (input, "source", source);
 	couchdb_document_set_string_field (input, "target", target);
 	if (continous)
diff --git a/couchdb-glib/couchdb-session.h b/couchdb-glib/couchdb-session.h
index 4ce00b6..c94bcef 100644
--- a/couchdb-glib/couchdb-session.h
+++ b/couchdb-glib/couchdb-session.h
@@ -57,10 +57,6 @@ typedef struct {
 	void (* database_created) (CouchdbSession *session, const char *dbname);
 	void (* database_deleted) (CouchdbSession *session, const char *dbname);
 
-	void (* document_created) (CouchdbSession *session, const char *dbname, CouchdbDocument *document);
-	void (* document_updated) (CouchdbSession *session, const char *dbname, CouchdbDocument *document);
-	void (* document_deleted) (CouchdbSession *session, const char *dbname, const char *docid);
-
 	/* Virtual methods */
 	CouchdbDatabase * (* get_database) (CouchdbSession *session, const char *dbname);
 } CouchdbSessionClass;
@@ -80,16 +76,10 @@ gboolean             couchdb_session_create_database (CouchdbSession *session, c
 gboolean             couchdb_session_delete_database (CouchdbSession *session, const char *dbname, GError **error);
 gboolean             couchdb_session_compact_database (CouchdbSession *session, const char *dbname, GError **error);
 
-void                 couchdb_session_listen_for_changes (CouchdbSession *session, const char *dbname);
-
 void                 couchdb_session_enable_authentication (CouchdbSession *session, CouchdbCredentials *credentials);
 void                 couchdb_session_disable_authentication (CouchdbSession *session);
 gboolean             couchdb_session_is_authentication_enabled (CouchdbSession *session);
 
-GSList              *couchdb_session_list_documents (CouchdbSession *session, const char *dbname, GError **error);
-GSList              *couchdb_session_get_all_documents (CouchdbSession *session, const char *dbname, GError **error);
-void                 couchdb_session_free_document_list (GSList *doclist);
-
 gboolean             couchdb_session_replicate (CouchdbSession *session,
 						const gchar *source,
 						const gchar *target,
diff --git a/couchdb-glib/couchdb-types.h b/couchdb-glib/couchdb-types.h
index 546601a..9065927 100644
--- a/couchdb-glib/couchdb-types.h
+++ b/couchdb-glib/couchdb-types.h
@@ -29,7 +29,6 @@
 G_BEGIN_DECLS
 
 typedef struct _CouchdbArrayField CouchdbArrayField;
-typedef struct _CouchdbDocument CouchdbDocument;
 typedef struct _CouchdbDatabaseInfo CouchdbDatabaseInfo;
 typedef struct _CouchdbDocumentInfo CouchdbDocumentInfo;
 typedef struct _CouchdbStructField CouchdbStructField;
diff --git a/couchdb-glib/dbwatch.c b/couchdb-glib/dbwatch.c
index 3d3d4ae..df92e36 100644
--- a/couchdb-glib/dbwatch.c
+++ b/couchdb-glib/dbwatch.c
@@ -45,18 +45,16 @@ process_change (DBWatch *watch, JsonNode *node)
 	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);
+	document = couchdb_database_get_document (watch->database, 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);
+				g_signal_emit_by_name (watch->database, "document_created", document);
 			else
-				g_signal_emit_by_name (watch->couchdb, "document_updated",
-						       watch->dbname, document);
+				g_signal_emit_by_name (watch->database, "document_updated", document);
 		}
 
 		g_object_unref (G_OBJECT (document));
@@ -66,7 +64,7 @@ process_change (DBWatch *watch, JsonNode *node)
 			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);
+			g_signal_emit_by_name (watch->database, "document_deleted", id);
 		}
 	}
 }
@@ -80,11 +78,11 @@ watch_timeout_cb (gpointer user_data)
 	DBWatch *watch = (DBWatch *) user_data;
 
 	url = g_strdup_printf ("%s/%s/_changes?since=%d",
-			       couchdb_session_get_uri (watch->couchdb),
-			       watch->dbname,
+			       couchdb_session_get_uri (couchdb_database_get_session (watch->database)),
+			       couchdb_database_get_name (watch->database),
 			       watch->last_update_seq);
 	parser = json_parser_new ();
-	if (couchdb_session_send_message (watch->couchdb, SOUP_METHOD_GET, url, NULL, parser, &error)) {
+	if (couchdb_session_send_message (couchdb_database_get_session (watch->database), SOUP_METHOD_GET, url, NULL, parser, &error)) {
 		JsonNode *root_node;
 
 		root_node = json_parser_get_root (parser);
@@ -115,18 +113,18 @@ watch_timeout_cb (gpointer user_data)
 }
 
 DBWatch *
-dbwatch_new (CouchdbSession *couchdb, const gchar *dbname, gint update_seq)
+dbwatch_new (CouchdbDatabase *database, gint update_seq)
 {
 	DBWatch *watch;
 	guint timeout;
 
 	watch = g_new0 (DBWatch, 1);
-	watch->couchdb = couchdb;
-	watch->dbname = g_strdup (dbname);
+	watch->database = database;
 	watch->last_update_seq = update_seq;
 
 	/* Set timeout to check for changes every 5 minutes*/
-	if (g_str_has_prefix (couchdb_session_get_uri (watch->couchdb), "http://127.0.0.1";))
+	if (g_str_has_prefix (couchdb_session_get_uri (couchdb_database_get_session (watch->database)),
+			      "http://127.0.0.1";))
 		timeout = LOCAL_TIMEOUT_SECONDS;
 	else
 		timeout = REMOTE_TIMEOUT_SECONDS;
@@ -139,7 +137,6 @@ dbwatch_new (CouchdbSession *couchdb, const gchar *dbname, gint update_seq)
 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
index ae6f26c..d86c0b7 100644
--- a/couchdb-glib/dbwatch.h
+++ b/couchdb-glib/dbwatch.h
@@ -23,17 +23,16 @@
 #define __DBWATCH_H__
 
 #include <glib.h>
-#include "couchdb-session.h"
+#include "couchdb-database.h"
 #include "utils.h"
 
 typedef struct {
-	CouchdbSession *couchdb;
-	gchar *dbname;
+	CouchdbDatabase *database;
 	gint last_update_seq;
 	guint timeout_id;
 } DBWatch;
 
-DBWatch *dbwatch_new (CouchdbSession *couchdb, const gchar *dbname, gint update_seq);
+DBWatch *dbwatch_new (CouchdbDatabase *database, gint update_seq);
 void     dbwatch_free (DBWatch *watch);
 
 #endif /* __DBWATCH_H__ */
diff --git a/couchdb-glib/utils.h b/couchdb-glib/utils.h
index 6d0b1fd..4ecf494 100644
--- a/couchdb-glib/utils.h
+++ b/couchdb-glib/utils.h
@@ -25,6 +25,7 @@
 #include <glib.h>
 #include <json-glib/json-glib.h>
 #include "config.h"
+#include "couchdb-document.h"
 #include "couchdb-session.h"
 
 #ifndef DEBUG_MESSAGES
@@ -45,7 +46,7 @@ gboolean            couchdb_session_send_message (CouchdbSession *session,
 						  JsonParser *output,
 						  GError **error);
 
-CouchdbDocument    *couchdb_document_new_from_json_object (CouchdbSession *session, JsonObject *json_object);
+CouchdbDocument    *couchdb_document_new_from_json_object (JsonObject *json_object);
 JsonObject*	    couchdb_document_get_json_object	(CouchdbDocument *document);
 
 CouchdbArrayField  *couchdb_array_field_new_from_json_array (JsonArray *json_array);
diff --git a/desktopcouch-glib/desktopcouch-document-contact.c b/desktopcouch-glib/desktopcouch-document-contact.c
index ea574b9..f31d346 100644
--- a/desktopcouch-glib/desktopcouch-document-contact.c
+++ b/desktopcouch-glib/desktopcouch-document-contact.c
@@ -22,316 +22,306 @@
 #include "desktopcouch-document-contact.h"
 #include "utils.h"
 
-CouchdbDocument *
-desktopcouch_document_contact_new (CouchdbSession *couchdb)
-{
-	CouchdbDocument *document;
-
-	g_return_val_if_fail (COUCHDB_IS_SESSION (couchdb), NULL);
+G_DEFINE_TYPE(DesktopcouchDocumentContact, desktopcouch_document_contact, DESKTOPCOUCH_TYPE_DOCUMENT)
 
-	document = couchdb_document_new (couchdb);
-	if (document)
-		desktopcouch_document_set_record_type (document, DESKTOPCOUCH_RECORD_TYPE_CONTACT);
-
-	return document;
+static void
+desktopcouch_document_contact_class_init (DesktopcouchDocumentContactClass *klass)
+{
 }
 
-gboolean
-desktopcouch_document_is_contact (CouchdbDocument *document)
+static void
+desktopcouch_document_contact_init (DesktopcouchDocumentContact *document)
 {
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), FALSE);
-
-	return !g_ascii_strcasecmp (desktopcouch_document_get_record_type (document),
-				    DESKTOPCOUCH_RECORD_TYPE_CONTACT);
+	desktopcouch_document_set_record_type (DESKTOPCOUCH_DOCUMENT (document), DESKTOPCOUCH_RECORD_TYPE_CONTACT);
 }
 
 const char *
-desktopcouch_document_contact_get_title (CouchdbDocument *document)
+desktopcouch_document_contact_get_title (DesktopcouchDocumentContact *document)
 {
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
-	return couchdb_document_get_string_field (document, "title");
+	return couchdb_document_get_string_field (COUCHDB_DOCUMENT (document), "title");
 }
 
 void
-desktopcouch_document_contact_set_title (CouchdbDocument *document, const char *title)
+desktopcouch_document_contact_set_title (DesktopcouchDocumentContact *document, const char *title)
 {
-      	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
-	g_return_if_fail (desktopcouch_document_is_contact (document));
+      	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
+	g_return_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)));
 	g_return_if_fail (title != NULL);
 
-	couchdb_document_set_string_field (document, "title", title);
+	couchdb_document_set_string_field (COUCHDB_DOCUMENT (document), "title", title);
 }
 
 const char *
-desktopcouch_document_contact_get_first_name (CouchdbDocument *document)
+desktopcouch_document_contact_get_first_name (DesktopcouchDocumentContact *document)
 {
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
-	return couchdb_document_get_string_field (document, "first_name");
+	return couchdb_document_get_string_field (COUCHDB_DOCUMENT (document), "first_name");
 }
 
 void
-desktopcouch_document_contact_set_first_name (CouchdbDocument *document, const char *first_name)
+desktopcouch_document_contact_set_first_name (DesktopcouchDocumentContact *document, const char *first_name)
 {
-	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
-	g_return_if_fail (desktopcouch_document_is_contact (document));
+	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
+	g_return_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)));
 	g_return_if_fail (first_name != NULL);
 
-	couchdb_document_set_string_field (document, "first_name", first_name);
+	couchdb_document_set_string_field (COUCHDB_DOCUMENT (document), "first_name", first_name);
 }
 
 const char *
-desktopcouch_document_contact_get_middle_name (CouchdbDocument *document)
+desktopcouch_document_contact_get_middle_name (DesktopcouchDocumentContact *document)
 {
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
-	return couchdb_document_get_string_field (document, "middle_name");
+	return couchdb_document_get_string_field (COUCHDB_DOCUMENT (document), "middle_name");
 }
 
 void
-desktopcouch_document_contact_set_middle_name (CouchdbDocument *document, const char *middle_name)
+desktopcouch_document_contact_set_middle_name (DesktopcouchDocumentContact *document, const char *middle_name)
 {
-	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
-	g_return_if_fail (desktopcouch_document_is_contact (document));
+	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
+	g_return_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)));
 	g_return_if_fail (middle_name != NULL);
 
-	couchdb_document_set_string_field (document, "middle_name", middle_name);
+	couchdb_document_set_string_field (COUCHDB_DOCUMENT (document), "middle_name", middle_name);
 }
 
 const char *
-desktopcouch_document_contact_get_last_name (CouchdbDocument *document)
+desktopcouch_document_contact_get_last_name (DesktopcouchDocumentContact *document)
 {
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
-	return couchdb_document_get_string_field (document, "last_name");
+	return couchdb_document_get_string_field (COUCHDB_DOCUMENT (document), "last_name");
 }
 
 void
-desktopcouch_document_contact_set_last_name (CouchdbDocument *document, const char *last_name)
+desktopcouch_document_contact_set_last_name (DesktopcouchDocumentContact *document, const char *last_name)
 {
-      	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
-	g_return_if_fail (desktopcouch_document_is_contact (document));
+      	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
+	g_return_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)));
 	g_return_if_fail (last_name != NULL);
 
-	couchdb_document_set_string_field (document, "last_name", last_name);
+	couchdb_document_set_string_field (COUCHDB_DOCUMENT (document), "last_name", last_name);
 }
 
 const char *
-desktopcouch_document_contact_get_suffix (CouchdbDocument *document)
+desktopcouch_document_contact_get_suffix (DesktopcouchDocumentContact *document)
 {
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
-	return couchdb_document_get_string_field (document, "suffix");
+	return couchdb_document_get_string_field (COUCHDB_DOCUMENT (document), "suffix");
 }
 
 void
-desktopcouch_document_contact_set_suffix (CouchdbDocument *document, const char *suffix)
+desktopcouch_document_contact_set_suffix (DesktopcouchDocumentContact *document, const char *suffix)
 {
-      	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
-	g_return_if_fail (desktopcouch_document_is_contact (document));
+      	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
+	g_return_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)));
 	g_return_if_fail (suffix != NULL);
 
-	couchdb_document_set_string_field (document, "suffix", suffix);
+	couchdb_document_set_string_field (COUCHDB_DOCUMENT (document), "suffix", suffix);
 }
 
 const char *
-desktopcouch_document_contact_get_nick_name (CouchdbDocument *document)
+desktopcouch_document_contact_get_nick_name (DesktopcouchDocumentContact *document)
 {
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
-	return couchdb_document_get_string_field (document, "nick_name");
+	return couchdb_document_get_string_field (COUCHDB_DOCUMENT (document), "nick_name");
 }
 
 void
-desktopcouch_document_contact_set_nick_name (CouchdbDocument *document, const char *nick_name)
+desktopcouch_document_contact_set_nick_name (DesktopcouchDocumentContact *document, const char *nick_name)
 {
-      	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
-	g_return_if_fail (desktopcouch_document_is_contact (document));
+      	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
+	g_return_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)));
 	g_return_if_fail (nick_name != NULL);
 
-	couchdb_document_set_string_field (document, "nick_name", nick_name);
+	couchdb_document_set_string_field (COUCHDB_DOCUMENT (document), "nick_name", nick_name);
 }
 
 const char *
-desktopcouch_document_contact_get_spouse_name (CouchdbDocument *document)
+desktopcouch_document_contact_get_spouse_name (DesktopcouchDocumentContact *document)
 {
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
-	return couchdb_document_get_string_field (document, "spouse_name");
+	return couchdb_document_get_string_field (COUCHDB_DOCUMENT (document), "spouse_name");
 }
 
 void
-desktopcouch_document_contact_set_spouse_name (CouchdbDocument *document, const char *spouse_name)
+desktopcouch_document_contact_set_spouse_name (DesktopcouchDocumentContact *document, const char *spouse_name)
 {
-      	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
-	g_return_if_fail (desktopcouch_document_is_contact (document));
+      	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
+	g_return_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)));
 	g_return_if_fail (spouse_name != NULL);
 
-	couchdb_document_set_string_field (document, "spouse_name", spouse_name);
+	couchdb_document_set_string_field (COUCHDB_DOCUMENT (document), "spouse_name", spouse_name);
 }
 
 const char *
-desktopcouch_document_contact_get_birth_date (CouchdbDocument *document)
+desktopcouch_document_contact_get_birth_date (DesktopcouchDocumentContact *document)
 {
 	JsonObject *object;
 
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
-	return couchdb_document_get_string_field (document, "birth_date");
+	return couchdb_document_get_string_field (COUCHDB_DOCUMENT (document), "birth_date");
 }
 
 void
-desktopcouch_document_contact_set_birth_date (CouchdbDocument *document, const char *birth_date)
+desktopcouch_document_contact_set_birth_date (DesktopcouchDocumentContact *document, const char *birth_date)
 {
-	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
-	g_return_if_fail (desktopcouch_document_is_contact (document));
+	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
+	g_return_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)));
 	g_return_if_fail (birth_date != NULL);
 
-	couchdb_document_set_string_field (document, "birth_date", birth_date);
+	couchdb_document_set_string_field (COUCHDB_DOCUMENT (document), "birth_date", birth_date);
 }
 
 const char *
-desktopcouch_document_contact_get_wedding_date (CouchdbDocument *document)
+desktopcouch_document_contact_get_wedding_date (DesktopcouchDocumentContact *document)
 {
 	JsonObject *object;
 
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
-	return couchdb_document_get_string_field (document, "wedding_date");
+	return couchdb_document_get_string_field (COUCHDB_DOCUMENT (document), "wedding_date");
 }
 
 void
-desktopcouch_document_contact_set_wedding_date (CouchdbDocument *document, const char *wedding_date)
+desktopcouch_document_contact_set_wedding_date (DesktopcouchDocumentContact *document, const char *wedding_date)
 {
-	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
-	g_return_if_fail (desktopcouch_document_is_contact (document));
+	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
+	g_return_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)));
 	g_return_if_fail (wedding_date != NULL);
 
-	couchdb_document_set_string_field (document, "wedding_date", wedding_date);
+	couchdb_document_set_string_field (COUCHDB_DOCUMENT (document), "wedding_date", wedding_date);
 }
 
 const char *
-desktopcouch_document_contact_get_company (CouchdbDocument *document)
+desktopcouch_document_contact_get_company (DesktopcouchDocumentContact *document)
 {
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
-	return couchdb_document_get_string_field (document, "company");
+	return couchdb_document_get_string_field (COUCHDB_DOCUMENT (document), "company");
 }
 
 void
-desktopcouch_document_contact_set_company (CouchdbDocument *document, const char *company)
+desktopcouch_document_contact_set_company (DesktopcouchDocumentContact *document, const char *company)
 {
-      	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
-	g_return_if_fail (desktopcouch_document_is_contact (document));
+      	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
+	g_return_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)));
 	g_return_if_fail (company != NULL);
 
-	couchdb_document_set_string_field (document, "company", company);
+	couchdb_document_set_string_field (COUCHDB_DOCUMENT (document), "company", company);
 }
 
 const char *
-desktopcouch_document_contact_get_department (CouchdbDocument *document)
+desktopcouch_document_contact_get_department (DesktopcouchDocumentContact *document)
 {
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
-	return couchdb_document_get_string_field (document, "department");
+	return couchdb_document_get_string_field (COUCHDB_DOCUMENT (document), "department");
 }
 
 void
-desktopcouch_document_contact_set_department (CouchdbDocument *document, const char *department)
+desktopcouch_document_contact_set_department (DesktopcouchDocumentContact *document, const char *department)
 {
-      	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
-	g_return_if_fail (desktopcouch_document_is_contact (document));
+      	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
+	g_return_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)));
 	g_return_if_fail (department != NULL);
 
-	couchdb_document_set_string_field (document, "department", department);
+	couchdb_document_set_string_field (COUCHDB_DOCUMENT (document), "department", department);
 }
 
 const char *
-desktopcouch_document_contact_get_job_title (CouchdbDocument *document)
+desktopcouch_document_contact_get_job_title (DesktopcouchDocumentContact *document)
 {
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
-	return couchdb_document_get_string_field (document, "job_title");
+	return couchdb_document_get_string_field (COUCHDB_DOCUMENT (document), "job_title");
 }
 
 void
-desktopcouch_document_contact_set_job_title (CouchdbDocument *document, const char *job_title)
+desktopcouch_document_contact_set_job_title (DesktopcouchDocumentContact *document, const char *job_title)
 {
-      	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
-	g_return_if_fail (desktopcouch_document_is_contact (document));
+      	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
+	g_return_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)));
 	g_return_if_fail (job_title != NULL);
 
-	couchdb_document_set_string_field (document, "job_title", job_title);
+	couchdb_document_set_string_field (COUCHDB_DOCUMENT (document), "job_title", job_title);
 }
 
 const char *
-desktopcouch_document_contact_get_manager_name (CouchdbDocument *document)
+desktopcouch_document_contact_get_manager_name (DesktopcouchDocumentContact *document)
 {
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
-	return couchdb_document_get_string_field (document, "manager_name");
+	return couchdb_document_get_string_field (COUCHDB_DOCUMENT (document), "manager_name");
 }
 
 void
-desktopcouch_document_contact_set_manager_name (CouchdbDocument *document, const char *manager_name)
+desktopcouch_document_contact_set_manager_name (DesktopcouchDocumentContact *document, const char *manager_name)
 {
-      	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
-	g_return_if_fail (desktopcouch_document_is_contact (document));
+      	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
+	g_return_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)));
 	g_return_if_fail (manager_name != NULL);
 
-	couchdb_document_set_string_field (document, "manager_name", manager_name);
+	couchdb_document_set_string_field (COUCHDB_DOCUMENT (document), "manager_name", manager_name);
 }
 
 const char *
-desktopcouch_document_contact_get_assistant_name (CouchdbDocument *document)
+desktopcouch_document_contact_get_assistant_name (DesktopcouchDocumentContact *document)
 {
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
-	return couchdb_document_get_string_field (document, "assistant_name");
+	return couchdb_document_get_string_field (COUCHDB_DOCUMENT (document), "assistant_name");
 }
 
 void
-desktopcouch_document_contact_set_assistant_name (CouchdbDocument *document, const char *assistant_name)
+desktopcouch_document_contact_set_assistant_name (DesktopcouchDocumentContact *document, const char *assistant_name)
 {
-      	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
-	g_return_if_fail (desktopcouch_document_is_contact (document));
+      	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
+	g_return_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)));
 	g_return_if_fail (assistant_name != NULL);
 
-	couchdb_document_set_string_field (document, "assistant_name", assistant_name);
+	couchdb_document_set_string_field (COUCHDB_DOCUMENT (document), "assistant_name", assistant_name);
 }
 
 const char *
-desktopcouch_document_contact_get_office (CouchdbDocument *document)
+desktopcouch_document_contact_get_office (DesktopcouchDocumentContact *document)
 {
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
-	return couchdb_document_get_string_field (document, "office");
+	return couchdb_document_get_string_field (COUCHDB_DOCUMENT (document), "office");
 }
 
 void
-desktopcouch_document_contact_set_office (CouchdbDocument *document, const char *office)
+desktopcouch_document_contact_set_office (DesktopcouchDocumentContact *document, const char *office)
 {
-      	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
-	g_return_if_fail (desktopcouch_document_is_contact (document));
+      	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
+	g_return_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)));
 	g_return_if_fail (office != NULL);
 
-	couchdb_document_set_string_field (document, "office", office);
+	couchdb_document_set_string_field (COUCHDB_DOCUMENT (document), "office", office);
 }
 
 static void
@@ -354,7 +344,7 @@ foreach_object_cb (JsonObject *object,
 
 /**
  * desktopcouch_document_contact_get_email_addresses:
- * @document: A #CouchdbDocument object representing a contact
+ * @document: A #DesktopcouchDocumentContact object representing a contact
  *
  * Retrieve a list of email addresses from the specified contact document.
  * Email addresses are returned in a GSList of #CouchdbStructField objects,
@@ -366,16 +356,16 @@ foreach_object_cb (JsonObject *object,
  * Return value: a #GSList of #CouchdbStructField objects.
  */
 GSList *
-desktopcouch_document_contact_get_email_addresses (CouchdbDocument *document)
+desktopcouch_document_contact_get_email_addresses (DesktopcouchDocumentContact *document)
 {
 	GSList *list = NULL;
 	JsonObject *addresses_json;
 
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
 	addresses_json = json_object_get_object_member (
-		couchdb_document_get_json_object (document), "email_addresses");;
+		couchdb_document_get_json_object (COUCHDB_DOCUMENT (document)), "email_addresses");;
 	if (addresses_json) {
 		json_object_foreach_member (addresses_json,
 					    (JsonObjectForeach) foreach_object_cb,
@@ -386,12 +376,12 @@ desktopcouch_document_contact_get_email_addresses (CouchdbDocument *document)
 }
 
 void
-desktopcouch_document_contact_set_email_addresses (CouchdbDocument *document, GSList *list)
+desktopcouch_document_contact_set_email_addresses (DesktopcouchDocumentContact *document, GSList *list)
 {
 	GSList *l;
 	JsonObject *addresses_json;
 
-	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
+	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
 
 	addresses_json = json_object_new ();
 	for (l = list; l != NULL; l = l->next) {
@@ -413,20 +403,22 @@ desktopcouch_document_contact_set_email_addresses (CouchdbDocument *document, GS
 		}
 	}
 
-	json_object_set_object_member (couchdb_document_get_json_object (document), "email_addresses", addresses_json);
+	json_object_set_object_member (couchdb_document_get_json_object (COUCHDB_DOCUMENT (document)),
+				       "email_addresses",
+				       addresses_json);
 }
 
 GSList *
-desktopcouch_document_contact_get_phone_numbers (CouchdbDocument *document)
+desktopcouch_document_contact_get_phone_numbers (DesktopcouchDocumentContact *document)
 {
 	GSList *list = NULL;
 	JsonObject *phone_numbers;
 
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
 	phone_numbers = json_object_get_object_member (
-		couchdb_document_get_json_object (document), "phone_numbers");
+		couchdb_document_get_json_object (COUCHDB_DOCUMENT (document)), "phone_numbers");
 	if (phone_numbers) {
 		json_object_foreach_member (phone_numbers,
 					    (JsonObjectForeach) foreach_object_cb,
@@ -437,12 +429,12 @@ desktopcouch_document_contact_get_phone_numbers (CouchdbDocument *document)
 }
 
 void
-desktopcouch_document_contact_set_phone_numbers (CouchdbDocument *document, GSList *list)
+desktopcouch_document_contact_set_phone_numbers (DesktopcouchDocumentContact *document, GSList *list)
 {
 	GSList *l;
 	JsonObject *phone_numbers;
 
-	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
+	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
 
 	phone_numbers = json_object_new ();
 	for (l = list; l != NULL; l = l->next) {
@@ -466,20 +458,21 @@ desktopcouch_document_contact_set_phone_numbers (CouchdbDocument *document, GSLi
 		}
 	}
 
-	json_object_set_object_member (couchdb_document_get_json_object (document), "phone_numbers", phone_numbers);
+	json_object_set_object_member (couchdb_document_get_json_object (COUCHDB_DOCUMENT (document)),
+				       "phone_numbers", phone_numbers);
 }
 
 GSList *
-desktopcouch_document_contact_get_addresses (CouchdbDocument *document)
+desktopcouch_document_contact_get_addresses (DesktopcouchDocumentContact *document)
 {
 	GSList *list = NULL;
 	JsonObject *addresses;
 
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
 	addresses = json_object_get_object_member (
-		couchdb_document_get_json_object (document), "addresses");
+		couchdb_document_get_json_object (COUCHDB_DOCUMENT (document)), "addresses");
 	if (addresses) {
 		json_object_foreach_member (addresses,
 					    (JsonObjectForeach) foreach_object_cb,
@@ -490,12 +483,12 @@ desktopcouch_document_contact_get_addresses (CouchdbDocument *document)
 }
 
 void
-desktopcouch_document_contact_set_addresses (CouchdbDocument *document, GSList *list)
+desktopcouch_document_contact_set_addresses (DesktopcouchDocumentContact *document, GSList *list)
 {
 	GSList *l;
 	JsonObject *addresses;
 
-	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
+	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
 
 	addresses = json_object_new ();
 	for (l = list; l != NULL; l = l->next) {
@@ -530,20 +523,21 @@ desktopcouch_document_contact_set_addresses (CouchdbDocument *document, GSList *
 		}
 	}
 
-	json_object_set_object_member (couchdb_document_get_json_object (document), "addresses", addresses);
+	json_object_set_object_member (couchdb_document_get_json_object (COUCHDB_DOCUMENT (document)),
+				       "addresses", addresses);
 }
 
 GSList *
-desktopcouch_document_contact_get_im_addresses (CouchdbDocument *document)
+desktopcouch_document_contact_get_im_addresses (DesktopcouchDocumentContact *document)
 {
 	GSList *list = NULL;
 	JsonObject *im_addresses;
 
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
 	im_addresses = json_object_get_object_member (
-		couchdb_document_get_json_object (document), "im_addresses");
+		couchdb_document_get_json_object (COUCHDB_DOCUMENT (document)), "im_addresses");
 	if (im_addresses != NULL) {
 		json_object_foreach_member (im_addresses,
 					    (JsonObjectForeach) foreach_object_cb,
@@ -554,12 +548,12 @@ desktopcouch_document_contact_get_im_addresses (CouchdbDocument *document)
 }
 
 void
-desktopcouch_document_contact_set_im_addresses (CouchdbDocument *document, GSList *list)
+desktopcouch_document_contact_set_im_addresses (DesktopcouchDocumentContact *document, GSList *list)
 {
 	GSList *l;
 	JsonObject *im_addresses_json;
 
-	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
+	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
 
 	im_addresses_json = json_object_new ();
 	for (l = list; l != NULL; l = l->next) {
@@ -583,20 +577,21 @@ desktopcouch_document_contact_set_im_addresses (CouchdbDocument *document, GSLis
 		}
 	}
 
-	json_object_set_object_member (couchdb_document_get_json_object (document), "im_addresses", im_addresses_json);
+	json_object_set_object_member (couchdb_document_get_json_object (COUCHDB_DOCUMENT (document)),
+				       "im_addresses", im_addresses_json);
 }
 
 GSList *
-desktopcouch_document_contact_get_urls (CouchdbDocument *document)
+desktopcouch_document_contact_get_urls (DesktopcouchDocumentContact *document)
 {
 	GSList *list = NULL;
 	JsonObject *urls;
 
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
 	urls = json_object_get_object_member (
-		couchdb_document_get_json_object (document), "urls");
+		couchdb_document_get_json_object (COUCHDB_DOCUMENT (document)), "urls");
 	if (urls) {
 		json_object_foreach_member (urls,
 					    (JsonObjectForeach) foreach_object_cb,
@@ -607,12 +602,12 @@ desktopcouch_document_contact_get_urls (CouchdbDocument *document)
 }
 
 void
-desktopcouch_document_contact_set_urls (CouchdbDocument *document, GSList *list)
+desktopcouch_document_contact_set_urls (DesktopcouchDocumentContact *document, GSList *list)
 {
 	GSList *l;
 	JsonObject *urls_json;
 
-	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
+	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
 
 	urls_json = json_object_new ();
 	for (l = list; l != NULL; l = l->next) {
@@ -634,53 +629,54 @@ desktopcouch_document_contact_set_urls (CouchdbDocument *document, GSList *list)
 		}
 	}
 
-	json_object_set_object_member (couchdb_document_get_json_object (document), "urls", urls_json);
+	json_object_set_object_member (couchdb_document_get_json_object (COUCHDB_DOCUMENT (document)),
+				       "urls", urls_json);
 }
 
 /**
  * desktopcouch_document_contact_get_categories:
- * @document: A #CouchdbDocument object
+ * @document: A #DesktopcouchDocumentContact object
  *
  * Get the list of categories (as a string) for this contact document.
  *
  * Return value: A comma separated list of categories as a string.
  */
 const char *
-desktopcouch_document_contact_get_categories (CouchdbDocument *document)
+desktopcouch_document_contact_get_categories (DesktopcouchDocumentContact *document)
 {
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
-	return couchdb_document_get_string_field (document, "categories");
+	return couchdb_document_get_string_field (COUCHDB_DOCUMENT (document), "categories");
 }
 
 void
-desktopcouch_document_contact_set_categories (CouchdbDocument *document, const char *categories)
+desktopcouch_document_contact_set_categories (DesktopcouchDocumentContact *document, const char *categories)
 {
-	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
-	g_return_if_fail (desktopcouch_document_is_contact (document));
+	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
+	g_return_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)));
 	g_return_if_fail (categories != NULL);
 
-	couchdb_document_set_string_field (document, "categories", categories);
+	couchdb_document_set_string_field (COUCHDB_DOCUMENT (document), "categories", categories);
 }
 
 const char *
-desktopcouch_document_contact_get_notes (CouchdbDocument *document)
+desktopcouch_document_contact_get_notes (DesktopcouchDocumentContact *document)
 {
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
-	g_return_val_if_fail (desktopcouch_document_is_contact (document), NULL);
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document), NULL);
+	g_return_val_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)), NULL);
 
-	return couchdb_document_get_string_field (document, "notes");
+	return couchdb_document_get_string_field (COUCHDB_DOCUMENT (document), "notes");
 }
 
 void
-desktopcouch_document_contact_set_notes (CouchdbDocument *document, const char *notes)
+desktopcouch_document_contact_set_notes (DesktopcouchDocumentContact *document, const char *notes)
 {
-	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
-	g_return_if_fail (desktopcouch_document_is_contact (document));
+	g_return_if_fail (DESKTOPCOUCH_IS_DOCUMENT_CONTACT (document));
+	g_return_if_fail (desktopcouch_document_is_contact (DESKTOPCOUCH_DOCUMENT (document)));
 	g_return_if_fail (notes != NULL);
 
-	couchdb_document_set_string_field (document, "notes", notes);
+	couchdb_document_set_string_field (COUCHDB_DOCUMENT (document), "notes", notes);
 }
 
 CouchdbStructField *
diff --git a/desktopcouch-glib/desktopcouch-document-contact.h b/desktopcouch-glib/desktopcouch-document-contact.h
index 9c28acb..d8dbf2b 100644
--- a/desktopcouch-glib/desktopcouch-document-contact.h
+++ b/desktopcouch-glib/desktopcouch-document-contact.h
@@ -27,68 +27,78 @@
 
 G_BEGIN_DECLS
 
-#define DESKTOPCOUCH_RECORD_TYPE_CONTACT "http://www.freedesktop.org/wiki/Specifications/desktopcouch/contact";
+#define DESKTOPCOUCH_TYPE_DOCUMENT_CONTACT                (desktopcouch_document_contact_get_type ())
+#define DESKTOPCOUCH_DOCUMENT_CONTACT(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), DESKTOPCOUCH_TYPE_DOCUMENT_CONTACT, DesktopcouchDocumentContact))
+#define DESKTOPCOUCH_IS_DOCUMENT_CONTACT(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DESKTOPCOUCH_TYPE_DOCUMENT_CONTACT))
+#define DESKTOPCOUCH_DOCUMENT_CONTACT_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST ((klass), DESKTOPCOUCH_TYPE_DOCUMENT_CONTACT, DesktopcouchDocumentContactClass))
+#define DESKTOPCOUCH_IS_DOCUMENT_CONTACT_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE ((klass), DESKTOPCOUCH_TYPE_DOCUMENT_CONTACT))
+#define DESKTOPCOUCH_DOCUMENT_CONTACTGET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), DESKTOPCOUCH_TYPE_DOCUMENT_CONTACT, DesktopouchDocumentContactClass))
 
-CouchdbDocument *desktopcouch_document_contact_new (CouchdbSession *couchdb);
-gboolean         desktopcouch_document_is_contact (CouchdbDocument *document);
+typedef struct {
+	DesktopcouchDocument parent;
+} DesktopcouchDocumentContact;
+
+typedef struct {
+	DesktopcouchDocumentClass parent_class;
+} DesktopcouchDocumentContactClass;
 
 /*
  * Top level functions to manipulate documents representing a contact
  */
 
-const char *desktopcouch_document_contact_get_title (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_title (CouchdbDocument *document, const char *title);
-const char *desktopcouch_document_contact_get_first_name (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_first_name (CouchdbDocument *document, const char *first_name);
-const char *desktopcouch_document_contact_get_middle_name (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_middle_name (CouchdbDocument *document, const char *middle_name);
-const char *desktopcouch_document_contact_get_last_name (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_last_name (CouchdbDocument *document, const char *last_name);
-const char *desktopcouch_document_contact_get_suffix (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_suffix (CouchdbDocument *document, const char *suffix);
-
-const char *desktopcouch_document_contact_get_nick_name (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_nick_name (CouchdbDocument *document, const char *nick_name);
-const char *desktopcouch_document_contact_get_spouse_name (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_spouse_name (CouchdbDocument *document, const char *spouse_name);
-const char *desktopcouch_document_contact_get_birth_date (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_birth_date (CouchdbDocument *document, const char *birth_date);
-const char *desktopcouch_document_contact_get_wedding_date (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_wedding_date (CouchdbDocument *document, const char *wedding_date);
-
-const char *desktopcouch_document_contact_get_company (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_company (CouchdbDocument *document, const char *company);
-const char *desktopcouch_document_contact_get_department (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_department (CouchdbDocument *document, const char *department);
-const char *desktopcouch_document_contact_get_job_title (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_job_title (CouchdbDocument *document, const char *job_title);
-const char *desktopcouch_document_contact_get_manager_name (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_manager_name (CouchdbDocument *document, const char *manager_name);
-const char *desktopcouch_document_contact_get_assistant_name (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_assistant_name (CouchdbDocument *document, const char *assistant_name);
-const char *desktopcouch_document_contact_get_office (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_office (CouchdbDocument *document, const char *office);
-
-GSList     *desktopcouch_document_contact_get_email_addresses (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_email_addresses (CouchdbDocument *document, GSList *list);
-
-GSList     *desktopcouch_document_contact_get_phone_numbers (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_phone_numbers (CouchdbDocument *document, GSList *list);
-
-GSList     *desktopcouch_document_contact_get_addresses (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_addresses (CouchdbDocument *document, GSList *list);
-
-GSList     *desktopcouch_document_contact_get_im_addresses (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_im_addresses (CouchdbDocument *document, GSList *list);
-
-GSList     *desktopcouch_document_contact_get_urls (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_urls (CouchdbDocument *document, GSList *list);
-
-const char *desktopcouch_document_contact_get_categories (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_categories (CouchdbDocument *document, const char *categories);
-
-const char *desktopcouch_document_contact_get_notes (CouchdbDocument *document);
-void        desktopcouch_document_contact_set_notes (CouchdbDocument *document, const char *notes);
+const char *desktopcouch_document_contact_get_title (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_title (DesktopcouchDocumentContact *document, const char *title);
+const char *desktopcouch_document_contact_get_first_name (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_first_name (DesktopcouchDocumentContact *document, const char *first_name);
+const char *desktopcouch_document_contact_get_middle_name (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_middle_name (DesktopcouchDocumentContact *document, const char *middle_name);
+const char *desktopcouch_document_contact_get_last_name (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_last_name (DesktopcouchDocumentContact *document, const char *last_name);
+const char *desktopcouch_document_contact_get_suffix (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_suffix (DesktopcouchDocumentContact *document, const char *suffix);
+
+const char *desktopcouch_document_contact_get_nick_name (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_nick_name (DesktopcouchDocumentContact *document, const char *nick_name);
+const char *desktopcouch_document_contact_get_spouse_name (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_spouse_name (DesktopcouchDocumentContact *document, const char *spouse_name);
+const char *desktopcouch_document_contact_get_birth_date (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_birth_date (DesktopcouchDocumentContact *document, const char *birth_date);
+const char *desktopcouch_document_contact_get_wedding_date (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_wedding_date (DesktopcouchDocumentContact *document, const char *wedding_date);
+
+const char *desktopcouch_document_contact_get_company (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_company (DesktopcouchDocumentContact *document, const char *company);
+const char *desktopcouch_document_contact_get_department (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_department (DesktopcouchDocumentContact *document, const char *department);
+const char *desktopcouch_document_contact_get_job_title (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_job_title (DesktopcouchDocumentContact *document, const char *job_title);
+const char *desktopcouch_document_contact_get_manager_name (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_manager_name (DesktopcouchDocumentContact *document, const char *manager_name);
+const char *desktopcouch_document_contact_get_assistant_name (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_assistant_name (DesktopcouchDocumentContact *document, const char *assistant_name);
+const char *desktopcouch_document_contact_get_office (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_office (DesktopcouchDocumentContact *document, const char *office);
+
+GSList     *desktopcouch_document_contact_get_email_addresses (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_email_addresses (DesktopcouchDocumentContact *document, GSList *list);
+
+GSList     *desktopcouch_document_contact_get_phone_numbers (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_phone_numbers (DesktopcouchDocumentContact *document, GSList *list);
+
+GSList     *desktopcouch_document_contact_get_addresses (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_addresses (DesktopcouchDocumentContact *document, GSList *list);
+
+GSList     *desktopcouch_document_contact_get_im_addresses (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_im_addresses (DesktopcouchDocumentContact *document, GSList *list);
+
+GSList     *desktopcouch_document_contact_get_urls (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_urls (DesktopcouchDocumentContact *document, GSList *list);
+
+const char *desktopcouch_document_contact_get_categories (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_categories (DesktopcouchDocumentContact *document, const char *categories);
+
+const char *desktopcouch_document_contact_get_notes (DesktopcouchDocumentContact *document);
+void        desktopcouch_document_contact_set_notes (DesktopcouchDocumentContact *document, const char *notes);
 
 /*
  * Utility functions to manipulate email addresses fields
diff --git a/desktopcouch-glib/desktopcouch-document.c b/desktopcouch-glib/desktopcouch-document.c
index 3950e10..1cc8239 100644
--- a/desktopcouch-glib/desktopcouch-document.c
+++ b/desktopcouch-glib/desktopcouch-document.c
@@ -21,9 +21,21 @@
 
 #include "desktopcouch-document.h"
 
+G_DEFINE_TYPE(DesktopcouchDocument, desktopcouch_document, COUCHDB_TYPE_DOCUMENT)
+
+static void
+desktopcouch_document_class_init (DesktopcouchDocumentClass *klass)
+{
+}
+
+static void
+desktopcouch_document_init (DesktopcouchDocument *document)
+{
+}
+
 /**
  * desktopcouch_document_get_record_type:
- * @document: A #CouchdbDocument object
+ * @document: A #DesktopcouchDocument object
  *
  * Retrieve the record type of the given document. Record types are special
  * fields in the CouchDB documents, used in DesktopCouch, to identify
@@ -33,7 +45,7 @@
  * Return value: The record type of the given document.
  */
 const char *
-desktopcouch_document_get_record_type (CouchdbDocument *document)
+desktopcouch_document_get_record_type (DesktopcouchDocument *document)
 {
 	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
 
@@ -42,13 +54,13 @@ desktopcouch_document_get_record_type (CouchdbDocument *document)
 
 /**
  * desktopcouch_document_set_record_type:
- * @document: A #CouchdbDocument object
+ * @document: A #DesktopcouchDocument object
  * @record_type: Record type to set the document to
  *
  * Set the record type of the given document.
  */
 void
-desktopcouch_document_set_record_type (CouchdbDocument *document, const char *record_type)
+desktopcouch_document_set_record_type (DesktopcouchDocument *document, const char *record_type)
 {
 	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
 	g_return_if_fail (record_type != NULL);
@@ -58,7 +70,7 @@ desktopcouch_document_set_record_type (CouchdbDocument *document, const char *re
 
 /**
  * desktopcouch_document_get_application_annotations:
- * @document: A #CouchdbDocument object
+ * @document: A #DesktopcouchDocument object
  *
  * Retrieve the application annotations for the given document.
  *
@@ -71,7 +83,7 @@ desktopcouch_document_set_record_type (CouchdbDocument *document, const char *re
  * annotations for the given document.
  */
 CouchdbStructField *
-desktopcouch_document_get_application_annotations (CouchdbDocument *document)
+desktopcouch_document_get_application_annotations (DesktopcouchDocument *document)
 {
 	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), NULL);
 
@@ -80,15 +92,33 @@ desktopcouch_document_get_application_annotations (CouchdbDocument *document)
 
 /**
  * desktopcouch_document_set_application_annotations:
- * @document: A #CouchdbDocument object
+ * @document: A #DesktopcouchDocument object
  * @annotations: A #CouchdbStructField with the contents of the application_annotations field.
  *
  * Set the application annotations for the given document.
  */
 void
-desktopcouch_document_set_application_annotations (CouchdbDocument *document, CouchdbStructField *annotations)
+desktopcouch_document_set_application_annotations (DesktopcouchDocument *document, CouchdbStructField *annotations)
 {
 	g_return_if_fail (COUCHDB_IS_DOCUMENT (document));
 
 	couchdb_document_set_struct_field (document, "application_annotations", annotations);
 }
+
+/**
+ * desktopcouch_document_is_contact:
+ * @document: A #DesktopcouchDocument object
+ *
+ * Check whether the given document represents a contact record, as specified
+ * at http://www.freedesktop.org/wiki/Specifications/desktopcouch/contact
+ *
+ * Return value: TRUE if the document represents a contact, FALSE otherwise.
+ */
+gboolean
+desktopcouch_document_is_contact (DesktopcouchDocument *document)
+{
+	g_return_val_if_fail (DESKTOPCOUCH_IS_DOCUMENT (document), FALSE);
+
+	return !g_ascii_strcasecmp (desktopcouch_document_get_record_type (document),
+				    DESKTOPCOUCH_RECORD_TYPE_CONTACT);
+}
diff --git a/desktopcouch-glib/desktopcouch-document.h b/desktopcouch-glib/desktopcouch-document.h
index 58d7137..ce7721f 100644
--- a/desktopcouch-glib/desktopcouch-document.h
+++ b/desktopcouch-glib/desktopcouch-document.h
@@ -26,14 +26,35 @@
 
 G_BEGIN_DECLS
 
-const char         *desktopcouch_document_get_record_type (CouchdbDocument *document);
-void                desktopcouch_document_set_record_type (CouchdbDocument *document,
+#define DESKTOPCOUCH_TYPE_DOCUMENT                (desktopcouch_document_get_type ())
+#define DESKTOPCOUCH_DOCUMENT(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), DESKTOPCOUCH_TYPE_DOCUMENT, DesktopcouchDocument))
+#define DESKTOPCOUCH_IS_DOCUMENT(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DESKTOPCOUCH_TYPE_DOCUMENT))
+#define DESKTOPCOUCH_DOCUMENT_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST ((klass), DESKTOPCOUCH_TYPE_DOCUMENT, DesktopcouchDocumentClass))
+#define DESKTOPCOUCH_IS_DOCUMENT_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE ((klass), DESKTOPCOUCH_TYPE_DOCUMENT))
+#define DESKTOPCOUCH_DOCUMENT_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), DESKTOPCOUCH_TYPE_DOCUMENT, DesktopouchDocumentClass))
+
+typedef struct {
+	CouchdbDocument parent;
+} DesktopcouchDocument;
+
+typedef struct {
+	CouchdbDocumentClass parent_class;
+} DesktopcouchDocumentClass;
+
+GType               desktopcouch_document_get_type (void);
+
+const char         *desktopcouch_document_get_record_type (DesktopcouchDocument *document);
+void                desktopcouch_document_set_record_type (DesktopcouchDocument *document,
 							   const char *record_type);
 
-CouchdbStructField *desktopcouch_document_get_application_annotations (CouchdbDocument *document);
-void                desktopcouch_document_set_application_annotations (CouchdbDocument *document,
+CouchdbStructField *desktopcouch_document_get_application_annotations (DesktopcouchDocument *document);
+void                desktopcouch_document_set_application_annotations (DesktopcouchDocument *document,
 								       CouchdbStructField *annotations);
 
+#define DESKTOPCOUCH_RECORD_TYPE_CONTACT "http://www.freedesktop.org/wiki/Specifications/desktopcouch/contact";
+
+gboolean            desktopcouch_document_is_contact (DesktopcouchDocument *document);
+
 G_END_DECLS
 
 #endif
diff --git a/desktopcouch-glib/desktopcouch-session.c b/desktopcouch-glib/desktopcouch-session.c
index 1aee1dc..85369f5 100644
--- a/desktopcouch-glib/desktopcouch-session.c
+++ b/desktopcouch-glib/desktopcouch-session.c
@@ -23,6 +23,34 @@
 #include <gnome-keyring.h>
 #include "desktopcouch-session.h"
 
+typedef struct {
+	CouchdbDatabase parent;
+} DesktopcouchDatabase;
+
+typedef struct {
+	CouchdbDatabaseClass parent_class;
+} DesktopcouchDatabaseClass;
+
+G_DEFINE_TYPE(DesktopcouchDatabase, desktopcouch_database, COUCHDB_TYPE_DATABASE)
+
+static CouchdbDocument *
+desktopcouch_database_create_document_from_json (CouchdbDatabase *database, gpointer json_data)
+{
+}
+
+static void
+desktopcouch_database_class_init (DesktopcouchDatabaseClass *klass)
+{
+	CouchdbDatabaseClass *db_class = COUCHDB_DATABASE_CLASS (klass);
+
+	db_class->create_document_from_json = desktopcouch_database_create_document_from_json;
+}
+
+static void
+desktopcouch_database_init (DesktopcouchDatabase *database)
+{
+}
+
 G_DEFINE_TYPE(DesktopcouchSession, desktopcouch_session, COUCHDB_TYPE_SESSION)
 
 static void
@@ -31,12 +59,23 @@ desktopcouch_session_finalize (GObject *object)
 	G_OBJECT_CLASS (desktopcouch_session_parent_class)->finalize (object);
 }
 
+static CouchdbDatabase *
+desktopcouch_session_get_database (CouchdbSession *session, const char *dbname)
+{
+	return g_object_new (desktopcouch_database_get_type (),
+			     "session", session,
+			     "database_name", dbname,
+			     NULL);
+}
+
 static void
 desktopcouch_session_class_init (DesktopcouchSessionClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	CouchdbSessionClass *session_class = COUCHDB_SESSION_CLASS (klass);
 
 	object_class->finalize = desktopcouch_session_finalize;
+	session_class->get_database = desktopcouch_session_get_database;
 }
 
 static void
diff --git a/tests/test-couchdb-glib.c b/tests/test-couchdb-glib.c
index 10208ae..6c9f702 100644
--- a/tests/test-couchdb-glib.c
+++ b/tests/test-couchdb-glib.c
@@ -40,6 +40,7 @@ test_list_databases (void)
 
 	while (dblist != NULL) {
 		CouchdbDatabaseInfo *dbinfo;
+		CouchdbDatabase *database;
 		GSList *doclist;
 
 		error = NULL;
@@ -48,16 +49,22 @@ test_list_databases (void)
 		g_assert (dbinfo != NULL);
 		g_assert (couchdb_database_info_get_dbname (dbinfo) != NULL);
 
+		error = NULL;
+		database = couchdb_session_get_database (couchdb, (const char *) dblist->data, &error);
+		g_assert (error == NULL);
+		g_assert (database != NULL);
+
 		/* Get list of documents to compare against couchdb_database_info_get_documents_count */
 		error = NULL;
-		doclist = couchdb_session_list_documents (couchdb, (const char *) dblist->data, &error);
+		doclist = couchdb_database_list_documents (database, &error);
 		g_assert (error == NULL);
 		g_assert (g_slist_length (doclist) == couchdb_database_info_get_documents_count (dbinfo));
 		if (doclist)
-			couchdb_session_free_document_list (doclist);
+			couchdb_database_free_document_list (doclist);
 
 		dblist = g_slist_remove (dblist, dblist->data);
 		couchdb_database_info_unref (dbinfo);
+		g_object_unref (G_OBJECT (database));
 	}
 }
 
@@ -72,9 +79,15 @@ test_list_documents (void)
 
 	while (dblist != NULL) {
 		GSList *doclist;
+		CouchdbDatabase *database;
 
 		error = NULL;
-		doclist = couchdb_session_list_documents (couchdb, (const char *) dblist->data, &error);
+		database = couchdb_session_get_database (couchdb, (const char *) dblist->data, &error);
+		g_assert (error == NULL);
+		g_assert (database != NULL);
+
+		error = NULL;
+		doclist = couchdb_database_list_documents (database, &error);
 		g_assert (error == NULL);
 
 		while (doclist) {
@@ -83,9 +96,9 @@ test_list_documents (void)
 			char *str;
 
 			error = NULL;
-			document = couchdb_document_get (couchdb, (const char *) dblist->data,
-							 couchdb_document_info_get_docid (doc_info),
-							 &error);
+			document = couchdb_database_get_document (database,
+								  couchdb_document_info_get_docid (doc_info),
+								  &error);
 			g_assert (error == NULL);
 			g_assert (document != NULL);
 			g_assert (g_strcmp0 (couchdb_document_info_get_docid (doc_info), couchdb_document_get_id (document)) == 0);
@@ -102,6 +115,7 @@ test_list_documents (void)
 		}
 
 		dblist = g_slist_remove (dblist, dblist->data);
+		g_object_unref (G_OBJECT (database));
 	}
 }
 
@@ -111,6 +125,7 @@ test_change_databases (void)
 	char *dbname;
 	gint i;
 	GError *error = NULL;
+	CouchdbDatabase *database;
 
 	dbname = generate_uuid ();
 	g_assert (dbname != NULL);
@@ -126,14 +141,15 @@ test_change_databases (void)
 		g_error_free (error);
 	}
 
-	couchdb_session_listen_for_changes (couchdb, dbname);
+	database = couchdb_session_get_database (couchdb, dbname, &error);
+	couchdb_database_listen_for_changes (database);
 
 	/* Create some documents */
 	for (i = 0; i < 10; i++) {
 		CouchdbDocument *document;
 		char *str;
 
-		document = couchdb_document_new (couchdb);
+		document = couchdb_document_new ();
 		g_assert (document != NULL);
 
 		couchdb_document_set_boolean_field (document, "boolean", TRUE);
@@ -144,10 +160,12 @@ test_change_databases (void)
 		couchdb_document_set_string_field (document, "string", str);
 		g_free (str);
 
-		g_assert (couchdb_document_put (document, dbname, &error));
+		g_assert (couchdb_database_put_document (database, document, &error));
 		g_assert (error == NULL);
 	}
-	
+
+	g_object_unref (G_OBJECT (database));
+
 	/* Delete database */
 	g_assert (couchdb_session_delete_database (couchdb, dbname, &error));
 	g_assert (error == NULL);
diff --git a/tests/test-list-databases.c b/tests/test-list-databases.c
index 34086f4..1b3debb 100644
--- a/tests/test-list-databases.c
+++ b/tests/test-list-databases.c
@@ -49,6 +49,7 @@ main (int argc, char *argv[])
 	
 	for (sl = dblist; sl != NULL; sl = sl->next) {
 		CouchdbDatabaseInfo *dbinfo;
+		CouchdbDatabase *database;
 		GSList *doclist;
 
 		error = NULL;
@@ -75,7 +76,11 @@ main (int argc, char *argv[])
 
 		/* now, get list of documents */
 		error = NULL;
-		doclist = couchdb_session_list_documents (couchdb, (const char *) sl->data, &error);
+		database = couchdb_session_get_database (couchdb, (const char *) sl->data, &error);
+		g_assert (database != NULL);
+
+		error = NULL;
+		doclist = couchdb_database_list_documents (couchdb, &error);
 		if (doclist) {
 			GSList *sl_doc;
 
@@ -85,10 +90,9 @@ main (int argc, char *argv[])
 				CouchdbDocument *document;
 
 				error = NULL;
-				document = couchdb_document_get (couchdb,
-								 (const char *) sl->data,
-								 couchdb_document_info_get_docid (doc_info),
-								 &error);
+				document = couchdb_database_get_document (database,
+									  couchdb_document_info_get_docid (doc_info),
+									  &error);
 				if (document) {
 					char *json;
 
@@ -107,6 +111,8 @@ main (int argc, char *argv[])
 						 couchdb_document_info_get_revision (doc_info));
 				}
 			}
+
+			couchdb_database_free_document_list (doclist);
 		} else {
 			g_print ("\tNo documents\n");
 		}



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