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

.circumflex-orm.1.1.source-code.common.scala Maven / Gradle / Ivy

There is a newer version: 2.5
Show newest version
package ru.circumflex.orm

import org.slf4j.LoggerFactory
import ORM._
import ru.circumflex.core.WrapperModel

// ## Common interfaces

/**
 * Simple interface for objects capable to render themselves into SQL statements.
 */
trait SQLable {
  def toSql: String
}

/**
 * Simple interface for expressions with JDBC-style parameters
 */
trait ParameterizedExpression extends SQLable {
  /**
   * The parameters associated with this expression. The order is important.
   */
  def parameters: Seq[Any]

  /**
   * Render this query by replacing parameter placeholders with actual values.
   */
  def toInlineSql: String = parameters.foldLeft(toSql)((sql, p) =>
    sql.replaceFirst("\\?", typeConverter.escape(p)))

  // Equality and others.

  override def equals(that: Any) = that match {
    case e: ParameterizedExpression =>
      e.toSql == this.toSql && (e.parameters.toList -- this.parameters.toList) == Nil
    case _ => false
  }

  override def hashCode = 0

  override def toString = toSql
}

/**
 * Simple interface for database objects capable to render themselves into DDL
 * CREATE and DROP statements.
 */
trait SchemaObject {
  /**
   * SQL statement to create this database object.
   */
  def sqlCreate: String

  /**
   * SQL statement to drop this database object.
   */
  def sqlDrop: String

  /**
   * SQL object name. It is used to uniquely identify this object
   * during schema creation by `DDL` to avoid duplicates and to print
   * nice messages on schema generation.
   *
   * We follow default convention to name objects:
   *
   *      
   *
   * where `TYPE OF OBJECT` is `TABLE`, `VIEW`, `SEQUENCE`, `TRIGGER`,
   * `FUNCTION`, `PROCEDURE`, `INDEX`, etc. (note the upper case), and
   * `qualified_name` is object's unique identifier.
   *
   * For equality testing, object names are taken in case-insensitive manner
   * (e.g. `MY_TABLE` and `my_table` are considered equal).
   */
  def objectName: String

  override def hashCode = objectName.toLowerCase.hashCode

  override def equals(obj: Any) = obj match {
    case so: SchemaObject => so.objectName.equalsIgnoreCase(this.objectName)
    case _ => false
  }

  override def toString = objectName
}

/**
 * *Value holder* is designed to be an extensible atomic data carrier unit
 * of record. It is subclassed by 'Field' and 'Association'.
 */
abstract class ValueHolder[T](val name: String, val uuid: String) extends WrapperModel {

  // An internally stored value.
  protected var _value: T = _

  protected var _setter: T => T = t => t

  // This way the value will be unwrapped by FTL engine.
  def item = getValue

  // Should the `NOT NULL` constraint be applied to this value holder?
  protected var _notNull: Boolean = true
  def nullable_?(): Boolean = !_notNull

  def notNull: this.type = {
    _notNull = true
    return this
  }
  def NOT_NULL: this.type = notNull

  def nullable: this.type = {
    _notNull = false
    return this
  }
  def NULLABLE: this.type = nullable

  def setter = _setter
  def setter(sf: T => T): this.type = {
    _setter = sf
    return this
  }
  def SETTER(sf: T => T): this.type = setter(sf)

  // Getters.

  def getValue(): T = _value
  def apply(): T = getValue
  def getOrElse(default: T) = get().getOrElse(default)
  def get(): Option[T] = getValue match {
    case null => None
    case value => Some(value)
  }

  def empty_?(): Boolean = getValue() == null
  def null_?(): Boolean = empty_?
  def NULL_?(): Boolean = empty_?

  // Setters.

  def setValue(newValue: T): this.type = {
    _value = if (newValue != null) _setter(newValue) else newValue
    return this
  }
  def :=(newValue: T): this.type = setValue(newValue)
  def update(newValue: T): this.type = setValue(newValue)

  def setNull(): this.type = setValue(null.asInstanceOf[T])
  def null_!() = setNull()
  def NULL_!() = null_!()

  // Equality methods.

  override def equals(that: Any) = that match {
    case vh: ValueHolder[T] => vh.uuid == this.uuid
    case _ => false
  }

  override def hashCode = this.uuid.hashCode

  /**
   * Return a `String` representation of internal value.
   */
  def toString(default: String = "") = if (getValue == null) default else getValue.toString

  /**
   * Return `uuid` as this holder's identifier.
   */
  override def toString = uuid
}

/**
 * An action for `ON UPDATE` and `ON DELETE` clauses of
 * foreign key definitions.
 */
case class ForeignKeyAction(val toSql: String) extends SQLable {
  override def toString = toSql
}

/**
 * Join types for use in `FROM` clauses of SQL queries.
 */
case class JoinType(val toSql: String) extends SQLable {
  override def toString = toSql
}

/**
 * Set operations for use in SQL queries.
 */
case class SetOperation(val toSql: String) extends SQLable {
  override def toString = toSql
}

/**
 * An expression to use in `ORDER BY` clause.
 */
class Order(val expression: String, val parameters: Seq[Any])
    extends ParameterizedExpression {

  // Specificator (`ASC` or `DESC`).

  protected[orm] var _specificator = dialect.asc

  def asc: this.type = {
    this._specificator = dialect.asc
    return this
  }
  def ASC: this.type = asc

  def desc: this.type = {
    this._specificator = dialect.desc
    return this
  }
  def DESC: this.type = desc

  // Miscellaneous.

  def toSql = expression + " " + _specificator
}

// ## JDBC utilities

/**
 * Helper constructions that automatically close such JDBC objects as
 * `ResultSet`s and `PreparedStatement`s.
 */
object JDBC {
  protected[orm] val sqlLog = LoggerFactory.getLogger("ru.circumflex.orm")

  def autoClose[A <: {def close(): Unit}, B](obj: A)
                                            (actions: A => B)
                                            (errors: Throwable => B): B =
    try {
      return actions(obj)
    } catch {
      case e => return errors(e)
    } finally {
      obj.close
    }

  def auto[A <: {def close(): Unit}, B](obj: A)
                                       (actions: A => B): B =
    autoClose(obj)(actions)(throw _)
}

// ## Exceptions

/**
 * The most generic exception class.
 */
class ORMException(msg: String, cause: Throwable) extends Exception(msg, cause) {
  def this(msg: String) = this(msg, null)
  def this(cause: Throwable) = this(null, cause)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy