Skip to content

Commit 399ef58

Browse files
committed
Merge branch 'develop'
2 parents 45ae268 + 991b99f commit 399ef58

File tree

16 files changed

+153
-116
lines changed

16 files changed

+153
-116
lines changed

.travis.yml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
language: scala
2+
jdk:
3+
# Play 2.4 supports only JDK8
4+
- oraclejdk8
25
scala:
3-
- 2.10.4
4-
- 2.11.5
5-
script: sbt clean coverage test
6-
after_success: sbt coveralls
6+
- 2.10.6
7+
- 2.11.8
8+
sudo: false
9+
script: sbt ++${TRAVIS_SCALA_VERSION} clean $(if [[ "${TRAVIS_SCALA_VERSION}" == "2.11.8" ]]; then echo coverage ; else echo "" ; fi) test
10+
after_success: sbt $(if [[ "${TRAVIS_SCALA_VERSION}" == "2.11.8" ]]; then echo coveralls ; else echo "" ; fi)
711
addons:
812
postgresql: '9.3'
913
before_script:
14+
- rm project/pgp.sbt && rm project/sbt-updates.sbt && rm project/sonatype.sbt
1015
- psql -c "CREATE ROLE sa WITH SUPERUSER LOGIN PASSWORD 'sa';" -U postgres
1116
- psql -c "CREATE DATABASE scalikejdbc;" -U postgres
1217
- psql -c "CREATE DATABASE scalikejdbc2;" -U postgres

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ ScalikeJDBC is a tidy SQL-based DB access library for Scala developers. This lib
1717

1818
### Important Notice
1919

