~ SparqlToSql.apply returns (sqlstring, varmap)
authorEric Prud'hommeaux <eric@w3.org>
Sat, 12 Jun 2010 09:27:16 -0400
changeset 204 89e270df8e93
parent 203 d684b9cd3b0c
child 205 745da618b07c
~ SparqlToSql.apply returns (sqlstring, varmap)
+ SqlToXMLRes
src/main/scala/Servlet.scala
src/main/scala/SparqlToSparqlToSql.scala
src/main/scala/SparqlToSql.scala
src/test/scala/SparqlToSparqlToSqlTest.scala
src/test/scala/SparqlToSqlTest.scala
--- a/src/main/scala/Servlet.scala	Fri Jun 11 21:46:40 2010 -0400
+++ b/src/main/scala/Servlet.scala	Sat Jun 12 09:27:16 2010 -0400
@@ -107,7 +107,7 @@
 
     val sparqlSelect = sparqlParser.parseAll(sparqlParser.select, query).get
 
-    val generated:sql.Select = SparqlToSql(Config.db, sparqlSelect, stemURI, true, false)
+    val generated:sql.Select = SparqlToSql(Config.db, sparqlSelect, stemURI, true, false)._1
 
     Class.forName("com.mysql.jdbc.Driver").newInstance
     val connection:Connection = DriverManager.getConnection("jdbc:mysql://localhost/rdb2rdf", "root", "")
--- a/src/main/scala/SparqlToSparqlToSql.scala	Fri Jun 11 21:46:40 2010 -0400
+++ b/src/main/scala/SparqlToSparqlToSql.scala	Sat Jun 12 09:27:16 2010 -0400
@@ -48,7 +48,7 @@
 	val asStem = sparql2sparql.SparqlToSparql(select, List(rule))
 	// println("triple: "+triple)
 	// println("asStem: "+asStem)
-	val sql.Select(sql.AttributeList(attributes), tablelist, expression) = sparql2sql.SparqlToSql(schema, asStem, stemUri, false, true)
+	val sql.Select(sql.AttributeList(attributes), tablelist, expression) = sparql2sql.SparqlToSql(schema, asStem, stemUri, false, true)._1
 	// println("SQL: "+sql.Select(sql.AttributeList(attributes ++ sconsts ++ pconsts ++ oconsts), tablelist, expression))
 
 	/* Add resulting SELECT to list of graph patterns. */
--- a/src/main/scala/SparqlToSql.scala	Fri Jun 11 21:46:40 2010 -0400
+++ b/src/main/scala/SparqlToSql.scala	Sat Jun 12 09:27:16 2010 -0400
@@ -266,11 +266,11 @@
    * @return a new R2RState incorporating the new binding
    * For example, <code>SELECT ?emp WHERE { ?emp emp:lastName ?name }</code> will call varConstraint twice:
    * 
-   *    given: alias:=R_emp, optAttr:=lastName, v:=?name, rel:=Employee) -&gt;
+   *    given: alias:=R_emp, optAttr:=lastName, v:=?name, rel:=Employee -&gt;
    *   return: (VarAssignable(?name),StringMapper(FullBinding(R_emp.lastName)))
    *   which maps "Smith" to "Smith"^^xsd:string
    * 
-   *    given: alias:=R_emp, optAttr:=empid, v:=?emp, rel:=Employee) -&gt;
+   *    given: alias:=R_emp, optAttr:=empid, v:=?emp, rel:=Employee -&gt;
    *   return: (VarAssignable(?emp),RDFNoder(Employee,FullBinding(R_emp.empid)))
    *   which maps 4 to &lt;http://hr.example/our/favorite/DB/Employee/id.4#record&gt;
    */
@@ -993,7 +993,7 @@
    * @param concat  if true, keys will produce SQL functions to generate a URI, e.g. SELECT CONCAT(stemURI, table, "/", pk, ".", R_who.pk) AS who
    * @return an SQL query corresponding to sparquery
    */
-  def translate (db:sql.DatabaseDesc, sparquery:sparql.Select, stem:StemURI, enforceForeignKeys:Boolean, concat:Boolean) : (sql.Select, Map[sparql.Assignable, SQL2RDFValueMapper]) = {
+  def apply (db:sql.DatabaseDesc, sparquery:sparql.Select, stem:StemURI, enforceForeignKeys:Boolean, concat:Boolean) : (sql.Select, Map[sparql.Assignable, SQL2RDFValueMapper]) = {
     val sparql.Select(attrs, triples) = sparquery
 
     /** Create an object to hold our compilation state. */
@@ -1037,13 +1037,62 @@
 	case _ => Some(sql.ExprConjunction(r2rState.exprs))
       }
     )
-    (select, r2rState.varmap)
-  }
-
-  def apply (db:sql.DatabaseDesc, sparquery:sparql.Select, stem:StemURI, enforceForeignKeys:Boolean, concat:Boolean) : sql.Select = {
     // println("r2rState.varmap: " + r2rState.varmap)
     // println("select.expression: " + select.expression)
-    translate(db, sparquery, stem, enforceForeignKeys, concat)._1.makePretty() // eliminate foo.bar=foo.bar and stuff like that.
+    (select.makePretty, r2rState.varmap)
   }
 }
 
+/**
+ * Support functions to inject SparqlToSql results into an XML Results Set.
+ * @example:
+ * <pre>
+ * val xmlres:String = 
+ *   head(List[String]("emp", "name")) +
+ *   startresult +
+ *     binding("emp", "253", rdfmap, stem) +
+ *     binding("name", "Bob", rdfmap, stem) +
+ *   endresult +
+ *   foot
+ * </pre>
+ *
+ * @see {@link w3c.sw.sparql2sql.SparqlToSql}
+ * @see {@link http://www.w3.org/TR/2008/REC-rdf-sparql-XMLres-20080115/ XML Results Format}
+ */
+object SqlToXMLRes {
+  def head (vars:List[String]) : String = {
+    "<?xml version=\"1.0\"?>\n<sparql xmlns=\"http://www.w3.org/2005/sparql-results#\">\n  <head>\n" +
+    vars.map(varname => "    <variable name=\"" + varname + "\"/>\n").mkString + 
+    "  </head>\n\n  <results>\n"
+  }
+  def startresult () : String = {
+    "    <result> \n"
+  }
+  def binding (name:String, value:String, varmap:Map[sparql.Assignable, SparqlToSql.SQL2RDFValueMapper], stem:StemURI) : String = {
+    def getattr (b:SparqlToSql.FullOrPartialBinding) : sql.Attribute = {
+      b match {
+	case SparqlToSql.FullBinding(sql.RelVarAttr(_, attr)) =>
+	  attr
+	case SparqlToSql.PartialBinding(binders) => {
+	  val SparqlToSql.BindingConstraint(expr, sql.RelVarAttr(rv, attr)) = binders.toList(0)
+	  attr
+	}
+      }
+    }
+    val t:String = varmap(sparql.VarAssignable(sparql.Var(name))) match {
+      case SparqlToSql.RDFNoder(rel, b)  => "<uri>" + stem.s + rel + "/" + getattr(b) + "." + value + "#record</uri>"
+      case SparqlToSql.RDFBNoder(rel, b) => "<bnode>bnode_" + rel + "/" + getattr(b) + "." + value + "</bnode>"
+      case SparqlToSql.DateMapper(_)     => "<literal datatype=\"http://www.w3.org/2001/XMLSchema#date\">" + value + "</literal>"
+      case SparqlToSql.IntMapper(_)      => "<literal datatype=\"http://www.w3.org/2001/XMLSchema#integer\">" + value + "</literal>"
+      case SparqlToSql.StringMapper(_)   => "<literal datatype=\"http://www.w3.org/2001/XMLSchema#string\">" + value + "</literal>"
+    }
+    "      <binding name=\"" + name + "\">\n	" + t + "\n      </binding>\n"
+  }
+  def endresult () : String = {
+    "    </result>\n"
+  }
+  def foot () : String = {
+    "  </results>\n</sparql>\n"
+  }
+}
+
--- a/src/test/scala/SparqlToSparqlToSqlTest.scala	Fri Jun 11 21:46:40 2010 -0400
+++ b/src/test/scala/SparqlToSparqlToSqlTest.scala	Sat Jun 12 09:27:16 2010 -0400
@@ -60,7 +60,7 @@
   FROM Employee AS R_emp
  WHERE R_emp.empid IS NOT NULL AND R_emp.lastName="Smith"
 """).get
-    val asSql = SparqlToSql(HR, asStem, StemURI("http://hr.example/DB/"), false, false)
+    val asSql = SparqlToSql(HR, asStem, StemURI("http://hr.example/DB/"), false, false)._1
     assert(asSql === sqlQuery)
     val output = """
 """
@@ -218,7 +218,7 @@
    AND R_patient.MiddleName IS NOT NULL
    AND R__0_sexEntry.EntryName IS NOT NULL
 """).get
