All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.squeryl.dsl.ast.ExpressionNode.scala Maven / Gradle / Ivy

Go to download

A Scala ORM and DSL for talking with Databases using minimum verbosity and maximum type safety

The newest version!
/*******************************************************************************
 * Copyright 2010 Maxime Lévesque
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ***************************************************************************** */
package org.squeryl.dsl.ast

import scala.collection.mutable.ArrayBuffer

import org.squeryl.internals._
import org.squeryl.dsl._
import org.squeryl.Session
import reflect.ClassTag

trait ExpressionNode {

  var parent: Option[ExpressionNode] = None

  def id = Integer.toHexString(System.identityHashCode(this))

  def inhibited = _inhibitedByWhen

  def inhibitedFlagForAstDump =
    if (inhibited) "!" else ""

  def write(sw: StatementWriter) =
    if (!inhibited)
      doWrite(sw)

  def doWrite(sw: StatementWriter): Unit

  def writeToString: String = {
    val sw = new StatementWriter(Session.currentSession.databaseAdapter)
    write(sw)
    sw.statement
  }

  def children: List[ExpressionNode] = List.empty

  override def toString = this.getClass.getName

  private def _visitDescendants(
    n: ExpressionNode,
    parent: Option[ExpressionNode],
    depth: Int,
    visitor: (ExpressionNode, Option[ExpressionNode], Int) => Unit
  ): Unit = {
    visitor(n, parent, depth)
    n.children.foreach(child => _visitDescendants(child, Some(n), depth + 1, visitor))
  }

  private def _filterDescendants(
    n: ExpressionNode,
    ab: ArrayBuffer[ExpressionNode],
    predicate: (ExpressionNode) => Boolean
  ): Iterable[ExpressionNode] = {
    if (predicate(n))
      ab.append(n)
    n.children.foreach(child => _filterDescendants(child, ab, predicate))
    ab
  }

  def filterDescendants(predicate: (ExpressionNode) => Boolean) =
    _filterDescendants(this, new ArrayBuffer[ExpressionNode], predicate)

  def filterDescendantsOfType[T](implicit ClassTag: ClassTag[T]) =
    _filterDescendants(
      this,
      new ArrayBuffer[ExpressionNode],
      (n: ExpressionNode) => ClassTag.runtimeClass.isAssignableFrom(n.getClass)
    ).asInstanceOf[Iterable[T]]

  /**
   * visitor's args are :
   *  -the visited node,
   *  -it's parent
   *  -it's depth
   */
  def visitDescendants(visitor: (ExpressionNode, Option[ExpressionNode], Int) => Unit) =
    _visitDescendants(this, None, 0, visitor)

  protected var _inhibitedByWhen = false

  def inhibitWhen(inhibited: Boolean): this.type = {
    _inhibitedByWhen = inhibited
    this
  }

  def ? : this.type = {
    if (!this.isInstanceOf[ConstantTypedExpression[_, _]])
      throw new UnsupportedOperationException(
        "the '?' operator (shorthand for 'p.inhibitWhen(p == None))' can only be used on a constant query argument"
      )

    val c = this.asInstanceOf[ConstantTypedExpression[_, _]]

    inhibitWhen(c.value == None)
  }

  def cast[A, T](typ: String)(implicit tef: TypedExpressionFactory[A, T]): TypedExpression[A, T] =
    new CastExpressionNode(this, typ) with TypedExpression[A, T] {
      override def mapper = tef.createOutMapper
    }
}

class ListExpressionNode(override val children: List[ExpressionNode]) extends ExpressionNode {
  override def doWrite(sw: StatementWriter) = {
    sw.writeNodesWithSeparator(children, ", ", false)
  }
}

class RowValueConstructorNode(override val children: List[ExpressionNode]) extends ExpressionNode {
  override def doWrite(sw: StatementWriter) = {
    // sw.write("ROW")
    sw.write("(")
    sw.writeNodesWithSeparator(children, ", ", false)
    sw.write(")")
  }
}

class EqualityExpression(override val left: TypedExpression[_, _], override val right: TypedExpression[_, _])
    extends BinaryOperatorNodeLogicalBoolean(left, right, "=") {

  override def doWrite(sw: StatementWriter) =
    right match {
      case c: ConstantTypedExpression[_, _] =>
        if (c.value == None) {
          left.write(sw)
          sw.write(" is null")
        } else super.doWrite(sw)
      case _ => super.doWrite(sw)
    }

}

class InclusionOperator(left: ExpressionNode, right: RightHandSideOfIn[_])
    extends BinaryOperatorNodeLogicalBoolean(left, right, "in", true) {

  override def doWrite(sw: StatementWriter) =
    if (right.isConstantEmptyList)
      sw.write("(1 = 0)")
    else
      super.doWrite(sw)
}

class ExclusionOperator(left: ExpressionNode, right: RightHandSideOfIn[_])
    extends BinaryOperatorNodeLogicalBoolean(left, right, "not in", true)

class BinaryOperatorNodeLogicalBoolean(
  left: ExpressionNode,
  right: ExpressionNode,
  op: String,
  rightArgInParent: Boolean = false
) extends BinaryOperatorNode(left, right, op)
    with LogicalBoolean {

  override def inhibited = _inhibitedByWhen || {
    left match {
      case _: LogicalBoolean =>
        left.inhibited && right.inhibited
      case _ =>
        left.inhibited || right.inhibited
    }
  }

  override def doWrite(sw: StatementWriter) = {
    // since we are executing this method, we have at least one non inhibited children
    val nonInh = children.filter(c => !c.inhibited).iterator

    sw.write("(")
    nonInh.next().write(sw)
    sw.write(" ")
    if (nonInh.hasNext) {
      sw.write(operatorToken)
      if (newLineAfterOperator)
        sw.nextLine
      sw.write(" ")

      if (rightArgInParent)
        sw.write("(")

      nonInh.next().write(sw)

      if (rightArgInParent)
        sw.write(")")
    }
    sw.write(")")
  }
}

class ExistsExpression(val ast: ExpressionNode, val opType: String)
    extends PrefixOperatorNode(ast, opType, false)
    with LogicalBoolean

class BetweenExpression(first: ExpressionNode, second: ExpressionNode, third: ExpressionNode)
    extends TernaryOperatorNode(first, second, third, "between")
    with LogicalBoolean {

  override def doWrite(sw: StatementWriter) = {
    first.write(sw)
    sw.write(" between ")
    second.write(sw)
    sw.write(" and ")
    third.write(sw)
  }
}

class TernaryOperatorNode(val first: ExpressionNode, val second: ExpressionNode, val third: ExpressionNode, op: String)
    extends FunctionNode(op, Seq(first, second, third))
    with LogicalBoolean {

  override def inhibited =
    _inhibitedByWhen || first.inhibited || second.inhibited || third.inhibited
}

trait LogicalBoolean extends ExpressionNode {

  def and(b: LogicalBoolean): LogicalBoolean =
    new BinaryOperatorNodeLogicalBoolean(this, b, "and")

  def or(b: LogicalBoolean): LogicalBoolean =
    new BinaryOperatorNodeLogicalBoolean(this, b, "or")

  def and(b: Option[LogicalBoolean]): LogicalBoolean =
    b.map(this and _).getOrElse(this)

  def or(b: Option[LogicalBoolean]): LogicalBoolean =
    b.map(this or _).getOrElse(this)

}

object TrueLogicalBoolean extends LogicalBoolean {

  override def and(b: LogicalBoolean): LogicalBoolean = b

  override def or(b: LogicalBoolean): LogicalBoolean = this

  override def doWrite(sw: StatementWriter) = {
    sw.write("(1=1)")
  }

}

object FalseLogicalBoolean extends LogicalBoolean {

  override def and(b: LogicalBoolean): LogicalBoolean = this

  override def or(b: LogicalBoolean): LogicalBoolean = b

  override def doWrite(sw: StatementWriter) = {
    sw.write("(1=0)")
  }

}

object LogicalBoolean {

  def and(conditions: collection.Seq[LogicalBoolean]): LogicalBoolean =
    conditions.foldLeft[LogicalBoolean](TrueLogicalBoolean)(_ and _)

