~ absorbed stemGraph's RDF object
authorEric Prud'hommeaux <eric@w3.org>
Sun, 31 Oct 2010 20:39:17 -0400
changeset 249 855ab0c30782
parent 246 417d33e9fa36
child 250 a5f27d9d047a
~ absorbed stemGraph's RDF object
+ stemGraph's DirectMapping
directmapping/src/main/scala/DirectMapping.scala
rdb/src/main/scala/RDB.scala
rdf/src/main/scala/RDF.scala
sparql/src/main/scala/SPARQL.scala
sparql/src/test/scala/SparqlTest.scala
sparql2sql/src/main/scala/SparqlToSql.scala
sql/src/main/scala/SQL.scala
--- a/directmapping/src/main/scala/DirectMapping.scala	Sun Oct 31 17:22:46 2010 -0400
+++ b/directmapping/src/main/scala/DirectMapping.scala	Sun Oct 31 20:39:17 2010 -0400
@@ -1,195 +1,194 @@
 package org.w3.sw.directmapping
 
-import org.w3.sw.rdb
-import org.w3.sw.rdf
-
-// to be adapted to the new RDB model
-
-// object DirectMapping {
-
-//   /** A KeyMap associates the candidate key and key values with the
-//    * node for any tuple in a unique relation. */
-//   case class KeyMap(m:Map[CandidateKey,  Map[List[CellValue], Node]]) {
-//     //def KeyMap() : KeyMap = KeyMap(Map[CandidateKey,  Map[List[CellValue], Node]]())
-//     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))
-// 	  }
-// 	})
-//       KeyMap(m2)
-//     }
-//   }
-//   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)
-//     }
-//   }
-//   implicit def list2map (l:Set[(RelName, KeyMap)]):Map[RelName,KeyMap] = l.toMap
-//   implicit def list2Nmap (l:Set[(RelName, KeyMap)]):NodeMap = NodeMap(l)
-
-//   /** The direct mapping requires one parameter: the StemIRI */
-//   case class StemIRI(stem:String) {
-//     def +(path:String):IRI = IRI(stem + path)
-//   }
-
-//   /**
-//    * The mapping functions implementing
-//    * <http://www.w3.org/2001/sw/rdb2rdf/directGraph/>
-//    */
-
-//   def references (t:Tuple, r:Relation):Set[List[AttrName]] = {
-//     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)
-//     })
-
-//     /** 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 -- nullFKs - r.fks(r.pk.get.attrs).key.attrs
-//     else
-//       r.fks.keySet -- nullFKs
-//   }
-
-//   def scalars (t:Tuple, r:Relation):Set[AttrName] = {
-//     val allAttrs:Set[AttrName] = r.header.keySet
-//     val allFKs:Set[List[AttrName]] = r.fks.keySet
-//     val unaryFKs:Set[AttrName] = allFKs.flatMap(a => {
-//       if (a.length == 1) a else None
-//     })
-//     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
-//   }
-
-//   /** The NodeMap-generating functions: */
-//   def relation2KeyMap (u:StemIRI, r:Relation) : KeyMap = {
-//     val m = KeyMap(Map[CandidateKey, Map[List[CellValue], Node]]())
-//     r.body.foldLeft(m)((m, t) => {
-//       val (pairs, node) = rdfNodeForTuple(u, t, r)
-//       m ++ (pairs, node)
-//     })
-//   }
+object DirectMapping {
 
-//   def rdfNodeForTuple (u:StemIRI, 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)
-// 	nodemap(u, r.name, r.pk.get.attrs, vs)
-//       } else
-// 	/** Table has no primkary key (but has some candidate keys). */
-// 	freshbnode()
-//     (r.candidates.map(k => {
-//       val values:List[CellValue] = k.attrs.map(a => t(a))
-//       (k, values)
-//     }), s)
-//   }
-
-//   /** The triples-generating functions start with databasemap: */
-//   def directDB (u:StemIRI, db:Database) : RDFGraph = {
-//     val idxables = db.keySet filter { rn => !db(rn).candidates.isEmpty }
-//     val nodeMap = idxables map {rn => rn -> relation2KeyMap(u, db(rn))}
-//     db.keySet.flatMap(rn => directR(u, db(rn), nodeMap, db))
-//   }
-
-//   def directR (u:StemIRI, r:Relation, nodes:NodeMap, db:Database) : RDFGraph =
-//     /* flatMap.toSet assumes that no two triples from directT would be the same.
-//      * We know this because relations with candidate keys are mapped to unique
-//      * subjects, and potentially redundant rows get unique blank node subjects.
-//      */
-//     r.body.flatMap(t => directT(u, t, r, nodes, db)).toSet
-
-//   def directT (u:StemIRI, t:Tuple, r:Relation, nodes:NodeMap, db:Database) : Set[Triple] = {
-//     val s:Node =
-//       if (r.candidates.size > 0) {
-// 	// 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
-// 	/** Table has no candidate keys. */
-// 	freshbnode()
-//     directS(u, s, t, r, nodes, db)
-//   }
-
-//   def directS (u:StemIRI, s:Node, t:Tuple, r:Relation, nodes:NodeMap, db:Database) : Set[Triple] = {
-//     references(t, r).map(as => directN(u, s, as, r, t, nodes)) ++
-//     scalars(t, r).map(a => directL(u, r.name, s, a, r.header, t))
-//   }
+  import org.w3.sw.rdb.RDB._
+  import org.w3.sw.rdf._
 
-//   var NextBNode = 97
-//   def freshbnode () : BNode = {
-//     val ret = NextBNode
-//     NextBNode = NextBNode + 1
-//     BNode(ret.toChar.toString)
-//   }
-
-//   def directL (u:StemIRI, rn:RelName, s:Node, a:AttrName, h:Header, t:Tuple) : Triple = {
-//     val p = predicatemap (u, rn, List(a))
-//     val l = t.lexvalue(a).get
-//     val o = literalmap(l, h.sqlDatatype(a))
-//     Triple(s, p, o)
-//   }
-//   def directN (u:StemIRI, s:Node, as:List[AttrName], r:Relation, t:Tuple, nodes:NodeMap) : Triple = {
-//     val p = predicatemap (u, r.name, as)
-//     val ls:List[LexicalValue] = t.lexvaluesNoNulls(as)
-//     val target = r.fks(as)
-//     val o:Object = nodes(target.rel)(target.key)(ls)
-//     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
+  /** A KeyMap associates the candidate key and key values with the
+   * node for any tuple in a unique relation. */
+  case class KeyMap(m:Map[CandidateKey,  Map[List[CellValue], Node]]) {
+    //def KeyMap() : KeyMap = KeyMap(Map[CandidateKey,  Map[List[CellValue], Node]]())
+    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))
+	  }
+	})
+      KeyMap(m2)
+    }
+  }
+  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)
+    }
+  }
+  implicit def list2map (l:Set[(RelName, KeyMap)]):Map[RelName,KeyMap] = l.toMap
+  implicit def list2Nmap (l:Set[(RelName, KeyMap)]):NodeMap = NodeMap(l)
 