-    val asSql = SparqlToSql(hosp1, stemQuery, StemURI("http://hospital.example/DB/"), false, false)
+    val asSql = SparqlToSql(hosp1, stemQuery, StemURI("http://hospital.example/DB/"), false, false)._1
     assert(asSql === sqlQuery)
     val output = """
 """
@@ -326,7 +326,7 @@
       println(stemQuery.toString())
     }
     assert(asStem == stemQuery)
-    val asSql = SparqlToSql(hosp1, asStem, StemURI("http://hospital.example/DB/"), false, false)
+    val asSql = SparqlToSql(hosp1, asStem, StemURI("http://hospital.example/DB/"), false, false)._1
     assert(asSql === sqlQuery)
     val output = """
 """
--- a/src/test/scala/SparqlToSqlTest.scala	Fri Jun 11 21:46:40 2010 -0400
+++ b/src/test/scala/SparqlToSqlTest.scala	Sat Jun 12 09:27:16 2010 -0400
@@ -8,7 +8,7 @@
 import java.net.URI
 import w3c.sw.sql.{Sql,DatabaseDesc,Relation,RelationDesc,Attribute,Value,Datatype,ForeignKey,Name}
 import w3c.sw.sparql.Sparql
-import w3c.sw.sparql2sql.{SparqlToSql,StemURI}
+import w3c.sw.sparql2sql.{SparqlToSql,StemURI,SqlToXMLRes}
 
 /* The SparqlToSqlTest class transforms SPARQL queries to a relational data
  * structure and compares them to a structure parsed from SQL.
@@ -167,7 +167,7 @@
             INNER JOIN Employee AS R_empid18
  WHERE R_empid18.empid=R_emp.manager AND R_empid18.empid=18 AND R_emp.empid IS NOT NULL
 """).get
-    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), true, false)
+    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), true, false)._1
     assert(generated === parsed)
     val output = """
 +-----+
@@ -178,6 +178,53 @@
 """
   }
 
+  /* Re-interpret native format: */
+  test("RDF(?s)") {
+    val sparqlParser = Sparql()
+    val sparqlSelect = sparqlParser.parseAll(sparqlParser.select, """
+PREFIX empP : <http://hr.example/DB/Employee#>
+SELECT ?emp {
+?emp  empP:manager    <http://hr.example/DB/Employee/empid.18#record>
+}
+""").get
+    val sqlParser = Sql()
+    val parsed = sqlParser.parseAll(sqlParser.select, """
+SELECT R_emp.empid AS emp
+       FROM Employee AS R_emp
+            INNER JOIN Employee AS R_empid18
+ WHERE R_empid18.empid=R_emp.manager AND R_empid18.empid=18 AND R_emp.empid IS NOT NULL
+""").get
+    val xmlres = """<?xml version="1.0"?>
+<sparql xmlns="http://www.w3.org/2005/sparql-results#">
+  <head>
+    <variable name="emp"/>
+  </head>
+
+  <results>
+    <result> 
+      <binding name="emp">
+	<uri>http://hr.example/DB/Employee/empid.253#record</uri>
+      </binding>
+    </result>
+  </results>
+</sparql>
+""" //"//
+    val stem = StemURI("http://hr.example/DB/")
+    val (generated, rdfmap) = SparqlToSql(db, sparqlSelect, stem, true, false)
+    val head = SqlToXMLRes.head(List[String]("emp"))
+    val body = SqlToXMLRes.startresult + SqlToXMLRes.binding("emp", "253", rdfmap, stem) + SqlToXMLRes.endresult
+    val foot = SqlToXMLRes.foot
+    assert(generated === parsed)
+    assert(head + body + foot === xmlres)
+    val output = """
++-----+
+| emp |
++-----+
+| 253 | 
++-----+
+"""
+  }
+
   /* Enable turtle string-izing and test URI generation: */
   test("SELECT <x> { ?sf <p> <x>} (in-SQL Nodizer)") {
     val sparqlParser = Sparql()
@@ -194,7 +241,7 @@
             INNER JOIN Employee AS R_empid18
  WHERE R_empid18.empid=R_emp.manager AND R_empid18.empid=18 AND R_emp.empid IS NOT NULL
 """).get
-    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), true, true)
+    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), true, true)._1
     assert(generated === parsed)
     val output = """
 +------------------------------------------------+
@@ -220,7 +267,7 @@
        FROM Employee AS R_emp
  WHERE R_emp.empid IS NOT NULL AND R_emp.lastName IS NOT NULL
 """).get
-    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), true, true)
+    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), true, true)._1
     assert(generated === parsed)
     val output = """
 +----------------------------------------------------+
@@ -250,7 +297,7 @@
             INNER JOIN Employee AS R_manager
  WHERE R_manager.empid=R_empid253.manager AND R_empid253.empid=253
 """).get
-    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), true, false)
+    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), true, false)._1
     assert(generated === parsed)
     val output = """
 +---------+
@@ -279,7 +326,7 @@
             INNER JOIN Employee AS R_18
  WHERE R_18.empid=R_emp.manager AND R_18.empid=18 AND R_emp.empid IS NOT NULL
 """).get
-    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), true, false)
+    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), true, false)._1
     assert(generated === parsed)
     val output = """
 +-----+
@@ -308,7 +355,7 @@
        INNER JOIN TaskAssignments AS R_task2 ON R_who.empid=R_task2.employee
  WHERE R_task1.id<R_task2.id 
 """).get
-    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), true, false)
+    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), true, false)._1
     assert(generated === parsed)
     val output = """
 +-------+-------+
@@ -339,7 +386,7 @@
             INNER JOIN Employee AS R_manager ON R_manager.empid=R_emp.manager
  WHERE R_emp    .lastName IS NOT NULL AND R_manager.lastName IS NOT NULL
 """).get
-    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), true, false)
+    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), true, false)._1
     assert(generated === parsed)
     val output = """
 +---------+------------+
@@ -367,7 +414,7 @@
        FROM Employee AS R_emp
  WHERE R_emp.manager=18 AND R_emp.lastName IS NOT NULL
 """).get
-    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), false, false)
+    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), false, false)._1
     assert(generated === parsed)
     val output = """
 +---------+
@@ -394,7 +441,7 @@
             INNER JOIN Employee AS R_empid18
  WHERE R_empid18.empid=R_emp.manager AND R_empid18.empid=18 AND R_emp.lastName IS NOT NULL
 """).get
-    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), true, false)
+    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), true, false)._1
     assert(generated === parsed)
     val output = """
 +---------+
@@ -424,7 +471,7 @@
        INNER JOIN Employee AS R_manager
 WHERE R_manager.empid=R_emp.manager AND R_manager.lastName="Johnson" AND R_emp.lastName IS NOT NULL
 """).get
-    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), true, false)
+    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), true, false)._1
     assert(generated === parsed)
     val output = """
 +---------+
@@ -470,7 +517,7 @@
  WHERE R_taskLead.birthday<R_emp.birthday AND R_grandManager.birthday<R_taskLead.birthday
    AND R_emp.lastName IS NOT NULL AND R_grandManager.lastName IS NOT NULL
 """).get
-    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), true, false)
+    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), true, false)._1
     assert(generated === parsed)
     val output = """
 +---------+----------------+
@@ -531,7 +578,7 @@
        AND (G_union1._DISJOINT_!=0 OR G_union1.who=R_who.empid)
        AND (G_union1._DISJOINT_!=1 OR G_union1.who=R_who.empid)
 """).get
-    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), false, false)
+    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), false, false)._1
     assert(generated === parsed)
     val output = """
 +---------+
@@ -595,7 +642,7 @@
    AND (G_union0._DISJOINT_!=1 OR R_who.empid=G_union0.who)
    AND R_who.lastName="Smith"
 """).get // !!!    AND (G_union0.bday IS NOT NULL) AND (G_union0.who IS NOT NULL)
-    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), false, false)
+    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), false, false)._1
     assert(generated === parsed)
     val output = """
 """
@@ -650,7 +697,7 @@
    AND (G_union1._DISJOINT_!=1 OR G_union1.who=R_who.empid)
    AND R_who.birthday IS NOT NULL AND R_who.lastName="Smith"
 """).get
