[libgdata] freebase: Add search API



commit 413e3cd52df049909cf6ddea52be2fdc560d2890
Author: Carlos Garnacho <carlosg gnome org>
Date:   Mon Mar 17 02:41:12 2014 +0100

    freebase: Add search API
    
    This API enables searching for search terms, returning amongst other
    info the Freebase IDs usable on the topic API.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=726486

 Makefile.am                                        |   32 +-
 docs/reference/gdata-docs.xml                      |    2 +
 docs/reference/gdata-sections.txt                  |   60 ++
 gdata/gdata.h                                      |    3 +
 gdata/gdata.symbols                                |   25 +
 .../freebase/gdata-freebase-search-query.c         |  602 ++++++++++++++++++++
 .../freebase/gdata-freebase-search-query.h         |   97 ++++
 .../freebase/gdata-freebase-search-result.c        |  395 +++++++++++++
 .../freebase/gdata-freebase-search-result.h        |   93 +++
 gdata/services/freebase/gdata-freebase-service.c   |   62 ++
 gdata/services/freebase/gdata-freebase-service.h   |    7 +
 11 files changed, 1377 insertions(+), 1 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index b2b685d..0a472d4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -26,6 +26,8 @@ GDATA_ENUM_FILES = \
        gdata/media/gdata-media-enums.h                         \
        gdata/services/documents/gdata-documents-enums.c        \
        gdata/services/documents/gdata-documents-enums.h        \
+       gdata/services/freebase/gdata-freebase-enums.c          \
+       gdata/services/freebase/gdata-freebase-enums.h          \
        gdata/services/picasaweb/gdata-picasaweb-enums.c        \
        gdata/services/picasaweb/gdata-picasaweb-enums.h        \
        gdata/services/youtube/gdata-youtube-enums.c            \
@@ -95,6 +97,29 @@ gdata/services/documents/gdata-documents-enums.c: $(gdata_documents_headers) Mak
        && sed "s/g_data/gdata/" gdata/services/documents/gdata-documents-enums.c.tmp > 
gdata/services/documents/gdata-documents-enums.c \
        && rm -f gdata/services/documents/gdata-documents-enums.c.tmp)
 
+gdata/services/freebase/gdata-freebase-enums.h: $(gdata_freebase_headers) Makefile
+       $(AM_V_GEN)($(GLIB_MKENUMS) \
+                       --fhead "#ifndef GDATA_FREEBASE_ENUMS_H\n#define GDATA_FREEBASE_ENUMS_H\n\n#include 
<glib-object.h>\n\nG_BEGIN_DECLS\n" \
+                       --fprod "/* enumerations from \"@filename \" */\n" \
+                       --vhead "GType @enum_name _get_type (void) G_GNUC_CONST;\n#define GDATA_TYPE_ 
ENUMSHORT@ (@enum_name _get_type())\n" \
+                       --ftail "G_END_DECLS\n\n#endif /* !GDATA_FREEBASE_ENUMS_H */" \
+               $(addprefix $(srcdir)/,$(gdata_freebase_headers)) > 
gdata/services/freebase/gdata-freebase-enums.h.tmp \
+       && sed "s/g_data_freebase/gdata_freebase/" gdata/services/freebase/gdata-freebase-enums.h.tmp > 
gdata/services/freebase/gdata-freebase-enums.h.tmp2 \
+       && sed "s/GDATA_TYPE_DATA_FREEBASE/GDATA_TYPE_FREEBASE/" 
gdata/services/freebase/gdata-freebase-enums.h.tmp2 > gdata/services/freebase/gdata-freebase-enums.h \
+       && rm -f gdata/services/freebase/gdata-freebase-enums.h.tmp \
+       && rm -f gdata/services/freebase/gdata-freebase-enums.h.tmp2)
+
+gdata/services/freebase/gdata-freebase-enums.c: $(gdata_freebase_headers) Makefile 
gdata/services/freebase/gdata-freebase-enums.h
+       $(AM_V_GEN)($(GLIB_MKENUMS) \
+                       --fhead "#include \"gdata-freebase-service.h\"\n#include 
\"gdata-freebase-search-query.h\"\n#include \"gdata-freebase-result.h\"\n#include \"gdata-freebase-enums.h\"" 
\
+                       --fprod "\n/* enumerations from \"@filename \" */" \
+                       --vhead "GType\n enum_name@_get_type (void)\n{\n  static GType etype = 0;\n  if 
(etype == 0) {\n    static const G Type@Value values[] = {" \
+                       --vprod "      { @VALUENAME@, \"@VALUENAME \", \"@valuenick \" }," \
+                       --vtail "      { 0, NULL, NULL }\n    };\n    etype = g_ type@_register_static 
(\"@EnumName \", values);\n  }\n  return etype;\n}\n" \
+               $(addprefix $(srcdir)/,$(gdata_freebase_headers)) > 
gdata/services/freebase/gdata-freebase-enums.c.tmp \
+       && sed "s/g_data_freebase/gdata_freebase/" gdata/services/freebase/gdata-freebase-enums.c.tmp > 
gdata/services/freebase/gdata-freebase-enums.c \
+       && rm -f gdata/services/freebase/gdata-freebase-enums.c.tmp)
+
 gdata/services/picasaweb/gdata-picasaweb-enums.h: $(gdata_picasaweb_headers) Makefile
        $(AM_V_GEN)($(GLIB_MKENUMS) \
                        --fhead "#ifndef GDATA_PICASAWEB_ENUMS_H\n#define GDATA_PICASAWEB_ENUMS_H\n\n#include 
<glib-object.h>\n\nG_BEGIN_DECLS\n" \
@@ -309,11 +334,14 @@ 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-search-query.h           \
+       gdata/services/freebase/gdata-freebase-search-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)
+       $(gdata_freebase_headers)                                       \
+       gdata/services/freebase/gdata-freebase-enums.h
 
 gdata_sources = \
        gdata/gdata-entry.c             \
@@ -426,6 +454,8 @@ gdata_sources = \
        \
        gdata/services/freebase/gdata-freebase-service.c                \
        gdata/services/freebase/gdata-freebase-result.c                 \
+       gdata/services/freebase/gdata-freebase-search-query.c           \
+       gdata/services/freebase/gdata-freebase-search-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 262ec28..c4edade 100644
--- a/docs/reference/gdata-docs.xml
+++ b/docs/reference/gdata-docs.xml
@@ -191,6 +191,8 @@
                        <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"/>
+                       <xi:include href="xml/gdata-freebase-search-query.xml"/>
+                       <xi:include href="xml/gdata-freebase-search-result.xml"/>
                </chapter>
        </part>
 
diff --git a/docs/reference/gdata-sections.txt b/docs/reference/gdata-sections.txt
index 4cc4604..2e9dbc6 100644
--- a/docs/reference/gdata-sections.txt
+++ b/docs/reference/gdata-sections.txt
@@ -2577,6 +2577,8 @@ gdata_freebase_service_query
 gdata_freebase_service_query_async
 gdata_freebase_service_get_topic
 gdata_freebase_service_get_topic_async
+gdata_freebase_service_search
+gdata_freebase_service_search_async
 <SUBSECTION Standard>
 gdata_freebase_service_get_type
 GDATA_FREEBASE_SERVICE
@@ -2694,3 +2696,61 @@ GDATA_TYPE_FREEBASE_TOPIC_VALUE
 <SUBSECTION Private>
 GDataFreebaseTopicResultPrivate
 </SECTION>
+
+<SECTION>
+<FILE>gdata-freebase-search-query</FILE>
+<TITLE>GDataFreebaseSearchQuery</TITLE>
+GDataFreebaseSearchQuery
+GDataFreebaseSearchQueryClass
+gdata_freebase_search_query_new
+gdata_freebase_search_query_set_language
+gdata_freebase_search_query_get_language
+gdata_freebase_search_query_set_stemmed
+gdata_freebase_search_query_get_stemmed
+GDataFreebaseSearchFilterType
+gdata_freebase_search_query_open_filter
+gdata_freebase_search_query_close_filter
+gdata_freebase_search_query_add_filter
+gdata_freebase_search_query_add_location
+<SUBSECTION Standard>
+gdata_freebase_search_query_get_type
+GDATA_FREEBASE_SEARCH_QUERY
+GDATA_FREEBASE_SEARCH_QUERY_CLASS
+GDATA_FREEBASE_SEARCH_QUERY_GET_CLASS
+GDATA_IS_FREEBASE_SEARCH_QUERY
+GDATA_IS_FREEBASE_SEARCH_QUERY_CLASS
+GDATA_TYPE_FREEBASE_SEARCH_QUERY
+gdata_freebase_search_filter_type_get_type
+GDATA_TYPE_FREEBASE_SEARCH_FILTER_TYPE
+<SUBSECTION Private>
+GDataFreebaseSearchQueryPrivate
+</SECTION>
+
+<SECTION>
+<FILE>gdata-freebase-search-result</FILE>
+<TITLE>GDataFreebaseSearchResult</TITLE>
+GDataFreebaseSearchResult
+GDataFreebaseSearchResultClass
+GDataFreebaseSearchResultItem
+gdata_freebase_search_result_new
+gdata_freebase_search_result_get_num_items
+gdata_freebase_search_result_get_total_hits
+gdata_freebase_search_result_get_item
+gdata_freebase_search_result_item_get_mid
+gdata_freebase_search_result_item_get_id
+gdata_freebase_search_result_item_get_name
+gdata_freebase_search_result_item_get_language
+gdata_freebase_search_result_item_get_notable_id
+gdata_freebase_search_result_item_get_notable_name
+gdata_freebase_search_result_item_get_score
+<SUBSECTION Standard>
+gdata_freebase_search_result_get_type
+GDATA_FREEBASE_SEARCH_RESULT
+GDATA_FREEBASE_SEARCH_RESULT_CLASS
+GDATA_FREEBASE_SEARCH_RESULT_GET_CLASS
+GDATA_IS_FREEBASE_SEARCH_RESULT
+GDATA_IS_FREEBASE_SEARCH_RESULT_CLASS
+GDATA_TYPE_FREEBASE_SEARCH_RESULT
+<SUBSECTION Private>
+GDataFreebaseSearchResultPrivate
+</SECTION>
diff --git a/gdata/gdata.h b/gdata/gdata.h
index 579ecad..158a765 100644
--- a/gdata/gdata.h
+++ b/gdata/gdata.h
@@ -147,7 +147,10 @@
 #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-search-query.h>
+#include <gdata/services/freebase/gdata-freebase-search-result.h>
 #include <gdata/services/freebase/gdata-freebase-topic-query.h>
 #include <gdata/services/freebase/gdata-freebase-topic-result.h>
+#include <gdata/services/freebase/gdata-freebase-enums.h>
 
 #endif /* !GDATA_H */
diff --git a/gdata/gdata.symbols b/gdata/gdata.symbols
index b149eb6..5fd4815 100644
--- a/gdata/gdata.symbols
+++ b/gdata/gdata.symbols
@@ -1026,9 +1026,34 @@ gdata_freebase_service_query
 gdata_freebase_service_query_async
 gdata_freebase_service_get_topic
 gdata_freebase_service_get_topic_async
+gdata_freebase_service_search
+gdata_freebase_service_search_async
 gdata_freebase_query_get_type
 gdata_freebase_query_new
 gdata_freebase_query_new_from_variant
+gdata_freebase_search_filter_type_get_type
+gdata_freebase_search_query_get_type
+gdata_freebase_search_query_new
+gdata_freebase_search_query_open_filter
+gdata_freebase_search_query_close_filter
+gdata_freebase_search_query_add_filter
+gdata_freebase_search_query_add_location
+gdata_freebase_search_query_set_language
+gdata_freebase_search_query_get_language
+gdata_freebase_search_query_set_stemmed
+gdata_freebase_search_query_get_stemmed
+gdata_freebase_search_result_get_type
+gdata_freebase_search_result_new
+gdata_freebase_search_result_get_num_items
+gdata_freebase_search_result_get_total_hits
+gdata_freebase_search_result_get_item
+gdata_freebase_search_result_item_get_mid
+gdata_freebase_search_result_item_get_id
+gdata_freebase_search_result_item_get_name
+gdata_freebase_search_result_item_get_language
+gdata_freebase_search_result_item_get_notable_name
+gdata_freebase_search_result_item_get_notable_id
+gdata_freebase_search_result_item_get_score
 gdata_freebase_topic_query_get_type
 gdata_freebase_topic_query_new
 gdata_freebase_topic_query_set_filter
diff --git a/gdata/services/freebase/gdata-freebase-search-query.c 
b/gdata/services/freebase/gdata-freebase-search-query.c
new file mode 100644
index 0000000..de6bf59
--- /dev/null
+++ b/gdata/services/freebase/gdata-freebase-search-query.c
@@ -0,0 +1,602 @@
+/* -*- 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-search-query
+ * @short_description: GData Freebase query object
+ * @stability: Unstable
+ * @include: gdata/services/freebase/gdata-freebase-query.h
+ *
+ * #GDataFreebaseQuery represents a collection of query parameters specific to the Google Freebase service.
+ * a #GDataFreebaseQuery is built on top of a search term, further filters can be set on the search query
+ * through gdata_freebase_search_query_add_filter() or gdata_freebase_search_query_add_location(). The 
filters
+ * can be nested in sublevels, created through gdata_freebase_search_query_open_filter()
+ * and gdata_freebase_search_query_close_filter().
+ *
+ * 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-search-query.h"
+#include "gdata-query.h"
+#include "gdata-parser.h"
+
+static void gdata_freebase_search_query_finalize (GObject *self);
+static void gdata_freebase_search_query_set_property (GObject *self, guint prop_id, const GValue *value, 
GParamSpec *pspec);
+static void gdata_freebase_search_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);
+
+typedef enum {
+       NODE_CONTAINER,
+       NODE_VALUE,
+       NODE_LOCATION
+} FilterNodeType;
+
+typedef union {
+       FilterNodeType type;
+
+       struct {
+               FilterNodeType type;
+               GDataFreebaseSearchFilterType filter_type;
+               GPtrArray *child_nodes; /* Contains owned FilterNode structs */
+       } container;
+
+       struct {
+               FilterNodeType type;
+               gchar *property;
+               gchar *value;
+       } value;
+
+       struct {
+               FilterNodeType type;
+               guint64 radius;
+               gdouble lat;
+               gdouble lon;
+       } location;
+} FilterNode;
+
+struct _GDataFreebaseSearchQueryPrivate {
+       FilterNode *filter;
+       GList *filter_stack; /* Contains unowned FilterNode structs */
+
+       gchar *lang;
+       guint stemmed : 1;
+};
+
+enum {
+       PROP_LANGUAGE = 1,
+       PROP_STEMMED
+};
+
+G_DEFINE_TYPE (GDataFreebaseSearchQuery, gdata_freebase_search_query, GDATA_TYPE_QUERY)
+
+static void
+gdata_freebase_search_query_class_init (GDataFreebaseSearchQueryClass *klass)
+{
+       GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+       GDataQueryClass *query_class = GDATA_QUERY_CLASS (klass);
+
+       g_type_class_add_private (klass, sizeof (GDataFreebaseSearchQueryPrivate));
+
+       gobject_class->finalize = gdata_freebase_search_query_finalize;
+       gobject_class->set_property = gdata_freebase_search_query_set_property;
+       gobject_class->get_property = gdata_freebase_search_query_get_property;
+
+       query_class->get_query_uri = get_query_uri;
+
+       /**
+        * GDataFreebaseSearchQuery:language:
+        *
+        * Language used for search results, 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));
+       /**
+        * GDataFreebaseSearchQuery:stemmed:
+        *
+        * Whether word stemming should happen on the search terms. If this property is enabled,
+        * words like eg. "natural", "naturally" or "nature" would be all reduced to the root "natur"
+        * for search purposes.
+        *
+        * Since: UNRELEASED
+        */
+       g_object_class_install_property (gobject_class, PROP_STEMMED,
+                                        g_param_spec_boolean ("stemmed",
+                                                              "Stem search terms",
+                                                              "Whether the search terms should be stemmed",
+                                                              FALSE,
+                                                              G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gdata_freebase_search_query_init (GDataFreebaseSearchQuery *self)
+{
+       self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_FREEBASE_SEARCH_QUERY, 
GDataFreebaseSearchQueryPrivate);
+}
+
+static void
+_free_filter_node (FilterNode *node)
+{
+       switch (node->type) {
+       case NODE_CONTAINER:
+               g_ptr_array_unref (node->container.child_nodes);
+               break;
+       case NODE_VALUE:
+               g_free (node->value.property);
+               g_free (node->value.value);
+               break;
+       case NODE_LOCATION:
+       default:
+               break;
+       }
+
+       g_slice_free (FilterNode, node);
+}
+
+static void
+gdata_freebase_search_query_finalize (GObject *self)
+{
+       GDataFreebaseSearchQueryPrivate *priv = GDATA_FREEBASE_SEARCH_QUERY (self)->priv;
+
+       g_free (priv->lang);
+       g_list_free (priv->filter_stack);
+
+       if (priv->filter != NULL)
+               _free_filter_node (priv->filter);
+
+       /* Chain up to the parent class */
+       G_OBJECT_CLASS (gdata_freebase_search_query_parent_class)->finalize (self);
+}
+
+static void
+gdata_freebase_search_query_set_property (GObject *self, guint prop_id, const GValue *value, GParamSpec 
*pspec)
+{
+       GDataFreebaseSearchQuery *query = GDATA_FREEBASE_SEARCH_QUERY (self);
+
+       switch (prop_id) {
+       case PROP_LANGUAGE:
+               gdata_freebase_search_query_set_language (query, g_value_get_string (value));
+               break;
+       case PROP_STEMMED:
+               gdata_freebase_search_query_set_stemmed (query, g_value_get_boolean (value));
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+gdata_freebase_search_query_get_property (GObject *self, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+       GDataFreebaseSearchQueryPrivate *priv = GDATA_FREEBASE_SEARCH_QUERY (self)->priv;
+
+       switch (prop_id) {
+       case PROP_LANGUAGE:
+               g_value_set_string (value, priv->lang);
+               break;
+       case PROP_STEMMED:
+               g_value_set_boolean (value, priv->stemmed);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+build_filter_string (FilterNode *node,
+                    GString    *str)
+{
+       switch (node->type) {
+       case NODE_CONTAINER:
+       {
+               /* Array matches GDataFreebaseSearchFilterType */
+               const gchar *type_str[] = { "all", "any", "not" };
+               guint i;
+
+               g_assert (node->container.filter_type >=0 &&
+                         node->container.filter_type < G_N_ELEMENTS (type_str));
+
+               g_string_append_printf (str, "(%s", type_str[node->container.type]);
+
+               for (i = 0; i < node->container.child_nodes->len; i++)
+                       build_filter_string (g_ptr_array_index (node->container.child_nodes, i), str);
+
+               g_string_append (str, ")");
+               break;
+       }
+       case NODE_VALUE:
+       {
+               gchar *escaped;
+
+               escaped = g_strescape (node->value.value, NULL);
+               g_string_append_printf (str, " %s:\"%s\"", node->value.property, escaped);
+               g_free (escaped);
+               break;
+       }
+       case NODE_LOCATION:
+               g_string_append_printf (str, "(within radius:%" G_GUINT64_FORMAT "m lon:%.4f lat:%.4f)",
+                                       node->location.radius, node->location.lon, node->location.lat);
+               break;
+       default:
+               g_assert_not_reached ();
+               break;
+       }
+}
+
+static void
+get_query_uri (GDataQuery *self, const gchar *feed_uri, GString *query_uri, gboolean *params_started)
+{
+       GDataFreebaseSearchQueryPrivate *priv = GDATA_FREEBASE_SEARCH_QUERY (self)->priv;
+       const gchar *query, *lang = NULL;
+       gint64 updated_max;
+       guint cur, limit;
+
+#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);
+       }
+
+       if (priv->filter != NULL) {
+               GString *str = g_string_new (NULL);
+
+               build_filter_string (priv->filter, str);
+
+               APPEND_SEP;
+               g_string_append (query_uri, "filter=");
+               g_string_append (query_uri, str->str);
+               g_string_free (str, TRUE);
+       }
+
+       updated_max = gdata_query_get_updated_max (self);
+
+       if (updated_max != -1) {
+               gchar *date_str;
+
+               date_str = gdata_parser_int64_to_json_iso8601 (updated_max);
+
+               APPEND_SEP;
+               g_string_append (query_uri, "as_of_time=");
+               g_string_append (query_uri, date_str);
+               g_free (date_str);
+       }
+
+       if (priv->lang != NULL) {
+               lang = priv->lang;
+       } else {
+               const gchar * const *user_languages;
+               GString *lang_str = NULL;
+               gint i;
+
+               user_languages = g_get_language_names ();
+
+               for (i = 0; user_languages[i] != NULL; i++) {
+                       if (strlen (user_languages[i]) != 2)
+                               continue;
+
+                       if (!lang_str)
+                               lang_str = g_string_new (user_languages[i]);
+                       else
+                               g_string_append_printf (lang_str, ",%s", user_languages[i]);
+               }
+
+               lang = g_string_free (lang_str, FALSE);
+       }
+
+       APPEND_SEP;
+       g_string_append (query_uri, "lang=");
+       g_string_append (query_uri, lang);
+
+       if (priv->stemmed) {
+               APPEND_SEP;
+               g_string_append (query_uri, "stemmed=true");
+       }
+
+       cur = gdata_query_get_start_index (self);
+
+       if (cur > 0) {
+               APPEND_SEP;
+               g_string_append_printf (query_uri, "cursor=%d", cur);
+       }
+
+       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_search_query_new:
+ * @search_terms: string to search for
+ *
+ * Creates a new #GDataFreebaseSearchQuery prepared to search for Freebase elements that
+ * match the given @search_terms. Further filters on the query can be set through
+ * gdata_freebase_search_query_add_filter() or gdata_freebase_search_query_add_location().
+ *
+ * Return value: (transfer full): a new #GDataFreebaseSearchQuery; unref with g_object_unref()
+ *
+ * Since: UNRELEASED
+ */
+GDataFreebaseSearchQuery *
+gdata_freebase_search_query_new (const gchar *search_terms)
+{
+       g_return_val_if_fail (search_terms != NULL, NULL);
+       return g_object_new (GDATA_TYPE_FREEBASE_SEARCH_QUERY, "q", search_terms, NULL);
+}
+
+/**
+ * gdata_freebase_search_query_open_filter:
+ * @self: a #GDataFreebaseSearchQuery
+ * @filter_type: filter type
+ *
+ * Opens a container of filter rules, those are applied according to the behavior specified by @filter_type.
+ * Every call to this function must be paired by a call to gdata_freebase_search_query_close_filter().
+ *
+ * Since: UNRELEASED
+ **/
+void
+gdata_freebase_search_query_open_filter (GDataFreebaseSearchQuery *self, GDataFreebaseSearchFilterType 
filter_type)
+{
+       GDataFreebaseSearchQueryPrivate *priv;
+       FilterNode *current_node, *node;
+
+       g_return_if_fail (GDATA_IS_FREEBASE_SEARCH_QUERY (self));
+
+       priv = GDATA_FREEBASE_SEARCH_QUERY (self)->priv;
+
+       node = g_slice_new0 (FilterNode);
+       node->type = NODE_CONTAINER;
+       node->container.filter_type = filter_type;
+       node->container.child_nodes = g_ptr_array_new_with_free_func ((GDestroyNotify) _free_filter_node);
+
+       if (priv->filter_stack != NULL) {
+               current_node = priv->filter_stack->data;
+               g_ptr_array_add (current_node->container.child_nodes, node);
+       } else if (priv->filter == NULL) {
+               priv->filter = node;
+       } else {
+               g_assert_not_reached ();
+       }
+
+       priv->filter_stack = g_list_prepend (priv->filter_stack, node);
+}
+
+/**
+ * gdata_freebase_search_query_close_filter:
+ * @self: a #GDataFreebaseSearchQuery
+ *
+ * Closes a filter level.
+ *
+ * Since: UNRELEASED
+ **/
+void
+gdata_freebase_search_query_close_filter (GDataFreebaseSearchQuery *self)
+{
+       GDataFreebaseSearchQueryPrivate *priv;
+
+       g_return_if_fail (GDATA_IS_FREEBASE_SEARCH_QUERY (self));
+
+       priv = GDATA_FREEBASE_SEARCH_QUERY (self)->priv;
+
+       if (priv->filter_stack == NULL)
+               g_assert_not_reached ();
+
+       priv->filter_stack = g_list_delete_link (priv->filter_stack, priv->filter_stack);
+}
+
+/**
+ * gdata_freebase_search_query_add_filter:
+ * @self: a #GDataFreebaseSearchQuery
+ * @property: Freebase property ID
+ * @value: match string
+ *
+ * Adds a property filter to the query. property filters are always nested in
+ * containers, opened and closed through gdata_freebase_search_query_open_filter()
+ * and gdata_freebase_search_query_close_filter().
+ *
+ * Since: UNRELEASED
+ **/
+void
+gdata_freebase_search_query_add_filter (GDataFreebaseSearchQuery *self, const gchar *property, const gchar 
*value)
+{
+       GDataFreebaseSearchQueryPrivate *priv;
+       FilterNode *current_node, *node;
+
+       g_return_if_fail (GDATA_IS_FREEBASE_SEARCH_QUERY (self));
+       g_return_if_fail (property != NULL && value != NULL);
+
+       priv = GDATA_FREEBASE_SEARCH_QUERY (self)->priv;
+
+       if (priv->filter_stack == NULL) {
+               g_critical ("A filter container must be opened before through "
+                           "gdata_freebase_search_query_open_filter()");
+               g_assert_not_reached ();
+       }
+
+       node = g_slice_new0 (FilterNode);
+       node->type = NODE_VALUE;
+       node->value.property = g_strdup (property);
+       node->value.value = g_strdup (value);
+
+       current_node = priv->filter_stack->data;
+       g_ptr_array_add (current_node->container.child_nodes, node);
+}
+
+/**
+ * gdata_freebase_search_query_add_location:
+ * @self: a #GDataFreebaseSearchQuery
+ * @radius: radius in meters
+ * @lat: latitude
+ * @lon: longitude
+ *
+ * Adds a geolocation filter to the query. location filters are always nested in
+ * containers, opened and closed through gdata_freebase_search_query_open_filter()
+ * and gdata_freebase_search_query_close_filter().
+ *
+ * Since: UNRELEASED
+ **/
+void
+gdata_freebase_search_query_add_location (GDataFreebaseSearchQuery *self, guint64 radius, gdouble lat, 
gdouble lon)
+{
+       GDataFreebaseSearchQueryPrivate *priv = GDATA_FREEBASE_SEARCH_QUERY (self)->priv;
+       FilterNode *current_node, *node;
+
+       g_return_if_fail (GDATA_IS_FREEBASE_SEARCH_QUERY (self));
+
+       if (priv->filter_stack == NULL) {
+               g_critical ("A filter container must be opened before through "
+                           "gdata_freebase_search_query_open_filter()");
+               g_assert_not_reached ();
+       }
+
+       node = g_slice_new0 (FilterNode);
+       node->type = NODE_LOCATION;
+       node->location.radius = radius;
+       node->location.lat = lat;
+       node->location.lon = lon;
+
+       current_node = priv->filter_stack->data;
+       g_ptr_array_add (current_node->container.child_nodes, node);
+}
+
+/**
+ * gdata_freebase_search_query_set_language:
+ * @self: a #GDataFreebaseSearchQuery
+ * @lang: (allow-none): Language used on the search terms and results, in ISO-639-1 format, or %NULL to 
unset.
+ *
+ * Sets the language used, both on the search terms and the results. If unset,
+ * the locale preferences will be respected.
+ *
+ * Since: UNRELEASED
+ **/
+void
+gdata_freebase_search_query_set_language (GDataFreebaseSearchQuery *self,
+                                         const gchar              *lang)
+{
+       GDataFreebaseSearchQueryPrivate *priv;
+
+       g_return_if_fail (GDATA_IS_FREEBASE_SEARCH_QUERY (self));
+       g_return_if_fail (!lang || 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_search_query_get_language:
+ * @self: a #GDataFreebaseSearchQuery
+ *
+ * Gets the language set on the search query, or %NULL if unset.
+ *
+ * Return value: (allow-none): The language used on the query.
+ *
+ * Since: UNRELEASED
+ **/
+const gchar *
+gdata_freebase_search_query_get_language (GDataFreebaseSearchQuery *self)
+{
+       GDataFreebaseSearchQueryPrivate *priv;
+
+       g_return_val_if_fail (GDATA_IS_FREEBASE_SEARCH_QUERY (self), NULL);
+
+       priv = self->priv;
+       return priv->lang;
+}
+
+/**
+ * gdata_freebase_search_query_set_stemmed:
+ * @self: a #GDataFreebaseSearchQuery
+ * @stemmed: %TRUE to perform stemming on the search results
+ *
+ * Sets whether stemming is performed on the provided search terms. If @stemmed is %TRUE,
+ * words like eg. "natural", "naturally" or "nature" would be all reduced to the root "natur"
+ * for search purposes.
+ *
+ * Since: UNRELEASED
+ **/
+void
+gdata_freebase_search_query_set_stemmed (GDataFreebaseSearchQuery *self,
+                                        gboolean                  stemmed)
+{
+       GDataFreebaseSearchQueryPrivate *priv;
+
+       g_return_if_fail (GDATA_IS_FREEBASE_SEARCH_QUERY (self));
+
+       priv = self->priv;
+
+       if (priv->stemmed == stemmed)
+               return;
+
+       priv->stemmed = stemmed;
+       g_object_notify (G_OBJECT (self), "stemmed");
+}
+
+/**
+ * gdata_freebase_search_query_get_stemmed:
+ * @self: a #GDataFreebaseSearchQuery
+ *
+ * Returns whether the #GDataFreebaseSearchQuery will perform stemming on the search terms.
+ *
+ * Return value: %TRUE if the #GDataFreebaseSearchQuery performs stemming
+ *
+ * Since: UNRELEASED
+ **/
+gboolean
+gdata_freebase_search_query_get_stemmed (GDataFreebaseSearchQuery *self)
+{
+       GDataFreebaseSearchQueryPrivate *priv;
+
+       g_return_val_if_fail (GDATA_IS_FREEBASE_SEARCH_QUERY (self), FALSE);
+
+       priv = self->priv;
+       return priv->stemmed;
+}
diff --git a/gdata/services/freebase/gdata-freebase-search-query.h 
b/gdata/services/freebase/gdata-freebase-search-query.h
new file mode 100644
index 0000000..58172a9
--- /dev/null
+++ b/gdata/services/freebase/gdata-freebase-search-query.h
@@ -0,0 +1,97 @@
+/* -*- 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_SEARCH_QUERY_H
+#define GDATA_FREEBASE_SEARCH_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_SEARCH_QUERY               (gdata_freebase_search_query_get_type ())
+#define GDATA_FREEBASE_SEARCH_QUERY(o)                 (G_TYPE_CHECK_INSTANCE_CAST ((o), 
GDATA_TYPE_FREEBASE_SEARCH_QUERY, GDataFreebaseSearchQuery))
+#define GDATA_FREEBASE_SEARCH_QUERY_CLASS(k)           (G_TYPE_CHECK_CLASS_CAST((k), 
GDATA_TYPE_FREEBASE_SEARCH_QUERY, GDataFreebaseSearchQueryClass))
+#define GDATA_IS_FREEBASE_SEARCH_QUERY(o)              (G_TYPE_CHECK_INSTANCE_TYPE ((o), 
GDATA_TYPE_FREEBASE_SEARCH_QUERY))
+#define GDATA_IS_FREEBASE_SEARCH_QUERY_CLASS(k)                (G_TYPE_CHECK_CLASS_TYPE ((k), 
GDATA_TYPE_FREEBASE_SEARCH_QUERY))
+#define GDATA_FREEBASE_SEARCH_QUERY_GET_CLASS(o)       (G_TYPE_INSTANCE_GET_CLASS ((o), 
GDATA_TYPE_FREEBASE_SEARCH_QUERY, GDataFreebaseSearchQueryClass))
+
+typedef struct _GDataFreebaseSearchQueryPrivate        GDataFreebaseSearchQueryPrivate;
+
+/**
+ * GDataFreebaseSearchFilterType:
+ * @GDATA_FREEBASE_SEARCH_FILTER_ALL: all enclosed elements must match, logically an AND
+ * @GDATA_FREEBASE_SEARCH_FILTER_ANY: any of the enclosed elements must match, logically an OR
+ * @GDATA_FREEBASE_SEARCH_FILTER_NOT: the match is inverted.
+ *
+ * Search filter container types.
+ *
+ * Since: UNRELEASED
+ */
+typedef enum {
+       GDATA_FREEBASE_SEARCH_FILTER_ALL,
+       GDATA_FREEBASE_SEARCH_FILTER_ANY,
+       GDATA_FREEBASE_SEARCH_FILTER_NOT
+} GDataFreebaseSearchFilterType;
+
+/**
+ * GDataFreebaseSearchQuery:
+ *
+ * All the fields in the #GDataFreebaseSearchQuery structure are private and should never be accessed 
directly.
+ *
+ * Since: UNRELEASED
+ */
+typedef struct {
+       GDataQuery parent;
+       GDataFreebaseSearchQueryPrivate *priv;
+} GDataFreebaseSearchQuery;
+
+/**
+ * GDataFreebaseSearchQueryClass:
+ *
+ * All the fields in the #GDataFreebaseSearchQueryClass structure are private and should never be accessed 
directly.
+ *
+ * Since: UNRELEASED
+ */
+typedef struct {
+       /*< private >*/
+       GDataQueryClass parent;
+} GDataFreebaseSearchQueryClass;
+
+GType gdata_freebase_search_query_get_type (void) G_GNUC_CONST;
+
+GDataFreebaseSearchQuery *gdata_freebase_search_query_new (const gchar *search_terms) 
G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
+
+void gdata_freebase_search_query_open_filter (GDataFreebaseSearchQuery *self, GDataFreebaseSearchFilterType 
filter_type);
+void gdata_freebase_search_query_close_filter (GDataFreebaseSearchQuery *self);
+void gdata_freebase_search_query_add_filter (GDataFreebaseSearchQuery *self, const gchar *property, const 
gchar *value);
+void gdata_freebase_search_query_add_location (GDataFreebaseSearchQuery *self, guint64 radius, gdouble lat, 
gdouble lon);
+
+void gdata_freebase_search_query_set_language (GDataFreebaseSearchQuery *self, const gchar *lang);
+const gchar * gdata_freebase_search_query_get_language (GDataFreebaseSearchQuery *self);
+
+void gdata_freebase_search_query_set_stemmed (GDataFreebaseSearchQuery *self, gboolean stemmed);
+gboolean gdata_freebase_search_query_get_stemmed (GDataFreebaseSearchQuery *self);
+
+G_END_DECLS
+
+#endif /* !GDATA_FREEBASE_SEARCH_QUERY_H */
diff --git a/gdata/services/freebase/gdata-freebase-search-result.c 
b/gdata/services/freebase/gdata-freebase-search-result.c
new file mode 100644
index 0000000..8c21237
--- /dev/null
+++ b/gdata/services/freebase/gdata-freebase-search-result.c
@@ -0,0 +1,395 @@
+/* -*- 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-search-result
+ * @short_description: GData Freebase search result object
+ * @stability: Unstable
+ * @include: gdata/services/freebase/gdata-freebase-result.h
+ *
+ * #GDataFreebaseSearchResult is a subclass of #GDataEntry to represent the result of a Freebase search 
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-search-result.h"
+#include "gdata-private.h"
+#include "gdata-types.h"
+
+#define URLBASE "https://www.googleapis.com/freebase/v1";
+
+struct _GDataFreebaseSearchResultItem {
+       gchar *mid;
+       gchar *id;
+       gchar *name;
+       gchar *lang;
+       gchar *notable_id;
+       gchar *notable_name;
+       gdouble score;
+};
+
+struct _GDataFreebaseSearchResultPrivate {
+       GPtrArray *items; /* contains owned GDataFreebaseSearchResultItem structs */
+       guint total_hits;
+};
+
+static void gdata_freebase_search_result_finalize (GObject *self);
+static gboolean parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error);
+
+G_DEFINE_TYPE (GDataFreebaseSearchResult, gdata_freebase_search_result, GDATA_TYPE_FREEBASE_RESULT)
+
+static void
+gdata_freebase_search_result_class_init (GDataFreebaseSearchResultClass *klass)
+{
+       GDataParsableClass *parsable_class = GDATA_PARSABLE_CLASS (klass);
+       GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+       g_type_class_add_private (klass, sizeof (GDataFreebaseSearchResultPrivate));
+
+       gobject_class->finalize = gdata_freebase_search_result_finalize;
+       parsable_class->parse_json = parse_json;
+}
+
+static GDataFreebaseSearchResultItem *
+item_new (void)
+{
+       return g_slice_new0 (GDataFreebaseSearchResultItem);
+}
+
+static void
+item_free (GDataFreebaseSearchResultItem *item)
+{
+       g_free (item->mid);
+       g_free (item->id);
+       g_free (item->name);
+       g_free (item->lang);
+       g_free (item->notable_id);
+       g_free (item->notable_name);
+       g_slice_free (GDataFreebaseSearchResultItem, item);
+}
+
+static void
+gdata_freebase_search_result_init (GDataFreebaseSearchResult *self)
+{
+       self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_FREEBASE_SEARCH_RESULT, 
GDataFreebaseSearchResultPrivate);
+       self->priv->items = g_ptr_array_new_with_free_func ((GDestroyNotify) item_free);
+}
+
+static void
+gdata_freebase_search_result_finalize (GObject *self)
+{
+       GDataFreebaseSearchResultPrivate *priv = GDATA_FREEBASE_SEARCH_RESULT (self)->priv;
+
+       g_ptr_array_unref (priv->items);
+
+       G_OBJECT_CLASS (gdata_freebase_search_result_parent_class)->finalize (self);
+}
+
+static gboolean
+parse_json (GDataParsable *parsable, JsonReader *reader, gpointer user_data, GError **error)
+{
+       GDataFreebaseSearchResultPrivate *priv = GDATA_FREEBASE_SEARCH_RESULT (parsable)->priv;
+       const GError *inner_error = NULL;
+       const gchar *member_name;
+       gint count, i;
+
+       GDATA_PARSABLE_CLASS (gdata_freebase_search_result_parent_class)->parse_json (parsable, reader, 
user_data, error);
+
+#define ITEM_SET_STRING(id,field,mandatory)                            \
+       json_reader_read_member (reader, #id);                          \
+       item->field = g_strdup (json_reader_get_string_value (reader)); \
+       if (mandatory) {                                                \
+               inner_error = json_reader_get_error (reader);           \
+               if (inner_error != NULL) goto item_error;               \
+       }                                                               \
+       json_reader_end_member (reader);
+
+#define ITEM_SET_DOUBLE(id,field)                                      \
+       json_reader_read_member (reader, #id);                          \
+       item->field = json_reader_get_double_value (reader);            \
+       inner_error = json_reader_get_error (reader);                   \
+       if (inner_error != NULL) goto item_error;                       \
+       json_reader_end_member (reader);
+
+       member_name = json_reader_get_member_name (reader);
+
+       if (member_name == NULL)
+               return FALSE;
+
+       if (strcmp (member_name, "hits") == 0) {
+               priv->total_hits = json_reader_get_int_value (reader);
+               return TRUE;
+       } else if (strcmp (member_name, "result") != 0) {
+               /* Avoid anything else besides hits/result */
+               return TRUE;
+       }
+
+       if (!json_reader_is_array (reader))
+               return FALSE;
+
+       count = json_reader_count_elements (reader);
+
+       for (i = 0; i < count; i++) {
+               GDataFreebaseSearchResultItem *item;
+
+               item = item_new ();
+               json_reader_read_element (reader, i);
+
+               ITEM_SET_STRING (mid, mid, TRUE);
+               ITEM_SET_STRING (id, id, FALSE);
+               ITEM_SET_STRING (name, name, TRUE);
+               ITEM_SET_STRING (lang, lang, FALSE);
+               ITEM_SET_DOUBLE (score, score);
+
+               /* Read "notable" */
+               json_reader_read_member (reader, "notable");
+
+               if (json_reader_get_error (reader) == NULL) {
+                       ITEM_SET_STRING (id, notable_id, TRUE);
+                       ITEM_SET_STRING (name, notable_name, TRUE);
+               }
+
+               json_reader_end_member (reader);
+               json_reader_end_element (reader);
+
+               g_ptr_array_add (priv->items, item);
+               continue;
+
+       item_error:
+               item_free (item);
+               gdata_parser_error_required_json_content_missing (reader, error);
+               return FALSE;
+       }
+
+#undef ITEM_SET_DOUBLE
+#undef ITEM_SET_STRING
+
+       return TRUE;
+}
+
+/**
+ * gdata_freebase_search_result_new:
+ *
+ * Creates a new #GDataFreebaseSearchResult with the given ID and default properties.
+ *
+ * Return value: (transfer full): a new #GDataFreebaseSearchResult; unref with g_object_unref()
+ *
+ * Since: UNRELEASED
+ */
+GDataFreebaseSearchResult *
+gdata_freebase_search_result_new (void)
+{
+       return g_object_new (GDATA_TYPE_FREEBASE_SEARCH_RESULT, NULL);
+}
+
+/**
+ * gdata_freebase_search_result_get_num_items:
+ * @self: a #GDataFreebaseSearchResult
+ *
+ * Returns the number of items contained in this result.
+ *
+ * Returns: The number of items
+ *
+ * Since: UNRELEASED
+ **/
+guint
+gdata_freebase_search_result_get_num_items (GDataFreebaseSearchResult *self)
+{
+       g_return_val_if_fail (GDATA_IS_FREEBASE_SEARCH_RESULT (self), 0);
+
+       return self->priv->items->len;
+}
+
+/**
+ * gdata_freebase_search_result_get_total_hits:
+ * @self: a #GDataFreebaseSearchResult
+ *
+ * Returns the total number of hits found for the search query.
+ *
+ * Returns: the total number of hits.
+ *
+ * Since: UNRELEASED
+ **/
+guint
+gdata_freebase_search_result_get_total_hits (GDataFreebaseSearchResult *self)
+{
+       g_return_val_if_fail (GDATA_IS_FREEBASE_SEARCH_RESULT (self), 0);
+
+       return self->priv->total_hits;
+}
+
+/**
+ * gdata_freebase_search_result_get_item:
+ * @self: a #GDataFreebaseSearchResult
+ * @i: number of item to retrieve
+ *
+ * Gets an item from the search result.
+ *
+ * Returns: (transfer none) (allow-none): a search result item, or %NULL on invalid item.
+ *
+ * Since: UNRELEASED
+ **/
+const GDataFreebaseSearchResultItem *
+gdata_freebase_search_result_get_item (GDataFreebaseSearchResult *self, guint i)
+{
+       GDataFreebaseSearchResultPrivate *priv;
+
+       g_return_val_if_fail (GDATA_IS_FREEBASE_SEARCH_RESULT (self), NULL);
+
+       priv = self->priv;
+       g_return_val_if_fail (i < priv->items->len, NULL);
+
+       return g_ptr_array_index (priv->items, i);
+}
+
+/**
+ * gdata_freebase_search_result_item_get_mid:
+ * @item: a #GDataFreebaseSearchResultItem
+ *
+ * Returns the machine-encoded ID (MID) of the search result item. Elements may
+ * have a single MID, as opposed to the potentially multiple Freebase IDs that
+ * may point to it. MIDs are usable interchangeably with Freebase IDs.
+ *
+ * Returns: (transfer none): The result item MID.
+ *
+ * Since: UNRELEASED
+ **/
+const gchar *
+gdata_freebase_search_result_item_get_mid (const GDataFreebaseSearchResultItem *item)
+{
+       g_return_val_if_fail (item != NULL, NULL);
+       return item->mid;
+}
+
+/**
+ * gdata_freebase_search_result_item_get_id:
+ * @item: a #GDataFreebaseSearchResultItem
+ *
+ * Returns the Freebase ID of the search result item.
+ *
+ * Returns: (transfer none): The search result item Freebase ID.
+ *
+ * Since: UNRELEASED
+ **/
+const gchar *
+gdata_freebase_search_result_item_get_id (const GDataFreebaseSearchResultItem *item)
+{
+       g_return_val_if_fail (item != NULL, NULL);
+
+       if (item->id != NULL)
+               return item->id;
+
+       return item->mid;
+}
+
+/**
+ * gdata_freebase_search_result_item_get_name:
+ * @item: a #GDataFreebaseSearchResultItem
+ *
+ * Returns the human readable name of the search result item.
+ *
+ * Returns: (transfer none): The human readable name of the item.
+ *
+ * Since: UNRELEASED
+ **/
+const gchar *
+gdata_freebase_search_result_item_get_name (const GDataFreebaseSearchResultItem *item)
+{
+       g_return_val_if_fail (item != NULL, NULL);
+       return item->name;
+}
+
+/**
+ * gdata_freebase_search_result_item_get_language:
+ * @item: a #GDataFreebaseSearchResultItem
+ *
+ * Gets the language of this search result item, in ISO-639-1 format.
+ *
+ * Returns: (transfer none): The language of the search result item.
+ *
+ * Since: UNRELEASED
+ **/
+const gchar *
+gdata_freebase_search_result_item_get_language (const GDataFreebaseSearchResultItem *item)
+{
+       g_return_val_if_fail (item != NULL, NULL);
+       return item->lang;
+}
+
+/**
+ * gdata_freebase_search_result_item_get_notable_id:
+ * @item: a #GDataFreebaseSearchResultItem
+ *
+ * If this search result item is notable in an specific topic, this function
+ * returns the Freebase ID of this topic.
+ *
+ * Returns: (transfer none) (allow-none): The topic the result item is most notable of, or %NULL.
+ *
+ * Since: UNRELEASED
+ **/
+const gchar *
+gdata_freebase_search_result_item_get_notable_id (const GDataFreebaseSearchResultItem *item)
+{
+       g_return_val_if_fail (item != NULL, NULL);
+       return item->notable_id;
+}
+
+/**
+ * gdata_freebase_search_result_item_get_notable_name:
+ * @item: a #GDataFreebaseSearchResultItem
+ *
+ * If this search result item is notable in an specific topic, this function
+ * returns the human readable name of this topic.
+ *
+ * Returns: (transfer none) (allow-none): The human readable topic name, or %NULL
+ *
+ * Since: UNRELEASED
+ **/
+const gchar *
+gdata_freebase_search_result_item_get_notable_name (const GDataFreebaseSearchResultItem *item)
+{
+       g_return_val_if_fail (item != NULL, NULL);
+       return item->notable_name;
+}
+
+/**
+ * gdata_freebase_search_result_item_get_score:
+ * @item: a #GDataFreebaseSearchResultItem
+ *
+ * Returns the score of this search result item. The higher, the more relevant this
+ * item seems, given the search terms.
+ *
+ * Returns: the result item score.
+ *
+ * Since: UNRELEASED
+ **/
+gdouble
+gdata_freebase_search_result_item_get_score (const GDataFreebaseSearchResultItem *item)
+{
+       g_return_val_if_fail (item != NULL, 0.0);
+       return item->score;
+}
diff --git a/gdata/services/freebase/gdata-freebase-search-result.h 
b/gdata/services/freebase/gdata-freebase-search-result.h
new file mode 100644
index 0000000..e8601b7
--- /dev/null
+++ b/gdata/services/freebase/gdata-freebase-search-result.h
@@ -0,0 +1,93 @@
+/* -*- 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_SEARCH_RESULT_H
+#define GDATA_FREEBASE_SEARCH_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_SEARCH_RESULT              (gdata_freebase_search_result_get_type ())
+#define GDATA_FREEBASE_SEARCH_RESULT(o)                (G_TYPE_CHECK_INSTANCE_CAST ((o), 
GDATA_TYPE_FREEBASE_SEARCH_RESULT, GDataFreebaseSearchResult))
+#define GDATA_FREEBASE_SEARCH_RESULT_CLASS(k)          (G_TYPE_CHECK_CLASS_CAST((k), 
GDATA_TYPE_FREEBASE_SEARCH_RESULT, GDataFreebaseSearchResultClass))
+#define GDATA_IS_FREEBASE_SEARCH_RESULT(o)             (G_TYPE_CHECK_INSTANCE_TYPE ((o), 
GDATA_TYPE_FREEBASE_SEARCH_RESULT))
+#define GDATA_IS_FREEBASE_SEARCH_RESULT_CLASS(k)       (G_TYPE_CHECK_CLASS_TYPE ((k), 
GDATA_TYPE_FREEBASE_SEARCH_RESULT))
+#define GDATA_FREEBASE_SEARCH_RESULT_GET_CLASS(o)      (G_TYPE_INSTANCE_GET_CLASS ((o), 
GDATA_TYPE_FREEBASE_SEARCH_RESULT, GDataFreebaseSearchResultClass))
+
+typedef struct _GDataFreebaseSearchResultPrivate GDataFreebaseSearchResultPrivate;
+
+/**
+ * GDataFreebaseSearchResultItem:
+ *
+ * Opaque struct holding data for a single search result item.
+ *
+ * Since: UNRELEASED
+ */
+typedef struct _GDataFreebaseSearchResultItem GDataFreebaseSearchResultItem;
+
+/**
+ * GDataFreebaseSearchResult:
+ *
+ * All the fields in the #GDataFreebaseSearchResult structure are private and should never be accessed 
directly.
+ *
+ * Since: UNRELEASED
+ */
+typedef struct {
+       GDataFreebaseResult parent;
+       GDataFreebaseSearchResultPrivate *priv;
+} GDataFreebaseSearchResult;
+
+/**
+ * GDataFreebaseSearchResultClass:
+ *
+ * All the fields in the #GDataFreebaseSearchResultClass structure are private and should never be accessed 
directly.
+ *
+ * Since: UNRELEASED
+ */
+
+typedef struct {
+       /*< private >*/
+       GDataFreebaseResultClass parent;
+} GDataFreebaseSearchResultClass;
+
+GType gdata_freebase_search_result_get_type (void) G_GNUC_CONST;
+
+GDataFreebaseSearchResult *gdata_freebase_search_result_new (void) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
+
+guint gdata_freebase_search_result_get_num_items (GDataFreebaseSearchResult *self);
+guint gdata_freebase_search_result_get_total_hits (GDataFreebaseSearchResult *self);
+
+const GDataFreebaseSearchResultItem *gdata_freebase_search_result_get_item (GDataFreebaseSearchResult *self, 
guint i);
+
+const gchar *gdata_freebase_search_result_item_get_mid (const GDataFreebaseSearchResultItem *item);
+const gchar *gdata_freebase_search_result_item_get_id (const GDataFreebaseSearchResultItem *item);
+const gchar *gdata_freebase_search_result_item_get_name (const GDataFreebaseSearchResultItem *item);
+const gchar *gdata_freebase_search_result_item_get_language (const GDataFreebaseSearchResultItem *item);
+const gchar *gdata_freebase_search_result_item_get_notable_id (const GDataFreebaseSearchResultItem *item);
+const gchar *gdata_freebase_search_result_item_get_notable_name (const GDataFreebaseSearchResultItem *item);
+gdouble gdata_freebase_search_result_item_get_score (const GDataFreebaseSearchResultItem *item);
+
+G_END_DECLS
+
+#endif /* !GDATA_FREEBASE_SEARCH_RESULT_H */
diff --git a/gdata/services/freebase/gdata-freebase-service.c 
b/gdata/services/freebase/gdata-freebase-service.c
index 96e1a1e..165ec14 100644
--- a/gdata/services/freebase/gdata-freebase-service.c
+++ b/gdata/services/freebase/gdata-freebase-service.c
@@ -315,3 +315,65 @@ gdata_freebase_service_get_topic_async (GDataFreebaseService *self, GDataFreebas
        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);
 }
+
+/**
+ * gdata_freebase_service_search:
+ * @self: a #GDataFreebaseService
+ * @query: a #GDataFreebaseSearchQuery containing the topic ID
+ * @cancellable: (allow-none): optional #GCancellable object, or %NULL
+ * @error: (allow-none): a #GError, or %NULL
+ *
+ * Performs a search for any given search term, filters can be set on @query to narrow down the results. The 
results returned
+ * are ordered by relevance. You can find out more about topic queries in the
+ * <ulink type="http" url="https://developers.google.com/freebase/v1/search-cookbook";>online 
documentation</ulink>.
+ *
+ * Return value: (transfer full): a #GDataFreebaseSearchResult containing the results for the given search 
query; unref with g_object_unref()
+ *
+ * Since: UNRELEASED
+ */
+GDataFreebaseSearchResult *
+gdata_freebase_service_search (GDataFreebaseService *self, GDataFreebaseSearchQuery *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_SEARCH_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 (), 
"search",
+                                                 GDATA_QUERY (query), GDATA_TYPE_FREEBASE_SEARCH_RESULT, 
cancellable, error);
+       if (entry == NULL)
+               return NULL;
+
+       return GDATA_FREEBASE_SEARCH_RESULT (entry);
+}
+
+/**
+ * gdata_freebase_service_search_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 search for any given search term. @self and @query are all reffed when this
+ * function is called, so can safely be unreffed after this function returns.
+ *
+ * For more details, see gdata_freebase_service_search(), which is the synchronous version of
+ * this function.
+ *
+ * Since: UNRELEASED
+ */
+void
+gdata_freebase_service_search_async (GDataFreebaseService *self, GDataFreebaseSearchQuery *query,
+                                    GCancellable *cancellable, GAsyncReadyCallback callback, gpointer 
user_data)
+{
+       g_return_if_fail (GDATA_IS_FREEBASE_SERVICE (self));
+       g_return_if_fail (GDATA_IS_FREEBASE_SEARCH_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 (), 
"search",
+                                               GDATA_QUERY (query), GDATA_TYPE_FREEBASE_SEARCH_RESULT, 
cancellable, callback, user_data);
+}
diff --git a/gdata/services/freebase/gdata-freebase-service.h 
b/gdata/services/freebase/gdata-freebase-service.h
index af553bb..609a38c 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-search-query.h"
+#include "gdata-freebase-search-result.h"
 #include "gdata-freebase-topic-query.h"
 #include "gdata-freebase-topic-result.h"
 
@@ -83,6 +85,11 @@ GDataFreebaseTopicResult *gdata_freebase_service_get_topic (GDataFreebaseService
 void gdata_freebase_service_get_topic_async (GDataFreebaseService *self, GDataFreebaseTopicQuery *query,
                                             GCancellable *cancellable, GAsyncReadyCallback callback, 
gpointer user_data);
 
+GDataFreebaseSearchResult *gdata_freebase_service_search (GDataFreebaseService *self, 
GDataFreebaseSearchQuery *query,
+                                                         GCancellable *cancellable, GError **error) 
G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
+void gdata_freebase_service_search_async (GDataFreebaseService *self, GDataFreebaseSearchQuery *query,
+                                         GCancellable *cancellable, GAsyncReadyCallback callback, gpointer 
user_data);
+
 G_END_DECLS
 
 #endif /* !GDATA_FREEBASE_SERVICE_H */


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