~ removing types, adding objects
authorEric Prud'hommeaux <eric@w3.org>
Tue, 12 Oct 2010 02:30:29 -0400
changeset 35 527a7792e4b6
parent 34 7e65c7f1f9c8
child 36 15ef23dfd492
~ removing types, adding objects
src/main/scala/Main.scala
src/test/scala/Test.scala
--- a/src/main/scala/Main.scala	Fri Oct 08 15:45:30 2010 -0400
+++ b/src/main/scala/Main.scala	Tue Oct 12 02:30:29 2010 -0400
@@ -9,8 +9,6 @@
     def apply (rn:RelName) = m(rn)
     def keySet () = m.keySet
   }
-  implicit def l2db (rs:List[Relation]):Map[RelName, Relation] =
-    rs.map(r => (r.name -> r)).toMap
 
   case class Relation (name:RelName, header:Header, body:Body, candidates:List[CandidateKey], pk:Option[CandidateKey], fks:ForeignKeys)
   case class Header (m:Map[AttrName, SQLDatatype]) {
@@ -18,6 +16,10 @@
     def keySet () = m.keySet
     def sqlDatatype (a:AttrName) : SQLDatatype = m(a)
   }
+  object Header {
+    def apply (s:(String, SQLDatatype)*):Header =
+      Header(s.map{p => (AttrName(p._1), p._2)}.toMap)
+  }
   type CandidateKey = List[AttrName]
 
   case class ForeignKeys (m:Map[List[AttrName], Target]) {
@@ -25,7 +27,10 @@
     def keySet () = m.keySet
     def contains (l:List[AttrName]) = m.contains(l)
   }
-  implicit def map2fks (m:Map[List[String],Target]) = ForeignKeys(m)
+  object ForeignKeys {
+    def apply (s:(List[String], Target)*):ForeignKeys =
+      ForeignKeys(s.map{p => (p._1.map{s => AttrName(s)}, p._2)}.toMap)
+  }
 
   case class Target (rel:RelName, attrs:CandidateKey)
 
@@ -51,25 +56,25 @@
     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 {
+	lexvalue(a) match {
 	  case None => Some(a)
 	  case _ => None
 	})
     }
   }
-  implicit def map2tuple (m:Map[AttrName, CellValue]):Tuple = Tuple(m)
+  object Tuple {
+    def apply (s:(String, CellValue)*):Tuple =
+      Tuple(s.map{p => (AttrName(p._1), p._2)}.toMap)
+  }
 
   abstract class CellValue
   case class LexicalValue (s:String) extends CellValue
   case class ␀ () extends CellValue
 
-  type RelName = String
-  type AttrName = String
-
-  // Accessor functions:
-  def pk (r:Relation) : Option[List[AttrName]] = r.pk
-  def header (r:Relation) : Header = r.header
-  def body (r:Relation) : Body = r.body
+  case class RelName(n:String)
+  case class AttrName(n:String) {
+    override def toString = n
+  }
 
 }
 
@@ -101,7 +106,9 @@
   implicit def bnode2objectnode(b:BNode):Object = ObjectNode(b)
   case class ObjectLiteral (n:Literal) extends Object
 
-  case class IRI(iri:String)
+  case class IRI(iri:String) {
+    override def toString = '"' + iri + '"'
+  }
   case class BNode(label:String)
 
   sealed abstract class Literal
