~ relaxed sparql.name
authorEric Prud'hommeaux <eric@w3.org>
Sat, 12 Jun 2010 17:14:07 -0400
changeset 206 d88313013f7d
parent 205 745da618b07c
child 208 b4daf7d3d232
~ relaxed sparql.name
+ sparql.Select(distinct, ... order, offset, limit)
+ sparql.PrimaryExpressionGt
+ sql.RelationalExpressionGt
+ skeleton bsbm
src/main/scala/SPARQL.scala
src/main/scala/SQL.scala
src/main/scala/SparqlToSparql.scala
src/main/scala/SparqlToSparqlToSql.scala
src/main/scala/SparqlToSql.scala
src/test/scala/SparqlTest.scala
src/test/scala/SparqlToSparqlToSqlTest.scala
--- a/src/main/scala/SPARQL.scala	Sat Jun 12 09:37:34 2010 -0400
+++ b/src/main/scala/SPARQL.scala	Sat Jun 12 17:14:07 2010 -0400
@@ -8,7 +8,7 @@
 
   val uri = """[a-zA-Z0-9:/#_\.\-]+""".r
   val integer = """[0-9]+""".r
-  val name = """[a-zA-Z][a-zA-Z0-9_]*|[a-zA-Z_][a-zA-Z0-9_]+""".r
+  val name = """[a-zA-Z][a-zA-Z0-9_-]*|[a-zA-Z_][a-zA-Z0-9_]+""".r
   var prefixes:Map[String, String] = Map()
   var bnodes:Map[String, BNode] = Map()
   var nextBNode = 1
@@ -16,8 +16,13 @@
 
 import MyParsers._
 
