--- a/src/main/scala/Main.scala Thu Apr 01 21:53:01 2010 -0400
+++ b/src/main/scala/Main.scala Fri Apr 02 04:40:48 2010 -0400
@@ -1,1 +1,95 @@
+package w3c.sw.StemGraph
+object Transformer {
+ // Transformation argument:
+ type StemURI = IRI
+
+ // Relational structure:
+ case class Relation ( name:RelName, header:Header, body:Body )
+ type Header = Map[AttrName, (LinkType, SQLDatatype)]
+ type Body = Set[Tuple]
+ type Tuple = Map[AttrName, Either[LexicalValue, ☹]]
+ case class ☹ () // SQL NULL value
+ sealed abstract class LinkType
+ case class Pk () extends LinkType
+ case class Fk(r:Relation, a:AttrName) extends LinkType
+ case class NotLinked () extends LinkType
+ sealed abstract class SQLDatatype
+ case class SQLString () extends SQLDatatype
+ case class SQLInt () extends SQLDatatype
+ type RelName = String
+ type AttrName = String
+ type LexicalValue = String
+
+ // RDF node types:
+ type RDFGraph = Set[RDFTriple]
+ case class RDFTriple (s:IRI, p:IRI, o:RDFObject)
+ sealed abstract class RDFObject
+ case class IRIObject (i:IRI) extends RDFObject
+ case class LiteralObject (l:RDFLiteral) extends RDFObject
+ type IRI = String
+ type RDFLiteral = String
+
+ // Accessor functions:
+ def pk (h:Header) : AttrName // Assume: one primary key.
+ = h.filter(x => x._2._1 == Pk()).keysIterator.toList(0)
+ def header (r:Relation) : Header = r.header
+ def body (r:Relation) : Body = r.body
+
+ def lexvalue (h:Header, t:Tuple, a:AttrName) : Either[LexicalValue, ☹]
+ = t(a)
+ def sqlDatatype (h:Header, a:AttrName) : SQLDatatype = h(a)._2
+ def linktype (h:Header, a:AttrName) : LinkType = h(a)._1
+ def relname (r:Relation) : RelName = r.name
+
+ // Mapping functions:
+ def relationmap (u:StemURI, r:Relation) : RDFGraph
+ = body(r).flatMap(t => tuplemap(u, t, r))
+
+ def tuplemap (u:StemURI, t:Tuple, r:Relation) : Set[RDFTriple] = {
+ val h = header(r)
+ val k = pk(h)
+ val s = nodemap(u, r, k, lexvalue(h, t, k).left.get) // Assume: no NULLs in primary key
+ h.keysIterator.toList.flatMap(a => cellmap(u, r, a, s, t)).toSet
+ }
+
+ def cellmap (u:StemURI, r:Relation, a:AttrName, s:IRI, t:Tuple) : Option[RDFTriple] = {
+ val h = header(r)
+ lexvalue(h, t, a) match {
+ case Right(☹()) => None
+ case Left(l:LexicalValue) => {
+ val p = predicatemap (u, r, a)
+ val o = linktype(h, a) match {
+ case Fk(r2, a2) => IRIObject(nodemap(u, r2, a2, l))
+ case _ => LiteralObject(literalmap(l, sqlDatatype(h, a)))
+ }
+ Some(RDFTriple(s, p, o))
+ }
+ }
+ }
+
+ def nodemap (u:StemURI, r:Relation, a:AttrName, l:LexicalValue) : IRI
+ = "<" + u + "/" + relname(r) + "/" + a + "." + l + "#foo>"
+ def predicatemap (u:StemURI, r:Relation, a:AttrName) : IRI
+ = "<" + u + "/" + relname(r) + "#" + a + ">"
+ def XSD (d:SQLDatatype) : IRI =
+ d match {
+ case SQLString() => "<http://www.w3.org/2001/XMLSchema#string>"
+ case SQLInt() => "<http://www.w3.org/2001/XMLSchema#int>"
+ }
+ def literalmap (l:LexicalValue, d:SQLDatatype) : RDFLiteral
+ = "\"" + l + "\"^^" + XSD(d)
+
+ // Utilities:
+ def toSet[T](list: List[T]) = {
+ def traverse(list: List[T])(set: Set[T]): Set[T] = list match {
+ case hd :: tail => traverse(tail)(set + hd)
+ case Nil => set
+ }
+
+ traverse(list)(Set[T]())
+ }
+
+}
+
+
--- a/src/test/scala/Test.scala Thu Apr 01 21:53:01 2010 -0400
+++ b/src/test/scala/Test.scala Fri Apr 02 04:40:48 2010 -0400
@@ -1,95 +1,8 @@
+import w3c.sw.StemGraph.Transformer._
import org.scalatest.FunSuite
-trait stemGraph {
-}
-
-
class Test extends FunSuite {
-
- type RelName = String
- case class Relation ( name:RelName, header:Header, body:Body )
- sealed abstract class LinkType
- case class Pk () extends LinkType
- case class Fk(r:Relation, a:AttrName) extends LinkType
- case class NotLinked () extends LinkType
- type Header = Map[AttrName, (LinkType, SQLDatatype)]
- type AttrName = String
- sealed abstract class SQLDatatype
- case class SQLString () extends SQLDatatype
- case class SQLInt () extends SQLDatatype
- type Tuple = Map[AttrName, Either[LexicalValue, ☹]]
- type Body = Set[Tuple]
- type LexicalValue = String
- type IRI = String
- type StemURI = IRI
- type RDFLiteral = String
- case class ☹ ()
-
- // == funcs ==
- def pk (h:Header) : AttrName
- = h.filter(x => x._2._1 == Pk()).keysIterator.toList(0)
- def header (r:Relation) : Header = r.header
- def body (r:Relation) : Body = r.body
-
- def lexvalue (h:Header, t:Tuple, a:AttrName) : Either[LexicalValue, ☹]
- = t(a)
- def sqlDatatype (h:Header, a:AttrName) : SQLDatatype = h(a)._2
- def linktype (h:Header, a:AttrName) : LinkType = h(a)._1
- def name (r:Relation) : RelName = r.name
- def nodemap (u:StemURI, r:Relation, a:AttrName, l:LexicalValue) : IRI
- = u + "/" + name(r) + "/" + a + "." + l + "#foo"
- def predicatemap (u:StemURI, r:Relation, a:AttrName) : IRI
- = u + "/" + name(r) + "#" + a
- def XSD (d:SQLDatatype) : IRI =
- d match {
- case SQLString() => "<http://...#string>"
- case SQLInt() => "<http://...#int>"
- }
- def literalmap (l:LexicalValue, d:SQLDatatype) : RDFLiteral
- = "\"" + l + "\"^^" + XSD(d)
-
- sealed abstract class RDFObject
- case class IRIObject (i:IRI) extends RDFObject
- case class LiteralObject (l:RDFLiteral) extends RDFObject
-
- case class RDFTriple (s:IRI, p:IRI, o:RDFObject)
- type RDFGraph = Set[RDFTriple]
-
- def cellmap (u:StemURI, r:Relation, a:AttrName, s:IRI, t:Tuple) : Option[RDFTriple] = {
- val h = header(r)
- lexvalue(h, t, a) match {
- case Right(☹()) => None
- case Left(l:LexicalValue) => {
- val p = predicatemap (u, r, a)
- val o = linktype(h, a) match {
- case Fk(r2, a2) => IRIObject(nodemap(u, r2, a2, l))
- case _ => LiteralObject(literalmap(l, sqlDatatype(h, a)))
- }
- Some(RDFTriple(s, p, o))
- }
- }
- }
-
- def toSet[T](list: List[T]) = {
- def traverse(list: List[T])(set: Set[T]): Set[T] = list match {
- case hd :: tail => traverse(tail)(set + hd) // create a new Set, adding hd
- case Nil => set
- }
-
- traverse(list)(Set[T]())
- }
-
- def tuplemap (u:StemURI, t:Tuple, r:Relation) : Set[RDFTriple] = {
- val h = header(r)
- val k = pk(h)
- val s = nodemap(u, r, k, lexvalue(h, t, k).left.get) // assume no NULLs in primary key
- h.keysIterator.toList.flatMap(a => cellmap(u, r, a, s, t)).toSet
- }
-
- def relationmap (u:StemURI, r:Relation) : RDFGraph
- = body(r).flatMap(t => tuplemap(u, t, r))
-
- test("") {
+ test("2 People 1 Addresses") {
val addresses = Relation("Addresses",
Map("ID" -> (Pk(), SQLInt()),
@@ -112,15 +25,15 @@
val u = "http://foo.example/DB"
val expected =
Set(
- RDFTriple("http://foo.example/DB/People/ID.7#foo","http://foo.example/DB/People#ID",LiteralObject("\"7\"^^<http://...#int>")),
- RDFTriple("http://foo.example/DB/People/ID.7#foo","http://foo.example/DB/People#fname",LiteralObject("\"Bob\"^^<http://...#string>")),
- RDFTriple("http://foo.example/DB/People/ID.7#foo","http://foo.example/DB/People#addr",IRIObject("http://foo.example/DB/Addresses/ID.18#foo")),
- RDFTriple("http://foo.example/DB/People/ID.8#foo","http://foo.example/DB/People#ID",LiteralObject("\"8\"^^<http://...#int>")),
- RDFTriple("http://foo.example/DB/People/ID.8#foo","http://foo.example/DB/People#fname",LiteralObject("\"Sue\"^^<http://...#string>")),
+ RDFTriple("<http://foo.example/DB/People/ID.7#foo>","<http://foo.example/DB/People#ID>",LiteralObject("\"7\"^^<http://www.w3.org/2001/XMLSchema#int>")),
+ RDFTriple("<http://foo.example/DB/People/ID.7#foo>","<http://foo.example/DB/People#fname>",LiteralObject("\"Bob\"^^<http://www.w3.org/2001/XMLSchema#string>")),
+ RDFTriple("<http://foo.example/DB/People/ID.7#foo>","<http://foo.example/DB/People#addr>",IRIObject("<http://foo.example/DB/Addresses/ID.18#foo>")),
+ RDFTriple("<http://foo.example/DB/People/ID.8#foo>","<http://foo.example/DB/People#ID>",LiteralObject("\"8\"^^<http://www.w3.org/2001/XMLSchema#int>")),
+ RDFTriple("<http://foo.example/DB/People/ID.8#foo>","<http://foo.example/DB/People#fname>",LiteralObject("\"Sue\"^^<http://www.w3.org/2001/XMLSchema#string>")),
- RDFTriple("http://foo.example/DB/Addresses/ID.18#foo","http://foo.example/DB/Addresses#ID",LiteralObject("\"18\"^^<http://...#int>")),
- RDFTriple("http://foo.example/DB/Addresses/ID.18#foo","http://foo.example/DB/Addresses#city",LiteralObject("\"Camrbidge\"^^<http://...#string>")),
- RDFTriple("http://foo.example/DB/Addresses/ID.18#foo","http://foo.example/DB/Addresses#state",LiteralObject("\"MA\"^^<http://...#string>")))
+ RDFTriple("<http://foo.example/DB/Addresses/ID.18#foo>","<http://foo.example/DB/Addresses#ID>",LiteralObject("\"18\"^^<http://www.w3.org/2001/XMLSchema#int>")),
+ RDFTriple("<http://foo.example/DB/Addresses/ID.18#foo>","<http://foo.example/DB/Addresses#city>",LiteralObject("\"Camrbidge\"^^<http://www.w3.org/2001/XMLSchema#string>")),
+ RDFTriple("<http://foo.example/DB/Addresses/ID.18#foo>","<http://foo.example/DB/Addresses#state>",LiteralObject("\"MA\"^^<http://www.w3.org/2001/XMLSchema#string>")))
assert (expected == relationmap(u, people) ++ relationmap(u, addresses))
}