[tracker/wip/carlosg/unrestricted-predicates: 5/6] libtracker-sparql: Implement NegatedPropertySet path operator



commit 87405905cc1f0e6937edb667e744b53f2fd302d5
Author: Carlos Garnacho <carlosg gnome org>
Date:   Sun Jan 13 16:17:26 2019 +0100

    libtracker-sparql: Implement NegatedPropertySet path operator
    
    The negated property set "!" looks up all the triples where the
    property does not match the given nested path. Use the tracker_triples
    table so we look up all triples except the ones that match the nested
    property path.
    
    We don't really look up the matching property in property path queries,
    so just account that there will be results that EXCEPT doesn't filter.

 src/libtracker-data/tracker-sparql-types.c |   3 +
 src/libtracker-data/tracker-sparql-types.h |   1 +
 src/libtracker-data/tracker-sparql.c       | 128 ++++++++++++++++++++++++++++-
 3 files changed, 129 insertions(+), 3 deletions(-)
---
diff --git a/src/libtracker-data/tracker-sparql-types.c b/src/libtracker-data/tracker-sparql-types.c
index 05b0600d7..91c502828 100644
--- a/src/libtracker-data/tracker-sparql-types.c
+++ b/src/libtracker-data/tracker-sparql-types.c
@@ -614,6 +614,9 @@ tracker_path_element_set_unique_name (TrackerPathElement *elem,
        case TRACKER_PATH_OPERATOR_ONEORMORE:
                name = "oneormore";
                break;
+       case TRACKER_PATH_OPERATOR_NEGATED:
+               name = "neg";
+               break;
        default:
                g_assert_not_reached ();
        }
diff --git a/src/libtracker-data/tracker-sparql-types.h b/src/libtracker-data/tracker-sparql-types.h
index bd3b063ba..58a3a04be 100644
--- a/src/libtracker-data/tracker-sparql-types.h
+++ b/src/libtracker-data/tracker-sparql-types.h
@@ -161,6 +161,7 @@ typedef enum {
        TRACKER_PATH_OPERATOR_ZEROORONE,   /* ? */
        TRACKER_PATH_OPERATOR_ONEORMORE,   /* + */
        TRACKER_PATH_OPERATOR_ZEROORMORE,  /* * */
+       TRACKER_PATH_OPERATOR_NEGATED,     /* ! */
 } TrackerPathOperator;
 
 struct _TrackerPathElement {
diff --git a/src/libtracker-data/tracker-sparql.c b/src/libtracker-data/tracker-sparql.c
index 9defa0b49..03ca5902e 100644
--- a/src/libtracker-data/tracker-sparql.c
+++ b/src/libtracker-data/tracker-sparql.c
@@ -625,6 +625,17 @@ _prepend_path_element (TrackerSparql      *sparql,
                                       path_elem->data.composite.child1->name,
                                       path_elem->data.composite.child1->name);
                break;
+       case TRACKER_PATH_OPERATOR_NEGATED:
+               _append_string_printf (sparql,
+                                      "\"%s\" (ID, value, graph, prop) AS "
+                                      "(SELECT subject, object, graph, predicate "
+                                      "FROM \"tracker_triples\" "
+                                      "EXCEPT "
+                                      "SELECT ID, value, graph, prop "
+                                      "FROM \"%s\") ",
+                                      path_elem->name,
+                                      path_elem->data.composite.child1->name);
+               break;
        }
 
        tracker_sparql_swap_builder (sparql, old);
