~ blind refactoring targetting RDB and the Direct Mapping
authorAlexandre Bertails <bertails@w3.org>
Mon, 17 Jan 2011 15:38:26 -0500
changeset 306 1c9d2ae8d049
parent 305 3104ca7c8c2f
child 307 6adb6a0a5243
~ blind refactoring targetting RDB and the Direct Mapping
directmapping/src/main/scala/DirectMapping.scala
rdb/src/main/scala/RDB.scala
sql/src/main/scala/SQL.scala
sql/src/test/scala/SQLTest.scala
--- a/directmapping/src/main/scala/DirectMapping.scala	Thu Jan 13 16:40:53 2011 -0500
+++ b/directmapping/src/main/scala/DirectMapping.scala	Mon Jan 17 15:38:26 2011 -0500
@@ -17,33 +17,33 @@
       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))
+          pairs.foldLeft(m) { case (m, (ck, cellValues)) => {
+            m.get(ck) match {
+              case Some(byKey) if byKey.get(cellValues).isDefined =>
+                error("tried to set " + ck + cellValues + " = " + n + "(was " + byKey(cellValues) + ")")
+              case Some(byKey) =>
+                m + (ck -> (byKey + (cellValues -> n)))
+              case None =>
+                m + (ck -> Map(cellValues -> n))
             }
-          })
+          } }
         KeyMap(m2)
       }
-      def contains(ck:CandidateKey) = m.contains(ck)
+      def contains(ck:CandidateKey) = m contains ck
     }
     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 a rearrangement of the pk, per issue fk-pk-order?
-        if (db(rn).pk.isDefined && db(rn).fks.contains(db(rn).pk.get.attrs)) {
-          /** Table's primary key is a foreign key. */
-          val target = db(rn).fks(db(rn).pk.get.attrs)
-          ultimateReferent(target.rel, target.key, vs, db)
-        } else
-          m(rn)(k)(vs)
+        db(rn).pk match {
+          case Some(pk) if db(rn).fks contains (pk.attrs) => {
+            /** Table's primary key is a foreign key. */
+            val target = db(rn).fks(pk.attrs)
+            ultimateReferent(target.rel, target.key, vs, db)
+          }
+          case _ =>
+            m(rn)(k)(vs)  
+        }
       }
       def contains(rn:RelName) = m.contains(rn)
     }