@@ -204,7 +211,7 @@
   /** The NodeMap-generating functions: */
   def relation2KeyMap (u:StemIRI, r:Relation) : KeyMap = {
     val m = KeyMap(Map[CandidateKey, Map[List[CellValue], Node]]())
-    body(r).foldLeft(m)((m, t) => {
+    r.body.foldLeft(m)((m, t) => {
       val (pairs, node) = rdfNodeForTuple(u, t, r)
       m ++ (pairs, node)
     })
@@ -233,7 +240,7 @@
   }
 
   def directR (u:StemIRI, r:Relation, nodes:NodeMap, db:Database) : RDFGraph =
-    body(r).flatMap(t => directT(u, t, r, nodes, db))
+    r.body.flatMap(t => directT(u, t, r, nodes, db))
 
   def directT (u:StemIRI, t:Tuple, r:Relation, nodes:NodeMap, db:Database) : Set[Triple] = {
     val s:Node =
@@ -274,6 +281,10 @@
     Triple(s, p, o)
   }
 
+  // These implicits make nodemap and predicatemap functions prettier.
+  implicit def relName2string (rn:RelName) = rn.n
+  implicit def attrName2string (rn:AttrName) = rn.n
+
   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("_") + "#_")
--- a/src/test/scala/Test.scala	Fri Oct 08 15:45:30 2010 -0400
+++ b/src/test/scala/Test.scala	Tue Oct 12 02:30:29 2010 -0400
@@ -8,32 +8,37 @@
 
 class Test extends FunSuite {
 
+  implicit def l2db (rs:List[Relation]):Map[RelName, Relation] =
+    rs.map(r => (r.name -> r)).toMap
+  implicit def string2relName (n:String) = RelName(n)
+  implicit def string2attrName (n:String) = AttrName(n)
+
   test("2 People 1 Addresses") {
 
     val addrs = Relation("Addresses",
-			 Header(Map("ID" -> SQLInt(),
-				    "city" -> SQLString(),
-				    "state" -> SQLString())),
-			 Set(Map("ID" -> LexicalValue("18"),
-				 "city" -> LexicalValue("Cambridge"),
-				 "state" -> LexicalValue("MA"))),
+			 Header("ID" -> SQLInt(),
+				"city" -> SQLString(),
+				"state" -> SQLString()),
+			 Set(Tuple("ID" -> LexicalValue("18"),
+				   "city" -> LexicalValue("Cambridge"),
+				   "state" -> LexicalValue("MA"))),
 			 List(List("ID")),
 			 Some(List("ID")),
-			 Map())
+			 ForeignKeys())
 
     val people = Relation("People",
-			  Header(Map("ID" -> SQLInt(),
-				     "fname" -> SQLString(),
-				     "addr" -> SQLInt())),
-			  Set(Map("ID" -> LexicalValue("7"),
-				  "fname" -> LexicalValue("Bob"),
-				  "addr" -> LexicalValue("18")),
-			      Map("ID" -> LexicalValue("8"),
-				  "fname" -> LexicalValue("Sue"),
-				  "addr" -> ␀())),
+			  Header("ID" -> SQLInt(),
+				 "fname" -> SQLString(),
+				 "addr" -> SQLInt()),
+			  Set(Tuple("ID" -> LexicalValue("7"),
+				    "fname" -> LexicalValue("Bob"),
+				    "addr" -> LexicalValue("18")),
+			      Tuple("ID" -> LexicalValue("8"),
+				    "fname" -> LexicalValue("Sue"),
+				    "addr" -> ␀())),
 			  List(List("ID")),
 			  Some(List("ID")),
-			  Map(List("addr") -> Target("Addresses", List("ID"))))
+			  ForeignKeys(List("addr") -> Target("Addresses", List("ID"))))
 
     val db = Database(List(addrs, people))
     val g = directDB(StemIRI("http://foo.example/DB"), db)
@@ -57,49 +62,49 @@
   test("2 People 1 Addresses 1 Department") {
 
     val addrs = Relation("Addresses",
-			 Header(Map("ID" -> SQLInt(),
-				    "city" -> SQLString(),
-				    "state" -> SQLString())),
-			 Set(Map("ID" -> LexicalValue("18"),
-				 "city" -> LexicalValue("Cambridge"),
-				 "state" -> LexicalValue("MA"))),
+			 Header("ID" -> SQLInt(),
+				"city" -> SQLString(),
+				"state" -> SQLString()),
+			 Set(Tuple("ID" -> LexicalValue("18"),
+				   "city" -> LexicalValue("Cambridge"),
+				   "state" -> LexicalValue("MA"))),
 			 List(List("ID")),
 			 Some(List("ID")),
-			 Map())
+			 ForeignKeys())
 
     val people = Relation("People",
-			  Header(Map("ID" -> SQLInt(),
-				     "fname" -> SQLString(),
-				     "addr" -> SQLInt(),
-				     "deptName" -> SQLString(),
-				     "deptCity" -> SQLString())),
-			  Set(Map("ID" -> LexicalValue("7"),
-				  "fname" -> LexicalValue("Bob"),
-				  "addr" -> LexicalValue("18"),
-				  "deptName" -> LexicalValue("accounting"),
-				  "deptCity" -> LexicalValue("Cambridge")),
-			      Map("ID" -> LexicalValue("8"),
-				  "fname" -> LexicalValue("Sue"),
-				  "addr" -> ␀(),
-				  "deptName" -> ␀(),
-				  "deptCity" -> ␀())),
+			  Header("ID" -> SQLInt(),
+				 "fname" -> SQLString(),
+				 "addr" -> SQLInt(),
+				 "deptName" -> SQLString(),
+				 "deptCity" -> SQLString()),
+			  Set(Tuple("ID" -> LexicalValue("7"),
+				    "fname" -> LexicalValue("Bob"),
+				    "addr" -> LexicalValue("18"),
+				    "deptName" -> LexicalValue("accounting"),
+				    "deptCity" -> LexicalValue("Cambridge")),
+			      Tuple("ID" -> LexicalValue("8"),
+				    "fname" -> LexicalValue("Sue"),
+				    "addr" -> ␀(),
+				    "deptName" -> ␀(),
+				    "deptCity" -> ␀())),
 			  List(List("ID")),
 			  Some(List("ID")),
-			  Map(List("addr") -> Target("Addresses", List("ID")),
-			      List("deptName", "deptCity") -> Target("Department", List("name", "city"))))
+			  ForeignKeys(List("addr") -> Target("Addresses", List("ID")),
+				      List("deptName", "deptCity") -> Target("Department", List("name", "city"))))
 
     val department = Relation("Department",
-			      Header(Map("ID" -> SQLInt(),
-					"name" -> SQLString(),
-					"city" -> SQLString(),
-					"manager" -> SQLInt())),
-			     Set(Map("ID" -> LexicalValue("23"),
-				     "name" -> LexicalValue("accounting"),
-				     "city" -> LexicalValue("Cambridge"),
-				     "manager" -> LexicalValue("8"))),
+			      Header("ID" -> SQLInt(),
+				     "name" -> SQLString(),
+				     "city" -> SQLString(),
+				     "manager" -> SQLInt()),
+			      Set(Tuple("ID" -> LexicalValue("23"),
+					"name" -> LexicalValue("accounting"),
+					"city" -> LexicalValue("Cambridge"),
+					"manager" -> LexicalValue("8"))),
 			      List(List("ID"), List("name", "city")),
 			      Some(List("ID")),
-			      Map(List("manager") -> Target("People", List("ID"))))
+			      ForeignKeys(List("manager") -> Target("People", List("ID"))))
 
     val db = Database(List(addrs, people, department))
     val g = directDB(StemIRI("http://foo.example/DB"), db)
