[libgdata] freebase: Add Topic query API



commit f4635b25e2a5809f111f232c9f81d6b0a650dfcf
Author: Carlos Garnacho <carlosg gnome org>
Date:   Mon Mar 17 02:34:31 2014 +0100

    freebase: Add Topic query API
    
    With this API, structured data can be obtained about any Freebase
    ID, including localized text and references to images.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=726486

 Makefile.am                                        |    4 +
 docs/reference/gdata-docs.xml                      |    2 +
 docs/reference/gdata-sections.txt                  |   70 ++
 gdata/gdata.h                                      |    2 +
 gdata/gdata.symbols                                |   34 +
 gdata/services/freebase/gdata-freebase-service.c   |   62 ++
 gdata/services/freebase/gdata-freebase-service.h   |    7 +
 .../services/freebase/gdata-freebase-topic-query.c |  338 +++++++
 .../services/freebase/gdata-freebase-topic-query.h |   75 ++
 .../freebase/gdata-freebase-topic-result.c         | 1019 ++++++++++++++++++++
 .../freebase/gdata-freebase-topic-result.h         |  126 +++
 11 files changed, 1739 insertions(+), 0 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index e255abc..b2b685d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -309,6 +309,8 @@ gdatafreebaseincludedir = $(gdataincludedir)/services/freebase
 gdata_freebase_headers = \
        gdata/services/freebase/gdata-freebase-service.h                \
        gdata/services/freebase/gdata-freebase-result.h                 \
+       gdata/services/freebase/gdata-freebase-topic-query.h            \
+       gdata/services/freebase/gdata-freebase-topic-result.h           \
        gdata/services/freebase/gdata-freebase-query.h
 gdatafreebaseinclude_HEADERS =                                                 \
        $(gdata_freebase_headers)
@@ -424,6 +426,8 @@ gdata_sources = \
        \
        gdata/services/freebase/gdata-freebase-service.c                \
        gdata/services/freebase/gdata-freebase-result.c                 \
+       gdata/services/freebase/gdata-freebase-topic-query.c            \
+       gdata/services/freebase/gdata-freebase-topic-result.c           \
        gdata/services/freebase/gdata-freebase-query.c
 
 
diff --git a/docs/reference/gdata-docs.xml b/docs/reference/gdata-docs.xml
index fb1edd3..262ec28 100644
--- a/docs/reference/gdata-docs.xml
+++ b/docs/reference/gdata-docs.xml
@@ -189,6 +189,8 @@
                        <xi:include href="xml/gdata-freebase-service.xml"/>
                        <xi:include href="xml/gdata-freebase-query.xml"/>
                        <xi:include href="xml/gdata-freebase-result.xml"/>
+                       <xi:include href="xml/gdata-freebase-topic-query.xml"/>
+                       <xi:include href="xml/gdata-freebase-topic-result.xml"/>
                </chapter>
        </part>
 
diff --git a/docs/reference/gdata-sections.txt b/docs/reference/gdata-sections.txt
index 0c452aa..4cc4604 100644
--- a/docs/reference/gdata-sections.txt
+++ b/docs/reference/gdata-sections.txt
@@ -2575,6 +2575,8 @@ gdata_freebase_service_new
 gdata_freebase_service_get_primary_authorization_domain
 gdata_freebase_service_query
 gdata_freebase_service_query_async
+gdata_freebase_service_get_topic
+gdata_freebase_service_get_topic_async
 <SUBSECTION Standard>
 gdata_freebase_service_get_type
 GDATA_FREEBASE_SERVICE
@@ -2624,3 +2626,71 @@ GDATA_TYPE_FREEBASE_RESULT
 <SUBSECTION Private>
 GDataFreebaseResultPrivate
 </SECTION>
+
+<SECTION>
+<FILE>gdata-freebase-topic-query</FILE>
+<TITLE>GDataFreebaseTopicQuery</TITLE>
+GDataFreebaseTopicQuery
+GDataFreebaseTopicQueryClass
+gdata_freebase_topic_query_new
+gdata_freebase_topic_query_set_filter
+gdata_freebase_topic_query_get_filter
+gdata_freebase_topic_query_set_language
+gdata_freebase_topic_query_get_language
+<SUBSECTION Standard>
+gdata_freebase_topic_query_get_type
+GDATA_FREEBASE_TOPIC_QUERY
+GDATA_FREEBASE_TOPIC_QUERY_CLASS
+GDATA_FREEBASE_TOPIC_QUERY_GET_CLASS
+GDATA_IS_FREEBASE_TOPIC_QUERY
+GDATA_IS_FREEBASE_TOPIC_QUERY_CLASS
+GDATA_TYPE_FREEBASE_TOPIC_QUERY
+<SUBSECTION Private>
+GDataFreebaseTopicQueryPrivate
+</SECTION>
+
+<SECTION>
+<FILE>gdata-freebase-topic-result</FILE>
+<TITLE>GDataFreebaseTopicResult</TITLE>
+GDataFreebaseTopicResult
+GDataFreebaseTopicResultClass
+gdata_freebase_topic_result_new
+gdata_freebase_topic_result_dup_object
+GDataFreebaseTopicObject
+gdata_freebase_topic_object_ref
+gdata_freebase_topic_object_unref
+gdata_freebase_topic_object_list_properties
+gdata_freebase_topic_object_get_id
+gdata_freebase_topic_object_get_property_count
+gdata_freebase_topic_object_get_property_hits
+gdata_freebase_topic_object_get_property_value
+GDataFreebaseTopicValue
+gdata_freebase_topic_value_ref
+gdata_freebase_topic_value_unref
+gdata_freebase_topic_value_get_property
+gdata_freebase_topic_value_get_text
+gdata_freebase_topic_value_get_language
+gdata_freebase_topic_value_get_creator
+gdata_freebase_topic_value_get_timestamp
+gdata_freebase_topic_value_get_value_type
+gdata_freebase_topic_value_copy_value
+gdata_freebase_topic_value_get_int
+gdata_freebase_topic_value_get_double
+gdata_freebase_topic_value_get_string
+gdata_freebase_topic_value_get_object
+gdata_freebase_topic_value_is_image
+<SUBSECTION Standard>
+gdata_freebase_topic_result_get_type
+gdata_freebase_topic_object_get_type
+gdata_freebase_topic_value_get_type
+GDATA_FREEBASE_TOPIC_RESULT
+GDATA_FREEBASE_TOPIC_RESULT_CLASS
+GDATA_FREEBASE_TOPIC_RESULT_GET_CLASS
+GDATA_IS_FREEBASE_TOPIC_RESULT
+GDATA_IS_FREEBASE_TOPIC_RESULT_CLASS
+GDATA_TYPE_FREEBASE_TOPIC_RESULT
+GDATA_TYPE_FREEBASE_TOPIC_OBJECT
+GDATA_TYPE_FREEBASE_TOPIC_VALUE
+<SUBSECTION Private>
+GDataFreebaseTopicResultPrivate
+</SECTION>
diff --git a/gdata/gdata.h b/gdata/gdata.h
index 7c43d4c..579ecad 100644
--- a/gdata/gdata.h
+++ b/gdata/gdata.h
@@ -147,5 +147,7 @@
 #include <gdata/services/freebase/gdata-freebase-service.h>
 #include <gdata/services/freebase/gdata-freebase-query.h>
 #include <gdata/services/freebase/gdata-freebase-result.h>
+#include <gdata/services/freebase/gdata-freebase-topic-query.h>
+#include <gdata/services/freebase/gdata-freebase-topic-result.h>
 
 #endif /* !GDATA_H */
diff --git a/gdata/gdata.symbols b/gdata/gdata.symbols
index b996686..b149eb6 100644
--- a/gdata/gdata.symbols
+++ b/gdata/gdata.symbols
@@ -1024,9 +1024,43 @@ gdata_freebase_service_get_type
 gdata_freebase_service_new
 gdata_freebase_service_query
 gdata_freebase_service_query_async
+gdata_freebase_service_get_topic
+gdata_freebase_service_get_topic_async
 gdata_freebase_query_get_type
 gdata_freebase_query_new
 gdata_freebase_query_new_from_variant
+gdata_freebase_topic_query_get_type
+gdata_freebase_topic_query_new
+gdata_freebase_topic_query_set_filter
+gdata_freebase_topic_query_get_filter
+gdata_freebase_topic_query_set_language
+gdata_freebase_topic_query_get_language
+gdata_freebase_topic_object_get_type
+gdata_freebase_topic_object_ref
+gdata_freebase_topic_object_unref
+gdata_freebase_topic_object_list_properties
+gdata_freebase_topic_object_get_id
+gdata_freebase_topic_object_get_property_count
+gdata_freebase_topic_object_get_property_hits
+gdata_freebase_topic_object_get_property_value
+gdata_freebase_topic_value_get_type
+gdata_freebase_topic_value_ref
+gdata_freebase_topic_value_unref
+gdata_freebase_topic_value_get_property
+gdata_freebase_topic_value_get_text
+gdata_freebase_topic_value_get_language
+gdata_freebase_topic_value_get_creator
+gdata_freebase_topic_value_get_timestamp
+gdata_freebase_topic_value_get_value_type
+gdata_freebase_topic_value_copy_value
+gdata_freebase_topic_value_get_int
+gdata_freebase_topic_value_get_double
+gdata_freebase_topic_value_get_string
+gdata_freebase_topic_value_get_object
+gdata_freebase_topic_value_is_image
+gdata_freebase_topic_result_get_type
+gdata_freebase_topic_result_new
+gdata_freebase_topic_result_dup_object
 gdata_freebase_result_error_get_type
 gdata_freebase_result_error_quark
 gdata_freebase_result_get_type
diff --git a/gdata/services/freebase/gdata-freebase-service.c 
b/gdata/services/freebase/gdata-freebase-service.c
index f4006db..96e1a1e 100644
--- a/gdata/services/freebase/gdata-freebase-service.c
+++ b/gdata/services/freebase/gdata-freebase-service.c
@@ -253,3 +253,65 @@ gdata_freebase_service_query_async (GDataFreebaseService *self, GDataFreebaseQue
        gdata_service_query_single_entry_async (GDATA_SERVICE (self), get_freebase_authorization_domain (), 
"mqlread",
                                                GDATA_QUERY (query), GDATA_TYPE_FREEBASE_RESULT, cancellable, 
callback, user_data);
 }
+
+/**
+ * gdata_freebase_service_get_topic:
+ * @self: a #GDataFreebaseService
+ * @query: a #GDataFreebaseTopicQuery containing the topic ID
+ * @cancellable: (allow-none): optional #GCancellable object, or %NULL
+ * @error: (allow-none): a #GError, or %NULL
+ *
+ * Queries information about a topic, identified through a Freebase ID. You can find out more about topic 
queries in the
+ * <ulink type="http" url="https://developers.google.com/freebase/v1/topic-response";>online 
documentation</ulink>.
+ *
+ * Return value: (transfer full): a #GDataFreebaseTopicResult containing information about the topic; unref 
with g_object_unref()
+ *
+ * Since: UNRELEASED
+ */
+GDataFreebaseTopicResult *
+gdata_freebase_service_get_topic (GDataFreebaseService *self, GDataFreebaseTopicQuery *query, GCancellable 
*cancellable, GError **error)
+{
+       GDataEntry *entry;
+
+       g_return_val_if_fail (GDATA_IS_FREEBASE_SERVICE (self), NULL);
+       g_return_val_if_fail (GDATA_IS_FREEBASE_TOPIC_QUERY (query), NULL);
+       g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
+       g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+       entry = gdata_service_query_single_entry (GDATA_SERVICE (self), get_freebase_authorization_domain (), 
"topic",
+                                                 GDATA_QUERY (query), GDATA_TYPE_FREEBASE_TOPIC_RESULT, 
cancellable, error);
+       if (entry == NULL)
+               return NULL;
+
+       return GDATA_FREEBASE_TOPIC_RESULT (entry);
+}
+
+/**
+ * gdata_freebase_service_get_topic_async:
+ * @self: a #GDataFreebaseService
+ * @query: a #GDataFreebaseQuery with the MQL query
+ * @cancellable: (allow-none): optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when authentication is finished
+ * @user_data: (closure): data to pass to the @callback function
+ *
+ * Queries information about a topic, identified through a Freebase ID. @self and @query are all reffed when 
this
+ * function is called, so can safely be unreffed after this function returns. When the query is replied, or 
fails,
+ * @callback will be executed, and the result can be obtained through 
gdata_service_query_single_entry_finish().
+ *
+ * For more details, see gdata_freebase_service_get_topic(), which is the synchronous version of
+ * this function.
+ *
+ * Since: UNRELEASED
+ */
+void
+gdata_freebase_service_get_topic_async (GDataFreebaseService *self, GDataFreebaseTopicQuery *query,
+                                       GCancellable *cancellable, GAsyncReadyCallback callback, gpointer 
user_data)
+{
+       g_return_if_fail (GDATA_IS_FREEBASE_SERVICE (self));
+       g_return_if_fail (GDATA_IS_FREEBASE_TOPIC_QUERY (query));
+       g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+       g_return_if_fail (callback != NULL);
+
+       gdata_service_query_single_entry_async (GDATA_SERVICE (self), get_freebase_authorization_domain (), 
"topic",
+                                               GDATA_QUERY (query), GDATA_TYPE_FREEBASE_RESULT, cancellable, 
callback, user_data);
+}
diff --git a/gdata/services/freebase/gdata-freebase-service.h 
b/gdata/services/freebase/gdata-freebase-service.h
index 1ccce64..af553bb 100644
--- a/gdata/services/freebase/gdata-freebase-service.h
+++ b/gdata/services/freebase/gdata-freebase-service.h
@@ -28,6 +28,8 @@
 #include <gdata/gdata-download-stream.h>
 #include "gdata-freebase-query.h"
 #include "gdata-freebase-result.h"
+#include "gdata-freebase-topic-query.h"
+#include "gdata-freebase-topic-result.h"
 
 G_BEGIN_DECLS
 
