[couchdb-glib/wip/query-response] introduce couchdb_database_execute_query and port all CouchdbDatabase methods to it



commit 17811c92b3027b76ce6ab48e4fc5733bd4983f47
Author: Krzysztof Klimonda <kklimonda syntaxhighlighted com>
Date:   Wed Jan 19 13:35:57 2011 +0100

    introduce couchdb_database_execute_query and port all CouchdbDatabase methods to it

 couchdb-glib/couchdb-database.c |  617 ++++++++++++++-------------------------
 couchdb-glib/couchdb-database.h |   64 +++--
 2 files changed, 267 insertions(+), 414 deletions(-)
---
diff --git a/couchdb-glib/couchdb-database.c b/couchdb-glib/couchdb-database.c
index 81a12ed..ede559b 100644
--- a/couchdb-glib/couchdb-database.c
+++ b/couchdb-glib/couchdb-database.c
@@ -177,33 +177,10 @@ couchdb_database_init (CouchdbDatabase *database)
 	database->priv = g_new0 (CouchdbDatabasePrivate, 1);
 }
 
-static CouchdbDocument *
-create_document_from_json_object (JsonObject *json_object)
+GQuark
+couchdb_database_error_quark ()
 {
-	CouchdbDocument *document;
-
-	if (g_str_has_prefix (json_object_get_string_member (json_object, "id"),
-			      "_design/")) {
-		document = COUCHDB_DOCUMENT (couchdb_design_document_new ());
-		couchdb_document_set_from_json_object (document,
-						       json_object_get_object_member (json_object, "doc"));
-	} else {
-		if (json_object_has_member (json_object, "record_type")) {
-			if (g_strcmp0 (json_object_get_string_member (json_object, "record_type"),
-				       COUCHDB_RECORD_TYPE_CONTACT) == 0) {
-				document = COUCHDB_DOCUMENT (couchdb_document_contact_new ());
-			} else if (g_strcmp0 (json_object_get_string_member (json_object, "record_type"),
-					      COUCHDB_RECORD_TYPE_TASK) == 0) {
-				document = COUCHDB_DOCUMENT (couchdb_document_task_new ());
-			} else
-				document = couchdb_document_new ();
-
-			couchdb_document_set_from_json_object (document, json_object);
-		} else
-			document = couchdb_document_new_from_json_object (json_object);
-	}
-
-	return document;
+	return g_quark_from_static_string ("couchdb-database-error-quark");
 }
 
 /**
@@ -211,8 +188,8 @@ create_document_from_json_object (JsonObject *json_object)
  * @session: A #CouchdbSession object
  * @dbname: Name of the database
  *
- * Create a new #CouchdbDatabase object, which is to be used for operations on specific
- * databases on the underlying CouchDB instance.
+ * Create a new #CouchdbDatabase object, which is to be used for
+ * operations on specific databases on the underlying CouchDB instance.
  *
  * Return value: A new #CouchdbDatabase object.
  */
@@ -225,137 +202,58 @@ 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_design_documents:
  * @database: A #CouchdbDatabase object
  * @error: Placeholder for error information
  *
- * Retrieve all design documents from the given database.
+ * Retrieve all design documents from the given database. For each document
+ * a #JsonObject is returned.
  *
- * Design documents are special documents (well, they are really normal documents in
- * the CouchDB database, just with a special ID) that contain views' code, which are used
- * to create queries on the database that are cached and so make access to the database
- * much quicker.
+ * Design documents are special documents (well, they are really normal documents
+ * in the CouchDB database, just with a special ID) that contain views' code,
+ * which are used to create queries on the database that are cached and so make
+ * access to the database much quicker.
  *
- * Return value: A list of #CouchdbDesignDocument 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.
+ * Return value: (element-type Json.Object) (transfer full): A #GList
+ * of #Json.Object objects, or %NULL if there aren't any documents,
+ * or there was an error (in which case the error argument will contain
+ * information about the error). Both #GList and documents should be freed
+ * once they are no longer needed.
  */
-GSList *
-couchdb_database_get_design_documents (CouchdbDatabase *database, GError **error)
+GList *
+couchdb_database_get_design_documents (CouchdbDatabase *self, 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;
-			const gchar *id;
-			CouchdbDesignDocument *document;
-
-			obj = json_array_get_object_element (rows, i);
-			if (!obj)
-				continue;
-
-			id = json_object_get_string_member (obj, "_id");
-			if (!g_str_has_prefix (id, "_design/"))
-				continue;
-
-			document = couchdb_design_document_new ();
-			if (document != NULL) {
-				couchdb_document_set_from_json_object (COUCHDB_DOCUMENT (document), obj);
-				doclist = g_slist_append (doclist, document);
-			}
-		}
+	CouchdbQuery *query;
+	CouchdbResponse *response;
+	GList *doclist = NULL, *rows, *iter;
+
+	g_return_val_if_fail (COUCHDB_IS_DATABASE (self), NULL);
+
+	query = couchdb_query_new_for_path ("/_all_docs");
+	couchdb_query_set_option (query, "include_docs", "true");
+	/* get only design documents, the idea to use startkey and endkey
+	 * this way comes from CouchDB's futon. All design documents have
+	 * IDs starting with _design and here we make use of the fact that,
+	 * when comparing strings "0" is bigger than "/". */
+	couchdb_query_set_option (query, "startkey", "_design/");
+	couchdb_query_set_option (query, "endkey", "_design0");
+
+	response = couchdb_database_execute_query (self, query, error);
+	rows = couchdb_response_get_rows (response);
+
+	for (iter = rows; iter != NULL; iter = g_list_next (iter)) {
+		JsonObject *document;
+
+		document = json_object_ref (
+			json_object_get_object_member (iter->data, "doc"));
+		doclist = g_list_prepend (doclist, document);
 	}
+	doclist = g_list_reverse (doclist);
 
-	g_object_unref (G_OBJECT (parser));
-	g_free (url);
+	g_list_free (rows);
+	g_object_unref (response);
+	g_object_unref (query);
 
 	return doclist;
 }
