Last active
November 3, 2018 01:25
-
-
Save tkroman/911671a50c39ee0bcc39b888bdcad616 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import AstElem._ | |
class AsString extends QueryAstVisitor[String] { | |
override def visitFromTable(from: From.Table): String = { | |
s"FROM ${from.name}" | |
} | |
override def visitFromNested(from: From.NestedQueryTree): String = { | |
s"FROM (${visitTopLevelQuery(from.tree)})" | |
} | |
override def visitFromUnion(from: From.NestedUnion): String = { | |
s"FROM (${visitUnion(from.union)})" | |
} | |
override def visitFromJoin(from: From.NestedJoin): String = { | |
s"FROM (${visitJoin(from.join)})" | |
} | |
override def visitHaving(having: Having): String = { | |
val Having(cond) = having | |
s"HAVING ${visitCond(cond)}" | |
} | |
override def visitGroupBy(groupBy: GroupBy): String = { | |
val GroupBy(fs, h) = groupBy | |
val fields: String = fs.mkString(",") | |
val having: String = h.map(visitHaving).getOrElse("") | |
s"GROUP BY $fields $having" | |
} | |
override def visitWhere(where: Where): String = { | |
val Where(cond) = where | |
s"WHERE ${visitCond(cond)}" | |
} | |
override def visitSelect(select: Select): String = { | |
val Select(fs) = select | |
s"SELECT ${fs.mkString(",")}" | |
} | |
override def visitCondAnd(cond: Cond.And): String = { | |
val Cond.And(a, b) = cond | |
s"(${visitCond(a)} AND ${visitCond(b)}))" | |
} | |
override def visitCondOr(cond: Cond.Or): String = { | |
val Cond.Or(a, b) = cond | |
s"(${visitCond(a)} OR ${visitCond(b)}))" | |
} | |
override def visitCondIn(cond: Cond.In): String = { | |
val Cond.In(fields, constExpr) = cond | |
s"(${fields.mkString(",")} IN ${constExpr.mkString("(",",",")")})" | |
} | |
override def visitCondInNested(cond: Cond.InNested): String = { | |
val Cond.InNested(fields, in) = cond | |
s"(${fields.mkString(",")} IN ${visitTopLevelQuery(in)})" | |
} | |
override def visitCondFlat(cond: Cond.Flat): String = { | |
s"(${cond.expr})" | |
} | |
override def visitJoin(join: Join): String = { | |
val Join(l, r, using, mod) = join | |
val left: String = visitTopLevelQuery(l) | |
val right: String = visitTopLevelQuery(r) | |
val fields: String = using.mkString(",") | |
s"$left $mod JOIN ($right) USING $fields)" | |
} | |
override def visitUnion(union: Union): String = { | |
val Union(qs) = union | |
qs.map(visitTopLevelQuery).mkString(" UNION ALL ") | |
} | |
override def visitTopLevelQuery(topLevelQuery: TopLevelQuery): String = { | |
val TopLevelQuery(select, from, where, groupBy) = topLevelQuery | |
val sel: String = visitSelect(select) | |
val froms: String = visitFrom(from) | |
val wheres: String = where.map(visitWhere).getOrElse("") | |
val groupBys: String = groupBy.map(visitGroupBy).getOrElse("") | |
s"$sel $froms $wheres $groupBys" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
sealed trait AstElem | |
object AstElem { | |
sealed trait From extends AstElem | |
object From { | |
case class Table(name: String) extends From | |
case class NestedQueryTree(tree: TopLevelQuery) extends From | |
case class NestedJoin(join: Join) extends From | |
case class NestedUnion(union: Union) extends From | |
} | |
case class Having(conditions: Cond) extends AstElem | |
case class GroupBy(fields: List[String], | |
having: Option[Having]) extends AstElem | |
case class Where(conditions: Cond) extends AstElem | |
case class Select(fields: List[String]) extends AstElem | |
sealed trait Cond extends AstElem { | |
def &(b: Cond): Cond = Cond.And(this, b) | |
def |(b: Cond): Cond = Cond.Or(this, b) | |
def &(b: Option[Cond]): Cond = { | |
b.map(c => Cond.And(this, c)).getOrElse(this) | |
} | |
def |(b: Option[Cond]): Cond = { | |
b.map(c => Cond.And(this, c)).getOrElse(this) | |
} | |
} | |
object Cond { | |
case class And(a: Cond, b: Cond) extends Cond | |
case class Or(a: Cond, b: Cond) extends Cond | |
case class Flat(expr: String) extends Cond | |
case class In(fields: List[String], constExpr: List[String]) extends Cond | |
case class InNested(fields: List[String], | |
in: TopLevelQuery) extends Cond | |
} | |
case class Join(left: TopLevelQuery, | |
right: TopLevelQuery, | |
using: List[String], | |
how: String = "ALL INNER") extends AstElem | |
case class Union(queries: List[TopLevelQuery]) extends AstElem | |
case class TopLevelQuery(select: Select, | |
from: From, | |
where: Option[Where], | |
groupBy: Option[GroupBy]) extends AstElem | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment