/
JdbcMappingCompilerComponent.scala
76 lines (63 loc) · 3.52 KB
/
JdbcMappingCompilerComponent.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package slick.jdbc
import java.sql.{PreparedStatement, ResultSet}
import slick.ast._
import slick.compiler.{CompilerState, CodeGen}
import slick.relational._
import slick.util.SQLBuilder
/** JDBC profile component which contains the mapping compiler and insert compiler */
trait JdbcMappingCompilerComponent { self: JdbcProfile =>
/** The `MappingCompiler` for this profile. */
val mappingCompiler: MappingCompiler = new MappingCompiler
/** Create a (possibly specialized) `ResultConverter` for the given `JdbcType`. */
def createBaseResultConverter[T](ti: JdbcType[T], name: String, idx: Int): ResultConverter[JdbcResultConverterDomain, T] =
SpecializedJdbcResultConverter.base(ti, name, idx)
/** Create a (possibly specialized) `ResultConverter` for `Option` values of the given `JdbcType`. */
def createOptionResultConverter[T](ti: JdbcType[T], idx: Int): ResultConverter[JdbcResultConverterDomain, Option[T]] =
SpecializedJdbcResultConverter.option(ti, idx)
/** A ResultConverterCompiler that builds JDBC-based converters. Instances of
* this class use mutable state internally. They are meant to be used for a
* single conversion only and must not be shared or reused. */
class MappingCompiler extends ResultConverterCompiler[JdbcResultConverterDomain] {
def createColumnConverter(n: Node, idx: Int, column: Option[FieldSymbol]): ResultConverter[JdbcResultConverterDomain, _] = {
val JdbcType(ti, option) = n.nodeType.structural
if(option) createOptionResultConverter(ti, idx)
else createBaseResultConverter(ti, column.fold("<computed>")(_.name), idx)
}
override def createGetOrElseResultConverter[T](rc: ResultConverter[JdbcResultConverterDomain, Option[T]], default: () => T) = rc match {
case rc: OptionResultConverter[_] => rc.getOrElse(default)
case _ => super.createGetOrElseResultConverter[T](rc, default)
}
override def createIsDefinedResultConverter[T](rc: ResultConverter[JdbcResultConverterDomain, Option[T]]) = rc match {
case rc: OptionResultConverter[_] => rc.isDefined
case _ => super.createIsDefinedResultConverter(rc)
}
override def createTypeMappingResultConverter(rc: ResultConverter[JdbcResultConverterDomain, Any], mapper: MappedScalaType.Mapper) = {
val tm = new TypeMappingResultConverter(rc, mapper.toBase, mapper.toMapped)
mapper.fastPath match {
case Some(f) => f(tm).asInstanceOf[ResultConverter[JdbcResultConverterDomain, Any]]
case None => tm
}
}
}
/** Code generator phase for queries on JdbcProfile. */
class JdbcCodeGen(f: QueryBuilder => SQLBuilder.Result) extends CodeGen {
def compileServerSideAndMapping(serverSide: Node, mapping: Option[Node], state: CompilerState) = {
val (tree, tpe) = treeAndType(serverSide)
val sbr = f(self.createQueryBuilder(tree, state))
(CompiledStatement(sbr.sql, sbr, tpe).infer(), mapping.map(mappingCompiler.compileMapping))
}
}
/** Code generator phase for inserts on JdbcProfile. */
class JdbcInsertCodeGen(f: Insert => InsertBuilder) extends CodeGen {
def compileServerSideAndMapping(serverSide: Node, mapping: Option[Node], state: CompilerState) = {
val ib = f(serverSide.asInstanceOf[Insert])
val ibr = ib.buildInsert
(CompiledStatement(ibr.sql, ibr, serverSide.nodeType).infer(), mapping.map(n => mappingCompiler.compileMapping(ib.transformMapping(n))))
}
}
}
trait JdbcResultConverterDomain extends ResultConverterDomain {
type Reader = ResultSet
type Writer = PreparedStatement
type Updater = ResultSet
}