@@ -370,147 +268,82 @@ couchdb_database_get_design_documents (CouchdbDatabase *database, GError **error
  * 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.
+ * Return value: (element-type Json.Object) (transfer full): A #GList
+ * of #Json.Object objects, or %NULL if there aren't any documents,
+ * or there was an error (in which case the error argument will contain
+ * information about the error). Both #GList and documents should be freed
+ * once they are no longer needed.
  */
-GSList *
-couchdb_database_get_all_documents (CouchdbDatabase *database, GError **error)
+GList *
+couchdb_database_get_all_documents (CouchdbDatabase *self, GError **error)
 {
-	char *url;
-	JsonParser *parser;
-	JsonArray *rows;
-	GSList *doclist = NULL;
+	CouchdbQuery *query;
+	CouchdbResponse *response;
+	GList *documents, *iter, *doclist = NULL;
 
-	g_return_val_if_fail (COUCHDB_IS_DATABASE (database), NULL);
+	g_return_val_if_fail (COUCHDB_IS_DATABASE (self), 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 = NULL;
-
-			obj = json_array_get_object_element (rows, i);
-			if (!obj)
-				continue;
-
-			document = create_document_from_json_object (json_object_get_object_member (obj, "doc"));
-			if (document != NULL) {
-				g_object_set (G_OBJECT (document), "database", database, NULL);
-				doclist = g_slist_append (doclist, document);
-			}
-		}
-	}
+	query = couchdb_query_new_for_path ("/_all_docs");
+	couchdb_query_set_option (query, "include_docs", "true");
 
-	g_object_unref (G_OBJECT (parser));
-	g_free (url);
+	response = couchdb_database_execute_query (self, query, error);
+	documents = couchdb_response_get_rows (response);
 
-	return doclist;
-}
+	for (iter = documents; iter != NULL; iter = g_list_next (iter)) {
+		JsonObject *document;
 
-/**
- * couchdb_database_execute_view:
- * @database: A #CouchdbDatabase object
- * @design_doc: Name of the design document where the view to execute is
- * @view_name: Name of the view to execute
- * @error: Placeholder for error information
- *
- * Run a view on the database to retrieve documents. 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_execute_view (CouchdbDatabase *database,
-			       const char *design_doc,
-			       const char *view_name,
-			       GError **error)
-{
-	char *url;
-	JsonParser *parser;
-	JsonArray *rows;
-	GSList *doclist = NULL;
-
-	g_return_val_if_fail (COUCHDB_IS_DATABASE (database), NULL);
+		document = json_object_ref (
+			json_object_get_object_member (iter->data, "doc"));
+		doclist = g_list_prepend (doclist, document);
 
-	if (g_str_has_prefix (design_doc, "_design/")) {
-		url = g_strdup_printf ("%s/%s/%s/_view/%s",
-				       couchdb_session_get_uri (database->priv->session),
-				       database->priv->dbname,
-				       design_doc,
-				       view_name);
-	} else {
-		url = g_strdup_printf ("%s/%s/_design/%s/_view/%s",
-				       couchdb_session_get_uri (database->priv->session),
-				       database->priv->dbname,
-				       design_doc,
-				       view_name);
-	}
-
-	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 = NULL;
-
-			obj = json_array_get_object_element (rows, i);
-			if (!obj)
-				continue;
-
-			document = create_document_from_json_object (json_object_get_object_member (obj, "value"));
-
-			if (document != NULL) {
-				couchdb_document_set_id (document, json_object_get_string_member (obj, "id"));
-				g_object_set (G_OBJECT (document), "database", database, NULL);
-				doclist = g_slist_append (doclist, document);
-			}
-		}
 	}
+	doclist = g_list_reverse (doclist);
 
-	g_object_unref (G_OBJECT (parser));
-	g_free (url);
+	g_list_free (documents);
+	g_object_unref (response);
+	g_object_unref (query);
 
 	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
+ * couchdb_database_execute_query:
+ * @self: A #CouchdbDatabase object
+ * @query: A #CouchdbQuery object describing a query
+ * @error: Placeholder for error information
  *
- * Free the list of documents returned by #couchdb_database_list_documents or
- * #couchdb_database_get_all_documents
+ * A helper function to execute created queries on a specified database,
+ * as opposed on session itself. It prepend database's name to query's path
+ * and calls couchdb_session_execute_query with it.
+ *
+ * Return value: (transfer full): A #CouchdbResponse object that contains
+ * response from the server, or %NULL if there was an error, in which case
+ * @error will be set appropriately.
  */
-void
-couchdb_database_free_document_list (GSList *doclist)
+CouchdbResponse *
+couchdb_database_execute_query (CouchdbDatabase * self,
+				CouchdbQuery * query, GError **error)
 {
-	g_return_if_fail (doclist != NULL);
+	CouchdbResponse *response;
+	const char *path;
+	char *full_path, *encoded_dbname;
 
-	while (doclist != NULL) {
-		gpointer data = doclist->data;
+	path = couchdb_query_get_path (query);
+	encoded_dbname = couchdb_uri_encode (self->priv->dbname);
 
-		doclist = g_slist_remove (doclist, data);
+	/* to prevent creating uri with two slashes check if first character
+	   of path is slash and, if it is, skip it. */
+	full_path = g_strconcat (encoded_dbname, "/",
+				 path ? (*path == '/' ? path+1 : path) : "", NULL);
+	couchdb_query_set_path (query, full_path);
 
-		if (COUCHDB_IS_DOCUMENT (data))
-			g_object_unref (G_OBJECT (data));
-		else
-			couchdb_document_info_unref (data);
-	}
+
+	response = couchdb_session_execute_query (self->priv->session,
+						  query, error);
+	g_free (full_path);
+	g_free (encoded_dbname);
+
+	return response;
 }
 
 /**
@@ -524,78 +357,34 @@ couchdb_database_free_document_list (GSList *doclist)
  * 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,
+JsonObject *
+couchdb_database_get_document (CouchdbDatabase *self,
+			       const char *id,
+			       const char *revision,
 			       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)) {
-		JsonObject *json_object = json_node_get_object (json_parser_get_root (parser));
-
-		document = create_document_from_json_object (json_object);
-		g_object_set (G_OBJECT (document), "database", database, NULL);
+	CouchdbQuery *query;
+	CouchdbResponse *response;
+	char *encoded_docid;
+	JsonObject *object;
+
+	g_return_val_if_fail (COUCHDB_IS_DATABASE (self), NULL);
+	g_return_val_if_fail (id != NULL, NULL);
+
+	encoded_docid = couchdb_uri_encode (id);
+	query = couchdb_query_new_for_path (encoded_docid);
+	if (revision != NULL) {
+		couchdb_query_set_option (query, "rev", revision);
 	}
+	
+	response = couchdb_database_execute_query (self, query, error);
+	object = json_object_ref (couchdb_response_get_json_object (response));
 
-	g_object_unref (G_OBJECT (parser));
+	g_object_unref (query);
+	g_object_unref (response);
 	g_free (encoded_docid);
-	g_free (url);
-
-	return document;
-}
-
-/**
- * couchdb_database_get_design_document:
- * @database: A #CouchdbDatabase object
- * @docid: ID of the design document
- * @error: Placeholder for error information
- *
- * Retrieve a design document from the given database.
- *
- * Return value: A #CouchdbDesignDocument object if successful, NULL otherwise, in
- * which case, the error argument will contain information about the error.
- */
-CouchdbDesignDocument *
-couchdb_database_get_design_document (CouchdbDatabase *database, const char *docid, GError **error)
-{
-	char *url;
-	JsonParser *parser;
-	CouchdbDesignDocument *document = NULL;
-
-	g_return_val_if_fail (COUCHDB_IS_DATABASE (database), NULL);
-	g_return_val_if_fail (docid != NULL, NULL);
-
-	if (g_str_has_prefix (docid, "_design/")) {
-		url = g_strdup_printf ("%s/%s/%s", couchdb_session_get_uri (database->priv->session),
-				       database->priv->dbname, docid);
-	} else {
-		url = g_strdup_printf ("%s/%s/_design/%s", couchdb_session_get_uri (database->priv->session),
-				       database->priv->dbname, docid);
-	}
-
-	parser = json_parser_new ();
-	if (couchdb_session_send_message (database->priv->session, SOUP_METHOD_GET, url, NULL, parser, error)) {
-		document = couchdb_design_document_new ();
-		couchdb_document_set_from_json_object (COUCHDB_DOCUMENT (document),
-						       json_node_get_object (json_parser_get_root (parser)));
-
-		g_object_set (G_OBJECT (document), "database", database, NULL);
-	}
-
-	g_object_unref (G_OBJECT (parser));
-	g_free (url);
 
-	return document;
+	return object;
 }
 
 /**
@@ -618,57 +407,79 @@ couchdb_database_get_design_document (CouchdbDatabase *database, const char *doc
  */
 gboolean
 couchdb_database_put_document (CouchdbDatabase *database,
-			       CouchdbDocument *document,
+			       JsonObject *document,
 			       GError **error)
 {
-	char *url, *body;
+	CouchdbQuery *query;
+	CouchdbResponse *response;
+	char *body;
 	const char *id;
+	JsonObject *object;
 	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);
+	g_return_val_if_fail (document != NULL, FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	id = couchdb_document_get_id (document);
-	body = couchdb_document_to_string (document);
-	parser = json_parser_new ();
-	if (id) {
-		char *encoded_docid;
+	if (json_object_has_member (document, "_id")) {
+		char *encoded_id;
 
-		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);
+		id = json_object_get_string_member (document, "_id");
+		encoded_id = couchdb_uri_encode (id);
+		query = couchdb_query_new_for_path (encoded_id);
+		couchdb_query_set_method (query, "PUT");
+		couchdb_query_set_json_object (query, document);
 
-		g_free (encoded_docid);
+		g_free (encoded_id);
 	} 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);
+		query = couchdb_query_new ();
+		couchdb_query_set_method (query, "POST");
+		couchdb_query_set_json_object (query, document);
 	}
 
