[libgdata] Build query URIs for GDataCalendarQuery



commit 78634a3d84a8f4717e1a5d9d1b5393bb567f0536
Author: Philip Withnall <philip tecnocode co uk>
Date:   Fri Apr 24 07:31:14 2009 +0100

    Build query URIs for GDataCalendarQuery
    
    GDataCalendarQuery can now put its properties into a query URI, as the
    gdata_query_get_query_uri function has been virtualised. A test case for
    calendar query URIs has been added.
---
 gdata/gdata-query.c                            |  174 +++++++++++++-----------
 gdata/gdata-query.h                            |    2 +
 gdata/services/calendar/gdata-calendar-event.c |    8 +-
 gdata/services/calendar/gdata-calendar-query.c |  104 ++++++++++++++-
 gdata/tests/calendar.c                         |   70 ++++++++++
 5 files changed, 270 insertions(+), 88 deletions(-)

diff --git a/gdata/gdata-query.c b/gdata/gdata-query.c
index 7cf0090..c85f5f6 100644
--- a/gdata/gdata-query.c
+++ b/gdata/gdata-query.c
@@ -56,6 +56,7 @@ typedef enum {
 static void gdata_query_finalize (GObject *object);
 static void gdata_query_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
 static void gdata_query_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
+static void get_query_uri (GDataQuery *self, const gchar *feed_uri, GString *query_uri, gboolean *params_started);
 
 struct _GDataQueryPrivate {
 	guint parameter_mask; /* GDataQueryParam */
@@ -110,6 +111,8 @@ gdata_query_class_init (GDataQueryClass *klass)
 	gobject_class->get_property = gdata_query_get_property;
 	gobject_class->finalize = gdata_query_finalize;
 
+	klass->get_query_uri = get_query_uri;
+
 	/**
 	 * GDataQuery:q:
 	 *
@@ -405,93 +408,22 @@ gdata_query_set_property (GObject *object, guint property_id, const GValue *valu
 	}
 }
 
-/**
- * gdata_query_new:
- * @q: a query string
- *
- * Creates a new #GDataQuery with its #GDataQuery:q property set to @q.
- *
- * Return value: a new #GDataQuery
- **/
-GDataQuery *
-gdata_query_new (const gchar *q)
-{
-	return g_object_new (GDATA_TYPE_QUERY, "q", q, NULL);
-}
-
-/**
- * gdata_query_new_with_limits:
- * @q: a query string
- * @start_index: a one-based start index for the results
- * @max_results: the maximum number of results to return
- *
- * Creates a new #GDataQuery with its #GDataQuery:q property set to @q, and the limits @start_index and @max_results
- * applied.
- *
- * Return value: a new #GDataQuery
- **/
-GDataQuery *
-gdata_query_new_with_limits (const gchar *q, gint start_index, gint max_results)
-{
-	return g_object_new (GDATA_TYPE_QUERY,
-			     "q", q,
-			     "start-index", start_index,
-			     "max-results", max_results,
-			     NULL);
-}
-
-/**
- * gdata_query_new_for_id:
- * @entry_id: an entry URN ID
- *
- * Creates a new #GDataQuery to query for @entry_id.
- *
- * Return value: a new #GDataQuery
- **/
-GDataQuery *
-gdata_query_new_for_id (const gchar *entry_id)
-{
-	return g_object_new (GDATA_TYPE_QUERY, "entry-id", entry_id, NULL);
-}
-
-/**
- * gdata_query_get_query_uri:
- * @self: a #GDataQuery
- * @feed_uri: the feed URI on which to build the query URI
- *
- * Builds a query URI from the given base feed URI, using the properties of the #GDataQuery. This function will take care
- * of all necessary URI escaping, so it should <emphasis>not</emphasis> be done beforehand.
- *
- * The query URI is what functions like gdata_service_query() use to query the online service.
- *
- * Return value: a query URI; free with g_free()
- **/
-gchar *
-gdata_query_get_query_uri (GDataQuery *self, const gchar *feed_uri)
+static void
+get_query_uri (GDataQuery *self, const gchar *feed_uri, GString *query_uri, gboolean *params_started)
 {
 	GDataQueryPrivate *priv = self->priv;
-	GString *query_uri;
-	gboolean params_started = FALSE;
-
-	#define APPEND_SEP g_string_append_c (query_uri, (params_started == FALSE) ? '?' : '&'); params_started = TRUE;
 
-	/* Check to see if we're paginating first */
-	if (priv->use_next_uri == TRUE)
-		return g_strdup (priv->next_uri);
-	if (priv->use_previous_uri == TRUE)
-		return g_strdup (priv->previous_uri);
+	#define APPEND_SEP g_string_append_c (query_uri, (*params_started == FALSE) ? '?' : '&'); *params_started = TRUE;
 
 	/* Check to see if any parameters have been set */
 	if ((priv->parameter_mask & GDATA_QUERY_PARAM_ALL) == 0)
-		return g_strdup (feed_uri);
-
-	query_uri = g_string_new (feed_uri);
+		return;
 
 	/* If we've been provided with an entry ID, only append that */
 	if (priv->entry_id != NULL) {
 		g_string_append_c (query_uri, '/');
 		g_string_append_uri_escaped (query_uri, priv->entry_id, NULL, TRUE);
-		return g_string_free (query_uri, FALSE);
+		return;
 	}
 
 	if (priv->categories != NULL) {
@@ -501,10 +433,7 @@ gdata_query_get_query_uri (GDataQuery *self, const gchar *feed_uri)
 
 	/* If that's it, return */
 	if ((priv->parameter_mask & (GDATA_QUERY_PARAM_ALL ^ GDATA_QUERY_PARAM_ENTRY_ID ^ GDATA_QUERY_PARAM_CATEGORIES)) == 0)
-		return g_string_free (query_uri, FALSE);
-
-	/* Determine whether the first param has already been appended (e.g. it exists in the feed_uri) */
-	params_started = (strstr (feed_uri, "?") != NULL) ? TRUE : FALSE;
+		return;
 
 	/* q param */
 	if (priv->q != NULL) {
@@ -573,6 +502,91 @@ gdata_query_get_query_uri (GDataQuery *self, const gchar *feed_uri)
 		APPEND_SEP
 		g_string_append_printf (query_uri, "max-results=%d", priv->max_results);
 	}
+}
+
+/**
+ * gdata_query_new:
+ * @q: a query string
+ *
+ * Creates a new #GDataQuery with its #GDataQuery:q property set to @q.
+ *
+ * Return value: a new #GDataQuery
+ **/
+GDataQuery *
+gdata_query_new (const gchar *q)
+{
+	return g_object_new (GDATA_TYPE_QUERY, "q", q, NULL);
+}
+
+/**
+ * gdata_query_new_with_limits:
+ * @q: a query string
+ * @start_index: a one-based start index for the results
+ * @max_results: the maximum number of results to return
+ *
+ * Creates a new #GDataQuery with its #GDataQuery:q property set to @q, and the limits @start_index and @max_results
+ * applied.
+ *
+ * Return value: a new #GDataQuery
+ **/
+GDataQuery *
+gdata_query_new_with_limits (const gchar *q, gint start_index, gint max_results)
+{
+	return g_object_new (GDATA_TYPE_QUERY,
+			     "q", q,
+			     "start-index", start_index,
+			     "max-results", max_results,
+			     NULL);
+}
+
+/**
+ * gdata_query_new_for_id:
+ * @entry_id: an entry URN ID
+ *
+ * Creates a new #GDataQuery to query for @entry_id.
+ *
+ * Return value: a new #GDataQuery
+ **/
+GDataQuery *
+gdata_query_new_for_id (const gchar *entry_id)
+{
+	return g_object_new (GDATA_TYPE_QUERY, "entry-id", entry_id, NULL);
+}
+
+/**
+ * gdata_query_get_query_uri:
+ * @self: a #GDataQuery
+ * @feed_uri: the feed URI on which to build the query URI
+ *
+ * Builds a query URI from the given base feed URI, using the properties of the #GDataQuery. This function will take care
+ * of all necessary URI escaping, so it should <emphasis>not</emphasis> be done beforehand.
+ *
+ * The query URI is what functions like gdata_service_query() use to query the online service.
+ *
+ * Return value: a query URI; free with g_free()
+ **/
+gchar *
+gdata_query_get_query_uri (GDataQuery *self, const gchar *feed_uri)
+{
+	GDataQueryClass *klass;
+	GString *query_uri;
+	gboolean params_started;
+
+	/* Check to see if we're paginating first */
+	if (self->priv->use_next_uri == TRUE)
+		return g_strdup (self->priv->next_uri);
+	if (self->priv->use_previous_uri == TRUE)
+		return g_strdup (self->priv->previous_uri);
+
+	klass = GDATA_ENTRY_GET_CLASS (self);
+	g_assert (klass->get_query_uri != NULL);
+
+	/* Determine whether the first param has already been appended (e.g. it exists in the feed_uri) */
+	params_started = (strstr (feed_uri, "?") != NULL) ? TRUE : FALSE;
+
+	/* Build the query URI */
+	query_uri = g_string_new (feed_uri);
+	klass->get_query_uri (self, feed_uri, query_uri, &params_started);
 
 	return g_string_free (query_uri, FALSE);
 }
diff --git a/gdata/gdata-query.h b/gdata/gdata-query.h
index 22f7440..7e45abe 100644
--- a/gdata/gdata-query.h
+++ b/gdata/gdata-query.h
@@ -52,6 +52,8 @@ typedef struct {
 typedef struct {
 	/*< private >*/
 	GObjectClass parent;
+
+	void (*get_query_uri) (GDataQuery *self, const gchar *feed_uri, GString *query_uri, gboolean *params_started);
 } GDataQueryClass;
 
 GType gdata_query_get_type (void) G_GNUC_CONST;
diff --git a/gdata/services/calendar/gdata-calendar-event.c b/gdata/services/calendar/gdata-calendar-event.c
index 450a39a..63548f6 100644
--- a/gdata/services/calendar/gdata-calendar-event.c
+++ b/gdata/services/calendar/gdata-calendar-event.c
@@ -58,10 +58,10 @@ struct _GDataCalendarEventPrivate {
 	guint sequence;
 	GList *times; /* GDataGDWhen */
 	GList *reminders;
-	gboolean guests_can_modify; /* TODO: Merge these four somehow? */
-	gboolean guests_can_invite_others;
-	gboolean guests_can_see_guests;
-	gboolean anyone_can_add_self;
+	guint guests_can_modify : 1;
+	guint guests_can_invite_others : 1;
+	guint guests_can_see_guests : 1;
+	guint anyone_can_add_self : 1;
 	GList *people; /* GDataGDWho */
 	GList *places; /* GDataGDWhere */
 };
diff --git a/gdata/services/calendar/gdata-calendar-query.c b/gdata/services/calendar/gdata-calendar-query.c
index 5f69e38..e3ab2a1 100644
--- a/gdata/services/calendar/gdata-calendar-query.c
+++ b/gdata/services/calendar/gdata-calendar-query.c
@@ -38,13 +38,11 @@
 #include "gdata-calendar-query.h"
 #include "gdata-query.h"
 
-/* Reference: http://code.google.com/apis/calendar/docs/2.0/reference.html#Parameters */
-
 static void gdata_calendar_query_finalize (GObject *object);
 static void gdata_calendar_query_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
 static void gdata_calendar_query_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
+static void get_query_uri (GDataQuery *self, const gchar *feed_uri, GString *query_uri, gboolean *params_started);
 
-/* TODO: Actually override GDataQuery's get_query_uri function to return a URI including all our custom parameters */
 struct _GDataCalendarQueryPrivate {
 	gboolean future_events;
 	gchar *order_by; /* TODO: enum? #defined values? */
@@ -76,6 +74,7 @@ static void
 gdata_calendar_query_class_init (GDataCalendarQueryClass *klass)
 {
 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GDataQueryClass *query_class = GDATA_QUERY_CLASS (klass);
 
 	g_type_class_add_private (klass, sizeof (GDataCalendarQueryPrivate));
 
@@ -83,6 +82,8 @@ gdata_calendar_query_class_init (GDataCalendarQueryClass *klass)
 	gobject_class->get_property = gdata_calendar_query_get_property;
 	gobject_class->finalize = gdata_calendar_query_finalize;
 
+	query_class->get_query_uri = get_query_uri;
+
 	/**
 	 * GDataCalendarQuery:future-events:
 	 *
@@ -296,6 +297,87 @@ gdata_calendar_query_set_property (GObject *object, guint property_id, const GVa
 	}
 }
 
+static void
+get_query_uri (GDataQuery *self, const gchar *feed_uri, GString *query_uri, gboolean *params_started)
+{
+	GDataCalendarQueryPrivate *priv = GDATA_CALENDAR_QUERY (self)->priv;
+
+	#define APPEND_SEP g_string_append_c (query_uri, (*params_started == FALSE) ? '?' : '&'); *params_started = TRUE;
+
+	/* Chain up to the parent class */
+	GDATA_QUERY_CLASS (gdata_calendar_query_parent_class)->get_query_uri (self, feed_uri, query_uri, params_started);
+
+	APPEND_SEP
+	if (priv->future_events == TRUE)
+		g_string_append (query_uri, "futureevents=true");
+	else
+		g_string_append (query_uri, "futureevents=false");
+
+	if (priv->order_by != NULL) {
+		APPEND_SEP
+		g_string_append (query_uri, "orderby=");
+		g_string_append_uri_escaped (query_uri, priv->order_by, NULL, TRUE);
+	}
+
+	if (priv->recurrence_expansion_start.tv_sec != 0 || priv->recurrence_expansion_start.tv_usec != 0) {
+		gchar *recurrence_expansion_start;
+
+		APPEND_SEP
+		g_string_append (query_uri, "recurrence-expansion-start=");
+		recurrence_expansion_start = g_time_val_to_iso8601 (&(priv->recurrence_expansion_start));
+		g_string_append (query_uri, recurrence_expansion_start);
+		g_free (recurrence_expansion_start);
+	}
+
+	if (priv->recurrence_expansion_end.tv_sec != 0 || priv->recurrence_expansion_end.tv_usec != 0) {
+		gchar *recurrence_expansion_end;
+
+		APPEND_SEP
+		g_string_append (query_uri, "recurrence-expansion-end=");
+		recurrence_expansion_end = g_time_val_to_iso8601 (&(priv->recurrence_expansion_end));
+		g_string_append (query_uri, recurrence_expansion_end);
+		g_free (recurrence_expansion_end);
+	}
+
+	APPEND_SEP
+	if (priv->single_events == TRUE)
+		g_string_append (query_uri, "singleevents=true");
+	else
+		g_string_append (query_uri, "singleevents=false");
+
+	if (priv->sort_order != NULL) {
+		APPEND_SEP
+		g_string_append (query_uri, "sortorder=");
+		g_string_append_uri_escaped (query_uri, priv->sort_order, NULL, TRUE);
+	}
+
+	if (priv->start_min.tv_sec != 0 || priv->start_min.tv_usec != 0) {
+		gchar *start_min;
+
+		APPEND_SEP
+		g_string_append (query_uri, "start-min=");
+		start_min = g_time_val_to_iso8601 (&(priv->start_min));
+		g_string_append (query_uri, start_min);
+		g_free (start_min);
+	}
+
+	if (priv->start_max.tv_sec != 0 || priv->start_max.tv_usec != 0) {
+		gchar *start_max;
+
+		APPEND_SEP
+		g_string_append (query_uri, "start-max=");
+		start_max = g_time_val_to_iso8601 (&(priv->start_max));
+		g_string_append (query_uri, start_max);
+		g_free (start_max);
+	}
+
+	if (priv->timezone != NULL) {
+		APPEND_SEP
+		g_string_append (query_uri, "ctz=");
+		g_string_append_uri_escaped (query_uri, priv->timezone, NULL, TRUE);
+	}
+}
+
 /**
  * gdata_calendar_query_new:
  * @q: a query string
@@ -653,6 +735,20 @@ gdata_calendar_query_set_timezone (GDataCalendarQuery *self, const gchar *_timez
 	g_return_if_fail (GDATA_IS_CALENDAR_QUERY (self));
 
 	g_free (self->priv->timezone);
-	self->priv->timezone = g_strdup (_timezone);
+
+	/* Replace all spaces with underscores */
+	if (_timezone != NULL) {
+		gchar *zone, *i;
+
+		zone = g_strdup (_timezone);
+		for (i = zone; *i != '\0'; i++) {
+			if (*i == ' ')
+				*i = '_';
+		}
+		self->priv->timezone = zone;
+	} else {
+		self->priv->timezone = NULL;
+	}
+
 	g_object_notify (G_OBJECT (self), "timezone");
 }
diff --git a/gdata/tests/calendar.c b/gdata/tests/calendar.c
index f59b848..9ebd977 100644
--- a/gdata/tests/calendar.c
+++ b/gdata/tests/calendar.c
@@ -372,6 +372,75 @@ test_xml_dates (void)
 	g_object_unref (event);
 }
 
+static void
+test_query_uri (void)
+{
+	GTimeVal time_val, time_val2;
+	gchar *query_uri;
+	GDataCalendarQuery *query = gdata_calendar_query_new ("q");
+
+	gdata_calendar_query_set_future_events (query, TRUE);
+	g_assert (gdata_calendar_query_get_future_events (query) == TRUE);
+
+	gdata_calendar_query_set_order_by (query, "starttime");
+	g_assert_cmpstr (gdata_calendar_query_get_order_by (query), ==, "starttime");
+
+	g_time_val_from_iso8601 ("2009-04-17T15:00:00.000Z", &time_val);
+	gdata_calendar_query_set_recurrence_expansion_start (query, &time_val);
+	gdata_calendar_query_get_recurrence_expansion_start (query, &time_val2);
+	g_assert_cmpint (time_val.tv_sec, ==, time_val2.tv_sec);
+	g_assert_cmpint (time_val.tv_usec, ==, time_val2.tv_usec);
+
+	g_time_val_from_iso8601 ("2010-04-17T15:00:00.000Z", &time_val);
+	gdata_calendar_query_set_recurrence_expansion_end (query, &time_val);
+	gdata_calendar_query_get_recurrence_expansion_end (query, &time_val2);
+	g_assert_cmpint (time_val.tv_sec, ==, time_val2.tv_sec);
+	g_assert_cmpint (time_val.tv_usec, ==, time_val2.tv_usec);
+
+	gdata_calendar_query_set_single_events (query, TRUE);
+	g_assert (gdata_calendar_query_get_single_events (query) == TRUE);
+
+	gdata_calendar_query_set_sort_order (query, "descending");
+	g_assert_cmpstr (gdata_calendar_query_get_sort_order (query), ==, "descending");
+
+	g_time_val_from_iso8601 ("2009-04-17T15:00:00.000Z", &time_val);
+	gdata_calendar_query_set_start_min (query, &time_val);
+	gdata_calendar_query_get_start_min (query, &time_val2);
+	g_assert_cmpint (time_val.tv_sec, ==, time_val2.tv_sec);
+	g_assert_cmpint (time_val.tv_usec, ==, time_val2.tv_usec);
+
+	g_time_val_from_iso8601 ("2010-04-17T15:00:00.000Z", &time_val);
+	gdata_calendar_query_set_start_max (query, &time_val);
+	gdata_calendar_query_get_start_max (query, &time_val2);
+	g_assert_cmpint (time_val.tv_sec, ==, time_val2.tv_sec);
+	g_assert_cmpint (time_val.tv_usec, ==, time_val2.tv_usec);
+
+	gdata_calendar_query_set_timezone (query, "America/Los Angeles");
+	g_assert_cmpstr (gdata_calendar_query_get_timezone (query), ==, "America/Los_Angeles");
+
+	/* Check the built query URI with a normal feed URI */
+	query_uri = gdata_query_get_query_uri (GDATA_QUERY (query), "http://example.com";);
+	g_assert_cmpstr (query_uri, ==, "http://example.com?q=q&futureevents=true&orderby=starttime&recurrence-expansion-start=2009-04-17T15:00:00Z";
+					"&recurrence-expansion-end=2010-04-17T15:00:00Z&singleevents=true&sortorder=descending"
+					"&start-min=2009-04-17T15:00:00Z&start-max=2010-04-17T15:00:00Z&ctz=America%2FLos_Angeles");
+	g_free (query_uri);
+
+	/* â?¦with a feed URI with a trailing slash */
+	query_uri = gdata_query_get_query_uri (GDATA_QUERY (query), "http://example.com/";);
+	g_assert_cmpstr (query_uri, ==, "http://example.com/?q=q&futureevents=true&orderby=starttime&recurrence-expansion-start=2009-04-17T15:00:00Z";
+					"&recurrence-expansion-end=2010-04-17T15:00:00Z&singleevents=true&sortorder=descending"
+					"&start-min=2009-04-17T15:00:00Z&start-max=2010-04-17T15:00:00Z&ctz=America%2FLos_Angeles");
+	g_free (query_uri);
+
+	/* â?¦with a feed URI with pre-existing arguments */
+	query_uri = gdata_query_get_query_uri (GDATA_QUERY (query), "http://example.com/bar/?test=test&this=that";);
+	g_assert_cmpstr (query_uri, ==, "http://example.com/bar/?test=test&this=that&q=q&futureevents=true&orderby=starttime";
+					"&recurrence-expansion-start=2009-04-17T15:00:00Z&recurrence-expansion-end=2010-04-17T15:00:00Z"
+					"&singleevents=true&sortorder=descending&start-min=2009-04-17T15:00:00Z&start-max=2010-04-17T15:00:00Z"
+					"&ctz=America%2FLos_Angeles");
+	g_free (query_uri);
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -395,6 +464,7 @@ main (int argc, char *argv[])
 	if (g_test_slow () == TRUE)
 		g_test_add_func ("/calendar/insert/simple", test_insert_simple);
 	g_test_add_func ("/calendar/xml/dates", test_xml_dates);
+	g_test_add_func ("/calendar/query/uri", test_query_uri);
 
 	retval = g_test_run ();
 	if (service != NULL)



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