@@ -132,84 +137,84 @@
   test("2 People 1 Addresses 1 Department 2 Projects 1 Task") {
 
     val addrs = Relation("Addresses",
-			 Header(Map("ID" -> SQLInt(),
-				    "city" -> SQLString(),
-				    "state" -> SQLString())),
-			 Set(Map("ID" -> LexicalValue("18"),
-				 "city" -> LexicalValue("Cambridge"),
-				 "state" -> LexicalValue("MA"))),
+			 Header("ID" -> SQLInt(),
+				"city" -> SQLString(),
+				"state" -> SQLString()),
+			 Set(Tuple("ID" -> LexicalValue("18"),
+				   "city" -> LexicalValue("Cambridge"),
+				   "state" -> LexicalValue("MA"))),
 			 List(List("ID")),
 			 Some(List("ID")),
-			 Map())
+			 ForeignKeys())
 
     val people = Relation("People",
-			  Header(Map("ID" -> SQLInt(),
-				     "fname" -> SQLString(),
-				     "addr" -> SQLInt(),
-				     "deptName" -> SQLString(),
-				     "deptCity" -> SQLString())),
-			  Set(Map("ID" -> LexicalValue("7"),
-				  "fname" -> LexicalValue("Bob"),
-				  "addr" -> LexicalValue("18"),
-				  "deptName" -> LexicalValue("accounting"),
-				  "deptCity" -> LexicalValue("Cambridge")),
-			      Map("ID" -> LexicalValue("8"),
-				  "fname" -> LexicalValue("Sue"),
-				  "addr" -> ␀(),
-				  "deptName" -> ␀(),
-				  "deptCity" -> ␀())), // no data
+			  Header("ID" -> SQLInt(),
+				 "fname" -> SQLString(),
+				 "addr" -> SQLInt(),
+				 "deptName" -> SQLString(),
+				 "deptCity" -> SQLString()),
+			  Set(Tuple("ID" -> LexicalValue("7"),
+				    "fname" -> LexicalValue("Bob"),
+				    "addr" -> LexicalValue("18"),
+				    "deptName" -> LexicalValue("accounting"),
+				    "deptCity" -> LexicalValue("Cambridge")),
+			      Tuple("ID" -> LexicalValue("8"),
+				    "fname" -> LexicalValue("Sue"),
+				    "addr" -> ␀(),
+				    "deptName" -> ␀(),
+				    "deptCity" -> ␀())), // no data
 			  List(List("ID")),
 			  Some(List("ID")),
-			  Map(List("addr") -> Target("Addresses", List("ID")),
-			      List("deptName", "deptCity") -> Target("Department", List("name", "city"))))
+			  ForeignKeys(List("addr") -> Target("Addresses", List("ID")),
+				      List("deptName", "deptCity") -> Target("Department", List("name", "city"))))
 
     val department = Relation("Department",
-			      Header(Map("ID" -> SQLInt(),
-					 "name" -> SQLString(),
-					 "city" -> SQLString(),
-					 "manager" -> SQLInt())),
-			      Set(Map("ID" -> LexicalValue("23"),
-				     "name" -> LexicalValue("accounting"),
-				     "city" -> LexicalValue("Cambridge"),
-				     "manager" -> LexicalValue("8"))),
+			      Header("ID" -> SQLInt(),
+				     "name" -> SQLString(),
+				     "city" -> SQLString(),
+				     "manager" -> SQLInt()),
+			      Set(Tuple("ID" -> LexicalValue("23"),
+					"name" -> LexicalValue("accounting"),
+					"city" -> LexicalValue("Cambridge"),
+					"manager" -> LexicalValue("8"))),
 			      List(List("ID"), List("name", "city")),
 			      Some(List("ID")),
-			      Map(List("manager") -> Target("People", List("ID"))))
+			      ForeignKeys(List("manager") -> Target("People", List("ID"))))
 
     val projects = Relation("Projects",
-			    Header(Map("lead" -> SQLInt(),
-				       "name" -> SQLString(),
-				       "deptName" -> SQLString(),
-				       "deptCity" -> SQLString())),
-			    Set(Map("lead" -> LexicalValue("8"),
-				    "name" -> LexicalValue("pencil survey"),
-				    "deptName" -> LexicalValue("accounting"),
-				    "deptCity" -> LexicalValue("Cambridge")),
-				Map("lead" -> LexicalValue("8"),
-				    "name" -> LexicalValue("eraser survey"),
-				    "deptName" -> LexicalValue("accounting"),
-				    "deptCity" -> LexicalValue("Cambridge"))),
+			    Header("lead" -> SQLInt(),
+				   "name" -> SQLString(),
+				   "deptName" -> SQLString(),
+				   "deptCity" -> SQLString()),
+			    Set(Tuple("lead" -> LexicalValue("8"),
+				      "name" -> LexicalValue("pencil survey"),
+				      "deptName" -> LexicalValue("accounting"),
+				      "deptCity" -> LexicalValue("Cambridge")),
+				Tuple("lead" -> LexicalValue("8"),
+				      "name" -> LexicalValue("eraser survey"),
+				      "deptName" -> LexicalValue("accounting"),
+				      "deptCity" -> LexicalValue("Cambridge"))),
 			    List(List("lead", "name"), List("name", "deptName", "deptCity")),
 			    None,
 			    /* List(List("name"), List("lead", "name"), List("name", "deptName", "deptCity")),
 			    List("name"), // !!! */
-			    Map(List("lead") -> Target("People", List("ID")),
-				List("deptName", "deptCity") -> Target("Department", List("name", "city"))))
+			    ForeignKeys(List("lead") -> Target("People", List("ID")),
+					List("deptName", "deptCity") -> Target("Department", List("name", "city"))))
 
     val tasks = Relation("TaskAssignments",
-			 Header(Map("worker" -> SQLInt(),
-				    "project" -> SQLString(),
-				    "deptName" -> SQLString(),
-				    "deptCity" -> SQLString())),
-			 Set(Map("worker" -> LexicalValue("7"),
-				 "project" -> LexicalValue("pencil survey"),
-				 "deptName" -> LexicalValue("accounting"),
-				 "deptCity" -> LexicalValue("Cambridge"))),
+			 Header("worker" -> SQLInt(),
+				"project" -> SQLString(),
+				"deptName" -> SQLString(),
+				"deptCity" -> SQLString()),
+			 Set(Tuple("worker" -> LexicalValue("7"),
+				   "project" -> LexicalValue("pencil survey"),
+				   "deptName" -> LexicalValue("accounting"),
+				   "deptCity" -> LexicalValue("Cambridge"))),
 			 List(List("worker", "project")),
 			 Some(List("worker", "project")),
-			 Map(List("worker") -> Target("People", List("ID")),
-			     List("project", "deptName", "deptCity") -> Target("Projects", List("name", "deptName", "deptCity")),
-			     List("deptName", "deptCity") -> Target("Department", List("name", "city"))))
+			 ForeignKeys(List("worker") -> Target("People", List("ID")),
+				     List("project", "deptName", "deptCity") -> Target("Projects", List("name", "deptName", "deptCity")),
+				     List("deptName", "deptCity") -> Target("Department", List("name", "city"))))
 
     val db = Database(List(addrs, people, department, projects, tasks))
     val g = directDB(StemIRI("http://foo.example/DB"), db)