-	if (send_ok) {
-		JsonObject *object;
+	response = couchdb_database_execute_query (database, query, error);
+	if (!response) {
+		g_assert (error == NULL || *error != NULL);
+
+		if ((*error)->code == COUCHDB_SESSION_ERROR_CONFLICT) {
+			g_clear_error (error);
+			g_set_error_literal (error,
+					     COUCHDB_DATABASE_ERROR,
+					     COUCHDB_DATABASE_ERROR_DOCUMENT_CONFLICT,
+					     "Document you are trying to put " \
+					     "already exists and revisions " \
+					     "don't match");
+		}
 
-		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"));
+		g_object_unref (query);
 
-		if (id)
-			g_signal_emit_by_name (database, "document_updated", document);
-		else
-			g_signal_emit_by_name (database, "document_created", document);
+		return FALSE;
+	}
 
-		g_object_set (G_OBJECT (document), "database", database, NULL);
+	object = couchdb_response_get_json_object (response);
 
-		result = TRUE;
+	if (json_object_has_member (object, "id")) {
+		id = json_object_get_string_member (object, "id");
+		json_object_set_string_member (document, "_id", id);
 	}
+	if (json_object_has_member (object, "rev")) {
+		const char *rev;
 
-	/* free memory */
-	g_free (url);
-	g_free (body);
-	g_object_unref (G_OBJECT (parser));
+		rev = json_object_get_string_member (object, "rev");
+		json_object_set_string_member (document, "_rev", rev);
+	}
 
-	return result;
+	if (id)
+		g_signal_emit_by_name (database, "document_updated", document);
+	else
+		g_signal_emit_by_name (database, "document_created", document);
+
+	g_object_unref (query);
+	g_object_unref (response);
+
+	return TRUE;
 }
 
 /**
@@ -684,38 +495,52 @@ couchdb_database_put_document (CouchdbDatabase *database,
  * 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.
+ * 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)
+couchdb_database_delete_document (CouchdbDatabase * database, 
+				  JsonObject * document, GError **error)
 {
-	const char *id, *revision;
-	char *url;
-	gboolean result = FALSE;
+	CouchdbQuery *query;
+	CouchdbResponse *response;
+	const gchar *id, *revision;
+	gchar *encoded_id;
 
 	g_return_val_if_fail (COUCHDB_IS_DATABASE (database), FALSE);
-	g_return_val_if_fail (COUCHDB_IS_DOCUMENT (document), FALSE);
+	g_return_val_if_fail (document != NULL, 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;
+	id = json_object_get_string_member (document, "_id");
+	revision = json_object_get_string_member (document, "_rev");
 
-	url = g_strdup_printf ("%s/%s/%s?rev=%s", couchdb_session_get_uri (database->priv->session), database->priv->dbname, id, revision);
+	/* we can't remove a document without an ID and/or a REVISION */
+	if (!id || !revision) 
+		return FALSE;
 	
