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



commit af2f8f67efda1c264a7a8cd515230cae2fc6d827
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.

 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]