@@ -4,14 +4,21 @@ import com.zaxxer.hikari.{HikariConfig, HikariDataSource}
4
4
5
5
import java .io .FileInputStream
6
6
import java .security .KeyStore
7
- import java .util .{UUID , Properties }
7
+ import java .util .{Properties , UUID }
8
8
import javax .sql .DataSource
9
-
10
9
import com .codahale .metrics .MetricRegistry
11
10
import com .codahale .metrics .health .HealthCheckRegistry
11
+ import com .simple .jdub .Database .Primary
12
+ import com .simple .jdub .Database .Replica
13
+
14
+ import scala .annotation .implicitNotFound
12
15
13
16
object Database {
14
17
18
+ sealed trait Role
19
+ final class Primary extends Role
20
+ final class Replica extends Role
21
+
15
22
/**
16
23
* Create a pool of connections to the given database.
17
24
*
@@ -20,7 +27,7 @@ object Database {
20
27
* @param password the database password
21
28
* @param sslSettings if present, uses the given SSL settings for a client-side SSL cert.
22
29
*/
23
- def connect (url : String ,
30
+ def connect [ R <: Role ] (url : String ,
24
31
username : String ,
25
32
password : String ,
26
33
name : Option [String ] = None ,
@@ -30,7 +37,7 @@ object Database {
30
37
sslSettings : Option [SslSettings ] = None ,
31
38
healthCheckRegistry : Option [HealthCheckRegistry ] = None ,
32
39
metricRegistry : Option [MetricRegistry ] = None ,
33
- connectionInitSql : Option [String ] = None ): Database = {
40
+ connectionInitSql : Option [String ] = None ): Database [ R ] = {
34
41
35
42
val properties = new Properties
36
43
@@ -95,8 +102,8 @@ object Database {
95
102
/**
96
103
* A set of pooled connections to a database.
97
104
*/
98
- class Database protected (val source : DataSource , metrics : Option [MetricRegistry ])
99
- extends Queryable {
105
+ class Database [ R <: Database . Role ] protected (val source : DataSource , metrics : Option [MetricRegistry ])
106
+ extends Queryable [ R ] {
100
107
101
108
private [jdub] def time [A ](klass : java.lang.Class [_])(f : => A ) = {
102
109
metrics.fold(f) { registry =>
@@ -110,34 +117,38 @@ class Database protected(val source: DataSource, metrics: Option[MetricRegistry]
110
117
}
111
118
}
112
119
113
- val transactionProvider : TransactionProvider = new TransactionManager
120
+ val transactionProvider : TransactionProvider [R ] = new TransactionManager
121
+
122
+ def replica : Database [Replica ] = new Database [Replica ](source, metrics)
123
+
124
+ def primary : Database [Primary ] = new Database [Primary ](source, metrics)
114
125
115
126
/**
116
127
* Opens a transaction which is committed after `f` is called. If `f` throws
117
128
* an exception, the transaction is rolled back.
118
129
*/
119
- def transaction [A ](f : Transaction => A ): A = transaction(true , f)
130
+ def transaction [A ](f : Transaction [ R ] => A )( implicit ev : R =:= Primary ): A = transaction(true , f)
120
131
121
132
/**
122
133
* Opens a transaction which is committed after `f` is called. If `f` throws
123
134
* an exception, the transaction is rolled back, but the exception is not
124
135
* logged (since it is rethrown).
125
136
*/
126
- def quietTransaction [A ](f : Transaction => A ): A = transaction(false , f)
137
+ def quietTransaction [A ](f : Transaction [ R ] => A )( implicit ev : R =:= Primary ): A = transaction(false , f)
127
138
128
- def transaction [A ](logError : Boolean , f : Transaction => A ): A = transaction(false , false , f)
139
+ def transaction [A ](logError : Boolean , f : Transaction [ R ] => A )( implicit ev : R =:= Primary ): A = transaction(false , false , f)
129
140
130
141
/**
131
142
* Opens a transaction which is committed after `f` is called. If `f` throws
132
143
* an exception, the transaction is rolled back.
133
144
*/
134
- def transaction [A ](logError : Boolean , forceNew : Boolean , f : Transaction => A ): A = {
145
+ def transaction [A ](logError : Boolean , forceNew : Boolean , f : Transaction [ R ] => A )( implicit ev : R =:= Primary ): A = {
135
146
if (! forceNew && transactionProvider.transactionExists) {
136
147
f(transactionProvider.currentTransaction)
137
148
} else {
138
149
val connection = source.getConnection
139
150
connection.setAutoCommit(false )
140
- val txn = new Transaction (connection)
151
+ val txn = new Transaction [ R ] (connection)
141
152
try {
142
153
logger.debug(" Starting transaction" )
143
154
val result = f(txn)
@@ -162,8 +173,8 @@ class Database protected(val source: DataSource, metrics: Option[MetricRegistry]
162
173
* thread within the scope of `f`. If `f` throws an exception the transaction
163
174
* is rolled back. Logs exceptions thrown by `f` as errors.
164
175
*/
165
- def transactionScope [A ](f : => A ): A = {
166
- transaction(logError = true , forceNew = false , (txn : Transaction ) => {
176
+ def transactionScope [A ](f : => A )( implicit ev : R =:= Primary ) : A = {
177
+ transaction(logError = true , forceNew = false , (txn : Transaction [ R ] ) => {
167
178
transactionProvider.begin(txn)
168
179
try {
169
180
f
@@ -181,8 +192,8 @@ class Database protected(val source: DataSource, metrics: Option[MetricRegistry]
181
192
* exception the transaction is rolled back. Logs exceptions thrown by
182
193
* `f` as errors.
183
194
*/
184
- def newTransactionScope [A ](f : => A ): A = {
185
- transaction(logError = true , forceNew = true , (txn : Transaction ) => {
195
+ def newTransactionScope [A ](f : => A )( implicit ev : R =:= Primary ) : A = {
196
+ transaction(logError = true , forceNew = true , (txn : Transaction [ R ] ) => {
186
197
transactionProvider.begin(txn)
187
198
try {
188
199
f
@@ -197,8 +208,8 @@ class Database protected(val source: DataSource, metrics: Option[MetricRegistry]
197
208
* thread within the scope of `f`. If `f` throws an exception the transaction
198
209
* is rolled back. Will not log exceptions thrown by `f`.
199
210
*/
200
- def quietTransactionScope [A ](f : => A ): A = {
201
- transaction(logError = false , forceNew = false , (txn : Transaction ) => {
211
+ def quietTransactionScope [A ](f : => A )( implicit ev : R =:= Primary ) : A = {
212
+ transaction(logError = false , forceNew = false , (txn : Transaction [ R ] ) => {
202
213
transactionProvider.begin(txn)
203
214
try {
204
215
f
@@ -216,8 +227,8 @@ class Database protected(val source: DataSource, metrics: Option[MetricRegistry]
216
227
* exception the transaction is rolled back. Will not log exceptions
217
228
* thrown by `f`.
218
229
*/
219
- def newQuietTransactionScope [A ](f : => A ): A = {
220
- transaction(logError = false , forceNew = true , (txn : Transaction ) => {
230
+ def newQuietTransactionScope [A ](f : => A )( implicit ev : R =:= Primary ) : A = {
231
+ transaction(logError = false , forceNew = true , (txn : Transaction [ R ] ) => {
221
232
transactionProvider.begin(txn)
222
233
try {
223
234
f
@@ -230,7 +241,7 @@ class Database protected(val source: DataSource, metrics: Option[MetricRegistry]
230
241
/**
231
242
* The transaction currently scoped via transactionScope.
232
243
*/
233
- def currentTransaction = {
244
+ def currentTransaction ( implicit ev : R =:= Primary ) = {
234
245
transactionProvider.currentTransaction
235
246
}
236
247
@@ -260,7 +271,7 @@ class Database protected(val source: DataSource, metrics: Option[MetricRegistry]
260
271
/**
261
272
* Executes an update, insert, delete, or DDL statement.
262
273
*/
263
- def execute (statement : Statement ) = {
274
+ def execute (statement : Statement )( implicit ev : R =:= Primary ) : Int = {
264
275
if (transactionProvider.transactionExists) {
265
276
transactionProvider.currentTransaction.execute(statement)
266
277
} else {
@@ -278,7 +289,7 @@ class Database protected(val source: DataSource, metrics: Option[MetricRegistry]
278
289
/**
279
290
* Rollback any existing ambient transaction
280
291
*/
281
- def rollback () {
292
+ def rollback ()( implicit ev : R =:= Primary ) {
282
293
transactionProvider.rollback
283
294
}
284
295
0 commit comments