@@ -4175,7 +4186,17 @@ translate_PathPrimary (TrackerSparql  *sparql,
        /* PathPrimary ::= iri | 'a' | '!' PathNegatedPropertySet | '(' Path ')'
         */
        if (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_OP_NEG)) {
+               TrackerPathElement *path_elem;
+
                _call_rule (sparql, NAMED_RULE_PathNegatedPropertySet, error);
+
+               path_elem = tracker_path_element_operator_new (TRACKER_PATH_OPERATOR_NEGATED,
+                                                              sparql->current_state.path,
+                                                              NULL);
+               tracker_select_context_add_path_element (TRACKER_SELECT_CONTEXT (sparql->context),
+                                                        path_elem);
+               _prepend_path_element (sparql, path_elem);
+               sparql->current_state.path = path_elem;
        } else if (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_OPEN_PARENS)) {
                _call_rule (sparql, NAMED_RULE_Path, error);
 
@@ -4226,19 +4247,120 @@ static gboolean
 translate_PathNegatedPropertySet (TrackerSparql  *sparql,
                                   GError        **error)
 {
+       GPtrArray *path_elems;
+
        /* PathNegatedPropertySet ::= PathOneInPropertySet | '(' ( PathOneInPropertySet ( '|' 
PathOneInPropertySet )* )? ')'
         */
-       _unimplemented ("Negated property set in property paths");
-       return FALSE;
+       path_elems = g_ptr_array_new ();
+
+       if (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_OPEN_PARENS)) {
+               _call_rule (sparql, NAMED_RULE_PathOneInPropertySet, error);
+               g_ptr_array_add (path_elems, sparql->current_state.path);
+
+               while (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_PATH_ALTERNATIVE)) {
+                       _call_rule (sparql, NAMED_RULE_PathOneInPropertySet, error);
+                       g_ptr_array_add (path_elems, sparql->current_state.path);
+               }
+
+               _expect (sparql, RULE_TYPE_LITERAL, LITERAL_CLOSE_PARENS);
+       } else {
+               _call_rule (sparql, NAMED_RULE_PathOneInPropertySet, error);
+               g_ptr_array_add (path_elems, sparql->current_state.path);
+       }
+
+       if (path_elems->len > 1) {
+               TrackerPathElement *path_elem;
+               gint i;
+
+               path_elem = tracker_path_element_operator_new (TRACKER_PATH_OPERATOR_ALTERNATIVE,
+                                                              g_ptr_array_index (path_elems, 0),
+                                                              g_ptr_array_index (path_elems, 1));
+               tracker_select_context_add_path_element (TRACKER_SELECT_CONTEXT (sparql->context),
+                                                        path_elem);
+               _prepend_path_element (sparql, path_elem);
+
+               for (i = 2; i < path_elems->len; i++) {
+                       TrackerPathElement *child;
+
+                       child = g_ptr_array_index (path_elems, i);
+                       path_elem = tracker_path_element_operator_new (TRACKER_PATH_OPERATOR_ALTERNATIVE,
+                                                                      child, path_elem);
+                       tracker_select_context_add_path_element (TRACKER_SELECT_CONTEXT (sparql->context),
+                                                                path_elem);
+                       _prepend_path_element (sparql, path_elem);
+               }
+
+               sparql->current_state.path = path_elem;
+       }
+
+       g_ptr_array_unref (path_elems);
+
+       return TRUE;
 }
 
 static gboolean
 translate_PathOneInPropertySet (TrackerSparql  *sparql,
                                 GError        **error)
 {
+       gboolean inverse = FALSE;
+
        /* PathOneInPropertySet ::= iri | 'a' | '^' ( iri | 'a' )
         */
-       return FALSE;
+       if (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_PATH_INVERSE))
+               inverse = TRUE;
+
+       if (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_A) ||
+           _check_in_rule (sparql, NAMED_RULE_iri)) {
+               TrackerOntologies *ontologies;
+               TrackerProperty *prop;
+               TrackerPathElement *path_elem;
+               gchar *str;
+
+               if (_check_in_rule (sparql, NAMED_RULE_iri))
+                       _call_rule (sparql, NAMED_RULE_iri, error);
+
+               str = _dup_last_string (sparql);
+               ontologies = tracker_data_manager_get_ontologies (sparql->data_manager);
+               prop = tracker_ontologies_get_property_by_uri (ontologies, str);
+
+               if (!prop) {
+                       g_set_error (error, TRACKER_SPARQL_ERROR,
+                                    TRACKER_SPARQL_ERROR_UNKNOWN_PROPERTY,
+                                    "Unknown property '%s'", str);
+                       g_free (str);
+                       return FALSE;
+               }
+
+               path_elem =
+                       tracker_select_context_lookup_path_element_for_property (TRACKER_SELECT_CONTEXT 
(sparql->context),
+                                                                                prop);
+
+               if (!path_elem) {
+                       path_elem = tracker_path_element_property_new (prop);
+                       tracker_select_context_add_path_element (TRACKER_SELECT_CONTEXT (sparql->context),
+                                                                path_elem);
+                       _prepend_path_element (sparql, path_elem);
+               }
+
+               sparql->current_state.path = path_elem;
+               g_free (str);
+       } else {
+               g_assert_not_reached ();
+       }
+
+       if (inverse) {
+               TrackerPathElement *path_elem;
+
+               path_elem = tracker_path_element_operator_new (TRACKER_PATH_OPERATOR_INVERSE,
+                                                              sparql->current_state.path,
+                                                              NULL);
+               tracker_select_context_add_path_element (TRACKER_SELECT_CONTEXT (sparql->context),
+                                                        path_elem);
+               _prepend_path_element (sparql, path_elem);
+               sparql->current_state.path = path_elem;
+       }
+
+       return TRUE;
 }
 
 static gboolean


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