Permalink
Browse files

[jdbc-scala] New debuging utility in the AcolyteDSL.

```scala
AcolyteDSL.debuging() { con =>
  val stmt = con.prepareStatement("SELECT * FROM Test WHERE id = ?")
  stmt.setString(1, "foo")
  stmt.executeQuery()
}
```
  • Loading branch information...
cchantep
cchantep committed Aug 11, 2015
1 parent 2ae96de commit 4f6afc2928fa3dbb469a1a54f7c556fa3e245afa
@@ -3,7 +3,7 @@ package acolyte.jdbc
import java.util.{ ArrayList, List JList }
import java.util.regex.Pattern
import java.sql.{ Connection SqlConnection, Statement }
import java.sql.{ Connection SqlConnection, Statement, SQLException }
import scala.language.implicitConversions
import scala.collection.JavaConversions
@@ -117,6 +117,45 @@ object AcolyteDSL {
*/
def updateResult(count: Int, keys: RowList[_]): UpdateResult =
new UpdateResult(count) withGeneratedKeys keys
/**
* Manages a scope to debug any JDBC execution
*
* @param printer the operation to print any [[QueryExecution]] that occurs within the scope of debuging.
* @param f the function working with the debug connection.
*
* {{{
* import acolyte.jdbc.AcolyteDSL
*
* AcolyteDSL.debuging() { con =>
* val stmt = con.prepareStatement("SELECT * FROM Test WHERE id = ?")
* stmt.setString(1, "foo")
* stmt.executeQuery()
* }
* // print on stdout:
* "Executed query: QueryExecution(SELECT * FROM Test WHERE id = ?,List(Param(foo, VARCHAR)))"
* }}}
*/
def debuging[A](printer: QueryExecution Unit = { x println(s"Executed query: $x") })(f: SqlConnection A): Unit = {
implicit val con = connection(handleQuery { x
printer(x)
throw DebugException
})
try {
f(con)
} catch {
case e: SQLException e.getCause match {
case DebugException ()
case sqlError throw sqlError
}
} finally {
con.close()
}
}
private case object DebugException
extends Exception with scala.util.control.NoStackTrace
}
/**
@@ -11,6 +11,12 @@ sealed trait Execution {
def parameters: List[ExecutedParameter]
}
/**
* Information about the execution of a query.
*
* @param sql the SQL statement
* @param parameter the parameters the query is executed with
*/
case class QueryExecution(
sql: String, parameters: List[ExecutedParameter] = Nil) extends Execution
@@ -28,7 +34,11 @@ case class ExecutedStatement(val p: String) {
re.findFirstIn(x.sql).map(_ (x.sql -> x.parameters))
}
sealed trait ExecutedParameter { def value: Any }
/** Parameter used to executed a query or an update. */
sealed trait ExecutedParameter {
/** The parameter value */
def value: Any
}
/** Executed parameter companion */
object ExecutedParameter {
@@ -16,4 +16,25 @@ object ConnectionSpec extends org.specs2.mutable.Specification {
}
}
"Debug" should {
"be successful" in {
val output = Seq.newBuilder[String]
AcolyteDSL.debuging(output += _.toString) { con =>
val stmt = con.prepareStatement("SELECT * FROM Test WHERE id = ?")
try {
stmt.setString(1, "foo")
stmt.executeQuery()
} catch {
case e: java.sql.SQLException => ()
} finally {
stmt.close()
}
}
output.result() must_== Seq("QueryExecution(SELECT * FROM Test WHERE id = ?,List(Param(foo, VARCHAR)))")
}
}
}
View
@@ -20,7 +20,7 @@ object Acolyte extends Build with Dependencies
jdbcDriver, jdbcScala, jdbcClojure, studio).
settings(
organization in ThisBuild := "org.eu.acolyte",
version in ThisBuild := s"1.0.33${versionVariant}",
version in ThisBuild := s"1.0.34${versionVariant}",
javaOptions in ThisBuild ++= Seq(
"-source", javaVersion, "-target", javaVersion),
scalaVersion in ThisBuild := "2.10.4",
@@ -16,6 +16,8 @@ With Maven 2/3+, its dependency can be resolved in the following way:
</dependencies>
```
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.eu.acolyte/jdbc-driver/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.eu.acolyte/jdbc-driver/)
Then code could be:
```java
View
@@ -8,6 +8,8 @@ Using SBT, Acolyte JDBC dependency can resolved as following:
libraryDependencies += "org.eu.acolyte" %% "jdbc-scala" % "VERSION" % "test"
```
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.eu.acolyte/jdbc-scala_2.11/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.eu.acolyte/jdbc-scala_2.11/)
Then code could be:
```scala
@@ -299,3 +301,31 @@ val uh1: UpdateExecution => UpdateResult =
// Defined from UpdateExecution => Int
{ ex: UpdateExecution => /* update count = */ 2 }
```
## Debug utility
Acolyte can be use to create [scope of debuging](http://acolyte.eu.org/jdbc-scaladoc/#acolyte.jdbc.AcolyteDSL$@debuging[A]%28printer:QueryExecution=%3EUnit%29%28f:SqlConnection=%3EA%29:Unit), to check what is executed in the JDBC layer.
```scala
import acolyte.jdbc.AcolyteDSL
AcolyteDSL.debuging() { con =>
val stmt = con.prepareStatement("SELECT * FROM Test WHERE id = ?")
stmt.setString(1, "foo")
stmt.executeQuery()
}
```
The previous example will print `Executed query: QueryExecution(SELECT * FROM Test WHERE id = ?,List(Param(foo, VARCHAR)))` on the stdout.
The default printer (using stdout) can be replaced by any function `acolyte.jdbc.QueryExecution => Unit` (see [`QueryExecution`](http://acolyte.eu.org/jdbc-scaladoc/#acolyte.jdbc.QueryExecution) API).
```scala
import acolyte.jdbc.AcolyteDSL
AcolyteDSL.debuging({ exec => myLogger.debug(s"Executed: $exec") }) { con =>
???
}
```
> Any function using JDBC which is called within the scope, will be passed to the debug printer.

0 comments on commit 4f6afc2

Please sign in to comment.