-//   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 predicatemap (u:StemIRI, rn:RelName, as:List[AttrName]) : IRI =
-//     u + ("/" + UE(rn) + "#" + as.mkString("_"))
+  /** The direct mapping requires one parameter: the StemIRI */
+  case class StemIRI(stem:String) {
+    def +(path:String):IRI = IRI(stem + path)
+  }
 
-//   def XSD (d:Datatype) : IRI =
-//     d match {
-//       case RDB.Datatype.INTEGER => IRI("http://www.w3.org/2001/XMLSchema#int")
-//       case RDB.Datatype.FLOAT => IRI("http://www.w3.org/2001/XMLSchema#float")
-//       case RDB.Datatype.DATE => IRI("http://www.w3.org/2001/XMLSchema#date")
-//       case RDB.Datatype.TIME => IRI("http://www.w3.org/2001/XMLSchema#time")
-//       case RDB.Datatype.TIMESTAMP => IRI("http://www.w3.org/2001/XMLSchema#timestamp")
-//       case RDB.Datatype.CHAR => IRI("http://www.w3.org/2001/XMLSchema#char")
-//       case RDB.Datatype.VARCHAR => IRI("http://www.w3.org/2001/XMLSchema#varchar")
-//       case RDB.Datatype.STRING => IRI("http://www.w3.org/2001/XMLSchema#string")
-//     }
+  /**
+   * The mapping functions implementing
+   * <http://www.w3.org/2001/sw/rdb2rdf/directGraph/>
+   */
 