@@ -261,37 +266,37 @@
   test("1 People 1 Addresses 1 Offices") {
 
     val addrs = Relation("Addresses",
-			 Header(Map("ID" -> SQLInt(),
-				    "city" -> SQLString(),
-				    "state" -> SQLString())),
-			 Set(Map("ID" -> LexicalValue("18"),
-				 "city" -> LexicalValue("Cambridge"),
-				 "state" -> LexicalValue("MA"))),
+			 Header("ID" -> SQLInt(),
+				"city" -> SQLString(),
+				"state" -> SQLString()),
+			 Set(Tuple("ID" -> LexicalValue("18"),
+				   "city" -> LexicalValue("Cambridge"),
+				   "state" -> LexicalValue("MA"))),
 			 List(List("ID")),
 			 Some(List("ID")),
-			 Map())
+			 ForeignKeys())
 
     val people = Relation("People",
-			  Header(Map("ID" -> SQLInt(),
-				     "fname" -> SQLString(),
-				     "addr" -> SQLInt())),
-			  Set(Map("ID" -> LexicalValue("7"),
-				  "fname" -> LexicalValue("Bob"),
-				  "addr" -> LexicalValue("18"))),
+			  Header("ID" -> SQLInt(),
+				 "fname" -> SQLString(),
+				 "addr" -> SQLInt()),
+			  Set(Tuple("ID" -> LexicalValue("7"),
+				    "fname" -> LexicalValue("Bob"),
+				    "addr" -> LexicalValue("18"))),
 			  List(List("ID")),
 			  Some(List("ID")),
-			  Map(List("addr") -> Target("Addresses", List("ID"))))
+			  ForeignKeys(List("addr") -> Target("Addresses", List("ID"))))
 
     val offices = Relation("Offices",
-			   Header(Map("ID" -> SQLInt(),
-				      "building" -> SQLInt(),
-				      "ofcNumber" -> SQLString())),
-			     Set(Map("ID" -> LexicalValue("18"),
+			   Header("ID" -> SQLInt(),
+				  "building" -> SQLInt(),
+				  "ofcNumber" -> SQLString()),
+			   Set(Tuple("ID" -> LexicalValue("18"),
 				     "building" -> LexicalValue("32"),
 				     "ofcNumber" -> LexicalValue("G528"))),
-			     List(List("ID")),
-			     Some(List("ID")),
-			     Map(List("ID") -> Target("Addresses", List("ID"))))
+			   List(List("ID")),
+			   Some(List("ID")),
+			   ForeignKeys(List("ID") -> Target("Addresses", List("ID"))))
 
     val db = Database(List(addrs, people, offices))
     val g = directDB(StemIRI("http://foo.example/DB"), db)
@@ -317,46 +322,46 @@
   test("1 People 1 Addresses 1 Offices 1 ExectutiveOffices") {
 
     val addrs = Relation("Addresses",
-			 Header(Map("ID" -> SQLInt(),
-				    "city" -> SQLString(),
-				    "state" -> SQLString())),
-			 Set(Map("ID" -> LexicalValue("18"),
-				 "city" -> LexicalValue("Cambridge"),
-				 "state" -> LexicalValue("MA"))),
+			 Header("ID" -> SQLInt(),
+				"city" -> SQLString(),
+				"state" -> SQLString()),
+			 Set(Tuple("ID" -> LexicalValue("18"),
+				   "city" -> LexicalValue("Cambridge"),
+				   "state" -> LexicalValue("MA"))),
 			 List(List("ID")),
 			 Some(List("ID")),
-			 Map())
+			 ForeignKeys())
 
     val people = Relation("People",
-			  Header(Map("ID" -> SQLInt(),
-				     "fname" -> SQLString(),
-				     "addr" -> SQLInt())),
-			  Set(Map("ID" -> LexicalValue("7"),
-				  "fname" -> LexicalValue("Bob"),
-				  "addr" -> LexicalValue("18"))),
+			  Header("ID" -> SQLInt(),
+				 "fname" -> SQLString(),
+				 "addr" -> SQLInt()),
+			  Set(Tuple("ID" -> LexicalValue("7"),
+				    "fname" -> LexicalValue("Bob"),
+				    "addr" -> LexicalValue("18"))),
 			  List(List("ID")),
 			  Some(List("ID")),
-			  Map(List("addr") -> Target("Addresses", List("ID"))))
+			  ForeignKeys(List("addr") -> Target("Addresses", List("ID"))))
 
     val offices = Relation("Offices",
-			   Header(Map("ID" -> SQLInt(),
-				      "building" -> SQLInt(),
-				      "ofcNumber" -> SQLString())),
-			     Set(Map("ID" -> LexicalValue("18"),
+			   Header("ID" -> SQLInt(),
+				  "building" -> SQLInt(),
+				  "ofcNumber" -> SQLString()),
+			   Set(Tuple("ID" -> LexicalValue("18"),
 				     "building" -> LexicalValue("32"),
 				     "ofcNumber" -> LexicalValue("G528"))),
 			     List(List("ID")),
 			     Some(List("ID")),
-			     Map(List("ID") -> Target("Addresses", List("ID"))))
+			     ForeignKeys(List("ID") -> Target("Addresses", List("ID"))))
 
     val execoffices = Relation("ExecutiveOffices",
-			       Header(Map("ID" -> SQLInt(),
-					  "desk" -> SQLString())),
-			       Set(Map("ID" -> LexicalValue("18"),
-				       "desk" -> LexicalValue("oak"))),
+			       Header("ID" -> SQLInt(),
+				      "desk" -> SQLString()),
+			       Set(Tuple("ID" -> LexicalValue("18"),
+					 "desk" -> LexicalValue("oak"))),
 			       List(List("ID")),
 			       Some(List("ID")),
-			       Map(List("ID") -> Target("Offices", List("ID"))))
+			       ForeignKeys(List("ID") -> Target("Offices", List("ID"))))
 
     val db = Database(List(addrs, people, offices, execoffices))
     val g = directDB(StemIRI("http://foo.example/DB"), db)
