~ referenceSemantics and lexicalValueSemantics no longer produce a Triple but only (Predicate, Object) no-hierarchy
authorAlexandre Bertails <bertails@gmail.com>
Sat, 12 Feb 2011 23:57:45 -0500
branchno-hierarchy
changeset 338 bcff22b5561a
parent 337 36f6fb9e06fa
child 339 44e6d81cb429
~ referenceSemantics and lexicalValueSemantics no longer produce a Triple but only (Predicate, Object)
~ ugly hack so that a Target can know directly about a Relation without needing a RelName
directmapping/src/main/scala/DirectMapping.scala
rdb/src/main/scala/RDB.scala
--- a/directmapping/src/main/scala/DirectMapping.scala	Sat Feb 12 22:48:05 2011 -0500
+++ b/directmapping/src/main/scala/DirectMapping.scala	Sat Feb 12 23:57:45 2011 -0500
@@ -37,14 +37,14 @@
      *   ∀ r:Relation, ∀ ck:CandidateKey, ck ∊ Relation, ∀ t1:Tuple, ∀ t2:Tuple,
      *   t1 ≠ t2 -> l1 = t1(ck) -> l2 = t2(ck) -> l1 = l2 -> nodemap(r)(ck)(l1) ≠ nodemap(r)(ck)(l1)
      */
-    type NodeMap = PartialFunction[RelName, KeyMap]
+    type NodeMap = PartialFunction[Relation, KeyMap]
 
     /**
      * dbToNodeMap builds the NodeMap making the tuple Node accessible to their candidate keys
      * it's defined only for the indexable table, as we need to have at least one candidate key
      */
     def dbToNodeMap(db:Database):NodeMap =
-      db.indexables map { rn => rn -> keyMapForRelation(db(rn)) } toMap
+      db.indexables map { r => r -> keyMapForRelation(r) } toMap
 
     /**
      * given:
@@ -111,34 +111,53 @@
       Graph(r.body flatMap { t => tupleSemantics(db, nodemap, r, t) })
   
     def tupleSemantics (db:Database, nodemap:NodeMap, r:Relation, t:Tuple):Set[Triple] = {
-      val s:Node =
+      val s:SubjectNode =
 	// look for the first candidate key if available
         r.candidates.headOption match {
 	  // if there is a candidate key, we know we can retrieve the mapped node
 	  // null values are ok at that point
           case Some(firstKey) => {
             val cellvalues = t.cellvalues(firstKey)
-            nodemap(r.name)(firstKey)(cellvalues)
+	    val mappedNode = nodemap(r)(firstKey)(cellvalues)
+            SubjectNode(mappedNode)
           }
           // there is no candidate key, we have to come up with a new bnode
-          case None =>
-            NodeBNode(freshbnode())  
+          case None => {
+            val freshnode = NodeBNode(freshbnode())  
+	    SubjectNode(freshnode)
+	  }
         }
-      // the foreign keys create triples
-      val triplesFromFKs = t.references(r) map { referenceSemantics(s, _, r, t, nodemap) }
-      // the lexical values (ie. not null values) also create triples
-      val triplesFromLexicalValues = t.scalars(r) flatMap { lexicalValueSemantics(r, s, _, t) }
+      val fromFKs = t.references(r) map { fk => referenceSemantics(r, nodemap, t, fk) }
+      // 
+      val fromLexicalValues = t.scalars(r) flatMap { a => lexicalValueSemantics(r, t, a) }
       // the relation provenance is mapped to an RDF type information, computed from the relation itself
-      val triple = Triple(SubjectNode(s),
-			  PredicateIRI(IRI("http://www.w3.org/1999/02/22-rdf-syntax-ns#type")),
+      val fromRelation = (PredicateIRI(IRI("http://www.w3.org/1999/02/22-rdf-syntax-ns#type")),
 			  ObjectNode(NodeIRI(IRI(UE(r)))))
-      triplesFromFKs ++ triplesFromLexicalValues + triple
+      (fromFKs ++ fromLexicalValues + fromRelation) map { case (p, o) => Triple(s, p, o) }
     }
 
     /**
-     * 
+     * a foreign key contribute to generating triples
      */