  def or(conditions: collection.Seq[LogicalBoolean]): LogicalBoolean =
    conditions.foldLeft[LogicalBoolean](FalseLogicalBoolean)(_ or _)

}

class UpdateAssignment(val left: FieldMetaData, val right: ExpressionNode)

trait BaseColumnAttributeAssignment {

  def clearColumnAttributes: Unit

  def isIdFieldOfKeyedEntity: Boolean

  def isIdFieldOfKeyedEntityWithoutUniquenessConstraint =
    isIdFieldOfKeyedEntity && !(columnAttributes.exists(_.isInstanceOf[PrimaryKey]) || columnAttributes.exists(
      _.isInstanceOf[Unique]
    ))

  def columnAttributes: collection.Seq[ColumnAttribute]

  def hasAttribute[A <: ColumnAttribute](implicit m: ClassTag[A]) =
    findAttribute[A](m).isDefined

  def findAttribute[A <: ColumnAttribute](implicit m: ClassTag[A]) =
    columnAttributes.find(ca => m.runtimeClass.isAssignableFrom(ca.getClass))
}

class ColumnGroupAttributeAssignment(
  cols: collection.Seq[FieldMetaData],
  columnAttributes_ : collection.Seq[ColumnAttribute]
) extends BaseColumnAttributeAssignment {

  private[this] val _columnAttributes = new ArrayBuffer[ColumnAttribute]

  _columnAttributes ++= columnAttributes_

  def columnAttributes: collection.Seq[ColumnAttribute] = _columnAttributes

  def addAttribute(a: ColumnAttribute) =
    _columnAttributes.append(a)

  def clearColumnAttributes = columns.foreach(_._clearColumnAttributes)

  def columns: collection.Seq[FieldMetaData] = cols

  def isIdFieldOfKeyedEntity = false

  def name: Option[String] = None
}

class CompositeKeyAttributeAssignment(val group: CompositeKey, _columnAttributes: collection.Seq[ColumnAttribute])
    extends ColumnGroupAttributeAssignment(group._fields, _columnAttributes) {

  override def isIdFieldOfKeyedEntity = {
    val fmdHead = group._fields.head
    fmdHead.parentMetaData.viewOrTable.ked.exists(k => Some(k.idPropertyName) == group._propertyName)
  }

  assert(group._propertyName.isDefined)

  override def name: Option[String] = group._propertyName
}

class ColumnAttributeAssignment(val left: FieldMetaData, val columnAttributes: collection.Seq[ColumnAttribute])
    extends BaseColumnAttributeAssignment {

  def clearColumnAttributes = left._clearColumnAttributes

  def isIdFieldOfKeyedEntity = left.isIdFieldOfKeyedEntity
}

class DefaultValueAssignment(val left: FieldMetaData, val value: TypedExpression[_, _])
    extends BaseColumnAttributeAssignment {

  def isIdFieldOfKeyedEntity = left.isIdFieldOfKeyedEntity

  def clearColumnAttributes = left._clearColumnAttributes

  def columnAttributes: Seq[ColumnAttribute] = Nil
}

class TokenExpressionNode(val token: String) extends ExpressionNode {
  def doWrite(sw: StatementWriter) = sw.write(token)
}

private[squeryl] class InputOnlyConstantExpressionNode(v: Any)
    extends ConstantTypedExpression[Any, Any](v, v.asInstanceOf[AnyRef], None)

class ConstantTypedExpression[A1, T1](
  val value: A1,
  val nativeJdbcValue: AnyRef,
  i: Option[TypedExpressionFactory[A1, _]]
) extends TypedExpression[A1, T1] {

  private def needsQuote = value.isInstanceOf[String]

  override def mapper: OutMapper[A1] = i.get.createOutMapper

  override def sample =
    if (value != null) value
    else i.get.sample

  def jdbcClass =
    i.map(_.jdbcSample).getOrElse(nativeJdbcValue).getClass

    if (nativeJdbcValue != null) nativeJdbcValue.getClass
    else mapper.jdbcClass

  def doWrite(sw: StatementWriter) = {
    if (sw.isForDisplay) {
      sw.write(displayAsString)
    } else {
      sw.write("?")
      sw.addParam(ConstantStatementParam(this))
    }
  }

  def displayAsString =
    if (value == null)
      "null"
    else if (needsQuote)
      "'" + value.toString + "'"
    else
      value.toString

  override def toString = "'ConstantTypedExpression:" + value
}