-case class Select(attrs:SparqlAttributeList, gp:GraphPattern) {
-  override def toString = attrs+"\n"+gp
+case class Select(distinct:Boolean, attrs:SparqlAttributeList, gp:GraphPattern, order:List[OrderElt], offset:Option[Int], limit:Option[Int]) {
+  override def toString =
+    { if (distinct) "DISTINCT " else "" }+
+    attrs+"\n"+gp+
+    { if (order.size > 0) { "ORDER BY " + order.map(o => o.toString).mkString(" ") } else "" }+
+    { if (offset.isDefined) {"OFFSET " + offset } else "" }+
+    { if (limit.isDefined) {"LIMIT " + limit } else "" }
 }
 case class Construct(head:TriplesBlock, gp:GraphPattern)
 case class SparqlAttributeList(attributelist:List[Var]) {
@@ -223,7 +228,12 @@
 sealed abstract class PrimaryExpression
 case class PrimaryExpressionEq(left:SparqlTermExpression, right:SparqlTermExpression) extends PrimaryExpression
 case class PrimaryExpressionLt(left:SparqlTermExpression, right:SparqlTermExpression) extends PrimaryExpression
-case class SparqlTermExpression(term:Term)
+case class PrimaryExpressionGt(left:SparqlTermExpression, right:SparqlTermExpression) extends PrimaryExpression
+case class SparqlTermExpression(term:Term) extends PrimaryExpression
+
+case class OrderElt(desc:Boolean, expr:Expression) {
+  override def toString = { if (desc) "DESC" else "ASC" } + "(" + expr.toString + ")"
+}
 
 sealed trait Term
 case class TermUri(u:Uri) extends Term {
@@ -243,7 +253,24 @@
 case class Sparql() extends JavaTokenParsers {
 
   def select:Parser[Select] =
-    rep(prefixdecls) ~ "SELECT" ~ attributelist ~ opt("WHERE") ~ groupgraphpattern ^^ { case x~"SELECT"~a~w~gp => Select(a, gp) }
+    rep(prefixdecls) ~ "SELECT" ~ opt("DISTINCT") ~ attributelist ~ opt("WHERE") ~ groupgraphpattern ~ opt(order) ~ opt(offset) ~ opt(limit) ^^ {
+      case x~"SELECT"~d~a~w~gp~ord~off~lim => Select(d.isDefined, a, gp, ord.getOrElse(List[OrderElt]()), off, lim)
+    }
+
+  def order:Parser[List[OrderElt]] = 
+    "ORDER" ~ "BY" ~ rep(orderelt) ^^ { case o~b~elts => elts }
+
+  def orderelt:Parser[OrderElt] = (
+      "ASC" ~ "(" ~ expression ~ ")" ^^ { case a~o~expr~c => OrderElt(false, expr) }
+    | "DESC" ~ "(" ~ expression ~ ")" ^^ { case a~o~expr~c => OrderElt(true, expr) }
+    | varr ^^ { case v => OrderElt(false, Expression(List(SparqlTermExpression(TermVar(v))))) }
+  )
+    
+  def offset:Parser[Int] =
+    "OFFSET" ~ integer ^^ { case o~i => i.toInt }
+
+  def limit:Parser[Int] =
+    "LIMIT" ~ integer ^^ { case o~i => i.toInt }
 
   def construct:Parser[Construct] =
     rep(prefixdecls) ~ "CONSTRUCT" ~ constructpattern ~ opt("WHERE") ~ groupgraphpattern ^^ { case x~"CONSTRUCT"~a~w~gp => Construct(a, gp) }
@@ -266,6 +293,9 @@
       { case left ~ "=" ~ right => PrimaryExpressionEq(left, right) }
     | value ~ "<" ~ value ^^
       { case left ~ "<" ~ right => PrimaryExpressionLt(left, right) }
+    | value ~ ">" ~ value ^^
+      { case left ~ ">" ~ right => PrimaryExpressionGt(left, right) }
+    | value
   )
 
   def value:Parser[SparqlTermExpression] = (
--- a/src/main/scala/SQL.scala	Sat Jun 12 09:37:34 2010 -0400
+++ b/src/main/scala/SQL.scala	Sat Jun 12 17:14:07 2010 -0400
@@ -116,6 +116,9 @@
 case class RelationalExpressionLt(l:Expression, r:Expression) extends RelationalExpression {
   override def toString = l + "<" + r
 }
+case class RelationalExpressionGt(l:Expression, r:Expression) extends RelationalExpression {
+  override def toString = l + ">" + r
+}
 case class RelationalExpressionNull(l:Expression) extends RelationalExpression { // Expression?
   override def toString = l + " IS NULL"
 }
@@ -406,6 +409,7 @@
       case RelationalExpressionEq(l, r) => findNonNullRelVarAttrs(l) ++ findNonNullRelVarAttrs(r)
       case RelationalExpressionNe(l, r) => findNonNullRelVarAttrs(l) ++ findNonNullRelVarAttrs(r)
       case RelationalExpressionLt(l, r) => findNonNullRelVarAttrs(l) ++ findNonNullRelVarAttrs(r)
+      case RelationalExpressionGt(l, r) => findNonNullRelVarAttrs(l) ++ findNonNullRelVarAttrs(r)
       case e:PrimaryExpressionTyped => Set()
       case PrimaryExpressionAttr(a) => Set(a)
       case e:ConstNULL => Set()
@@ -428,6 +432,7 @@
       case e:RelationalExpressionEq => Some(e)
       case e:RelationalExpressionNe => Some(e)
       case e:RelationalExpressionLt => Some(e)
+      case e:RelationalExpressionGt => Some(e)
       case e:PrimaryExpressionTyped => Some(e)
       case e:PrimaryExpressionAttr => Some(e)
       case e:ConstNULL => Some(e)
@@ -457,6 +462,7 @@
       }
       case e:RelationalExpressionNe => Some(e)
       case e:RelationalExpressionLt => Some(e)
+      case e:RelationalExpressionGt => Some(e)
       case e:PrimaryExpressionTyped => Some(e)
       case e:PrimaryExpressionAttr => Some(e)
       case e:ConstNULL => Some(e)
--- a/src/main/scala/SparqlToSparql.scala	Sat Jun 12 09:37:34 2010 -0400
+++ b/src/main/scala/SparqlToSparql.scala	Sat Jun 12 17:14:07 2010 -0400
@@ -302,8 +302,10 @@
     })
     //println("ruleMap: " + ruleMap)
     sparql.Select(
+      false,
       query.attrs,
-      mapGraphPattern(query.gp, ruleMap, "_")
+      mapGraphPattern(query.gp, ruleMap, "_"),
+      List[sparql.OrderElt](), None, None
     )
   }
 