-	/* 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);
+	encoded_id = couchdb_uri_encode (id);
+	query = couchdb_query_new_for_path (encoded_id);
+	couchdb_query_set_method (query, "DELETE");
+	couchdb_query_set_option (query, "rev", revision);
+
+	error = NULL;
+	response = couchdb_database_execute_query (database, query, error);
+	if (error != NULL) {
+		g_free (encoded_id);
+		g_object_unref (query);
+
+		return FALSE;
 	}
 
-	g_free (url);
 
-	return result;
+	g_free (encoded_id);
+	g_object_unref (query);
+	g_object_unref (response);
+
+	return TRUE;
 }
 
 /**
@@ -723,25 +548,28 @@ couchdb_database_delete_document (CouchdbDatabase *database, CouchdbDocument *do
  * @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.
+ * 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.
+ * 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;
+	JsonObject *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);
+		g_warning ("Already listening for changes in '%s' database",
+			   database->priv->dbname);
 		return;
 	}
 
@@ -757,11 +585,12 @@ couchdb_database_listen_for_changes (CouchdbDatabase *database)
 		return;
 	}
 
-	database->priv->db_watch = dbwatch_new (database,
-						couchdb_database_info_get_update_sequence (db_info));
+	database->priv->db_watch =
+		dbwatch_new (database,
+			     json_object_get_int_member (db_info, "update_seq"));
 
 	/* Free memory */
