{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE PostfixOperators #-} module Database.HSparql.QueryGeneratorTest ( testSuite ) where import Test.Framework (testGroup, Test) import Test.Framework.Providers.HUnit import Test.HUnit import Data.Text (Text) import qualified Data.Text as T import Data.String.QQ (s) import Database.HSparql.QueryGenerator class CreateQuery a where createQuery :: a -> Text instance CreateQuery (Query SelectQuery) where createQuery = T.pack . createSelectQuery instance CreateQuery (Query ConstructQuery) where createQuery = T.pack . createConstructQuery instance CreateQuery (Query AskQuery) where createQuery = T.pack . createAskQuery instance CreateQuery (Query UpdateQuery) where createQuery = T.pack . createUpdateQuery instance CreateQuery (Query DescribeQuery) where createQuery = T.pack . createDescribeQuery normalizeWhitespace :: Text -> Text normalizeWhitespace = T.strip . (T.replace " " " ") . (T.replace " " " ") . (T.replace " " " ") . (T.replace "\n" " ") queryTexts :: [(Text, Text)] queryTexts = [ ( [s| PREFIX dbpedia: PREFIX dbprop: PREFIX foaf: SELECT ?x1 ?x2 WHERE { ?x0 dbprop:genre dbpedia:Web_browser . ?x0 foaf:name ?x1 . ?x0 foaf:page ?x2 . } |] , createQuery $ do resource <- prefix "dbpedia" (iriRef "http://dbpedia.org/resource/") dbpprop <- prefix "dbprop" (iriRef "http://dbpedia.org/property/") foaf <- prefix "foaf" (iriRef "http://xmlns.com/foaf/0.1/") x <- var name <- var page <- var triple_ x (dbpprop .:. "genre") (resource .:. "Web_browser") triple_ x (foaf .:. "name") name triple_ x (foaf .:. "page") page selectVars [name, page] ) , ( [s| PREFIX dbpedia: PREFIX dbprop: PREFIX foaf: PREFIX example: CONSTRUCT { ?x0 example:hasName ?x1 . } WHERE { ?x0 dbprop:genre dbpedia:Web_browser . ?x0 foaf:name ?x1 . ?x0 foaf:page ?x2 . } |] , createQuery $ do resource <- prefix "dbpedia" (iriRef "http://dbpedia.org/resource/") dbpprop <- prefix "dbprop" (iriRef "http://dbpedia.org/property/") foaf <- prefix "foaf" (iriRef "http://xmlns.com/foaf/0.1/") example <- prefix "example" (iriRef "http://www.example.com/") x <- var name <- var page <- var construct <- constructTriple x (example .:. "hasName") name triple_ x (dbpprop .:. "genre") (resource .:. "Web_browser") triple_ x (foaf .:. "name") name triple_ x (foaf .:. "page") page return ConstructQuery { queryConstructs = [construct] } ) , ( [s| PREFIX dbpedia: DESCRIBE dbpedia:Edinburgh WHERE { } |] , createQuery $ do resource <- prefix "dbpedia" (iriRef "http://dbpedia.org/resource/") uri <- describeIRI (resource .:. "Edinburgh") return DescribeQuery { queryDescribe = uri } ) , ( [s| PREFIX dbpedia: PREFIX dbprop: ASK { ?x0 dbprop:genre dbpedia:Web_browser . } |] , createQuery $ do resource <- prefix "dbpedia" (iriRef "http://dbpedia.org/resource/") dbprop <- prefix "dbprop" (iriRef "http://dbpedia.org/property/") x <- var ask <- askTriple x (dbprop .:. "genre") (resource .:. "Web_browser") return AskQuery { queryAsk = [ask] } ) -- https://github.com/robstewart57/hsparql/pull/31 , ( [s| PREFIX : PREFIX ex: SELECT ?x0 WHERE { ?x0 :property1 :X . FILTER ((?x1>(10))&&(?x1<(20))) . { SELECT ((AVG(?x0_0)) AS ?x1) WHERE { ?x0 :property2 [ex:property3 ?x0_0] . } } } |] , createQuery $ do p1 <- prefix "" (iriRef "http://example1.com/") s <- var v <- var triple_ s (p1 .:. "property1") (p1 .:. "X") filterExpr_ $ (v .>. (10::Integer)) .&&. (v .<. (20::Integer)) subQuery_ $ do p2 <- prefix "ex" (iriRef "http://example2.com/") v' <- var triple_ s (p1 .:. "property2") [mkPredicateObject (p2 .:. "property3") v'] select [avg v' `as` v] selectVars [s] ) -- https://www.w3.org/TR/sparql11-query/#OptionalMatching , ( [s| PREFIX foaf: SELECT ?x1 ?x2 WHERE { ?x0 foaf:name ?x1 . OPTIONAL { ?x0 foaf:mbox ?x2 . } } |] , createQuery $ do foaf <- prefix "foaf" (iriRef "http://xmlns.com/foaf/0.1/") x <- var name <- var mbox <- var triple_ x (foaf .:. "name") name optional_ $ do triple_ x (foaf .:. "mbox") mbox selectVars [name, mbox] ) -- https://www.w3.org/TR/sparql11-query/#alternatives , ( [s| PREFIX dc10: PREFIX dc11: SELECT ?x1 WHERE { { ?x0 dc10:title ?x1 . } UNION { ?x0 dc11:title ?x1 . } } |] , createQuery $ do dc10 <- prefix "dc10" (iriRef "http://purl.org/dc/elements/1.0/") dc11 <- prefix "dc11" (iriRef "http://purl.org/dc/elements/1.1/") book <- var title <- var let tt10 = triple_ book (dc10 .:. "title") title tt11 = triple_ book (dc11 .:. "title") title in union_ tt10 tt11 selectVars [title] ) -- https://www.w3.org/TR/sparql11-query/#neg-notexists , ( [s| PREFIX rdf: PREFIX foaf: SELECT ?x0 WHERE { ?x0 rdf:type foaf:Person . FILTER NOT EXISTS { ?x0 foaf:name ?x1 . } } |] , createQuery $ do rdf <- prefix "rdf" (iriRef "http://www.w3.org/1999/02/22-rdf-syntax-ns#") foaf <- prefix "foaf" (iriRef "http://xmlns.com/foaf/0.1/") person <- var name <- var triple_ person (rdf .:. "type") (foaf .:. "Person") filterNotExists_ $ do triple_ person (foaf .:. "name") name selectVars [person] ) , ( [s| PREFIX ex: SELECT ?x0 ?x1 WHERE { ?x0 ex:foo%20bar ?x1 . } |] , createQuery $ do ex <- prefix "ex" (iriRef "http://example.com/") s <- var o <- var triple_ s (ex .:. "foo bar") o selectVars [s, o] ) -- Count distinct subjects and objects query , ( [s| SELECT ((COUNT(?x0)) AS ?x4) WHERE { { SELECT DISTINCT ?x0 WHERE { { ?x0 ?x2 ?x3 . } UNION { ?x1 ?x2 ?x0 . } } } } |] , createQuery $ do r <- var s <- var p <- var o <- var subQuery_ $ do let tt1 = triple_ r p o tt2 = triple_ s p r in do distinct_ union_ tt1 tt2 selectVars [r] countVar <- var select [count r `as` countVar] ) -- Count number of instances of each class in the dataset. , ( [s| SELECT ?x1 ((COUNT(?x0)) AS ?x2) WHERE { ?x0 ?x1 . } GROUP BY ?x1 |] , createQuery $ do s <- var o <- var triple_ s (iriRef "http://www.w3.org/1999/02/22-rdf-syntax-ns#type") o groupBy_ o countVar <- var select [SelectVar o, count s `as` countVar] ) -- Count number of resources typed with a class from Wikidata. , ( [s| SELECT ((COUNT(?x0)) AS ?x2) WHERE { ?x0 ?x1 . FILTER (CONTAINS((STR(?x1)), "http://www.wikidata.org/entity")) . } |] , createQuery $ do s <- var o <- var triple_ s (iriRef "http://www.w3.org/1999/02/22-rdf-syntax-ns#type") o filterExpr_ $ contains (str o) ("http://www.wikidata.org/entity" :: Text) countVar <- var select [count s `as` countVar] ) -- Create a federated query , ( [s| PREFIX foaf: SELECT ?x1 WHERE { foaf:knows ?x0 . SERVICE { ?x0 foaf:name ?x1 . } } |] , createQuery $ do foaf <- prefix "foaf" (iriRef "http://xmlns.com/foaf/0.1/") person <- var name <- var triple_ (iriRef "http://example.org/myfoaf/I") (foaf .:. "knows") person service_ (iriRef "http://people.example.org/sparql") $ do triple_ person (foaf .:. "name") name selectVars [name] ) -- Create query containing property paths , ( [s| PREFIX foaf: SELECT ?x0 ?x1 WHERE { ?x0 ((foaf:knows/foaf:knows)/foaf:name) ?x1 . } |] , createQuery $ do foaf <- prefix "foaf" (iriRef "http://xmlns.com/foaf/0.1/") s <- var o <- var let foafKnows = foaf .:. "knows" let foafName = foaf .:. "name" triple_ s (foafKnows .//. foafKnows .//. foafName) o selectVars [s, o] ) , ( [s| PREFIX foaf: SELECT ?x0 ?x1 WHERE { ?x0 (^foaf:mbox) ?x1 . } |] , createQuery $ do foaf <- prefix "foaf" (iriRef "http://xmlns.com/foaf/0.1/") s <- var o <- var let foafMbox = foaf .:. "mbox" triple_ s (inv foafMbox) o selectVars [s, o] ) , ( [s| PREFIX foaf: SELECT ?x0 ?x1 WHERE { ?x0 (foaf:knows/(^foaf:knows)) ?x1 . } |] , createQuery $ do foaf <- prefix "foaf" (iriRef "http://xmlns.com/foaf/0.1/") s <- var o <- var let foafKnows = foaf .:. "knows" triple_ s (foafKnows .//. inv foafKnows) o selectVars [s, o] ) , ( [s| PREFIX foaf: SELECT ?x0 ?x1 WHERE { ?x0 (foaf:knows/(^foaf:knows)) ?x1 . } |] , createQuery $ do foaf <- prefix "foaf" (iriRef "http://xmlns.com/foaf/0.1/") s <- var o <- var let foafKnows = foaf .:. "knows" triple_ s (foafKnows .//. inv foafKnows) o selectVars [s, o] ) , ( [s| PREFIX foaf: SELECT ?x0 ?x1 WHERE { ?x0 ((foaf:knows+)/foaf:name) ?x1 . } |] , createQuery $ do foaf <- prefix "foaf" (iriRef "http://xmlns.com/foaf/0.1/") s <- var o <- var let foafKnows = foaf .:. "knows" let foafName = foaf .:. "name" triple_ s ((foafKnows +.) .//. foafName) o selectVars [s, o] ) , ( [s| PREFIX ex: SELECT ?x0 ?x1 WHERE { ?x0 ((ex:motherOf|ex:fatherOf)+) ?x1 . } |] , createQuery $ do ex <- prefix "ex" (iriRef "http://example.com/") s <- var o <- var let exMotherOf = ex .:. "motherOf" let exFatherOf = ex .:. "fatherOf" triple_ s ((exMotherOf .|. exFatherOf) +.) o selectVars [s, o] ) , ( [s| PREFIX ex: SELECT ?x0 ?x1 WHERE { ?x0 ((ex:motherOf|ex:fatherOf)+) ?x1 . } |] , createQuery $ do ex <- prefix "ex" (iriRef "http://example.com/") s <- var o <- var let exMotherOf = ex .:. "motherOf" let exFatherOf = ex .:. "fatherOf" triple_ s ((exMotherOf .|. exFatherOf) +.) o selectVars [s, o] ) , ( [s| PREFIX rdf: PREFIX rdfs: SELECT ?x0 ?x1 WHERE { ?x0 (rdf:type/(rdfs:subClassOf*)) ?x1 . } |] , createQuery $ do rdf <- prefix "rdf" (iriRef "http://www.w3.org/1999/02/22-rdf-syntax-ns#") rdfs <- prefix "rdfs" (iriRef "http://www.w3.org/2000/01/rdf-schema#") s <- var o <- var let rdfType = rdf .:. "type" let rdfsSubClassOf = rdfs .:. "subClassOf" triple_ s (rdfType .//. (rdfsSubClassOf *.)) o selectVars [s, o] ) , ( [s| PREFIX rdfs: SELECT ?x0 ?x1 WHERE { ?x0 (a/(rdfs:subClassOf*)) ?x1 . } |] , createQuery $ do rdfs <- prefix "rdfs" (iriRef "http://www.w3.org/2000/01/rdf-schema#") s <- var o <- var let rdfsSubClassOf = rdfs .:. "subClassOf" triple_ s (a .//. (rdfsSubClassOf *.)) o selectVars [s, o] ) , ( [s| PREFIX rdfs: SELECT ?x0 ?x1 WHERE { ?x0 (a/(rdfs:subClassOf?)) ?x1 . } |] , createQuery $ do rdfs <- prefix "rdfs" (iriRef "http://www.w3.org/2000/01/rdf-schema#") s <- var o <- var let rdfsSubClassOf = rdfs .:. "subClassOf" triple_ s (a .//. (rdfsSubClassOf ?.)) o selectVars [s, o] ) , ( [s| PREFIX rdf: PREFIX rdfs: SELECT ?x0 ?x1 WHERE { ?x0 !(rdf:type|rdfs:subClassOf|a) ?x1 . } |] , createQuery $ do rdf <- prefix "rdf" (iriRef "http://www.w3.org/1999/02/22-rdf-syntax-ns#") rdfs <- prefix "rdfs" (iriRef "http://www.w3.org/2000/01/rdf-schema#") s <- var o <- var let rdfType = rdf .:. "type" let rdfsSubClassOf = rdfs .:. "subClassOf" triple_ s (neg $ rdfType ..|.. rdfsSubClassOf ..|.. a) o selectVars [s, o] ) , ( [s| PREFIX rdf: SELECT ?x0 ?x1 WHERE { ?x0 !(rdf:type|^rdf:type) ?x1 . } |] , createQuery $ do rdf <- prefix "rdf" (iriRef "http://www.w3.org/1999/02/22-rdf-syntax-ns#") s <- var o <- var let rdfType = rdf .:. "type" triple_ s (neg $ rdfType ..|.. inv' rdfType) o selectVars [s, o] ) ] testSuite :: [Test.Framework.Test] testSuite = [ testGroup "Database.HSparql.QueryGenerator tests" $ (`map` queryTexts) $ \(expected, actual) -> testCase (T.unpack expected) $ do assertEqual "" (normalizeWhitespace expected) (normalizeWhitespace actual) ]