[tracker/sparql-ontology-tree] WIP



commit d819f0a6f6f116597cc2eea885fa5f451edfc21c
Author: Martyn Russell <martyn lanedo com>
Date:   Tue Feb 18 13:31:27 2014 +0000

    WIP

 src/tracker-utils/tracker-sparql.c |  261 +++++++++++++++++++++++++++++++++++-
 1 files changed, 259 insertions(+), 2 deletions(-)
---
diff --git a/src/tracker-utils/tracker-sparql.c b/src/tracker-utils/tracker-sparql.c
index 201915d..8d7970d 100644
--- a/src/tracker-utils/tracker-sparql.c
+++ b/src/tracker-utils/tracker-sparql.c
@@ -56,6 +56,7 @@ static gboolean list_class_prefixes;
 static gchar *list_properties;
 static gchar *list_notifies;
 static gchar *list_indexes;
+static gchar *tree;
 static gboolean print_version;
 static gchar *search;
 
@@ -89,9 +90,13 @@ static GOptionEntry   entries[] = {
          N_("CLASS"),
        },
        { "list-indexes", 'i', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, parse_list_indexes,
-         N_("Retrieve indexes used in database to improve performance (PROPERTY is optional) "),
+         N_("Retrieve indexes used in database to improve performance (PROPERTY is optional)"),
          N_("PROPERTY"),
        },
+       { "tree", 't', 0, G_OPTION_ARG_STRING, &tree,
+         N_("Describe subclasses, superclasses and their properties for the given CLASS"),
+         N_("CLASS"),
+       },
        { "search", 's', 0, G_OPTION_ARG_STRING, &search,
          N_("Search for a class or property and display more information (e.g. Document)"),
          N_("CLASS/PROPERTY"),
@@ -429,6 +434,253 @@ print_cursor (TrackerSparqlCursor *cursor,
        }
 }
 
