--- 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(" ", "+")
+}
+