1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3  * GData Client
4  * Copyright (C) 2014 Carlos Garnacho <carlosg@gnome.org>
5  *
6  * GData Client is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * GData Client is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with GData Client.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 /**
21  * SECTION:gdata-freebase-query
22  * @short_description: GData Freebase query object
23  * @stability: Stable
24  * @include: gdata/services/freebase/gdata-freebase-query.h
25  *
26  * #GDataFreebaseQuery represents a MQL query specific to the Google Freebase service.
27  *
28  * This implementation of #GDataQuery respects the gdata_query_set_max_results() call.
29  *
30  * For more details of Google Freebase API, see the <ulink type="http" url="https://developers.google.com/freebase/v1/">
31  * online documentation</ulink>.
32  *
33  * Since: 0.15.1
34  * Deprecated: 0.17.7: Google Freebase has been permanently shut down.
35  */
36 
37 #include <config.h>
38 #include <glib.h>
39 #include <glib/gi18n-lib.h>
40 #include <string.h>
41 #include <json-glib/json-glib.h>
42 
43 #include "gdata-freebase-query.h"
44 #include "gdata-query.h"
45 #include "gdata-parser.h"
46 #include "gdata-private.h"
47 
48 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
49 
50 static void gdata_freebase_query_finalize (GObject *self);
51 static void gdata_freebase_query_set_property (GObject *self, guint prop_id, const GValue *value, GParamSpec *pspec);
52 static void gdata_freebase_query_get_property (GObject *self, guint prop_id, GValue *value, GParamSpec *pspec);
53 static void get_query_uri (GDataQuery *self, const gchar *feed_uri, GString *query_uri, gboolean *params_started);
54 
55 struct _GDataFreebaseQueryPrivate {
56 	/* These params are here not in GDataQuery due of differently named query params for JSON protocols therefore need for different parse_uri */
57 	GVariant *variant;
58 	JsonNode *query_node;
59 };
60 
61 enum {
62 	PROP_VARIANT = 1,
63 };
64 
G_DEFINE_TYPE(GDataFreebaseQuery,gdata_freebase_query,GDATA_TYPE_QUERY)65 G_DEFINE_TYPE (GDataFreebaseQuery, gdata_freebase_query, GDATA_TYPE_QUERY)
66 
67 static void
68 gdata_freebase_query_class_init (GDataFreebaseQueryClass *klass)
69 {
70 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
71 	GDataQueryClass *query_class = GDATA_QUERY_CLASS (klass);
72 
73 	g_type_class_add_private (klass, sizeof (GDataFreebaseQueryPrivate));
74 
75 	gobject_class->finalize = gdata_freebase_query_finalize;
76 	gobject_class->set_property = gdata_freebase_query_set_property;
77 	gobject_class->get_property = gdata_freebase_query_get_property;
78 
79 	query_class->get_query_uri = get_query_uri;
80 
81 	/**
82 	 * GDataFreebaseQuery:variant:
83 	 *
84 	 * Variant containing the MQL query. The variant is a very generic container of type "a{smv}",
85 	 * containing (possibly nested) Freebase schema types and values.
86 	 *
87 	 * Since: 0.15.1
88 	 * Deprecated: 0.17.7: Google Freebase has been permanently shut down.
89 	 */
90 	g_object_class_install_property (gobject_class, PROP_VARIANT,
91 	                                 g_param_spec_variant ("variant",
92 							       "Variant",
93 							       "Variant to construct the query from.",
94 							       G_VARIANT_TYPE ("a{smv}"), NULL,
95 							       G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
96 							       G_PARAM_DEPRECATED));
97 }
98 
99 static void
gdata_freebase_query_init(GDataFreebaseQuery * self)100 gdata_freebase_query_init (GDataFreebaseQuery *self)
101 {
102 	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_FREEBASE_QUERY, GDataFreebaseQueryPrivate);
103 
104 	/* https://developers.google.com/freebase/v1/search#cursor */
105 	_gdata_query_set_pagination_type (GDATA_QUERY (self),
106 	                                  GDATA_QUERY_PAGINATION_INDEXED);
107 }
108 
109 static void
gdata_freebase_query_finalize(GObject * self)110 gdata_freebase_query_finalize (GObject *self)
111 {
112 	GDataFreebaseQueryPrivate *priv = GDATA_FREEBASE_QUERY (self)->priv;
113 
114 	if (priv->variant != NULL)
115 		g_variant_unref (priv->variant);
116 	if (priv->query_node != NULL)
117 		json_node_free (priv->query_node);
118 	/* Chain up to the parent class */
119 	G_OBJECT_CLASS (gdata_freebase_query_parent_class)->finalize (self);
120 }
121 
122 static void
gdata_freebase_query_set_property(GObject * self,guint prop_id,const GValue * value,GParamSpec * pspec)123 gdata_freebase_query_set_property (GObject *self, guint prop_id, const GValue *value, GParamSpec *pspec)
124 {
125 	GDataFreebaseQueryPrivate *priv = GDATA_FREEBASE_QUERY (self)->priv;
126 
127 	switch (prop_id) {
128 	case PROP_VARIANT:
129 		priv->variant = g_value_get_variant (value);
130 		if (priv->variant)
131 			priv->query_node = json_gvariant_serialize (priv->variant);
132 		break;
133 	default:
134 		G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
135 		break;
136 	}
137 }
138 
139 static void
gdata_freebase_query_get_property(GObject * self,guint prop_id,GValue * value,GParamSpec * pspec)140 gdata_freebase_query_get_property (GObject *self, guint prop_id, GValue *value, GParamSpec *pspec)
141 {
142 	GDataFreebaseQueryPrivate *priv = GDATA_FREEBASE_QUERY (self)->priv;
143 
144 	switch (prop_id) {
145 	case PROP_VARIANT:
146 		g_value_set_variant (value, priv->variant);
147 		break;
148 	default:
149 		G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
150 		break;
151 	}
152 }
153 
154 static void
get_query_uri(GDataQuery * self,const gchar * feed_uri,GString * query_uri,gboolean * params_started)155 get_query_uri (GDataQuery *self, const gchar *feed_uri, GString *query_uri, gboolean *params_started)
156 {
157 	GDataFreebaseQueryPrivate *priv = GDATA_FREEBASE_QUERY (self)->priv;
158 	const gchar *query;
159 
160 #define APPEND_SEP g_string_append_c (query_uri, (*params_started == FALSE) ? '?' : '&'); *params_started = TRUE;
161 
162 	query = gdata_query_get_q (self);
163 
164 	if (query != NULL) {
165 		APPEND_SEP;
166 		g_string_append (query_uri, "query=");
167 		g_string_append (query_uri, query);
168 	} else if (priv->query_node != NULL) {
169 		JsonGenerator *generator;
170 		JsonNode *copy;
171 		gchar *json;
172 		guint limit;
173 
174 		copy = json_node_copy (priv->query_node);
175 
176 		limit = gdata_query_get_max_results (self);
177 
178 		if (limit > 0) {
179 			JsonNode *limit_node;
180 			JsonObject *object;
181 
182 			limit_node = json_node_new (JSON_NODE_VALUE);
183 			json_node_set_int (limit_node, limit);
184 
185 			object = json_node_get_object (copy);
186 			json_object_set_member (object, "limit", limit_node);
187 		}
188 
189 		generator = json_generator_new ();
190 		json_generator_set_root (generator, copy);
191 		json = json_generator_to_data (generator, NULL);
192 		g_object_unref (generator);
193 
194 		APPEND_SEP;
195 		g_string_append (query_uri, "query=");
196 		g_string_append (query_uri, json);
197 		g_free (json);
198 	}
199 
200 	/* We don't chain up with parent class get_query_uri because it uses
201 	 *  GData protocol parameters and they aren't compatible with newest API family
202 	 */
203 #undef APPEND_SEP
204 }
205 
206 /**
207  * gdata_freebase_query_new:
208  * @mql: a MQL query string
209  *
210  * Creates a new #GDataFreebaseQuery with the MQL query provided in @mql. MQL
211  * is a JSON-based query language, analogous to SPARQL. To learn more about MQL,
212  * see the <ulink type="http" url="https://developers.google.com/freebase/v1/mql-overview">
213  * MQL overview</ulink> and <ulink type="http" url="https://developers.google.com/freebase/v1/mql-cookbook">
214  * cookbook</ulink>.
215  *
216  * For detailed information on Freebase schemas, The <ulink type="http" url="http://www.freebase.com/schema">"Schema"
217  * section</ulink> on the main site allows for natural search and navigation through the multiple data properties and domains.
218  *
219  * Return value: (transfer full): a new #GDataFreebaseQuery
220  *
221  * Since: 0.15.1
222  * Deprecated: 0.17.7: Google Freebase has been permanently shut down.
223  */
224 GDataFreebaseQuery *
gdata_freebase_query_new(const gchar * mql)225 gdata_freebase_query_new (const gchar *mql)
226 {
227 	g_return_val_if_fail (mql != NULL, NULL);
228 
229 	return g_object_new (GDATA_TYPE_FREEBASE_QUERY, "q", mql, NULL);
230 }
231 
232 /**
233  * gdata_freebase_query_new_from_variant:
234  * @variant: a variant containing the MQL query structure
235  *
236  * Creates a new #GDataFreebaseQuery with the MQL query provided in a serialized form as @variant
237  * of type "a{smv}" containing the JSON data tree of a MQL query. One convenient way
238  * to build the variant is using json_gvariant_serialize() from a #JsonNode. For more information
239  * about MQL, see gdata_freebase_query_new().
240  *
241  * #GDataFreebaseQuery takes ownership on @variant, if it has a floating reference, it will be sunk.
242  * Otherwise an extra reference will be added.
243  *
244  * Return value: (transfer full): a new #GDataFreebaseQuery
245  *
246  * Since: 0.15.1
247  * Deprecated: 0.17.7: Google Freebase has been permanently shut down.
248  */
249 GDataFreebaseQuery *
gdata_freebase_query_new_from_variant(GVariant * variant)250 gdata_freebase_query_new_from_variant (GVariant *variant)
251 {
252 	g_return_val_if_fail (variant != NULL, NULL);
253 
254 	return g_object_new (GDATA_TYPE_FREEBASE_QUERY,
255 			     "variant", g_variant_ref_sink (variant),
256 			     NULL);
257 }
258 
259 G_GNUC_END_IGNORE_DEPRECATIONS
260