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

rcumflex.circumflex-orm.3.0-RC1.source-code.package.scala Maven / Gradle / Ivy

The newest version!
package pro.savant.circumflex

import core._
import collection.mutable.Stack
import java.util.regex.Pattern

/*!# The `orm` Package

Package `orm` contains different shortcuts, utilities, helpers and implicits --
the basis of Circumflex ORM DSL.

You should import this package to use Circumflex ORM in your application:

``` {.scala}
import pro.savant.circumflex.orm._
```
*/
package object orm {

  val ORM_LOG = new Logger("pro.savant.circumflex.orm")

  lazy val DEFAULT_ORM_CONF = cx.instantiate[ORMConfiguration](
    "orm.configuration", new SimpleORMConfiguration(""))
  def ormConf = ctx.get("orm.conf") match {
    case Some(c: ORMConfiguration) => c
    case _ => DEFAULT_ORM_CONF
  }

  def tx: Transaction = ormConf.transactionManager.get

  def COMMIT() {
    tx.commit()
  }

  def ROLLBACK() {
    tx.rollback()
  }

  def using[A](newConf: ORMConfiguration)(block: => A): A =
    Context.executeInNew { ctx =>
      ctx.update("orm.conf", newConf)
      block
    }

  def usingAll[A]
  (newConfs: ORMConfiguration*)
  (block: ORMConfiguration => A): Seq[A] =
    newConfs.map { c => using(c) { block(c) } }

  /*! ## Alias Stack

  Circumflex ORM offers nice DSL to reference fields of aliased tables:

  ``` {.scala}
  val co = Country AS "co"
  val predicate = co.name EQ "Switzerland"
  ```

  In this example `RelationNode[Country]` with alias `co` is implicitly converted
  into `Country`, its underlying `Relation`, because only that relation owns field
  `name`. However, the information about the alias is lost during this conversion.
  We use `aliasStack` to remember it during conversion so it can be accessed later.
  */
  object aliasStack {

    protected[orm] def stack: Stack[String] =
      ctx.getAs[Stack[String]]("orm.aliasStack")
          .getOrElse {
        val s = new Stack[String]
        ctx += "orm.aliasStack" -> s
        s
      }

    protected[orm] def setStack(stack: Stack[String]) {
      ctx.update("orm.aliasStack", stack)
    }

    def preserve[A](actions: () => A): A = {
      val st = stack.clone()
      val result = actions()
      setStack(st)
      result
    }

    def pop(): Option[String] = if (stack.size == 0) None else Some(stack.pop())

    def push(alias: String) {
      stack.push(alias)
    }

  }

  // Pimping core libs

  implicit def str2expr(str: String): Expression = prepareExpr(str)

  implicit def string2exprHelper(expression: String): SimpleExpressionHelper =
    new SimpleExpressionHelper(expression)

  implicit def string2nativeHelper(expression: String): NativeQueryHelper =
    new NativeQueryHelper(expression)

  implicit def pair2proj[T1, T2](t: (Projection[T1], Projection[T2])) =
    new PairProjection(t._1, t._2)

  // Constants

  val NO_ACTION = ForeignKeyAction(ormConf.dialect.fkNoAction)
  val CASCADE = ForeignKeyAction(ormConf.dialect.fkCascade)
  val RESTRICT = ForeignKeyAction(ormConf.dialect.fkRestrict)
  val SET_NULL = ForeignKeyAction(ormConf.dialect.fkSetNull)
  val SET_DEFAULT = ForeignKeyAction(ormConf.dialect.fkSetDefault)

  val INNER = JoinType(ormConf.dialect.innerJoin)
  val LEFT = JoinType(ormConf.dialect.leftJoin)
  val RIGHT = JoinType(ormConf.dialect.rightJoin)
  val FULL = JoinType(ormConf.dialect.fullJoin)

  val OP_UNION = SetOperation(ormConf.dialect.UNION)
  val OP_UNION_ALL = SetOperation(ormConf.dialect.UNION_ALL)
  val OP_EXCEPT = SetOperation(ormConf.dialect.EXCEPT)
  val OP_EXCEPT_ALL = SetOperation(ormConf.dialect.EXCEPT_ALL)
  val OP_INTERSECT = SetOperation(ormConf.dialect.INTERSECT)
  val OP_INTERSECT_ALL = SetOperation(ormConf.dialect.INTERSECT_ALL)

  // Predicates DSL

  def AND(predicates: Predicate*) =
    new AggregatePredicate(ormConf.dialect.AND, predicates.toSeq)
  def OR(predicates: Predicate*) =
    new AggregatePredicate(ormConf.dialect.OR, predicates.toSeq)
  def NOT(predicate: Predicate) =
    new SimpleExpression(ormConf.dialect.not(predicate.toSql), predicate.parameters)

  def prepareExpr(expression: String, params: Pair[String, Any]*): SimpleExpression = {
    var sqlText = expression
    var parameters: Seq[Any] = Nil
    val paramsMap = Map[String, Any](params: _*)
    val pattern = Pattern.compile(":(\\w+)\\b")
    val matcher = pattern.matcher(expression)
    while (matcher.find) {
      val name = matcher.group(1)
      paramsMap.get(name) match {
        case Some(param) => parameters ++= List(param)
        case _ => parameters ++= List(":" + name)
      }
    }
    sqlText = matcher.replaceAll("?")
    new SimpleExpression(sqlText, parameters)
  }

  // Simple subqueries DSL

  def EXISTS(subquery: SQLQuery[_]) =
    new SubqueryExpression(ormConf.dialect.EXISTS, subquery)
  def NOT_EXISTS(subquery: SQLQuery[_]) =
    new SubqueryExpression(ormConf.dialect.NOT_EXISTS, subquery)

  // Simple projections

  def expr[T](expression: String): ExpressionProjection[T] =
    new ExpressionProjection[T](expression)
  def COUNT(expr: Expression): Projection[Long] =
    new ExpressionProjection[Long](ormConf.dialect.COUNT(expr.toSql))
  def COUNT_DISTINCT(expr: Expression): Projection[Long] =
    new ExpressionProjection[Long](ormConf.dialect.COUNT_DISTINCT(expr.toSql))
  def MAX[T](expr: Expression) =
    new ExpressionProjection[T](ormConf.dialect.MAX(expr.toSql))
  def MIN[T](expr: Expression) =
    new ExpressionProjection[T](ormConf.dialect.MIN(expr.toSql))
  def SUM[T](expr: Expression) =
    new ExpressionProjection[T](ormConf.dialect.SUM(expr.toSql))
  def AVG[T](expr: Expression) =
    new ExpressionProjection[T](ormConf.dialect.AVG(expr.toSql))

  // Queries DSL

  def SELECT[T](p1: Projection[T], p2: Projection[_], pn: Projection[_]*) = {
    val projections = List(p1, p2) ++ pn
    new Select(new RowProjection(projections))
  }
  def SELECT[T](projection: Projection[T]): Select[T] = new Select(projection)
  def INSERT_INTO[PK, R <: Record[PK, R]](relation: Relation[PK, R]) =
    new InsertSelectHelper(relation)
  def UPDATE[PK, R <: Record[PK, R]](node: RelationNode[PK, R]) =
    new Update(node)
  def DELETE[PK, R <: Record[PK, R]](node: RelationNode[PK, R]) =
    new Delete(node)

  // Common functions
  def NOW = new SimpleExpression(ormConf.dialect.NOW, Nil)
  def RANDOM = new SimpleExpression(ormConf.dialect.RANDOM, Nil)

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy