diff options
author | Carlos Garnacho <carlosg@gnome.org> | 2014-03-17 02:05:17 +0100 |
---|---|---|
committer | Carlos Garnacho <carlosg@gnome.org> | 2014-05-27 02:36:27 +0200 |
commit | 7d919fd88d88fa39f6870588826469bdae811d1a (patch) | |
tree | f8216771d112d5150a69906135cb2f832c61c966 /gdata/services | |
parent | b03f422a2e87dda27f593c866a45c1f112b4f6a8 (diff) | |
download | libgdata-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.c | 245 | ||||
-rw-r--r-- | gdata/services/freebase/gdata-freebase-query.h | 72 | ||||
-rw-r--r-- | gdata/services/freebase/gdata-freebase-result.c | 196 | ||||
-rw-r--r-- | gdata/services/freebase/gdata-freebase-result.h | 72 | ||||
-rw-r--r-- | gdata/services/freebase/gdata-freebase-service.c | 255 | ||||
-rw-r--r-- | gdata/services/freebase/gdata-freebase-service.h | 81 |
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 */ |