20-
ScalikeJDBC-Async and [postgrsql-async and mysql-async](https://github.com/mauricio/postgresql-async) are still in the alpha stage. If you don't have motivation to investigate or fix issues by yourself, we recommend you waiting until stable version release someday.
20+
ScalikeJDBC-Async is still in the beta stage. If you don't have motivation to investigate or fix issues by yourself, we recommend you waiting until stable version release someday.
2121

2222
### Supported RDBMS
2323

build.sbt

Lines changed: 0 additions & 2 deletions
This file was deleted.

core/build.sbt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1 @@
11
scalariformSettings
2-
3-
net.virtualvoid.sbt.graph.Plugin.graphSettings
4-

core/src/main/scala/scalikejdbc/async/AsyncDBSession.scala

Lines changed: 105 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -28,54 +28,63 @@ trait AsyncDBSession extends LogSupport {
2828

2929
val connection: AsyncConnection
3030

31-
def execute(statement: String, parameters: Any*)(implicit cxt: EC = ECGlobal): Future[Boolean] =
32-
withListeners(statement, parameters) {
33-
queryLogging(statement, parameters)
34-
connection.sendPreparedStatement(statement, parameters: _*).map { result =>
31+
def execute(statement: String, parameters: Any*)(implicit cxt: EC = ECGlobal): Future[Boolean] = {
32+
val _parameters = ensureAndNormalizeParameters(parameters)
33+
withListeners(statement, _parameters) {
34+
queryLogging(statement, _parameters)
35+
connection.sendPreparedStatement(statement, _parameters: _*).map { result =>
3536
result.rowsAffected.map(_ > 0).getOrElse(false)
3637
}
3738
}
39+
}
3840

39-
def update(statement: String, parameters: Any*)(implicit cxt: EC = ECGlobal): Future[Int] =
40-
withListeners(statement, parameters) {
41-
queryLogging(statement, parameters)
41+
def update(statement: String, parameters: Any*)(implicit cxt: EC = ECGlobal): Future[Int] = {
42+
val _parameters = ensureAndNormalizeParameters(parameters)
43+
withListeners(statement, _parameters) {
44+
queryLogging(statement, _parameters)
4245
if (connection.isShared) {
4346
// create local transaction because postgresql-async 0.2.4 seems not to be stable with PostgreSQL without transaction
4447
connection.toNonSharedConnection().map(c => TxAsyncDBSession(c)).flatMap { tx: TxAsyncDBSession =>
45-
tx.update(statement, parameters: _*)
48+
tx.update(statement, _parameters: _*)
4649
}
4750
} else {
48-
connection.sendPreparedStatement(statement, parameters: _*).map { result =>
51+
connection.sendPreparedStatement(statement, _parameters: _*).map { result =>
4952
result.rowsAffected.map(_.toInt).getOrElse(0)
5053
}
5154
}
5255
}
56+
}
5357

54-
def updateAndReturnGeneratedKey(statement: String, parameters: Any*)(implicit cxt: EC = ECGlobal): Future[Long] =
55-
withListeners(statement, parameters) {
56-
queryLogging(statement, parameters)
58+
def updateAndReturnGeneratedKey(statement: String, parameters: Any*)(implicit cxt: EC = ECGlobal): Future[Long] = {
59+
val _parameters = ensureAndNormalizeParameters(parameters)
60+
withListeners(statement, _parameters) {
61+
queryLogging(statement, _parameters)
5762
connection.toNonSharedConnection().flatMap { conn =>
58-
conn.sendPreparedStatement(statement, parameters: _*).map { result =>
63+
conn.sendPreparedStatement(statement, _parameters: _*).map { result =>
5964
result.generatedKey.getOrElse {
6065
throw new IllegalArgumentException(ErrorMessage.FAILED_TO_RETRIEVE_GENERATED_KEY + " SQL: '" + statement + "'")
6166
}
6267
}
6368
}
6469
}
70+
}
6571

66-
def traversable[A](statement: String, parameters: Any*)(extractor: WrappedResultSet => A)(implicit cxt: EC = ECGlobal): Future[Traversable[A]] =
67-
withListeners(statement, parameters) {
68-
queryLogging(statement, parameters)
69-
connection.sendPreparedStatement(statement, parameters: _*).map { result =>
72+
def traversable[A](statement: String, parameters: Any*)(extractor: WrappedResultSet => A)(implicit cxt: EC = ECGlobal): Future[Traversable[A]] = {
73+
val _parameters = ensureAndNormalizeParameters(parameters)
74+
withListeners(statement, _parameters) {
75+
queryLogging(statement, _parameters)
76+
connection.sendPreparedStatement(statement, _parameters: _*).map { result =>
7077
result.rows.map { ars =>
7178
new AsyncResultSetTraversable(ars).map(rs => extractor(rs))
7279
}.getOrElse(Nil)
7380
}
7481
}
82+
}
7583

7684
def single[A](statement: String, parameters: Any*)(extractor: WrappedResultSet => A)(
7785
implicit cxt: EC = ECGlobal): Future[Option[A]] = {
78-
traversable(statement, parameters: _*)(extractor).map { results =>
86+
val _parameters = ensureAndNormalizeParameters(parameters)
87+
traversable(statement, _parameters: _*)(extractor).map { results =>
7988
results match {
8089
case Nil => None
8190
case one :: Nil => Option(one)
@@ -85,13 +94,15 @@ trait AsyncDBSession extends LogSupport {
8594
}
8695

8796
def list[A](statement: String, parameters: Any*)(extractor: WrappedResultSet => A)(implicit cxt: EC = ECGlobal): Future[List[A]] = {
88-
(traversable[A](statement, parameters: _*)(extractor)).map(_.toList)
97+
val _parameters = ensureAndNormalizeParameters(parameters)
98+
(traversable[A](statement, _parameters: _*)(extractor)).map(_.toList)
8999
}
90100

91101
def oneToOneTraversable[A, B, Z](statement: String, parameters: Any*)(extractOne: (WrappedResultSet) => A)(extractTo: (WrappedResultSet) => Option[B])(transform: (A, B) => Z)(
92-
implicit cxt: EC = ECGlobal): Future[Traversable[Z]] =
93-
withListeners(statement, parameters) {
94-
queryLogging(statement, parameters)
102+
implicit cxt: EC = ECGlobal): Future[Traversable[Z]] = {
103+
val _parameters = ensureAndNormalizeParameters(parameters)
104+
withListeners(statement, _parameters) {
105+
queryLogging(statement, _parameters)
95106

96107
def processResultSet(oneToOne: (LinkedHashMap[A, Option[B]]), rs: WrappedResultSet): LinkedHashMap[A, Option[B]] = {
97108
val o = extractOne(rs)
@@ -101,7 +112,7 @@ trait AsyncDBSession extends LogSupport {
101112
oneToOne += (o -> extractTo(rs))
102113
}
103114
}
104-
connection.sendPreparedStatement(statement, parameters: _*).map { result =>
115+
connection.sendPreparedStatement(statement, _parameters: _*).map { result =>
105116
result.rows.map { ars =>
106117
new AsyncResultSetTraversable(ars).foldLeft(LinkedHashMap[A, Option[B]]())(processResultSet).map {
107118
case (one, Some(to)) => transform(one, to)
@@ -110,11 +121,16 @@ trait AsyncDBSession extends LogSupport {
110121
}.getOrElse(Nil)
111122
}
112123
}
124+
}
113125

114-
def oneToManyTraversable[A, B, Z](statement: String, parameters: Any*)(extractOne: (WrappedResultSet) => A)(extractTo: (WrappedResultSet) => Option[B])(transform: (A, Seq[B]) => Z)(
115-
implicit cxt: EC = ECGlobal): Future[Traversable[Z]] =
116-
withListeners(statement, parameters) {
117-
queryLogging(statement, parameters)
126+
def oneToManyTraversable[A, B, Z](statement: String, parameters: Any*)(
127+
extractOne: (WrappedResultSet) => A)(
128+
extractTo: (WrappedResultSet) => Option[B])(
129+
transform: (A, Seq[B]) => Z)(
130+
implicit cxt: EC = ECGlobal): Future[Traversable[Z]] = {
131+
val _parameters = ensureAndNormalizeParameters(parameters)
132+
withListeners(statement, _parameters) {
133+
queryLogging(statement, _parameters)
118134

119135
def processResultSet(oneToMany: (LinkedHashMap[A, Seq[B]]), rs: WrappedResultSet): LinkedHashMap[A, Seq[B]] = {
120136
val o = extractOne(rs)
@@ -124,21 +140,25 @@ trait AsyncDBSession extends LogSupport {
124140
oneToMany += (o -> extractTo(rs).map(many => Vector(many)).getOrElse(Nil))
125141
}
126142
}
127-
connection.sendPreparedStatement(statement, parameters: _*).map { result =>
143+
connection.sendPreparedStatement(statement, _parameters: _*).map { result =>
128144
result.rows.map { ars =>
129145
new AsyncResultSetTraversable(ars).foldLeft(LinkedHashMap[A, Seq[B]]())(processResultSet).map {
130146
case (one, to) => transform(one, to)
131147
}
132148
}.getOrElse(Nil)
133149
}
134150
}
151+
}
135152

136153
def oneToManies2Traversable[A, B1, B2, Z](statement: String, parameters: Any*)(
137154
extractOne: (WrappedResultSet) => A)(
138155
extractTo1: (WrappedResultSet) => Option[B1],
139-
extractTo2: (WrappedResultSet) => Option[B2])(transform: (A, Seq[B1], Seq[B2]) => Z)(implicit cxt: EC = ECGlobal): Future[Traversable[Z]] =
140-
withListeners(statement, parameters) {
141-
queryLogging(statement, parameters)
156+
extractTo2: (WrappedResultSet) => Option[B2])(
157+
transform: (A, Seq[B1], Seq[B2]) => Z)(
158+
implicit cxt: EC = ECGlobal): Future[Traversable[Z]] = {
159+
val _parameters = ensureAndNormalizeParameters(parameters)
160+
withListeners(statement, _parameters) {
161+
queryLogging(statement, _parameters)
142162

143163
def processResultSet(result: (LinkedHashMap[A, (Seq[B1], Seq[B2])]), rs: WrappedResultSet): LinkedHashMap[A, (Seq[B1], Seq[B2])] = {
144164
val o = extractOne(rs)
@@ -155,22 +175,26 @@ trait AsyncDBSession extends LogSupport {
155175
result += (o -> (to1.map(t => Vector(t)).getOrElse(Vector()), to2.map(t => Vector(t)).getOrElse(Vector())))
156176
}
157177
}
158-
connection.sendPreparedStatement(statement, parameters: _*).map { result =>
178+
connection.sendPreparedStatement(statement, _parameters: _*).map { result =>
159179
result.rows.map { ars =>
160180
new AsyncResultSetTraversable(ars).foldLeft(LinkedHashMap[A, (Seq[B1], Seq[B2])]())(processResultSet).map {
161181
case (one, (t1, t2)) => transform(one, t1, t2)
162182
}
163183
}.getOrElse(Nil)
164184
}
165185
}
186+
}
166187

167188
def oneToManies3Traversable[A, B1, B2, B3, Z](statement: String, parameters: Any*)(
168189
extractOne: (WrappedResultSet) => A)(
169190
extractTo1: (WrappedResultSet) => Option[B1],
170191
extractTo2: (WrappedResultSet) => Option[B2],
171-
extractTo3: (WrappedResultSet) => Option[B3])(transform: (A, Seq[B1], Seq[B2], Seq[B3]) => Z)(implicit cxt: EC = ECGlobal): Future[Traversable[Z]] =
172-
withListeners(statement, parameters) {
173-
queryLogging(statement, parameters)
192+
extractTo3: (WrappedResultSet) => Option[B3])(
193+
transform: (A, Seq[B1], Seq[B2], Seq[B3]) => Z)(
194+
implicit cxt: EC = ECGlobal): Future[Traversable[Z]] = {
195+
val _parameters = ensureAndNormalizeParameters(parameters)
196+
withListeners(statement, _parameters) {
197+
queryLogging(statement, _parameters)
174198

175199
def processResultSet(result: (LinkedHashMap[A, (Seq[B1], Seq[B2], Seq[B3])]), rs: WrappedResultSet): LinkedHashMap[A, (Seq[B1], Seq[B2], Seq[B3])] = {
176200
val o = extractOne(rs)
@@ -194,23 +218,27 @@ trait AsyncDBSession extends LogSupport {
194218
)
195219
}
196220
}
197-
connection.sendPreparedStatement(statement, parameters: _*).map { result =>
221+
connection.sendPreparedStatement(statement, _parameters: _*).map { result =>
198222
result.rows.map { ars =>
199223
new AsyncResultSetTraversable(ars).foldLeft(LinkedHashMap[A, (Seq[B1], Seq[B2], Seq[B3])]())(processResultSet).map {
200224
case (one, (t1, t2, t3)) => transform(one, t1, t2, t3)
201225
}
202226
}.getOrElse(Nil)
203227
}
204228
}
229+
}
205230

206231
def oneToManies4Traversable[A, B1, B2, B3, B4, Z](statement: String, parameters: Any*)(
207232
extractOne: (WrappedResultSet) => A)(
208233
extractTo1: (WrappedResultSet) => Option[B1],
209234
extractTo2: (WrappedResultSet) => Option[B2],
210235
extractTo3: (WrappedResultSet) => Option[B3],
211-
extractTo4: (WrappedResultSet) => Option[B4])(transform: (A, Seq[B1], Seq[B2], Seq[B3], Seq[B4]) => Z)(implicit cxt: EC = ECGlobal): Future[Traversable[Z]] =
212-
withListeners(statement, parameters) {
213-
queryLogging(statement, parameters)
236+
extractTo4: (WrappedResultSet) => Option[B4])(
237+
transform: (A, Seq[B1], Seq[B2], Seq[B3], Seq[B4]) => Z)(
238+
implicit cxt: EC = ECGlobal): Future[Traversable[Z]] = {
239+
val _parameters = ensureAndNormalizeParameters(parameters)
240+
withListeners(statement, _parameters) {
241+
queryLogging(statement, _parameters)
214242

215243
def processResultSet(result: (LinkedHashMap[A, (Seq[B1], Seq[B2], Seq[B3], Seq[B4])]), rs: WrappedResultSet): LinkedHashMap[A, (Seq[B1], Seq[B2], Seq[B3], Seq[B4])] = {
216244
val o = extractOne(rs)
@@ -236,26 +264,35 @@ trait AsyncDBSession extends LogSupport {
236264
)
237265
}
238266
}
239-
connection.sendPreparedStatement(statement, parameters: _*).map { result =>
267+
connection.sendPreparedStatement(statement, _parameters: _*).map { result =>
240268
result.rows.map { ars =>
241-
new AsyncResultSetTraversable(ars).foldLeft(LinkedHashMap[A, (Seq[B1], Seq[B2], Seq[B3], Seq[B4])]())(processResultSet).map {
242-
case (one, (t1, t2, t3, t4)) => transform(one, t1, t2, t3, t4)
243-
}
269+
new AsyncResultSetTraversable(ars).foldLeft(
270+
LinkedHashMap[A, (Seq[B1], Seq[B2], Seq[B3], Seq[B4])]())(processResultSet).map {
271+
case (one, (t1, t2, t3, t4)) => transform(one, t1, t2, t3, t4)
272+
}
244273
}.getOrElse(Nil)
245274
}
246275
}
276+
}
247277

248-
def oneToManies5Traversable[A, B1, B2, B3, B4, B5, Z](statement: String, parameters: Any*)(
249-
extractOne: (WrappedResultSet) => A)(
250-
extractTo1: (WrappedResultSet) => Option[B1],
251-
extractTo2: (WrappedResultSet) => Option[B2],
252-
extractTo3: (WrappedResultSet) => Option[B3],
253-
extractTo4: (WrappedResultSet) => Option[B4],
254-
extractTo5: (WrappedResultSet) => Option[B5])(transform: (A, Seq[B1], Seq[B2], Seq[B3], Seq[B4], Seq[B5]) => Z)(implicit cxt: EC = ECGlobal): Future[Traversable[Z]] =
255-
withListeners(statement, parameters) {
256-
queryLogging(statement, parameters)
257-
258-
def processResultSet(result: (LinkedHashMap[A, (Seq[B1], Seq[B2], Seq[B3], Seq[B4], Seq[B5])]), rs: WrappedResultSet): LinkedHashMap[A, (Seq[B1], Seq[B2], Seq[B3], Seq[B4], Seq[B5])] = {
278+
def oneToManies5Traversable[A, B1, B2, B3, B4, B5, Z](
279+
statement: String,
280+
parameters: Any*)(
281+
extractOne: (WrappedResultSet) => A)(
282+
extractTo1: (WrappedResultSet) => Option[B1],
283+
extractTo2: (WrappedResultSet) => Option[B2],
284+
extractTo3: (WrappedResultSet) => Option[B3],
285+
extractTo4: (WrappedResultSet) => Option[B4],
286+
extractTo5: (WrappedResultSet) => Option[B5])(
287+
transform: (A, Seq[B1], Seq[B2], Seq[B3], Seq[B4], Seq[B5]) => Z)(
288+
implicit cxt: EC = ECGlobal): Future[Traversable[Z]] = {
289+
val _parameters = ensureAndNormalizeParameters(parameters)
290+
withListeners(statement, _parameters) {
291+
queryLogging(statement, _parameters)
292+
293+
def processResultSet(
294+
result: (LinkedHashMap[A, (Seq[B1], Seq[B2], Seq[B3], Seq[B4], Seq[B5])]),
295+
rs: WrappedResultSet): LinkedHashMap[A, (Seq[B1], Seq[B2], Seq[B3], Seq[B4], Seq[B5])] = {
259296
val o = extractOne(rs)
260297
val (to1, to2, to3, to4, to5) = (extractTo1(rs), extractTo2(rs), extractTo3(rs), extractTo4(rs), extractTo5(rs))
261298
result.keys.find(_ == o).map { _ =>
@@ -281,21 +318,31 @@ trait AsyncDBSession extends LogSupport {
281318
)
282319
}
283320
}
284-
connection.sendPreparedStatement(statement, parameters: _*).map { result =>
321+
connection.sendPreparedStatement(statement, _parameters: _*).map { result =>
285322
result.rows.map { ars =>
286-
new AsyncResultSetTraversable(ars).foldLeft(LinkedHashMap[A, (Seq[B1], Seq[B2], Seq[B3], Seq[B4], Seq[B5])]())(processResultSet).map {
287-
case (one, (t1, t2, t3, t4, t5)) => transform(one, t1, t2, t3, t4, t5)
288-
}
323+
new AsyncResultSetTraversable(ars).foldLeft(
324+
LinkedHashMap[A, (Seq[B1], Seq[B2], Seq[B3], Seq[B4], Seq[B5])]())(processResultSet).map {
325+
case (one, (t1, t2, t3, t4, t5)) => transform(one, t1, t2, t3, t4, t5)
326+
}
289327
}.getOrElse(Nil)
290328
}
291329
}
330+
}
292331

293332
protected def queryLogging(statement: String, parameters: Seq[Any]): Unit = {
294333
if (loggingSQLAndTime.enabled) {
295334
log.withLevel(loggingSQLAndTime.logLevel)(s"[SQL Execution] '${statement}' with (${parameters.mkString(",")})")
296335
}
297336
}
298337

338+
protected def ensureAndNormalizeParameters(parameters: Seq[Any]): Seq[Any] = {
339+
parameters.map {
340+
case withValue: ParameterBinderWithValue[_] => withValue.value
341+
case binder: ParameterBinder => throw new IllegalArgumentException("ParameterBinder is unsupported")
342+
case rawValue => rawValue
343+
}
344+
}
345+
299346
protected def withListeners[A](statement: String, parameters: Seq[Any], startMillis: Long = System.currentTimeMillis)(
300347
f: Future[A])(implicit cxt: EC = EC.global): Future[A] = {
301348
f.onSuccess {

core/src/test/scala/programmerlist/ExampleSpec.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class ExampleSpec extends FlatSpec with Matchers with DBSettings with Logging {
3838
val withinTx: Future[Unit] = AsyncDB.localTx { implicit tx =>
3939
for {
4040
programmers <- Programmer.findAllBy(sqls.eq(p.companyId, newCompany.id))
41-
restructuring <- programmers.foldLeft(Future.successful()) { (prev, programmer) =>
41+
restructuring <- programmers.foldLeft(Future.successful(())) { (prev, programmer) =>
4242
for {
4343
_ <- prev
4444
res <- programmer.destroy()

core/src/test/scala/sample/MySQLSampleSpec.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,18 +54,18 @@ class MySQLSampleSpec extends FlatSpec with Matchers with DBSettings with Loggin
5454
}
5555

5656
it should "read values with convenience methods" in {
57-
val generatedIdFuture: Future[Long] = AsyncDB.withPool { implicit s =>
57+
val generatedIdFuture: Future[Long] = NamedAsyncDB('mysql).withPool { implicit s =>
5858
withSQL {
5959
insert.into(AsyncLover).namedValues(
6060
column.name -> "Eric",
6161
column.rating -> 2,
6262
column.isReactive -> false,
63-
column.createdAt -> createdTime).returningId
63+
column.createdAt -> createdTime)
6464
}.updateAndReturnGeneratedKey.future()
6565
}
6666
// in AsyncLover#apply we are using get with typebinders, specialized getters should work
6767
val generatedId = Await.result(generatedIdFuture, 5.seconds)
68-
val created = DB.readOnly { implicit s =>
68+
val created = NamedDB('mysql).readOnly { implicit s =>
6969
withSQL { select.from(AsyncLover as al).where.eq(al.id, generatedId) }.map((rs: WrappedResultSet) => {
7070
AsyncLover(
7171
id = rs.long(al.resultName.id),
@@ -109,7 +109,7 @@ class MySQLSampleSpec extends FlatSpec with Matchers with DBSettings with Loggin
109109

110110
it should "update" in {
111111
// updating queries should be successful
112-
DB autoCommit { implicit s =>
112+
NamedDB('mysql) autoCommit { implicit s =>
113113
withSQL { delete.from(AsyncLover).where.eq(column.id, 1004) }.update.apply()
114114
withSQL {
115115
insert.into(AsyncLover).namedValues(

0 commit comments

Comments
 (0)