--- a/src/main/scala/SparqlToSparqlToSql.scala	Sat Jun 12 09:37:34 2010 -0400
+++ b/src/main/scala/SparqlToSparqlToSql.scala	Sat Jun 12 17:14:07 2010 -0400
@@ -40,8 +40,10 @@
 	val (p, pselects, pconsts) = substituteVar(triple.p, "P", triple);
 	val (o, oselects, oconsts) = substituteVar(triple.o, "O", triple);
 	val select = sparql.Select(
+	  false,
 	  sparql.SparqlAttributeList(sselects ++ pselects ++ oselects),
-	  sparql.TriplesBlock(List(sparql.TriplePattern(s, p, o)))
+	  sparql.TriplesBlock(List(sparql.TriplePattern(s, p, o))),
+	  List[sparql.OrderElt](), None, None
 	)
 
 	/* Convert to equivalent SQL SELECT. */
--- a/src/main/scala/SparqlToSql.scala	Sat Jun 12 09:37:34 2010 -0400
+++ b/src/main/scala/SparqlToSql.scala	Sat Jun 12 17:14:07 2010 -0400
@@ -599,6 +599,8 @@
     val (lTerm:sparql.Term, rTerm:sparql.Term, sqlexpr) = f match {
       case sparql.PrimaryExpressionEq(l, r) => (l.term, r.term, sql.RelationalExpressionEq(_,_))
       case sparql.PrimaryExpressionLt(l, r) => (l.term, r.term, sql.RelationalExpressionLt(_,_))
+      case sparql.PrimaryExpressionGt(l, r) => (l.term, r.term, sql.RelationalExpressionGt(_,_))
+      case sparql.SparqlTermExpression(t) => error("not implemented") // (l.term, r.term, sql.PrimaryExpressionAttr(_,_))
     }
 
     lTerm match {
@@ -994,7 +996,7 @@
    * @return an SQL query corresponding to sparquery
    */
   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
+    val sparql.Select(_, attrs, triples, _, _, _) = sparquery
 
     /** Create an object to hold our compilation state. */
     val initState = R2RState(
--- a/src/test/scala/SparqlTest.scala	Sat Jun 12 09:37:34 2010 -0400
+++ b/src/test/scala/SparqlTest.scala	Sat Jun 12 17:14:07 2010 -0400
@@ -100,13 +100,15 @@
 """
     val tps =
       Select(
+	false,
 	SparqlAttributeList(List(Var("empName"), Var("manageName"))),
 	TriplesBlock(
 	  List(
 	    TriplePattern(
 	      TermVar(Var("emp")),
 		TermUri(Uri("http://hr.example/DB/Employee#lastName")),
-	      TermVar(Var("empName"))))))
+	      TermVar(Var("empName"))))),
+	List[OrderElt](), None, None)
     assert(tps === a.parseAll(a.select, e).get)
   }
 
@@ -121,13 +123,15 @@
 """
     val tps =
       Select(
+	false,
 	SparqlAttributeList(List(Var("empName"), Var("manageName"))),
 	TriplesBlock(
 	  List(
 	    TriplePattern(
 	      TermVar(Var("emp")),
 		TermUri(Uri("http://hr.example/DB/Employee#lastName")),
-	      TermVar(Var("empName"))))))
+	      TermVar(Var("empName"))))),
+	List[OrderElt](), None, None)
     assert(tps === a.parseAll(a.select, e).get)
   }
 
@@ -141,6 +145,7 @@
 """
     val tps =
       Select(
+	false,
 	SparqlAttributeList(List(Var("empName"), Var("manageName"))),
 	TableFilter(
 	  TriplesBlock(
@@ -153,7 +158,8 @@
 	    PrimaryExpressionLt(SparqlTermExpression(TermVar(Var("manBday"))),
 				      SparqlTermExpression(TermVar(Var("empBday")))), 
 	    PrimaryExpressionLt(SparqlTermExpression(TermVar(Var("grandManBday"))),
-				      SparqlTermExpression(TermVar(Var("manBday"))))))))
+				      SparqlTermExpression(TermVar(Var("manBday"))))))),
+	List[OrderElt](), None, None)
     assert(tps === a.parseAll(a.select, e).get)
   }
 
@@ -168,6 +174,7 @@
 """
     val tps =
       Select(
+	false,
 	SparqlAttributeList(List(Var("empName"), Var("manageName"))),
 	TriplesBlock(
 	  List(
@@ -182,7 +189,8 @@
 	    TriplePattern(
 	      TermVar(Var("manager")),
 	      TermUri(Uri("http://hr.example/DB/Employee#lastName")),
-	      TermVar(Var("managName"))))))
+	      TermVar(Var("managName"))))),
+	List[OrderElt](), None, None)
     assert(tps === a.parseAll(a.select, e).get)
   }
 
