Browse Source

Merge pull request #124 from scossu/user_types

User types
Stefano Cossu 4 years ago
parent
commit
4427a7b51c
3 changed files with 95 additions and 4 deletions
  1. 12 0
      lakesuperior/endpoints/ldp.py
  2. 29 4
      lakesuperior/model/ldp/ldpr.py
  3. 54 0
      tests/2_api/test_2_0_resource_api.py

+ 12 - 0
lakesuperior/endpoints/ldp.py

@@ -661,6 +661,18 @@ def parse_repr_options(retr_opts, out_headers):
     Ideally, IMR retrieval is done once per request, so all the options
     are set once in the `imr()` property.
 
+    Representation options include:
+
+    - ``embed_children``: include full resource representation of all resource
+        children in the resource graph.
+    - ``incl_children``: TODO
+    - ``incl_inbound``: include inbound triples (triples whose object is
+      this resource).
+    - ``incl_srv_mgd``: include server-managed triples.
+
+    All options above are ``False`` by default except for ``incl_srv_mgd``
+    which is only ``False`` if the ``return`` representation is ``minimal``.
+
     :param dict retr_opts:: Options parsed from `Prefer` header.
     :param dict out_headers:: Response headers.
     """

+ 29 - 4
lakesuperior/model/ldp/ldpr.py

@@ -158,10 +158,11 @@ class Ldpr(metaclass=ABCMeta):
             set) it refers to the root node. It can also be the full URI or
             URN, in which case it will be converted.
         :param dict repr_opts: Options used to retrieve the IMR. See
-            `parse_rfc7240` for format details.
+            :py:meth:`~lakesuperior.endpoints.ldp.parse_repr_options` for
+            format details.
         :param str provided_imr: RDF data provided by the client in
             operations such as `PUT` or `POST`, serialized as a string. This
-            sets the `provided_imr` property.
+            sets the :py:data:`~Ldpr.provided_imr` property.
         """
         self.uid = (
             rdfly.uri_to_uid(uid) if isinstance(uid, URIRef) else uid)
@@ -264,6 +265,17 @@ class Ldpr(metaclass=ABCMeta):
         return self._metadata
 
 
+    @property
+    def user_data(self):
+        """
+        User-defined triples.
+        """
+        if not hasattr(self, '_user_data'):
+            self._user_data = rdfly.get_user_data(self.uid)
+
+        return self._user_data
+
+
     @metadata.setter
     def metadata(self, rsrc):
         """
@@ -339,7 +351,8 @@ class Ldpr(metaclass=ABCMeta):
 
     @property
     def types(self):
-        """All RDF types.
+        """
+        All RDF types, both server-managed and user-defined.
 
         :rtype: set(rdflib.term.URIRef)
         """
@@ -352,7 +365,7 @@ class Ldpr(metaclass=ABCMeta):
             else:
                 return set()
 
-            self._types = set(metadata[self.uri: RDF.type])
+            self._types = set(metadata[self.uri: RDF.type]) | self.user_types
 
         return self._types
 
@@ -369,6 +382,18 @@ class Ldpr(metaclass=ABCMeta):
         return self._ldp_types
 
 
+    @property
+    def user_types(self):
+        """User-defined types.
+
+        :rtype: set(rdflib.term.URIRef)
+        """
+        if not hasattr(self, '_ud_types'):
+            self._ud_types = self.user_data[self.uri: RDF.type]
+
+        return self._ud_types
+
+
     ## LDP METHODS ##
 
     def head(self):

+ 54 - 0
tests/2_api/test_2_0_resource_api.py

@@ -568,6 +568,60 @@ class TestResourceCRUD:
     #                top_cont_rsrc.uri: nsc['dcterms'].relation:
     #                nsc['fcres'][target_uid]]
 
+    def test_user_data(self):
+        '''
+        Verify that only user-defined data are in user_data.
+        '''
+        data = b'''
+        <> a <urn:t:1> ;
+            <urn:p:1> "Property 1" ;
+            <urn:p:2> <urn:o:2> .
+        '''
+        uid = f'/{uuid4()}'
+        uri = nsc['fcres'][uid]
+
+        rsrc_api.create_or_replace(uid, rdf_data=data, rdf_fmt='ttl')
+        rsrc = rsrc_api.get(uid)
+
+        with env.app_globals.rdf_store.txn_ctx():
+            ud_data = rsrc.user_data
+
+            assert ud_data[uri: nsc['rdf'].type: URIRef('urn:t:1')]
+            assert ud_data[uri: URIRef('urn:p:1'): Literal('Property 1')]
+            assert ud_data[uri: URIRef('urn:p:2'): URIRef('urn:o:2')]
+            assert not ud_data[uri: nsc['rdf'].type: nsc['ldp'].Resource]
+
+
+    def test_types(self):
+        '''
+        Test server-managed and user-defined RDF types.
+        '''
+        data = b'''
+        <> a <urn:t:1> , <urn:t:2> .
+        '''
+        uid = f'/{uuid4()}'
+        uri = nsc['fcres'][uid]
+
+        rsrc_api.create_or_replace(uid, rdf_data=data, rdf_fmt='ttl')
+        rsrc = rsrc_api.get(uid)
+
+        with env.app_globals.rdf_store.txn_ctx():
+            assert URIRef('urn:t:1') in rsrc.types
+            assert URIRef('urn:t:1') in rsrc.user_types
+            assert URIRef('urn:t:1') not in rsrc.ldp_types
+
+            assert URIRef('urn:t:2') in rsrc.types
+            assert URIRef('urn:t:2') in rsrc.user_types
+            assert URIRef('urn:t:2') not in rsrc.ldp_types
+
+            assert nsc['ldp'].Resource in rsrc.types
+            assert nsc['ldp'].Resource not in rsrc.user_types
+            assert nsc['ldp'].Resource in rsrc.ldp_types
+
+            assert nsc['ldp'].Container in rsrc.types
+            assert nsc['ldp'].Container not in rsrc.user_types
+            assert nsc['ldp'].Container in rsrc.ldp_types
+
 
 
 @pytest.mark.usefixtures('db')