-    def lexicalValueSemantics(r:Relation, s:Node, a:AttrName, t:Tuple):Option[Triple] = {
+    def referenceSemantics (r:Relation, nodes:NodeMap, t:Tuple, fk:ForeignKey):(Predicate, Object) = {
+      val p = predicateSemantics (r, fk)
+      val cellvalues:List[CellValue] = t.cellvalues(fk)
+      val ForeignKey(as, target@Target(_, key)) = fk
+      val rel = target.r
+      if (!(nodes isDefinedAt rel))
+        error("No referent relation \"" + rel + "\" to match " + r.name + t)
+      if (!(nodes(rel) isDefinedAt key))
+        error("Relation " + rel + " has no attributes (" + key + ") to match " + r.name + t)
+      if (!(nodes(rel)(key) isDefinedAt cellvalues))
+        error("Relation " + rel + "(" + key + ") has no values " + cellvalues + " to match " + r.name + t)
+      val o:Object = ObjectNode(nodes(rel)(key)(cellvalues))
+       (PredicateIRI(p), o)
+     }
+
+    /**
+     * a lexical value contribute to generating triples (only if it is not null)
+     */
+    def lexicalValueSemantics(r:Relation, t:Tuple, a:AttrName):Option[(Predicate, Object)] = {
       // a is implicitly promoted to an AttrList
       val p = predicateSemantics(r, a)
       val cellValue = t(a)
@@ -146,30 +165,17 @@
       (cellValue, datatype)  match {
 	case (LexicalValue(l), Datatype.STRING) => {
 	  val o = PlainLiteral(l, None)
-	  Some(Triple(SubjectNode(s), PredicateIRI(p), ObjectLiteral(o)))
+	  Some(PredicateIRI(p), ObjectLiteral(o))
 	}
 	case (LexicalValue(l), d) => {
 	  val o = TypedLiteral(l, datatypeSemantics(d))
-	  Some(Triple(SubjectNode(s), PredicateIRI(p), ObjectLiteral(o)))
+	  Some(PredicateIRI(p), ObjectLiteral(o))
 	}
 	case (␀, _) => None
       }
+      
     }
 
-    def referenceSemantics (s:Node, fk:ForeignKey, r:Relation, t:Tuple, nodes:NodeMap) : Triple = {
-      val p = predicateSemantics (r, fk)
-      val cellvalues:List[CellValue] = t.cellvalues(fk)
-      val ForeignKey(as, Target(rel, key)) = fk
-      if (!(nodes isDefinedAt rel))
-        error("No referent relation \"" + rel + "\" to match " + r.name + t)
-      if (!(nodes(rel) isDefinedAt key))
-        error("Relation " + rel + " has no attributes (" + key + ") to match " + r.name + t)
-      if (!(nodes(rel)(key) isDefinedAt cellvalues))
-        error("Relation " + rel + "(" + key + ") has no values " + cellvalues + " to match " + r.name + t)
-      val o:Object = ObjectNode(nodes(rel)(key)(cellvalues))
-       Triple(SubjectNode(s), PredicateIRI(p), o)
-     }
-
     def predicateSemantics (r:Relation, as:AttrList) : IRI =
       IRI(UE(r) + "#" + as.attrs.mkString("_"))
 
@@ -188,8 +194,7 @@
 
     // These invariants make nodemap and predicateSemantics functions prettier.
     def UE(s:String):String = s.replaceAll(" ", "+")
-    def UE(rn:RelName):String = UE(rn.n)
-    def UE(r:Relation):String = UE(r.name)
+    def UE(r:Relation):String = UE(r.name.n)
     def UE(a:AttrName):String = UE(a.n)
   
     def iri(rn:Relation, as:AttrList, ls:List[LexicalValue]):IRI = {
--- a/rdb/src/main/scala/RDB.scala	Sat Feb 12 22:48:05 2011 -0500
+++ b/rdb/src/main/scala/RDB.scala	Sat Feb 12 23:57:45 2011 -0500
@@ -9,12 +9,22 @@
    * a Database maps a relation name to the actual Relation
    */
   case class Database(private val m:Map[RelName, Relation]) extends PartialFunction[RelName, Relation] {
+    // tricky and evil
+    // when the Database is created, it can go through all the foreign key and set the database field
+    // this way, a Target can know directly the Relation without using Database
+    for {
+      (_, r) <- m
+      fk <- r.fks
+    } {
+      fk.target.db = Some(this)
+    }
+
     def apply(rn:RelName) = m(rn)
     def isDefinedAt(rn:RelName) = m isDefinedAt rn
     /** returns all the relation names */
     def relNames:Set[RelName] = m.keySet.toSet
     /** return all the relations with at least on Candidate Key */
-    def indexables = m collect { case (rn, r) if r.isIndexable => rn }
+    def indexables = m collect { case (rn, r) if r.isIndexable => r }
   }
 
   object Database {
@@ -33,6 +43,7 @@
 		      candidates:List[CandidateKey],
 		      pk:Option[CandidateKey],
 		      fks:ForeignKeys) {
+
     /** adds a tuple in the body of the relation */
     def +(t:Tuple):Relation = this.copy(body = body :+ t)
     /** a relation is indexable if it has at least one candidate key */
@@ -116,6 +127,7 @@
     def unaryFKs:Set[ForeignKey] = fks filter { _.isUnary }
     def definesActuallyUnaryFK(a:AttrName):Boolean = unaryFKs exists { _.attrs contains a }
     def filter(p: ForeignKey => Boolean):Set[ForeignKey] = fks filter p
+    def foreach(f:ForeignKey => Unit) = fks foreach f
   }
 
   object ForeignKeys {
@@ -125,7 +137,12 @@
 
   case class ForeignKey(attrs:List[AttrName], target:Target) extends AttrList
 
-  case class Target(rel:RelName, key:CandidateKey)
+  case class Target(rel:RelName, key:CandidateKey) {
+    var db:Option[Database] = None
+    lazy val r:Relation = db.get(rel)
+  }
+
+
 
   case class CandidateKey (attrs:List[AttrName]) extends AttrList