~ cleaning up
authorEric Prud'hommeaux <eric@w3.org>
Wed, 29 Sep 2010 00:28:35 -0400
changeset 29 0e1bfa74e36c
parent 28 4e6c7a41fac0
child 30 7479e15a17e1
~ cleaning up
src/main/scala/Main.scala
--- a/src/main/scala/Main.scala	Tue Sep 28 23:40:05 2010 -0400
+++ b/src/main/scala/Main.scala	Wed Sep 29 00:28:35 2010 -0400
@@ -6,20 +6,46 @@
 object SQL {
 
   case class Database(m:Map[RelName, Relation]) {
+    def apply (rn:RelName) = m(rn)
+    def keySet () = m.keySet
     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 apply (a:AttrName) = m(a)
     def keySet () = m.keySet
-    def apply (a:AttrName) = m(a)
+    def sqlDatatype (a:AttrName) : SQLDatatype = m(a)
   }
   type CandidateKey = List[AttrName]
-  type ForeignKeys = Map[List[AttrName], Target]
+
+  case class ForeignKeys (m:Map[List[AttrName], Target]) {
+    def apply (l:List[AttrName]) = m(l)
+    def keySet () = m.keySet
+    def contains (l:List[AttrName]) = m.contains(l)
+  }
+  implicit def map2fks (m:Map[List[String],Target]) = ForeignKeys(m)
+
   case class Target(rel:RelName, attrs:CandidateKey)
 
   type Body = Set[Tuple]
 
-  type Tuple = Map[AttrName, CellValue]
+  case class Tuple (m:Map[AttrName, CellValue]) {
+    def apply (a:AttrName) = m(a)
+    def lexvalue (a:AttrName) : Option[LexicalValue] = 
+      m(a) match {
+	case ␀() => None
+	case v:LexicalValue => Some(v)
+      }
+    def lexvaluesNoNulls (as:List[AttrName]) = as.map(a => m(a).asInstanceOf[LexicalValue])
+    def nullAttributes (h:Header) : Set[(AttrName)] = {
+      h.keySet.flatMap(a =>
+	m.lexvalue(a) match {
+	  case None => Some(a)
+	  case _ => None
+	})
+    }
+  }
+  implicit def map2tuple (m:Map[AttrName, CellValue]):Tuple = Tuple(m)
 
   abstract class CellValue
   case class LexicalValue (s:String) extends CellValue
@@ -43,14 +69,6 @@
   def header (r:Relation) : Header = r.header
   def body (r:Relation) : Body = r.body
 
-  def lexvalue (h:Header, t:Tuple, a:AttrName) : Option[LexicalValue] = 
-    t(a) match {
-      case ␀() => None
-      case v:LexicalValue => Some(v)
-    }
-
-  def sqlDatatype (h:Header, a:AttrName) : SQLDatatype = h(a)
-
 }
 
 // RDF node types
