+ CREATE VIEW
authorEric Prud'hommeaux <eric@w3.org>
Sat, 27 Feb 2010 08:46:18 -0500
changeset 176 afb41e675eaf
parent 175 2d389929e595
child 177 fff0e3d31323
+ CREATE VIEW
src/main/scala/SQL.scala
src/test/scala/SQLTest.scala
--- a/src/main/scala/SQL.scala	Sat Feb 27 00:26:57 2010 -0500
+++ b/src/main/scala/SQL.scala	Sat Feb 27 08:46:18 2010 -0500
@@ -169,11 +169,16 @@
 sealed abstract class KeyDeclaration extends FieldDescOrKeyDeclaration
 case class PrimaryKeyDeclaration(attr:Attribute) extends KeyDeclaration
 case class ForeignKeyDeclaration(fk:Attribute, rel:Relation, pk:Attribute) extends KeyDeclaration
+case class View(rel:Relation, defn:SelectORUnion) // sibling of RelationDesc
 
 case class Sql() extends JavaTokenParsers {
 
+  def createview:Parser[View] = // @@@ could stick under ddl
+    "CREATE" ~ "VIEW" ~ relation ~ "AS" ~ selectORunion ^^
+  { case "CREATE"~"VIEW"~relation~"AS"~defn => View(relation, defn) }
+
   def ddl:Parser[DatabaseDesc] =
-    rep1sep(create, ";") ~ opt(";") ^^
+    rep1sep(createtable, ";") ~ opt(";") ^^
   {
     case l~x => DatabaseDesc(l.foldLeft(Map[Relation, RelationDesc]())((m, p) => {
       val (rel:Relation, desc:RelationDesc) = p
@@ -181,13 +186,17 @@
     }))
   }
 
-  def create:Parser[(Relation, RelationDesc)] =
+  def createtable:Parser[(Relation, RelationDesc)] =
     "CREATE" ~ "TABLE" ~ relation ~ "(" ~ rep1sep(fielddescorkeydef, ",") ~ ")" ^^
   {
     case "CREATE"~"TABLE"~relation~"("~reldesc~")" => {
       val pk0:Option[Attribute] = None
       val attrs0 = Map[Attribute, ValueDescription]()
       val fks0 = Map[Attribute, ForeignKey]()
+      /* <pk>: (most recently parsed) PRIMARY KEY
+       * <attrs>: map of attribute to type (e.g. INTEGER)
+       * <fks>: map holding FOREIGN KEY relation REFERENCES attr
+       */
       val (pk, attrs, fks) =
 	reldesc.foldLeft((pk0, attrs0, fks0))((p, rd) => {
 	  val (pkopt, attrs, fks) = p
@@ -198,10 +207,15 @@
 		else pkopt
 	      (pkNew, attrs + (attr -> value), fks)
 	    }
-	    case PrimaryKeyDeclaration(attr) => (Some(attr), attrs, fks)
-	    case ForeignKeyDeclaration(fk, rel, pk) => (pkopt, attrs, fks + (fk -> ForeignKey(rel, pk)))
+	    case PrimaryKeyDeclaration(attr) =>
+	      (Some(attr), attrs, fks)
+	    case ForeignKeyDeclaration(fk, rel, pk) =>
+	      (pkopt, attrs, fks + (fk -> ForeignKey(rel, pk)))
 	  }
 	})
+      /* Change data type of foreign key attributes to ForeignKey.
+       * The type isn't really lost -- it's the same as the referenced type.
+       */
       val attrs2 = attrs.map(x => {
 	val (attr:Attribute, value:Value) = x
 	if (fks.contains(attr))	(attr -> fks(attr))
--- a/src/test/scala/SQLTest.scala	Sat Feb 27 00:26:57 2010 -0500
+++ b/src/test/scala/SQLTest.scala	Sat Feb 27 08:46:18 2010 -0500
@@ -389,7 +389,7 @@
       (Relation("Sex_DE") -> 
        RelationDesc(Option(Attribute("ID")),
 		    Map(Attribute("ID") -> Value(Datatype.INTEGER))))
-      assert(expected === (a.parseAll(a.create, e).get))
+      assert(expected === (a.parseAll(a.createtable, e).get))
   }
 
   test("integrated PK") {
@@ -486,4 +486,33 @@
     assert(expected === (a.parseAll(a.ddl, e).get))
   }
 
+  test("CREATE VIEW") {
+    // AliasedResource(Relation(Name("Employee")),RelVar(Name("R_emp")))
+    val a = Sql()
+    val e = """
+CREATE VIEW triples AS SELECT
+            CONCAT("http://hr.example/DB/", "Employee", "/", "empid", ".", R_emp.id, "#record") AS S, 
+            "<http://hr.example/DB/Employee#lastName>" AS P, 
+            R_emp.lastName AS O
+       FROM Employee AS R_emp
+""" // "
+    val expected = View(Relation(Name("triples")), Select(AttributeList(Set(
+      NamedAttribute(Concat(List(PrimaryExpressionTyped(Datatype("String"),Name("http://hr.example/DB/")),
+				 PrimaryExpressionTyped(Datatype("String"),Name("Employee")),
+				 PrimaryExpressionTyped(Datatype("String"),Name("/")),
+				 PrimaryExpressionTyped(Datatype("String"),Name("empid")),
+				 PrimaryExpressionTyped(Datatype("String"),Name(".")),
+				 PrimaryExpressionAttr(RelVarAttr(RelVar(Name("R_emp")),Attribute(Name("id")))),
+				 PrimaryExpressionTyped(Datatype("String"),Name("#record")))),
+		     AttrAlias(Name("S"))),
+      NamedAttribute(PrimaryExpressionTyped(Datatype.STRING,Name("<http://hr.example/DB/Employee#lastName>")),
+		     AttrAlias(Name("P"))),
+      NamedAttribute(RelVarAttr(RelVar(Name("R_emp")),
+				Attribute(Name("lastName"))),
+		     AttrAlias(Name("O"))))), 
+			  TableList(AddOrderedSet(InnerJoin(AliasedResource(Relation(Name("Employee")),RelVar(Name("R_emp"))), None))),
+			  None))
+    assert(expected === (a.parseAll(a.createview, e).get))
+  }
+
 }