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

org.scalaquery.ql.Query.scala Maven / Gradle / Ivy

package org.scalaquery.ql

import scala.reflect.Manifest
import org.scalaquery.SQueryException
import org.scalaquery.util.{Node, WithOp}

/**
 * A query monad which contains the AST for a query's projection and the accumulated
 * restrictions and other modifiers.
 */
class Query[+E](val value: E, val cond: List[Column[_]],  val condHaving: List[Column[_]],
                val modifiers: List[QueryModifier]) extends Node {

  def nodeChildren = Node(value) :: cond.map(Node.apply) ::: modifiers
  override def nodeNamedChildren = (Node(value), "select") :: cond.map(n => (Node(n), "where")) ::: modifiers.map(o => (o, "modifier"))

  override def toString = "Query"

  def flatMap[F](f: E => Query[F]): Query[F] = {
    val q = f(value)
    new Query(q.value, cond ::: q.cond, condHaving ::: q.condHaving, modifiers ::: q.modifiers)
  }

  def map[F](f: E => F): Query[F] = flatMap(v => Query(f(v)))

  def >>[F](q: Query[F]): Query[F] = flatMap(_ => q)

  def filter[T](f: E => T)(implicit wt: CanBeQueryCondition[T]): Query[E] =
    new Query(value, wt(f(value), cond), condHaving, modifiers)

  def withFilter[T](f: E => T)(implicit wt: CanBeQueryCondition[T]): Query[E] = filter(f)(wt)

  def where[T <: Column[_]](f: E => T)(implicit wt: CanBeQueryCondition[T]): Query[E] = filter(f)(wt)

  def having[T <: Column[_]](f: E => T)(implicit wt: CanBeQueryCondition[T]): Query[E] =
    new Query(value, cond, wt(f(value), condHaving), modifiers)

  def groupBy(by: Column[_]*) =
    new Query[E](value, cond, condHaving, modifiers ::: by.view.map(c => new Grouping(Node(c))).toList)

  def orderBy(by: Ordering*) = new Query[E](value, cond, condHaving, modifiers ::: by.toList)

  def exists = ColumnOps.Exists(map(_ => ConstColumn(1)))

  def typedModifiers[T <: QueryModifier](implicit m: ClassManifest[T]) =
    modifiers.filter(m.erasure.isInstance(_)).asInstanceOf[List[T]]

  def createOrReplaceSingularModifier[T <: QueryModifier](f: Option[T] => T)(implicit m: Manifest[T]): Query[E] = {
    val (xs, other) = modifiers.partition(m.erasure.isInstance(_))
    val mod = xs match {
      case x :: _ => f(Some(x.asInstanceOf[T]))
      case _ => f(None)
    }
    new Query[E](value, cond, condHaving, mod :: other)
  }

  // Query[ColumnBase[_]] only
  def union[O >: E <: ColumnBase[_]](other: Query[O]*) = wrap(Union(false, this :: other.toList))

  def unionAll[O >: E <: ColumnBase[_]](other: Query[O]*) = wrap(Union(true, this :: other.toList))

  def count(implicit ev: E <:< ColumnBase[_]) = ColumnOps.CountAll(Subquery(this, false))

  def sub(implicit ev: E <:< ColumnBase[_]) = wrap(this)

  private[this] def wrap(base: Node): Query[E] = Query(value.asInstanceOf[WithOp] match {
    case t:AbstractTable[_] =>
      t.mapOp(_ => Subquery(base, false)).asInstanceOf[E]
    case o =>
      var pos = 0
      val p = Subquery(base, true)
      o.mapOp { v =>
        pos += 1
        SubqueryColumn(pos, p, v match {
          case c: Column[_] => c.typeMapper
          case SubqueryColumn(_, _, tm) => tm
          case _ => throw new SQueryException("Expected Column or SubqueryColumn")
        })
      }.asInstanceOf[E]
  })

  // Query[Column[_]] only
  def asColumn(implicit ev: E <:< Column[_]): E = value.asInstanceOf[WithOp].mapOp(_ => this).asInstanceOf[E]
}

object Query extends Query[Unit]((), Nil, Nil, Nil) {
  def apply[E](value: E) = new Query(value, Nil, Nil, Nil)
}

trait CanBeQueryCondition[-T] {
  def apply(value: T, l: List[Column[_]]): List[Column[_]]
}

object CanBeQueryCondition {
  implicit object BooleanColumnCanBeQueryCondition extends CanBeQueryCondition[Column[Boolean]] {
    def apply(value: Column[Boolean], l: List[Column[_]]): List[Column[_]] = value :: l
  }
  implicit object BooleanOptionColumnCanBeQueryCondition extends CanBeQueryCondition[Column[Option[Boolean]]] {
    def apply(value: Column[Option[Boolean]], l: List[Column[_]]): List[Column[_]] = value :: l
  }
  implicit object BooleanCanBeQueryCondition extends CanBeQueryCondition[Boolean] {
    def apply(value: Boolean, l: List[Column[_]]): List[Column[_]] =
      if(value) l else new ConstColumn(false)(TypeMapper.BooleanTypeMapper) :: Nil
  }
}

case class Subquery(query: Node, rename: Boolean) extends Node {
  def nodeChildren = query :: Nil
  override def nodeNamedChildren = (query, "query") :: Nil
  override def isNamedTable = true
}

case class SubqueryColumn(pos: Int, subquery: Subquery, typeMapper: TypeMapper[_]) extends Node {
  def nodeChildren = subquery :: Nil
  override def nodeNamedChildren = (subquery, "subquery") :: Nil
  override def toString = "SubqueryColumn c"+pos
}

case class Union(all: Boolean, queries: List[Query[_]]) extends Node {
  override def toString = if(all) "Union all" else "Union"
  def nodeChildren = queries
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy