aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala8
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala2
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/implicits/JavaCollections.scala1
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/sparql/ConjunctiveQuery.scala124
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/sparql/ConjunctiveQueryAnswers.scala29
-rw-r--r--src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxHelpers.scala15
-rw-r--r--src/test/scala/uk/ac/ox/cs/rsacomb/FilteringProgramSpecs.scala85
-rw-r--r--src/test/scala/uk/ac/ox/cs/rsacomb/sparql/ConjunctiveQueryAnswerSpecs.scala62
-rw-r--r--src/test/scala/uk/ac/ox/cs/rsacomb/sparql/ConjunctiveQuerySpec.scala235
9 files changed, 466 insertions, 95 deletions
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala
index a8107b5..28196be 100644
--- a/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala
@@ -113,7 +113,7 @@ object RSAComb extends App {
113 ontology.individuals.foreach(println) 113 ontology.individuals.foreach(println)
114 114
115 println("\nThings:") 115 println("\nThings:")
116 val things = RDFoxHelpers.submitSelectQuery( 116 val things = RDFoxHelpers.submitQuery(
117 data, 117 data,
118 """ 118 """
119 PREFIX owl: <http://www.w3.org/2002/07/owl#> 119 PREFIX owl: <http://www.w3.org/2002/07/owl#>
@@ -126,7 +126,7 @@ object RSAComb extends App {
126 println(things) 126 println(things)
127 127
128 println("\nNAMEDs:") 128 println("\nNAMEDs:")
129 val named = RDFoxHelpers.submitSelectQuery( 129 val named = RDFoxHelpers.submitQuery(
130 data, 130 data,
131 """ 131 """
132 SELECT ?X { 132 SELECT ?X {
@@ -138,7 +138,7 @@ object RSAComb extends App {
138 println(named) 138 println(named)
139 139
140 println("\nNIs:") 140 println("\nNIs:")
141 val nis = RDFoxHelpers.submitSelectQuery( 141 val nis = RDFoxHelpers.submitQuery(
142 data, 142 data,
143 """ 143 """
144 SELECT ?X { 144 SELECT ?X {
@@ -159,7 +159,7 @@ object RSAComb extends App {
159 println(ids) 159 println(ids)
160 160
161 println("\nCongruent:") 161 println("\nCongruent:")
162 val equivs = RDFoxHelpers.submitSelectQuery( 162 val equivs = RDFoxHelpers.submitQuery(
163 data, 163 data,
164 """ 164 """
165 SELECT ?X ?Y { 165 SELECT ?X ?Y {
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala
index 93fd5cd..c4d4184 100644
--- a/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/RSAOntology.scala
@@ -254,7 +254,7 @@ class RSAOntology(val ontology: OWLOntology) extends RSAAxiom {
254 data: DataStoreConnection 254 data: DataStoreConnection
255 ): Graph[Resource, UnDiEdge] = { 255 ): Graph[Resource, UnDiEdge] = {
256 val query = "SELECT ?X ?Y WHERE { ?X rsa:E ?Y }" 256 val query = "SELECT ?X ?Y WHERE { ?X rsa:E ?Y }"
257 val answers = RDFoxHelpers.submitSelectQuery(data, query, RSA.Prefixes) 257 val answers = RDFoxHelpers.submitQuery(data, query, RSA.Prefixes).get
258 var edges: List[UnDiEdge[Resource]] = answers.map { 258 var edges: List[UnDiEdge[Resource]] = answers.map {
259 case n1 :: n2 :: _ => UnDiEdge(n1, n2) 259 case n1 :: n2 :: _ => UnDiEdge(n1, n2)
260 } 260 }
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/JavaCollections.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/JavaCollections.scala
index 3b621f4..9d205b5 100644
--- a/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/JavaCollections.scala
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/implicits/JavaCollections.scala
@@ -9,5 +9,4 @@ object JavaCollections {
9 9
10 implicit def scalaToJavaList[A](list: List[A]): java.util.List[A] = 10 implicit def scalaToJavaList[A](list: List[A]): java.util.List[A] =
11 list.asJava 11 list.asJava
12
13} 12}
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/sparql/ConjunctiveQuery.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/sparql/ConjunctiveQuery.scala
new file mode 100644
index 0000000..b523938
--- /dev/null
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/sparql/ConjunctiveQuery.scala
@@ -0,0 +1,124 @@
1package uk.ac.ox.cs.rsacomb.sparql
2
3import java.util.{Map => JMap, HashMap => JHashMap}
4import tech.oxfordsemantic.jrdfox.Prefixes
5import tech.oxfordsemantic.jrdfox.client.DataStoreConnection
6import tech.oxfordsemantic.jrdfox.logic.expression.Variable
7import tech.oxfordsemantic.jrdfox.logic.sparql.pattern.{
8 ConjunctionPattern,
9 QueryPattern,
10 TriplePattern
11}
12import tech.oxfordsemantic.jrdfox.logic.sparql.statement.SelectQuery
13import uk.ac.ox.cs.rsacomb.util.RDFoxHelpers
14
15/** Factory for [[uk.ac.ox.cs.rsacomb.sparql.ConjunctiveQuery]]. */
16object ConjunctiveQuery {
17
18 /** Creates a new ConjunctiveQuery instance.
19 *
20 * @param query `SelectQuery` instance representing the actual query
21 */
22 def apply(query: SelectQuery): ConjunctiveQuery =
23 new ConjunctiveQuery(query)
24
25 /** Creates a new ConjunctiveQuery from a query string
26 *
27 * @param query a string representing the query in SPARQL format
28 * @param prefixes additional prefixes used in the query. Defaults to
29 * an empty set of prefixes.
30 * @return an [[scala.Option]] containing a ConjunctiveQuery if the
31 * input query represents one, None is returned otherwise.
32 */
33 def apply(
34 query: String,
35 prefixes: Prefixes = new Prefixes()
36 ): Option[ConjunctiveQuery] =
37 RDFoxHelpers.parseSelectQuery(query, prefixes).map(ConjunctiveQuery(_))
38
39}
40
41/** A conjunctive query
42 *
43 * A thin layer around
44 * [[tech.oxfordsemantics.jrdfox.logic.sparql.statement.SelectQuery]].
45 *
46 * Instances should be created using the companion object.
47 *
48 * @todo additional checks need to be performed in order for a
49 * `SelectQuery` to be considered a conjunctive query.
50 */
51class ConjunctiveQuery(
52 query: SelectQuery,
53 val prefixes: Prefixes = new Prefixes()
54) {
55
56 import uk.ac.ox.cs.rsacomb.implicits.JavaCollections._
57
58 /** SELECT section of the SPARQL query.
59 *
60 * Simply exposes the underlying `getSelection` method in
61 * [[tech.oxfordsemantics.jrdfox.logic.sparql.statement.SelectQuery]].
62 */
63 val select = query.getSelection
64
65 /** WHERE section of the SPARQL query.
66 *
67 * Simply exposes the underlying `getWherePattern` method in
68 * [[tech.oxfordsemantics.jrdfox.logic.sparql.statement.QueryBody]].
69 */
70 val where = query.getQueryBody.getWherePattern
71
72 /** Returns true if it is a boolean CQ.
73 *
74 * @note checking for `select` being empty is not enough. When a
75 * query selects '''all''' variables with `*`, `select` is empty as
76 * well.
77 */
78 val boolean: Boolean = select.isEmpty && !query.getAllPossibleVariables
79
80 /** Returns the full set of variables involved in the query. */
81 val variables: Set[Variable] =
82 where match {
83 case b: ConjunctionPattern => {
84 b.getConjuncts.toSet.flatMap { conj: QueryPattern =>
85 conj match {
86 case c: TriplePattern =>
87 Set(c.getSubject, c.getPredicate, c.getObject).collect {
88 case v: Variable => v
89 }
90 case _ => Set()
91 }
92 }
93 }
94 case _ => Set()
95 }
96
97 /** Returns the collection of answer variables in the query. */
98 val answer: Set[Variable] =
99 if (query.getAllPossibleVariables)
100 variables
101 else
102 select.map(_.getVariable).toSet
103
104 /** Returns the collection of bounded (existential) variables in the query. */
105 val bounded: Set[Variable] = variables &~ answer
106
107 /** Returns the answers to a query
108 *
109 * @param data data store against which the query is executed
110 * @param opts additional options passed to RDFox
111 * @return a new [[ConjunctiveQueryAnswers]] instance containing the
112 * collection of answers.
113 */
114 def answers(
115 data: DataStoreConnection,
116 opts: JMap[String, String] = new JHashMap[String, String]()
117 ): ConjunctiveQueryAnswers =
118 new ConjunctiveQueryAnswers(
119 boolean,
120 RDFoxHelpers.submitSelectQuery(data, query, opts)
121 )
122
123 override def toString(): String = query.toString
124}
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/sparql/ConjunctiveQueryAnswers.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/sparql/ConjunctiveQueryAnswers.scala
new file mode 100644
index 0000000..223e121
--- /dev/null
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/sparql/ConjunctiveQueryAnswers.scala
@@ -0,0 +1,29 @@
1package uk.ac.ox.cs.rsacomb.sparql
2
3import tech.oxfordsemantic.jrdfox.logic.expression.Resource
4
5/** A collections of answers to a query
6 *
7 * Will take the query type (CQ or BCQ) into consideration when
8 * serialised.
9 *
10 * @param boolean whether the answers are to a BCQ
11 * @param answers collection of answers to a query. When dealing with
12 * BCQs, and empty collection represents a ''false'',
13 * ''true'' otherwise.
14 */
15class ConjunctiveQueryAnswers(
16 boolean: Boolean,
17 val answers: Seq[Seq[Resource]]
18) {
19
20 override def toString(): String =
21 if (boolean) {
22 if (answers.isEmpty) "FALSE" else "TRUE"
23 } else {
24 if (answers.isEmpty)
25 "NO ANSWER"
26 else
27 answers.map(_.mkString("(", ", ", ")")).mkString("\n")
28 }
29}
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxHelpers.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxHelpers.scala
index fd9e1c5..5b85436 100644
--- a/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxHelpers.scala
+++ b/src/main/scala/uk/ac/ox/cs/rsacomb/util/RDFoxHelpers.scala
@@ -54,11 +54,10 @@ object RDFoxHelpers {
54 54
55 def submitSelectQuery( 55 def submitSelectQuery(
56 data: DataStoreConnection, 56 data: DataStoreConnection,
57 query: String, 57 query: SelectQuery,
58 prefixes: Prefixes = new Prefixes(),
59 opts: JMap[String, String] = new JHashMap[String, String]() 58 opts: JMap[String, String] = new JHashMap[String, String]()
60 ): List[List[Resource]] = { 59 ): List[List[Resource]] = {
61 val cursor = data.createCursor(prefixes, query, opts) 60 val cursor = data.createCursor(query, opts)
62 var answers: List[List[Resource]] = List() 61 var answers: List[List[Resource]] = List()
63 var mul = cursor.open() 62 var mul = cursor.open()
64 while (mul > 0) { 63 while (mul > 0) {
@@ -71,6 +70,14 @@ object RDFoxHelpers {
71 answers 70 answers
72 } 71 }
73 72
73 def submitQuery(
74 data: DataStoreConnection,
75 query: String,
76 prefixes: Prefixes = new Prefixes(),
77 opts: JMap[String, String] = new JHashMap[String, String]()
78 ): Option[List[List[Resource]]] =
79 parseSelectQuery(query, prefixes).map(submitSelectQuery(data, _, opts))
80
74 def queryInternalPredicate( 81 def queryInternalPredicate(
75 data: DataStoreConnection, 82 data: DataStoreConnection,
76 pred: String, 83 pred: String,
@@ -86,7 +93,7 @@ object RDFoxHelpers {
86 query ++= s" ?S rsa:${pred :: Nth(i)} ?X$i ." 93 query ++= s" ?S rsa:${pred :: Nth(i)} ?X$i ."
87 } 94 }
88 query ++= " }" 95 query ++= " }"
89 submitSelectQuery(data, query, RSA.Prefixes, opts) 96 submitQuery(data, query, RSA.Prefixes, opts).get
90 } 97 }
91 98
92 def closeConnection( 99 def closeConnection(
diff --git a/src/test/scala/uk/ac/ox/cs/rsacomb/FilteringProgramSpecs.scala b/src/test/scala/uk/ac/ox/cs/rsacomb/FilteringProgramSpecs.scala
index 49abd48..e9a20db 100644
--- a/src/test/scala/uk/ac/ox/cs/rsacomb/FilteringProgramSpecs.scala
+++ b/src/test/scala/uk/ac/ox/cs/rsacomb/FilteringProgramSpecs.scala
@@ -310,89 +310,4 @@ class FilteringProgramSpec
310 310
311 import FilteringProgramSpec._ 311 import FilteringProgramSpec._
312 312
313 "Queries" should "have distinct answer and bounded variables" in {
314 for (query <- queries) {
315 val program = new FilteringProgram(query, List())
316 forAll(program.answer) { v => program.bounded should not contain v }
317 forAll(program.bounded) { v => program.answer should not contain v }
318 }
319 }
320
321 "Query 0" should "have {?obj, ?pred} as bounded variables" in {
322 val pred = Variable.create("obj")
323 val obj = Variable.create("pred")
324 val program = new FilteringProgram(query0, List())
325 program.bounded should contain theSameElementsAs List(pred, obj)
326 }
327
328 "Query 1" should "have no bounded variable" in {
329 val program = new FilteringProgram(query1, List())
330 program.bounded shouldBe empty
331 }
332
333 "Query 2" should "have no bounded variable" in {
334 val program = new FilteringProgram(query2, List())
335 program.bounded shouldBe empty
336 }
337
338 "Query 3" should "have {?w, ?fp} as bounded variables" in {
339 val w = Variable.create("w")
340 val fp = Variable.create("fp")
341 val program = new FilteringProgram(query3, List())
342 program.bounded should contain theSameElementsAs List(w, fp)
343 }
344
345 "Query 4" should "have no bounded variable" in {
346 val program = new FilteringProgram(query4, List())
347 program.bounded shouldBe empty
348 }
349
350 "Query 5" should "have a non-empty bounded set" in {
351 val w = Variable.create("w")
352 val c_int = Variable.create("c_int")
353 val f_int = Variable.create("f_int")
354 val c_unit = Variable.create("c_unit")
355 val program = new FilteringProgram(query5, List())
356 program.bounded should contain theSameElementsAs List(
357 w,
358 c_int,
359 f_int,
360 c_unit
361 )
362 }
363
364 "Query 6" should "have a non-empty bounded set" in {
365 val w = Variable.create("w")
366 val int = Variable.create("int")
367 val program = new FilteringProgram(query6, List())
368 program.bounded should contain theSameElementsAs List(w, int)
369 }
370
371 "Query 7" should "have a non-empty bounded set" in {
372 val w = Variable.create("w")
373 val z = Variable.create("z")
374 val u = Variable.create("u")
375 val strat_unit_name = Variable.create("strat_unit_name")
376 val wellbore = Variable.create("wellbore")
377 val cored_int = Variable.create("cored_int")
378 val c = Variable.create("c")
379 val sample_depth = Variable.create("sample_depth")
380 val p = Variable.create("p")
381 val top = Variable.create("top")
382 val bot = Variable.create("bot")
383 val program = new FilteringProgram(query7, List())
384 program.bounded should contain theSameElementsAs List(
385 w,
386 z,
387 u,
388 strat_unit_name,
389 wellbore,
390 cored_int,
391 c,
392 sample_depth,
393 p,
394 top,
395 bot
396 )
397 }
398} 313}
diff --git a/src/test/scala/uk/ac/ox/cs/rsacomb/sparql/ConjunctiveQueryAnswerSpecs.scala b/src/test/scala/uk/ac/ox/cs/rsacomb/sparql/ConjunctiveQueryAnswerSpecs.scala
new file mode 100644
index 0000000..65c3e29
--- /dev/null
+++ b/src/test/scala/uk/ac/ox/cs/rsacomb/sparql/ConjunctiveQueryAnswerSpecs.scala
@@ -0,0 +1,62 @@
1package uk.ac.ox.cs.rsacomb.sparql
2
3import org.scalatest.flatspec.AnyFlatSpec
4import org.scalatest.matchers.should.Matchers
5import tech.oxfordsemantic.jrdfox.logic.expression.IRI
6
7object ConjunctiveQueryAnswerSpec {
8
9 val iri1 = IRI.create("_:iri1")
10 val iri2 = IRI.create("_:iri2")
11 val iri3 = IRI.create("_:iri3")
12
13 val oneAnswer = new ConjunctiveQueryAnswers(false, Seq(Seq(iri1, iri2, iri3)))
14 val multipleAnswers =
15 new ConjunctiveQueryAnswers(
16 false,
17 Seq(Seq(iri1, iri1), Seq(iri1, iri2), Seq(iri1, iri3))
18 )
19 val noAnswer = new ConjunctiveQueryAnswers(false, Seq())
20 val emptyAnswer = new ConjunctiveQueryAnswers(false, Seq(Seq()))
21
22 val falseAnswer = new ConjunctiveQueryAnswers(true, Seq())
23 val trueAnswer1 = new ConjunctiveQueryAnswers(true, Seq(Seq()))
24 val trueAnswer2 =
25 new ConjunctiveQueryAnswers(
26 true,
27 Seq(Seq(iri1, iri1), Seq(iri1, iri2), Seq(iri1, iri3))
28 )
29}
30
31class ConjunctiveQueryAnswerSpec extends AnyFlatSpec with Matchers {
32
33 import ConjunctiveQueryAnswerSpec._
34
35 "A conjunctive query" should "print a single line if it has a single answer" in {
36 oneAnswer.toString shouldBe s"($iri1, $iri2, $iri3)"
37 }
38
39 it should "print multiple answers on multiple lines" in {
40 multipleAnswers.toString shouldBe s"($iri1, $iri1)\n($iri1, $iri2)\n($iri1, $iri3)"
41 }
42
43 it should "print a special \"NO ANSWER\" string when it has no answer" in {
44 noAnswer.toString shouldBe "NO ANSWER"
45 }
46
47 it should "print an empty list when it has an empty answer" in {
48 emptyAnswer.toString shouldBe "()"
49 }
50
51 "A boolean conjunctive query" should "print \"FALSE\" when it has no answer" in {
52 falseAnswer.toString shouldBe "FALSE"
53 }
54
55 it should "print \"TRUE\" when it has a single empty answer" in {
56 trueAnswer1.toString shouldBe "TRUE"
57 }
58
59 it should "print \"TRUE\" when it has a non-empty collection of answers" in {
60 trueAnswer2.toString shouldBe "TRUE"
61 }
62}
diff --git a/src/test/scala/uk/ac/ox/cs/rsacomb/sparql/ConjunctiveQuerySpec.scala b/src/test/scala/uk/ac/ox/cs/rsacomb/sparql/ConjunctiveQuerySpec.scala
new file mode 100644
index 0000000..e683d36
--- /dev/null
+++ b/src/test/scala/uk/ac/ox/cs/rsacomb/sparql/ConjunctiveQuerySpec.scala
@@ -0,0 +1,235 @@
1package uk.ac.ox.cs.rsacomb.sparql
2
3import org.scalatest.{Inspectors, OptionValues}
4import org.scalatest.flatspec.AnyFlatSpec
5import org.scalatest.matchers.should.Matchers
6import tech.oxfordsemantic.jrdfox.logic.expression.Variable
7
8object ConjunctiveQuerySpec {
9
10 val cq0 = """
11 PREFIX : <http://example.com/rsa_example.owl#>
12
13 SELECT ?X
14 WHERE {
15 ?X a :D ;
16 :R ?Y .
17 ?Y :S ?Z .
18 ?Z a :D .
19 }
20 """
21
22 val cq1 = """
23 PREFIX : <http://example.com/rsa_example.owl#>
24
25 SELECT *
26 WHERE {
27 ?X a :D ;
28 :R ?Y .
29 ?Y :S ?Z .
30 ?Z a :D .
31 }
32 """
33
34 val cq2 = """
35 PREFIX : <http://slegger.gitlab.io/slegge-obda/ontology/subsurface-exploration#>
36 SELECT *
37 WHERE {
38 ?w a :Wellbore ;
39 :wellboreDocument ?doc .
40 ?doc :hasURL ?document_hyperlink
41 }
42 """
43
44 val cq3 = """
45 PREFIX : <http://slegger.gitlab.io/slegge-obda/ontology/subsurface-exploration#>
46 SELECT ?wellbore ?formation_pressure
47 WHERE {
48 ?w a :Wellbore ;
49 :name ?wellbore ;
50 :hasFormationPressure ?fp .
51 ?fp :valueInStandardUnit ?formation_pressure
52 }
53 """
54
55 val cq4 = """
56 PREFIX : <http://slegger.gitlab.io/slegge-obda/ontology/subsurface-exploration#>
57 SELECT *
58 WHERE {
59 ?w a :Wellbore ;
60 :hasGeochemicalMeasurement ?measurement .
61 ?measurement :cgType ?cgtype ;
62 :peakName ?peakType ;
63 :peakHeight ?peak_height ;
64 :peakAmount ?peak_amount
65 }
66 """
67
68 val cq5 = """
69 PREFIX : <http://slegger.gitlab.io/slegge-obda/ontology/subsurface-exploration#>
70 SELECT ?wellbore ?unit_name ?discovery
71 WHERE {
72 ?w a :Wellbore ;
73 :name ?wellbore ;
74 :hasWellboreInterval ?c_int ;
75 :hasWellboreInterval ?f_int .
76 ?c_int :hasUnit ?c_unit .
77 ?c_unit :name ?unit_name .
78 ?f_int a :FluidZone ;
79 :name ?discovery ;
80 :overlapsWellboreInterval ?c_int
81 }
82 """
83
84 val cq6 = """
85 PREFIX : <http://slegger.gitlab.io/slegge-obda/ontology/subsurface-exploration#>
86 SELECT DISTINCT ?wellbore ?content
87 WHERE {
88 ?w a :Wellbore ;
89 :name ?wellbore ;
90 :hasWellboreInterval ?int .
91 ?int a :FluidZone ;
92 :fluidZoneContent ?content
93 }
94 """
95
96 val cq7 = """
97 PREFIX : <http://slegger.gitlab.io/slegge-obda/ontology/subsurface-exploration#>
98 SELECT ?wName ?sample ?porosity ?top_depth_md ?bot_depth_md
99 WHERE {
100 ?w a :Wellbore ;
101 :name ?wName ;
102 :hasWellboreInterval ?z .
103 ?z :hasUnit ?u .
104 ?u :name ?strat_unit_name .
105 ?wellbore :hasWellboreInterval ?cored_int .
106 ?c :extractedFrom ?cored_int ;
107 :hasCoreSample ?sample .
108 ?sample :hasDepth ?sample_depth .
109 ?sample_depth
110 :inWellboreInterval ?z .
111 ?sample :hasPorosity ?p .
112 ?p :valueInStandardUnit ?porosity .
113 ?z :hasTopDepth ?top .
114 ?top a :MeasuredDepth ;
115 :valueInStandardUnit ?top_depth_md .
116 ?z :hasBottomDepth ?bot .
117 ?bot a :MeasuredDepth ;
118 :valueInStandardUnit ?bot_depth_md
119 }
120 """
121
122 val bcq0 = """
123 PREFIX : <http://example.com/scrubs/casting/>
124 ASK {
125 :turk a :Doctor ;
126 :married ?X .
127 ?X a :Nurse .
128 }
129 """
130
131 val queries =
132 List(cq0, cq1, cq2, cq3, cq4, cq5, cq6, cq7, bcq0)
133
134}
135
136class ConjunctiveQuerySpec
137 extends AnyFlatSpec
138 with Matchers
139 with Inspectors
140 with OptionValues {
141
142 import ConjunctiveQuerySpec._
143
144 "A conjunctive query" should "result in a `ConjunctiveQuery` instance" in {
145 ConjunctiveQuery(cq0) shouldBe defined
146 }
147
148 "A boolean conjunctive query" should "result in a `ConjunctiveQuery` instance" in {
149 ConjunctiveQuery(bcq0) shouldBe defined
150 }
151
152 "A query with proper SELECT defined" should "not be a BCQ" in {
153 ConjunctiveQuery(cq0).value should not be 'boolean
154 }
155
156 "A query with a \"*\" SELECT" should "not be a BCQ" in {
157 ConjunctiveQuery(cq1).value should not be 'boolean
158 }
159
160 "An ASK query" should "not be a BCQ" in {
161 ConjunctiveQuery(bcq0).value shouldBe 'boolean
162 }
163
164 "Queries" should "have distinct answer and bounded variables" in {
165 for (q <- queries) {
166 val cq = ConjunctiveQuery(q)
167 forAll(cq.value.answer) { v => cq.value.bounded should not contain v }
168 forAll(cq.value.bounded) { v => cq.value.answer should not contain v }
169 }
170 }
171
172 "CQ0" should "have {?obj, ?pred} as bounded variables" in {
173 ConjunctiveQuery(cq0).value.bounded should contain theSameElementsAs
174 List(
175 Variable.create("Y"),
176 Variable.create("Z")
177 )
178 }
179
180 "CQ1" should "have no bounded variable" in {
181 ConjunctiveQuery(cq1).value.bounded shouldBe empty
182 }
183
184 "CQ2" should "have no bounded variable" in {
185 ConjunctiveQuery(cq2).value.bounded shouldBe empty
186 }
187
188 "CQ3" should "have {?w, ?fp} as bounded variables" in {
189 ConjunctiveQuery(cq3).value.bounded should contain theSameElementsAs
190 List(
191 Variable.create("w"),
192 Variable.create("fp")
193 )
194 }
195
196 "CQ4" should "have no bounded variable" in {
197 ConjunctiveQuery(cq4).value.bounded shouldBe empty
198 }
199
200 "CQ5" should "have a non-empty bounded set" in {
201 ConjunctiveQuery(cq5).value.bounded should contain theSameElementsAs
202 List(
203 Variable.create("w"),
204 Variable.create("c_int"),
205 Variable.create("f_int"),
206 Variable.create("c_unit")
207 )
208 }
209
210 "CQ6" should "have a non-empty bounded set" in {
211 ConjunctiveQuery(cq6).value.bounded should contain theSameElementsAs
212 List(
213 Variable.create("w"),
214 Variable.create("int")
215 )
216 }
217
218 "CQ7" should "have a non-empty bounded set" in {
219 ConjunctiveQuery(cq7).value.bounded should contain theSameElementsAs
220 List(
221 Variable.create("w"),
222 Variable.create("z"),
223 Variable.create("u"),
224 Variable.create("strat_unit_name"),
225 Variable.create("wellbore"),
226 Variable.create("cored_int"),
227 Variable.create("c"),
228 Variable.create("sample_depth"),
229 Variable.create("p"),
230 Variable.create("top"),
231 Variable.create("bot")
232 )
233 }
234
235}