~ move first couple DB construction tests from DirectMappingTest to SQLTest
authorEric Prud'hommeaux <eric@w3.org>
Tue, 02 Nov 2010 17:16:10 -0400
changeset 253 36cf6a08cca2
parent 252 ebdbce2c6ea4
child 254 d9caadd558bc
~ move first couple DB construction tests from DirectMappingTest to SQLTest
directmapping/src/test/scala/DirectMappingTest.scala
project/build/RDB2RDF.scala
sql/src/test/scala/SQLTest.scala
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/directmapping/src/test/scala/DirectMappingTest.scala	Tue Nov 02 17:16:10 2010 -0400
@@ -0,0 +1,399 @@
+package org.w3.sw.directmapping
+
+import org.w3.sw.rdf._
+import org.w3.sw.rdb.RDB._
+import org.w3.sw.sql.SqlParser
+import org.w3.sw.directmapping.DirectMapping._
+
+import org.scalatest.FunSuite
+
+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 p = SqlParser()
+    val s = """
+CREATE TABLE Addresses (ID INT PRIMARY KEY, city STRING, state STRING);
+INSERT INTO Addresses (ID, city, state) VALUES (18, "Cambridge", "MA");
+CREATE TABLE People (ID INT PRIMARY KEY, fname STRING, addr INT, FOREIGN KEY (addr) REFERENCES Addresses(ID));
+INSERT INTO People (ID, fname, addr) VALUES (7, "Bob", 18);
+INSERT INTO People (ID, fname, addr) VALUES (8, "Sue", NULL);
+"""
+    val db = p.parseAll(p.ddl, s).get
+    val g = directDB(StemIRI("http://foo.example/DB"), db)
+
+    val expected:Graph =
+      Set(
+	Triple(IRI("http://foo.example/DB/People/ID.7#_"),IRI("http://foo.example/DB/People#ID"),TypedLiteral("7",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/People/ID.7#_"),IRI("http://foo.example/DB/People#fname"),TypedLiteral("Bob",IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/People/ID.7#_"),IRI("http://foo.example/DB/People#addr"),IRI("http://foo.example/DB/Addresses/ID.18#_")),
+	Triple(IRI("http://foo.example/DB/People/ID.8#_"),IRI("http://foo.example/DB/People#ID"),TypedLiteral("8",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/People/ID.8#_"),IRI("http://foo.example/DB/People#fname"),TypedLiteral("Sue",IRI("http://www.w3.org/2001/XMLSchema#string"))), 
+
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/Addresses#ID"),TypedLiteral("18",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/Addresses#city"),TypedLiteral("Cambridge",IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/Addresses#state"),TypedLiteral("MA",IRI("http://www.w3.org/2001/XMLSchema#string")))
+      )
+    assert (expected === g)
+  }
+
+
+  test("2 People 1 Addresses 1 Department") {
+
+    val p = SqlParser()
+    val s = """
+CREATE TABLE Addresses (ID INT PRIMARY KEY, city STRING, state STRING);
+INSERT INTO Addresses (ID, city, state) VALUES (18, "Cambridge", "MA");
+CREATE TABLE Department (ID INT PRIMARY KEY, name STRING, city STRING,
+                         manager INT, FOREIGN KEY (manager) REFERENCES People(ID), UNIQUE (name, city));
+INSERT INTO Department (ID, name, city, manager) VALUES (23, "accounting", "Cambridge", 8);
+CREATE TABLE People (ID INT PRIMARY KEY, fname STRING,
+                     addr INT, FOREIGN KEY (addr) REFERENCES Addresses(ID),
+                     deptName STRING, deptCity STRING, FOREIGN KEY (deptName, deptCity) REFERENCES Department(name, city));
+INSERT INTO People (ID, fname, addr, deptName, deptCity) VALUES (7, "Bob", 18, "accounting", "Cambridge");
+INSERT INTO People (ID, fname, addr, deptName, deptCity) VALUES (8, "Sue", NULL, NULL, NULL);
+"""
+    val db = p.parseAll(p.ddl, s).get
+    val g = directDB(StemIRI("http://foo.example/DB"), db)
+
+    val expected:Graph =
+      Set(
+	Triple(IRI("http://foo.example/DB/People/ID.7#_"),IRI("http://foo.example/DB/People#deptName"),TypedLiteral("accounting",IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/People/ID.7#_"),IRI("http://foo.example/DB/People#deptCity"),TypedLiteral("Cambridge",IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/People/ID.7#_"),IRI("http://foo.example/DB/People#deptName_deptCity"),IRI("http://foo.example/DB/Department/ID.23#_")),
+
+	Triple(IRI("http://foo.example/DB/Department/ID.23#_"),IRI("http://foo.example/DB/Department#ID"),TypedLiteral("23",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/Department/ID.23#_"),IRI("http://foo.example/DB/Department#name"),TypedLiteral("accounting",IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/Department/ID.23#_"),IRI("http://foo.example/DB/Department#city"),TypedLiteral("Cambridge",IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/Department/ID.23#_"),IRI("http://foo.example/DB/Department#manager"),IRI("http://foo.example/DB/People/ID.8#_")),
+
+	Triple(IRI("http://foo.example/DB/People/ID.7#_"),IRI("http://foo.example/DB/People#ID"),TypedLiteral("7",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/People/ID.7#_"),IRI("http://foo.example/DB/People#fname"),TypedLiteral("Bob",IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/People/ID.7#_"),IRI("http://foo.example/DB/People#addr"),IRI("http://foo.example/DB/Addresses/ID.18#_")),
+	Triple(IRI("http://foo.example/DB/People/ID.8#_"),IRI("http://foo.example/DB/People#ID"),TypedLiteral("8",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/People/ID.8#_"),IRI("http://foo.example/DB/People#fname"),TypedLiteral("Sue",IRI("http://www.w3.org/2001/XMLSchema#string"))), 
+
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/Addresses#ID"),TypedLiteral("18",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/Addresses#city"),TypedLiteral("Cambridge",IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/Addresses#state"),TypedLiteral("MA",IRI("http://www.w3.org/2001/XMLSchema#string")))
+      )
+    assert (expected === g)
+  }
+
+
+  test("2 People 1 Addresses 1 Department 2 Projects 1 Task") {
+
+    val addrs = Relation("Addresses",
+			 Header("ID" -> Datatype.INTEGER,
+				"city" -> Datatype.STRING,
+				"state" -> Datatype.STRING),
+			 List(Tuple("ID" -> LexicalValue("18"),
+				    "city" -> LexicalValue("Cambridge"),
+				    "state" -> LexicalValue("MA"))),
+			 List(CandidateKey("ID")),
+			 Some(CandidateKey("ID")),
+			 ForeignKeys())
+
+    val people = Relation("People",
+			  Header("ID" -> Datatype.INTEGER,
+				 "fname" -> Datatype.STRING,
+				 "addr" -> Datatype.INTEGER,
+				 "deptName" -> Datatype.STRING,
+				 "deptCity" -> Datatype.STRING),
+			  List(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(CandidateKey("ID")),
+			  Some(CandidateKey("ID")),
+			  ForeignKeys(List("addr") -> Target("Addresses", CandidateKey("ID")),
+				      List("deptName", "deptCity") -> Target("Department", CandidateKey("name", "city"))))
+
+    val department = Relation("Department",
+			      Header("ID" -> Datatype.INTEGER,
+				     "name" -> Datatype.STRING,
+				     "city" -> Datatype.STRING,
+				     "manager" -> Datatype.INTEGER),
+			      List(Tuple("ID" -> LexicalValue("23"),
+					 "name" -> LexicalValue("accounting"),
+					 "city" -> LexicalValue("Cambridge"),
+					 "manager" -> LexicalValue("8"))),
+			      List(CandidateKey("ID"),
+				   CandidateKey("name", "city")),
+			      Some(CandidateKey("ID")),
+			      ForeignKeys(List("manager") -> Target("People", CandidateKey("ID"))))
+
+    val projects = Relation("Projects",
+			    Header("lead" -> Datatype.INTEGER,
+				   "name" -> Datatype.STRING,
+				   "deptName" -> Datatype.STRING,
+				   "deptCity" -> Datatype.STRING),
+			    List(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(CandidateKey("lead", "name"),
+				 CandidateKey("name", "deptName", "deptCity")),
+			    None,
+			    /* List(List("name"), List("lead", "name"), List("name", "deptName", "deptCity")),
+			    List("name"), // !!! */
+			    ForeignKeys(List("lead") -> Target("People", CandidateKey("ID")),
+					List("deptName", "deptCity") -> Target("Department", CandidateKey("name", "city"))))
+
+    val tasks = Relation("TaskAssignments",
+			 Header("worker" -> Datatype.INTEGER,
+				"project" -> Datatype.STRING,
+				"deptName" -> Datatype.STRING,
+				"deptCity" -> Datatype.STRING),
+			 List(Tuple("worker" -> LexicalValue("7"),
+				    "project" -> LexicalValue("pencil survey"),
+				    "deptName" -> LexicalValue("accounting"),
+				    "deptCity" -> LexicalValue("Cambridge"))),
+			 List(CandidateKey("worker", "project")),
+			 Some(CandidateKey("worker", "project")),
+			 ForeignKeys(List("worker") -> Target("People", CandidateKey("ID")),
+				     List("project", "deptName", "deptCity") -> Target("Projects", CandidateKey("name", "deptName", "deptCity")),
+				     List("deptName", "deptCity") -> Target("Department", CandidateKey("name", "city"))))
+
+    val db = Database(List(addrs, people, department, projects, tasks))
+    val g = directDB(StemIRI("http://foo.example/DB"), db)
+
+    val expected:Graph =
+      Set(
+	Triple(BNode("a"), IRI("http://foo.example/DB/Projects#lead"), IRI("http://foo.example/DB/People/ID.8#_")),
+	Triple(BNode("a"), IRI("http://foo.example/DB/Projects#name"), TypedLiteral("pencil survey", IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(BNode("a"), IRI("http://foo.example/DB/Projects#deptName"), TypedLiteral("accounting", IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(BNode("a"), IRI("http://foo.example/DB/Projects#deptCity"), TypedLiteral("Cambridge", IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(BNode("a"), IRI("http://foo.example/DB/Projects#deptName_deptCity"), IRI("http://foo.example/DB/Department/ID.23#_")),
+
+	Triple(BNode("b"), IRI("http://foo.example/DB/Projects#lead"), IRI("http://foo.example/DB/People/ID.8#_")),
+	Triple(BNode("b"), IRI("http://foo.example/DB/Projects#name"), TypedLiteral("eraser survey", IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(BNode("b"), IRI("http://foo.example/DB/Projects#deptName"), TypedLiteral("accounting", IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(BNode("b"), IRI("http://foo.example/DB/Projects#deptCity"), TypedLiteral("Cambridge", IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(BNode("b"), IRI("http://foo.example/DB/Projects#deptName_deptCity"), IRI("http://foo.example/DB/Department/ID.23#_")),
+
+	Triple(IRI("http://foo.example/DB/TaskAssignments/worker.7_project.pencil+survey#_"), IRI("http://foo.example/DB/TaskAssignments#worker"), IRI("http://foo.example/DB/People/ID.7#_")),
+	Triple(IRI("http://foo.example/DB/TaskAssignments/worker.7_project.pencil+survey#_"), IRI("http://foo.example/DB/TaskAssignments#project"), TypedLiteral("pencil survey", IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/TaskAssignments/worker.7_project.pencil+survey#_"), IRI("http://foo.example/DB/TaskAssignments#deptName"), TypedLiteral("accounting", IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/TaskAssignments/worker.7_project.pencil+survey#_"), IRI("http://foo.example/DB/TaskAssignments#deptCity"), TypedLiteral("Cambridge", IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/TaskAssignments/worker.7_project.pencil+survey#_"), IRI("http://foo.example/DB/TaskAssignments#deptName_deptCity"), IRI("http://foo.example/DB/Department/ID.23#_")),
+	Triple(IRI("http://foo.example/DB/TaskAssignments/worker.7_project.pencil+survey#_"), IRI("http://foo.example/DB/TaskAssignments#project_deptName_deptCity"), BNode("a")),
+
+	Triple(IRI("http://foo.example/DB/People/ID.7#_"),IRI("http://foo.example/DB/People#deptName"),TypedLiteral("accounting",IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/People/ID.7#_"),IRI("http://foo.example/DB/People#deptCity"),TypedLiteral("Cambridge",IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/People/ID.7#_"),IRI("http://foo.example/DB/People#deptName_deptCity"),IRI("http://foo.example/DB/Department/ID.23#_")),
+
+	Triple(IRI("http://foo.example/DB/Department/ID.23#_"),IRI("http://foo.example/DB/Department#ID"),TypedLiteral("23",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/Department/ID.23#_"),IRI("http://foo.example/DB/Department#name"),TypedLiteral("accounting",IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/Department/ID.23#_"),IRI("http://foo.example/DB/Department#city"),TypedLiteral("Cambridge",IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/Department/ID.23#_"),IRI("http://foo.example/DB/Department#manager"),IRI("http://foo.example/DB/People/ID.8#_")),
+
+	Triple(IRI("http://foo.example/DB/People/ID.7#_"),IRI("http://foo.example/DB/People#ID"),TypedLiteral("7",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/People/ID.7#_"),IRI("http://foo.example/DB/People#fname"),TypedLiteral("Bob",IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/People/ID.7#_"),IRI("http://foo.example/DB/People#addr"),IRI("http://foo.example/DB/Addresses/ID.18#_")),
+	Triple(IRI("http://foo.example/DB/People/ID.8#_"),IRI("http://foo.example/DB/People#ID"),TypedLiteral("8",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/People/ID.8#_"),IRI("http://foo.example/DB/People#fname"),TypedLiteral("Sue",IRI("http://www.w3.org/2001/XMLSchema#string"))), 
+
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/Addresses#ID"),TypedLiteral("18",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/Addresses#city"),TypedLiteral("Cambridge",IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/Addresses#state"),TypedLiteral("MA",IRI("http://www.w3.org/2001/XMLSchema#string")))
+      )
+    assert (expected === g)
+  }
+
+
+  test("1 People 1 Addresses 1 Offices") {
+
+    val addrs = Relation("Addresses",
+			 Header("ID" -> Datatype.INTEGER,
+				"city" -> Datatype.STRING,
+				"state" -> Datatype.STRING),
+			 List(Tuple("ID" -> LexicalValue("18"),
+				    "city" -> LexicalValue("Cambridge"),
+				    "state" -> LexicalValue("MA"))),
+			 List(CandidateKey("ID")),
+			 Some(CandidateKey("ID")),
+			 ForeignKeys())
+
+    val people = Relation("People",
+			  Header("ID" -> Datatype.INTEGER,
+				 "fname" -> Datatype.STRING,
+				 "addr" -> Datatype.INTEGER),
+			  List(Tuple("ID" -> LexicalValue("7"),
+				     "fname" -> LexicalValue("Bob"),
+				     "addr" -> LexicalValue("18"))),
+			  List(CandidateKey("ID")),
+			  Some(CandidateKey("ID")),
+			  ForeignKeys(List("addr") -> Target("Addresses", CandidateKey("ID"))))
+
+    val offices = Relation("Offices",
+			   Header("ID" -> Datatype.INTEGER,
+				  "building" -> Datatype.INTEGER,
+				  "ofcNumber" -> Datatype.STRING),
+			   List(Tuple("ID" -> LexicalValue("18"),
+				      "building" -> LexicalValue("32"),
+				      "ofcNumber" -> LexicalValue("G528"))),
+			   List(CandidateKey("ID")),
+			   Some(CandidateKey("ID")),
+			   ForeignKeys(List("ID") -> Target("Addresses", CandidateKey("ID"))))
+
+    val db = Database(List(addrs, people, offices))
+    val g = directDB(StemIRI("http://foo.example/DB"), db)
+
+    val expected:Graph =
+      Set(
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/Offices#ID"),TypedLiteral("18",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/Offices#building"),TypedLiteral("32",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/Offices#ofcNumber"),TypedLiteral("G528",IRI("http://www.w3.org/2001/XMLSchema#string"))), 
+
+	Triple(IRI("http://foo.example/DB/People/ID.7#_"),IRI("http://foo.example/DB/People#ID"),TypedLiteral("7",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/People/ID.7#_"),IRI("http://foo.example/DB/People#fname"),TypedLiteral("Bob",IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/People/ID.7#_"),IRI("http://foo.example/DB/People#addr"),IRI("http://foo.example/DB/Addresses/ID.18#_")),
+
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/Addresses#ID"),TypedLiteral("18",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/Addresses#city"),TypedLiteral("Cambridge",IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/Addresses#state"),TypedLiteral("MA",IRI("http://www.w3.org/2001/XMLSchema#string")))
+      )
+    assert (expected === g)
+  }
+
+
+  test("1 People 1 Addresses 1 Offices 1 ExectutiveOffices") {
+
+    val addrs = Relation("Addresses",
+			 Header("ID" -> Datatype.INTEGER,
+				"city" -> Datatype.STRING,
+				"state" -> Datatype.STRING),
+			 List(Tuple("ID" -> LexicalValue("18"),
+				    "city" -> LexicalValue("Cambridge"),
+				    "state" -> LexicalValue("MA"))),
+			 List(CandidateKey("ID")),
+			 Some(CandidateKey("ID")),
+			 ForeignKeys())
+
+    val people = Relation("People",
+			  Header("ID" -> Datatype.INTEGER,
+				 "fname" -> Datatype.STRING,
+				 "addr" -> Datatype.INTEGER),
+			  List(Tuple("ID" -> LexicalValue("7"),
+				     "fname" -> LexicalValue("Bob"),
+				     "addr" -> LexicalValue("18"))),
+			  List(CandidateKey("ID")),
+			  Some(CandidateKey("ID")),
+			  ForeignKeys(List("addr") -> Target("Addresses", CandidateKey("ID"))))
+
+    val offices = Relation("Offices",
+			   Header("ID" -> Datatype.INTEGER,
+				  "building" -> Datatype.INTEGER,
+				  "ofcNumber" -> Datatype.STRING),
+			   List(Tuple("ID" -> LexicalValue("18"),
+				      "building" -> LexicalValue("32"),
+				      "ofcNumber" -> LexicalValue("G528"))),
+			     List(CandidateKey("ID")),
+			     Some(CandidateKey("ID")),
+			     ForeignKeys(List("ID") -> Target("Addresses", CandidateKey("ID"))))
+
+    val execoffices = Relation("ExecutiveOffices",
+			       Header("ID" -> Datatype.INTEGER,
+				      "desk" -> Datatype.STRING),
+			       List(Tuple("ID" -> LexicalValue("18"),
+					  "desk" -> LexicalValue("oak"))),
+			       List(CandidateKey("ID")),
+			       Some(CandidateKey("ID")),
+			       ForeignKeys(List("ID") -> Target("Offices", CandidateKey("ID"))))
+
+    val db = Database(List(addrs, people, offices, execoffices))
+    val g = directDB(StemIRI("http://foo.example/DB"), db)
+
+    val expected:Graph =
+      Set(
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/ExecutiveOffices#ID"),TypedLiteral("18",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/ExecutiveOffices#desk"),TypedLiteral("oak",IRI("http://www.w3.org/2001/XMLSchema#string"))), 
+
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/Offices#ID"),TypedLiteral("18",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/Offices#building"),TypedLiteral("32",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/Offices#ofcNumber"),TypedLiteral("G528",IRI("http://www.w3.org/2001/XMLSchema#string"))), 
+
+	Triple(IRI("http://foo.example/DB/People/ID.7#_"),IRI("http://foo.example/DB/People#ID"),TypedLiteral("7",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/People/ID.7#_"),IRI("http://foo.example/DB/People#fname"),TypedLiteral("Bob",IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/People/ID.7#_"),IRI("http://foo.example/DB/People#addr"),IRI("http://foo.example/DB/Addresses/ID.18#_")),
+
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/Addresses#ID"),TypedLiteral("18",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/Addresses#city"),TypedLiteral("Cambridge",IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/Addresses/ID.18#_"),IRI("http://foo.example/DB/Addresses#state"),TypedLiteral("MA",IRI("http://www.w3.org/2001/XMLSchema#string")))
+      )
+    assert (expected === g)
+  }
+
+
+  test("NodeMap") {
+
+    val ck1:CandidateKey = CandidateKey("name", "ssn")
+    val ck2:CandidateKey = CandidateKey("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("Employees",
+			     Header("ID" -> Datatype.INTEGER,
+				    "fname" -> Datatype.STRING,
+				    "boss" -> Datatype.INTEGER),
+			     List(Tuple("ID" -> LexicalValue("1"),
+					"fname" -> LexicalValue("Alice"),
+					"boss" -> ␀()),
+				  Tuple("ID" -> LexicalValue("2"),
+					"fname" -> LexicalValue("Bob"),
+					"boss" -> LexicalValue("1"))
+				),
+			     List(CandidateKey("ID")),
+			     Some(CandidateKey("ID")),
+			     ForeignKeys(List("boss") -> Target("Employees", CandidateKey("ID"))))
+    val db = Database(List(employees))
+    val g = directDB(StemIRI("http://foo.example/DB"), db)
+
+    val expected:Graph =
+      Set(
+	Triple(IRI("http://foo.example/DB/Employees/ID.1#_"),IRI("http://foo.example/DB/Employees#ID"),TypedLiteral("1",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/Employees/ID.1#_"),IRI("http://foo.example/DB/Employees#fname"),TypedLiteral("Alice",IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/Employees/ID.2#_"),IRI("http://foo.example/DB/Employees#ID"),TypedLiteral("2",IRI("http://www.w3.org/2001/XMLSchema#int"))),
+	Triple(IRI("http://foo.example/DB/Employees/ID.2#_"),IRI("http://foo.example/DB/Employees#fname"),TypedLiteral("Bob",IRI("http://www.w3.org/2001/XMLSchema#string"))),
+	Triple(IRI("http://foo.example/DB/Employees/ID.2#_"),IRI("http://foo.example/DB/Employees#boss"),IRI("http://foo.example/DB/Employees/ID.1#_"))
+      )
+    assert (expected === g)
+  }
+
+}
+
--- a/project/build/RDB2RDF.scala	Tue Nov 02 17:14:43 2010 -0400
+++ b/project/build/RDB2RDF.scala	Tue Nov 02 17:16:10 2010 -0400
@@ -12,7 +12,7 @@
   lazy val rdb = project("rdb", "rdb", new RDB(_))
   lazy val sql = project("sql", "sql", new SQL(_), rdb)
   lazy val rdf = project("rdf", "rdf", new RDF(_))
-  lazy val directmapping = project("directmapping", "directmapping", new DirectMapping(_), rdb, rdf)
+  lazy val directmapping = project("directmapping", "directmapping", new DirectMapping(_), rdb, rdf, sql)
   lazy val sparql = project("sparql", "sparql", new SPARQL(_), rdf)
   lazy val sparql2sql = project("sparql2sql", "sparql2sql", new SPARQL2SQL(_), sparql, sql)
   lazy val sparql2sparql = project("sparql2sparql", "sparql2sparql", new SPARQL2SPARQL(_), sparql)
--- a/sql/src/test/scala/SQLTest.scala	Tue Nov 02 17:14:43 2010 -0400
+++ b/sql/src/test/scala/SQLTest.scala	Tue Nov 02 17:16:10 2010 -0400
@@ -422,7 +422,7 @@
     assert(expected === (a.parseAll(a.select, e).get))
   }
 
-  test("x") {
+  test("parse PRIMARY KEY") {
     val a = SqlParser()
     val e = """
 ID INT PRIMARY KEY
@@ -431,7 +431,7 @@
     assert(expected === (a.parseAll(a.fielddescorkeydef, e).get))
   }
 
-  test("y") {
+  test("parse CREATE") {
     val a = SqlParser()
     val e = """
 CREATE TABLE Sex_DE (ID INT PRIMARY KEY)
@@ -603,6 +603,119 @@
     assert(expected === (a.parseAll(a.createview, e).get))
   }
 
+
+  test("parse 2 People 1 Addresses") {
+    val p = SqlParser()
+    val s = """
+CREATE TABLE Addresses (ID INT PRIMARY KEY, city STRING, state STRING);
+INSERT INTO Addresses (ID, city, state) VALUES (18, "Cambridge", "MA");
+CREATE TABLE People (ID INT PRIMARY KEY, fname STRING, addr INT, FOREIGN KEY (addr) REFERENCES Addresses(ID));
+INSERT INTO People (ID, fname, addr) VALUES (7, "Bob", 18);
+INSERT INTO People (ID, fname, addr) VALUES (8, "Sue", NULL);
+"""
+    val addrs = RDB.Relation(
+      "Addresses",
+      RDB.Header("ID" -> RDB.Datatype.INTEGER,
+		 "city" -> RDB.Datatype.STRING,
+		 "state" -> RDB.Datatype.STRING),
+      List(RDB.Tuple("ID" -> RDB.LexicalValue("18"),
+		     "city" -> RDB.LexicalValue("Cambridge"),
+		     "state" -> RDB.LexicalValue("MA"))),
+      List(RDB.CandidateKey("ID")),
+      Some(RDB.CandidateKey("ID")),
+      RDB.ForeignKeys())
+
+    val people = RDB.Relation(
+      "People",
+      RDB.Header("ID" -> RDB.Datatype.INTEGER,
+		 "fname" -> RDB.Datatype.STRING,
+		 "addr" -> RDB.Datatype.INTEGER),
+      List(RDB.Tuple("ID" -> RDB.LexicalValue("7"),
+		     "fname" -> RDB.LexicalValue("Bob"),
+		     "addr" -> RDB.LexicalValue("18")),
+	   RDB.Tuple("ID" -> RDB.LexicalValue("8"),
+		     "fname" -> RDB.LexicalValue("Sue"),
+		     "addr" -> RDB.␀())),
+      List(RDB.CandidateKey("ID")),
+      Some(RDB.CandidateKey("ID")),
+      RDB.ForeignKeys(List("addr") -> RDB.Target("Addresses", RDB.CandidateKey("ID"))))
+
+    val expected = RDB.Database(List(addrs, people))
+    assert(expected === (p.parseAll(p.ddl, s).get))
+  }
+
+
+  test("parse 2 People 1 Addresses 1 Department") {
+    val p = SqlParser()
+    val s = """
+CREATE TABLE Addresses (ID INT PRIMARY KEY, city STRING, state STRING);
+INSERT INTO Addresses (ID, city, state) VALUES (18, "Cambridge", "MA");
+CREATE TABLE Department (ID INT PRIMARY KEY, name STRING, city STRING,
+                         manager INT, FOREIGN KEY (manager) REFERENCES People(ID), UNIQUE (name, city));
+INSERT INTO Department (ID, name, city, manager) VALUES (23, "accounting", "Cambridge", 8);
+CREATE TABLE People (ID INT PRIMARY KEY, fname STRING,
+                     addr INT, FOREIGN KEY (addr) REFERENCES Addresses(ID),
+                     deptName STRING, deptCity STRING, FOREIGN KEY (deptName, deptCity) REFERENCES Department(name, city));
+INSERT INTO People (ID, fname, addr, deptName, deptCity) VALUES (7, "Bob", 18, "accounting", "Cambridge");
+INSERT INTO People (ID, fname, addr, deptName, deptCity) VALUES (8, "Sue", NULL, NULL, NULL);
+"""
+
+    val addrs = RDB.Relation(
+      "Addresses",
+      RDB.Header("ID" -> RDB.Datatype.INTEGER,
+		 "city" -> RDB.Datatype.STRING,
+		 "state" -> RDB.Datatype.STRING),
+      List(RDB.Tuple("ID" -> RDB.LexicalValue("18"),
+		     "city" -> RDB.LexicalValue("Cambridge"),
+		     "state" -> RDB.LexicalValue("MA"))),
+      List(RDB.CandidateKey("ID")),
+      Some(RDB.CandidateKey("ID")),
+      RDB.ForeignKeys())
+
+    val people = RDB.Relation(
+      "People",
+      RDB.Header("ID" -> RDB.Datatype.INTEGER,
+		 "fname" -> RDB.Datatype.STRING,
+		 "addr" -> RDB.Datatype.INTEGER,
+		 "deptName" -> RDB.Datatype.STRING,
+		 "deptCity" -> RDB.Datatype.STRING),
+      List(RDB.Tuple("ID" -> RDB.LexicalValue("7"),
+		     "fname" -> RDB.LexicalValue("Bob"),
+		     "addr" -> RDB.LexicalValue("18"),
+		     "deptName" -> RDB.LexicalValue("accounting"),
+		     "deptCity" -> RDB.LexicalValue("Cambridge")),
+	   RDB.Tuple("ID" -> RDB.LexicalValue("8"),
+		     "fname" -> RDB.LexicalValue("Sue"),
+		     "addr" -> RDB.␀(),
+		     "deptName" -> RDB.␀(),
+		     "deptCity" -> RDB.␀())),
+      List(RDB.CandidateKey("ID")),
+      Some(RDB.CandidateKey("ID")),
+      RDB.ForeignKeys(List("addr") -> RDB.Target("Addresses", RDB.CandidateKey("ID")),
+		      List("deptName", "deptCity") -> RDB.Target("Department", RDB.CandidateKey("name", "city"))))
+
+    val department = RDB.Relation(
+      "Department",
+      RDB.Header("ID" -> RDB.Datatype.INTEGER,
+		 "name" -> RDB.Datatype.STRING,
+		 "city" -> RDB.Datatype.STRING,
+		 "manager" -> RDB.Datatype.INTEGER),
+      List(RDB.Tuple("ID" -> RDB.LexicalValue("23"),
+		     "name" -> RDB.LexicalValue("accounting"),
+		     "city" -> RDB.LexicalValue("Cambridge"),
+		     "manager" -> RDB.LexicalValue("8"))),
+      List(RDB.CandidateKey("ID"),
+	   RDB.CandidateKey("name", "city")),
+      Some(RDB.CandidateKey("ID")),
+      RDB.ForeignKeys(List("manager") -> RDB.Target("People", RDB.CandidateKey("ID"))))
+
+    val db = RDB.Database(List(addrs, people, department))
+
+    val expected = RDB.Database(List(addrs, people, department))
+    assert(expected === (p.parseAll(p.ddl, s).get))
+  }
+
+
   /**
    * junk that should be elsewhere
    */