~ n-ary keys
authorEric Prud'hommeaux <eric@w3.org>
Sun, 26 Sep 2010 12:43:33 -0400
changeset 20 ae6390ee0fa4
parent 19 d7d4ffe9d5a7
child 21 402e3f761b4d
~ n-ary keys
src/main/scala/Main.scala
src/test/scala/Test.scala
--- a/src/main/scala/Main.scala	Sun Sep 26 07:48:33 2010 -0400
+++ b/src/main/scala/Main.scala	Sun Sep 26 12:43:33 2010 -0400
@@ -12,14 +12,14 @@
   }
 
   type PrimaryKey = List[AttrName]
-  type ForeignKeys = Map[AttrName, Target]
-  case class Target(rel:RelName, attr:AttrName)
+  type ForeignKeys = Map[List[AttrName], Target]
+  case class Target(rel:RelName, attrs:List[AttrName])
 
   type Body = Set[Tuple]
 
   abstract class CellValue
   case class LexicalValue (s:String) extends CellValue
-  case class ☹ () extends CellValue
+  case class ␀ () extends CellValue
 
   type Tuple = Map[AttrName, CellValue]
 
@@ -31,7 +31,7 @@
   type AttrName = String
 
   // Accessor functions:
-  def pk (h:Header) : AttrName = h.pk(0) // Assume: one primary key.
+  def pk (h:Header) : List[AttrName] = h.pk
   def header (r:Relation) : Header = r.header
   def body (r:Relation) : Body = r.body
 
@@ -97,67 +97,66 @@
 
   def tuplemap (u:StemIRI, rn:RelName, t:Tuple, r:Relation) : Set[Triple] = {
     val h = header(r)
-    val k = pk(h)
-    val s = nodemap(u, rn, k, lexvalue(h, t, k).asInstanceOf[LexicalValue]) // Assume: no NULLs in primary key
+    val vs = pk(h).map(k => lexvalue(h, t, k).asInstanceOf[LexicalValue])
+    val s = nodemap(u, rn, pk(h), vs) // Assume: no NULLs in primary key
 
-    // val nulllist = nulls(h, t)
-    // val scalarlist = h.keySet -- h.fks.keySet -- nulllist /* -- h.pk*/
-    // val referencelist = h.fks.keySet -- nulllist
+    val allAttrs:Set[AttrName] = h.keySet
+    val allFKs:Set[List[AttrName]] = h.fks.keySet
+    val unaryFKs:Set[AttrName] = allFKs.flatMap(a => {
+      if (a.length == 1) {
+	a
+      } else {
+	None
+      }
+    })
+    val nulllist = nulls(h, t)
+    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 scalarlist = allAttrs -- unaryFKs -- nulllist /* -- h.pk*/
+    val referencelist = h.fks.keySet -- nullFKs
 
-    // scalarlist.map(a => scalartriples(u, rn, s, a, h, t)) ++
-    // referencelist.map(a => referencetriples(u, rn, s, a, h, t))
+    scalarlist.map(a => scalartriples(u, rn, s, a, h, t)) ++
+    referencelist.map(as => referencetriples(u, rn, s, as, h, t))
 
-    h.keySet.flatMap(a => cellmap(u, rn, h, a, s, t))
   }
 
 /* BEGIN different approaches { */
 
   def scalartriples (u:StemIRI, rn:RelName, s:IRI, a:AttrName, h:Header, t:Tuple) : Triple = {
-    val p = predicatemap (u, rn, a)
+    val p = predicatemap (u, rn, List(a))
     val l = t(a).asInstanceOf[LexicalValue]
     val o = literalmap(l, sqlDatatype(h, a))
     Triple(s, p, o)
   }
-  def referencetriples (u:StemIRI, rn:RelName, s:IRI, a:AttrName, h:Header, t:Tuple) : Triple = {
-    val p = predicatemap (u, rn, a)
-    val l = t(a).asInstanceOf[LexicalValue]
-    val target = h.fks(a)
-    val o = nodemap(u, target.rel, target.attr, l)
+  def referencetriples (u:StemIRI, rn:RelName, s:IRI, as:List[AttrName], h:Header, t:Tuple) : Triple = {
+    val p = predicatemap (u, rn, as)
+    val ls:List[LexicalValue] = as.map(a =>t(a).asInstanceOf[LexicalValue])
+    val target = h.fks(as)
+    val o = nodemap(u, 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 ☹() => Some(a)
+	case ␀() => Some(a)
 	case _ => None
       })
   }
 
-  def cellmap (u:StemIRI, rn:RelName, h:Header, a:AttrName, s:IRI, t:Tuple) : Option[Triple] = {
-    def hasForeignKeys(a:AttrName):Boolean = h.fks.get(a).isDefined
-    lexvalue(h, t, a) match {
-      // case _ if h.pk contains a => None
-      case ☹()                  => None
-      case l:LexicalValue if hasForeignKeys(a) => {
-	val target = h.fks(a)
-	val p = predicatemap (u, rn, a)
-	val o = nodemap(u, target.rel, target.attr, l)
-	Some(Triple(s, p, o))
-      }
-      case l:LexicalValue => {
-	val p = predicatemap (u, rn, a)
-	val o = literalmap(l, sqlDatatype(h, a))
-	Some(Triple(s, p, o))
-      }
-    }
+  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("_") + "#_")
   }
 
-  def nodemap (u:StemIRI, rn:RelName, a:AttrName, l:LexicalValue) : IRI =
-    u + ("/" + rn + "/" + a + "." + l.s + "#_")
-
-  def predicatemap (u:StemIRI, rn:RelName, a:AttrName) : IRI =
-    u + ("/" + rn + "#" + a)
+  def predicatemap (u:StemIRI, rn:RelName, as:List[AttrName]) : IRI =
+    u + ("/" + UE(rn) + "#" + as.mkString("_"))
 
   def XSD (d:SQLDatatype) : IRI =
     d match {
@@ -167,6 +166,7 @@
 
   def literalmap (l:LexicalValue, d:SQLDatatype) : TypedLiteral =
     TypedLiteral(l.s, XSD(d))
-  
+
+  def UE (s:String) : String = s
 }
 
--- a/src/test/scala/Test.scala	Sun Sep 26 07:48:33 2010 -0400
+++ b/src/test/scala/Test.scala	Sun Sep 26 12:43:33 2010 -0400
@@ -13,7 +13,7 @@
 					"city" -> SQLString(),
 					"state" -> SQLString()),
 				    List("ID"),
-				    Map[AttrName, Target]()),
+				    Map()),
 			     Set(Map("ID" -> LexicalValue("18"),
 				     "city" -> LexicalValue("Cambridge"),
 				     "state" -> LexicalValue("MA"))))
@@ -22,15 +22,13 @@
 				     "fname" -> SQLString(),
 				     "addr" -> SQLInt()),
 				 List("ID"),
-				 Map[AttrName, Target](
-				   "addr" -> Target("Addresses", "ID")
-				 )),
+				 Map(List("addr") -> Target("Addresses", List("ID")))),
 			  Set(Map("ID" -> LexicalValue("7"),
 				  "fname" -> LexicalValue("Bob"),
 				  "addr" -> LexicalValue("18")),
 			      Map("ID" -> LexicalValue("8"),
 				  "fname" -> LexicalValue("Sue"),
-				  "addr" -> ☹())))
+				  "addr" -> ␀())))
 
     val db = Database(Map("Addresses" -> addresses, 
 			  "People" -> people))
@@ -56,12 +54,10 @@
 					"fname" -> SQLString(),
 					"boss" -> SQLInt()),
 				    List("ID"),
-				    Map[AttrName, Target](
-				      "boss" -> Target("Employees", "ID")
-				    )),
+				    Map(List("boss") -> Target("Employees", List("ID")))),
 			     Set(Map("ID" -> LexicalValue("1"),
 				     "fname" -> LexicalValue("Alice"),
-				     "boss" -> ☹()),
+				     "boss" -> ␀()),
 				 Map("ID" -> LexicalValue("2"),
 				     "fname" -> LexicalValue("Bob"),
 				     "boss" -> LexicalValue("1"))