class ConstantExpressionNodeList[T](val value: Iterable[T], mapper: OutMapper[_]) extends ExpressionNode {

  def isEmpty =
    value == Nil

  def doWrite(sw: StatementWriter) =
    if (sw.isForDisplay)
      sw.write(ConstantExpressionNodeList.this.value.map(e => "'" + e + "'").mkString(","))
    else {
      sw.write(ConstantExpressionNodeList.this.value.toSeq.map(z => "?").mkString(","))
      ConstantExpressionNodeList.this.value.foreach(z =>
        sw.addParam(ConstantExpressionNodeListParam(z.asInstanceOf[AnyRef], ConstantExpressionNodeList.this))
      )
    }
}

class FunctionNode(val name: String, val args: collection.Seq[ExpressionNode]) extends ExpressionNode {

  def doWrite(sw: StatementWriter) = {

    sw.write(name)
    sw.write("(")
    sw.writeNodesWithSeparator(args, ",", false)
    sw.write(")")
  }

  override def children = args.toList
}

class PostfixOperatorNode(val token: String, val arg: ExpressionNode) extends ExpressionNode {

  def doWrite(sw: StatementWriter) = {
    arg.write(sw)
    sw.write(" ")
    sw.write(token)
  }

  override def children = List(arg)
}

class TypeConversion(e: ExpressionNode) extends ExpressionNode {

  override def inhibited = e.inhibited

  override def doWrite(sw: StatementWriter) = e.doWrite((sw))

  override def children = e.children
}

class BinaryOperatorNode(
  val left: ExpressionNode,
  val right: ExpressionNode,
  val operatorToken: String,
  val newLineAfterOperator: Boolean = false
) extends ExpressionNode {

  override def children = List(left, right)

  override def inhibited =
    _inhibitedByWhen || left.inhibited || right.inhibited

  override def toString =
    "'BinaryOperatorNode:" + operatorToken + inhibitedFlagForAstDump

  def doWrite(sw: StatementWriter) = {
    sw.write("(")
    left.write(sw)
    sw.write(" ")
    sw.write(operatorToken)
    if (newLineAfterOperator)
      sw.nextLine
    sw.write(" ")
    right.write(sw)
    sw.write(")")
  }
}

class PrefixOperatorNode(
  val child: ExpressionNode,
  val operatorToken: String,
  val newLineAfterOperator: Boolean = false
) extends ExpressionNode {

  override def children = List(child)

  override def inhibited = _inhibitedByWhen || child.inhibited

  override def toString = "'PrefixOperatorNode:" + operatorToken + inhibitedFlagForAstDump

  override def doWrite(sw: StatementWriter) = {
    sw.write("(")
    sw.write(operatorToken)
    if (newLineAfterOperator)
      sw.nextLine
    child.write(sw)
    sw.write(")")
  }
}

class LeftOuterJoinNode(left: ExpressionNode, right: ExpressionNode)
    extends BinaryOperatorNode(left, right, "left", false) {

  override def doWrite(sw: StatementWriter) = {}

  override def toString = "'LeftOuterJoin"
}

class FullOuterJoinNode(left: ExpressionNode, right: ExpressionNode)
    extends BinaryOperatorNode(left, right, "full", false) {
  override def toString = "'FullOuterJoin"
}

trait UniqueIdInAliaseRequired {
  var uniqueId: Option[Int] = None
}

trait QueryableExpressionNode extends ExpressionNode with UniqueIdInAliaseRequired {

  private[this] var _inhibited = false

  override def inhibited = _inhibited

  def inhibited_=(b: Boolean) = _inhibited = b

  /**
   * When the join syntax is used, isMemberOfJoinList is true if this instance is not in the from clause
   * but a 'join element'. 
   */
  def isMemberOfJoinList = joinKind.isDefined

  // new join syntax
  var joinKind: Option[(String, String)] = None

