+ parse INSERTs to populate DB
authorEric Prud'hommeaux <eric@w3.org>
Tue, 02 Nov 2010 17:14:43 -0400
changeset 252 ebdbce2c6ea4
parent 251 9fcd21747a7d
child 253 36cf6a08cca2
+ parse INSERTs to populate DB
rdb/src/main/scala/RDB.scala
sql/src/main/scala/SQL.scala
--- a/rdb/src/main/scala/RDB.scala	Tue Nov 02 16:55:25 2010 -0400
+++ b/rdb/src/main/scala/RDB.scala	Tue Nov 02 17:14:43 2010 -0400
@@ -14,7 +14,12 @@
       Database(l.map{r => (r.name -> r)}.toMap)
   }
 
-  case class Relation (name:RelName, header:Header, body:List[Tuple], candidates:List[CandidateKey], pk:Option[CandidateKey], fks:ForeignKeys)
+  case class Relation (name:RelName, header:Header, body:List[Tuple], candidates:List[CandidateKey], pk:Option[CandidateKey], fks:ForeignKeys) {
+    def ++ (t:Tuple):Relation = {
+      val b2:List[RDB.Tuple] = body ++ List(t)
+      Relation(name, header, b2, candidates, pk, fks)
+    }
+  }
 
   case class Header (m:Map[AttrName, Datatype]) {
     def apply (a:AttrName) = m(a)
--- a/sql/src/main/scala/SQL.scala	Tue Nov 02 16:55:25 2010 -0400
+++ b/sql/src/main/scala/SQL.scala	Tue Nov 02 17:14:43 2010 -0400
@@ -166,6 +166,7 @@
 case class FieldDesc(attr:RDB.AttrName, datatype:RDB.Datatype, pkness:Boolean) extends FieldDescOrKeyDeclaration
 sealed abstract class KeyDeclaration extends FieldDescOrKeyDeclaration
 case class PrimaryKeyDeclaration(key:RDB.CandidateKey) extends KeyDeclaration
+case class CandidateKeyDeclaration(key:RDB.CandidateKey) extends KeyDeclaration
 case class ForeignKeyDeclaration(fk:List[RDB.AttrName], rel:RDB.RelName, pk:RDB.CandidateKey) extends KeyDeclaration
 case class View(rel:RDB.RelName, defn:SelectORUnion) { // sibling of RDB.Relation
   override def toString = "CREATE VIEW " + rel + " AS\n" + defn
@@ -177,16 +178,27 @@
     "CREATE" ~ "VIEW" ~ relation ~ "AS" ~ selectORunion ^^
   { case "CREATE"~"VIEW"~relation~"AS"~defn => View(relation, defn) }
 
+  sealed abstract class DataDefinition
+  case class Create(rn:RDB.RelName, relation:RDB.Relation) extends DataDefinition
+  case class Insert(rn:RDB.RelName, tuple:RDB.Tuple) extends DataDefinition
+
   def ddl:Parser[RDB.Database] =
-    rep1sep(createtable, ";") ~ opt(";") ^^
+    rep1sep(createorinsert, ";") ~ opt(";") ^^
   {
     case l~x => RDB.Database(l.foldLeft(Map[RDB.RelName, RDB.Relation]())((m, p) => {
-      val (rel:RDB.RelName, desc:RDB.Relation) = p
-      m + (rel -> desc)
+      p match {
+	case Create(rn:RDB.RelName, relation:RDB.Relation) => m + (rn -> relation)
+	case Insert(rn:RDB.RelName, tuple:RDB.Tuple) => m + (rn -> (m(rn) ++ tuple)) // add the tuple
+      }
     }))
   }
 
-  def createtable:Parser[(RDB.RelName, RDB.Relation)] =
+  def createorinsert:Parser[DataDefinition] = (
+      createtable ^^ { case c => c }
+    | inserttable ^^ { case c => c }
+  )
+
+  def createtable:Parser[Create] =
     "CREATE" ~ "TABLE" ~ relation ~ "(" ~ rep1sep(fielddescorkeydef, ",") ~ ")" ^^
   {
     case "CREATE"~"TABLE"~relation~"("~reldesc~")" => {
@@ -211,12 +223,26 @@
 	    case PrimaryKeyDeclaration(key) =>
 	      // @@ why doesn't [[ candidates + RDB.CandidateKey(attr.n) ]] work?
 	      (Some(key), attrs, candidates ++ List(RDB.CandidateKey(key map {attr => RDB.AttrName(attr.n)})), fks)
+	    case CandidateKeyDeclaration(key) =>
+	      // @@ why doesn't [[ candidates + RDB.CandidateKey(attr.n) ]] work?
+	      (pkopt, attrs, candidates ++ List(RDB.CandidateKey(key map {attr => RDB.AttrName(attr.n)})), fks)
 	    case ForeignKeyDeclaration(fk, rel, pk) =>
 	      (pkopt, attrs, candidates, fks + (fk -> RDB.Target(rel, pk)))
 	  }
 	})
       val rd = RDB.Relation(relation, RDB.Header(attrs), List(), candidates, pk, RDB.ForeignKeys(fks))
-      (relation -> rd)
+      Create(relation, rd)
+    }
+  }
+
+  def inserttable:Parser[Insert] =
+    "INSERT" ~ "INTO" ~ relation ~ "(" ~ rep1sep(attribute, ",") ~ ")" ~ "VALUES" ~ "(" ~ rep1sep(value, ",") ~ ")" ^^
+  {
+    case "INSERT"~"INTO"~relation~"("~relnames~")"~"VALUES"~"("~values~")" => {
+      if (relnames.size != values.size)
+	error("different numbers of elements in names " + relnames + " vs. values " + values)
+      Map.empty ++ (relnames zip values)
+      Insert(relation, RDB.Tuple(Map.empty ++ (relnames zip values)))
     }
   }
 
@@ -225,12 +251,15 @@
       { case attribute~typpe~pkness => FieldDesc(attribute, typpe, pkness.isDefined) }
     | "PRIMARY" ~ "KEY" ~ "(" ~ rep1sep(attribute, ",") ~ ")" ^^
       { case "PRIMARY"~"KEY"~"("~attributes~")" => PrimaryKeyDeclaration(RDB.CandidateKey(attributes)) }
+    | "UNIQUE" ~ "(" ~ rep1sep(attribute, ",") ~ ")" ^^
+      { case "UNIQUE"~"("~attributes~")" => CandidateKeyDeclaration(RDB.CandidateKey(attributes)) }
     | "FOREIGN" ~ "KEY" ~ "(" ~ rep1sep(attribute, ",") ~ ")" ~ "REFERENCES" ~ relation ~ "(" ~ rep1sep(attribute, ",") ~ ")" ^^
       { case "FOREIGN"~"KEY"~"("~fk~")"~"REFERENCES"~relation~"("~pk~")" => ForeignKeyDeclaration(fk, relation, RDB.CandidateKey(pk)) }
   )
 
   def typpe:Parser[RDB.Datatype] = (
-      "INT" ^^ { case _ => RDB.Datatype.INTEGER }
+      "INT" ^^ { case _ => RDB.Datatype.INTEGER } // alias for INTEGER
+    | "INTEGER" ^^ { case _ => RDB.Datatype.INTEGER }
     | "DOUBLE" ^^ { case _ => RDB.Datatype.DOUBLE }
     | "STRING" ^^ { case _ => RDB.Datatype.STRING }
     | "DATETIME" ^^ { case _ => RDB.Datatype.DATETIME }
@@ -373,6 +402,12 @@
     | "(" ~ expression ~ ")" ^^ { case "("~x~")" => x }
   )
 
+  def value:Parser[RDB.CellValue] = (
+      int ^^ { i => RDB.LexicalValue(i) }
+    | chars  ^^ { x => RDB.LexicalValue(x.substring(1, x.size - 1)) }
+    | "NULL" ^^ { case "NULL" => RDB.␀() }
+  )
+
 }
 
 case class PrettySql(select:Select) {