-    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), false, false)
+    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), false, false)._1
     assert(generated === parsed)
     val output = """
 """
@@ -705,7 +752,7 @@
    AND (G_union1._DISJOINT_!=1 OR R_who.birthday=G_union1.bday)
    AND R_who.lastName="Smith"
 """).get
-    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), false, false)
+    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), false, false)._1
     assert(generated === parsed)
     val output = """
 """
@@ -736,7 +783,7 @@
                   ) AS G_opt1 ON G_opt1.emp=R_emp.empid
  WHERE R_emp.empid IS NOT NULL AND R_emp.lastName IS NOT NULL
 """).get
-    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), false, false)
+    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), false, false)._1
     assert(generated === parsed)
     val output = """
 """
@@ -767,7 +814,7 @@
  WHERE (G_opt1._DISJOINT_ IS NULL OR R_emp.empid=G_opt1.emp)
    AND R_emp.lastName IS NOT NULL
 """).get
-    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), false, false)
+    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), false, false)._1
     assert(generated === parsed)
     val output = """
 """
@@ -805,7 +852,7 @@
                   ) AS G_opt1 ON G_opt1.emp=R_emp.empid
  WHERE R_emp.empid IS NOT NULL AND R_emp.lastName IS NOT NULL
 """).get
-    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), false, false)
+    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), false, false)._1
     assert(generated === parsed)
     val output = """
 """