@@ -61,65 +61,62 @@
      */
   
     def references (t:Tuple, r:Relation):Set[List[AttrName]] = {
-      val allFKs:Set[List[AttrName]] = r.fks.keySet.toSet
+      val allFKs:Set[List[AttrName]] = r.fks.keySet
       val nulllist:Set[AttrName] = t.nullAttributes(r.header)
-      val nullFKs:Set[List[AttrName]] = allFKs.flatMap(a => {
-        val int:Set[AttrName] = nulllist & a.toSet
-        if (int.toList.length == 0) None else List(a)
-      })
+      val nullFKs:Set[List[AttrName]] = allFKs filter { fk => (nulllist & fk.toSet) nonEmpty  }
   
       /** Check to see if r's primary key is a hierarchical key.
        * http://www.w3.org/2001/sw/rdb2rdf/directGraph/#rule3 */
-      if (r.pk.isDefined && r.fks.contains(r.pk.get.attrs))
-        r.fks.keySet.toSet -- nullFKs - r.fks(r.pk.get.attrs).key.attrs
-      else
-        r.fks.keySet.toSet -- nullFKs
+      r.pk match {
+        case Some(pk) if r.fks contains (pk.attrs) =>
+          r.fks.keySet -- nullFKs - r.fks(pk.attrs).key.attrs
+        case _ =>
+          r.fks.keySet -- nullFKs
+      }
     }
   
     def scalars (t:Tuple, r:Relation):Set[AttrName] = {
-      val allAttrs:Set[AttrName] = r.header.keySet.toSet
-      val allFKs:Set[List[AttrName]] = r.fks.keySet.toSet
-      val unaryFKs:Set[AttrName] = allFKs.flatMap(a => {
-        if (a.length == 1) a else None
-      })
+      val allAttrs:Set[AttrName] = r.header.keySet
+      val allFKs:Set[List[AttrName]] = r.fks.keySet
+      val unaryFKs:Set[AttrName] = allFKs filter { _.length == 1 } flatten
       val nulllist:Set[AttrName] = t.nullAttributes(r.header)
   
       /** Check to see if r's primary key is a hierarchical key.
        * http://www.w3.org/2001/sw/rdb2rdf/directGraph/#rule3 */
-      if (r.pk.isDefined && r.fks.contains(r.pk.get.attrs))
-        allAttrs -- unaryFKs -- nulllist ++ r.fks(r.pk.get.attrs).key.attrs
-      else
-        allAttrs -- unaryFKs -- nulllist
+      r.pk match {
+        case Some(pk) if r.fks contains (pk.attrs) =>
+          allAttrs -- unaryFKs -- nulllist ++ r.fks(pk.attrs).key.attrs
+        case _ =>
+          allAttrs -- unaryFKs -- nulllist
+      }
     }
   
     /** The NodeMap-generating functions: */
     def relation2KeyMap (r:Relation) : KeyMap = {
       val m = KeyMap(Map[CandidateKey, Map[List[CellValue], Node]]())
-      r.body.foldLeft(m)((m, t) => {
+      r.body.foldLeft(m) { (m, t) => {
         val (pairs, node) = rdfNodeForTuple(t, r)
         m ++ (pairs, node)
-      })
+      } }
     }
   
     def rdfNodeForTuple (t:Tuple, r:Relation) : (List[(CandidateKey, List[CellValue])], Node) = {
       val s:Node =
-        if (r.pk.isDefined) {
-          /** Table has a primkary key. */
-          val vs = t.lexvaluesNoNulls(r.pk.get.attrs)
-          NodeIRI(nodemap(r.name, r.pk.get.attrs, vs))
-        } else
-          /** Table has no primkary key (but has some candidate keys). */
-          NodeBNode(freshbnode())
-      (r.candidates.map(k => {
-        val values:List[CellValue] = k.attrs.map(a => t(a))
-        (k, values)
-      }), s)
+        r.pk match {
+          case Some(pk) =>
+            /** Table has a primkary key. */
+            NodeIRI(nodemap(r.name, pk.attrs, t.lexvaluesNoNulls(pk.attrs)))
+          case None =>
+            /** Table has no primkary key (but has some candidate keys). */
+            NodeBNode(freshbnode())
+        }
+      (r.candidates map { k => (k, k.attrs map { t(_) }) }, s)
     }
   
     /** The triples-generating functions start with databasemap: */
     def directDB (db:Database) : Graph = {
-      val idxables = db.keySet.toSet filter { rn => !db(rn).candidates.isEmpty }
-      val nodeMap:NodeMap = idxables map {rn => rn -> relation2KeyMap(db(rn))}
+      val idxables = db.keySet filter { rn => db(rn).candidates nonEmpty }
+      val nodeMap:NodeMap = idxables map { rn => rn -> relation2KeyMap(db(rn)) }
       Graph(db.keySet flatMap  { (rn:RelName) => directR(db(rn), nodeMap, db) })
     }
   
@@ -132,22 +129,25 @@
   
     def directT (t:Tuple, r:Relation, nodes:NodeMap, db:Database) : Set[Triple] = {
       val s:Node =
-        if (r.candidates.size > 0) {
+        r.candidates.headOption match {
           // Known to have at least one key, so take the first one.
-          val k = r.candidates(0)
-          val vs = t.lexvaluesNoNulls(k.attrs)
-          nodes.ultimateReferent(r.name, k, vs, db)
-        } else
+          case Some(firstKey) => {
+            val vs = t.lexvaluesNoNulls(firstKey.attrs)
+            nodes.ultimateReferent(r.name, firstKey, vs, db)
+          }
           /** Table has no candidate keys. */
-          NodeBNode(freshbnode())
+          case None =>
+            NodeBNode(freshbnode())  
+        }
       directS(s, t, r, nodes, db)
     }
   
     def directS (s:Node, t:Tuple, r:Relation, nodes:NodeMap, db:Database) : Set[Triple] = {
-      references(t, r).map(as => directN(s, as, r, t, nodes)) ++
-      scalars(t, r).map(a => directL(r.name, s, a, r.header, t))
+      ( references(t, r) map { directN(s, _, r, t, nodes) } ) ++
+      ( scalars(t, r)    map { directL(r.name, s, _, r.header, t) } )
     }
   
