Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package ru.circumflex.orm
import java.lang.String
/*!# Relation Nodes
The `RelationNode` is essentially a wrapper around relation which provides
an `alias` so that it can participate in complex SQL query plans.
Generally a relation node is created implicitly from `Relation`.
A special alias `this` is assigned to new relation nodes, it is transformed
inside queries into a query-unique alias so that no collisions occur.
You may assign an alias explicitly using the `AS` method.
*/
class RelationNode[PK, R <: Record[PK, R]](val relation: Relation[PK, R])
extends SQLable with Cloneable with Equals {
protected var _alias: String = "this"
def alias = _alias
def AS(alias: String): this.type = {
this._alias = alias
return this
}
/*! Relation nodes allow Scala-like syntactic sugar by using the `map` method.
Following example gives table `City` an alias `ci` and uses it to construct a
`Criteria` object.
(City AS "ci").map(ci => ci.criteria.add(ci.name LIKE "Lausanne")).list
*/
def map[T](f: RelationNode[PK, R] => T): T = f(this)
/*! The `*` method creates a `RecordProjection` from this node and is
widely used in the `SELECT` clause of SQL queries.
*/
def * = new RecordProjection[PK, R](this)
/*! Each relation node define which projection it yields. When nodes are joined
the resulting node contains projections from both nodes.
*/
def projections: Seq[Projection[_]] = List(*)
/*! Creates new `Criteria` instance with this node as its query plan root. */
def criteria = new Criteria[PK, R](this)
/*! Relation nodes can be joined to allow restrictions of associated relations. */
def findAssociation[T, F <: Record[T, F]](node: RelationNode[T, F]): Option[Association[T, R, F]] =
this.relation.findAssociation(node.relation)
def JOIN[T, J <: Record[T, J]](node: RelationNode[T, J],
on: Expression,
joinType: JoinType): JoinNode[PK, R, T, J] =
new JoinNode(this, node, joinType).ON(on)
def JOIN[T, J <: Record[T, J]](node: RelationNode[T, J],
joinType: JoinType = LEFT): JoinNode[PK, R, T, J] =
findAssociation(node) match {
case Some(a: Association[T, R, J]) => // many-to-one join
new ManyToOneJoin[PK, R, T, J](this, node, a, joinType)
case _ => node.findAssociation(this) match {
case Some(a: Association[PK, J, R]) => // one-to-many join
new OneToManyJoin[PK, R, T, J](this, node, a, joinType)
case _ =>
new JoinNode(this, node, joinType).ON(EmptyPredicate)
}
}
def INNER_JOIN[T, J <: Record[T, J]](node: RelationNode[T, J]): JoinNode[PK, R, T, J] =
JOIN(node, INNER)
def LEFT_JOIN[T, J <: Record[T, J]](node: RelationNode[T, J]): JoinNode[PK, R, T, J] =
JOIN(node, LEFT)
def RIGHT_JOIN[T, J <: Record[T, J]](node: RelationNode[T, J]): JoinNode[PK, R, T, J] =
JOIN(node, RIGHT)
def FULL_JOIN[T, J <: Record[T, J]](node: RelationNode[T, J]): JoinNode[PK, R, T, J] =
JOIN(node, FULL)
/*!## Equality & Others
Two nodes are considered equal if they wrap the same relation and share
same aliases.
The `hashCode` method delegates to node's relation.
The `canEqual` method indicates that two nodes wrap the same relation.
The `clone` methods creates a shallow copy of this node (the underlying
relation remains unchanged).
Finally, both `toSql` and `toString` return dialect specific SQL expression
which appends an alias to relation's qualified name.
*/
override def equals(that: Any): Boolean = that match {
case that: RelationNode[_, _] =>
this.canEqual(that) && this.alias == that.alias
case _ => false
}
override def hashCode: Int = relation.hashCode
def canEqual(that: Any): Boolean = that match {
case that: RelationNode[_, _] =>
this.relation == that.relation
}
def toSql: String = dialect.alias(relation.qualifiedName, alias)
override def clone(): this.type = super.clone.asInstanceOf[this.type]
override def toString: String = toSql
}
/*! The `ProxyNode` wraps a node and provides functionality to arrange
joined nodes into a query plan (tree-like structure) by allowing to replace
an underlying `node` with it's equivalent `JoinNode`. Most methods delegate
to underlying `node`.
*/
class ProxyNode[PK, R <: Record[PK, R]](protected[orm] var node: RelationNode[PK, R])
extends RelationNode[PK, R](node.relation) {
override def alias = node.alias
override def AS(alias: String): this.type = {
node.AS(alias)
return this
}
override def projections = node.projections
override def * = node.*
override def canEqual(that: Any): Boolean = node.canEqual(that)
override def equals(obj: Any) = node.equals(obj)
override def hashCode = node.hashCode
override def toSql = node.toSql
/**
* Unlike `clone` in `RelationNode` this creates a deep copy (clones underlying
* `node`, but `relation` remains unchanged).
*/
override def clone(): this.type = {
val newNode = super.clone().asInstanceOf[this.type]
val n = node.clone().asInstanceOf[RelationNode[PK, R]]
newNode.node = n
return newNode
}
}
/*!# Joins
Relations can be joined within one query to allow applying restrictions on
associated relations. The `JoinNode` class represents a join between two relations.
We stick to a general convention called _left associativity_: two joined nodes
with equal left nodes are considered equal:
(ci JOIN co) == ci
(ci JOIN co JOIN ca) == ((ci JOIN co) JOIN ca)
This way you can compose arbitrary complex query plans. The join condition
(the `ON` subclause) can be either inferred from associations or specified
manually using the `ON` method.
*/
class JoinNode[PKL, L <: Record[PKL, L], PKR, R <: Record[PKR, R]](
protected var _left: RelationNode[PKL, L],
protected var _right: RelationNode[PKR, R],
protected var _joinType: JoinType) extends ProxyNode[PKL, L](_left) {
def left = _left
def right = _right
def joinType = _joinType
protected var _on: Expression = EmptyPredicate
def on = _on
def ON(expr: Expression): this.type = {
_on = expr
return this
}
def sqlOn = dialect.ON(this.on)
override def projections = left.projections ++ right.projections
def replaceLeft(newLeft: RelationNode[PKL, L]): this.type = {
this._left = newLeft
return this
}
def replaceRight(newRight: RelationNode[PKR, R]): this.type = {
this._right = newRight
return this
}
override def toSql = dialect.join(this)
/**
* Creates a deep copy of this node, cloning left and right nodes.
* The underlying relations of nodes remain unchanged.
*/
override def clone(): this.type = super.clone()
.replaceLeft(this.left.clone)
.replaceRight(this.right.clone)
override def toString = "(" + left + " -> " + right + ")"
}
class ManyToOneJoin[PKL, L <: Record[PKL, L], PKR, R <: Record[PKR, R]](
childNode: RelationNode[PKL, L],
parentNode: RelationNode[PKR, R],
val association: Association[PKR, L, R],
joinType: JoinType) extends JoinNode[PKL, L, PKR, R](childNode, parentNode, joinType) {
override def on =
if (_on == EmptyPredicate)
association.joinPredicate(childNode.alias, parentNode.alias)
else _on
}
class OneToManyJoin[PKL, L <: Record[PKL, L], PKR, R <: Record[PKR, R]](
parentNode: RelationNode[PKL, L],
childNode: RelationNode[PKR, R],
val association: Association[PKL, R, L],
joinType: JoinType) extends JoinNode[PKL, L, PKR, R](parentNode, childNode, joinType) {
override def on =
if (_on == EmptyPredicate)
association.joinPredicate(childNode.alias, parentNode.alias)
else _on
}