--- a/src/main/scala/Main.scala Tue Sep 28 23:40:05 2010 -0400
+++ b/src/main/scala/Main.scala Wed Sep 29 00:28:35 2010 -0400
@@ -6,20 +6,46 @@
object SQL {
case class Database(m:Map[RelName, Relation]) {
+ def apply (rn:RelName) = m(rn)
+ def keySet () = m.keySet
def idxables():Set[RelName] = m.keySet filter { rn => !m(rn).candidates.isEmpty }
}
case class Relation (header:Header, body:Body, candidates:List[CandidateKey], pk:Option[CandidateKey], fks:ForeignKeys)
case class Header (m:Map[AttrName, SQLDatatype]) {
+ def apply (a:AttrName) = m(a)
def keySet () = m.keySet
- def apply (a:AttrName) = m(a)
+ def sqlDatatype (a:AttrName) : SQLDatatype = m(a)
}
type CandidateKey = List[AttrName]
- type ForeignKeys = Map[List[AttrName], Target]
+
+ case class ForeignKeys (m:Map[List[AttrName], Target]) {
+ def apply (l:List[AttrName]) = m(l)
+ def keySet () = m.keySet
+ def contains (l:List[AttrName]) = m.contains(l)
+ }
+ implicit def map2fks (m:Map[List[String],Target]) = ForeignKeys(m)
+
case class Target(rel:RelName, attrs:CandidateKey)
type Body = Set[Tuple]
- type Tuple = Map[AttrName, CellValue]
+ case class Tuple (m:Map[AttrName, CellValue]) {
+ def apply (a:AttrName) = m(a)
+ def lexvalue (a:AttrName) : Option[LexicalValue] =
+ m(a) match {
+ case ␀() => None
+ case v:LexicalValue => Some(v)
+ }
+ 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 {
+ case None => Some(a)
+ case _ => None
+ })
+ }
+ }
+ implicit def map2tuple (m:Map[AttrName, CellValue]):Tuple = Tuple(m)
abstract class CellValue
case class LexicalValue (s:String) extends CellValue
@@ -43,14 +69,6 @@
def header (r:Relation) : Header = r.header
def body (r:Relation) : Body = r.body
- def lexvalue (h:Header, t:Tuple, a:AttrName) : Option[LexicalValue] =
- t(a) match {
- case ␀() => None
- case v:LexicalValue => Some(v)
- }
-
- def sqlDatatype (h:Header, a:AttrName) : SQLDatatype = h(a)
-
}
// RDF node types
@@ -125,10 +143,10 @@
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 to a rearrangement of the pk?
- if (db.m(rn).pk.isDefined && db.m(rn).fks.contains(db.m(rn).pk.get)) {
+ // 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)) {
/** Table's primary key is a foreign key. */
- val target = db.m(rn).fks(db.m(rn).pk.get)
+ val target = db(rn).fks(db(rn).pk.get)
ultimateReferent(target.rel, target.attrs, vs, db)
} else
m(rn)(k)(vs)
@@ -142,25 +160,24 @@
// Mapping functions:
def databasemap (u:StemIRI, db:Database) : RDFGraph = {
- val nodes = NodeMap(db.idxables.map(rn => rn -> relation2subject(u, rn, db.m(rn))).toMap)
- db.m.keySet.flatMap(rn => relationmap(u, rn, db.m(rn), nodes, db))
+ val nodes = NodeMap(db.idxables.map(rn => rn -> relation2KeyMap(u, rn, db(rn))).toMap)
+ db.keySet.flatMap(rn => relationmap(u, rn, db(rn), nodes, db))
}
- def relation2subject (u:StemIRI, rn:RelName, r:Relation) : KeyMap = {
+ def relation2KeyMap (u:StemIRI, rn:RelName, r:Relation) : KeyMap = {
val m = KeyMap(Map[CandidateKey, Map[List[CellValue], Node]]())
body(r).foldLeft(m)((m, t) => {
- val s = tuple2subject(u, rn, t, r)
+ val s = rdfNodeForTuple(u, rn, t, r)
m ++ (s._1, s._2)
})
}
- def tuple2subject (u:StemIRI, rn:RelName, t:Tuple, r:Relation) : (List[(CandidateKey, List[CellValue])], Node) = {
+ def rdfNodeForTuple (u:StemIRI, rn:RelName, t:Tuple, r:Relation) : (List[(CandidateKey, List[CellValue])], Node) = {
val h = header(r)
val s:Node =
if (r.pk.isDefined) {
/** Table has a primkary key. */
- // Assume: no NULLs in primary key
- val vs = r.pk.get.map(k => lexvalue(h, t, k).get)
+ val vs = t.lexvaluesNoNulls(r.pk.get)
nodemap(u, rn, r.pk.get, vs)
} else
/** Table has no primkary key (but has some candidate keys). */
@@ -176,7 +193,7 @@
def tuplemap (u:StemIRI, rn:RelName, t:Tuple, r:Relation, nodes:NodeMap, db:Database) : Set[Triple] = {
val h = header(r)
- val hierarchicalKey:List[AttrName] =
+ val hierarchicalKey:CandidateKey =
if (r.pk.isDefined && r.fks.contains(r.pk.get))
r.fks(r.pk.get).attrs
else
@@ -187,7 +204,7 @@
// Known to have at least one key, so take the first one.
val k = r.candidates(0)
// Assume: no NULLs in candidate key
- val vs = k.map(a => lexvalue(h, t, a).get)
+ val vs = t.lexvaluesNoNulls(k)
nodes.ultimateReferent(rn, k, vs, db)
} else
/** Table has no candidate keys. */
@@ -198,7 +215,7 @@
val unaryFKs:Set[AttrName] = allFKs.flatMap(a => {
if (a.length == 1) a else None
})
- val nulllist = nulls(h, t)
+ val nulllist = t.nullAttributes(h)
val nullFKs:Set[List[AttrName]] = allFKs.flatMap(a => {
val int:Set[AttrName] = nulllist & a.toSet
if (int.toList.length == 0) None else List(a)
@@ -220,26 +237,18 @@
def scalartriples (u:StemIRI, rn:RelName, s:Node, a:AttrName, h:Header, t:Tuple) : Triple = {
val p = predicatemap (u, rn, List(a))
- val l = t(a).asInstanceOf[LexicalValue]
- val o = literalmap(l, sqlDatatype(h, a))
+ val l = t.lexvalue(a).get
+ val o = literalmap(l, h.sqlDatatype(a))
Triple(s, p, o)
}
def referencetriples (u:StemIRI, rn:RelName, s:Node, as:List[AttrName], r:Relation, t:Tuple, nodes:NodeMap) : Triple = {
val p = predicatemap (u, rn, as)
- val ls:List[LexicalValue] = as.map(a =>t(a).asInstanceOf[LexicalValue])
+ val ls:List[LexicalValue] = t.lexvaluesNoNulls(as)
val target = r.fks(as)
val o:Object = nodes(target.rel)(target.attrs)(ls)
Triple(s, p, o)
}
- def nulls (h:Header, t:Tuple) : Set[(AttrName)] = {
- h.keySet.flatMap(a =>
- lexvalue(h, t, a) match {
- case None => Some(a)
- case _ => None
- })
- }
-
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("_") + "#_")