--- a/src/main/scala/SQL.scala Wed Jan 06 17:24:50 2010 -0500
+++ b/src/main/scala/SQL.scala Thu Jan 07 09:31:42 2010 -0500
@@ -54,11 +54,15 @@
override def toString = n.s /* "'" + n.s + "'" */
}
case class TableList(joins:AddOrderedSet[Join]) {
- override def toString = " FROM " + joins.foldLeft(("", 0))(
- (pair, entry) => (pair._1 + {
- if (pair._2 == 0) entry.toString.substring(19) // !!! shameless!
- else entry
- }, pair._2+1))._1
+ override def toString =
+ if (joins.size == 0) ""
+ else {
+ " FROM " + joins.foldLeft(("", 0))(
+ (pair, entry) => (pair._1 + {
+ if (pair._2 == 0) entry.toString.substring(19) // !!! shameless!
+ else entry
+ }, pair._2+1))._1
+ }
}
sealed abstract class Join(res:AliasedResource)
@@ -137,11 +141,14 @@
rep1sep(select, "UNION") ^^ { l => if (l.size == 1) l(0) else Union(l.toSet) }
def select:Parser[Select] =
- "SELECT" ~ attributelist ~ "FROM" ~ tablelist ~ opt(where) ^^
+ "SELECT" ~ attributelist ~ opt(tablelist) ~ opt(where) ^^
{
- case "SELECT" ~ attributes ~ "FROM" ~ tablesANDons ~ whereexpr => {
- val t:Set[Expression] = tablesANDons._2
- val onConjoints:Set[Expression] = tablesANDons._2.foldLeft(Set[Expression]())((s, ent) =>
+ case "SELECT" ~ attributes ~ tablesANDons ~ whereexpr => {
+ val (tables, onExpressions) =
+ tablesANDons.getOrElse((TableList(AddOrderedSet[Join]()), Set[Expression]()))
+ val t:Set[Expression] = onExpressions
+ val onConjoints:Set[Expression] =
+ onExpressions.foldLeft(Set[Expression]())((s, ent) =>
s ++ {ent match {
case ExprConjunction(l) => l
case _ => Set(ent)
@@ -156,7 +163,7 @@
case 1 => Some(conjoints.toList(0))
case _ => Some(ExprConjunction(conjoints))
}
- Select(attributes, tablesANDons._1, expr)
+ Select(attributes, tables, expr)
}
}
@@ -195,8 +202,9 @@
"""[a-zA-Z_]\w*""".r ^^ { x => RelAlias(Name(x)) }
def tablelist:Parser[(TableList, Set[Expression])] =
- aliasedjoin ~ rep(innerORouter) ^^ { case aj~l => (TableList(AddOrderedSet(InnerJoin(aj) :: l.map((one) => one._1))),
- l.foldLeft(Set[Expression]())((all, one) => all ++ one._2)) }
+ "FROM" ~ aliasedjoin ~ rep(innerORouter) ^^
+ { case "FROM"~aj~l => (TableList(AddOrderedSet(InnerJoin(aj) :: l.map((one) => one._1))),
+ l.foldLeft(Set[Expression]())((all, one) => all ++ one._2)) }
def innerORouter:Parser[(Join, Set[Expression])] = (
"INNER" ~ "JOIN" ~ aliasedjoin ~ opt("ON" ~ expression) ^^
--- a/src/test/scala/SQLTest.scala Wed Jan 06 17:24:50 2010 -0500
+++ b/src/test/scala/SQLTest.scala Thu Jan 07 09:31:42 2010 -0500
@@ -48,6 +48,19 @@
assert(expected === (a.parseAll(a.expression, e).get))
}
+ test("parse no FROM") {
+ // AliasedResource(Relation(Name("Employee")),RelAlias(Name("R_emp")))
+ val a = Sql()
+ val e = """
+SELECT 1 AS _TEST_
+"""
+ val expected = Select(AttributeList(Set(NamedAttribute(PrimaryExpressionTyped(Datatype.INTEGER,Name("1")),
+ AttrAlias(Name("_TEST_"))))),
+ TableList(AddOrderedSet()),
+ None)
+ assert(expected === (a.parseAll(a.select, e).get))
+ }
+
test("parse WHERE") {
// AliasedResource(Relation(Name("Employee")),RelAlias(Name("R_emp")))
val a = Sql()