-	couchdb_database_info_unref (db_info);
+	json_object_unref (db_info);
 }
 
 /**
diff --git a/couchdb-glib/couchdb-database.h b/couchdb-glib/couchdb-database.h
index 072aa7a..663c41c 100644
--- a/couchdb-glib/couchdb-database.h
+++ b/couchdb-glib/couchdb-database.h
@@ -23,8 +23,9 @@
 #define __COUCHDB_DATABASE_H__
 
 #include <glib-object.h>
-#include "couchdb-design-document.h"
-#include "couchdb-document.h"
+#include <json-glib/json-glib.h>
+#include "couchdb-query.h"
+#include "couchdb-response.h"
 #include "couchdb-session.h"
 
 G_BEGIN_DECLS
@@ -36,6 +37,8 @@ G_BEGIN_DECLS
 #define COUCHDB_IS_DATABASE_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE ((klass), COUCHDB_TYPE_DATABASE))
 #define COUCHDB_DATABASE_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), COUCHDB_TYPE_DATABASE, CouchdbDatabaseClass))
 
+#define COUCHDB_DATABASE_ERROR (couchdb_database_error_quark ())
+
 typedef struct _CouchdbDatabasePrivate CouchdbDatabasePrivate;
 
 struct _CouchdbDatabase {
@@ -47,34 +50,55 @@ typedef struct {
 	GObjectClass parent_class;
 
 	/* Signals */
-	void (* document_created) (CouchdbDatabase *database, CouchdbDocument *document);
-	void (* document_updated) (CouchdbDatabase *database, CouchdbDocument *document);
+	void (* document_created) (CouchdbDatabase *database, JsonObject *document);
+	void (* document_updated) (CouchdbDatabase *database, JsonObject *document);
 	void (* document_deleted) (CouchdbDatabase *database, const char *docid);
 } CouchdbDatabaseClass;
 
+enum {
+	COUCHDB_DATABASE_ERROR_DOCUMENT_CONFLICT,
+	COUCHDB_DATABASE_ERROR_UNKNOWN
+};
+
+GQuark couchdb_database_error_quark (void);
+
 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_design_documents (CouchdbDatabase *database, GError **error);
-GSList          *couchdb_database_get_all_documents (CouchdbDatabase *database, GError **error);
-GSList          *couchdb_database_execute_view (CouchdbDatabase *database,
-						const char *design_doc,
-						const char *view_name,
-						GError **error);
-void             couchdb_database_free_document_list (GSList *doclist);
+GList          *couchdb_database_list_documents (CouchdbDatabase *database, GError **error);
+GList          *couchdb_database_get_design_documents (CouchdbDatabase *database, GError **error);
+GList          *couchdb_database_get_all_documents (CouchdbDatabase *database, GError **error);
 
-CouchdbDocument *couchdb_database_get_document (CouchdbDatabase *database,
-						const char *docid,
+CouchdbResponse *	couchdb_database_execute_query		(CouchdbDatabase *self,
+								 CouchdbQuery *query,
+								 GError **error);
+
+JsonObject *couchdb_database_get_document (CouchdbDatabase *database,
+						const char *id,
+						const char *revision,
 						GError **error);
-CouchdbDesignDocument *couchdb_database_get_design_document (CouchdbDatabase *database,
+JsonObject *couchdb_database_get_design_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);
-
+gboolean		couchdb_database_put_document		(CouchdbDatabase *database,
+								 JsonObject *document,
+								 GError **error);
+gboolean		couchdb_database_delete_document	(CouchdbDatabase *database,
+								 JsonObject *document,
+								 GError **error);
+#if 0
+void			couchdb_database_put_attachment		(CouchdbDatabase * self,
+								 JsonObject * document,
+								 CouchdbAttachment * attachment,
+								 GError ** error);
+CouchdbAttachment *	couchdb_database_get_attachment		(CouchdbDatabase * self,
+								 JsonObject * document,
+								 GError ** error);
+void			couchdb_database_delete_attachment	(CouchdbDatabase * self,
+								 JsonObject * document,
+								 CouchdbAttachment * attachment,
+								 GError ** error);
+#endif
 void             couchdb_database_listen_for_changes (CouchdbDatabase *database);
 
 CouchdbSession  *couchdb_database_get_session (CouchdbDatabase *database);



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