/
MemoryProfile.scala
133 lines (109 loc) · 5.14 KB
/
MemoryProfile.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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package scala.slick.memory
import scala.language.{implicitConversions, existentials}
import scala.collection.mutable.ArrayBuffer
import scala.slick.ast._
import scala.slick.compiler._
import scala.slick.profile.Capability
import TypeUtil.typeToTypeUtil
/** A profile and driver for interpreted queries on top of the in-memory database. */
trait MemoryProfile extends MemoryQueryingProfile { driver: MemoryDriver =>
type SchemaDescription = SchemaDescriptionDef
type InsertInvoker[T] = InsertInvokerDef[T]
type QueryExecutor[R] = QueryExecutorDef[R]
type Backend = HeapBackend
val Implicit: Implicits = new Implicits {}
val backend: Backend = HeapBackend
val simple: SimpleQL = new SimpleQL {}
val compiler = QueryCompiler.standard
lazy val queryCompiler = compiler + new MemoryCodeGen
lazy val updateCompiler = compiler
lazy val deleteCompiler = compiler
lazy val insertCompiler = QueryCompiler(Phase.inline, Phase.assignUniqueSymbols, new MemoryInsertCompiler)
override protected def computeCapabilities = super.computeCapabilities ++ MemoryProfile.capabilities.all
def createQueryExecutor[R](tree: Node, param: Any): QueryExecutor[R] = new QueryExecutorDef[R](tree, param)
def createInsertInvoker[T](tree: scala.slick.ast.Node): InsertInvoker[T] = new InsertInvokerDef[T](tree)
def createDDLInvoker(sd: SchemaDescription): DDLInvoker = ???
def buildSequenceSchemaDescription(seq: Sequence[_]): SchemaDescription = ???
def buildTableSchemaDescription(table: Table[_]): SchemaDescription = new TableDDL(table)
trait Implicits extends super.Implicits {
implicit def ddlToDDLInvoker(d: SchemaDescription): DDLInvoker = d.asInstanceOf[DDLInvoker]
}
trait SimpleQL extends super.SimpleQL with Implicits
class QueryExecutorDef[R](tree: Node, param: Any) extends super.QueryExecutorDef[R] {
def run(implicit session: Backend#Session): R = {
val inter = new QueryInterpreter(session.database, param) {
override def run(n: Node) = n match {
case ResultSetMapping(gen, from, CompiledMapping(converter, tpe)) =>
val fromV = run(from).asInstanceOf[TraversableOnce[Any]]
val b = n.nodeType.asCollectionType.cons.canBuildFrom()
b ++= fromV.map(v => converter.read(v.asInstanceOf[QueryInterpreter.ProductValue]))
b.result()
case n => super.run(n)
}
}
inter.run(tree).asInstanceOf[R]
}
}
class InsertInvokerDef[T](tree: Node) extends super.InsertInvokerDef[T] {
protected[this] val ResultSetMapping(_, Insert(_, table: TableNode, projection, _), CompiledMapping(converter, _)) = tree
type SingleInsertResult = Unit
type MultiInsertResult = Unit
def += (value: T)(implicit session: Backend#Session) {
val htable = session.database.getTable(table.tableName)
val buf = htable.createInsertRow
converter.set(value, buf, false)
htable.append(buf)
}
def ++= (values: Iterable[T])(implicit session: Backend#Session): Unit =
values.foreach(this += _)
}
abstract class DDL extends SchemaDescriptionDef with DDLInvoker { self =>
def ++(other: SchemaDescription): SchemaDescription = {
val d = Implicit.ddlToDDLInvoker(other)
new DDL {
def create(implicit session: Backend#Session) { self.create; d.create }
def drop(implicit session: Backend#Session) { self.drop; d.drop }
}
}
}
class TableDDL(table: Table[_]) extends DDL {
def create(implicit session: Backend#Session): Unit =
session.database.createTable(table.tableName,
table.create_*.map { fs => new HeapBackend.Column(fs, typeInfoFor(fs.tpe)) }.toIndexedSeq,
table.indexes.toIndexedSeq, table.tableConstraints.toIndexedSeq)
def drop(implicit session: Backend#Session): Unit =
session.database.dropTable(table.tableName)
}
}
object MemoryProfile {
object capabilities {
/** Supports all MemoryProfile features which do not have separate capability values */
val other = Capability("memory.other")
/** All MemoryProfile capabilities */
val all = Set(other)
}
}
trait MemoryDriver extends MemoryQueryingDriver with MemoryProfile { driver =>
override val profile: MemoryProfile = this
type RowWriter = ArrayBuffer[Any]
class InsertMappingCompiler(insert: Insert) extends super.MappingCompiler {
val Insert(_, table: TableNode, _, ProductNode(cols)) = insert
val tableColumnIdxs = table.driverTable.asInstanceOf[Table[_]].create_*.zipWithIndex.toMap
def createColumnConverter(n: Node, path: Node, option: Boolean, column: Option[FieldSymbol]): ResultConverter = {
val fs = column.get
val tidx = tableColumnIdxs(fs)
val autoInc = fs.options.contains(ColumnOption.AutoInc)
new ResultConverter {
def read(pr: RowReader) = ???
def update(value: Any, pr: RowUpdater) = ???
def set(value: Any, pp: RowWriter, forced: Boolean) =
if(forced || !autoInc) pp(tidx) = value
}
}
}
class MemoryInsertCompiler extends InsertCompiler {
def createMapping(ins: Insert) =
CompiledMapping(new InsertMappingCompiler(ins).compileMapping(ins.map), ins.map.nodeType)
}
}
object MemoryDriver extends MemoryDriver