  def isOuterJoined =
    joinKind.isDefined && joinKind.get._2 == "outer"

  var joinExpression: Option[LogicalBoolean] = None

  // this 'old' join syntax will become deprecated :
  var outerJoinExpression: Option[OuterJoinExpression] = None

  var isRightJoined = false

  def isChild(q: QueryableExpressionNode): Boolean

  def owns(aSample: AnyRef): Boolean

  def alias: String

  def getOrCreateSelectElement(fmd: FieldMetaData, forScope: QueryExpressionElements): SelectElement

  def getOrCreateAllSelectElements(forScope: QueryExpressionElements): Iterable[SelectElement]

  def dumpAst = {
    val sb = new java.lang.StringBuilder
    visitDescendants { (n, parent, d: Int) =>
      val c = 4 * d
      for (i <- 1 to c) sb.append(' ')
      sb.append(n)
      sb.append("\n")
    }
    sb.toString
  }
}

class OrderByArg(val e: ExpressionNode) {

  private[this] var _ascending = true

  private[squeryl] def isAscending = _ascending

  def asc = {
    _ascending = true
    this
  }

  def desc = {
    _ascending = false
    this
  }
}

class OrderByExpression(a: OrderByArg) extends ExpressionNode {

  private def e = a.e

  override def inhibited = _inhibitedByWhen || e.inhibited

  def doWrite(sw: StatementWriter) = {
    e.write(sw)
    if (a.isAscending)
      sw.write(" Asc")
    else
      sw.write(" Desc")
  }

  override def children = List(e)

  def inverse = {

    val aCopy = new OrderByArg(a.e)

    if (aCopy.isAscending)
      aCopy.desc
    else
      aCopy.asc

    new OrderByExpression(aCopy)
  }
}

/**
 * Update, delete and insert statement are not built with AST nodes,
 * (for example Table[].update), although some portions of these statements
 * (where clauses are sometimes built with it.
 * The StatisticsListener needs to view every expression call as an AST,
 * which is the reason for this class.
 * AST are meant to be "non rendered", i.e. agnostic to specific DatabaseAdapter,
 * this DummyExpressionHolder is an exception.  
 * TODO: unify expression building to be completely AST based.
 */
class DummyExpressionHolder(val renderedExpression: String) extends ExpressionNode {

  def doWrite(sw: StatementWriter) =
    sw.write(renderedExpression)
}

class RightHandSideOfIn[A](val ast: ExpressionNode, val isIn: Option[Boolean] = None) extends ExpressionNode {
  def toIn = new RightHandSideOfIn[A](ast, Some(true))
  def toNotIn = new RightHandSideOfIn[A](ast, Some(false))

  override def children = List(ast)

  override def inhibited =
    super.inhibited ||
      (isConstantEmptyList && // not in Empty is always true, so we remove the condition
        (!isIn.get))

  def isConstantEmptyList: Boolean = ast match {
    case a: ConstantExpressionNodeList[_] =>
      a.isEmpty
    case a: ListExpressionNode =>
      a.children.isEmpty
    case _ =>
      false
  }

  override def doWrite(sw: StatementWriter) =
    if (isConstantEmptyList && isIn.get)
      sw.write("1 = 0") // in Empty is always false
    else {
      ast.doWrite(sw)
    }
}

class UnionExpressionNode(val kind: String, val ast: ExpressionNode) extends ExpressionNode {
  def doWrite(sw: StatementWriter) = {
    sw.write(kind)
    sw.nextLine
    sw.write("(")
    sw.nextLine
    sw.indent(1)
    ast.write(sw)
    sw.unindent(1)
    sw.write(")")
    sw.nextLine
  }

  override def toString = {
    s"'UnionExpressionNode[with${kind}]"
  }

  override def children =
    List(ast)
}

class QueryValueExpressionNode[A1, T1](val ast: ExpressionNode, override val mapper: OutMapper[A1])
    extends TypedExpression[A1, T1] {
  def doWrite(sw: StatementWriter) = {
    ast.write(sw)
  }

  override def toString = {
    "'QueryValueExpressionNode"
  }

  override def children =
    List(ast)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy