summaryrefslogtreecommitdiff
path: root/gdata/services
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2014-03-17 02:05:17 +0100
committerCarlos Garnacho <carlosg@gnome.org>2014-05-27 02:36:27 +0200
commit7d919fd88d88fa39f6870588826469bdae811d1a (patch)
treef8216771d112d5150a69906135cb2f832c61c966 /gdata/services
parentb03f422a2e87dda27f593c866a45c1f112b4f6a8 (diff)
downloadlibgdata-7d919fd88d88fa39f6870588826469bdae811d1a.tar.gz
Add Freebase service
This service is, according to the main site, a "A community-curated database of well-known people, places, and things", it allows searching for and offering information about a wide range of topics, in a well-structured and uniform manner. The most low-level API is the MQL query interface, that is a JSON-based language, queries consist of a data graph (according to their data schema) with blank places, that will be filled in in the reply. https://bugzilla.gnome.org/show_bug.cgi?id=726486
Diffstat (limited to 'gdata/services')
-rw-r--r--gdata/services/freebase/gdata-freebase-query.c245
-rw-r--r--gdata/services/freebase/gdata-freebase-query.h72
-rw-r--r--gdata/services/freebase/gdata-freebase-result.c196
-rw-r--r--gdata/services/freebase/gdata-freebase-result.h72
-rw-r--r--gdata/services/freebase/gdata-freebase-service.c255
-rw-r--r--gdata/services/freebase/gdata-freebase-service.h81
6 files changed, 921 insertions, 0 deletions
diff --git a/gdata/services/freebase/gdata-freebase-query.c b/gdata/services/freebase/gdata-freebase-query.c
new file mode 100644
index 00000000..ced053ab
--- /dev/null
+++ b/gdata/services/freebase/gdata-freebase-query.c
@@ -0,0 +1,245 @@
+/* -*- 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-query
+ * @short_description: GData Freebase query object
+ * @stability: Unstable
+ * @include: gdata/services/freebase/gdata-freebase-query.h
+ *
+ * #GDataFreebaseQuery represents a MQL query specific to the Google Freebase service.
+ *
+ * This implementation of #GDataQuery respects the gdata_query_set_max_results() call.
+ *
+ * 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-query.h"
+#include "gdata-query.h"
+#include "gdata-parser.h"
+
+static void gdata_freebase_query_finalize (GObject *self);
+static void gdata_freebase_query_set_property (GObject *self, guint prop_id, const GValue *value, GParamSpec *pspec);
+static void gdata_freebase_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 _GDataFreebaseQueryPrivate {
+ /* These params are here not in GDataQuery due of differently named query params for JSON protocols therefore need for different parse_uri */
+ GVariant *variant;
+ JsonNode *query_node;
+};
+
+enum {
+ PROP_VARIANT = 1,
+};
+
+G_DEFINE_TYPE (GDataFreebaseQuery, gdata_freebase_query, GDATA_TYPE_QUERY)
+
+static void
+gdata_freebase_query_class_init (GDataFreebaseQueryClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GDataQueryClass *query_class = GDATA_QUERY_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (GDataFreebaseQueryPrivate));
+
+ gobject_class->finalize = gdata_freebase_query_finalize;
+ gobject_class->set_property = gdata_freebase_query_set_property;
+ gobject_class->get_property = gdata_freebase_query_get_property;
+
+ query_class->get_query_uri = get_query_uri;
+
+ /**
+ * GDataFreebaseQuery:variant:
+ *
+ * Variant containing the MQL query. The variant is a very generic container of type "a{smv}",
+ * containing (possibly nested) Freebase schema types and values.
+ *
+ * Since: UNRELEASED
+ **/
+ g_object_class_install_property (gobject_class, PROP_VARIANT,
+ g_param_spec_variant ("variant",
+ "Variant",
+ "Variant to construct the query from.",
+ G_VARIANT_TYPE ("a{smv}"), NULL,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gdata_freebase_query_init (GDataFreebaseQuery *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_FREEBASE_QUERY, GDataFreebaseQueryPrivate);
+}
+
+static void
+gdata_freebase_query_finalize (GObject *self)
+{
+ GDataFreebaseQueryPrivate *priv = GDATA_FREEBASE_QUERY (self)->priv;
+
+ if (priv->variant != NULL)
+ g_variant_unref (priv->variant);
+ if (priv->query_node != NULL)
+ json_node_free (priv->query_node);
+ /* Chain up to the parent class */
+ G_OBJECT_CLASS (gdata_freebase_query_parent_class)->finalize (self);
+}
+
+static void
+gdata_freebase_query_set_property (GObject *self, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GDataFreebaseQueryPrivate *priv = GDATA_FREEBASE_QUERY (self)->priv;
+
+ switch (prop_id) {
+ case PROP_VARIANT:
+ priv->variant = g_value_get_variant (value);
+ if (priv->variant)
+ priv->query_node = json_gvariant_serialize (priv->variant);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdata_freebase_query_get_property (GObject *self, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GDataFreebaseQueryPrivate *priv = GDATA_FREEBASE_QUERY (self)->priv;
+
+ switch (prop_id) {
+ case PROP_VARIANT:
+ g_value_set_variant (value, priv->variant);
+ 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)
+{
+ GDataFreebaseQueryPrivate *priv = GDATA_FREEBASE_QUERY (self)->priv;
+ const gchar *query;
+
+#define APPEND_SEP g_string_append_c (query_uri, (*params_started == FALSE) ? '?' : '&'); *params_started = TRUE;
+
+ query = gdata_query_get_q (self);
+
+ if (query != NULL) {
+ APPEND_SEP;
+ g_string_append (query_uri, "query=");
+ g_string_append (query_uri, query);
+ } else if (priv->query_node != NULL) {
+ JsonGenerator *generator;
+ JsonNode *copy;
+ gchar *json;
+ guint limit;
+
+ copy = json_node_copy (priv->query_node);
+
+ limit = gdata_query_get_max_results (self);
+
+ if (limit > 0) {
+ JsonNode *limit_node;
+ JsonObject *object;
+
+ limit_node = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (limit_node, limit);
+
+ object = json_node_get_object (copy);
+ json_object_set_member (object, "limit", limit_node);
+ }
+
+ generator = json_generator_new ();
+ json_generator_set_root (generator, copy);
+ json = json_generator_to_data (generator, NULL);
+ g_object_unref (generator);
+
+ APPEND_SEP;
+ g_string_append (query_uri, "query=");
+ g_string_append (query_uri, json);
+ g_free (json);
+ }
+
+ /* 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_query_new:
+ * @mql: a MQL query string
+ *
+ * Creates a new #GDataFreebaseQuery with the MQL query provided in @mql. MQL
+ * is a JSON-based query language, analogous to SPARQL. To learn more about MQL,
+ * see the <ulink type="http" url="https://developers.google.com/freebase/v1/mql-overview">
+ * MQL overview</ulink> and <ulink type="http" url="https://developers.google.com/freebase/v1/mql-cookbook">
+ * cookbook</ulink>.
+ *
+ * For detailed information on Freebase schemas, The <ulink type="http" url="http://www.freebase.com/schema">"Schema"
+ * section</ulink> on the main site allows for natural search and navigation through the multiple data properties and domains.
+ *
+ * Return value: (transfer full): a new #GDataFreebaseQuery
+ *
+ * Since: UNRELEASED
+ */
+GDataFreebaseQuery *
+gdata_freebase_query_new (const gchar *mql)
+{
+ g_return_val_if_fail (mql != NULL, NULL);
+
+ return g_object_new (GDATA_TYPE_FREEBASE_QUERY, "q", mql, NULL);
+}
+
+/**
+ * gdata_freebase_query_new_from_variant:
+ * @variant: a variant containing the MQL query structure
+ *
+ * Creates a new #GDataFreebaseQuery with the MQL query provided in a serialized form as @variant
+ * of type "a{smv}" containing the JSON data tree of a MQL query. One convenient way
+ * to build the variant is using json_gvariant_serialize() from a #JsonNode. For more information
+ * about MQL, see gdata_freebase_query_new().
+ *
+ * #GDataFreebaseQuery takes ownership on @variant, if it has a floating reference, it will be sunk.
+ * Otherwise an extra reference will be added.
+ *
+ * Return value: (transfer full): a new #GDataFreebaseQuery
+ *
+ * Since: UNRELEASED
+ */
+GDataFreebaseQuery *
+gdata_freebase_query_new_from_variant (GVariant *variant)
+{
+ g_return_val_if_fail (variant != NULL, NULL);
+
+ return g_object_new (GDATA_TYPE_FREEBASE_QUERY,
+ "variant", g_variant_ref_sink (variant),
+ NULL);
+}
diff --git a/gdata/services/freebase/gdata-freebase-query.h b/gdata/services/freebase/gdata-freebase-query.h
new file mode 100644
index 00000000..c350ae2a
--- /dev/null
+++ b/gdata/services/freebase/gdata-freebase-query.h
@@ -0,0 +1,72 @@
+/* -*- 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_QUERY_H
+#define GDATA_FREEBASE_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_QUERY (gdata_freebase_query_get_type ())
+#define GDATA_FREEBASE_QUERY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDATA_TYPE_FREEBASE_QUERY, GDataFreebaseQuery))
+#define GDATA_FREEBASE_QUERY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDATA_TYPE_FREEBASE_QUERY, GDataFreebaseQueryClass))
+#define GDATA_IS_FREEBASE_QUERY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDATA_TYPE_FREEBASE_QUERY))
+#define GDATA_IS_FREEBASE_QUERY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDATA_TYPE_FREEBASE_QUERY))
+#define GDATA_FREEBASE_QUERY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDATA_TYPE_FREEBASE_QUERY, GDataFreebaseQueryClass))
+
+typedef struct _GDataFreebaseQueryPrivate GDataFreebaseQueryPrivate;
+
+/**
+ * GDataFreebaseQuery:
+ *
+ * All the fields in the #GDataFreebaseQuery structure are private and should never be accessed directly.
+ *
+ * Since: UNRELEASED
+ */
+typedef struct {
+ GDataQuery parent;
+ /*< private >*/
+ GDataFreebaseQueryPrivate *priv;
+} GDataFreebaseQuery;
+
+/**
+ * GDataFreebaseQueryClass:
+ *
+ * All the fields in the #GDataFreebaseQueryClass structure are private and should never be accessed directly.
+ *
+ * Since: UNRELEASED
+ */
+typedef struct {
+ /*< private >*/
+ GDataQueryClass parent;
+} GDataFreebaseQueryClass;
+
+GType gdata_freebase_query_get_type (void) G_GNUC_CONST;
+
+GDataFreebaseQuery *gdata_freebase_query_new (const gchar *mql) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
+GDataFreebaseQuery *gdata_freebase_query_new_from_variant (GVariant *variant) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
+
+G_END_DECLS
+
+#endif /* !GDATA_FREEBASE_QUERY_H */
diff --git a/gdata/services/freebase/gdata-freebase-result.c b/gdata/services/freebase/gdata-freebase-result.c
new file mode 100644
index 00000000..9ba81aea
--- /dev/null
+++ b/gdata/services/freebase/gdata-freebase-result.c
@@ -0,0 +1,196 @@
+/* -*- 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-result
+ * @short_description: GData Freebase result object
+ * @stability: Unstable
+ * @include: gdata/services/freebase/gdata-freebase-result.h
+ *
+ * #GDataFreebaseResult is a subclass of #GDataEntry to represent the result of a Google Freebase MQL query.
+ *
+ * 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 "gdata-freebase-result.h"
+#include "gdata-private.h"
+#include "gdata-types.h"
+
+#define URLBASE "https://www.googleapis.com/freebase/v1/"
+
+enum {
+ PROP_VARIANT = 1
+};
+
+struct _GDataFreebaseResultPrivate {
+ GVariant *result;
+};
+
+static void gdata_freebase_result_finalize (GObject *self);
+static void gdata_freebase_result_get_property (GObject *self, guint prop_id, GValue *value, GParamSpec *pspec);
+static gboolean parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error);
+static const gchar *get_content_type (void);
+static gchar *get_entry_uri (const gchar *id);
+
+G_DEFINE_TYPE (GDataFreebaseResult, gdata_freebase_result, GDATA_TYPE_ENTRY)
+
+static void
+gdata_freebase_result_class_init (GDataFreebaseResultClass *klass)
+{
+ GDataParsableClass *parsable_class = GDATA_PARSABLE_CLASS (klass);
+ GDataEntryClass *entry_class = GDATA_ENTRY_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (GDataFreebaseResultPrivate));
+
+ gobject_class->finalize = gdata_freebase_result_finalize;
+ gobject_class->get_property = gdata_freebase_result_get_property;
+
+ parsable_class->parse_json = parse_json;
+ parsable_class->get_content_type = get_content_type;
+ entry_class->get_entry_uri = get_entry_uri;
+
+ /**
+ * GDataFreebaseResult:variant:
+ *
+ * Variant containing the MQL result. The variant is a very generic container of type "a{smv}",
+ * containing (possibly nested) Freebase schema types and values.
+ *
+ * Since: UNRELEASED
+ **/
+ g_object_class_install_property (gobject_class, PROP_VARIANT,
+ g_param_spec_variant ("variant",
+ "Variant", "Variant holding the raw result.",
+ G_VARIANT_TYPE ("a{smv}"), NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gdata_freebase_result_init (GDataFreebaseResult *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_FREEBASE_RESULT, GDataFreebaseResultPrivate);
+}
+
+static void
+gdata_freebase_result_finalize (GObject *self)
+{
+ GDataFreebaseResultPrivate *priv = GDATA_FREEBASE_RESULT (self)->priv;
+
+ if (priv->result != NULL)
+ g_variant_unref (priv->result);
+
+ G_OBJECT_CLASS (gdata_freebase_result_parent_class)->finalize (self);
+}
+
+static void
+gdata_freebase_result_get_property (GObject *self, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GDataFreebaseResultPrivate *priv = GDATA_FREEBASE_RESULT (self)->priv;
+
+ switch (prop_id) {
+ case PROP_VARIANT:
+ g_value_set_variant (value, priv->result);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error)
+{
+ GDataFreebaseResultPrivate *priv = GDATA_FREEBASE_RESULT (parsable)->priv;
+ JsonNode *root, *node;
+ JsonObject *object;
+
+ if (g_strcmp0 (json_reader_get_member_name (reader), "result") != 0)
+ return TRUE;
+
+ g_object_get (reader, "root", &root, NULL);
+ object = json_node_get_object (root);
+ node = json_object_get_member (object, "result");
+
+ priv->result = g_variant_ref_sink (json_gvariant_deserialize (node, NULL, error));
+ json_node_free (root);
+
+ return (priv->result != NULL);
+}
+
+static const gchar *
+get_content_type (void)
+{
+ return "application/json";
+}
+
+static gchar *
+get_entry_uri (const gchar *id)
+{
+ /* https://www.googleapis.com/freebase/v1/mqlread interface */
+ return g_strconcat (URLBASE, id, NULL);
+}
+
+/**
+ * gdata_freebase_result_new:
+ *
+ * Creates a new #GDataFreebaseResult.
+ *
+ * Return value: (transfer full): a new #GDataFreebaseResult; unref with g_object_unref()
+ *
+ * Since: UNRELEASED
+ */
+GDataFreebaseResult *
+gdata_freebase_result_new (void)
+{
+ return g_object_new (GDATA_TYPE_FREEBASE_RESULT, NULL);
+}
+
+/**
+ * gdata_freebase_result_dup_variant:
+ * @self: a #GDataFreebaseResult
+ *
+ * Gets the result serialized as a #GVariant of type "a{smv}", containing the JSON
+ * data tree. This variant can be alternatively processed through json_gvariant_serialize().
+ *
+ * Returns: (allow-none) (transfer full): the serialized result, or %NULL; unref with g_variant_unref()
+ *
+ * Since: UNRELEASED
+ **/
+GVariant *
+gdata_freebase_result_dup_variant (GDataFreebaseResult *self)
+{
+ GDataFreebaseResultPrivate *priv;
+
+ g_return_val_if_fail (GDATA_IS_FREEBASE_RESULT (self), NULL);
+
+ priv = self->priv;
+
+ if (priv->result == NULL)
+ return NULL;
+
+ return g_variant_ref (priv->result);
+}
diff --git a/gdata/services/freebase/gdata-freebase-result.h b/gdata/services/freebase/gdata-freebase-result.h
new file mode 100644
index 00000000..e369b8ef
--- /dev/null
+++ b/gdata/services/freebase/gdata-freebase-result.h
@@ -0,0 +1,72 @@
+/* -*- 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_RESULT_H
+#define GDATA_FREEBASE_RESULT_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gdata/gdata-entry.h>
+#include <gdata/gdata-types.h>
+
+G_BEGIN_DECLS
+
+#define GDATA_TYPE_FREEBASE_RESULT (gdata_freebase_result_get_type ())
+#define GDATA_FREEBASE_RESULT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDATA_TYPE_FREEBASE_RESULT, GDataFreebaseResult))
+#define GDATA_FREEBASE_RESULT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDATA_TYPE_FREEBASE_RESULT, GDataFreebaseResultClass))
+#define GDATA_IS_FREEBASE_RESULT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDATA_TYPE_FREEBASE_RESULT))
+#define GDATA_IS_FREEBASE_RESULT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDATA_TYPE_FREEBASE_RESULT))
+#define GDATA_FREEBASE_RESULT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDATA_TYPE_FREEBASE_RESULT, GDataFreebaseResultClass))
+
+typedef struct _GDataFreebaseResultPrivate GDataFreebaseResultPrivate;
+
+/**
+ * GDataFreebaseResult:
+ *
+ * All the fields in the #GDataFreebaseResult structure are private and should never be accessed directly.
+ *
+ * Since: UNRELEASED
+ */
+typedef struct {
+ GDataEntry parent;
+ GDataFreebaseResultPrivate *priv;
+} GDataFreebaseResult;
+
+/**
+ * GDataFreebaseResultClass:
+ *
+ * All the fields in the #GDataFreebaseResultClass structure are private and should never be accessed directly.
+ *
+ * Since: UNRELEASED
+ */
+
+typedef struct {
+ /*< private >*/
+ GDataEntryClass parent;
+} GDataFreebaseResultClass;
+
+GType gdata_freebase_result_get_type (void) G_GNUC_CONST;
+
+GDataFreebaseResult *gdata_freebase_result_new (void) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
+GVariant *gdata_freebase_result_dup_variant (GDataFreebaseResult *self) G_GNUC_WARN_UNUSED_RESULT;
+
+G_END_DECLS
+
+#endif /* !GDATA_FREEBASE_RESULT_H */
diff --git a/gdata/services/freebase/gdata-freebase-service.c b/gdata/services/freebase/gdata-freebase-service.c
new file mode 100644
index 00000000..f4006dbd
--- /dev/null
+++ b/gdata/services/freebase/gdata-freebase-service.c
@@ -0,0 +1,255 @@
+/* -*- 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-service
+ * @short_description: GData Freebase service object
+ * @stability: Unstable
+ * @include: gdata/services/freebase/gdata-freebase-service.h
+ *
+ * #GDataFreebaseService is a subclass of #GDataService for communicating with the Google Freebase API. It supports queries
+ * in MQL format, that allows highly flexible queries on any topic. MQL is a JSON based query language, MQL requests consist
+ * of a mix of defined and empty values for types in the Freebase schema, those "placeholder" values will be filled in on the
+ * reply. For more information and examples, see the <ulink type="http" url="https://developers.google.com/freebase/v1/mql-overview">
+ * MQL overview page</ulink>.
+ *
+ * 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 "gdata-freebase-service.h"
+#include "gdata-freebase-result.h"
+#include "gdata-service.h"
+#include "gdata-private.h"
+#include "gdata-query.h"
+
+/* Standards reference at https://developers.google.com/freebase/v1/ */
+
+#define URLBASE "://www.googleapis.com/freebase/v1"
+
+enum {
+ PROP_DEVELOPER_KEY = 1
+};
+
+struct _GDataFreebaseServicePrivate {
+ gchar *developer_key;
+};
+
+static void gdata_freebase_service_set_property (GObject *self, guint prop_id, const GValue *value, GParamSpec *pspec);
+static void gdata_freebase_service_get_property (GObject *self, guint prop_id, GValue *value, GParamSpec *pspec);
+static void gdata_freebase_service_finalize (GObject *self);
+static GList *get_authorization_domains (void);
+
+_GDATA_DEFINE_AUTHORIZATION_DOMAIN (freebase, "freebase", "https" URLBASE)
+
+G_DEFINE_TYPE (GDataFreebaseService, gdata_freebase_service, GDATA_TYPE_SERVICE)
+
+static void
+gdata_freebase_service_class_init (GDataFreebaseServiceClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GDataServiceClass *service_class = GDATA_SERVICE_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (GDataFreebaseServicePrivate));
+
+ gobject_class->set_property = gdata_freebase_service_set_property;
+ gobject_class->get_property = gdata_freebase_service_get_property;
+ gobject_class->finalize = gdata_freebase_service_finalize;
+
+ service_class->get_authorization_domains = get_authorization_domains;
+
+ /**
+ * GDataFreebaseService:developer-key:
+ *
+ * The developer key your application has registered with the Freebase API. For more information, see the <ulink type="http"
+ * url="https://developers.google.com/freebase/v1/how-tos/authorizing">online documentation</ulink>.
+ *
+ * Since: UNRELEASED
+ **/
+ g_object_class_install_property (gobject_class, PROP_DEVELOPER_KEY,
+ g_param_spec_string ("developer-key",
+ "Developer key", "Your Freebase developer API key.",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gdata_freebase_service_init (GDataFreebaseService *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_FREEBASE_SERVICE, GDataFreebaseServicePrivate);
+}
+
+static GList *
+get_authorization_domains (void)
+{
+ return g_list_prepend (NULL, get_freebase_authorization_domain ());
+}
+
+static void
+gdata_freebase_service_set_property (GObject *self, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GDataFreebaseServicePrivate *priv = GDATA_FREEBASE_SERVICE (self)->priv;
+
+ switch (prop_id) {
+ case PROP_DEVELOPER_KEY:
+ priv->developer_key = g_value_dup_string (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdata_freebase_service_get_property (GObject *self, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GDataFreebaseServicePrivate *priv = GDATA_FREEBASE_SERVICE (self)->priv;
+
+ switch (prop_id) {
+ case PROP_DEVELOPER_KEY:
+ g_value_set_string (value, priv->developer_key);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdata_freebase_service_finalize (GObject *self)
+{
+ GDataFreebaseServicePrivate *priv = GDATA_FREEBASE_SERVICE (self)->priv;
+
+ g_free (priv->developer_key);
+
+ G_OBJECT_CLASS (gdata_freebase_service_parent_class)->finalize (self);
+}
+
+/**
+ * gdata_freebase_service_new:
+ * @developer_key: (allow-none): developer key to use the API, or %NULL
+ * @authorizer: (allow-none): a #GDataAuthorizer to authorize the service's requests, or %NULL
+ *
+ * Creates a new #GDataFreebaseService using the given #GDataAuthorizer. If @authorizer is %NULL, all requests are made as an unauthenticated user.
+ * Having both @developer_key and @authorizer set to %NULL is allowed, but this should be reserved for debugging situations, as there is a certain
+ * key-less quota for those purposes. If this service is used on any code intended to be deployed, one or both of @developer_key and @authorizer
+ * should be non-%NULL and valid.
+ *
+ * Return value: (transfer full): a new #GDataFreebaseService; unref with g_object_unref()
+ *
+ * Since: UNRELEASED
+ */
+GDataFreebaseService *
+gdata_freebase_service_new (const gchar *developer_key, GDataAuthorizer *authorizer)
+{
+ g_return_val_if_fail (authorizer == NULL || GDATA_IS_AUTHORIZER (authorizer), NULL);
+
+ return g_object_new (GDATA_TYPE_FREEBASE_SERVICE,
+ "developer-key", developer_key,
+ "authorizer", authorizer,
+ NULL);
+}
+
+/**
+ * gdata_freebase_service_get_primary_authorization_domain:
+ *
+ * The primary #GDataAuthorizationDomain for interacting with Freebase. This will not normally need to be used, as it's used internally
+ * by the #GDataFreebaseService methods. However, if using the plain #GDataService methods to implement custom queries or requests which libgdata
+ * does not support natively, then this domain may be needed to authorize the requests.
+ *
+ * The domain never changes, and is interned so that pointer comparison can be used to differentiate it from other authorization domains.
+ *
+ * Return value: (transfer none): the service's authorization domain
+ *
+ * Since: 0.9.0
+ */
+GDataAuthorizationDomain *
+gdata_freebase_service_get_primary_authorization_domain (void)
+{
+ return get_freebase_authorization_domain ();
+}
+
+/**
+ * gdata_freebase_service_query:
+ * @self: a #GDataFreebaseService
+ * @query: a #GDataFreebaseQuery with the MQL query
+ * @cancellable: (allow-none): optional #GCancellable object, or %NULL
+ * @error: (allow-none): a #GError, or %NULL
+ *
+ * Performs a MQL query on the service, you can find out more about MQL in the <ulink type="http" url="http://mql.freebaseapps.com/index.html">online MQL documentation</ulink>.
+ *
+ * Return value: (transfer full): a #GDataFreebaseResult containing the query result; unref with g_object_unref()
+ *
+ * Since: UNRELEASED
+ */
+GDataFreebaseResult *
+gdata_freebase_service_query (GDataFreebaseService *self, GDataFreebaseQuery *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_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 (), "mqlread",
+ GDATA_QUERY (query), GDATA_TYPE_FREEBASE_RESULT, cancellable, error);
+ if (entry == NULL)
+ return NULL;
+
+ return GDATA_FREEBASE_RESULT (entry);
+}
+
+/**
+ * gdata_freebase_service_query_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
+ *
+ * Performs a MQL query on the service. @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_query(), which is the synchronous version of
+ * this function.
+ *
+ * Since: UNRELEASED
+ */
+void
+gdata_freebase_service_query_async (GDataFreebaseService *self, GDataFreebaseQuery *query, GCancellable *cancellable,
+ GAsyncReadyCallback callback, gpointer user_data)
+{
+ g_return_if_fail (GDATA_IS_FREEBASE_SERVICE (self));
+ g_return_if_fail (GDATA_IS_FREEBASE_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 (), "mqlread",
+ 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
new file mode 100644
index 00000000..1ccce64a
--- /dev/null
+++ b/gdata/services/freebase/gdata-freebase-service.h
@@ -0,0 +1,81 @@
+/* -*- 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_SERVICE_H
+#define GDATA_FREEBASE_SERVICE_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libsoup/soup.h>
+
+#include <gdata/gdata-service.h>
+#include <gdata/gdata-download-stream.h>
+#include "gdata-freebase-query.h"
+#include "gdata-freebase-result.h"
+
+G_BEGIN_DECLS
+
+#define GDATA_TYPE_FREEBASE_SERVICE (gdata_freebase_service_get_type ())
+#define GDATA_FREEBASE_SERVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDATA_TYPE_FREEBASE_SERVICE, GDataFreebaseService))
+#define GDATA_FREEBASE_SERVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDATA_TYPE_FREEBASE_SERVICE, GDataFreebaseServiceClass))
+#define GDATA_IS_FREEBASE_SERVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDATA_TYPE_FREEBASE_SERVICE))
+#define GDATA_IS_FREEBASE_SERVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDATA_TYPE_FREEBASE_SERVICE))
+#define GDATA_FREEBASE_SERVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDATA_TYPE_FREEBASE_SERVICE, GDataFreebaseServiceClass))
+
+typedef struct _GDataFreebaseServicePrivate GDataFreebaseServicePrivate;
+
+/**
+ * GDataFreebaseService:
+ *
+ * All the fields in the #GDataFreebaseService structure are private and should never be accessed directly.
+ *
+ * Since: UNRELEASED
+ **/
+typedef struct {
+ GDataService parent;
+ /*< private >*/
+ GDataFreebaseServicePrivate *priv;
+} GDataFreebaseService;
+
+/**
+ * GDataFreebaseServiceClass:
+ *
+ * All the fields in the #GDataFreebaseServiceClass structure are private and should never be accessed directly.
+ *
+ * Since: UNRELEASED
+ **/
+typedef struct {
+ /*< private >*/
+ GDataServiceClass parent;
+} GDataFreebaseServiceClass;
+
+GType gdata_freebase_service_get_type (void) G_GNUC_CONST;
+
+GDataFreebaseService *gdata_freebase_service_new (const gchar *developer_key, GDataAuthorizer *authorizer) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
+
+GDataAuthorizationDomain *gdata_freebase_service_get_primary_authorization_domain (void) G_GNUC_CONST;
+
+GDataFreebaseResult *gdata_freebase_service_query (GDataFreebaseService *self, GDataFreebaseQuery *query,
+ GCancellable *cancellable, GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
+void gdata_freebase_service_query_async (GDataFreebaseService *self, GDataFreebaseQuery *query,
+ GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+
+G_END_DECLS
+
+#endif /* !GDATA_FREEBASE_SERVICE_H */