diff options
-rw-r--r-- | Makefile.am | 32 | ||||
-rw-r--r-- | docs/reference/gdata-docs.xml | 2 | ||||
-rw-r--r-- | docs/reference/gdata-sections.txt | 60 | ||||
-rw-r--r-- | gdata/gdata.h | 3 | ||||
-rw-r--r-- | gdata/gdata.symbols | 25 | ||||
-rw-r--r-- | gdata/services/freebase/gdata-freebase-search-query.c | 602 | ||||
-rw-r--r-- | gdata/services/freebase/gdata-freebase-search-query.h | 97 | ||||
-rw-r--r-- | gdata/services/freebase/gdata-freebase-search-result.c | 395 | ||||
-rw-r--r-- | gdata/services/freebase/gdata-freebase-search-result.h | 93 | ||||
-rw-r--r-- | gdata/services/freebase/gdata-freebase-service.c | 62 | ||||
-rw-r--r-- | gdata/services/freebase/gdata-freebase-service.h | 7 |
11 files changed, 1377 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am index b2b685de..0a472d44 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 262ec281..c4edade9 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 4cc46044..2e9dbc64 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 579ecade..158a7651 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 b149eb66..5fd48156 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 00000000..de6bf599 --- /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 00000000..58172a96 --- /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 00000000..8c212370 --- /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 00000000..e8601b79 --- /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 96e1a1e9..165ec140 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 af553bbd..609a38c5 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 */ |