Skip to content

Commit

Permalink
Remove WithOp.
Browse files Browse the repository at this point in the history
Apart from tables in the lifted embedding, all uses are switched over to
EncodeRef which gets the same result in a cleaner way without having to
clone existing objects. The WithOp implementation is now contained
directly in AbstractTable and exposed through the EncodeRef interface.
  • Loading branch information
szeiger committed Jul 1, 2013
1 parent cd1e60c commit 73c79b3
Show file tree
Hide file tree
Showing 11 changed files with 67 additions and 65 deletions.
18 changes: 18 additions & 0 deletions src/main/scala/scala/slick/ast/EncodeRef.scala
@@ -0,0 +1,18 @@
package scala.slick.ast

import scala.slick.util.TupleSupport

trait EncodeRef {
def encodeRef(sym: Symbol, positions: List[Int] = Nil): Any
}

object EncodeRef {
def apply[T](x: T, sym: Symbol, positions: List[Int] = Nil): T = {
(x match {
case e: EncodeRef => e.encodeRef(sym, positions)
case p: Product => // Only works for tuples but they have no common superclass
TupleSupport.buildTuple(p.productIterator.zipWithIndex.map {
case (x, pos) => apply(x, sym, (pos + 1) :: positions) }.toIndexedSeq)
}).asInstanceOf[T]
}
}
8 changes: 3 additions & 5 deletions src/main/scala/scala/slick/ast/Node.scala
Expand Up @@ -132,9 +132,7 @@ trait SimplyTypedNode extends Node {

object Node extends Logging {
def apply(o: Any): Node =
if(o == null) LiteralNode(null)
else if(o.isInstanceOf[WithOp] && (o.asInstanceOf[WithOp].op ne null)) Node(o.asInstanceOf[WithOp].op)
else if(o.isInstanceOf[NodeGenerator]) {
if(o.isInstanceOf[NodeGenerator]) {
val gen = o.asInstanceOf[NodeGenerator]
if(gen.nodeDelegate eq gen) gen.nodeDelegate else Node(gen.nodeDelegate)
}
Expand Down Expand Up @@ -559,12 +557,12 @@ object FwdPath {
abstract class TableNode extends NullaryNode { self =>
type Self = TableNode
def tableIdentitySymbol: TableIdentitySymbol
def nodeTableProjection: Node
def nodeTableProjection(tableRef: Node): Node
def schemaName: Option[String]
def tableName: String
override def toString = "Table " + tableName
def nodeRebuild: TableNode = new TableNode {
def nodeTableProjection = self.nodeTableProjection
def nodeTableProjection(tableRef: Node) = self.nodeTableProjection(tableRef)
def schemaName = self.schemaName
def tableName = self.tableName
def tableIdentitySymbol = self.tableIdentitySymbol
Expand Down
44 changes: 0 additions & 44 deletions src/main/scala/scala/slick/ast/WithOp.scala

This file was deleted.

2 changes: 1 addition & 1 deletion src/main/scala/scala/slick/compiler/Columnizer.scala
Expand Up @@ -117,7 +117,7 @@ class ExpandTables extends Phase {
case t: TableExpansion => t
case t: TableNode =>
val sym = new AnonSymbol
val expanded = WithOp.encodeRef(t, sym).nodeTableProjection
val expanded = t.nodeTableProjection(Ref(sym))
val processed = apply(state.compiler.runBefore(this, state.withNode(expanded)).tree, state)
TableExpansion(sym, t, ProductNode(processed.flattenProduct))
case n => n.nodeMapChildren(ch => apply(ch, state))
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/scala/slick/compiler/InsertCompiler.scala
Expand Up @@ -23,7 +23,7 @@ trait InsertCompiler extends Phase {

def tr(n: Node): Node = n match {
case _: OptionApply | _: GetOrElse | _: ProductNode | _: TypeMapping => n.nodeMapChildren(tr, keepType = true)
case t:TableNode => tr(Node(t.nodeTableProjection))
case t: TableNode => tr(t.nodeTableProjection(t))
case sel @ Select(Ref(IntrinsicSymbol(t: TableNode)), fs: FieldSymbol) =>
if(table eq null) table = t
else if(table ne t) throw new SlickException("Cannot insert into more than one table at once")
Expand Down
6 changes: 3 additions & 3 deletions src/main/scala/scala/slick/direct/SlickBackend.scala
Expand Up @@ -202,13 +202,13 @@ class SlickBackend( val driver: JdbcDriver, mapper:Mapper ) extends QueryableBac
def typetagToQuery(typetag:TypeTag[_]) : Query = {
def _fields = getConstructorArgs(typetag.tpe)

val table = new sq.TableNode with sq.WithOp with sq.TypedNode {
val table = new sq.TableNode with sq.TypedNode {
val schemaName = None
val tableName = mapper.typeToTable( typetag.tpe )
val tableIdentitySymbol = sq.SimpleTableIdentitySymbol(driver, schemaName.getOrElse("_"), tableName)
val rowType = sq.StructType(_fields.map( sym => columnField(sym) -> columnType(sym.typeSignature) ).toIndexedSeq)
def nodeTableProjection = sq.TypeMapping(
sq.ProductNode( _fields.map( fieldSym => columnSelect(fieldSym,sq.Node(this)) )),
def nodeTableProjection(tableRef: sq.Node) = sq.TypeMapping(
sq.ProductNode( _fields.map( fieldSym => columnSelect(fieldSym, tableRef) )),
v => throw new Exception("not implemented yet"),
v => cm.reflectClass( cm.classSymbol(cm.runtimeClass(typetag.tpe)) )
.reflectConstructor(
Expand Down
29 changes: 27 additions & 2 deletions src/main/scala/scala/slick/lifted/AbstractTable.scala
Expand Up @@ -3,10 +3,35 @@ package scala.slick.lifted
import scala.slick.ast._
import scala.slick.ast.Util.nodeToNodeOps

abstract class AbstractTable[T](val schemaName: Option[String], val tableName: String) extends TableNode with TypedNode with ColumnBase[T] with WithOp {
abstract class AbstractTable[T](val schemaName: Option[String], val tableName: String) extends TableNode with TypedNode with ColumnBase[T] with Cloneable with EncodeRef {

private[this] def mapOp(f: (Node, List[Int]) => Node, positions: List[Int] = Nil): this.type = {
val tv = Node(this)
val fv = f(tv, positions)
if(fv eq tv) this
else {
val t = clone.asInstanceOf[this.type]
t._op = fv
t
}
}

private[AbstractTable] var _op: Node = _

def tableIsRaw = _op eq null

def encodeRef(sym: Symbol, positions: List[Int] = Nil): this.type = {
def f(n: Node, positions: List[Int]): Node = Path(positions.map(ElementSymbol) :+ sym)
mapOp(f, positions)
}

def * : ProvenShape[T]
def nodeTableProjection: Node = Node(*)
def nodeTableProjection(tableRef: Node): Node = {
val base = if(tableRef eq this) this else mapOp((_, _) => tableRef)
Node(base.*)
}

override def nodeDelegate = if(_op eq null) this else _op

def create_* : Iterable[FieldSymbol] = collectFieldSymbols(Node(*))

Expand Down
8 changes: 5 additions & 3 deletions src/main/scala/scala/slick/lifted/ColumnBase.scala
Expand Up @@ -3,14 +3,14 @@ package scala.slick.lifted
import scala.slick.ast._

/** Common base trait for all lifted values. */
trait Rep[T] extends NodeGenerator with WithOp
trait Rep[T] extends NodeGenerator

/** Common base trait for record values
* (anything that is isomorphic to a tuple of scalar values). */
trait ColumnBase[T] extends Rep[T]

/** Base class for columns. */
abstract class Column[T](implicit final val tpe: TypedType[T]) extends ColumnBase[T] { self =>
abstract class Column[T](implicit final val tpe: TypedType[T]) extends ColumnBase[T] with EncodeRef { self =>
def asc = ColumnOrdered[T](this, Ordering())
def desc = ColumnOrdered[T](this, Ordering(direction = Ordering.Desc))

Expand All @@ -19,11 +19,13 @@ abstract class Column[T](implicit final val tpe: TypedType[T]) extends ColumnBas
if(n eq this) super.toString
else s"Column($n)"
}
def encodeRef(sym: Symbol, positions: List[Int] = Nil): Column[T] =
Column.forNode(Path(positions.map(ElementSymbol) :+ sym))
}

object Column {
def forNode[T : TypedType](n: Node): Column[T] = new Column[T] {
def nodeDelegate = if(op eq null) n else op.nodeDelegate
def nodeDelegate = n
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/scala/slick/lifted/Query.scala
Expand Up @@ -18,7 +18,7 @@ abstract class Query[+E, U] extends Rep[Seq[U]] with EncodeRef { self =>
val generator = new AnonSymbol
val aliased = {
val uv = unpackable.value
WithOp.encodeRef(uv, generator)
EncodeRef(uv, generator)
}
val fv = f(aliased)
new WrappingQuery[F, T](new Bind(generator, Node(this), Node(fv)), fv.unpackable)
Expand Down Expand Up @@ -104,7 +104,7 @@ abstract class Query[+E, U] extends Rep[Seq[U]] with EncodeRef { self =>

object Query extends Query[Column[Unit], Unit] {
def nodeDelegate = packed
def unpackable = ShapedValue(ConstColumn(()).mapOp((n, _) => Pure(n)), Shape.unpackColumnBase[Unit, Column[Unit]])
def unpackable = ShapedValue(Column.forNode[Unit](Pure(ConstColumn(()))), Shape.unpackColumnBase[Unit, Column[Unit]])

def apply[E, U, R](value: E)(implicit unpack: Shape[E, U, R]): Query[R, U] = {
val unpackable = ShapedValue(value, unpack).packedValue
Expand Down
9 changes: 6 additions & 3 deletions src/main/scala/scala/slick/lifted/Shape.scala
Expand Up @@ -92,7 +92,7 @@ final class TupleShape[M <: Product, U <: Product, P <: Product](ps: Shape[_, _,
*/
case class ShapedValue[T, U](value: T, shape: Shape[T, U, _]) {
def encodeRef(s: Symbol, positions: List[Int] = Nil): ShapedValue[T, U] = {
val fv = WithOp.encodeRef(value, s, positions)
val fv = EncodeRef(value, s, positions)
if(fv.asInstanceOf[AnyRef] eq value.asInstanceOf[AnyRef]) this else new ShapedValue(fv, shape)
}
def packedNode = Node(shape.pack(value))
Expand Down Expand Up @@ -134,9 +134,12 @@ object ProvenShape {
}
}

final class MappedProjection[T, P](child: Node, f: (P => T), g: (T => P)) extends ColumnBase[T] with NodeGenerator {
class MappedProjection[T, P](child: Node, f: (P => T), g: (T => P)) extends ColumnBase[T] with NodeGenerator with EncodeRef {
type Self = MappedProjection[_, _]
override def toString = "MappedProjection"
private def typeMapping = TypeMapping(Node(child), (v => g(v.asInstanceOf[T])), (v => f(v.asInstanceOf[P])))
override def nodeDelegate = if(op eq null) typeMapping else op.nodeDelegate
override def nodeDelegate: Node = typeMapping
def encodeRef(sym: Symbol, positions: List[Int] = Nil): MappedProjection[T, P] = new MappedProjection[T, P](child, f, g) {
override def nodeDelegate = Path(positions.map(ElementSymbol) :+ sym)
}
}
2 changes: 1 addition & 1 deletion src/main/scala/scala/slick/profile/RelationalProfile.scala
Expand Up @@ -24,7 +24,7 @@ trait RelationalProfile extends BasicProfile with RelationalTableComponent
implicit def columnToOptionColumn[T : BaseTypedType](c: Column[T]): Column[Option[T]] = c.?
implicit def valueToConstColumn[T : TypedType](v: T) = new ConstColumn[T](v)
implicit def tableToQuery[T <: AbstractTable[_]](t: T) = {
if(t.op ne null) throw new SlickException("Trying to implicitly lift a single table row to a Query. If this is really what you want, use an explicit Query(...) call instead")
if(!t.tableIsRaw) throw new SlickException("Trying to implicitly lift a single table row to a Query. If this is really what you want, use an explicit Query(...) call instead")
Query[T, NothingContainer#TableNothing, T](t)(Shape.tableShape)
}
implicit def columnToOrdered[T](c: Column[T]): ColumnOrdered[T] = c.asc
Expand Down

0 comments on commit 73c79b3

Please sign in to comment.