/circumflex-orm/src/main/scala/node.scala

https://github.com/Heit/circumflex · Scala · 275 lines · 155 code · 52 blank · 68 comment · 3 complexity · 6c8b8e30e597750c7ec34899cae96bd4 MD5 · raw file

  1. package ru.circumflex.orm
  2. import ORM._
  3. import java.lang.String
  4. // ## Relation Node
  5. /**
  6. * **Relation Node** is essentially a wrapper around `Relation` that
  7. * provides an `alias` so that it can be used in SQL queries.
  8. */
  9. class RelationNode[R <: Record[R]](val relation: Relation[R])
  10. extends SQLable with Cloneable {
  11. // ### Alias
  12. protected[orm] var _alias = "this"
  13. /**
  14. * An alias of this node. `this` is expanded to query-unique alias.
  15. */
  16. def alias = _alias
  17. /**
  18. * Change the alias of this node.
  19. */
  20. def as(alias: String): this.type = {
  21. this._alias = alias
  22. return this
  23. }
  24. def AS(alias: String): this.type = as(alias)
  25. // ### Projections
  26. /**
  27. * Construct a new `RecordProjection` for this node.
  28. */
  29. def * = new RecordProjection[R](this)
  30. /**
  31. * Default projections for this node.
  32. */
  33. def projections: Seq[Projection[_]] = List(*)
  34. // ### Criteria and simple queries
  35. def criteria = new Criteria(this)
  36. // ### Joins
  37. def findAssociation[F <: Record[F]](node: RelationNode[F]): Option[Association[R, F]] =
  38. relation.findAssociation(node.relation)
  39. /**
  40. * Explicit join.
  41. */
  42. def join[J <: Record[J]](node: RelationNode[J],
  43. on: String,
  44. joinType: JoinType): JoinNode[R, J] =
  45. new ExplicitJoin(this, node, on, joinType)
  46. def JOIN[J <: Record[J]](node: RelationNode[J],
  47. on: String,
  48. joinType: JoinType): JoinNode[R, J] =
  49. join(node, on, joinType)
  50. /**
  51. * Auto-join (the `ON` subclause is evaluated by searching matching association).
  52. */
  53. def join[J <: Record[J]](node: RelationNode[J],
  54. joinType: JoinType = LEFT): JoinNode[R, J] =
  55. findAssociation(node) match {
  56. case Some(a: Association[R, J]) => // many-to-one join
  57. new ManyToOneJoin[R, J](this, node, a, joinType)
  58. case _ => node.findAssociation(this) match {
  59. case Some(a: Association[J, R]) => // one-to-many join
  60. new OneToManyJoin[R, J](this, node, a, joinType)
  61. case _ =>
  62. throw new ORMException("Failed to join " + this + " and " + node +
  63. ": no associations found.")
  64. }
  65. }
  66. def JOIN[J <: Record[J]](node: RelationNode[J],
  67. joinType: JoinType = LEFT): JoinNode[R, J] =
  68. join(node, joinType)
  69. // Join shortcuts for different types
  70. def innerJoin[J <: Record[J]](node: RelationNode[J],
  71. on: String): JoinNode[R, J] =
  72. join(node, on, INNER)
  73. def INNER_JOIN[J <: Record[J]](node: RelationNode[J],
  74. on: String): JoinNode[R, J] =
  75. innerJoin(node, on)
  76. def innerJoin[J <: Record[J]](node: RelationNode[J]): JoinNode[R, J] =
  77. join(node, INNER)
  78. def INNER_JOIN[J <: Record[J]](node: RelationNode[J]): JoinNode[R, J] =
  79. innerJoin(node)
  80. def leftJoin[J <: Record[J]](node: RelationNode[J],
  81. on: String): JoinNode[R, J] =
  82. join(node, on, LEFT)
  83. def LEFT_JOIN[J <: Record[J]](node: RelationNode[J],
  84. on: String): JoinNode[R, J] =
  85. leftJoin(node, on)
  86. def leftJoin[J <: Record[J]](node: RelationNode[J]): JoinNode[R, J] =
  87. join(node, LEFT)
  88. def LEFT_JOIN[J <: Record[J]](node: RelationNode[J]): JoinNode[R, J] =
  89. leftJoin(node)
  90. def rightJoin[J <: Record[J]](node: RelationNode[J],
  91. on: String): JoinNode[R, J] =
  92. join(node, on, RIGHT)
  93. def RIGHT_JOIN[J <: Record[J]](node: RelationNode[J],
  94. on: String): JoinNode[R, J] =
  95. rightJoin(node, on)
  96. def rightJoin[J <: Record[J]](node: RelationNode[J]): JoinNode[R, J] =
  97. join(node, RIGHT)
  98. def RIGHT_JOIN[J <: Record[J]](node: RelationNode[J]): JoinNode[R, J] =
  99. rightJoin(node)
  100. def fullJoin[J <: Record[J]](node: RelationNode[J],
  101. on: String): JoinNode[R, J] =
  102. join(node, on, FULL)
  103. def FULL_JOIN[J <: Record[J]](node: RelationNode[J],
  104. on: String): JoinNode[R, J] =
  105. fullJoin(node, on)
  106. def fullJoin[J <: Record[J]](node: RelationNode[J]): JoinNode[R, J] =
  107. join(node, FULL)
  108. def FULL_JOIN[J <: Record[J]](node: RelationNode[J]): JoinNode[R, J] =
  109. fullJoin(node)
  110. // ### Equality and others
  111. override def equals(obj: Any) = obj match {
  112. case r: RelationNode[_] =>
  113. r.relation == this.relation && r.alias == this.alias
  114. case _ => false
  115. }
  116. override def hashCode = this.relation.hashCode * 31 + this.alias.hashCode
  117. /**
  118. * Creates a shallow copy of this node.
  119. * The underlying relation remains unchanged.
  120. */
  121. override def clone(): this.type = super.clone.asInstanceOf[this.type]
  122. def toSql = dialect.alias(relation.qualifiedName, alias)
  123. override def toString = toSql
  124. }
  125. // ## Proxy Node
  126. /**
  127. * In order to organize joined nodes into tree we introduce this proxy
  128. * for `RelationNode`. It delegates all methods to underlying `node`.
  129. */
  130. class ProxyNode[R <: Record[R]](protected[orm] var node: RelationNode[R])
  131. extends RelationNode[R](node.relation) {
  132. override def alias = node.alias
  133. override def as(alias: String): this.type = {
  134. node.as(alias)
  135. return this
  136. }
  137. override def projections = node.projections
  138. override def * = node.*
  139. override def equals(obj: Any) = node.equals(obj)
  140. override def hashCode = node.hashCode
  141. override def toSql = node.toSql
  142. /**
  143. * Unlike `clone` in `RelationNode` this creates a deep copy
  144. * (clones underlying `node`, but `relation` remains unchanged).
  145. */
  146. override def clone(): this.type = {
  147. val newNode = super.clone().asInstanceOf[this.type]
  148. val n = node.clone().asInstanceOf[RelationNode[R]]
  149. newNode.node = n
  150. return newNode
  151. }
  152. }
  153. // ## Joins
  154. /**
  155. * This node represents a relational join between two nodes (`left` and `right`).
  156. */
  157. abstract class JoinNode[L <: Record[L], R <: Record[R]](
  158. protected var _left: RelationNode[L],
  159. protected var _right: RelationNode[R],
  160. protected var _joinType: JoinType) extends ProxyNode[L](_left) {
  161. def left = _left
  162. def right = _right
  163. def joinType = _joinType
  164. /**
  165. * Join condition expression (used in `ON` subclauses).
  166. */
  167. def on: String
  168. def sqlOn = dialect.on(this.on)
  169. /**
  170. * Join node returns projections of `left` node appended with projections
  171. * of `right` node.
  172. */
  173. override def projections = left.projections ++ right.projections
  174. // ### Replacement methods
  175. def replaceLeft(newLeft: RelationNode[L]): this.type = {
  176. this._left = newLeft
  177. return this
  178. }
  179. def replaceRight(newRight: RelationNode[R]): this.type = {
  180. this._right = newRight
  181. return this
  182. }
  183. // ### Others
  184. override def toSql = dialect.join(this)
  185. /**
  186. * Creates a deep copy of this node, cloning left and right nodes.
  187. * The underlying relations of nodes remain unchanged.
  188. */
  189. override def clone(): this.type = super.clone()
  190. .replaceLeft(this.left.clone)
  191. .replaceRight(this.right.clone)
  192. override def toString = "(" + left + " -> " + right + ")"
  193. }
  194. /**
  195. * A join with explicit join condition.
  196. */
  197. class ExplicitJoin[L <: Record[L], R <: Record[R]](
  198. left: RelationNode[L],
  199. right: RelationNode[R],
  200. val on: String,
  201. joinType: JoinType) extends JoinNode[L, R](left, right, joinType)
  202. /**
  203. * A join in many-to-one direction.
  204. */
  205. class ManyToOneJoin[L <: Record[L], R <: Record[R]](
  206. childNode: RelationNode[L],
  207. parentNode: RelationNode[R],
  208. val association: Association[L, R],
  209. joinType: JoinType) extends JoinNode[L, R](childNode, parentNode, joinType) {
  210. def on = childNode.alias + "." + association.name + " = " +
  211. parentNode.alias + "." + association.foreignRelation.primaryKey.name
  212. }
  213. /**
  214. * A join in one-to-many direction.
  215. */
  216. class OneToManyJoin[L <: Record[L], R <: Record[R]](
  217. parentNode: RelationNode[L],
  218. childNode: RelationNode[R],
  219. val association: Association[R, L],
  220. joinType: JoinType) extends JoinNode[L, R](parentNode, childNode, joinType) {
  221. def on = childNode.alias + "." + association.name + " = " +
  222. parentNode.alias + "." + association.foreignRelation.primaryKey.name
  223. }