@@ -214,13 +222,15 @@
 """
     val tps =
       Select(
+	false,
 	SparqlAttributeList(List(Var("x"))),
 	TriplesBlock(
 	  List(
 	    TriplePattern(
 	      TermVar(Var("x")),
 	      TermUri(Uri("http://hr.example/DB/Employee#manager")),
-	      TermVar(Var("y"))))))
+	      TermVar(Var("y"))))),
+	List[OrderElt](), None, None)
     assert(tps === a.parseAll(a.select, e).get)
   }
 
@@ -231,6 +241,7 @@
 """
     val tps =
       Select(
+	false,
 	SparqlAttributeList(List(Var("x"))),
 	TableConjunction(List(
 	  TriplesBlock(
@@ -244,7 +255,8 @@
 	      TriplePattern(
 		TermVar(Var("x")),
 		TermUri(Uri("http://hr.example/DB/Employee#manager")),
-		TermVar(Var("y"))))))))
+		TermVar(Var("y"))))))),
+	List[OrderElt](), None, None)
     assert(tps === a.parseAll(a.select, e).get)
   }
 
@@ -255,6 +267,7 @@
 """
     val tps =
       Select(
+	false,
 	SparqlAttributeList(List(Var("x"))),
 	TableDisjunction(List(
 	  TriplesBlock(
@@ -268,7 +281,8 @@
 	      TriplePattern(
 		TermVar(Var("x")),
 		TermUri(Uri("http://hr.example/DB/Employee#manager")),
-		TermVar(Var("y"))))))))
+		TermVar(Var("y"))))))),
+	List[OrderElt](), None, None)
     assert(tps === a.parseAll(a.select, e).get)
   }
 
@@ -279,6 +293,7 @@
 """
     val tps =
       Select(
+	false,
 	SparqlAttributeList(List(Var("x"))),
 	TableConjunction(List(
 	  TriplesBlock(
@@ -293,7 +308,8 @@
 		TriplePattern(
 		  TermVar(Var("x")),
 		  TermUri(Uri("http://hr.example/DB/Employee#manager")),
-		  TermVar(Var("y")))))))))
+		  TermVar(Var("y")))))))),
+	List[OrderElt](), None, None)
     assert(tps === a.parseAll(a.select, e).get)
   }
 
@@ -304,6 +320,7 @@
 """
     val tps =
       Select(
+	false,
 	SparqlAttributeList(List(Var("x"))),
 	OptionalGraphPattern(
 	  TriplesBlock(
@@ -311,7 +328,8 @@
 	      TriplePattern(
 		TermVar(Var("x")),
 		TermUri(Uri("http://hr.example/DB/Employee#manager")),
-		TermVar(Var("y")))))))
+		TermVar(Var("y")))))),
+	List[OrderElt](), None, None)
     assert(tps === a.parseAll(a.select, e).get)
   }
 
@@ -322,6 +340,7 @@
 """
     val tps =
       Select(
+	false,
 	SparqlAttributeList(List(Var("x"))),
 	TableConjunction(List(
 	  TriplesBlock(
@@ -336,7 +355,8 @@
 		TriplePattern(
 		  TermVar(Var("x")),
 		  TermUri(Uri("http://hr.example/DB/Employee#manager")),
-		  TermVar(Var("y")))))))))
+		  TermVar(Var("y")))))))),
+	List[OrderElt](), None, None)
     assert(tps === a.parseAll(a.select, e).get)
   }
 
