package scala.dbc2.syntax import DBC2Tokens._ import TokenVal._ import statement.AnyValueDef._ import java.lang.String /** Object ExpressionSyntax provide some tools to write a complete SQL request in scala. The syntax of the request is not exactly the SQL syntax because of limitation of the names of methods in that language. When writing some request, you should not use scala short syntax. */ object ExpressionSyntax { private[dbc2] def toLTWC(list: List[List[Token]]): List[Token] = list.tail.foldLeft[List[Token]](list.head)((accu, elem) => accu ::: List(COMMA) ::: elem) private[dbc2] def toLOWC(list: List[Token]): List[Token] = toLTWC(list.map(List(_))) private[dbc2] def listWithPar(exprs: List[ExpressionBeyond[statement.Relation]]) = new ExpressionBeyond[statement.Relation] { def tokens: List[Token] = listObjectToListToken(RPAREN :: toLTWC(exprs.reverse.map(getTokens(_))) ::: List(LPAREN)) } implicit private[dbc2] def listObjectToListToken(list: List[Object]): List[Token] = list.map(elem => elem match { case t: Token => t case t: TokenValue => token(t) case s: Symbol => token(s) case a: AnyValue => token(a) case _ => {println(elem); error("error")} }) //Beginnig of each request. //def select(cols: List[ExpressionBeyond[statement.Relation]]) = ExpressionBeyond[statement.Relation](toLTWC(cols.reverse.map(getTokens(_))) ::: List(SELECT)) //def select(setQuantifier: TokenValue, cols: List[ExpressionBeyond[statement.Relation]]) = ExpressionBeyond[statement.Relation](toLTWC(cols.reverse.map(getTokens(_))) ::: List(setQuantifier, SELECT)) /** Used for the setFunctions. */ def generalFunction(setQuantifier: Option[TokenValue], func: TokenValue, expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[statement.Relation](setQuantifier match { case None => listObjectToListToken(RPAREN :: getTokens(expr) ::: List(LPAREN, func)) case Some(t) => listObjectToListToken(RPAREN :: getTokens(expr) ::: List(t, LPAREN, func)) }) /** Class that provide functions to write an SQL request in scala. That class doesn't check that the request is well formed. It only creates a list of tokens that can be parsed. */ abstract class ExpressionBeyond[T <: statement.Statement] { //def tokens: List[Object] def tokens: List[Token] /** Parse the list of tokens with an SQL parser. */ def parse: T = { val p = new SQLParser import p.{Success, Failure, Error} import dbc2.exception.ParseRequestException //p.phrase(p.request)(new MyScanner(tokens.reverse, tokens.size))//.get p.request(new MyScanner(/*listObjectToListToken(tokens.reverse)*/ tokens.reverse, tokens.size)) match { case s@Success(_, _) => s.get match { case t: T => t } case Failure(msg, scan) => throw new ParseRequestException("[" + scan.pos + "] " + msg) case Error(msg, scan) => throw new ParseRequestException("[" + scan.pos + "] " + msg) } } def into(table_name: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(table_name) ::: List(INTO) ::: ExpressionBeyond.this.tokens) /** Method that adds the token TABLE and the table name. Used when we specifie the table * scope with createGlobal or createLocal. */ def table(table_name: Symbol) = ExpressionBeyond[T](List(table_name, TABLE) ::: ExpressionBeyond.this.tokens) /** Method that adds the list of columns (names or definitions) surrounded by parenthesis. */ def columns(exprs: ExpressionBeyond[statement.Relation]*) = ExpressionBeyond[T](RPAREN :: toLTWC(exprs.toList.reverse.map(getTokens(_))) ::: List(LPAREN) ::: ExpressionBeyond.this.tokens) /** Method that adds a list of expressions surrounded by parenthesis and separated by comma to the list of tokens. Used in create request to define the list of column that are concerned by the request. */ def vals(exprs: ExpressionBeyond[statement.Relation]*) = ExpressionBeyond[T](RPAREN :: toLTWC(exprs.toList.reverse.map(getTokens(_))) ::: List(LPAREN) ::: ExpressionBeyond.this.tokens) /** Same method as is(...) but it adds an AS token before the list. Used in create request where we use a subquery. */ //def as(exprs: ExpressionBeyond[statement.Relation]*) = ExpressionBeyond[T](RPAREN :: toLTWC(exprs.toList.reverse.map(getTokens(_))) ::: List(LPAREN, AS) ::: ExpressionBeyond.this.tokens) def as(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(expr) ::: List(LPAREN, AS) ::: ExpressionBeyond.this.tokens) def asType(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(AS) ::: ExpressionBeyond.this.tokens) /** Adds a subquery to the list of tokens. The subquery is surrounded by parenthesis. */ def subquery(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(expr) ::: List(LPAREN) ::: ExpressionBeyond.this.tokens) /** Adds the token VALUES and a list of tuples separated by commas. Used in the insert request. */ def values(exprs: Product*): ExpressionBeyond[T] = ExpressionBeyond[T](toLTWC(exprs.toList.map(e => getTokens(ShortSyntax.productToExpressionBeyond(e)))) ::: List(VALUES) ::: ExpressionBeyond.this.tokens) def values(e: ExpressionBeyond[statement.Relation], exprs: ExpressionBeyond[statement.Relation]*): ExpressionBeyond[T] = ExpressionBeyond[T](RPAREN :: toLTWC((e::exprs.toList).reverse.map(getTokens(_))) ::: List(LPAREN, VALUES) ::: ExpressionBeyond.this.tokens) /** Adds the list of relation in from clause for the select request. */ def from(tables: ExpressionBeyond[statement.Relation]*) = ExpressionBeyond[T](toLTWC(tables.toList.reverse.map(getTokens(_))) ::: List(FROM) ::: ExpressionBeyond.this.tokens) /** Specify the condition where that (or part of) request has to be applied. */ def where(search: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(search) ::: List(WHERE) ::: ExpressionBeyond.this.tokens) /** In select request, specify the \"group by\" clause. */ lazy val group = ExpressionBeyond[T](GROUP :: ExpressionBeyond.this.tokens) /** In select request, specify the \"having\" clause. */ def having(search: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(search) ::: List(HAVING) ::: ExpressionBeyond.this.tokens) /** In create request, specify the \"with data\" option */ def With(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(WITH) ::: ExpressionBeyond.this.tokens) /** In create request, specify the \"with no data\" option */ //def withNo(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(NO, WITH) ::: ExpressionBeyond.this.tokens) /** In update request, specify how fields are changed */ def set(expr: ExpressionBeyond[statement.Relation]*) = ExpressionBeyond[T](toLTWC(expr.toList.reverse.map(getTokens(_))) ::: List(SET) ::: ExpressionBeyond.this.tokens) /** In select request, specify the type for a specific field. */ def of(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(OF) ::: ExpressionBeyond.this.tokens) //Join options ("inner join", "left outer join", "right outer join", "full outer join") lazy val inner = ExpressionBeyond[T](INNER :: ExpressionBeyond.this.tokens) def inner(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(INNER) ::: ExpressionBeyond.this.tokens) lazy val outer = ExpressionBeyond[T](OUTER :: ExpressionBeyond.this.tokens) def outer(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(OUTER) ::: ExpressionBeyond.this.tokens) lazy val left = ExpressionBeyond[T](LEFT :: ExpressionBeyond.this.tokens) def left(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(LEFT) ::: ExpressionBeyond.this.tokens) lazy val right = ExpressionBeyond[T](RIGHT :: ExpressionBeyond.this.tokens) def right(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(RIGHT) ::: ExpressionBeyond.this.tokens) lazy val full = ExpressionBeyond[T](FULL :: ExpressionBeyond.this.tokens) def full(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(FULL) ::: ExpressionBeyond.this.tokens) def join(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(expr) ::: List(LPAREN, JOIN) ::: ExpressionBeyond.this.tokens) //Predicate part of request : // - is (not) null // - ... in (values) // - cast value as type // - ... op ... // - ... between ... and ... def is(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(IS) ::: ExpressionBeyond.this.tokens) def isNot(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(NOT, IS) ::: ExpressionBeyond.this.tokens) lazy val nullVal = ExpressionBeyond[T](NULLVAL :: ExpressionBeyond.this.tokens) def in(inValues: ExpressionBeyond[statement.Relation]*) = ExpressionBeyond[T](RPAREN :: toLTWC(inValues.toList.reverse.map(getTokens(_))) ::: List(LPAREN, IN) ::: ExpressionBeyond.this.tokens) def between(value: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(value) ::: List(LPAREN, BETWEEN) ::: ExpressionBeyond.this.tokens) def cast(operand: ExpressionBeyond[statement.Relation], target: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(target) ::: List(AS) ::: getTokens(operand) ::: List(LPAREN, CAST) ::: ExpressionBeyond.this.tokens) def rename(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(AS) ::: ExpressionBeyond.this.tokens) /** In column definition, specify the default value. */ def default(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(DEFAULT) ::: ExpressionBeyond.this.tokens) /** In insert request, we can insert default values */ def all(exprs: ExpressionBeyond[statement.Relation]*) = ExpressionBeyond[T](toLTWC(exprs.toList.reverse.map(getTokens(_))) ::: List(ALL) ::: ExpressionBeyond.this.tokens) def distinct(exprs: ExpressionBeyond[statement.Relation]*) = ExpressionBeyond[T](toLTWC(exprs.toList.reverse.map(getTokens(_))) ::: List(DISTINCT) ::: ExpressionBeyond.this.tokens) /** Filter for SetFunctions. */ def filter(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(expr) ::: List(LPAREN, FILTER) ::: ExpressionBeyond.this.tokens) /** We can not call the method "." to select a field in a table then it's replaced by the method **. */ def **(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(PERIOD) ::: ExpressionBeyond.this.tokens) //Don't work on Derby. def restrict = ExpressionBeyond[T](RESTRICT :: ExpressionBeyond.this.tokens) //Don't work on Derby. def cascade = ExpressionBeyond[T](CASCADE :: ExpressionBeyond.this.tokens) //Constraint definition def constraint(constraintName: Symbol) = ExpressionBeyond[T](constraintName :: List(CONSTRAINT) ::: ExpressionBeyond.this.tokens) def not(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(NOT) ::: ExpressionBeyond.this.tokens) lazy val unique = ExpressionBeyond[T](UNIQUE :: ExpressionBeyond.this.tokens) def unique(cols: Symbol*) = ExpressionBeyond[T](RPAREN :: toLOWC(cols.toList.reverse) ::: List(LPAREN, UNIQUE) ::: ExpressionBeyond.this.tokens) def primary(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[statement.Relation](getTokens(expr) ::: List(PRIMARY) ::: ExpressionBeyond.this.tokens) def foreign(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[statement.Relation](getTokens(expr) ::: List(FOREIGN) ::: ExpressionBeyond.this.tokens) def references(tableName: Symbol) = ExpressionBeyond[T](tableName :: List(REFERENCES) ::: ExpressionBeyond.this.tokens) def references(tableName: Symbol, cols: Symbol*) = ExpressionBeyond[T](RPAREN :: toLOWC(cols.toList.reverse) ::: List(LPAREN, tableName, REFERENCES) ::: ExpressionBeyond.this.tokens) def check(search: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(search) ::: List(LPAREN, CHECK) ::: ExpressionBeyond.this.tokens) lazy val key = ExpressionBeyond[T](KEY :: ExpressionBeyond.this.tokens) def key(cols: Symbol*) = ExpressionBeyond[T](RPAREN :: toLOWC(cols.toList.reverse) ::: List(LPAREN, KEY) ::: ExpressionBeyond.this.tokens) //Datatypes lazy val smallint = ExpressionBeyond[T](SMALLINT :: ExpressionBeyond.this.tokens) def smallint(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(SMALLINT) ::: ExpressionBeyond.this.tokens) lazy val integer = ExpressionBeyond[T](INTEGER :: ExpressionBeyond.this.tokens) def integer(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(INTEGER) ::: ExpressionBeyond.this.tokens) lazy val bigint = ExpressionBeyond[T](BIGINT :: ExpressionBeyond.this.tokens) def bigint(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(BIGINT) ::: ExpressionBeyond.this.tokens) def numeric(precision: Int) = ExpressionBeyond[T](List(RPAREN, token(precision), LPAREN, NUMERIC) ::: ExpressionBeyond.this.tokens) def numeric(precision: Int, scale: Int) = ExpressionBeyond[T](List(RPAREN, token(precision), COMMA, token(scale), LPAREN, NUMERIC) ::: ExpressionBeyond.this.tokens) lazy val real = ExpressionBeyond[T](REAL :: ExpressionBeyond.this.tokens) def real(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(REAL) ::: ExpressionBeyond.this.tokens) def double(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(DOUBLE) ::: ExpressionBeyond.this.tokens) lazy val precision = ExpressionBeyond[T](PRECISION :: ExpressionBeyond.this.tokens) lazy val boolean = ExpressionBeyond[T](BOOLEAN :: ExpressionBeyond.this.tokens) def boolean(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(BOOLEAN) ::: ExpressionBeyond.this.tokens) def character(length: Int) = ExpressionBeyond[T](List(RPAREN, token(length), LPAREN, CHARACTER) ::: ExpressionBeyond.this.tokens) def character(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(CHARACTER) ::: ExpressionBeyond.this.tokens) def varying(length: Int) = ExpressionBeyond[T](List(RPAREN, token(length), LPAREN, VARYING) ::: ExpressionBeyond.this.tokens) def large(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(LARGE) ::: ExpressionBeyond.this.tokens) lazy val Object = ExpressionBeyond[T](OBJECT :: ExpressionBeyond.this.tokens) def Object(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](getTokens(expr) ::: List(OBJECT) ::: ExpressionBeyond.this.tokens) //Operators and others functions for searchConditions def <(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(expr) ::: List(LPAREN, LT) ::: ExpressionBeyond.this.tokens) def <=(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(expr) ::: List(LPAREN, LE) ::: ExpressionBeyond.this.tokens) def >(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(expr) ::: List(LPAREN, GT) ::: ExpressionBeyond.this.tokens) def >=(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(expr) ::: List(LPAREN, GE) ::: ExpressionBeyond.this.tokens) def <>(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(expr) ::: List(LPAREN, DIFF) ::: ExpressionBeyond.this.tokens) def ===(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(expr) ::: List(LPAREN, EQ) ::: ExpressionBeyond.this.tokens) def and(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(expr) ::: List(LPAREN, AND) ::: ExpressionBeyond.this.tokens) def or(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(expr) ::: List(LPAREN, OR) ::: ExpressionBeyond.this.tokens) def notLog(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(expr) ::: List(LPAREN, NOT) ::: ExpressionBeyond.this.tokens) def +(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(expr) ::: List(LPAREN, PLUS) ::: ExpressionBeyond.this.tokens) def -(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(expr) ::: List(LPAREN, MINUS) ::: ExpressionBeyond.this.tokens) def *(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(expr) ::: List(LPAREN, ASTERISK) ::: ExpressionBeyond.this.tokens) def /(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(expr) ::: List(LPAREN, DIV) ::: ExpressionBeyond.this.tokens) def ||(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(expr) ::: List(LPAREN, CONCAT) ::: ExpressionBeyond.this.tokens) def union(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(expr) ::: List(LPAREN, UNION) ::: ExpressionBeyond.this.tokens) def except(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(expr) ::: List(LPAREN, EXCEPT) ::: ExpressionBeyond.this.tokens) def intersect(expr: ExpressionBeyond[statement.Relation]) = ExpressionBeyond[T](RPAREN :: getTokens(expr) ::: List(LPAREN, INTERSECT) ::: ExpressionBeyond.this.tokens) lazy val unknown = ExpressionBeyond[T](UNKNOWN :: ExpressionBeyond.this.tokens) override def toString = "ExpressionBeyond(" + tokens + ")" } def getTokens[T <: statement.Statement](ex: ExpressionBeyond[T]): List[Token] = if (ex == null) List(NULLVAL) else ex.tokens object ExpressionBeyond { def apply[T <: statement.Statement](tks: List[Token]): ExpressionBeyond[T] = new ExpressionBeyond[T] { def tokens: List[Token] = tks } def apply[T <: statement.Statement](tks: Token*): ExpressionBeyond[T] = new ExpressionBeyond[T] { def tokens: List[Token] = tks.toList } } }