diff options
author | Matthias Baumgartner <dev@igsor.net> | 2023-03-05 19:25:29 +0100 |
---|---|---|
committer | Matthias Baumgartner <dev@igsor.net> | 2023-03-05 19:25:29 +0100 |
commit | 48b6081d0092e9c5a1b0ad79bdde2e51649bf61a (patch) | |
tree | 634198c34aae3c0306ce30ac7452abd7b53a14e8 /test/triple_store/sparql/test_parse_fetch.py | |
parent | 91437ba89d35bf482f3d9671bb99ef2fc69f5985 (diff) | |
parent | e4845c627e97a6d125bf33d9e7a4a8d373d7fc4a (diff) | |
download | bsfs-0.23.03.tar.gz bsfs-0.23.03.tar.bz2 bsfs-0.23.03.zip |
Merge branch 'develop'v0.23.03
Diffstat (limited to 'test/triple_store/sparql/test_parse_fetch.py')
-rw-r--r-- | test/triple_store/sparql/test_parse_fetch.py | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/test/triple_store/sparql/test_parse_fetch.py b/test/triple_store/sparql/test_parse_fetch.py new file mode 100644 index 0000000..1d793e7 --- /dev/null +++ b/test/triple_store/sparql/test_parse_fetch.py @@ -0,0 +1,257 @@ + +# imports +import rdflib +import unittest + +# bsie imports +from bsfs import schema +from bsfs.namespace import Namespace, ns +from bsfs.query import ast +from bsfs.utils import errors, URI + +# objects to test +from bsfs.triple_store.sparql.parse_fetch import Fetch + + +## code ## + +ns.bse = ns.bsfs.Entity() +ns.bst = ns.bsfs.Tag() +ns.bsc = ns.bsfs.Collection() + +class TestParseFetch(unittest.TestCase): + + def setUp(self): + self.schema = schema.from_string(''' + prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> + prefix xsd: <http://www.w3.org/2001/XMLSchema#> + + prefix bsfs: <https://schema.bsfs.io/core/> + prefix bse: <https://schema.bsfs.io/core/Entity#> + prefix bst: <https://schema.bsfs.io/core/Tag#> + prefix bsc: <https://schema.bsfs.io/core/Collection#> + + # nodes + bsfs:Entity rdfs:subClassOf bsfs:Node . + bsfs:Tag rdfs:subClassOf bsfs:Node . + bsfs:Collection rdfs:subClassOf bsfs:Node . + + # literals + xsd:integer rdfs:subClassOf bsfs:Literal . + xsd:string rdfs:subClassOf bsfs:Literal . + + # predicates + bse:tag rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:Entity ; + rdfs:range bsfs:Tag . + + bse:collection rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:Entity ; + rdfs:range bsfs:Collection . + + bse:filename rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:Entity ; + rdfs:range xsd:string . + + bse:rank rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:Entity ; + rdfs:range xsd:integer . + + bst:main rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:Tag ; + rdfs:range bsfs:Entity . + + bst:label rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:Tag ; + rdfs:range xsd:string . + + bsc:tag rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:Collection ; + rdfs:range bsfs:Tag . + + bsc:label rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:Collection ; + rdfs:range xsd:string . + + bsc:rating rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:Collection ; + rdfs:range xsd:integer . + + ''') + + # graph to test queries + self.graph = rdflib.Graph() + # schema hierarchies + self.graph.add((rdflib.URIRef('https://schema.bsfs.io/core/Entity'), rdflib.RDFS.subClassOf, rdflib.URIRef('https://schema.bsfs.io/core/Node'))) + self.graph.add((rdflib.URIRef('https://schema.bsfs.io/core/Collection'), rdflib.RDFS.subClassOf, rdflib.URIRef('https://schema.bsfs.io/core/Node'))) + self.graph.add((rdflib.URIRef('https://schema.bsfs.io/core/Tag'), rdflib.RDFS.subClassOf, rdflib.URIRef('https://schema.bsfs.io/core/Node'))) + # entities + self.graph.add((rdflib.URIRef('http://example.com/entity#1234'), rdflib.RDF.type, rdflib.URIRef('https://schema.bsfs.io/core/Entity'))) + self.graph.add((rdflib.URIRef('http://example.com/entity#4321'), rdflib.RDF.type, rdflib.URIRef('https://schema.bsfs.io/core/Entity'))) + # tags + self.graph.add((rdflib.URIRef('http://example.com/tag#1234'), rdflib.RDF.type, rdflib.URIRef('https://schema.bsfs.io/core/Tag'))) + self.graph.add((rdflib.URIRef('http://example.com/tag#4321'), rdflib.RDF.type, rdflib.URIRef('https://schema.bsfs.io/core/Tag'))) + # collections + self.graph.add((rdflib.URIRef('http://example.com/collection#1234'), rdflib.RDF.type, rdflib.URIRef('https://schema.bsfs.io/core/Collection'))) + self.graph.add((rdflib.URIRef('http://example.com/collection#4321'), rdflib.RDF.type, rdflib.URIRef('https://schema.bsfs.io/core/Collection'))) + # entity literals + self.graph.add((rdflib.URIRef('http://example.com/entity#1234'), rdflib.URIRef(ns.bse.rank), rdflib.Literal('1234', datatype=rdflib.XSD.integer))) + self.graph.add((rdflib.URIRef('http://example.com/entity#1234'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('filename_1234', datatype=rdflib.XSD.string))) + #self.graph.add((rdflib.URIRef('http://example.com/entity#4321'), rdflib.URIRef(ns.bse.rank), rdflib.Literal('4321', datatype=rdflib.XSD.integer))) + self.graph.add((rdflib.URIRef('http://example.com/entity#4321'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('filename_4321', datatype=rdflib.XSD.string))) + # tag literals + self.graph.add((rdflib.URIRef('http://example.com/tag#1234'), rdflib.URIRef(ns.bst.label), rdflib.Literal('tag_label_1234', datatype=rdflib.XSD.string))) + self.graph.add((rdflib.URIRef('http://example.com/tag#4321'), rdflib.URIRef(ns.bst.label), rdflib.Literal('tag_label_4321', datatype=rdflib.XSD.string))) + # collection literals + self.graph.add((rdflib.URIRef('http://example.com/collection#1234'), rdflib.URIRef(ns.bsc.label), rdflib.Literal('collection_label_1234', datatype=rdflib.XSD.string))) + self.graph.add((rdflib.URIRef('http://example.com/collection#1234'), rdflib.URIRef(ns.bsc.rating), rdflib.Literal('1234', datatype=rdflib.XSD.integer))) + self.graph.add((rdflib.URIRef('http://example.com/collection#4321'), rdflib.URIRef(ns.bsc.label), rdflib.Literal('collection_label_4321', datatype=rdflib.XSD.string))) + self.graph.add((rdflib.URIRef('http://example.com/collection#4321'), rdflib.URIRef(ns.bsc.rating), rdflib.Literal('4321', datatype=rdflib.XSD.integer))) + # entity-tag links + self.graph.add((rdflib.URIRef('http://example.com/entity#1234'), rdflib.URIRef(ns.bse.tag), rdflib.URIRef('http://example.com/tag#1234'))) + self.graph.add((rdflib.URIRef('http://example.com/entity#4321'), rdflib.URIRef(ns.bse.tag), rdflib.URIRef('http://example.com/tag#4321'))) + # entity-collection links + self.graph.add((rdflib.URIRef('http://example.com/entity#1234'), rdflib.URIRef(ns.bse.collection), rdflib.URIRef('http://example.com/collection#1234'))) + self.graph.add((rdflib.URIRef('http://example.com/entity#4321'), rdflib.URIRef(ns.bse.collection), rdflib.URIRef('http://example.com/collection#4321'))) + # collection-tag links + self.graph.add((rdflib.URIRef('http://example.com/collection#1234'), rdflib.URIRef(ns.bsc.tag), rdflib.URIRef('http://example.com/tag#1234'))) + self.graph.add((rdflib.URIRef('http://example.com/collection#4321'), rdflib.URIRef(ns.bsc.tag), rdflib.URIRef('http://example.com/tag#4321'))) + # tag-entity links # NOTE: cross-over + self.graph.add((rdflib.URIRef('http://example.com/tag#1234'), rdflib.URIRef(ns.bst.main), rdflib.URIRef('http://example.com/entity#4321'))) + self.graph.add((rdflib.URIRef('http://example.com/tag#4321'), rdflib.URIRef(ns.bst.main), rdflib.URIRef('http://example.com/entity#1234'))) + + # default parser + self.parser = Fetch(self.schema) + self.ent = self.schema.node(ns.bsfs.Entity) + + + def test_call(self): + # NOTE: The individual ast components are considered in the respective tests. Here, we test __call__ specifics. + + # __call__ requires a valid root type + self.assertRaises(errors.BackendError, self.parser, self.schema.literal(ns.bsfs.Literal), ast.fetch.This('this')) + self.assertRaises(errors.ConsistencyError, self.parser, self.schema.node(ns.bsfs.Node).child(ns.bsfs.Invalid), ast.fetch.This('this')) + # __call__ requires a parseable root + self.assertRaises(errors.BackendError, self.parser, self.ent, ast.filter.FilterExpression()) + # __call__ returns an executable query + q = self.parser(self.ent, ast.fetch.Fetch(ns.bse.tag, ast.fetch.Value(ns.bst.label, 'label'))) + self.assertSetEqual(set(q(self.graph)), { + (rdflib.URIRef('http://example.com/entity#1234'), rdflib.Literal('tag_label_1234', datatype=rdflib.XSD.string)), + (rdflib.URIRef('http://example.com/entity#4321'), rdflib.Literal('tag_label_4321', datatype=rdflib.XSD.string)), + }) + + + def test_routing(self): + self.assertRaises(errors.BackendError, self.parser._parse_fetch_expression, self.ent, ast.fetch.FetchExpression(), '?head') + + + def test_all(self): + # multiple values query + q = self.parser(self.ent, ast.fetch.All( + ast.fetch.Value(ns.bse.filename, name='filename'), + ast.fetch.Value(ns.bse.rank, name='rank')), + ) + self.assertSetEqual(set(q.names), {'filename', 'rank'}) + if q.names == ('filename', 'rank'): + self.assertSetEqual(set(q(self.graph)), { + (rdflib.URIRef('http://example.com/entity#1234'), rdflib.Literal('filename_1234', datatype=rdflib.XSD.string), rdflib.Literal('1234', datatype=rdflib.XSD.integer)), + (rdflib.URIRef('http://example.com/entity#4321'), rdflib.Literal('filename_4321', datatype=rdflib.XSD.string), None), + }) + else: + self.assertSetEqual(set(q(self.graph)), { + (rdflib.URIRef('http://example.com/entity#1234'), rdflib.Literal('1234', datatype=rdflib.XSD.integer), rdflib.Literal('filename_1234', datatype=rdflib.XSD.string)), + (rdflib.URIRef('http://example.com/entity#4321'), None, rdflib.Literal('filename_4321', datatype=rdflib.XSD.string)), + }) + # mixed values and node query + q = self.parser(self.ent, ast.fetch.All( + ast.fetch.Value(ns.bse.filename, name='filename'), + ast.fetch.Node(ns.bse.tag, name='tag'), + )) + self.assertSetEqual(set(q.names), {'filename', 'tag'}) + if q.names == ('filename', 'tag'): + self.assertSetEqual(set(q(self.graph)), { + (rdflib.URIRef('http://example.com/entity#1234'), rdflib.Literal('filename_1234', datatype=rdflib.XSD.string), rdflib.URIRef('http://example.com/tag#1234')), + (rdflib.URIRef('http://example.com/entity#4321'), rdflib.Literal('filename_4321', datatype=rdflib.XSD.string), rdflib.URIRef('http://example.com/tag#4321')), + }) + else: + self.assertSetEqual(set(q(self.graph)), { + (rdflib.URIRef('http://example.com/entity#1234'), rdflib.URIRef('http://example.com/tag#1234'), rdflib.Literal('filename_1234', datatype=rdflib.XSD.string)), + (rdflib.URIRef('http://example.com/entity#4321'), rdflib.URIRef('http://example.com/tag#4321'), rdflib.Literal('filename_4321', datatype=rdflib.XSD.string)), + }) + # multiple values and second hop + q = self.parser(self.ent, ast.fetch.Fetch(ns.bse.tag, ast.fetch.All( + ast.fetch.This(name='tag'), + ast.fetch.Value(ns.bst.label, name='label'), + ))) + self.assertSetEqual(set(q.names), {'tag', 'label'}) + if q.names == ('tag', 'label'): + self.assertSetEqual(set(q(self.graph)), { + (rdflib.URIRef('http://example.com/entity#1234'), rdflib.URIRef('http://example.com/tag#1234'), rdflib.Literal('tag_label_1234', datatype=rdflib.XSD.string)), + (rdflib.URIRef('http://example.com/entity#4321'), rdflib.URIRef('http://example.com/tag#4321'), rdflib.Literal('tag_label_4321', datatype=rdflib.XSD.string)), + }) + else: + self.assertSetEqual(set(q(self.graph)), { + (rdflib.URIRef('http://example.com/entity#1234'), rdflib.Literal('tag_label_1234', datatype=rdflib.XSD.string), rdflib.URIRef('http://example.com/tag#1234')), + (rdflib.URIRef('http://example.com/entity#4321'), rdflib.Literal('tag_label_4321', datatype=rdflib.XSD.string), rdflib.URIRef('http://example.com/tag#4321')), + }) + + + + def test_fetch(self): + # two-hop query + q = self.parser(self.ent, ast.fetch.Fetch(ns.bse.tag, ast.fetch.Value(ns.bst.label, 'tag_label'))) + self.assertSetEqual(set(q(self.graph)), { + (rdflib.URIRef('http://example.com/entity#1234'), rdflib.Literal('tag_label_1234', datatype=rdflib.XSD.string)), + (rdflib.URIRef('http://example.com/entity#4321'), rdflib.Literal('tag_label_4321', datatype=rdflib.XSD.string)), + }) + # three-hop-query + q = self.parser(self.ent, ast.fetch.Fetch(ns.bse.tag, ast.fetch.Fetch(ns.bst.main, ast.fetch.Value(ns.bse.rank, 'entity_rank')))) + self.assertSetEqual(set(q(self.graph)), { + (rdflib.URIRef('http://example.com/entity#1234'), None), + (rdflib.URIRef('http://example.com/entity#4321'), rdflib.Literal('1234', datatype=rdflib.XSD.integer)), + }) + + + def test_node(self): + # cannot use the internal hop name + self.assertRaises(errors.BackendError, self.parser, self.ent, ast.fetch.Node(ns.bse.tag, self.parser.ngen.prefix[1:] + '123')) + # a simple Node statement + q = self.parser(self.ent, ast.fetch.Node(ns.bse.tag, 'tag')) + self.assertSetEqual(set(q.names), {'tag'}) + self.assertSetEqual(set(q(self.graph)), { + (rdflib.URIRef('http://example.com/entity#1234'), rdflib.URIRef('http://example.com/tag#1234')), + (rdflib.URIRef('http://example.com/entity#4321'), rdflib.URIRef('http://example.com/tag#4321')), + }) + + + def test_value(self): + # cannot use the internal hop name + self.assertRaises(errors.BackendError, self.parser, self.schema.node(ns.bsfs.Entity), ast.fetch.Value(ns.bse.filename, self.parser.ngen.prefix[1:] + '123')) + # a simple Value statement + q = self.parser(self.ent, ast.fetch.Value(ns.bse.filename, 'filename')) + self.assertSetEqual(set(q.names), {'filename'}) + self.assertSetEqual(set(q(self.graph)), { + (rdflib.URIRef('http://example.com/entity#1234'), rdflib.Literal('filename_1234', datatype=rdflib.XSD.string)), + (rdflib.URIRef('http://example.com/entity#4321'), rdflib.Literal('filename_4321', datatype=rdflib.XSD.string)), + }) + + + def test_this(self): + # cannot use the internal hop name + self.assertRaises(errors.BackendError, self.parser, self.ent, ast.fetch.This(self.parser.ngen.prefix[1:] + '123')) + # a simple This statement + self.assertEqual(self.parser._this(self.ent, ast.fetch.This('this'), '?head'), + ({('?head', 'this')}, '')) + q = self.parser(self.ent, ast.fetch.This('this')) + self.assertSetEqual(set(q(self.graph)), { + (rdflib.URIRef('http://example.com/entity#1234'), rdflib.URIRef('http://example.com/entity#1234')), + (rdflib.URIRef('http://example.com/entity#4321'), rdflib.URIRef('http://example.com/entity#4321')), + }) + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## |