@@ -850,7 +897,7 @@
    AND R_emp2.empid IS NOT NULL AND R_emp2.lastName<R_emp3.lastName
    AND R_emp3.lastName<R_emp4.lastName AND R_emp1.empid IS NOT NULL
 """).get
-    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), false, false)
+    val generated = SparqlToSql(db, sparqlSelect, StemURI("http://hr.example/DB/"), false, false)._1
     assert(generated === parsed)
     val output = """
 """
@@ -936,7 +983,7 @@
    AND R_patient.MiddleName IS NOT NULL
    AND R_sexEntry.EntryName IS NOT NULL
 """).get //    AND G_opt6.patient IS NULL
-    val generated = SparqlToSql(hosp1, sparqlSelect, StemURI("http://hospital.example/DB/"), false, false)
+    val generated = SparqlToSql(hosp1, sparqlSelect, StemURI("http://hospital.example/DB/"), false, false)._1
     assert(generated === parsed)
     val output = """
 """
@@ -1013,7 +1060,7 @@
    AND R_patient.MiddleName IS NOT NULL
    AND R_sexEntry.EntryName IS NOT NULL
 """).get
-    val generated = SparqlToSql(hosp1, sparqlSelect, StemURI("http://hospital.example/DB/"), false, false)
+    val generated = SparqlToSql(hosp1, sparqlSelect, StemURI("http://hospital.example/DB/"), false, false)._1
     assert(generated === parsed)
     val output = """
 """