@@ -355,6 +375,7 @@
 """
     val tps =
       Select(
+	false,
 	SparqlAttributeList(List(Var("name"))),
 	TableConjunction(List(
 	  TriplesBlock(
@@ -393,7 +414,8 @@
 		  TermVar(Var("managed")),
 		  TermUri(Uri("http://hr.example/DB/Employee#lastName")),
 		  TermVar(Var("name")))
-	      )))))))
+	      )))))),
+	List[OrderElt](), None, None)
     assert(tps === a.parseAll(a.select, e).get)
   }
 
@@ -411,13 +433,14 @@
          FILTER ( ?emp1Name < ?emp2Name && ?emp2Name < ?emp3Name && ?emp3Name < ?emp4Name) }
 """
     val tps =
-      Select(SparqlAttributeList(List(Var("emp1Name"), Var("emp2Name"), Var("emp3Name"))),
+      Select(false, SparqlAttributeList(List(Var("emp1Name"), Var("emp2Name"), Var("emp3Name"))),
        TableFilter(TableConjunction(List(TriplesBlock(List(TriplePattern(TermVar(Var("emp1")), TermUri(Uri("http://hr.example/DB/Employee#lastName")), TermVar(Var("emp1Name"))))),
 					 OptionalGraphPattern(TriplesBlock(List(TriplePattern(TermVar(Var("emp1")), TermUri(Uri("http://hr.example/DB/Employee#birthday")), TermVar(Var("birthday")))))),
 					 TriplesBlock(List(TriplePattern(TermVar(Var("emp2")), TermUri(Uri("http://hr.example/DB/Employee#lastName")), TermVar(Var("emp2Name"))))),
 					 OptionalGraphPattern(TriplesBlock(List(TriplePattern(TermVar(Var("emp2")), TermUri(Uri("http://hr.example/DB/Employee#birthday")), TermVar(Var("birthday")))))),
 					 TriplesBlock(List(TriplePattern(TermVar(Var("emp4")),TermUri(Uri("http://hr.example/DB/Employee#birthday")),TermVar(Var("birthday"))))))),
-		   Expression(List(PrimaryExpressionLt(SparqlTermExpression(TermVar(Var("emp1Name"))),SparqlTermExpression(TermVar(Var("emp2Name")))), PrimaryExpressionLt(SparqlTermExpression(TermVar(Var("emp2Name"))),SparqlTermExpression(TermVar(Var("emp3Name")))), PrimaryExpressionLt(SparqlTermExpression(TermVar(Var("emp3Name"))),SparqlTermExpression(TermVar(Var("emp4Name"))))))))
+		   Expression(List(PrimaryExpressionLt(SparqlTermExpression(TermVar(Var("emp1Name"))),SparqlTermExpression(TermVar(Var("emp2Name")))), PrimaryExpressionLt(SparqlTermExpression(TermVar(Var("emp2Name"))),SparqlTermExpression(TermVar(Var("emp3Name")))), PrimaryExpressionLt(SparqlTermExpression(TermVar(Var("emp3Name"))),SparqlTermExpression(TermVar(Var("emp4Name"))))))),
+	     List[OrderElt](), None, None)
     assert(tps === a.parseAll(a.select, e).get)
   }
 
--- a/src/test/scala/SparqlToSparqlToSqlTest.scala	Sat Jun 12 09:37:34 2010 -0400
+++ b/src/test/scala/SparqlToSparqlToSqlTest.scala	Sat Jun 12 17:14:07 2010 -0400
@@ -95,7 +95,8 @@
     FROM Employee AS R_S
    WHERE (R_S.empid IS NOT NULL)
      AND (R_S.lastName IS NOT NULL)
-""").get
+""" //"
+				    ).get
     assert(expected === view)
   }
 
@@ -343,4 +344,92 @@
 //     assert(expected === view)
   // }
 
+  /* ========== DiabeticPatient database tests ==========
+   *
+   */
+  val bsbmDdl = """
+CREATE TABLE Person (ID INT PRIMARY KEY, MiddleName STRING, DateOfBirth DATE, SexDE INT, PRIMARY KEY (ID), FOREIGN KEY (SexDE) REFERENCES Sex_DE(ID));
+CREATE TABLE Sex_DE (ID INT PRIMARY KEY, EntryName STRING);
+CREATE TABLE Item_Medication (ID INT PRIMARY KEY, PRIMARY KEY (ID), PatientID INT, FOREIGN KEY (PatientID) REFERENCES Person(ID), PerformedDTTM DATE, EntryName STRING);
+CREATE TABLE Medication (ID INT PRIMARY KEY, PRIMARY KEY (ID), ItemID INT, FOREIGN KEY (ItemID) REFERENCES Item_Medication(ID), MedDictDE INT, FOREIGN KEY (MedDictDE) REFERENCES Medication_DE(ID), DaysToTake INT);
+CREATE TABLE Medication_DE (ID INT PRIMARY KEY, NDC INT);
+CREATE TABLE NDCcodes (ID INT PRIMARY KEY, NDC INT, ingredient INT);
+"""
+  val bsbmDb:DatabaseDesc = DDLParser.parseAll(DDLParser.ddl, bsbmDdl).get
+  val delme = Sparql() // re-use ConstructParser ?
+  val db2bsbm = delme.parseAll(delme.construct, """
+PREFIX map: <file:/E:/code/d2r-server-0.4/d2r-mapping.n3#>
+PREFIX vocab: <vocab/>
+PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
+PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
+PREFIX d2rq: <http://www.wiwiss.fu-berlin.de/suhl/bizer/D2RQ/0.1#>
+PREFIX dc: <http://purl.org/dc/elements/1.1/>
+PREFIX bsbm: <http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/vocabulary/>
+PREFIX bsbm-inst: <http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/instances/>
+PREFIX foaf: <http://xmlns.com/foaf/0.1/>
+PREFIX rev: <http://purl.org/stuff/rev#>
+
+PREFIX offer: <http://bsbm.example/db/offer#>
+PREFIX person: <http://bsbm.example/db/person#>
+PREFIX producer: <http://bsbm.example/db/producer#>
+PREFIX product: <http://bsbm.example/db/product#>
+PREFIX productfeatureproduct: <http://bsbm.example/db/productfeatureproduct#>
+PREFIX producttypeproduct: <http://bsbm.example/db/producttypeproduct#>
+PREFIX productfeature: <http://bsbm.example/db/productfeature#>
+PREFIX producttype: <http://bsbm.example/db/producttype#>
+PREFIX review: <http://bsbm.example/db/review#>
+PREFIX vendor: <http://bsbm.example/db/vendor#>
+
+PREFIX tr: <http://www.w3.org/2008/04/SPARQLfed/#>
+
+CONSTRUCT {
+<s> <p> <o> .
+} WHERE {
+<s> <p> <o> .
+}""" //"
+			      ).get
+  test("bsbm1") {
+    val sparqlParser = Sparql()
+    val bsbmQuery = sparqlParser.parseAll(sparqlParser.select, """
+PREFIX bsbm-inst: <http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/instances/>
+PREFIX bsbm: <http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/vocabulary/>
+PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
+PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+
+SELECT DISTINCT ?product ?label
+WHERE { 
+ ?product rdfs:label ?label .
+ ?product a <http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/instances/ProductType59> .
+ ?product bsbm:productFeature <http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/instances/ProductFeature5> . 
+ ?product bsbm:productFeature <http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/instances/ProductFeature7> . 
+?product bsbm:productPropertyNumeric1 ?value1 .
+	FILTER (?value1 > 578) 
+	}
+ORDER BY ?label
+LIMIT 10
+""").get
+
+    val stemQuery = sparqlParser.parseAll(sparqlParser.select, """
+SELECT ?o WHERE { ?s <p> ?o }
+""").get
+    val sqlParser = Sql()
+    val sqlQuery = sqlParser.parseAll(sqlParser.select, """
+SELECT R_emp.empid AS emp
+  FROM Employee AS R_emp
+ WHERE R_emp.empid IS NOT NULL AND R_emp.lastName="Smith"
+""").get
+//     val asStem = SparqlToSparql(bsbmQuery, List(db2bsbm))
+//     if (!(asStem == stemQuery)) {
+//       println(asStem.toString())
+//       println("---")
+//       println(stemQuery.toString())
+//     }
+//     assert(asStem == stemQuery)
+//     val asSql = SparqlToSql(bsbmDb, asStem, StemURI("http://hospital.example/DB/"), false, false)._1
+//     assert(asSql === sqlQuery)
+//     val output = """
+// """
+  }
+
 }