[tracker/wip/carlosg/http-endpoint: 2/10] libtracker-sparql: Add private JSON serializer subclass
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker/wip/carlosg/http-endpoint: 2/10] libtracker-sparql: Add private JSON serializer subclass
- Date: Sat, 12 Dec 2020 20:24:28 +0000 (UTC)
commit 62d3f84beb36285457d0ce846292f4f6421ac871
Author: Carlos Garnacho <carlosg gnome org>
Date: Sat Dec 12 15:54:22 2020 +0100
libtracker-sparql: Add private JSON serializer subclass
This object takes care of translating a cursor into
application/sparql-results+json output.
docs/reference/libtracker-sparql/meson.build | 1 +
src/libtracker-sparql/meson.build | 1 +
src/libtracker-sparql/tracker-serializer-json.c | 273 ++++++++++++++++++++++++
src/libtracker-sparql/tracker-serializer-json.h | 36 ++++
4 files changed, 311 insertions(+)
---
diff --git a/docs/reference/libtracker-sparql/meson.build b/docs/reference/libtracker-sparql/meson.build
index 7b7ce25d5..d5817657c 100644
--- a/docs/reference/libtracker-sparql/meson.build
+++ b/docs/reference/libtracker-sparql/meson.build
@@ -38,6 +38,7 @@ private_headers = [
'tracker-notifier-private.h',
'tracker-private.h',
'tracker-serializer.h',
+ 'tracker-serializer-json.h',
'direct',
'bus',
'remote',
diff --git a/src/libtracker-sparql/meson.build b/src/libtracker-sparql/meson.build
index a9f505065..55248ac38 100644
--- a/src/libtracker-sparql/meson.build
+++ b/src/libtracker-sparql/meson.build
@@ -26,6 +26,7 @@ libtracker_sparql_c_sources = files(
'tracker-resource.c',
'tracker-statement.c',
'tracker-serializer.c',
+ 'tracker-serializer-json.c',
'tracker-uri.c',
'tracker-utils.c',
'tracker-version.c',
diff --git a/src/libtracker-sparql/tracker-serializer-json.c b/src/libtracker-sparql/tracker-serializer-json.c
new file mode 100644
index 000000000..1f3976502
--- /dev/null
+++ b/src/libtracker-sparql/tracker-serializer-json.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2020, Red Hat, Inc
+ *
+ * This library 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.
+ *
+ * This library 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Author: Carlos Garnacho <carlosg gnome org>
+ */
+
+#include "config.h"
+
+#include "tracker-serializer-json.h"
+
+#include <json-glib/json-glib.h>
+
+struct _TrackerSerializerJson
+{
+ TrackerSerializer parent_instance;
+ JsonGenerator *generator;
+ GString *data;
+ GPtrArray *vars;
+ gssize current_pos;
+ guint stream_closed : 1;
+ guint cursor_started : 1;
+ guint cursor_finished : 1;
+ guint head_printed : 1;
+};
+
+G_DEFINE_TYPE (TrackerSerializerJson, tracker_serializer_json,
+ TRACKER_TYPE_SERIALIZER)
+
+static void
+tracker_serializer_json_finalize (GObject *object)
+{
+ g_input_stream_close (G_INPUT_STREAM (object), NULL, NULL);
+
+ G_OBJECT_CLASS (tracker_serializer_json_parent_class)->finalize (object);
+}
+
+static gboolean
+serialize_up_to_position (TrackerSerializerJson *serializer_json,
+ gsize pos,
+ GCancellable *cancellable,
+ GError **error)
+{
+ TrackerSparqlCursor *cursor;
+ GError *inner_error = NULL;
+ JsonBuilder *builder;
+ JsonNode *node;
+ gint i;
+
+ if (!serializer_json->data)
+ serializer_json->data = g_string_new (NULL);
+ if (!serializer_json->generator)
+ serializer_json->generator = json_generator_new ();
+ if (!serializer_json->vars)
+ serializer_json->vars = g_ptr_array_new_with_free_func (g_free);
+
+ cursor = tracker_serializer_get_cursor (TRACKER_SERIALIZER (serializer_json));
+ builder = json_builder_new ();
+
+ if (!serializer_json->head_printed) {
+ json_builder_reset (builder);
+ json_builder_begin_object (builder);
+ json_builder_set_member_name (builder, "vars");
+ json_builder_begin_array (builder);
+
+ for (i = 0; i < tracker_sparql_cursor_get_n_columns (cursor); i++) {
+ const gchar *var;
+
+ var = tracker_sparql_cursor_get_variable_name (cursor, i);
+
+ if (var && *var) {
+ g_ptr_array_add (serializer_json->vars,
+ g_strdup (var));
+ } else {
+ g_ptr_array_add (serializer_json->vars,
+ g_strdup_printf ("var%d", i + 1));
+ }
+
+ json_builder_add_string_value (builder,
+ g_ptr_array_index (serializer_json->vars, i));
+ }
+
+ json_builder_end_array (builder);
+ json_builder_end_object (builder);
+
+ node = json_builder_get_root (builder);
+
+ g_string_append_printf (serializer_json->data,
+ "{\"head\":");
+ json_generator_set_root (serializer_json->generator, node);
+ json_generator_to_gstring (serializer_json->generator,
+ serializer_json->data);
+ g_string_append_printf (serializer_json->data,
+ ",\"results\":{\"bindings\":[");
+
+ serializer_json->head_printed = TRUE;
+ }
+
+ while (!serializer_json->cursor_finished &&
+ serializer_json->data->len < pos) {
+ if (!tracker_sparql_cursor_next (cursor, cancellable, &inner_error)) {
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ g_clear_object (&builder);
+ return FALSE;
+ } else {
+ serializer_json->cursor_finished = TRUE;
+ g_string_append (serializer_json->data, "]}}");
+ break;
+ }
+ } else {
+ if (serializer_json->cursor_started)
+ g_string_append_c (serializer_json->data, ',');
+
+ serializer_json->cursor_started = TRUE;
+ }
+
+ json_builder_reset (builder);
+ json_builder_begin_object (builder);
+
+ for (i = 0; i < tracker_sparql_cursor_get_n_columns (cursor); i++) {
+ const gchar *var, *str, *type, *datatype = NULL;
+
+ if (tracker_sparql_cursor_get_value_type (cursor, i) ==
TRACKER_SPARQL_VALUE_TYPE_UNBOUND)
+ continue;
+
+ var = g_ptr_array_index (serializer_json->vars, i);
+ json_builder_set_member_name (builder, var);
+
+ json_builder_begin_object (builder);
+
+ switch (tracker_sparql_cursor_get_value_type (cursor, i)) {
+ case TRACKER_SPARQL_VALUE_TYPE_URI:
+ type = "uri";
+ break;
+ case TRACKER_SPARQL_VALUE_TYPE_STRING:
+ type = "literal";
+ datatype = TRACKER_PREFIX_XSD "string";
+ break;
+ case TRACKER_SPARQL_VALUE_TYPE_INTEGER:
+ case TRACKER_SPARQL_VALUE_TYPE_BOOLEAN:
+ type = "literal";
+ datatype = TRACKER_PREFIX_XSD "integer";
+ break;
+ case TRACKER_SPARQL_VALUE_TYPE_DOUBLE:
+ type = "literal";
+ datatype = TRACKER_PREFIX_XSD "double";
+ break;
+ case TRACKER_SPARQL_VALUE_TYPE_DATETIME:
+ type = "literal";
+ datatype = TRACKER_PREFIX_XSD "dateTime";
+ break;
+ case TRACKER_SPARQL_VALUE_TYPE_BLANK_NODE:
+ type = "bnode";
+ break;
+ default:
+ g_warn_if_reached ();
+ break;
+ }
+
+ json_builder_set_member_name (builder, "type");
+ json_builder_add_string_value (builder, type);
+
+ if (datatype) {
+ json_builder_set_member_name (builder, "datatype");
+ json_builder_add_string_value (builder, datatype);
+ }
+
+ str = tracker_sparql_cursor_get_string (cursor, i, NULL);
+
+ if (str) {
+ json_builder_set_member_name (builder, "value");
+ json_builder_add_string_value (builder,
+ tracker_sparql_cursor_get_string (cursor, i,
NULL));
+ json_builder_end_object (builder);
+ }
+ }
+
+ json_builder_end_object (builder);
+ node = json_builder_get_root (builder);
+
+ json_generator_set_root (serializer_json->generator, node);
+ json_generator_to_gstring (serializer_json->generator,
+ serializer_json->data);
+ }
+
+ g_clear_object (&builder);
+
+ return TRUE;
+}
+
+static gssize
+tracker_serializer_json_read (GInputStream *istream,
+ gpointer buffer,
+ gsize count,
+ GCancellable *cancellable,
+ GError **error)
+{
+ TrackerSerializerJson *serializer_json = TRACKER_SERIALIZER_JSON (istream);
+ gsize bytes_unflushed, bytes_copied;
+
+ if (serializer_json->stream_closed ||
+ (serializer_json->cursor_finished &&
+ serializer_json->current_pos == serializer_json->data->len))
+ return 0;
+
+ if (!serialize_up_to_position (serializer_json,
+ serializer_json->current_pos + count,
+ cancellable,
+ error))
+ return -1;
+
+ bytes_unflushed =
+ serializer_json->data->len - serializer_json->current_pos;
+ bytes_copied = MIN (count, bytes_unflushed);
+
+ memcpy (buffer,
+ &serializer_json->data->str[serializer_json->current_pos],
+ bytes_copied);
+ serializer_json->current_pos += bytes_copied;
+
+ return bytes_copied;
+}
+
+static gboolean
+tracker_serializer_json_close (GInputStream *istream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ TrackerSerializerJson *serializer_json = TRACKER_SERIALIZER_JSON (istream);
+
+ if (serializer_json->data) {
+ g_string_free (serializer_json->data, TRUE);
+ serializer_json->data = NULL;
+ }
+
+ g_clear_object (&serializer_json->generator);
+ serializer_json->stream_closed = TRUE;
+ g_clear_pointer (&serializer_json->vars, g_ptr_array_unref);
+
+ return TRUE;
+}
+
+static void
+tracker_serializer_json_class_init (TrackerSerializerJsonClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GInputStreamClass *istream_class = G_INPUT_STREAM_CLASS (klass);
+
+ object_class->finalize = tracker_serializer_json_finalize;
+
+ istream_class->read_fn = tracker_serializer_json_read;
+ istream_class->close_fn = tracker_serializer_json_close;
+}
+
+static void
+tracker_serializer_json_init (TrackerSerializerJson *serializer)
+{
+}
diff --git a/src/libtracker-sparql/tracker-serializer-json.h b/src/libtracker-sparql/tracker-serializer-json.h
new file mode 100644
index 000000000..ca0d49e47
--- /dev/null
+++ b/src/libtracker-sparql/tracker-serializer-json.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020, Red Hat, Inc
+ *
+ * This library 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.
+ *
+ * This library 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Author: Carlos Garnacho <carlosg gnome org>
+ */
+
+#ifndef TRACKER_SERIALIZER_JSON_H
+#define TRACKER_SERIALIZER_JSON_H
+
+#include <libtracker-sparql/tracker-sparql.h>
+#include <libtracker-sparql/tracker-private.h>
+#include <libtracker-sparql/tracker-serializer.h>
+
+#define TRACKER_TYPE_SERIALIZER_JSON (tracker_serializer_json_get_type())
+
+G_DECLARE_FINAL_TYPE (TrackerSerializerJson,
+ tracker_serializer_json,
+ TRACKER, SERIALIZER_JSON,
+ TrackerSerializer);
+
+#endif /* TRACKER_SERIALIZER_JSON_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]