major overhaul with alexandre
authorEric Prud'hommeaux <bertails@w3.org>
Mon, 14 Dec 2009 02:11:39 -0500
changeset 27 6fada4947550
parent 26 a125541a8c30
child 28 5c20336674ac
major overhaul with alexandre
src/main/scala/RDB2RDFMain.scala
src/main/scala/SQL.scala
src/test/scala/RDB2RDFTest.scala
src/test/scala/SQLTest.scala
--- a/src/main/scala/RDB2RDFMain.scala	Sun Dec 13 19:17:29 2009 -0500
+++ b/src/main/scala/RDB2RDFMain.scala	Mon Dec 14 02:11:39 2009 -0500
@@ -19,7 +19,7 @@
 case class PrimaryKey(attr:Attribute)
 
 sealed abstract class Binding
-case class Node(fqattr:FQAttribute) extends Binding
+case class RDFNode(fqattr:FQAttribute) extends Binding
 case class Str(fqattr:FQAttribute) extends Binding
 case class Int(fqattr:FQAttribute) extends Binding
 case class Enum(fqattr:FQAttribute) extends Binding
@@ -98,27 +98,66 @@
     println("equiv|=" + fqattr + "=" + value)
   }
 
-  def VarConstraint(v:Var, attr:FQAttribute) = {
-    println("?" + v.s + "=> @@Binding(" + toString(attr) + ")")
+  /** varConstraint
+   * called on triple pattern subjects and objects of type variable
+   * passed the relation name (from predicate)
+   *   if a subject, then the attribute is the primary key for relation
+   *   if an object, then passed the attribute name (from predicate)
+   * passed the alias for this relation (e.g. _emp)
+   * */
+  def varConstraint(v:Var, rel:Relation, alias:Relation, attr:Attribute) = {
+    //                     Employee      _emp 	         id            
+    //                     Employee      _emp	         lastName      
+    //                     Employee      _emp            manager       
+
+    // if schema(rel)(fttr) is a String => (v => SRValueString(alias.attr))
+
+    // schema(Employee.id) => (?emp => NodeTemplate("Employee", _emp.id) stemURI + rel + fk(rel) + value
+    // schema(Employee.lastName) => (?lastName => RValueString(_emp.lastName)
+    // schema(Employee.manater) => (?manager => ForeignKey("Employee", _manager.id)
+
+    // SELECT ?emp WHERE { ?emp emp:manager <http://hr.example/our/favorite/DB/Employee/id.18#record> ; emp:name ?name }
+    // SQL Results                     SPARQL Results
+    // __emp __name    ?emp                                                      ?name
+    // 4     "Bob"     <http://hr.example/our/favorite/DB/Employee/id.4#record>  "Bob"^^xsd:string
+    // 6     "Sue"     <http://hr.example/our/favorite/DB/Employee/id.6#record>  "Sue"^^xsd:string
+
+//     type String -> RDFStringConstructor // adds ^^xsd:string
+//     type primary key -> RDFNodeConstructor // prefixes with stemURL + relation + attribute  and adds #record
+
+    println("?" + v.s + "=> @@Binding(" + alias.n.s + "." + attr.n.s + ")")
+null
   }
 
   def LiteralConstraint(lit:SparqlLiteral, attr:FQAttribute) = {
     println("equiv|=" + attr + "=" + lit)
   }
 
+  def insertKeyPair(frel:String, fattr:String, trel:String, tattr:String) = {
+//     fks + (Relation(Name(frel)) -> 
+// 	   (Attribute(Name(fattr)) -> 
+// 	    FQAttribute(Relation(Name(trel)), Attribute(Name(tattr)))))
+  }
+
   def getKeyTarget(from:FQAttribute) : Option[FQAttribute] = {
-    from match {
-      case FQAttribute(Relation(Name("Employee")), Attribute(Name("manager"))) =>
-	Some(FQAttribute(Relation(Name("Employee")), Attribute(Name("id"))))
-      case FQAttribute(Relation(Name("Employee")), Attribute(Name("lastName"))) => None
+    val fk = Map[Relation,Map[Attribute, FQAttribute]]()
+    try {
+      Some(fk(from.relation)(from.attribute))
+    } catch {
+      case _ => None
     }
+// from match {
+//       case FQAttribute(Relation(Name("Employee")), Attribute(Name("manager"))) =>
+// 	Some(FQAttribute(Relation(Name("Employee")), Attribute(Name("id"))))
+//       case FQAttribute(Relation(Name("Employee")), Attribute(Name("lastName"))) => None
+//     }
   }
 
   def toString(fqattr:FQAttribute) : String = {
     fqattr.relation.n.s + "." + fqattr.attribute.n.s
   }
 
-  def acc(state:R2RState, triple:TriplePattern, pk:PrimaryKey):R2RState = {
+  def acc(db:DatabaseDesc, state:R2RState, triple:TriplePattern, pk:PrimaryKey):R2RState = {
     val R2RState(project, joins, exprs, varmap) = state
     val TriplePattern(s, p, o) = triple
     p match {
@@ -129,38 +168,50 @@
 	println(rel.n.s + " AS " + alias.n.s)
 	s match {
 	  case SUri(u) => URIconstraint(u, pk)
-	  case SVar(v) => VarConstraint(v, FQAttribute(alias, pk.attr))
+	  case SVar(v) => varConstraint(v, rel, alias, pk.attr)
 	  null
 	}
 	val objattr = FQAttribute(alias, attr)
 	val oAlias = AliasFromO(o) // None if OLit
-	val target = getKeyTarget(FQAttribute(rel, attr))
-	target match {
-	  case None => null
-	  case Some(fqattr) => {
+	val fks = Map[Relation,Map[Attribute, FQAttribute]]()
+	//fks.insertKeyPair("Employee", "manager", "manager", "id")
+	// fks.insertKeyPair("Employee", "asdf", "fdsa", "id")
+// 	val target = getKeyTarget(FQAttribute(rel, attr))
+// 	(target, oAlias) match {
+// 	    case _, _ =>
+// 	}
+
+	val target = db.relationdescs(rel).attributes(attr) match {
+	  case ForeignKey(fkrel, fkattr) => {
+	    val fqattr = FQAttribute(fkrel, fkattr)
 	    oAlias match {
 	      case None => error("no oAlias for foreign key " + toString(fqattr))
 	      case Some(a) => {
 		println(toString(objattr) + "->" + toString(FQAttribute(a, fqattr.attribute)))
-		1 // null ptr error otherwise. what's getting assigned to this?
+		o match {
+		  case OUri(u) => URIconstraint(u, pk)
+		  case OVar(v) => varConstraint(v, fqattr.relation, a, fqattr.attribute)
+		  case OLit(l) => LiteralConstraint(l, objattr)
+		}
 	      }
 	    }
 	  }
+	  case Value(dt) => {
+	    o match {
+	      case OUri(u) => URIconstraint(u, pk)
+	      case OVar(v) => varConstraint(v, rel, alias, attr)
+	      case OLit(l) => LiteralConstraint(l, objattr)
+	    }
+	  }
 	}
-	o match {
-	  case OUri(u) => URIconstraint(u, pk)
-	  case OVar(v) => VarConstraint(v, objattr)
-	  case OLit(l) => LiteralConstraint(l, objattr)
-	  null
-	}
-	null
+
       }
       case PVar(v) => error("variable predicates require tedious enumeration; too tedious for me.")
     }
     state
   }
 
-  def apply (sparql:SparqlSelect, stem:StemURI, pk:PrimaryKey) : Select = {
+  def apply (db:DatabaseDesc, sparql:SparqlSelect, stem:StemURI, pk:PrimaryKey) : Select = {
     val SparqlSelect(attrs, triples) = sparql
     var r2rState = R2RState(
       // AttributeList(List()), 
@@ -184,7 +235,7 @@
       Map[Var, FQAttribute]()
     )
 
-    triples.triplepatterns.foreach(s => r2rState = acc(r2rState, s, pk))
+    triples.triplepatterns.foreach(s => r2rState = acc(db, r2rState, s, pk))
 
     Select(
       r2rState.project,
--- a/src/main/scala/SQL.scala	Sun Dec 13 19:17:29 2009 -0500
+++ b/src/main/scala/SQL.scala	Mon Dec 14 02:11:39 2009 -0500
@@ -21,10 +21,27 @@
 case class PrimaryExpressionNotNull(l:FQAttribute) extends PrimaryExpression
 sealed abstract class RValue
 case class RValueAttr(fqattribute:FQAttribute) extends RValue
-case class RValueInt(i:Name) extends RValue
-case class RValueString(i:Name) extends RValue
+case class RValueTyped(datatype:SQLDatatype, i:Name) extends RValue
 case class Name(s:String)
 
+object Name {
+  implicit def fromStringToName(s:String):Name = Name(s)
+}
+
+case class SQLDatatype(name:String)
+
+object SQLDatatype {
+  val STRING = SQLDatatype("String")
+  val INTEGER = SQLDatatype("Int")
+}
+
+sealed abstract class ValueDescription
+case class Value(datatype:SQLDatatype) extends ValueDescription
+case class ForeignKey(rel:Relation, attr:Attribute) extends ValueDescription
+
+case class DatabaseDesc(relationdescs:Map[Relation,RelationDesc])
+case class RelationDesc(primaryKey:Attribute, attributes:Map[Attribute, ValueDescription])
+
 case class Sql() extends JavaTokenParsers {
 
   def select:Parser[Select] =
@@ -82,8 +99,8 @@
 
   def rvalue:Parser[RValue] = (
       fqattribute ^^ { RValueAttr(_) }
-    | """[0-9]+""".r ^^ { x => RValueInt(Name(x)) }
-    | "\"[^\"]*\"".r  ^^ { x => RValueString(Name(x.substring(1, x.size - 1))) }
+    | """[0-9]+""".r ^^ { x => RValueTyped(SQLDatatype.INTEGER, Name(x)) }
+    | "\"[^\"]*\"".r  ^^ { x => RValueTyped(SQLDatatype.STRING, Name(x.substring(1, x.size - 1))) }
   )
 
 }
--- a/src/test/scala/RDB2RDFTest.scala	Sun Dec 13 19:17:29 2009 -0500
+++ b/src/test/scala/RDB2RDFTest.scala	Mon Dec 14 02:11:39 2009 -0500
@@ -5,6 +5,16 @@
 
 class RDB2RDFTest extends FunSuite {
 
+  val db:DatabaseDesc = DatabaseDesc(
+    Map(Relation("Employee") -> 
+	RelationDesc(Attribute("id"), 
+		     Map(Attribute("id") -> Value(SQLDatatype.INTEGER),
+			 Attribute("lastName") -> Value(SQLDatatype.STRING),
+			 Attribute("width") -> Value(SQLDatatype.INTEGER), 
+			 Attribute("manager") -> ForeignKey(Relation("Employee"), Attribute("id")), 
+			 Attribute("address") -> ForeignKey(Relation("Address"),  Attribute("id"))))))
+
+
   test("SQLbgp") {
     val sparqlParser = Sparql()
     val sparqlSelect = sparqlParser.parseAll(sparqlParser.select, """
@@ -22,7 +32,7 @@
             INNER JOIN Employee AS manager ON manager.id=emp.manager
  WHERE emp.lastName IS NOT NULL AND manager.lastName IS NOT NULL
 """).get
-    assert(RDB2RDF(sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id")))) === sqlSelect)
+    assert(RDB2RDF(db, sparqlSelect, StemURI("http://hr.example/DB/"), PrimaryKey(Attribute(Name("id")))) === sqlSelect)
   }
 
 
--- a/src/test/scala/SQLTest.scala	Sun Dec 13 19:17:29 2009 -0500
+++ b/src/test/scala/SQLTest.scala	Mon Dec 14 02:11:39 2009 -0500
@@ -24,7 +24,7 @@
   FROM Employee AS emp
  WHERE emp.manager=18 AND emp.lastName IS NOT NULL
 """
-    val expected = Select(AttributeList(List(NamedAttribute(FQAttribute(Relation(Name("emp")),Attribute(Name("lastName"))),Attribute(Name("empName"))))),TableList(List(Join(TableAlias(Relation(Name("Employee")),Relation(Name("emp"))),None))),Some(Expression(List(PrimaryExpressionEq(FQAttribute(Relation(Name("emp")),Attribute(Name("manager"))),RValueInt(Name("18"))), PrimaryExpressionNotNull(FQAttribute(Relation(Name("emp")),Attribute(Name("lastName"))))))))
+    val expected = Select(AttributeList(List(NamedAttribute(FQAttribute(Relation(Name("emp")),Attribute(Name("lastName"))),Attribute(Name("empName"))))),TableList(List(Join(TableAlias(Relation(Name("Employee")),Relation(Name("emp"))),None))),Some(Expression(List(PrimaryExpressionEq(FQAttribute(Relation(Name("emp")),Attribute(Name("manager"))),RValueTyped(SQLDatatype.INTEGER,Name("18"))), PrimaryExpressionNotNull(FQAttribute(Relation(Name("emp")),Attribute(Name("lastName"))))))))
     assert(expected === (a.parseAll(a.select, e).get))
   }
 
@@ -37,7 +37,7 @@
                                        AND manager.lastName="Johnson"
 WHERE emp.lastName IS NOT NULL
 """
-    val expected = Select(AttributeList(List(NamedAttribute(FQAttribute(Relation(Name("emp")),Attribute(Name("lastName"))),Attribute(Name("empName"))))),TableList(List(Join(TableAlias(Relation(Name("Employee")),Relation(Name("emp"))),None),Join(TableAlias(Relation(Name("Employee")),Relation(Name("manager"))),Some(Expression(List(PrimaryExpressionEq(FQAttribute(Relation(Name("emp")),Attribute(Name("manager"))),RValueAttr(FQAttribute(Relation(Name("manager")),Attribute(Name("id"))))), PrimaryExpressionEq(FQAttribute(Relation(Name("manager")),Attribute(Name("lastName"))),RValueString(Name("Johnson"))))))))),Some(Expression(List(PrimaryExpressionNotNull(FQAttribute(Relation(Name("emp")),Attribute(Name("lastName"))))))))
+    val expected = Select(AttributeList(List(NamedAttribute(FQAttribute(Relation(Name("emp")),Attribute(Name("lastName"))),Attribute(Name("empName"))))),TableList(List(Join(TableAlias(Relation(Name("Employee")),Relation(Name("emp"))),None),Join(TableAlias(Relation(Name("Employee")),Relation(Name("manager"))),Some(Expression(List(PrimaryExpressionEq(FQAttribute(Relation(Name("emp")),Attribute(Name("manager"))),RValueAttr(FQAttribute(Relation(Name("manager")),Attribute(Name("id"))))), PrimaryExpressionEq(FQAttribute(Relation(Name("manager")),Attribute(Name("lastName"))),RValueTyped(SQLDatatype.STRING,Name("Johnson"))))))))),Some(Expression(List(PrimaryExpressionNotNull(FQAttribute(Relation(Name("emp")),Attribute(Name("lastName"))))))))
     assert(expected === (a.parseAll(a.select, e).get))
   }