~ encapsulated Header
authorEric Prud'hommeaux <eric@w3.org>
Tue, 28 Sep 2010 18:23:51 -0400
changeset 26 7429859b958b
parent 25 f460e59ebcc2
child 27 594065eeeedc
~ encapsulated Header
~ encapsulated KeyMap
~ s/keys/candidates/
src/main/scala/Main.scala
src/test/scala/Test.scala
--- a/src/main/scala/Main.scala	Tue Sep 28 09:04:23 2010 -0400
+++ b/src/main/scala/Main.scala	Tue Sep 28 18:23:51 2010 -0400
@@ -5,12 +5,14 @@
 // Relational structure
 object SQL {
 
-  case class Database(m:Map[RelName, Relation])
-  case class Relation (header:Header, body:Body, keys:List[CandidateKey], pk:Option[CandidateKey], fks:ForeignKeys)
-  case class Header (types:Map[AttrName, SQLDatatype]) {
-    def keySet () = types.keySet
+  case class Database(m:Map[RelName, Relation]) {
+    def idxables():Set[RelName] = m.keySet filter { rn => !m(rn).candidates.isEmpty }
   }
-
+  case class Relation (header:Header, body:Body, candidates:List[CandidateKey], pk:Option[CandidateKey], fks:ForeignKeys)
+  case class Header (m:Map[AttrName, SQLDatatype]) {
+    def keySet () = m.keySet
+    def apply (a:AttrName) = m(a)
+  }
   type CandidateKey = List[AttrName]
   type ForeignKeys = Map[List[AttrName], Target]
   case class Target(rel:RelName, attrs:CandidateKey)
@@ -47,7 +49,7 @@
       case v:LexicalValue => Some(v)
     }
 
-  def sqlDatatype (h:Header, a:AttrName) : SQLDatatype = h.types(a)
+  def sqlDatatype (h:Header, a:AttrName) : SQLDatatype = h(a)
 
 }
 
@@ -99,7 +101,27 @@
   import RDF._
   import SQL._
 
-  type KeyMap = Map[CandidateKey, Map[List[CellValue], Node]]
+  case class KeyMap(m:Map[CandidateKey,  Map[List[CellValue], Node]]) {
+    //def KeyMap() : KeyMap = KeyMap(Map[CandidateKey,  Map[List[CellValue], Node]]())
+    def apply(i:CandidateKey) : Map[List[CellValue], Node] = m(i)
+    def ++(pairs:List[(CandidateKey, List[CellValue])], n:Node):KeyMap = {
+      val m2:Map[CandidateKey,  Map[List[CellValue], Node]] =
+	pairs.foldLeft(m)((m, p) => {
+	  if (m.get(p._1).isDefined) {
+	    val byKey = m(p._1)
+	    if (byKey.get(p._2).isDefined) {
+	      error("tried to set " + p._1 + p._2 + " = " + n + "(was " + byKey(p._2) + ")")
+	    } else {
+	      val im1 = byKey ++ Map[List[CellValue], Node](p._2 -> n)
+	      m ++ Map[CandidateKey, Map[List[CellValue], Node]](p._1 -> im1)
+	    }
+	  } else {
+	    m ++ Map[CandidateKey, Map[List[CellValue], Node]](p._1 -> Map(p._2 -> n))
+	  }
+	})
+      KeyMap(m2)
+    }
+  }
   type NodeMap = Map[RelName, KeyMap]
 
   // Transformation argument:
@@ -109,72 +131,16 @@
 
   // Mapping functions:
   def databasemap (u:StemIRI, db:Database) : RDFGraph = {
-    val idxables:Set[RelName] = db.m.keySet.filter(rn => db.m(rn).keys.size > 0)
-    val nodes:NodeMap = idxables.map(rn => rn -> relation2subject(u, rn, db.m(rn))).toMap
-    db.m.keySet.flatMap(rn => relationmap(u, rn, db.m(rn), nodes))
+    val nodes:NodeMap = db.idxables.map(rn => rn -> relation2subject(u, rn, db.m(rn))).toMap
+    db.m.keySet.flatMap(rn => relationmap(u, rn, db.m(rn), nodes, db))
   }
 
   def relation2subject (u:StemIRI, rn:RelName, r:Relation) : KeyMap = {
-
-    // Here's a built-In test to make sure we don't screw this up:
-    val ck1:CandidateKey = List("name", "ssn")
-    val ck2:CandidateKey = List("ID")
-    val v11:List[CellValue] = List(LexicalValue("bob"), LexicalValue("123"))
-    val v21:List[CellValue] = List(LexicalValue("alice"), LexicalValue("8"))
-    val v12:List[CellValue] = List(LexicalValue("18"))
-    val v22:List[CellValue] = List(LexicalValue("23"))
-    val s1:Node = BNode("1")
-    val s2:Node = BNode("2")
-    val data:Set[(List[(CandidateKey, List[CellValue])], Node)] =
-      Set((List((ck1, v11),(ck2, v21)), s1),
-	  (List((ck1, v12),(ck2, v22)), s2))
-    val test = data.foldLeft(Map[CandidateKey, Map[List[CellValue], Node]]())((m, t) => {
-      val pairs = t._1
-      pairs.foldLeft(m)((m, p) => {
-	if (m.get(p._1).isDefined) {
-	  val byKey = m(p._1)
-	  if (byKey.get(p._2).isDefined) {
-	    error("tried to set " + rn + p._1 + p._2 + " = " + t._2 + "(was " + byKey(p._2) + ")")
-	  } else {
-	    val im1 = byKey ++ Map[List[CellValue], Node](p._2 -> t._2)
-	    m ++ Map[CandidateKey, Map[List[CellValue], Node]](p._1 -> im1)
-	  }
-	} else {
-	  m ++ Map[CandidateKey, Map[List[CellValue], Node]](p._1 -> Map(p._2 -> t._2))
-	}
-      })
+    val m = KeyMap(Map[CandidateKey, Map[List[CellValue], Node]]())
+    body(r).foldLeft(m)((m, t) => {
+      val s = tuple2subject(u, rn, t, r)
+      m ++ (s._1, s._2)
     })
-
-    val goal:Map[CandidateKey, Map[List[CellValue], Node]] =
-      Map(ck1 -> Map(v11 -> s1,
-      		     v12 -> s2),
-      	  ck2 -> Map(v21 -> s1,
-      		     v22 -> s2))
-    assert(goal == test)
-
-    // Now the useful invocation:
-    val data2:Set[(List[(CandidateKey, List[CellValue])], Node)] = body(r).map(t => {
-      // (List(List("name", "ssn"), List("ID")), List(List("bob", 123), List(18)), 1)
-      // (List(List("name", "ssn"), List("ID")), List(List("alice", 8), List(23)), 2)
-      tuple2subject(u, rn, t, r)
-    })
-    data2.foldLeft(Map[CandidateKey, Map[List[CellValue], Node]]())((m, t) => {
-      val pairs = t._1
-      pairs.foldLeft(m)((m, p) => {
-	if (m.get(p._1).isDefined) {
-	  val byKey = m(p._1)
-	  if (byKey.get(p._2).isDefined) {
-	    error("tried to set " + rn + p._1 + p._2 + " = " + t._2 + "(was " + byKey(p._2) + ")")
-	  } else {
-	    val im1 = byKey ++ Map[List[CellValue], Node](p._2 -> t._2)
-	    m ++ Map[CandidateKey, Map[List[CellValue], Node]](p._1 -> im1)
-	  }
-	} else {
-	  m ++ Map[CandidateKey, Map[List[CellValue], Node]](p._1 -> Map(p._2 -> t._2))
-	}
-      })
-    })
-
   }
 
   def tuple2subject (u:StemIRI, rn:RelName, t:Tuple, r:Relation) : (List[(CandidateKey, List[CellValue])], Node) = {
@@ -186,21 +152,21 @@
 	nodemap(u, rn, r.pk.get, vs)
       } else
 	freshbnode()
-    (r.keys.map(k => {
+    (r.candidates.map(k => {
       val values:List[CellValue] = k.map(a => t(a))
       (k, values)
     }), s)
   }
 
-  def relationmap (u:StemIRI, rn:RelName, r:Relation, nodes:NodeMap) : RDFGraph =
-    body(r).flatMap(t => tuplemap(u, rn, t, r, nodes))
+  def relationmap (u:StemIRI, rn:RelName, r:Relation, nodes:NodeMap, db:Database) : RDFGraph =
+    body(r).flatMap(t => tuplemap(u, rn, t, r, nodes, db))
 
-  def tuplemap (u:StemIRI, rn:RelName, t:Tuple, r:Relation, nodes:NodeMap) : Set[Triple] = {
+  def tuplemap (u:StemIRI, rn:RelName, t:Tuple, r:Relation, nodes:NodeMap, db:Database) : Set[Triple] = {
     val h = header(r)
     val s:Node =
-      if (nodes.get(rn).isDefined) {
+      if (r.candidates.size > 0) { // which implies !nodes.get(rn).isDefined
 	// Known to have at least one key, so take the first one.
-	val k = r.keys(0)
+	val k = r.candidates(0)
 	// Assume: no NULLs in candidate key
 	val vs = k.map(a => lexvalue(h, t, a).get)
 	nodes(rn)(k)(vs)
@@ -221,7 +187,7 @@
     val referencelist = r.fks.keySet -- nullFKs
 
     scalarlist.map(a => scalartriples(u, rn, s, a, h, t)) ++
-    referencelist.map(as => referencetriples(u, rn, s, as, r, t, nodes))
+    referencelist.map(as => referencetriples(u, rn, s, as, r, t, nodes, db))
 
   }
 
@@ -238,12 +204,15 @@
     val o = literalmap(l, sqlDatatype(h, a))
     Triple(s, p, o)
   }
-  def referencetriples (u:StemIRI, rn:RelName, s:Node, as:List[AttrName], r:Relation, t:Tuple, nodes:NodeMap) : Triple = {
+  def referencetriples (u:StemIRI, rn:RelName, s:Node, as:List[AttrName], r:Relation, t:Tuple, nodes:NodeMap, db:Database) : Triple = {
     val p = predicatemap (u, rn, as)
     val ls:List[LexicalValue] = as.map(a =>t(a).asInstanceOf[LexicalValue])
     val target = r.fks(as)
     val o999 = nodemap(u, target.rel, target.attrs, ls)
     val o:Object = nodes(target.rel)(target.attrs)(ls)
+    // if (db.m(target.rel).fks.contains(target.attrs))
+    //   error("need to follow " + target.rel + target.attrs + "->" + db.m(target.rel).fks(target.attrs))
+    // println("need to follow " + target.rel + target.attrs)
     Triple(s, p, o)
   }
 
--- a/src/test/scala/Test.scala	Tue Sep 28 09:04:23 2010 -0400
+++ b/src/test/scala/Test.scala	Tue Sep 28 18:23:51 2010 -0400
@@ -311,6 +311,29 @@
     assert (expected === g)
   }
 
+  test("NodeMap") {
+
+    val ck1:CandidateKey = List("name", "ssn")
+    val ck2:CandidateKey = List("ID")
+    val v11:List[CellValue] = List(LexicalValue("bob"), LexicalValue("123"))
+    val v21:List[CellValue] = List(LexicalValue("alice"), LexicalValue("8"))
+    val v12:List[CellValue] = List(LexicalValue("18"))
+    val v22:List[CellValue] = List(LexicalValue("23"))
+    val s1:Node = BNode("1")
+    val s2:Node = BNode("2")
+    val data:Set[(List[(CandidateKey, List[CellValue])], Node)] =
+      Set((List((ck1, v11),(ck2, v21)), s1),
+	  (List((ck1, v12),(ck2, v22)), s2))
+    val test = data.foldLeft(KeyMap(Map[CandidateKey,  Map[List[CellValue], Node]]()))((m, t) => m ++ (t._1, t._2))
+
+    val goal:KeyMap = KeyMap(
+      Map(ck1 -> Map(v11 -> s1,
+      		     v12 -> s2),
+      	  ck2 -> Map(v21 -> s1,
+      		     v22 -> s2))
+    )
+    assert(goal === test)
+  }
 
   test("2 Employees") {
     val employees = Relation(Header(Map("ID" -> SQLInt(),