+    // should be done by BNode
     var NextBNode = 97
     def freshbnode () : BNode = {
       val ret = NextBNode
@@ -157,12 +157,14 @@
   
     def directL (rn:RelName, s:Node, a:AttrName, h:Header, t:Tuple) : Triple = {
       val p = predicatemap (rn, List(a))
+      // hrmmmmm
       val l = t.lexvalue(a).get
       val o = literalmap(l, h.sqlDatatype(a))
       Triple(SubjectNode(s),
              PredicateIRI(p),
              ObjectLiteral(o))
     }
+
     def directN (s:Node, as:List[AttrName], r:Relation, t:Tuple, nodes:NodeMap) : Triple = {
       val p = predicatemap (r.name, as)
       val ls:List[LexicalValue] = t.lexvaluesNoNulls(as)
@@ -182,13 +184,14 @@
     implicit def attrName2string (rn:AttrName) = rn.n
   
     def nodemap (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))
+      val pairs:List[String] = as.zip(ls) map { case (attrName, lexicalValue) => UE(attrName) + "." + UE(lexicalValue.s) }
       IRI(UE(rn) + "/" + pairs.mkString("_") + "#_")
     }
   
     def predicatemap (rn:RelName, as:List[AttrName]) : IRI =
       IRI(UE(rn) + "#" + as.mkString("_"))
-  
+
+    // TODO: aren't they already part of the RDF model?
     def XSD (d:Datatype) : IRI =
       d match {
         case Datatype.INTEGER => IRI("http://www.w3.org/2001/XMLSchema#integer")
--- a/rdb/src/main/scala/RDB.scala	Thu Jan 13 16:40:53 2011 -0500
+++ b/rdb/src/main/scala/RDB.scala	Mon Jan 17 15:38:26 2011 -0500
@@ -7,45 +7,43 @@
 
   case class Database (m:Map[RelName, Relation]) {
     def apply (rn:RelName) = m(rn)
-    def keySet () = m.keySet
+    def keySet = m.keySet.toSet
   }
   object Database {
-    def apply (l:(Relation)*):Database =
-      Database(l.map{r => (r.name -> r)}.toMap)
+    def apply (l:Relation*):Database =
+      Database(l map { r => (r.name -> r) } toMap)
   }
 
   case class Relation (name:RelName, header:Header, body:List[Tuple], candidates:List[CandidateKey], pk:Option[CandidateKey], fks:ForeignKeys) {
-    def ++ (t:Tuple):Relation = {
-      val b2:List[RDB.Tuple] = body ++ List(t)
-      Relation(name, header, b2, candidates, pk, fks)
-    }
+    // TODO: should be + instead of ++
+    def ++ (t:Tuple):Relation = this.copy(body = body :+ t)
   }
 
   case class Header (m:Map[AttrName, Datatype]) {
     def apply (a:AttrName) = m(a)
-    def keySet () = m.keySet.toSet
+    def keySet = m.keySet.toSet
     def sqlDatatype (a:AttrName) : Datatype = m(a)
-    def contains (a:AttrName) : Boolean = m.contains(a)
+    def contains (a:AttrName) : Boolean = m contains a
   }
   object Header {
     def apply (s:(String, Datatype)*):Header =
-      Header(s.map{p => (AttrName(p._1), p._2)}.toMap)
+      Header(s map { case (name, datatype) => (AttrName(name), datatype) } toMap)
   }
   case class CandidateKey (attrs:List[AttrName])
   object CandidateKey {
-    def apply (l:(String)*):CandidateKey =
-      CandidateKey(l.map{s => AttrName(s)}.toList)
+    def apply (l:String*):CandidateKey =
+      CandidateKey(l.toList map { AttrName(_) })
   }
   implicit def cc2list (cc:CandidateKey) = cc.attrs
 
   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)
+    def keySet = m.keySet.toSet
+    def contains (l:List[AttrName]) = m contains l
   }
   object ForeignKeys {
     def apply (s:(List[String], Target)*):ForeignKeys =
-      ForeignKeys(s.map{p => (p._1.map{s => AttrName(s)}, p._2)}.toMap)
+      ForeignKeys(s map { case (keys, target) => (keys map { AttrName(_) }, target)} toMap)
   }
 
   case class Target (rel:RelName, key:CandidateKey)