@@ -409,19 +414,19 @@
 
   test("2 Employees") {
     val employees = Relation("Employees",
-			     Header(Map("ID" -> SQLInt(),
-					"fname" -> SQLString(),
-					"boss" -> SQLInt())),
-			     Set(Map("ID" -> LexicalValue("1"),
-				     "fname" -> LexicalValue("Alice"),
-				     "boss" -> ␀()),
-				 Map("ID" -> LexicalValue("2"),
-				     "fname" -> LexicalValue("Bob"),
-				     "boss" -> LexicalValue("1"))
+			     Header("ID" -> SQLInt(),
+				    "fname" -> SQLString(),
+				    "boss" -> SQLInt()),
+			     Set(Tuple("ID" -> LexicalValue("1"),
+				       "fname" -> LexicalValue("Alice"),
+				       "boss" -> ␀()),
+				 Tuple("ID" -> LexicalValue("2"),
+				       "fname" -> LexicalValue("Bob"),
+				       "boss" -> LexicalValue("1"))
 			       ),
 			     List(List("ID")),
 			     Some(List("ID")),
-			     Map(List("boss") -> Target("Employees", List("ID"))))
+			     ForeignKeys(List("boss") -> Target("Employees", List("ID"))))
     val db = Database(List(employees))
     val g = directDB(StemIRI("http://foo.example/DB"), db)