@@ -125,10 +143,10 @@
   case class NodeMap(m:Map[RelName, KeyMap]) {
     def apply(rn:RelName) = m(rn)
     def ultimateReferent (rn:RelName, k:CandidateKey, vs:List[LexicalValue], db:Database) : Node = {
-      // Issue: What if fk is to a rearrangement of the pk?
-      if (db.m(rn).pk.isDefined && db.m(rn).fks.contains(db.m(rn).pk.get)) {
+      // Issue: What if fk is a rearrangement of the pk, per issue fk-pk-order?
+      if (db(rn).pk.isDefined && db(rn).fks.contains(db(rn).pk.get)) {
 	/** Table's primary key is a foreign key. */
-	val target = db.m(rn).fks(db.m(rn).pk.get)
+	val target = db(rn).fks(db(rn).pk.get)
 	ultimateReferent(target.rel, target.attrs, vs, db)
       } else
 	m(rn)(k)(vs)
@@ -142,25 +160,24 @@
 
   // Mapping functions:
   def databasemap (u:StemIRI, db:Database) : RDFGraph = {
-    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))
+    val nodes = NodeMap(db.idxables.map(rn => rn -> relation2KeyMap(u, rn, db(rn))).toMap)
+    db.keySet.flatMap(rn => relationmap(u, rn, db(rn), nodes, db))
   }
 
-  def relation2subject (u:StemIRI, rn:RelName, r:Relation) : KeyMap = {
+  def relation2KeyMap (u:StemIRI, rn:RelName, r:Relation) : KeyMap = {
     val m = KeyMap(Map[CandidateKey, Map[List[CellValue], Node]]())
     body(r).foldLeft(m)((m, t) => {
-      val s = tuple2subject(u, rn, t, r)
+      val s = rdfNodeForTuple(u, rn, t, r)
       m ++ (s._1, s._2)
     })
   }
 
-  def tuple2subject (u:StemIRI, rn:RelName, t:Tuple, r:Relation) : (List[(CandidateKey, List[CellValue])], Node) = {
+  def rdfNodeForTuple (u:StemIRI, rn:RelName, t:Tuple, r:Relation) : (List[(CandidateKey, List[CellValue])], Node) = {
     val h = header(r)
     val s:Node =
       if (r.pk.isDefined) {
 	/** Table has a primkary key. */
-	// Assume: no NULLs in primary key
-	val vs = r.pk.get.map(k => lexvalue(h, t, k).get)
+	val vs = t.lexvaluesNoNulls(r.pk.get)
 	nodemap(u, rn, r.pk.get, vs)
       } else
 	/** Table has no primkary key (but has some candidate keys). */
@@ -176,7 +193,7 @@
 
   def tuplemap (u:StemIRI, rn:RelName, t:Tuple, r:Relation, nodes:NodeMap, db:Database) : Set[Triple] = {
     val h = header(r)
-    val hierarchicalKey:List[AttrName] =
+    val hierarchicalKey:CandidateKey =
       if (r.pk.isDefined && r.fks.contains(r.pk.get))
 	r.fks(r.pk.get).attrs
       else
@@ -187,7 +204,7 @@
 	// Known to have at least one key, so take the first one.
 	val k = r.candidates(0)
 	// Assume: no NULLs in candidate key
-	val vs = k.map(a => lexvalue(h, t, a).get)
+	val vs = t.lexvaluesNoNulls(k)
 	nodes.ultimateReferent(rn, k, vs, db)
       } else
 	/** Table has no candidate keys. */
@@ -198,7 +215,7 @@
     val unaryFKs:Set[AttrName] = allFKs.flatMap(a => {
       if (a.length == 1) a else None
     })
-    val nulllist = nulls(h, t)
+    val nulllist = t.nullAttributes(h)
     val nullFKs:Set[List[AttrName]] = allFKs.flatMap(a => {
       val int:Set[AttrName] = nulllist & a.toSet
       if (int.toList.length == 0) None else List(a)
@@ -220,26 +237,18 @@
 
   def scalartriples (u:StemIRI, rn:RelName, s:Node, a:AttrName, h:Header, t:Tuple) : Triple = {
     val p = predicatemap (u, rn, List(a))
-    val l = t(a).asInstanceOf[LexicalValue]
-    val o = literalmap(l, sqlDatatype(h, a))
+    val l = t.lexvalue(a).get
+    val o = literalmap(l, h.sqlDatatype(a))
     Triple(s, p, o)
   }
   def referencetriples (u:StemIRI, rn:RelName, s:Node, as:List[AttrName], r:Relation, t:Tuple, nodes:NodeMap) : Triple = {
     val p = predicatemap (u, rn, as)
-    val ls:List[LexicalValue] = as.map(a =>t(a).asInstanceOf[LexicalValue])
+    val ls:List[LexicalValue] = t.lexvaluesNoNulls(as)
     val target = r.fks(as)
     val o:Object = nodes(target.rel)(target.attrs)(ls)
     Triple(s, p, o)
   }
 
-  def nulls (h:Header, t:Tuple) : Set[(AttrName)] = {
-    h.keySet.flatMap(a =>
-      lexvalue(h, t, a) match {
-	case None => Some(a)
-	case _ => None
-      })
-  }
-
   def nodemap (u:StemIRI, rn:RelName, as:List[AttrName], ls:List[LexicalValue]) : IRI = {
     val pairs:List[String] = as.zip(ls).map(x => UE(x._1) + "." + UE(x._2.s))
     u + ("/" + UE(rn) + "/" + pairs.mkString("_") + "#_")