@@ -76,6 +78,11 @@ GDataFreebaseResult *gdata_freebase_service_query (GDataFreebaseService *self, G
 void gdata_freebase_service_query_async (GDataFreebaseService *self, GDataFreebaseQuery *query,
                                         GCancellable *cancellable, GAsyncReadyCallback callback, gpointer 
user_data);
 
+GDataFreebaseTopicResult *gdata_freebase_service_get_topic (GDataFreebaseService *self, 
GDataFreebaseTopicQuery *query,
+                                                           GCancellable *cancellable, GError **error) 
G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
+void gdata_freebase_service_get_topic_async (GDataFreebaseService *self, GDataFreebaseTopicQuery *query,
+                                            GCancellable *cancellable, GAsyncReadyCallback callback, 
gpointer user_data);
+
 G_END_DECLS
 
 #endif /* !GDATA_FREEBASE_SERVICE_H */
diff --git a/gdata/services/freebase/gdata-freebase-topic-query.c 
b/gdata/services/freebase/gdata-freebase-topic-query.c
new file mode 100644
index 0000000..1fddd1d
--- /dev/null
+++ b/gdata/services/freebase/gdata-freebase-topic-query.c
@@ -0,0 +1,338 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * GData Client
+ * Copyright (C) 2014 Carlos Garnacho <carlosg gnome org>
+ *
+ * GData Client is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GData Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GData Client.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION:gdata-freebase-topic-query
+ * @short_description: GData Freebase topic query object
+ * @stability: Unstable
+ * @include: gdata/services/freebase/gdata-freebase-topic-query.h
+ *
+ * #GDataFreebaseTopicQuery represents a Freebase topic query. The topic query happens on a single Freebase 
ID,
+ * given in gdata_freebase_topic_query_new(), the reply returns all known information in Freebase for that 
given ID.
+ * For more documentation and examples, see the <ulink type="http" 
url="https://developers.google.com/freebase/v1/topic-response";>
+ * Topic response API documentation</ulink>
+ *
+ * This implementation of #GDataQuery respects the gdata_query_set_max_results() and 
gdata_query_set_updated_max() calls.
+ *
+ * For more details of Google Freebase API, see the <ulink type="http" 
url="https://developers.google.com/freebase/v1/";>
+ * online documentation</ulink>.
+ *
+ * Since: UNRELEASED
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <string.h>
+#include <json-glib/json-glib.h>
+
+#include "gdata-freebase-topic-query.h"
+#include "gdata-query.h"
+#include "gdata-parser.h"
+
+static void gdata_freebase_topic_query_finalize (GObject *self);
+static void gdata_freebase_topic_query_set_property (GObject *self, guint prop_id, const GValue *value, 
GParamSpec *pspec);
+static void gdata_freebase_topic_query_get_property (GObject *self, guint prop_id, GValue *value, GParamSpec 
*pspec);
+static void get_query_uri (GDataQuery *self, const gchar *feed_uri, GString *query_uri, gboolean 
*params_started);
+
+struct _GDataFreebaseTopicQueryPrivate {
+       gchar *lang;
+       gchar **filter;
+};
+
+enum {
+       PROP_LANGUAGE = 1,
+       PROP_FILTER
+};
+
+G_DEFINE_TYPE (GDataFreebaseTopicQuery, gdata_freebase_topic_query, GDATA_TYPE_QUERY)
+
+static void
+gdata_freebase_topic_query_class_init (GDataFreebaseTopicQueryClass *klass)
+{
+       GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+       GDataQueryClass *query_class = GDATA_QUERY_CLASS (klass);
+
+       g_type_class_add_private (klass, sizeof (GDataFreebaseTopicQueryPrivate));
+
+       gobject_class->finalize = gdata_freebase_topic_query_finalize;
+       gobject_class->set_property = gdata_freebase_topic_query_set_property;
+       gobject_class->get_property = gdata_freebase_topic_query_get_property;
+
+       query_class->get_query_uri = get_query_uri;
+
+       /**
+        * GDataFreebaseTopicQuery:language:
+        *
+        * Language used for topic values in the result, in ISO-639-1 format.
+        *
+        * Since: UNRELEASED
+        */
+       g_object_class_install_property (gobject_class, PROP_LANGUAGE,
+                                        g_param_spec_string ("language",
+                                                             "Language used for results",
+                                                             "Language in ISO-639-1 format.",
+                                                             NULL,
+                                                             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+       /**
+        * GDataFreebaseTopicQuery:filter:
+        *
+        * Array of properties (eg. "/common/topic/description", or "/computer/software/first_released"), or 
property
+        * domains (eg. "/common/topic", or "/computer") to be used as filter.
+        *
+        * Since: UNRELEASED
+        */
+       g_object_class_install_property (gobject_class, PROP_FILTER,
+                                        g_param_spec_boxed ("filter",
+                                                            "Filter",
+                                                            "Property domain to be used as filter",
+                                                            G_TYPE_STRV,
+                                                            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gdata_freebase_topic_query_init (GDataFreebaseTopicQuery *self)
+{
+       self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_FREEBASE_TOPIC_QUERY, 
GDataFreebaseTopicQueryPrivate);
+}
+
+static void
+gdata_freebase_topic_query_finalize (GObject *self)
+{
+       GDataFreebaseTopicQueryPrivate *priv = GDATA_FREEBASE_TOPIC_QUERY (self)->priv;
+
+       g_free (priv->lang);
+       g_free (priv->filter);
+
+       /* Chain up to the parent class */
+       G_OBJECT_CLASS (gdata_freebase_topic_query_parent_class)->finalize (self);
+}
+
+static void
+gdata_freebase_topic_query_set_property (GObject *self, guint prop_id, const GValue *value, GParamSpec 
*pspec)
+{
+       GDataFreebaseTopicQuery *query = GDATA_FREEBASE_TOPIC_QUERY (self);
+
+       switch (prop_id) {
+       case PROP_LANGUAGE:
+               gdata_freebase_topic_query_set_language (query, g_value_get_string (value));
+               break;
+       case PROP_FILTER:
+               gdata_freebase_topic_query_set_filter (query, g_value_get_boxed (value));
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+gdata_freebase_topic_query_get_property (GObject *self, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+       GDataFreebaseTopicQueryPrivate *priv = GDATA_FREEBASE_TOPIC_QUERY (self)->priv;
+
+       switch (prop_id) {
+       case PROP_LANGUAGE:
+               g_value_set_string (value, priv->lang);
+               break;
+       case PROP_FILTER:
+               g_value_set_boxed (value, priv->filter);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+get_query_uri (GDataQuery *self, const gchar *feed_uri, GString *query_uri, gboolean *params_started)
+{
+       GDataFreebaseTopicQueryPrivate *priv = GDATA_FREEBASE_TOPIC_QUERY (self)->priv;
+       const gchar *lang = NULL;
+       gint64 updated_max;
+       guint limit;
+
+       g_string_append (query_uri, gdata_query_get_q (self));
+
+#define APPEND_SEP g_string_append_c (query_uri, (*params_started == FALSE) ? '?' : '&'); *params_started = 
TRUE;
+
+       if (priv->lang != NULL) {
+               lang = priv->lang;
+       } else {
+               const gchar * const *user_languages;
+               guint i;
+
+               user_languages = g_get_language_names ();
+
+               /* Pick the first user language */
+               for (i = 0; user_languages[i] != NULL; i++) {
+                       if (strlen (user_languages[i]) == 2) {
+                               lang = user_languages[i];
+                               break;
+                       }
+               }
+       }
+
+       APPEND_SEP;
+       g_string_append (query_uri, "lang=");
+       g_string_append (query_uri, lang);
+
+       if (priv->filter) {
+               guint i;
+
+               for (i = 0; priv->filter[i] != NULL; i++) {
+                       APPEND_SEP;
+                       g_string_append (query_uri, "filter=");
+                       g_string_append (query_uri, priv->filter[i]);
+               }
+       }
+
+       updated_max = gdata_query_get_updated_max (self);
+
+       if (updated_max > -1) {
+               APPEND_SEP;
+               g_string_append_printf (query_uri, "dateline=%" G_GINT64_FORMAT, updated_max);
+       }
+
+       limit = gdata_query_get_max_results (self);
+
+       if (limit > 0) {
+               APPEND_SEP;
+               g_string_append_printf (query_uri, "limit=%d", limit);
+       }
+
+       /* We don't chain up with parent class get_query_uri because it uses
+        *  GData protocol parameters and they aren't compatible with newest API family
+        */
+#undef APPEND_SEP
+}
+
+/**
+ * gdata_freebase_topic_query_new:
+ * @id: a Freebase ID or MID
+ *
+ * Creates a new #GDataFreebaseTopicQuery for the given Freebase ID. Those can be
+ * obtained programmatically through gdata_freebase_search_result_item_get_id() or
+ * embedded in the result of a gdata_freebase_service_query() call.
+ *
+ * Return value: (transfer full): a new #GDataFreebaseTopicQuery
+ *
+ * Since: UNRELEASED
+ */
+GDataFreebaseTopicQuery *
+gdata_freebase_topic_query_new (const gchar *id)
+{
+       g_return_val_if_fail (id != NULL, NULL);
+       return g_object_new (GDATA_TYPE_FREEBASE_TOPIC_QUERY, "q", id, NULL);
+}
+
+/**
+ * gdata_freebase_topic_query_set_language:
+ * @self: a #GDataFreebaseTopicQuery
+ * @lang: (allow-none): language used on the topic query, in ISO-639-1 format, or %NULL to unset the language
+ *
+ * Sets the language used in the topic query. If unset,
+ * the locale preferences will be respected.
+ *
+ * Since: UNRELEASED
+ **/
+void
+gdata_freebase_topic_query_set_language (GDataFreebaseTopicQuery *self,
+                                        const gchar             *lang)
+{
+       GDataFreebaseTopicQueryPrivate *priv;
+
+       g_return_if_fail (GDATA_IS_FREEBASE_TOPIC_QUERY (self));
+       g_return_if_fail (lang == NULL || strlen (lang) == 2);
+
+       priv = self->priv;
+
+       if (g_strcmp0 (priv->lang, lang) == 0)
+               return;
+
+       g_free (priv->lang);
+       priv->lang = g_strdup (lang);
+       g_object_notify (G_OBJECT (self), "language");
+}
+
+/**
+ * gdata_freebase_topic_query_get_language:
+ * @self: a #GDataFreebaseTopicQuery
+ *
+ * Gets the language set on the topic query, or %NULL if unset.
+ *
+ * Return value: (allow-none): The language used on the query.
+ *
+ * Since: UNRELEASED
+ **/
+const gchar *
+gdata_freebase_topic_query_get_language (GDataFreebaseTopicQuery *self)
+{
+       g_return_val_if_fail (GDATA_IS_FREEBASE_TOPIC_QUERY (self), NULL);
+
+       return self->priv->lang;
+}
+
+/**
+ * gdata_freebase_topic_query_set_filter:
+ * @self: a #GDataFreebaseTopicQuery
+ * @filter:  (array zero-terminated=1) (allow-none): %NULL-terminated array of filter strings, or %NULL to 
unset
+ *
+ * Sets a filter on the properties to be returned by the #GDataFreebaseTopicQuery, a filter string usually 
contains either
+ * a specific property (eg. "/common/topic/description", or "/computer/software/first_released"), or a 
property domain
+ * (eg. "/common/topic", or "/computer"), all properties pertaining to the domain will be returned through 
the
+ * #GDataFreebaseTopicResult in the latter case. Other special strings can be passed as filter strings, 
those are documented
+ * in the <ulink type="http" url="https://developers.google.com/freebase/v1/topic-overview#filter";>Topic API 
overview</ulink>
+ *
+ * If multiple filter strings are set, the result will contain all information necessary to satisfy each of 
those individually.
+ * If no filter is set, the "commons" special value will be implicitly assumed, which returns a reasonably 
complete data set.
+ *
+ * Since: UNRELEASED
+ **/
+void
+gdata_freebase_topic_query_set_filter (GDataFreebaseTopicQuery *self, const gchar * const *filter)
+{
+       GDataFreebaseTopicQueryPrivate *priv;
+
+       g_return_if_fail (GDATA_IS_FREEBASE_TOPIC_QUERY (self));
+       priv = self->priv;
+
+       g_strfreev (priv->filter);
+       priv->filter = g_strdupv ((gchar **) filter);
+       g_object_notify (G_OBJECT (self), "filter");
+}
+
+/**
+ * gdata_freebase_topic_query_get_filter:
+ * @self: a #GDataFreebaseTopicQuery
+ *
+ * Gets the filter set on the topic query, or %NULL if unset.
+ *
+ * Return value: (array zero-terminated=1) (transfer none) (allow-none): The filter used on the query.
+ *
+ * Since: UNRELEASED
+ **/
+const gchar * const *
+gdata_freebase_topic_query_get_filter (GDataFreebaseTopicQuery *self)
+{
+       g_return_val_if_fail (GDATA_IS_FREEBASE_TOPIC_QUERY (self), NULL);
+
+       return (const gchar * const *) self->priv->filter;
+}
diff --git a/gdata/services/freebase/gdata-freebase-topic-query.h 
b/gdata/services/freebase/gdata-freebase-topic-query.h
new file mode 100644
index 0000000..1f1053a
--- /dev/null
+++ b/gdata/services/freebase/gdata-freebase-topic-query.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * GData Client
+ * Copyright (C) 2014 Carlos Garnacho <carlosg gnome org>
+ *
+ * GData Client is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GData Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GData Client.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GDATA_FREEBASE_TOPIC_QUERY_H
+#define GDATA_FREEBASE_TOPIC_QUERY_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gdata/gdata-query.h>
+#include <gdata/gdata-types.h>
+
+G_BEGIN_DECLS
+
+#define GDATA_TYPE_FREEBASE_TOPIC_QUERY                        (gdata_freebase_topic_query_get_type ())
+#define GDATA_FREEBASE_TOPIC_QUERY(o)                  (G_TYPE_CHECK_INSTANCE_CAST ((o), 
GDATA_TYPE_FREEBASE_TOPIC_QUERY, GDataFreebaseTopicQuery))
+#define GDATA_FREEBASE_TOPIC_QUERY_CLASS(k)            (G_TYPE_CHECK_CLASS_CAST((k), 
GDATA_TYPE_FREEBASE_TOPIC_QUERY, GDataFreebaseTopicQueryClass))
+#define GDATA_IS_FREEBASE_TOPIC_QUERY(o)               (G_TYPE_CHECK_INSTANCE_TYPE ((o), 
GDATA_TYPE_FREEBASE_TOPIC_QUERY))
+#define GDATA_IS_FREEBASE_TOPIC_QUERY_CLASS(k)         (G_TYPE_CHECK_CLASS_TYPE ((k), 
GDATA_TYPE_FREEBASE_TOPIC_QUERY))
+#define GDATA_FREEBASE_TOPIC_QUERY_GET_CLASS(o)                (G_TYPE_INSTANCE_GET_CLASS ((o), 
GDATA_TYPE_FREEBASE_TOPIC_QUERY, GDataFreebaseTopicQueryClass))
+
+typedef struct _GDataFreebaseTopicQueryPrivate GDataFreebaseTopicQueryPrivate;
+
+/**
+ * GDataFreebaseTopicQuery:
+ *
+ * All the fields in the #GDataFreebaseTopicQuery structure are private and should never be accessed 
directly.
+ *
+ * Since: UNRELEASED
+ */
+typedef struct {
+       GDataQuery parent;
+       GDataFreebaseTopicQueryPrivate *priv;
+} GDataFreebaseTopicQuery;
+
+/**
+ * GDataFreebaseTopicQueryClass:
+ *
+ * All the fields in the #GDataFreebaseTopicQueryClass structure are private and should never be accessed 
directly.
+ *
+ * Since: UNRELEASED
+ */
+typedef struct {
+       /*< private >*/
+       GDataQueryClass parent;
+} GDataFreebaseTopicQueryClass;
+
+GType gdata_freebase_topic_query_get_type (void) G_GNUC_CONST;
+
+GDataFreebaseTopicQuery *gdata_freebase_topic_query_new (const gchar *id) G_GNUC_WARN_UNUSED_RESULT 
G_GNUC_MALLOC;
+void gdata_freebase_topic_query_set_language (GDataFreebaseTopicQuery *self, const gchar *lang);
+const gchar *gdata_freebase_topic_query_get_language (GDataFreebaseTopicQuery *self);
+
+void gdata_freebase_topic_query_set_filter (GDataFreebaseTopicQuery *self, const gchar * const *filter);
+const gchar * const *gdata_freebase_topic_query_get_filter (GDataFreebaseTopicQuery *self);
+
+G_END_DECLS
+
+#endif /* !GDATA_FREEBASE_TOPIC_QUERY_H */
diff --git a/gdata/services/freebase/gdata-freebase-topic-result.c 
b/gdata/services/freebase/gdata-freebase-topic-result.c
new file mode 100644
index 0000000..5357bbb
--- /dev/null
+++ b/gdata/services/freebase/gdata-freebase-topic-result.c
@@ -0,0 +1,1019 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * GData Client
+ * Copyright (C) 2014 Carlos Garnacho <carlosg gnome org>
+ *
+ * GData Client is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GData Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GData Client.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION:gdata-freebase-topic-result
+ * @short_description: GData Freebase topic result object
+ * @stability: Unstable
+ * @include: gdata/services/freebase/gdata-freebase-topic-result.h
+ *
+ * #GDataFreebaseTopicResult is a subclass of #GDataFreebaseResult that contains all or a subset of the 
information
+ * contained in Freebase about the Freebase ID given to the #GDataFreebaseTopicQuery.
+ *
+ * For more details of Google Freebase API, see the <ulink type="http" 
url="https://developers.google.com/freebase/v1/";>
+ * online documentation</ulink>.
+ *
+ * Since: UNRELEASED
+ */
+
+typedef struct _GDataFreebaseTopicValueArray GDataFreebaseTopicValueArray;
+
+#include <config.h>
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <string.h>
+
+#include "gdata-freebase-topic-result.h"
+#include "gdata-download-stream.h"
+#include "gdata-private.h"
+#include "gdata-types.h"
+
+typedef enum {
+       TYPE_NONE,
+       TYPE_BOOL,
+       TYPE_INT,
+       TYPE_DOUBLE,
+       TYPE_STRING,
+       TYPE_DATETIME,
+       TYPE_COMPOUND,
+       TYPE_OBJECT,
+       TYPE_KEY,
+       TYPE_URI
+} TopicValueType;
+
+/* Wraps a compound object, either the main object returned by the result, or a
+ * complex object within the result values (events are at least composed of
+ * location and time at least, for example).
+ */
+struct _GDataFreebaseTopicObject {
+       gchar *id;
+       GHashTable *values; /* Hashtable of property->GDataFreebaseTopicValueArray */
+       volatile gint ref_count;
+};
+
+/* Wraps an array of values, single-valued properties will contain an array with a single value here */
+struct _GDataFreebaseTopicValueArray {
+       TopicValueType type;
+       GPtrArray *values;
+       guint64 hits; /* Total number of hits, as opposed to values->len */
+};
+
+/* Wraps a single value in the topic result, may be either simple (numbers, strings, Freebase IDs...),
+ * or nested compound types (contained by a GDataFreebaseTopicObject, which is what the value would
+ * contain in that case).
+ */
+struct _GDataFreebaseTopicValue {
+       gchar *property;
+       gchar *text;
+       gchar *lang;
+       gchar *creator;
+       gint64 timestamp;
+       GValue value;
+       gint ref_count;
+};
+
+struct _GDataFreebaseTopicResultPrivate {
+       GDataFreebaseTopicObject *object;
+};
+
+static void gdata_freebase_topic_result_finalize (GObject *self);
+static gboolean parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error);
+static GDataFreebaseTopicObject *object_new (const gchar *id);
+static void value_free (GDataFreebaseTopicValue *object);
+static gboolean reader_get_properties (JsonReader *reader, GDataFreebaseTopicObject *object, GError **error);
+
+G_DEFINE_BOXED_TYPE (GDataFreebaseTopicObject, gdata_freebase_topic_object, gdata_freebase_topic_object_ref, 
gdata_freebase_topic_object_unref)
+G_DEFINE_BOXED_TYPE (GDataFreebaseTopicValue, gdata_freebase_topic_value, gdata_freebase_topic_value_ref, 
gdata_freebase_topic_value_unref)
+G_DEFINE_TYPE (GDataFreebaseTopicResult, gdata_freebase_topic_result, GDATA_TYPE_FREEBASE_RESULT)
+
+static void
+gdata_freebase_topic_result_class_init (GDataFreebaseTopicResultClass *klass)
+{
+       GDataParsableClass *parsable_class = GDATA_PARSABLE_CLASS (klass);
+       GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+       g_type_class_add_private (klass, sizeof (GDataFreebaseTopicResultPrivate));
+
+       gobject_class->finalize = gdata_freebase_topic_result_finalize;
+       parsable_class->parse_json = parse_json;
+}
+
+static void
+gdata_freebase_topic_result_init (GDataFreebaseTopicResult *self)
+{
+       self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_FREEBASE_TOPIC_RESULT, 
GDataFreebaseTopicResultPrivate);
+}
+
+static void
+gdata_freebase_topic_result_finalize (GObject *self)
+{
+       GDataFreebaseTopicResultPrivate *priv = GDATA_FREEBASE_TOPIC_RESULT (self)->priv;
+
+       gdata_freebase_topic_object_unref (priv->object);
+
+       G_OBJECT_CLASS (gdata_freebase_topic_result_parent_class)->finalize (self);
+}
+
+static GDataFreebaseTopicValueArray *
+value_array_new (TopicValueType type, guint64 hits)
+{
+       GDataFreebaseTopicValueArray *array;
+
+       array = g_slice_new0 (GDataFreebaseTopicValueArray);
+       array->values = g_ptr_array_new_with_free_func ((GDestroyNotify) gdata_freebase_topic_value_unref);
+       array->type = type;
+       array->hits = hits;
+
+       return array;
+}
+
+/* Takes ownership on @value */
+static void
+value_array_add (GDataFreebaseTopicValueArray *array, GDataFreebaseTopicValue *value)
+{
+       g_ptr_array_add (array->values, value);
+}
+
+static void
+value_array_free (GDataFreebaseTopicValueArray *array)
+{
+       g_ptr_array_unref (array->values);
+       g_slice_free (GDataFreebaseTopicValueArray, array);
+}
+
+static guint64
+reader_get_item_count (JsonReader *reader)
+{
+       gint64 count;
+
+       json_reader_read_member (reader, "count");
+       count = json_reader_get_int_value (reader);
+       json_reader_end_member (reader);
+
+       return (guint64) count;
+}
+
+static guint
+reader_get_value_type (JsonReader *reader, const gchar *property, GError **error)
+{
+       TopicValueType type = TYPE_NONE;
+       const GError *reader_error;
+       const gchar *valuestr;
+
+       json_reader_read_member (reader, "valuetype");
+       valuestr = json_reader_get_string_value (reader);
+
+       reader_error = json_reader_get_error (reader);
+
+       if (reader_error != NULL) {
+               if (error != NULL && *error == NULL)
+                       *error = g_error_copy (reader_error);
+       } else {
+               if (strcmp (valuestr, "key") == 0)
+                       type = TYPE_KEY;
+               else if (strcmp (valuestr, "uri") == 0)
+                       type = TYPE_URI;
+               else if (strcmp (valuestr, "compound") == 0)
+                       type = TYPE_COMPOUND;
+               else if (strcmp (valuestr, "object") == 0)
+                       type = TYPE_OBJECT;
+               else if (strcmp (valuestr, "float") == 0)
+                       type = TYPE_DOUBLE;
+               else if (strcmp (valuestr, "string") == 0)
+                       type = TYPE_STRING;
+               else if (strcmp (valuestr, "int") == 0)
+                       type = TYPE_INT;
+               else if (strcmp (valuestr, "bool") == 0)
+                       type = TYPE_BOOL;
+               else if (strcmp (valuestr, "datetime") == 0)
+                       type = TYPE_DATETIME;
+               else
+                       gdata_parser_error_required_json_content_missing (reader, error);
+       }
+
+       json_reader_end_member (reader);
+       return type;
+}
+
+static void
+value_free (GDataFreebaseTopicValue *value)
+{
+       if (G_IS_VALUE (&value->value))
+               g_value_unset (&value->value);
+       g_free (value->text);
+       g_free (value->lang);
+       g_free (value->creator);
+       g_free (value->property);
+       g_slice_free (GDataFreebaseTopicValue, value);
+}
+
+/* Parsing functions to create GDataFreebaseTopicValues, and arrays of those */
+static gchar *
+reader_dup_member_string (JsonReader *reader, const gchar *member, GError **error)
+{
+       const GError *reader_error;
+       gchar *str;
+
+       if (error != NULL && *error != NULL)
+               return NULL;
+
+       json_reader_read_member (reader, member);
+       str = g_strdup (json_reader_get_string_value (reader));
+       reader_error = json_reader_get_error (reader);
+
+       if (reader_error != NULL) {
+               g_free (str);
+               str = NULL;
+
+               if (error != NULL)
+                       *error = g_error_copy (reader_error);
+       }
+
+       json_reader_end_member (reader);
+
+       return str;
+}
+
+static gint64
+reader_parse_timestamp (JsonReader *reader, const gchar *member, GError **error)
+{
+       const GError *reader_error;
+       const gchar *date_str;
+       gint64 timestamp = -1;
+
+       if (error != NULL && *error != NULL)
+               return -1;
+
+       json_reader_read_member (reader, member);
+       date_str = json_reader_get_string_value (reader);
+       reader_error = json_reader_get_error (reader);
+
+       if (reader_error != NULL) {
+               if (error != NULL)
+                       *error = g_error_copy (reader_error);
+       } else if (date_str) {
+               if (!gdata_parser_int64_from_iso8601 (date_str, &timestamp))
+                       timestamp = -1;
+       }
+
+       json_reader_end_member (reader);
+
+       return timestamp;
+}
+
+static gboolean
+reader_fill_simple_gvalue (JsonReader *reader, TopicValueType type, GValue *value)
+{
+       gboolean retval = TRUE;
+       gint64 datetime;
+
+       json_reader_read_member (reader, "value");
+
+       if (json_reader_get_error (reader) != NULL) {
+               json_reader_end_member (reader);
+               return FALSE;
+       }
+
+       switch (type) {
+       case TYPE_BOOL:
+       case TYPE_INT:
+       case TYPE_DOUBLE:
+       case TYPE_STRING:
+               json_node_get_value (json_reader_get_value (reader), value);
+               break;
+       case TYPE_DATETIME:
+               if (gdata_parser_int64_from_iso8601 (json_reader_get_string_value (reader), &datetime) ||
+                   gdata_parser_int64_from_date (json_reader_get_string_value (reader), &datetime)) {
+                       g_value_init (value, G_TYPE_INT64);
+                       g_value_set_int64 (value, datetime);
+               } else {
+                       retval = FALSE;
+               }
+
+               break;
+       case TYPE_NONE:
+       case TYPE_COMPOUND:
+       case TYPE_OBJECT:
+       case TYPE_KEY:
+       case TYPE_URI:
+       default:
+               retval = FALSE;
+       }
+
+       json_reader_end_member (reader);
+       return retval;
+}
+
+static GDataFreebaseTopicObject *
+reader_create_object (JsonReader *reader, TopicValueType type)
+{
+       GDataFreebaseTopicObject *object;
+
+       if (type != TYPE_OBJECT && type != TYPE_COMPOUND)
+               return NULL;
+
+       json_reader_read_member (reader, "id");
+
+       if (json_reader_get_error (reader) != NULL) {
+               json_reader_end_member (reader);
+               return NULL;
+       }
+
+       object = object_new (json_reader_get_string_value (reader));
+       json_reader_end_member (reader);
+
+       return object;
+}
+
+static gboolean
+reader_fill_object_gvalue (JsonReader *reader, TopicValueType type, GValue *value)
+{
+       GDataFreebaseTopicObject *object;
+
+       if (type != TYPE_OBJECT && type != TYPE_COMPOUND)
+               return FALSE;
+
+       object = reader_create_object (reader, type);
+
+       if (object != NULL) {
+               g_value_init (value, GDATA_TYPE_FREEBASE_TOPIC_OBJECT);
+               g_value_take_boxed (value, object);
+       }
+
+       return (object != NULL);
+}
+
+static gboolean
+reader_fill_compound_gvalue (JsonReader *reader, TopicValueType type, GValue *value, GError **error)
+{
+       GDataFreebaseTopicObject *object;
+
+       if (type != TYPE_COMPOUND)
+               return FALSE;
+
+       object = reader_create_object (reader, type);
+
+       if (object != NULL)
+               return FALSE;
+
+       json_reader_read_member (reader, "property");
+
+       if (json_reader_get_error (reader) != NULL) {
+               json_reader_end_member (reader);
+               gdata_freebase_topic_object_unref (object);
+               return FALSE;
+       }
+
+       reader_get_properties (reader, object, error);
+       json_reader_end_member (reader);
+
+       g_value_init (value, GDATA_TYPE_FREEBASE_TOPIC_OBJECT);
+       g_value_take_boxed (value, object);
+       return TRUE;
+}
+
+static GDataFreebaseTopicValue *
+reader_create_value (JsonReader *reader, const gchar *property, TopicValueType type, GError **error)
+{
+       GDataFreebaseTopicValue *value;
+
+       value = g_slice_new0 (GDataFreebaseTopicValue);
+
+       value->ref_count = 1;
+       value->property = g_strdup (property);
+       value->text = reader_dup_member_string (reader, "text", error);
+       value->lang = reader_dup_member_string (reader, "lang", error);
+
+       /* Not all parsed nodes are meant to contain creator/timestamp tags,
+        * do not pass error to those, so parsing continues.
+        */
+       value->creator = reader_dup_member_string (reader, "creator", NULL);
+       value->timestamp = reader_parse_timestamp (reader, "timestamp", NULL);
+
+       if (reader_fill_simple_gvalue (reader, type, &value->value) ||
+           reader_fill_object_gvalue (reader, type, &value->value) ||
+           reader_fill_compound_gvalue (reader, type, &value->value, error))
+               return value;
+
+       value_free (value);
+       return NULL;
+}
+
+static GDataFreebaseTopicValueArray *
+reader_create_value_array (JsonReader  *reader, const gchar *property, GError **error)
+{
+       GDataFreebaseTopicValueArray *array;
+       GDataFreebaseTopicValue *value;
+       TopicValueType type;
+       guint64 count, i;
+
+       count = reader_get_item_count (reader);
+
+       if (count <= 0)
+               return NULL;
+
+       type = reader_get_value_type (reader, property, error);
+
+       if (type == TYPE_NONE || type == TYPE_URI || type == TYPE_KEY)
+               return NULL;
+
+       array = value_array_new (type, count);
+
+       json_reader_read_member (reader, "values");
+       count = json_reader_count_elements (reader);
+
+       for (i = 0; i < count; i++) {
+               json_reader_read_element (reader, i);
+               value = reader_create_value (reader, property, type, error);
+               json_reader_end_element (reader);
+
+               if (value != NULL)
+                       value_array_add (array, value);
+       }
+
+       json_reader_end_member (reader);
+
+       return array;
+}
+
+static GDataFreebaseTopicObject *
+object_new (const gchar *id)
+{
+       GDataFreebaseTopicObject *object;
+
+       object = g_slice_new0 (GDataFreebaseTopicObject);
+       object->id = g_strdup (id);
+       object->ref_count = 1;
+       object->values = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                               (GDestroyNotify) g_free,
+                                               (GDestroyNotify) value_array_free);
+       return object;
+}
+
+/* Takes ownership on @array */
+static void
+object_add_value (GDataFreebaseTopicObject *object, const gchar *property, GDataFreebaseTopicValueArray 
*array)
+{
+       g_return_if_fail (object != NULL);
+       g_return_if_fail (property != NULL);
+       g_return_if_fail (array != NULL);
+       g_hash_table_replace (object->values, g_strdup (property), array);
+}
+
+static gboolean
+reader_get_properties (JsonReader *reader, GDataFreebaseTopicObject *object, GError **error)
+{
+       GDataFreebaseTopicValueArray *array;
+       gboolean retval = TRUE;
+       gint count, i;
+
+       count = json_reader_count_members (reader);
+
+       for (i = 0; i < count; i++) {
+               GError *inner_error = NULL;
+               const gchar *name;
+               gchar *property;
+
+               json_reader_read_element (reader, i);
+               property = g_strdup (json_reader_get_member_name (reader));
+               name = property;
+
+               /* Reverse properties start with !, display those as
+                * regular properties, and skip that char
+                */
+               if (name[0] == '!')
+                       name++;
+
+               /* All Freebase properties and IDs start with '/' */
+               if (name[0] != '/')
+                       continue;
+
+               /* Parse the value for this property, possibly with nested contents */
+               array = reader_create_value_array (reader, name, &inner_error);
+               json_reader_end_element (reader);
+
+               if (inner_error != NULL) {
+                       g_propagate_error (error, inner_error);
+                       retval = FALSE;
+                       break;
+               } else if (array != NULL) {
+                       /* Takes ownership of array */
+                       object_add_value (object, name, array);
+               }
+
+               g_free (property);
+       }
+
+       return retval;
+}
+
+static gboolean
+parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error)
+{
+       GDataFreebaseTopicResultPrivate *priv = GDATA_FREEBASE_TOPIC_RESULT (parsable)->priv;
+       const gchar *member_name;
+
+       GDATA_PARSABLE_CLASS (gdata_freebase_topic_result_parent_class)->parse_json (parsable, reader, 
user_data, error);
+
+       member_name = json_reader_get_member_name (reader);
+
+       if (member_name == NULL)
+               return FALSE;
+
+       if (strcmp (member_name, "id") == 0) {
+               /* We only expect one member containing information */
+               g_assert (priv->object == NULL);
+               priv->object = object_new (json_reader_get_string_value (reader));
+       } else if (strcmp (member_name, "property") == 0) {
+               reader_get_properties (reader, priv->object, error);
+       } else {
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+/**
+ * gdata_freebase_topic_result_new:
+ *
+ * Creates a new #GDataFreebaseTopicResult with the given ID and default properties.
+ *
+ * Return value: (transfer full): a new #GDataFreebaseTopicResult; unref with g_object_unref()
+ *
+ * Since: UNRELEASED
+ */
+GDataFreebaseTopicResult *
+gdata_freebase_topic_result_new (void)
+{
+       return g_object_new (GDATA_TYPE_FREEBASE_TOPIC_RESULT, NULL);
+}
+
+/**
+ * gdata_freebase_topic_result_dup_object:
+ * @self: a #GDataFreebaseTopicResult
+ *
+ * Returns a reference to the root #GDataFreebaseTopicObject containing the
+ * topic query results.
+ *
+ * Returns: (transfer full): A new reference on the result object, unref with
+ *   gdata_freebase_topic_object_unref()
+ *
+ * Since: UNRELEASED
+ **/
+GDataFreebaseTopicObject *
+gdata_freebase_topic_result_dup_object (GDataFreebaseTopicResult *self)
+{
+       g_return_val_if_fail (GDATA_IS_FREEBASE_TOPIC_RESULT (self), NULL);
+
+       return gdata_freebase_topic_object_ref (self->priv->object);
+}
+
+/**
+ * gdata_freebase_topic_object_ref:
+ * @object: a #GDataFreebaseTopicObject
+ *
+ * Creates and returns a new reference on @object.
+ *
+ * Returns: (transfer full): @object, with an extra reference.
+ *
+ * Since: UNRELEASED
+ **/
+GDataFreebaseTopicObject *
+gdata_freebase_topic_object_ref (GDataFreebaseTopicObject *object)
+{
+       g_return_val_if_fail (object != NULL, NULL);
+
+       g_atomic_int_inc (&object->ref_count);
+       return object;
+}
+
+/**
+ * gdata_freebase_topic_object_unref:
+ * @object: (transfer full): a #GDataFreebaseTopicResult
+ *
+ * Removes a reference from @object. If the reference count drops to 0,
+ * the object is freed.
+ *
+ * Since: UNRELEASED
+ **/
+void
+gdata_freebase_topic_object_unref (GDataFreebaseTopicObject *object)
+{
+       g_return_if_fail (object != NULL);
+
+       if (g_atomic_int_dec_and_test (&object->ref_count)) {
+               g_hash_table_unref (object->values);
+               g_free (object->id);
+               g_slice_free (GDataFreebaseTopicObject, object);
+       }
+}
+
+/**
+ * gdata_freebase_topic_object_list_properties:
+ * @object: a #GDataFreebaseTopicObject
+ *
+ * Returns the list of Freebase properties described by @object.
+ *
+ * Returns: (transfer container) (element-type gchar*): An array of property names, free with 
g_ptr_array_unref().
+ *
+ * Since: UNRELEASED
+ **/
+GPtrArray *
+gdata_freebase_topic_object_list_properties (const GDataFreebaseTopicObject *object)
+{
+       GPtrArray *properties;
+       GHashTableIter iter;
+       gchar *property;
+
+       g_return_val_if_fail (object != NULL, NULL);
+
+       properties = g_ptr_array_new ();
+       g_hash_table_iter_init (&iter, object->values);
+
+       while (g_hash_table_iter_next (&iter, (gpointer *) &property, NULL))
+               g_ptr_array_add (properties, property);
+
+       return properties;
+}
+
+/**
+ * gdata_freebase_topic_object_get_property_count:
+ * @object: a #GDataFreebaseTopicObject
+ * @property: a property name contained in @object
+ *
+ * Returns the number of values that @object holds for the given @property. If @object
+ * contains no information about @property, 0 is returned.
+ *
+ * Returns: The number of values contained for @property
+ *
+ * Since: UNRELEASED
+ **/
+guint64
+gdata_freebase_topic_object_get_property_count (const GDataFreebaseTopicObject *object, const gchar 
*property)
+{
+       GDataFreebaseTopicValueArray *array;
+
+       g_return_val_if_fail (object != NULL, 0);
+       g_return_val_if_fail (property != NULL, 0);
+       array = g_hash_table_lookup (object->values, property);
+
+       if (array == NULL)
+               return 0;
+
+       return array->values->len;
+}
+
+/**
+ * gdata_freebase_topic_object_get_property_hits:
+ * @object: a #GDataFreebaseTopicObject
+ * @property: a property name contained in @object
+ *
+ * Returns the total number of hits that the Freebase database stores
+ * for this object, this number either equals or is greater than
+ * gdata_freebase_topic_object_get_property_count(), the query limit
+ * can be controlled through gdata_query_set_max_results() on the topic
+ * query.
+ *
+ * If @object contains no information about @property, 0 is returned.
+ *
+ * Returns: the total number of hits for this property
+ *
+ * Since: UNRELEASED
+ **/
+guint64
+gdata_freebase_topic_object_get_property_hits (const GDataFreebaseTopicObject *object, const gchar *property)
+{
+       GDataFreebaseTopicValueArray *array;
+
+       g_return_val_if_fail (object != NULL, 0);
+       g_return_val_if_fail (property != NULL, 0);
+       array = g_hash_table_lookup (object->values, property);
+
+       if (array == NULL)
+               return 0;
+
+       return array->hits;
+}
+
+/**
+ * gdata_freebase_topic_object_get_property_value:
+ * @object: a #GDataFreebaseTopicObject
+ * @property: a property name contained in @object
+ * @item: item number to retrieve from @property
+ *
+ * Gets the value that @object stores for this @property/@item pair, as a generic
+ * #GDataFreebaseTopicValue. If @object contains no information about @property,
+ * or @item is outside the [0..gdata_freebase_topic_object_get_property_count() - 1]
+ * range, %NULL is returned.
+ *
+ * Returns: (allow-none) (transfer none): the value for this property/item
+ *
+ * Since: UNRELEASED
+ **/
+GDataFreebaseTopicValue *
+gdata_freebase_topic_object_get_property_value (const GDataFreebaseTopicObject *object, const gchar 
*property, gint64 item)
+{
+       GDataFreebaseTopicValueArray *array;
+
+       g_return_val_if_fail (object != NULL, NULL);
+       g_return_val_if_fail (property != NULL, NULL);
+       array = g_hash_table_lookup (object->values, property);
+
+       if (array == NULL)
+               return NULL;
+
+       if (item < 0 || item >= array->values->len)
+               return NULL;
+
+       return g_ptr_array_index (array->values, item);
+}
+
+/**
+ * gdata_freebase_topic_object_get_id:
+ * @object: a #GDataFreebaseTopicObject
+ *
+ * Gets the Freebase ID for this specific object.
+ *
+ * Returns: (transfer none): the Freebase ID of this object
+ *
+ * Since: UNRELEASED
+ **/
+const gchar *
+gdata_freebase_topic_object_get_id (const GDataFreebaseTopicObject *object)
+{
+       g_return_val_if_fail (object != NULL, NULL);
+       return object->id;
+}
+
+/**
+ * gdata_freebase_topic_value_ref:
+ * @value: a #GDataFreebaseTopicValue
+ *
+ * Creates and returns a new reference on @value.
+ *
+ * Returns: (transfer full): @value, with an extra reference.
+ *
+ * Since: UNRELEASED
+ **/
+GDataFreebaseTopicValue *
+gdata_freebase_topic_value_ref (GDataFreebaseTopicValue *value)
+{
+       g_return_val_if_fail (value != NULL, NULL);
+
+       g_atomic_int_inc (&value->ref_count);
+       return value;
+}
+
+/**
+ * gdata_freebase_topic_value_unref:
+ * @value:  (transfer full): a #GDataFreebaseTopicValue
+ *
+ * Removes a reference from @value. If the reference count drops to 0,
+ * the object is freed.
+ *
+ * Since: UNRELEASED
+ **/
+void
+gdata_freebase_topic_value_unref (GDataFreebaseTopicValue *value)
+{
+       g_return_if_fail (value != NULL);
+
+       if (g_atomic_int_dec_and_test (&value->ref_count))
+               value_free (value);
+}
+
+/**
+ * gdata_freebase_topic_value_get_property:
+ * @value: a #GDataFreebaseTopicValue
+ *
+ * Returns the property name that this value describes
+ *
+ * Returns: the property name of @value
+ *
+ * Since: UNRELEASED
+ **/
+const gchar *
+gdata_freebase_topic_value_get_property (GDataFreebaseTopicValue *value)
+{
+       g_return_val_if_fail (value != NULL, NULL);
+       return value->property;
+}
+
+/**
+ * gdata_freebase_topic_value_get_text:
+ * @value: a #GDataFreebaseTopicValue
+ *
+ * Returns a textual representation of this value, this is either
+ * the value contained transformed to a string, or a concatenation
+ * of subvalues for compound types.
+ *
+ * Returns: a textual representation of @value
+ *
+ * Since: UNRELEASED
+ **/
+const gchar *
+gdata_freebase_topic_value_get_text (GDataFreebaseTopicValue *value)
+{
+       g_return_val_if_fail (value != NULL, NULL);
+       return value->text;
+}
+
+/**
+ * gdata_freebase_topic_value_get_language:
+ * @value: a #GDataFreebaseTopicValue
+ *
+ * Returns the language used in the content of @value
+ *
+ * Returns: the language @value is written in
+ *
+ * Since: UNRELEASED
+ **/
+const gchar *
+gdata_freebase_topic_value_get_language (GDataFreebaseTopicValue *value)
+{
+       g_return_val_if_fail (value != NULL, NULL);
+       return value->lang;
+}
+
+/**
+ * gdata_freebase_topic_value_get_creator:
+ * @value: a #GDataFreebaseTopicValue
+ *
+ * Returns the Freebase ID of the user that created this value.
+ *
+ * Returns: the creator of this value, as a Freebase ID
+ *
+ * Since: UNRELEASED
+ **/
+const gchar *
+gdata_freebase_topic_value_get_creator (GDataFreebaseTopicValue *value)
+{
+       g_return_val_if_fail (value != NULL, NULL);
+       return value->creator;
+}
+
+/**
+ * gdata_freebase_topic_value_get_timestamp:
+ * @value: #GDataFreebaseTopicValue
+ *
+ * Returns the time at which this value was created in the Freebase database.
+ * It's a UNIX timestamp in seconds since the epoch. If @value has no timestamp,
+ * -1 will be returned.
+ *
+ * Returns: The creation time of @value, or -1
+ *
+ * Since: UNRELEASED
+ **/
+gint64
+gdata_freebase_topic_value_get_timestamp (GDataFreebaseTopicValue *value)
+{
+       g_return_val_if_fail (value != NULL, 0);
+       return value->timestamp;
+}
+
+/**
+ * gdata_freebase_topic_value_get_value_type:
+ * @value: a #GDataFreebaseTopicValue
+ *
+ * Returns the #GType of the real value held in @value.
+ *
+ * Returns: the #GType of the contained value
+ *
+ * Since: UNRELEASED
+ **/
+GType
+gdata_freebase_topic_value_get_value_type (GDataFreebaseTopicValue *value)
+{
+       g_return_val_if_fail (value != NULL, G_TYPE_INVALID);
+       return G_VALUE_TYPE (&value->value);
+}
+
+/**
+ * gdata_freebase_topic_value_copy_value:
+ * @value: a #GDataFreebaseTopicValue
+ * @gvalue: (out caller-allocates) (transfer full): an empty #GValue
+ *
+ * Copies in @gvalue the value held in @value. the #GValue must be later freed through g_value_unset()
+ *
+ * Since: UNRELEASED
+ **/
+void
+gdata_freebase_topic_value_copy_value (GDataFreebaseTopicValue *value, GValue *gvalue)
+{
+       g_return_if_fail (value != NULL);
+
+       g_value_copy (&value->value, gvalue);
+}
+
+/**
+ * gdata_freebase_topic_value_get_int:
+ * @value: a #GDataFreebaseTopicValue
+ *
+ * Returns a #gint64 value held in @value. It is only valid to call this if the #GType is a %G_TYPE_INT64
+ *
+ * Returns: the #gint64 value
+ *
+ * Since: UNRELEASED
+ **/
+gint64
+gdata_freebase_topic_value_get_int (GDataFreebaseTopicValue *value)
+{
+       g_return_val_if_fail (value != NULL, 0);
+       g_return_val_if_fail (G_VALUE_HOLDS_INT64 (&value->value), 0);
+
+       return g_value_get_int64 (&value->value);
+}
+
+/**
+ * gdata_freebase_topic_value_get_double:
+ * @value: a #GDataFreebaseTopicValue
+ *
+ * Returns a #gdouble value held in @value. It is only valid to call this if the #GType is a %G_TYPE_DOUBLE
+ *
+ * Returns: the #gdouble value
+ *
+ * Since: UNRELEASED
+ **/
+gdouble
+gdata_freebase_topic_value_get_double (GDataFreebaseTopicValue *value)
+{
+       g_return_val_if_fail (value != NULL, 0);
+       g_return_val_if_fail (G_VALUE_HOLDS_DOUBLE (&value->value), 0);
+
+       return g_value_get_double (&value->value);
+}
+
+/**
+ * gdata_freebase_topic_value_get_string:
+ * @value: a #GDataFreebaseTopicValue
+ *
+ * Returns a string value held in @value. It is only valid to call this if the #GType is a %G_TYPE_STRING
+ *
+ * Returns: the string value
+ *
+ * Since: UNRELEASED
+ **/
+const gchar *
+gdata_freebase_topic_value_get_string (GDataFreebaseTopicValue *value)
+{
+       g_return_val_if_fail (value != NULL, NULL);
+       g_return_val_if_fail (G_VALUE_HOLDS_STRING (&value->value), NULL);
+
+       return g_value_get_string (&value->value);
+}
+
+/**
+ * gdata_freebase_topic_value_get_object:
+ * @value: a #GDataFreebaseTopicValue
+ *
+ * Returns a compound/complex object held in @value. It is only valid to call this if the #GType is a
+ * %GDATA_TYPE_FREEBASE_TOPIC_OBJECT.
+ *
+ * Returns: (transfer none): the compound value as a #GDataFreebaseTopicObject
+ *
+ * Since: UNRELEASED
+ **/
+const GDataFreebaseTopicObject *
+gdata_freebase_topic_value_get_object (GDataFreebaseTopicValue *value)
+{
+       g_return_val_if_fail (value != NULL, NULL);
+       g_return_val_if_fail (G_VALUE_HOLDS (&value->value, GDATA_TYPE_FREEBASE_TOPIC_OBJECT), NULL);
+
+       return g_value_get_boxed (&value->value);
+}
+
+/**
+ * gdata_freebase_topic_value_is_image:
+ * @value: a #GDataFreebaseTopicValue
+ *
+ * Returns true if @value holds a freebase image object, on such values it
+ * will be valid to call gdata_freebase_service_get_image() to get a stream
+ * to the image itself.
+ *
+ * Returns: Whether @value holds a Freebase image object
+ *
+ * Since: UNRELEASED
+ **/
+gboolean
+gdata_freebase_topic_value_is_image (GDataFreebaseTopicValue *value)
+{
+       g_return_val_if_fail (value != NULL, FALSE);
+
+       return (strcmp (value->property, "/common/topic/image") == 0);
+}
diff --git a/gdata/services/freebase/gdata-freebase-topic-result.h 
b/gdata/services/freebase/gdata-freebase-topic-result.h
new file mode 100644
index 0000000..7355d24
--- /dev/null
+++ b/gdata/services/freebase/gdata-freebase-topic-result.h
@@ -0,0 +1,126 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * GData Client
+ * Copyright (C) 2014 Carlos Garnacho <carlosg gnome org>
+ *
+ * GData Client is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GData Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GData Client.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GDATA_FREEBASE_TOPIC_RESULT_H
+#define GDATA_FREEBASE_TOPIC_RESULT_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gdata/gdata-types.h>
+#include "gdata-freebase-result.h"
+
+G_BEGIN_DECLS
+
+#define GDATA_TYPE_FREEBASE_TOPIC_OBJECT               (gdata_freebase_topic_object_get_type ())
+#define GDATA_TYPE_FREEBASE_TOPIC_VALUE                        (gdata_freebase_topic_value_get_type ())
+#define GDATA_TYPE_FREEBASE_TOPIC_RESULT               (gdata_freebase_topic_result_get_type ())
+#define GDATA_FREEBASE_TOPIC_RESULT(o)                 (G_TYPE_CHECK_INSTANCE_CAST ((o), 
GDATA_TYPE_FREEBASE_TOPIC_RESULT, GDataFreebaseTopicResult))
+#define GDATA_FREEBASE_TOPIC_RESULT_CLASS(k)           (G_TYPE_CHECK_CLASS_CAST((k), 
GDATA_TYPE_FREEBASE_TOPIC_RESULT, GDataFreebaseTopicResultClass))
+#define GDATA_IS_FREEBASE_TOPIC_RESULT(o)              (G_TYPE_CHECK_INSTANCE_TYPE ((o), 
GDATA_TYPE_FREEBASE_TOPIC_RESULT))
+#define GDATA_IS_FREEBASE_TOPIC_RESULT_CLASS(k)                (G_TYPE_CHECK_CLASS_TYPE ((k), 
GDATA_TYPE_FREEBASE_TOPIC_RESULT))
+#define GDATA_FREEBASE_TOPIC_RESULT_GET_CLASS(o)       (G_TYPE_INSTANCE_GET_CLASS ((o), 
GDATA_TYPE_FREEBASE_TOPIC_RESULT, GDataFreebaseTopicResultClass))
+
+typedef struct _GDataFreebaseTopicResultPrivate GDataFreebaseTopicResultPrivate;
+
+/**
+ * GDataFreebaseTopicObject:
+ *
+ * Opaque struct containing a Freebase topic object. This object may contain one or more
+ * #GDataFreebaseTopicValue structs, which may in turn contain nested #GDataFreebaseTopicObject
+ * structs to express complex data.
+ *
+ * Since: UNRELEASED
+ */
+typedef struct _GDataFreebaseTopicObject GDataFreebaseTopicObject;
+
+/**
+ * GDataFreebaseTopicValue:
+ *
+ * Opaque struct containing a value of a Freebase topic object. This struct may contain a simple
+ * value (integers, doubles, strings...) or complex values, expressed through a #GDataFreebaseTopicObject.
+ *
+ * Since: UNRELEASED
+ */
+typedef struct _GDataFreebaseTopicValue GDataFreebaseTopicValue;
+
+/**
+ * GDataFreebaseTopicResult:
+ *
+ * All the fields in the #GDataFreebaseTopicResult structure are private and should never be accessed 
directly.
+ *
+ * Since: UNRELEASED
+ */
+typedef struct {
+       GDataFreebaseResult parent;
+       GDataFreebaseTopicResultPrivate *priv;
+} GDataFreebaseTopicResult;
+
+/**
+ * GDataFreebaseTopicResultClass:
+ *
+ * All the fields in the #GDataFreebaseTopicResultClass structure are private and should never be accessed 
directly.
+ *
+ * Since: UNRELEASED
+ */
+typedef struct {
+       /*< private >*/
+       GDataFreebaseResultClass parent;
+} GDataFreebaseTopicResultClass;
+
+GType gdata_freebase_topic_object_get_type (void) G_GNUC_CONST;
+GType gdata_freebase_topic_value_get_type (void) G_GNUC_CONST;
+GType gdata_freebase_topic_result_get_type (void) G_GNUC_CONST;
+
+GDataFreebaseTopicResult *gdata_freebase_topic_result_new (void) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
+
+GDataFreebaseTopicObject *gdata_freebase_topic_result_dup_object (GDataFreebaseTopicResult *self);
+
+GDataFreebaseTopicObject *gdata_freebase_topic_object_ref (GDataFreebaseTopicObject *object);
+void gdata_freebase_topic_object_unref (GDataFreebaseTopicObject *object);
+
+GPtrArray *gdata_freebase_topic_object_list_properties (const GDataFreebaseTopicObject *object);
+
+const gchar *gdata_freebase_topic_object_get_id (const GDataFreebaseTopicObject *object);
+guint64 gdata_freebase_topic_object_get_property_count (const GDataFreebaseTopicObject *object, const gchar 
*property);
+guint64 gdata_freebase_topic_object_get_property_hits (const GDataFreebaseTopicObject *object, const gchar 
*property);
+GDataFreebaseTopicValue *gdata_freebase_topic_object_get_property_value (const GDataFreebaseTopicObject 
*object, const gchar *property, gint64 item);
+
+GDataFreebaseTopicValue *gdata_freebase_topic_value_ref (GDataFreebaseTopicValue *value);
+void gdata_freebase_topic_value_unref (GDataFreebaseTopicValue *value);
+
+const gchar *gdata_freebase_topic_value_get_property (GDataFreebaseTopicValue *value);
+
+const gchar *gdata_freebase_topic_value_get_text (GDataFreebaseTopicValue *value);
+const gchar *gdata_freebase_topic_value_get_language (GDataFreebaseTopicValue *value);
+const gchar *gdata_freebase_topic_value_get_creator (GDataFreebaseTopicValue *value);
+gint64 gdata_freebase_topic_value_get_timestamp (GDataFreebaseTopicValue *value);
+GType gdata_freebase_topic_value_get_value_type (GDataFreebaseTopicValue *value);
+void gdata_freebase_topic_value_copy_value (GDataFreebaseTopicValue *value, GValue *gvalue);
+
+gint64 gdata_freebase_topic_value_get_int (GDataFreebaseTopicValue *value);
+gdouble gdata_freebase_topic_value_get_double (GDataFreebaseTopicValue *value);
+const gchar *gdata_freebase_topic_value_get_string (GDataFreebaseTopicValue *value);
+const GDataFreebaseTopicObject *gdata_freebase_topic_value_get_object (GDataFreebaseTopicValue *value);
+
+gboolean gdata_freebase_topic_value_is_image (GDataFreebaseTopicValue *value);
+
+G_END_DECLS
+
+#endif /* !GDATA_FREEBASE_TOPIC_RESULT_H */


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