@@ -70,26 +68,20 @@
     def apply (a:AttrName) = m(a)
     def lexvalue (a:AttrName) : Option[LexicalValue] = 
       m(a) match {
-	case ␀() => None
+	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 =>
-	lexvalue(a) match {
-	  case None => Some(a)
-	  case _ => None
-	})
-    }
+    def lexvaluesNoNulls (as:List[AttrName]) = as map { m(_).asInstanceOf[LexicalValue] }
+    def nullAttributes (h:Header) : Set[AttrName] = h.keySet filter { lexvalue(_) isEmpty }
   }
   object Tuple {
     def apply (s:(String, CellValue)*):Tuple =
-      Tuple(s.map{p => (AttrName(p._1), p._2)}.toMap)
+      Tuple(s map { case (name, cellValue) => (AttrName(name), cellValue) } toMap)
   }
 
   abstract class CellValue
   case class LexicalValue (s:String) extends CellValue
-  case class ␀ () extends CellValue
+  case object ␀ extends CellValue
 
   case class RelName(n:String) {
     override def toString = n
--- a/sql/src/main/scala/SQL.scala	Thu Jan 13 16:40:53 2011 -0500
+++ b/sql/src/main/scala/SQL.scala	Mon Jan 17 15:38:26 2011 -0500
@@ -419,7 +419,7 @@
       int ^^ { i => RDB.LexicalValue(i) }
     | dquote  ^^ { x => RDB.LexicalValue(x.substring(1, x.size - 1)) }
     | squote  ^^ { x => RDB.LexicalValue(x.substring(1, x.size - 1)) }
-    | "NULL" ^^ { case "NULL" => RDB.␀() }
+    | "NULL" ^^ { case "NULL" => RDB.␀ }
   )
 
 }
--- a/sql/src/test/scala/SQLTest.scala	Thu Jan 13 16:40:53 2011 -0500
+++ b/sql/src/test/scala/SQLTest.scala	Mon Jan 17 15:38:26 2011 -0500
@@ -682,7 +682,7 @@
 		     "addr" -> RDB.LexicalValue("18")),
 	   RDB.Tuple("ID" -> RDB.LexicalValue("8"),
 		     "fname" -> RDB.LexicalValue("Sue"),
-		     "addr" -> RDB.␀())),
+		     "addr" -> RDB.␀)),
       List(RDB.CandidateKey("ID")),
       Some(RDB.CandidateKey("ID")),
       RDB.ForeignKeys(List("addr") -> RDB.Target("Addresses", RDB.CandidateKey("ID"))))
@@ -735,9 +735,9 @@
 		     "deptCity" -> RDB.LexicalValue("Cambridge")),
 	   RDB.Tuple("ID" -> RDB.LexicalValue("8"),
 		     "fname" -> RDB.LexicalValue("Sue"),
-		     "addr" -> RDB.␀(),
-		     "deptName" -> RDB.␀(),
-		     "deptCity" -> RDB.␀())),
+		     "addr" -> RDB.␀,
+		     "deptName" -> RDB.␀,
+		     "deptCity" -> RDB.␀)),
       List(RDB.CandidateKey("ID")),
       Some(RDB.CandidateKey("ID")),
       RDB.ForeignKeys(List("addr") -> RDB.Target("Addresses", RDB.CandidateKey("ID")),
@@ -824,9 +824,9 @@
 		     "deptCity" -> RDB.LexicalValue("Cambridge")),
 	   RDB.Tuple("ID" -> RDB.LexicalValue("8"),
 		     "fname" -> RDB.LexicalValue("Sue"),
-		     "addr" -> RDB.␀(),
-		     "deptName" -> RDB.␀(),
-		     "deptCity" -> RDB.␀())),
+		     "addr" -> RDB.␀,
+		     "deptName" -> RDB.␀,
+		     "deptCity" -> RDB.␀)),
       List(RDB.CandidateKey("ID")),
       Some(RDB.CandidateKey("ID")),
       RDB.ForeignKeys(List("addr") -> RDB.Target("Addresses", RDB.CandidateKey("ID")),