--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/SparqlToSparqlToSql.scala Sun Feb 28 11:40:20 2010 -0500
@@ -0,0 +1,56 @@
+/* SparqlToSparqlToSql: convert SPARQL queries to sound SQL queries.
+ * $Id$
+ */
+
+package w3c.sw.sparql2sparql2sql
+
+import w3c.sw.sql
+import w3c.sw.sparql
+import w3c.sw.sparql2sparql
+import w3c.sw.sparql2sql
+
+object SparqlToSparqlToSql {
+
+ def toView (rules:List[sparql.Construct], schema:sql.DatabaseDesc, stemUri:sparql2sql.StemURI) = {
+
+ /* For each rule... */
+ val disjoints = rules.foldLeft(List[sql.Select]())((allgps, rule) => {
+
+ /* ... turn each triple pattern in the rule heads into a SQL pattern. */
+ rule.head.triplepatterns.foldLeft(allgps)((gps, triple) => {
+
+ /* Substituted SPARQL ?S and ?O into the triple pattern. */
+ val s = sparql.Var("S");
+ val o = sparql.Var("O")
+ val select = sparql.Select(
+ sparql.SparqlAttributeList(List(s, o)),
+ sparql.TriplesBlock(
+ List(sparql.TriplePattern(sparql.TermVar(s), triple.p, sparql.TermVar(o)))))
+
+ /* Convert to equivalent SQL SELECT. */
+ val asStem = sparql2sparql.SparqlToSparql(select, List(rule))
+ val sql.Select(sql.AttributeList(attributes), tablelist, expression) = sparql2sql.SparqlToSql(schema, asStem, stemUri, false, true)
+
+ /* Add constant for predicate into selects. */
+ val p = triple.p match {
+ case sparql.TermUri(u) => sql.NamedAttribute(sql.PrimaryExpressionTyped(sql.Datatype.STRING,sql.Name("<" + u.s + ">")),
+ sql.AttrAlias(sql.Name("P")))
+ case sparql.TermVar(v) => error("triplification algorithm doesn't handly variable predicate in " + triple)
+ case sparql.TermLit(_) => error("illegal literal in predicate position of " + triple)
+ }
+
+ /* Add resulting SELECT to list of graph patterns. */
+ gps :+ sql.Select(sql.AttributeList(attributes + p), tablelist, expression)
+ })
+ })
+
+ /* Create a view from the disjoints.*/
+ val body:sql.SelectORUnion = disjoints.size match {
+ case 0 => error("not sure why you want a view with no rows...")
+ case 1 => disjoints.toList(0)
+ case _ => sql.Union(disjoints.toSet)
+ }
+ sql.View(sql.Relation(sql.Name("triples")), body)
+ }
+}
+
--- a/src/test/scala/SparqlToSparqlToSqlTest.scala Sun Feb 28 11:38:44 2010 -0500
+++ b/src/test/scala/SparqlToSparqlToSqlTest.scala Sun Feb 28 11:40:20 2010 -0500
@@ -10,6 +10,7 @@
import w3c.sw.sparql2sparql.{SparqlToSparql}
import w3c.sw.sql.{Sql,DatabaseDesc,Relation,RelationDesc,Attribute,Value,Datatype,ForeignKey,Name}
import w3c.sw.sparql2sql.{SparqlToSql,StemURI}
+import w3c.sw.sparql2sparql2sql.SparqlToSparqlToSql.toView
/* The SparqlToSparqlTest class transforms SPARQL queries to a relational data
* structure and compares them to a structure parsed from SQL.
@@ -19,7 +20,7 @@
val DDLParser = Sql()
val dbDdl = """
-CREATE TABLE Employee (empid INT, PRIMARY KEY (empid), lastName STRING, birthday DATE, manager INT, FOREIGN KEY (manager) REFERENCES Employee(empid));
+CREATE TABLE Employee (empid INT, PRIMARY KEY (empid), firstName STRING, lastName STRING, birthday DATE, manager INT, FOREIGN KEY (manager) REFERENCES Employee(empid));
CREATE TABLE Tasks (taskid INT, PRIMARY KEY (taskid), name STRING, lead INT, FOREIGN KEY (lead) REFERENCES Employee(empid));
CREATE TABLE TaskAssignments (id INT PRIMARY KEY, PRIMARY KEY (id), task INT, FOREIGN KEY (task) REFERENCES Tasks(taskid), employee INT, FOREIGN KEY (employee) REFERENCES Employee(empid));
"""
@@ -65,6 +66,33 @@
"""
}
+ test("foaf2HR as view") {
+ val sparqlParser = Sparql()
+ val hr2foaf = sparqlParser.parseAll(sparqlParser.construct, """
+PREFIX foaf : <http://xmlns.com/foaf/0.1/>
+PREFIX empP : <http://hr.example/DB/Employee#>
+CONSTRUCT { ?who foaf:first_name ?fname .
+ ?who foaf:last_name ?lname }
+ WHERE { ?who empP:firstName ?fname .
+ ?who empP:lastName ?lname }
+""").get
+ val view = toView(List(hr2foaf), HR, StemURI("http://hr.example/DB/"))
+ val sqlParser = Sql()
+ val expected = sqlParser.parseAll(sqlParser.createview, """
+CREATE VIEW triples AS
+ SELECT CONCAT("'", R_S.firstName, "'^^<http://www.w3.org/2001/XMLSchema#string>") AS O, "<http://xmlns.com/foaf/0.1/first_name>" AS P, CONCAT("http://hr.example/DB/", "Employee", "/", "empid", ".", R_S.empid, "#record") AS S
+ FROM Employee AS R_S
+ WHERE (R_S.empid IS NOT NULL)
+ AND (R_S.firstName IS NOT NULL)
+UNION
+ SELECT CONCAT("'", R_S.lastName, "'^^<http://www.w3.org/2001/XMLSchema#string>") AS O, "<http://xmlns.com/foaf/0.1/last_name>" AS P, CONCAT("http://hr.example/DB/", "Employee", "/", "empid", ".", R_S.empid, "#record") AS S
+ FROM Employee AS R_S
+ WHERE (R_S.empid IS NOT NULL)
+ AND (R_S.lastName IS NOT NULL)
+""").get
+ assert(expected === view)
+ }
+
/* ========== DiabeticPatient database tests ==========
*
*/
@@ -77,28 +105,8 @@
CREATE TABLE NDCcodes (ID INT PRIMARY KEY, NDC INT, ingredient INT);
"""
val hosp1:DatabaseDesc = DDLParser.parseAll(DDLParser.ddl, hosp1Ddl).get
-
- test("~/swobjects/tests/healthCare/lists-notBound/hl7.rq short") {
- val sparqlParser = Sparql()
- val hl7Query = sparqlParser.parseAll(sparqlParser.select, """
-PREFIX hl7: <http://www.hl7.org/v3ballot/xml/infrastructure/vocabulary/vocabulary#>
-SELECT ?patient ?dob ?sex
-WHERE
-{
- ?patient a hl7:Person .
- ?patient hl7:entityName ?middleName .
- ?patient hl7:livingSubjectBirthTime ?dob .
- ?patient hl7:administrativeGenderCodePrintName ?sex .
- ?patient hl7:substanceAdministration ?subs_admin .
- ?subs_admin a hl7:SubstanceAdministration .
- ?subs_admin hl7:consumable ?consumable .
- ?consumable hl7:displayName ?takes .
- ?consumable hl7:activeIngredient ?ingredient .
- ?ingredient hl7:classCode 6809 .
- ?subs_admin hl7:effectiveTime ?indic_span .
-}""").get
-
- val db2hl7 = sparqlParser.parseAll(sparqlParser.construct, """
+ val ConstructParser = Sparql()
+ val db2hl7 = ConstructParser.parseAll(ConstructParser.construct, """
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX Person: <http://hospital.example/DB/Person#>
PREFIX Sex_DE: <http://hospital.example/DB/Sex_DE#>
@@ -140,6 +148,27 @@
?indicCode NDCcodes:NDC ?indicNDC .
?indicCode NDCcodes:ingredient ?ingredCode }
""").get
+
+ test("~/swobjects/tests/healthCare/lists-notBound/hl7.rq short") {
+ val sparqlParser = Sparql()
+ val hl7Query = sparqlParser.parseAll(sparqlParser.select, """
+PREFIX hl7: <http://www.hl7.org/v3ballot/xml/infrastructure/vocabulary/vocabulary#>
+SELECT ?patient ?dob ?sex
+WHERE
+{
+ ?patient a hl7:Person .
+ ?patient hl7:entityName ?middleName .
+ ?patient hl7:livingSubjectBirthTime ?dob .
+ ?patient hl7:administrativeGenderCodePrintName ?sex .
+ ?patient hl7:substanceAdministration ?subs_admin .
+ ?subs_admin a hl7:SubstanceAdministration .
+ ?subs_admin hl7:consumable ?consumable .
+ ?consumable hl7:displayName ?takes .
+ ?consumable hl7:activeIngredient ?ingredient .
+ ?ingredient hl7:classCode 6809 .
+ ?subs_admin hl7:effectiveTime ?indic_span .
+}""").get
+
val stemQuery = sparqlParser.parseAll(sparqlParser.select, """
PREFIX Person: <http://hospital.example/DB/Person#>
PREFIX Sex_DE: <http://hospital.example/DB/Sex_DE#>
@@ -219,48 +248,6 @@
}
}""").get
- val db2hl7 = sparqlParser.parseAll(sparqlParser.construct, """
-PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
-PREFIX Person: <http://hospital.example/DB/Person#>
-PREFIX Sex_DE: <http://hospital.example/DB/Sex_DE#>
-PREFIX Item_Medication: <http://hospital.example/DB/Item_Medication#>
-PREFIX Medication: <http://hospital.example/DB/Medication#>
-PREFIX Medication_DE: <http://hospital.example/DB/Medication_DE#>
-PREFIX NDCcodes: <http://hospital.example/DB/NDCcodes#>
-
-PREFIX hl7: <http://www.hl7.org/v3ballot/xml/infrastructure/vocabulary/vocabulary#>
-PREFIX spl: <http://www.hl7.org/v3ballot/xml/infrastructure/vocabulary/vocabulary#>
-
-CONSTRUCT {
-?person a hl7:Person .
-?person hl7:entityName ?middleName .
-?person hl7:livingSubjectBirthTime ?dob .
-?person hl7:administrativeGenderCodePrintName ?sex .
-?person hl7:substanceAdministration ?subst .
-?subst a hl7:SubstanceAdministration .
-?subst hl7:consumable ?cons .
-?cons hl7:displayName ?takes .
-?cons spl:activeIngredient ?ingred .
-?ingred spl:classCode ?ingredCode .
-?subst hl7:effectiveTime ?interval .
-?interval hl7:start ?indicDate
-} WHERE {
- ?person Person:MiddleName ?middleName .
- ?person Person:DateOfBirth ?dob .
- ?person Person:SexDE ?sexEntry .
-
- ?sexEntry Sex_DE:EntryName ?sex .
-
- ?indicItem Item_Medication:PatientID ?person .
- ?indicItem Item_Medication:PerformedDTTM ?indicDate .
- ?indicItem Item_Medication:EntryName ?takes .
- ?indicMed Medication:ItemID ?indicItem .
- ?indicMed Medication:DaysToTake ?indicDuration .
- ?indicMed Medication:MedDictDE ?indicDE .
- ?indicDE Medication_DE:NDC ?indicNDC .
- ?indicCode NDCcodes:NDC ?indicNDC .
- ?indicCode NDCcodes:ingredient ?ingredCode }
-""").get
val stemQuery = sparqlParser.parseAll(sparqlParser.select, """
PREFIX Person: <http://hospital.example/DB/Person#>
PREFIX Sex_DE: <http://hospital.example/DB/Sex_DE#>
@@ -339,4 +326,13 @@
"""
}
+// test("hospital as view") {
+// val sparqlParser = Sparql()
+// val view = toView(List(db2hl7), HR, StemURI("http://hospital.example/DB/"))
+// val sqlParser = Sql()
+// val expected = sqlParser.parseAll(sqlParser.createview, """
+// """).get
+// assert(expected === view)
+// }
+
}