[tracker/wip/sam/resource: 10/22] libtracker-sparql: Add SPARQL serialisation to tracker-resource
- From: Sam Thursfield <sthursfield src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker/wip/sam/resource: 10/22] libtracker-sparql: Add SPARQL serialisation to tracker-resource
- Date: Fri, 8 Apr 2016 17:18:24 +0000 (UTC)
commit 86ad8503ca2cc52b183b33854152a8d8b3831dea
Author: Sam Thursfield <sam afuera me uk>
Date: Fri Apr 8 15:49:06 2016 +0100
libtracker-sparql: Add SPARQL serialisation to tracker-resource
src/libtracker-sparql/tracker-resource.c | 212 ++++++++++++++++++++++++++++++
src/libtracker-sparql/tracker-resource.h | 4 +
2 files changed, 216 insertions(+), 0 deletions(-)
---
diff --git a/src/libtracker-sparql/tracker-resource.c b/src/libtracker-sparql/tracker-resource.c
index 0335386..c0cc206 100644
--- a/src/libtracker-sparql/tracker-resource.c
+++ b/src/libtracker-sparql/tracker-resource.c
@@ -520,3 +520,215 @@ tracker_resource_print_jsonld_string (TrackerResource *resource)
}*/
return string;
}
+
+typedef struct {
+ TrackerSparqlBuilder *builder;
+ const char *graph_id;
+ GList *done_list;
+} GenerateSparqlRelationsData;
+
+typedef struct {
+ TrackerSparqlBuilder *builder;
+ GHashTable *overwrite_flags;
+} GenerateSparqlDeletesData;
+
+static void
+generate_sparql_relations_foreach (gpointer key,
+ gpointer value_ptr,
+ gpointer user_data)
+{
+ const char *property = key;
+ const GValue *value = value_ptr;
+ GenerateSparqlRelationsData *data = user_data;
+ GError *error = NULL;
+
+ if (G_VALUE_HOLDS (value, TRACKER_TYPE_RESOURCE)) {
+ TrackerResource *relation = g_value_get_object (value);
+
+ if (g_list_find (data->done_list, relation) == NULL) {
+ tracker_resource_generate_sparql_update (relation,
+ data->builder,
+ data->graph_id,
+ &error);
+ data->done_list = g_list_prepend (data->done_list, relation);
+ }
+ }
+}
+
+static char *
+variable_name_for_property (const char *property) {
+ return g_strcanon (g_strdup (property),
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
+ '_');
+}
+
+static void
+generate_sparql_deletes_foreach (gpointer key,
+ gpointer value_ptr,
+ gpointer user_data)
+{
+ const char *property = key;
+ const GValue *value = value_ptr;
+ GenerateSparqlDeletesData *data = user_data;
+
+ /* Whether to generate the DELETE is based on whether set_value was ever
+ * called for this property. That's tracked in a hash table.
+ */
+ if (g_hash_table_lookup (data->overwrite_flags, property)) {
+ char *variable_name = variable_name_for_property (property);
+ tracker_sparql_builder_predicate (data->builder, property);
+ tracker_sparql_builder_object_variable (data->builder, variable_name);
+ g_free (variable_name);
+ }
+}
+
+static void
+append_value_to_sparql_builder (const GValue *value,
+ TrackerSparqlBuilder *builder)
+{
+ GType type = G_VALUE_TYPE (value);
+ if (type == G_TYPE_BOOLEAN) {
+ tracker_sparql_builder_object_boolean (builder, g_value_get_boolean (value));
+ } else if (type == G_TYPE_DATE || type == G_TYPE_DATE_TIME) {
+ g_warning ("Ignoring date/datetime value, not yet implemented.");
+ /* FIXME: date & datetime ... tricky because we need to get a time_t */
+ tracker_sparql_builder_object (builder, "null");
+ } else if (type == G_TYPE_DOUBLE) {
+ tracker_sparql_builder_object_double (builder, g_value_get_double (value));
+ } else if (type == G_TYPE_FLOAT) {
+ tracker_sparql_builder_object_double (builder, g_value_get_float (value));
+ } else if (type == G_TYPE_CHAR) {
+ tracker_sparql_builder_object_int64 (builder, g_value_get_schar (value));
+ } else if (type == G_TYPE_INT) {
+ tracker_sparql_builder_object_int64 (builder, g_value_get_int (value));
+ } else if (type == G_TYPE_INT64) {
+ tracker_sparql_builder_object_int64 (builder, g_value_get_int64 (value));
+ } else if (type == G_TYPE_LONG) {
+ tracker_sparql_builder_object_int64 (builder, g_value_get_long (value));
+ } else if (type == G_TYPE_UCHAR) {
+ tracker_sparql_builder_object_int64 (builder, g_value_get_uchar (value));
+ } else if (type == G_TYPE_UINT) {
+ tracker_sparql_builder_object_int64 (builder, g_value_get_uint (value));
+ } else if (type == G_TYPE_ULONG) {
+ tracker_sparql_builder_object_int64 (builder, g_value_get_ulong (value));
+ } else if (type == G_TYPE_UINT64) {
+ g_warning ("Cannot serialize uint64 types to SPARQL. Use int64.");
+ tracker_sparql_builder_object (builder, "null");
+ } else if (type == G_TYPE_STRING) {
+ tracker_sparql_builder_object_string (builder, g_value_get_string (value));
+ } else if (type == TRACKER_TYPE_URI) {
+ tracker_sparql_builder_object_iri (builder, g_value_get_string (value));
+ } else if (type == TRACKER_TYPE_RESOURCE) {
+ TrackerResource *relation = TRACKER_RESOURCE (g_value_get_object (value));
+ tracker_sparql_builder_object_iri (builder, tracker_resource_get_identifier (relation));
+ } else {
+ g_warning ("Cannot serialize value of type %s to SPARQL", G_VALUE_TYPE_NAME (value));
+ tracker_sparql_builder_object (builder, "null");
+ }
+}
+
+static void
+generate_sparql_inserts_foreach (gpointer key,
+ gpointer value_ptr,
+ gpointer user_data)
+{
+ const char *property = key;
+ const GValue *value = value_ptr;
+ TrackerSparqlBuilder *builder = TRACKER_SPARQL_BUILDER (user_data);
+
+ /* FIXME: shouldn't be hardcoding this compact URI... */
+ if (strcmp (property, "rdf:type") == 0) {
+ tracker_sparql_builder_predicate (builder, "a");
+ } else {
+ tracker_sparql_builder_predicate (builder, property);
+ }
+
+ if (G_VALUE_TYPE (value) == G_TYPE_PTR_ARRAY) {
+ g_ptr_array_foreach (g_value_get_boxed (value), (GFunc)append_value_to_sparql_builder,
builder);
+ } else {
+ append_value_to_sparql_builder (value, builder);
+ }
+}
+
+/**
+ * tracker_resource_generate_sparql_update:
+ * @self: a #TrackerResource
+ * @builder: a #TrackerSparqlBuilder where the result will be returned
+ * @error: address where an error can be returned
+ *
+ * Generates a SPARQL command to update a database with the information
+ * stored in @resource.
+ *
+ * Since: 1.10
+ */
+/* FIXME: cycles between resources will cause this to infinite loop. It should
+ * exit with an error instead, or better yet do the clever trickery in
+ * order to actually insert them. */
+void
+tracker_resource_generate_sparql_update (TrackerResource *resource,
+ TrackerSparqlBuilder *builder,
+ const char *graph_id,
+ GError **error)
+{
+ TrackerResourcePrivate *priv = GET_PRIVATE (resource);
+ GenerateSparqlRelationsData relations_data;
+ GenerateSparqlDeletesData deletes_data;
+
+ if (! priv->identifier) {
+ /* FIXME: use GError? */
+ g_warning ("Main resource must have an identifier.");
+ return;
+ }
+
+ g_return_if_fail (tracker_sparql_builder_get_state (builder) == TRACKER_SPARQL_BUILDER_STATE_UPDATE);
+
+ /* First, forget everything you know */
+ tracker_sparql_builder_delete_open (builder, NULL);
+ tracker_sparql_builder_delete_close (builder);
+ tracker_sparql_builder_where_open (builder);
+ if (graph_id) {
+ tracker_sparql_builder_graph_open (builder, graph_id);
+ }
+
+ tracker_sparql_builder_subject_iri (builder, priv->identifier);
+
+ deletes_data.builder = builder;
+ deletes_data.overwrite_flags = priv->overwrite;
+
+ g_hash_table_foreach (priv->properties, generate_sparql_deletes_foreach, &deletes_data);
+
+ if (graph_id){
+ tracker_sparql_builder_graph_close (builder);
+ }
+ tracker_sparql_builder_where_close (builder);
+
+ /* Now emit any sub-resources. */
+ relations_data.builder = builder;
+ relations_data.graph_id = graph_id;
+ relations_data.done_list = NULL;
+
+ g_hash_table_foreach (priv->properties, generate_sparql_relations_foreach, &relations_data);
+
+ /* Finally insert the rest of the data */
+
+ /* Passing the graph directly to insert_open causes it to generate a
+ * non-standard 'INSERT INTO <graph>' statement, while calling graph_open
+ * separately causes it to generate INSERT { GRAPH { .. } }. See
+ * <https://bugzilla.gnome.org/show_bug.cgi?id=658838>.
+ */
+ tracker_sparql_builder_insert_open (builder, NULL);
+ if (graph_id) {
+ tracker_sparql_builder_graph_open (builder, graph_id);
+ }
+
+ tracker_sparql_builder_subject_iri (builder, priv->identifier);
+
+ g_hash_table_foreach (priv->properties, generate_sparql_inserts_foreach, builder);
+
+ if (graph_id){
+ tracker_sparql_builder_graph_close (builder);
+ }
+ tracker_sparql_builder_insert_close (builder);
+}
+
+/* FIXME: serialize_json should be generate_json for consistency with this */
diff --git a/src/libtracker-sparql/tracker-resource.h b/src/libtracker-sparql/tracker-resource.h
index ff43028..7ced0bd 100644
--- a/src/libtracker-sparql/tracker-resource.h
+++ b/src/libtracker-sparql/tracker-resource.h
@@ -22,6 +22,8 @@
#include <glib-object.h>
+#include <libtracker-sparql/tracker-generated.h>
+
G_BEGIN_DECLS
#define TRACKER_TYPE_RESOURCE tracker_resource_get_type()
@@ -62,6 +64,8 @@ const char *tracker_resource_get_first_uri (TrackerResource *self, const char *p
const char *tracker_resource_get_identifier (TrackerResource *self);
gint tracker_resource_identifier_compare_func (TrackerResource *resource, const char *identifier);
+void tracker_resource_generate_sparql_update (TrackerResource *self, TrackerSparqlBuilder *builder, const
char *graph_id, GError **error);
+
G_END_DECLS
#endif /* __LIBTRACKER_RESOURCE_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]