+static GNode *root = NULL;
+
+typedef struct {
+       gchar *class;
+       guint parent_known:1;
+} NodeData;
+
+static inline NodeData *
+tree_node_data_new (const gchar *class,
+                    gboolean     parent_known)
+{
+       NodeData *data;
+
+       data = g_slice_new0 (NodeData);
+       data->class = g_strdup (class);
+       data->parent_known = parent_known;
+
+       return data;
+}
+
+static inline void
+tree_node_data_free (NodeData *data)
+{
+       if (!data) {
+               return;
+       }
+
+       g_free (data->class);
+       g_slice_free (NodeData, data);
+}
+
+static gboolean
+tree_node_data_equal (GNode       *node,
+                      const gchar *class)
+{
+       NodeData *data;
+
+       data = node->data;
+
+       return strcmp (class, data->class) == 0 ? TRUE : FALSE;
+}
+
+static GNode *
+tree_node_lookup (GNode        *tree,
+                  const gchar  *class,
+                  GNode       **parent_node)
+{
+       GNode *parent, *node_found, *parent_found;
+
+       node_found = parent_found = NULL;
+
+       if (parent_node) {
+               *parent_node = NULL;
+       }
+
+       if (!tree) {
+               return NULL;
+       }
+
+       parent = tree;
+
+       while (parent) {
+               GNode *child, *next = NULL;
+
+               for (child = g_node_first_child (parent);
+                    child != NULL;
+                    child = g_node_next_sibling (child)) {
+                       if (tree_node_data_equal (child, class)) {
+                               next = child;
+                               break;
+                       }
+               }
+
+               if (next) {
+                       /* Exact match */
+                       node_found = next;
+                       parent_found = parent;
+                       break;
+               } else {
+                       /* Descent down the child */
+                       parent = next;
+               }
+       }
+
+       if (parent_node) {
+               *parent_node = parent_found;
+       }
+
+       return node_found;
+}
+
+static GNode *
+tree_add_class (const gchar *class,
+                const gchar *parent,
+                gboolean     parent_known)
+{
+       GNode *node, *parent_node;
+
+       g_debug ("Adding class '%s', parent '%s', parent known: %s",
+                class, parent, parent_known ? "yes" : "no");
+
+       // Check init...
+       if (!root) {
+               root = g_node_new (NULL);
+       }
+
+       // Look up class node
+       node = parent_node = NULL;
+
+       if (class) {
+               // If there is no class, node is root
+               node = tree_node_lookup (root, class, &parent_node);
+       }
+
+       if (!node) {
+               // Create node
+               NodeData *data;
+
+               data = tree_node_data_new (class, parent_known);
+               node = g_node_new (data);
+
+               if (!parent_known || !parent) {
+                       // Add to root node
+                       g_node_append (root, node);
+
+                       // If node is currently an orphan, add to root
+                       // and we will reorder it when we know more...
+               } else {
+
+                       // Lookup parent node and add to that.
+                       parent_node = tree_node_lookup (root, parent, NULL);
+
+                       if (!parent_node) {
+                               // Create parent node.
+                               parent_node = tree_add_class (parent, NULL, FALSE);
+                               g_assert (parent_node != NULL);
+                       }
+
+                       g_node_append (parent_node, node);
+               }
+       } else {
+               // Lookup parent node and add to that.
+               parent_node = tree_node_lookup (root, parent, NULL);
+
+               // Reparent found node, if we need to
+               if (parent_node) {
+                       NodeData *parent_data;
+
+                       parent_data = parent_node->data;
+
+                       if (!parent_data->parent_known) {
+                               // Add to right parent.
+                               g_node_append (parent_node, node);
+                               parent_data->parent_known = TRUE;
+                       }
+               }
+       }
+
+       return node;
+}
+
+static void
+tree_print (GNode      *tree,
+            GHashTable *prefixes)
+{
+       GNode *parent;
+
+       if (!tree) {
+               return;
+       }
+
+       // Print, depth first
+
+       parent = tree;
+
+       if (!parent->data) {
+               // Handle root
+               g_print ("ROOT\n");
+       }
+
+       while (parent) {
+               GNode *child, *next = NULL;
+
+               for (child = g_node_first_child (parent);
+                    child != NULL;
+                    child = g_node_next_sibling (child)) {
+                       NodeData *data;
+                       gchar *shorthand = NULL;
+
+                       data = child->data;
+
+                       if (prefixes) {
+                               shorthand = get_shorthand_for_offsets (prefixes, data->class);
+                       }
+
+                       g_print ("%*s-> %s\n",
+                                (g_node_depth (child) - 1) * 2,
+                                " ",
+                                shorthand ? shorthand : data->class);
+                       g_free (shorthand);
+
+                       tree_print (child, prefixes);
+               }
+
+               if (!next) {
+                       /* Descent down the child */
+                       parent = next;
+               }
+       }
+}
+
+static gint
+tree_get (TrackerSparqlConnection *connection,
+          const gchar             *class_lookup)
+{
+       TrackerSparqlCursor *cursor;
+       GHashTable *prefixes;
+       GError *error = NULL;
+       gchar *query;
+
+       /* Get subclasses of classes */
+       query = "select ?p ?c where { ?c a rdfs:Class . OPTIONAL { ?c rdfs:subClassOf ?p } }";
+       cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
+
+       if (error) {
+               g_printerr ("%s, %s\n",
+                           _("Could not create tree: subclass query failed"),
+                           error->message);
+               g_error_free (error);
+               g_object_unref (connection);
+
+               return EXIT_FAILURE;
+       }
+
+       while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
+               const gchar *parent = tracker_sparql_cursor_get_string (cursor, 0, NULL);
+               const gchar *class = tracker_sparql_cursor_get_string (cursor, 1, NULL);
+               tree_add_class (class, parent, TRUE);
+       }
+
+       prefixes = get_prefixes (connection);
+       tree_print (root, prefixes);
+       g_hash_table_unref (prefixes);
+
+       return EXIT_SUCCESS;
+}
+
 int
 main (int argc, char **argv)
 {
@@ -457,7 +709,8 @@ main (int argc, char **argv)
        }
 
        if (!list_classes && !list_class_prefixes && !list_properties &&
-           !list_notifies && !list_indexes && !search && !file && !query) {
+           !list_notifies && !list_indexes && !tree && !search &&
+           !file && !query) {
                error_message = _("An argument must be supplied");
        } else if (file && query) {
                error_message = _("File and query can not be used together");
@@ -670,6 +923,10 @@ main (int argc, char **argv)
                print_cursor (cursor, _("No indexes were found"), _("Indexes"), TRUE);
        }
 
+       if (tree) {
+               return tree_get (connection, tree);
+       }
+
        if (search) {
                gchar *query;
 


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