-//   def literalmap (l:LexicalValue, d:Datatype) : TypedLiteral =
-//     TypedLiteral(l.s, XSD(d))
+  def references (t:Tuple, r:Relation):Set[List[AttrName]] = {
+    val allFKs:Set[List[AttrName]] = r.fks.keySet.toSet
+    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)
+    })
 
-//   def UE (s:String) : String = s.replaceAll(" ", "+")
-// }
+    /** 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
+  }
+
+  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 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
+  }
+
+  /** The NodeMap-generating functions: */
+  def relation2KeyMap (u:StemIRI, r:Relation) : KeyMap = {
+    val m = KeyMap(Map[CandidateKey, Map[List[CellValue], Node]]())
+    r.body.foldLeft(m)((m, t) => {
+      val (pairs, node) = rdfNodeForTuple(u, t, r)
+      m ++ (pairs, node)
+    })
+  }
+
+  def rdfNodeForTuple (u:StemIRI, 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)
+	nodemap(u, r.name, r.pk.get.attrs, vs)
+      } else
+	/** Table has no primkary key (but has some candidate keys). */
+	freshbnode()
+    (r.candidates.map(k => {
+      val values:List[CellValue] = k.attrs.map(a => t(a))
+      (k, values)
+    }), s)
+  }
+
+  /** The triples-generating functions start with databasemap: */
+  def directDB (u:StemIRI, db:Database) : Graph = {
+    val idxables = db.keySet.toSet filter { rn => !db(rn).candidates.isEmpty }
+    val nodeMap:NodeMap = idxables map {rn => rn -> relation2KeyMap(u, db(rn))}
+    db.keySet.toSet.flatMap((rn:RelName) => directR(u, db(rn), nodeMap, db))
+  }
+
+  def directR (u:StemIRI, r:Relation, nodes:NodeMap, db:Database) : Graph =
+    /* flatMap.toSet assumes that no two triples from directT would be the same.
+     * We know this because relations with candidate keys are mapped to unique
+     * subjects, and potentially redundant rows get unique blank node subjects.
+     */
+    r.body.flatMap(t => directT(u, t, r, nodes, db)).toSet
+
+  def directT (u:StemIRI, t:Tuple, r:Relation, nodes:NodeMap, db:Database) : Set[Triple] = {
+    val s:Node =
+      if (r.candidates.size > 0) {
+	// 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
+	/** Table has no candidate keys. */
+	freshbnode()
+    directS(u, s, t, r, nodes, db)
+  }
+
+  def directS (u:StemIRI, s:Node, t:Tuple, r:Relation, nodes:NodeMap, db:Database) : Set[Triple] = {
+    references(t, r).map(as => directN(u, s, as, r, t, nodes)) ++
+    scalars(t, r).map(a => directL(u, r.name, s, a, r.header, t))
+  }
+
+  var NextBNode = 97
+  def freshbnode () : BNode = {
+    val ret = NextBNode
+    NextBNode = NextBNode + 1
+    BNode(ret.toChar.toString)
+  }
+
+  def directL (u:StemIRI, rn:RelName, s:Node, a:AttrName, h:Header, t:Tuple) : Triple = {
+    val p = predicatemap (u, rn, List(a))
+    val l = t.lexvalue(a).get
+    val o = literalmap(l, h.sqlDatatype(a))
+    Triple(s, p, o)
+  }
+  def directN (u:StemIRI, s:Node, as:List[AttrName], r:Relation, t:Tuple, nodes:NodeMap) : Triple = {
+    val p = predicatemap (u, r.name, as)
+    val ls:List[LexicalValue] = t.lexvaluesNoNulls(as)
+    val target = r.fks(as)
+    val o:Object = nodes(target.rel)(target.key)(ls)
+    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("_") + "#_")
+  }
+
+  def predicatemap (u:StemIRI, rn:RelName, as:List[AttrName]) : IRI =
+    u + ("/" + UE(rn) + "#" + as.mkString("_"))
+
+  def XSD (d:Datatype) : IRI =
+    d match {
+      case Datatype.INTEGER => IRI("http://www.w3.org/2001/XMLSchema#int")
+      case Datatype.FLOAT => IRI("http://www.w3.org/2001/XMLSchema#float")
+      case Datatype.DATE => IRI("http://www.w3.org/2001/XMLSchema#date")
+      case Datatype.TIME => IRI("http://www.w3.org/2001/XMLSchema#time")
+      case Datatype.TIMESTAMP => IRI("http://www.w3.org/2001/XMLSchema#timestamp")
+      case Datatype.CHAR => IRI("http://www.w3.org/2001/XMLSchema#char")
+      case Datatype.VARCHAR => IRI("http://www.w3.org/2001/XMLSchema#varchar")
+      case Datatype.STRING => IRI("http://www.w3.org/2001/XMLSchema#string")
+    }
+
+  def literalmap (l:LexicalValue, d:Datatype) : TypedLiteral =
+    TypedLiteral(l.s, XSD(d))
+
+  def UE (s:String) : String = s.replaceAll(" ", "+")
+}
+
--- a/rdb/src/main/scala/RDB.scala	Sun Oct 31 17:22:46 2010 -0400
+++ b/rdb/src/main/scala/RDB.scala	Sun Oct 31 20:39:17 2010 -0400
@@ -1,8 +1,8 @@
 package org.w3.sw.rdb
 
-import scala.collection.Set
-
-// Relational structure
+/**
+ * Relational structure
+ */
 object RDB {
 
   case class Database (m:Map[RelName, Relation]) {
@@ -18,7 +18,7 @@
 
   case class Header (m:Map[AttrName, Datatype]) {
     def apply (a:AttrName) = m(a)
-    def keySet () = m.keySet
+    def keySet () = m.keySet.toSet
     def sqlDatatype (a:AttrName) : Datatype = m(a)
     def contains (a:AttrName) : Boolean = m.contains(a)
   }
@@ -56,6 +56,7 @@
     val FLOAT = Datatype("Float")
     val DOUBLE = Datatype("Double")
     val DATE = Datatype("Date")
+    val TIME = Datatype("Time")
     val TIMESTAMP = Datatype("Timestamp")
     val DATETIME = Datatype("Datetime")
   }
--- a/rdf/src/main/scala/RDF.scala	Sun Oct 31 17:22:46 2010 -0400
+++ b/rdf/src/main/scala/RDF.scala	Sun Oct 31 20:39:17 2010 -0400
@@ -1,31 +1,64 @@
-package org.w3.sw.rdf
-
-import java.net.URI
-
-case class RDFTriple(s:RDFSubject, p:RDFPredicate, o:RDFObject)
-
-sealed abstract class RDFSubject()
-case class RDFSubjectUri(uri:URI) extends RDFSubject
-case class RDFSubjectBlankNode(b:BlankNode) extends RDFSubject
+package org.w3.sw
 
-case class RDFPredicate(uri:URI)
-
-sealed abstract class RDFObject()
-case class RDFObjectUri(uri:URI) extends RDFObject
-case class RDFObjectBlankNode(b:BlankNode) extends RDFObject
+object rdf {
 
-case class BlankNode(debugName:String)
+type Graph = Set[Triple]
 
-case class RDFLiteral(lexicalForm:String, datatype:Datatype) {
-  override def toString = "\"" + lexicalForm + "\"" + datatype
+case class Triple (s:Subject, p:Predicate, o:Object)
+
+sealed abstract class Node // factor out IRIs and BNodes
+case class NodeIRI(i:IRI) extends Node
+implicit def iri2nodeiri(i:IRI):Node = NodeIRI(i)
+case class NodeBNode(b:BNode) extends Node
+implicit def bnode2nodebnode(b:BNode):Node = NodeBNode(b)
+
+sealed abstract class Subject
+case class SubjectNode(n:Node) extends Subject
+implicit def node2subjectnode(n:Node):Subject = SubjectNode(n)
+implicit def iri2subjectnode(i:IRI):Subject = SubjectNode(i)
+implicit def bnode2subjectnode(b:BNode):Subject = SubjectNode(b)
+
+sealed abstract class Predicate
+case class PredicateIRI(i:IRI) extends Predicate
+implicit def iri2predicateiri(i:IRI):Predicate = PredicateIRI(i)
+
+sealed abstract class Object
+case class ObjectNode(n:Node) extends Object
+implicit def node2objectnode(n:Node):Object = ObjectNode(n)
+implicit def iri2objectnode(i:IRI):Object = ObjectNode(i)
+implicit def bnode2objectnode(b:BNode):Object = ObjectNode(b)
+case class ObjectLiteral (n:Literal) extends Object
+
+case class IRI(iri:String) {
+  override def toString = '"' + iri + '"'
 }
-case class Datatype(uri:URI) {
-  override def toString = "^^" + uri
+case class BNode(label:String)
+
+  sealed abstract class Literal(val lexicalForm:String)
+
+  case class PlainLiteral(override val lexicalForm:String, langtag:Option[LangTag]) extends Literal(lexicalForm) {
+    override def toString = "\"" + lexicalForm + "\"" + { if (langtag.isDefined) langtag.get }
+  }
+  implicit def typed2object(i:TypedLiteral):Object = ObjectLiteral(i)
+
+  case class TypedLiteral(override val lexicalForm:String, datatype:IRI) extends Literal(lexicalForm) {
+    override def toString = "\"" + lexicalForm + "\"^^" + datatype
+  }
+  implicit def plain2object(b:PlainLiteral):Object = ObjectLiteral(b)
+
+  case class LangTag(s:String)
+
+val StringDatatype = IRI("http://www.w3.org/2001/XMLSchema#string")
+val IntegerDatatype = IRI("http://www.w3.org/2001/XMLSchema#integer")
+val DateDatatype = IRI("http://www.w3.org/2001/XMLSchema#date")
+val DateTimeDatatype = IRI("http://www.w3.org/2001/XMLSchema#dateTime")
+
 }
 
-object RDFLiteral {
-  val StringDatatype = Datatype(new URI("http://www.w3.org/2001/XMLSchema#string"))
-  val IntegerDatatype = Datatype(new URI("http://www.w3.org/2001/XMLSchema#integer"))
-  val DateDatatype = Datatype(new URI("http://www.w3.org/2001/XMLSchema#date"))
-  // val DateTimeDatatype = Datatype(new URI("http://www.w3.org/2001/XMLSchema#dateTime"))
-}
+// object Literal {
+//   val StringDatatype = Datatype(IRI("http://www.w3.org/2001/XMLSchema#string"))
+//   val IntegerDatatype = Datatype(IRI("http://www.w3.org/2001/XMLSchema#integer"))
+//   val DateDatatype = Datatype(IRI("http://www.w3.org/2001/XMLSchema#date"))
+//   // val DateTimeDatatype = Datatype(IRI("http://www.w3.org/2001/XMLSchema#dateTime"))
+// }
+
--- a/sparql/src/main/scala/SPARQL.scala	Sun Oct 31 17:22:46 2010 -0400
+++ b/sparql/src/main/scala/SPARQL.scala	Sun Oct 31 20:39:17 2010 -0400
@@ -1,6 +1,6 @@
 package org.w3.sw.sparql
 
-import org.w3.sw.rdf._
+import org.w3.sw.rdf
 import scala.util.parsing.combinator._
 import java.net.URI
 
@@ -201,9 +201,9 @@
   }
 }
 
-case class Literal(lit:RDFLiteral) {
+case class Literal(lit:rdf.Literal) {
   override def toString = lit match {
-    case RDFLiteral(s, RDFLiteral.IntegerDatatype) => s
+    case rdf.TypedLiteral(s, rdf.IntegerDatatype) => s
     case _ => lit.toString
   }
 }
@@ -411,15 +411,15 @@
   def literal:Parser[Literal] = (
       stringLiteral~"^^"~qnameORuri ^^
       {
-	case lit~"^^"~dt => Literal(RDFLiteral(lit.substring(1,lit.size - 1), dt.s match {
-	  case "http://www.w3.org/2001/XMLSchema#string" => RDFLiteral.StringDatatype
-	  case "http://www.w3.org/2001/XMLSchema#integer" => RDFLiteral.IntegerDatatype
-	  case "http://www.w3.org/2001/XMLSchema#date" => RDFLiteral.DateDatatype
-	  // case "http://www.w3.org/2001/XMLSchema#dateTime" => RDFLiteral.DateTimeDatatype
+	case lit~"^^"~dt => Literal(rdf.TypedLiteral(lit.substring(1,lit.size - 1), dt.s match {
+	  case "http://www.w3.org/2001/XMLSchema#string" => rdf.StringDatatype
+	  case "http://www.w3.org/2001/XMLSchema#integer" => rdf.IntegerDatatype
+	  case "http://www.w3.org/2001/XMLSchema#date" => rdf.DateDatatype
+	  // case "http://www.w3.org/2001/XMLSchema#dateTime" => rdf.DateTimeDatatype
 	  case x => error("only programed to deal with string and integer, not " + x)
 	}))
       }
-    | integer ^^ { l => Literal(RDFLiteral(l, RDFLiteral.IntegerDatatype)) }
+    | integer ^^ { l => Literal(rdf.TypedLiteral(l, rdf.IntegerDatatype)) }
   )
 
   def varr:Parser[Var] = "?"~ident ^^ { case "?"~x => Var(x) }
--- a/sparql/src/test/scala/SparqlTest.scala	Sun Oct 31 17:22:46 2010 -0400
+++ b/sparql/src/test/scala/SparqlTest.scala	Sun Oct 31 20:39:17 2010 -0400
@@ -1,8 +1,7 @@
 package org.w3.sw.sparql
 
-import org.w3.sw.rdf._
+import org.w3.sw.rdf
 import org.scalatest.FunSuite
-import java.net.URI
 
 class SparqlTest extends FunSuite {
 
@@ -11,7 +10,7 @@
     val e = """
 ?emp      <http://hr.example/DB/Employee#lastName>   "bob"^^<http://www.w3.org/2001/XMLSchema#string>
 """
-    val expected = TriplesBlock(List(TriplePattern(TermVar(Var("emp")),TermUri(Uri("http://hr.example/DB/Employee#lastName")),TermLit(Literal(RDFLiteral("bob",Datatype(new URI("http://www.w3.org/2001/XMLSchema#string"))))))))
+    val expected = TriplesBlock(List(TriplePattern(TermVar(Var("emp")),TermUri(Uri("http://hr.example/DB/Employee#lastName")),TermLit(Literal(rdf.TypedLiteral("bob",rdf.IRI("http://www.w3.org/2001/XMLSchema#string")))))))
     assert(expected === (a.parseAll(a.triplesblock, e).get))
   }
 
@@ -20,7 +19,7 @@
     val e = """
 ?emp      <http://hr.example/DB/Employee#age>   "21"^^<http://www.w3.org/2001/XMLSchema#integer>
 """
-    val expected = TriplesBlock(List(TriplePattern(TermVar(Var("emp")),TermUri(Uri("http://hr.example/DB/Employee#age")),TermLit(Literal(RDFLiteral("21",Datatype(new URI("http://www.w3.org/2001/XMLSchema#integer"))))))))
+    val expected = TriplesBlock(List(TriplePattern(TermVar(Var("emp")),TermUri(Uri("http://hr.example/DB/Employee#age")),TermLit(Literal(rdf.TypedLiteral("21",rdf.IRI("http://www.w3.org/2001/XMLSchema#integer")))))))
     assert(expected === (a.parseAll(a.triplesblock, e).get))
   }
 
@@ -383,7 +382,7 @@
 	      TriplePattern(
 		TermVar(Var("who")),
 		TermUri(Uri("http://hr.example/DB/Employee#lastName")),
-		TermLit(Literal(RDFLiteral("Smith",Datatype(new URI("http://www.w3.org/2001/XMLSchema#string")))))))),
+		TermLit(Literal(rdf.TypedLiteral("Smith",rdf.IRI("http://www.w3.org/2001/XMLSchema#string"))))))),
 	  TableDisjunction(List(
 	    TriplesBlock(
 	      List(
--- a/sparql2sql/src/main/scala/SparqlToSql.scala	Sun Oct 31 17:22:46 2010 -0400
+++ b/sparql2sql/src/main/scala/SparqlToSql.scala	Sun Oct 31 20:39:17 2010 -0400
@@ -259,7 +259,7 @@
     R2RState(state.joins,
 	     state.varmap,
 	     state.exprs + sql.RelationalExpressionEq(sql.PrimaryExpressionAttr(constrainMe),
-						      sql.PrimaryExpressionTyped(dt,sql.Name(lit.lit.lexicalForm))))    
+						      sql.PrimaryExpressionTyped(dt,sql.Name(lit.lit.lexicalForm))))
   }
 
   /** varConstraint
@@ -586,12 +586,13 @@
       case sparql.TermUri(u) => error("not implemented: translating RDF URI to SQL: " + u) // :sparql.Uri
       case sparql.TermVar(v) => sql.PrimaryExpressionAttr(varToAttribute(varmap, sparql.VarAssignable(v)))
       case sparql.TermBNode(b) => sql.PrimaryExpressionAttr(varToAttribute(varmap, sparql.BNodeAssignable(b)))
-      case sparql.TermLit(sparql.Literal(rdf.RDFLiteral(lit,rdf.Datatype(dt)))) =>
+      case sparql.TermLit(sparql.Literal(p:rdf.PlainLiteral)) => error("not implemented")
+      case sparql.TermLit(sparql.Literal(rdf.TypedLiteral(lit,dt))) =>
 	sql.PrimaryExpressionTyped({
-	  dt.toString match {
-	    case "http://www.w3.org/2001/XMLSchema#string" => rdb.RDB.Datatype.STRING
-	    case "http://www.w3.org/2001/XMLSchema#integer" => rdb.RDB.Datatype.INTEGER
-	    case "http://www.w3.org/2001/XMLSchema#date" => rdb.RDB.Datatype.DATE
+	  dt match {
+	    case rdf.IRI("http://www.w3.org/2001/XMLSchema#string") => rdb.RDB.Datatype.STRING
+	    case rdf.IRI("http://www.w3.org/2001/XMLSchema#integer") => rdb.RDB.Datatype.INTEGER
+	    case rdf.IRI("http://www.w3.org/2001/XMLSchema#date") => rdb.RDB.Datatype.DATE
 	    case _ => error("unable to translate to RDF literal SQL: \"" + lit + "\"^^<" + dt + ">")
 	  }
 	}, lit)
@@ -1078,12 +1079,13 @@
       case sparql.TermUri(u) => error("not implemented: translating RDF URI to SQL: " + u) // :sparql.Uri
       case sparql.TermVar(v) => sql.PrimaryExpressionAttr(varToAttribute(varmap, sparql.VarAssignable(v)))
       case sparql.TermBNode(b) => sql.PrimaryExpressionAttr(varToAttribute(varmap, sparql.BNodeAssignable(b)))
-      case sparql.TermLit(sparql.Literal(rdf.RDFLiteral(lit,rdf.Datatype(dt)))) =>
+      case sparql.TermLit(sparql.Literal(p:rdf.PlainLiteral)) => error("not implemented")
+      case sparql.TermLit(sparql.Literal(rdf.TypedLiteral(lit,dt))) =>
 	sql.PrimaryExpressionTyped({
-	  dt.toString match {
-	    case "http://www.w3.org/2001/XMLSchema#string" => rdb.RDB.Datatype.STRING
-	    case "http://www.w3.org/2001/XMLSchema#integer" => rdb.RDB.Datatype.INTEGER
-	    case "http://www.w3.org/2001/XMLSchema#date" => rdb.RDB.Datatype.DATE
+	  dt match {
+	    case rdf.IRI("http://www.w3.org/2001/XMLSchema#string") => rdb.RDB.Datatype.STRING
+	    case rdf.IRI("http://www.w3.org/2001/XMLSchema#integer") => rdb.RDB.Datatype.INTEGER
+	    case rdf.IRI("http://www.w3.org/2001/XMLSchema#date") => rdb.RDB.Datatype.DATE
 	    case _ => error("unable to translate to RDF literal SQL: \"" + lit + "\"^^<" + dt + ">")
 	  }
 	}, lit)
--- a/sql/src/main/scala/SQL.scala	Sun Oct 31 17:22:46 2010 -0400
+++ b/sql/src/main/scala/SQL.scala	Sun Oct 31 20:39:17 2010 -0400
@@ -5,8 +5,6 @@
 
 import scala.util.parsing.combinator._
 
-import scala.collection.Set
-
 object SQLParsers extends RegexParsers {
 
   val int = """[0-9]+""".r