Browse files

Merge pull request #2447 from cchantep/anorm-batchsql

Error handling for batch SQL
  • Loading branch information...
2 parents b12ed71 + e38b935 commit f87ae8caf84c51f4a870e10d76e9c74d775a3443 @jroper jroper committed Mar 7, 2014
View
2 framework/project/Dependencies.scala
@@ -201,7 +201,7 @@ object Dependencies {
val anormDependencies = specsBuild.map(_ % "test") ++ Seq(
h2database % "test",
- "org.eu.acolyte" %% "acolyte-scala" % "1.0.13" % "test",
+ "org.eu.acolyte" %% "jdbc-scala" % "1.0.15" % "test",
"com.chuusai" % "shapeless_2.10.2" % "2.0.0-M1" % "test"
)
View
61 framework/src/anorm/src/main/scala/anorm/Anorm.scala
@@ -264,67 +264,6 @@ case class SimpleSql[T](sql: SqlQuery, params: Map[String, ParameterValue], defa
}
-case class BatchSql(sql: SqlQuery, params: Seq[Map[String, ParameterValue]]) {
- def addBatch(args: NamedParameter*): BatchSql =
- copy(params = this.params :+ (args.foldLeft(Map[String, ParameterValue]())(
- (m, np) => m + np.tupled)))
-
- def addBatchList(paramsMap: TraversableOnce[Seq[NamedParameter]]): BatchSql =
- copy(params = this.params ++ paramsMap.map(_.foldLeft(Map[String, ParameterValue]()) { (m, p) =>
- m + p.tupled
- }))
-
- def addBatchParams(args: ParameterValue*): BatchSql =
- copy(params = this.params :+ Sql.
- zipParams(sql.argsInitialOrder, args, Map.empty))
-
- def addBatchParamsList(paramsSeqList: TraversableOnce[Seq[ParameterValue]]): BatchSql = copy(params = this.params ++ paramsSeqList.map(Sql.zipParams(sql.argsInitialOrder, _, Map.empty)))
-
- /** Add batch parameters to given statement. */
- private def addBatchParams(stmt: PreparedStatement, ps: Seq[(Int, ParameterValue)]): PreparedStatement = {
- ps foreach { p =>
- val (i, v) = p
- v.set(stmt, i + 1)
- }
- stmt.addBatch()
- stmt
- }
-
- @annotation.tailrec
- private def fill(con: Connection, statement: PreparedStatement, getGeneratedKeys: Boolean = false, pm: Seq[Map[String, ParameterValue]]): PreparedStatement =
- (statement, pm.headOption) match {
- case (null, Some(ps)) => { // First
- val st: (String, Seq[(Int, ParameterValue)]) =
- Sql.prepareQuery(sql.query, 0, sql.argsInitialOrder.map(ps), Nil)
-
- val stmt = if (getGeneratedKeys) con.prepareStatement(sql.query, java.sql.Statement.RETURN_GENERATED_KEYS) else con.prepareStatement(sql.query)
-
- sql.queryTimeout.foreach(timeout => stmt.setQueryTimeout(timeout))
-
- fill(con, addBatchParams(stmt, st._2), getGeneratedKeys, pm.tail)
- }
- case (stmt, Some(ps)) => {
- val vs: Seq[(Int, ParameterValue)] =
- Sql.prepareQuery(sql.query, 0, sql.argsInitialOrder.map(ps), Nil)._2
-
- fill(con, addBatchParams(stmt, vs), getGeneratedKeys, pm.tail)
- }
- case _ => statement
- }
-
- def getFilledStatement(connection: Connection, getGeneratedKeys: Boolean = false) = fill(connection, null, getGeneratedKeys, params)
-
- @deprecated(message = "Use [[getFilledStatement]]", since = "2.3.0")
- def filledStatement(implicit connection: Connection) =
- getFilledStatement(connection)
-
- def execute()(implicit connection: Connection): Array[Int] =
- getFilledStatement(connection).executeBatch()
-
- def withQueryTimeout(seconds: Option[Int]): BatchSql =
- copy(sql = sql.withQueryTimeout(seconds))
-}
-
sealed trait Sql {
def getFilledStatement(connection: Connection, getGeneratedKeys: Boolean = false): PreparedStatement
View
194 framework/src/anorm/src/main/scala/anorm/BatchSql.scala
@@ -0,0 +1,194 @@
+package anorm
+
+import java.sql.{ Connection, PreparedStatement }
+
+private[anorm] object BatchSqlErrors {
+ val HeterogeneousParameterMaps = "if each map hasn't same parameter names"
+ val ParameterNamesNotMatchingPlaceholders =
+ "if parameter names don't match query placeholders"
+ val UnexpectedParameterName = "if `args` contains unexpected parameter name"
+ val MissingParameter = "if `args` is missing some expected parameter names"
+}
+
+/** SQL batch */
+sealed trait BatchSql {
+ /** SQL query */
+ def sql: SqlQuery
+
+ /** Names of parameter expected for each parameter map */
+ def names: Set[String]
+
+ /** Named parameters */
+ def params: Seq[Map[String, ParameterValue]] // checked: maps have same keys
+
+ @throws[IllegalArgumentException](BatchSqlErrors.UnexpectedParameterName)
+ @throws[IllegalArgumentException](BatchSqlErrors.MissingParameter)
+ @throws[IllegalArgumentException](BatchSqlErrors.ParameterNamesNotMatchingPlaceholders)
+ def addBatch(args: NamedParameter*): BatchSql = {
+ if (params.isEmpty) { // first parameter map
+ val ps = toMap(args)
+ val ks = ps.keySet
+
+ if (!BatchSql.matchPlaceholders(sql, ks))
+ throw new IllegalArgumentException(s"""Expected parameter names don't correspond to placeholders in query: ${ks mkString ", "} not matching ${sql.argsInitialOrder mkString ", "}""")
+
+ copy(names = ks, params = Seq(ps))
+ } else copy(params = this.params :+ checkedMap(args))
+ }
+
+ @throws[IllegalArgumentException](BatchSqlErrors.UnexpectedParameterName)
+ @throws[IllegalArgumentException](BatchSqlErrors.MissingParameter)
+ @throws[IllegalArgumentException](BatchSqlErrors.HeterogeneousParameterMaps)
+ @throws[IllegalArgumentException](BatchSqlErrors.ParameterNamesNotMatchingPlaceholders)
+ def addBatchList(args: Traversable[Seq[NamedParameter]]): BatchSql = {
+ if (params.isEmpty) BatchSql.Checked(sql, args.map(_.map(_.tupled).toMap))
+ else copy(params = this.params ++ args.map(checkedMap))
+ }
+
+ /**
+ * Adds a parameter map, created by zipping values with query placeholders
+ * ([[SqlQuery.argsInitialOrder]]). If parameter is used for more than one
+ * placeholder, it will result in a parameter map with smaller size than
+ * given arguments (as duplicate entry are removed from map).
+ */
+ @deprecated(message = "Use [[addBatch]]", since = "2.3.0")
+ @throws[IllegalArgumentException](BatchSqlErrors.MissingParameter)
+ @throws[IllegalArgumentException](BatchSqlErrors.ParameterNamesNotMatchingPlaceholders)
+ def addBatchParams(args: ParameterValue*): BatchSql = {
+ if (params.isEmpty) {
+ BatchSql.Checked(sql,
+ Seq(Sql.zipParams(sql.argsInitialOrder, args, Map.empty)))
+ } else {
+ val m = checkedMap(sql.argsInitialOrder.zip(args).
+ foldLeft(Seq[NamedParameter]())((ps, t) =>
+ ps :+ implicitly[NamedParameter](t)))
+
+ copy(params = this.params :+ m)
+ }
+ }
+
+ /**
+ * Adds a parameter maps, created by zipping values with query placeholders
+ * ([[SqlQuery.argsInitialOrder]]). If parameter is used for more than one
+ * placeholder, it will result in parameter maps with smaller size than
+ * given arguments (as duplicate entry are removed from map).
+ */
+ @deprecated(message = "Use [[addBatchList]]", since = "2.3.0")
+ @throws[IllegalArgumentException](BatchSqlErrors.MissingParameter)
+ @throws[IllegalArgumentException](BatchSqlErrors.ParameterNamesNotMatchingPlaceholders)
+ def addBatchParamsList(args: Traversable[Seq[ParameterValue]]): BatchSql = {
+ if (params.isEmpty) {
+ BatchSql.Checked(sql,
+ args.map(Sql.zipParams(sql.argsInitialOrder, _, Map.empty)))
+
+ } else {
+ val ms = args.map(x => checkedMap(sql.argsInitialOrder.zip(x).
+ foldLeft(Seq[NamedParameter]())((ps, t) =>
+ ps :+ implicitly[NamedParameter](t))))
+
+ copy(params = this.params ++ ms)
+ }
+ }
+
+ def getFilledStatement(connection: Connection, getGeneratedKeys: Boolean = false) = fill(connection, null, getGeneratedKeys, params)
+
+ @deprecated(message = "Use [[getFilledStatement]]", since = "2.3.0")
+ def filledStatement(implicit connection: Connection) =
+ getFilledStatement(connection)
+
+ def execute()(implicit connection: Connection): Array[Int] =
+ getFilledStatement(connection).executeBatch()
+
+ def withQueryTimeout(seconds: Option[Int]): BatchSql =
+ copy(sql = sql.withQueryTimeout(seconds))
+
+ /** Add batch parameters to given statement. */
+ private def addBatchParams(stmt: PreparedStatement, ps: Seq[(Int, ParameterValue)]): PreparedStatement = {
+ ps foreach { p =>
+ val (i, v) = p
+ v.set(stmt, i + 1)
+ }
+ stmt.addBatch()
+ stmt
+ }
+
+ @annotation.tailrec
+ private def fill(con: Connection, statement: PreparedStatement, getGeneratedKeys: Boolean = false, pm: Seq[Map[String, ParameterValue]]): PreparedStatement =
+ (statement, pm.headOption) match {
+ case (null, Some(ps)) => { // First
+ val st: (String, Seq[(Int, ParameterValue)]) =
+ Sql.prepareQuery(sql.query, 0, sql.argsInitialOrder.map(ps), Nil)
+
+ val stmt = if (getGeneratedKeys) con.prepareStatement(sql.query, java.sql.Statement.RETURN_GENERATED_KEYS) else con.prepareStatement(sql.query)
+
+ sql.queryTimeout.foreach(timeout => stmt.setQueryTimeout(timeout))
+
+ fill(con, addBatchParams(stmt, st._2), getGeneratedKeys, pm.tail)
+ }
+ case (stmt, Some(ps)) => {
+ val vs: Seq[(Int, ParameterValue)] =
+ Sql.prepareQuery(sql.query, 0, sql.argsInitialOrder.map(ps), Nil)._2
+
+ fill(con, addBatchParams(stmt, vs), getGeneratedKeys, pm.tail)
+ }
+ case _ => statement
+ }
+
+ @inline private def toMap(args: Seq[NamedParameter]): Map[String, ParameterValue] = args.foldLeft(Map[String, ParameterValue]())((m, np) => m + np.tupled)
+
+ @throws[IllegalArgumentException](BatchSqlErrors.UnexpectedParameterName)
+ @throws[IllegalArgumentException](BatchSqlErrors.MissingParameter)
+ @inline private def checkedMap(args: Seq[NamedParameter]): Map[String, ParameterValue] = {
+ val ps = args.foldLeft(Map[String, ParameterValue]()) { (m, np) =>
+ if (!names.contains(np.name)) throw new IllegalArgumentException(s"""Unexpected parameter name: ${np.name} != expected ${names mkString ", "}""")
+ else m + np.tupled
+ }
+
+ if (ps.size != names.size) throw new IllegalArgumentException(s"""Missing parameters: ${names.filterNot(ps.contains(_)) mkString ", "}""")
+
+ ps
+ }
+
+ private def copy(sql: SqlQuery = this.sql, names: Set[String] = this.names, params: Seq[Map[String, ParameterValue]] = this.params) = BatchSql.Copy(sql, names, params)
+}
+
+/** SQL batch companion */
+object BatchSql {
+ @throws[IllegalArgumentException](BatchSqlErrors.HeterogeneousParameterMaps)
+ @throws[IllegalArgumentException](BatchSqlErrors.ParameterNamesNotMatchingPlaceholders)
+ def apply(query: SqlQuery, ps: Seq[Seq[NamedParameter]] = Nil): BatchSql =
+ Checked(query, ps.map(_.map(_.tupled).toMap))
+
+ @throws[IllegalArgumentException](BatchSqlErrors.HeterogeneousParameterMaps)
+ @throws[IllegalArgumentException](BatchSqlErrors.ParameterNamesNotMatchingPlaceholders)
+ private[anorm] def Checked[M](query: SqlQuery, ps: Traversable[Map[String, ParameterValue]]): BatchSql = ps.headOption.
+ fold(Copy(query, Set.empty, Nil)) { m =>
+ val ks = m.keySet
+
+ if (!matchPlaceholders(query, ks))
+ throw new IllegalArgumentException(s"""Expected parameter names don't correspond to placeholders in query: ${ks mkString ", "} not matching ${query.argsInitialOrder mkString ", "}""")
+
+ paramNames(ps.tail, m.keySet) match {
+ case Left(err) => throw new IllegalArgumentException(err)
+ case Right(ns) => Copy(query, ns, ps.toSeq)
+ }
+ }
+
+ /** Checks whether parameter `names` matches [[SqlQuery.argsInitialOrder]] */
+ @inline private[anorm] def matchPlaceholders(query: SqlQuery, names: Set[String]): Boolean = {
+ val pl = query.argsInitialOrder.toSet
+ (pl.size == names.size && pl.intersect(names).size == names.size)
+ }
+
+ /** Get parameter names */
+ @annotation.tailrec
+ private def paramNames(ps: Traversable[Map[String, ParameterValue]], ns: Set[String]): Either[String, Set[String]] = ps.headOption match {
+ case Some(m) =>
+ if (ns.intersect(m.keySet).size != m.size)
+ Left(s"""Unexpected parameter names: ${m.keySet mkString ", "} != expected ${ns mkString ", "}""")
+ else paramNames(ps.tail, ns)
+ case _ => Right(ns)
+ }
+
+ private[anorm] case class Copy(sql: SqlQuery, names: Set[String], params: Seq[Map[String, ParameterValue]]) extends BatchSql
+}
View
16 framework/src/anorm/src/main/scala/anorm/ParameterValue.scala
@@ -35,8 +35,12 @@ sealed trait ParameterValue {
* }}}
*/
object ParameterValue {
- def apply[A](value: A, s: ToSql[A], toStmt: ToStatement[A]) =
- new ParameterValue {
+ private[anorm] trait Wrapper[T] { def value: T }
+
+ def apply[A](v: A, s: ToSql[A], toStmt: ToStatement[A]) =
+ new ParameterValue with Wrapper[A] {
+ val value = v
+
def toSql(stmt: String, o: Int): (String, Int) = {
val frag: (String, Int) =
if (s == null) ("?" -> 1) else s.fragment(value)
@@ -47,5 +51,13 @@ object ParameterValue {
}
def set(s: PreparedStatement, i: Int) = toStmt.set(s, i, value)
+
+ override lazy val toString = s"ParameterValue($value)"
+ override lazy val hashCode = value.hashCode
+
+ override def equals(that: Any) = that match {
+ case o: Wrapper[A] => (o.value == value)
+ case _ => false
+ }
}
}
View
299 framework/src/anorm/src/test/scala/anorm/BatchSqlSpec.scala
@@ -0,0 +1,299 @@
+package anorm
+
+object BatchSqlSpec extends org.specs2.mutable.Specification {
+ "Batch SQL" title
+
+ "Creation" should {
+ "fail with parameter maps not having same names" in {
+ lazy val batch = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a}", List("a")),
+ Seq(Seq[NamedParameter]("a" -> 0),
+ Seq[NamedParameter]("a" -> 1, "b" -> 2)))
+
+ batch aka "creation" must throwA[IllegalArgumentException](
+ message = "Unexpected parameter names: a, b != expected a")
+ }
+
+ "fail with names not matching query placeholders" in {
+ lazy val batch = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a}, b = {b}", List("a", "b")),
+ Seq(Seq[NamedParameter]("a" -> 1, "b" -> 2, "c" -> 3)))
+
+ batch.addBatch("a" -> 0).
+ aka("append") must throwA[IllegalArgumentException](
+ message = "Expected parameter names don't correspond to placeholders in query: a, b, c not matching a, b")
+ }
+
+ "be successful with parameter maps having same names" in {
+ lazy val batch = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a}, b = {b}", List("a", "b")),
+ Seq(Seq[NamedParameter]("a" -> 0, "b" -> -1),
+ Seq[NamedParameter]("a" -> 1, "b" -> 2)))
+
+ lazy val expectedMaps = Seq(
+ Map[String, ParameterValue]("a" -> 0, "b" -> -1),
+ Map[String, ParameterValue]("a" -> 1, "b" -> 2))
+
+ (batch aka "creation" must not(throwA[IllegalArgumentException](
+ message = "Unexpected parameter names: a, b != expected a"))).
+ and(batch.params aka "parameters" must_== expectedMaps)
+ }
+ }
+
+ "Appending list of named parameters" should {
+ "fail with unexpected name" in {
+ val batch = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a}, b = {b}", List("a", "b")),
+ Seq(Seq[NamedParameter]("a" -> 1, "b" -> 2)))
+
+ batch.addBatch("a" -> 0, "c" -> 4).
+ aka("append") must throwA[IllegalArgumentException](
+ message = "Unexpected parameter name: c != expected a, b")
+ }
+
+ "fail with missing names" in {
+ val batch = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a} AND b = {b} AND c = {c}",
+ List("a", "b", "c")),
+ Seq(Seq[NamedParameter]("a" -> 1, "b" -> 2, "c" -> 3)))
+
+ batch.addBatch("a" -> 0).
+ aka("append") must throwA[IllegalArgumentException](
+ message = "Missing parameters: b, c")
+ }
+
+ "with first parameter map" >> {
+ "fail if parameter names not matching query placeholders" in {
+ val batch = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a}, b = {b}", List("a", "b")))
+
+ batch.addBatch("a" -> 0).
+ aka("append") must throwA[IllegalArgumentException](
+ message = "Expected parameter names don't correspond to placeholders in query: a not matching a, b")
+
+ }
+
+ "be successful" in {
+ val b1 = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a}, b = {b}", List("a", "b")))
+
+ lazy val b2 = b1.addBatch("a" -> 0, "b" -> 1)
+
+ lazy val expectedMaps =
+ Seq(Map[String, ParameterValue]("a" -> 0, "b" -> 1))
+
+ (b2 aka "append" must not(throwA[Throwable])).
+ and(b2.params aka "parameters" must_== expectedMaps)
+ }
+ }
+
+ "be successful" in {
+ val b1 = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a}, b = {b}", List("a", "b")),
+ Seq(Seq[NamedParameter]("a" -> 0, "b" -> 1)))
+
+ lazy val b2 = b1.addBatch("a" -> 2, "b" -> 3)
+
+ lazy val expectedMaps = Seq(
+ Map[String, ParameterValue]("a" -> 0, "b" -> 1),
+ Map[String, ParameterValue]("a" -> 2, "b" -> 3))
+
+ (b2 aka "append" must not(throwA[Throwable])).
+ and(b2.params aka "parameters" must_== expectedMaps)
+ }
+ }
+
+ "Appending list of list of named parameters" should {
+ "fail with unexpected name" in {
+ val batch = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a}, b = {b}", List("a", "b")),
+ Seq(Seq[NamedParameter]("a" -> 1, "b" -> 2)))
+
+ batch.addBatchList(Seq(Seq("a" -> 0, "c" -> 4))).
+ aka("append all") must throwA[IllegalArgumentException](
+ message = "Unexpected parameter name: c != expected a, b")
+ }
+
+ "fail with missing names" in {
+ val batch = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a} AND b = {b} AND c = {c}",
+ List("a", "b", "c")),
+ Seq(Seq[NamedParameter]("a" -> 1, "b" -> 2, "c" -> 3)))
+
+ batch.addBatchList(Seq(Seq("a" -> 0))).
+ aka("append all") must throwA[IllegalArgumentException](
+ message = "Missing parameters: b, c")
+ }
+
+ "with first parameter map" >> {
+ "be successful" in {
+ val b1 = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a}, b = {b}", List("a", "b")))
+
+ lazy val b2 = b1.addBatchList(Seq(Seq("a" -> 0, "b" -> 1)))
+
+ lazy val expectedMaps =
+ Seq(Map[String, ParameterValue]("a" -> 0, "b" -> 1))
+
+ (b2 aka "append all" must not(throwA[Throwable])).
+ and(b2.params aka "parameters" must_== expectedMaps)
+ }
+
+ "fail with parameter maps not having same names" in {
+ val b1 = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a}", List("a")))
+
+ lazy val b2 = b1.addBatchList(Seq(
+ Seq("a" -> 0), Seq("a" -> 1, "b" -> 2)))
+
+ b2 aka "creation" must throwA[IllegalArgumentException](
+ message = "Unexpected parameter names: a, b != expected a")
+ }
+
+ "fail with names not matching query placeholders" in {
+ val b1 = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a} AND b = {b} AND c = {c}",
+ List("a", "b", "c")))
+
+ lazy val b2 = b1.addBatchList(Seq(Seq("a" -> 0)))
+
+ b2 aka "append" must throwA[IllegalArgumentException](
+ message = "Expected parameter names don't correspond to placeholders in query: a not matching a, b, c")
+ }
+
+ "be successful with parameter maps having same names" in {
+ val b1 = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a}, b = {b}", List("a", "b")))
+
+ lazy val b2 = b1.addBatchList(Seq(
+ Seq[NamedParameter]("a" -> 0, "b" -> -1),
+ Seq[NamedParameter]("a" -> 1, "b" -> 2)))
+
+ lazy val expectedMaps = Seq(
+ Map[String, ParameterValue]("a" -> 0, "b" -> -1),
+ Map[String, ParameterValue]("a" -> 1, "b" -> 2))
+
+ (b2 aka "creation" must not(throwA[IllegalArgumentException](
+ message = "Unexpected parameter names: a, b != expected a"))).
+ and(b2.params aka "parameters" must_== expectedMaps)
+ }
+ }
+
+ "be successful" in {
+ val b1 = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a}, b = {b}", List("a", "b")),
+ Seq(Seq("a" -> 0, "b" -> 1)))
+
+ lazy val b2 = b1.addBatchList(Seq(Seq("a" -> 2, "b" -> 3)))
+
+ lazy val expectedMaps = Seq(
+ Map[String, ParameterValue]("a" -> 0, "b" -> 1),
+ Map[String, ParameterValue]("a" -> 2, "b" -> 3))
+
+ (b2 aka "append all" must not(throwA[Throwable])).
+ and(b2.params aka "parameters" must_== expectedMaps)
+ }
+ }
+
+ "Appending list of parameter values" should {
+ "fail with missing names" in {
+ lazy val batch = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a} AND b = {b} AND c = {c}",
+ List("d", "b", "c")),
+ Seq(Seq[NamedParameter]("a" -> 1, "b" -> 2, "c" -> 3)))
+
+ batch.addBatchParams(0).
+ aka("append") must throwA[IllegalArgumentException](
+ message = "Expected parameter names don't correspond to placeholders in query: a, b, c not matching d, b, c")
+ }
+
+ "be successful with first parameter map" in {
+ val b1 = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a}, b = {b}", List("a", "b")))
+
+ lazy val b2 = b1.addBatchParams(0, 1)
+ lazy val expectedMaps =
+ Seq(Map[String, ParameterValue]("a" -> 0, "b" -> 1))
+
+ (b2 aka "append" must not(throwA[Throwable])).
+ and(b2.params aka "parameters" must_== expectedMaps)
+ }
+
+ "fail with missing argument" in {
+ val b1 = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a}, b = {b}", List("a", "b"))).
+ addBatchParams(0, 1)
+
+ lazy val b2 = b1.addBatchParams(2)
+
+ b2 aka "append" must throwA[IllegalArgumentException](
+ message = "Missing parameters: b")
+ }
+
+ "be successful" in {
+ val b1 = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a}, b = {b}", List("a", "b")))
+
+ lazy val b2 = b1.addBatchParams(0, 1).addBatchParams(2, 3)
+ lazy val expectedMaps = Seq(
+ Map[String, ParameterValue]("a" -> 0, "b" -> 1),
+ Map[String, ParameterValue]("a" -> 2, "b" -> 3))
+
+ (b2 aka "append" must not(throwA[Throwable])).
+ and(b2.params aka "parameters" must_== expectedMaps)
+ }
+ }
+
+ "Appending list of list of parameter values" should {
+ "fail with missing names" in {
+ lazy val batch = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a} AND b = {b} AND c = {c}",
+ List("d", "b", "c")),
+ Seq(Seq[NamedParameter]("a" -> 1, "b" -> 2, "c" -> 3)))
+
+ batch.addBatchParamsList(Seq(Seq(4, 5, 6))).
+ aka("append") must throwA[IllegalArgumentException](
+ message = "Expected parameter names don't correspond to placeholders in query: a, b, c not matching d, b, c")
+ }
+
+ "be successful with first parameter map" in {
+ val b1 = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a}, b = {b}", List("a", "b")))
+
+ lazy val b2 = b1.addBatchParamsList(Seq(Seq(0, 1), Seq(2, 3)))
+ lazy val expectedMaps = Seq(
+ Map[String, ParameterValue]("a" -> 0, "b" -> 1),
+ Map[String, ParameterValue]("a" -> 2, "b" -> 3))
+
+ (b2 aka "append" must not(throwA[Throwable])).
+ and(b2.params aka "parameters" must_== expectedMaps)
+ }
+
+ "fail with missing argument" in {
+ val b1 = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a}, b = {b}", List("a", "b"))).
+ addBatchParams(0, 1)
+
+ lazy val b2 = b1.addBatchParamsList(Seq(Seq(2)))
+
+ b2 aka "append" must throwA[IllegalArgumentException](
+ message = "Missing parameters: b")
+ }
+
+ "be successful" in {
+ val b1 = BatchSql(
+ SqlQuery("SELECT * FROM tbl WHERE a = {a}, b = {b}", List("a", "b")))
+
+ lazy val b2 = b1.addBatchParamsList(Seq(Seq(0, 1))).
+ addBatchParamsList(Seq(Seq(2, 3), Seq(4, 5)))
+
+ lazy val expectedMaps = Seq(
+ Map[String, ParameterValue]("a" -> 0, "b" -> 1),
+ Map[String, ParameterValue]("a" -> 2, "b" -> 3),
+ Map[String, ParameterValue]("a" -> 4, "b" -> 5))
+
+ (b2 aka "append" must not(throwA[Throwable])).
+ and(b2.params aka "parameters" must_== expectedMaps)
+ }
+ }
+}
View
6 framework/src/anorm/src/test/scala/anorm/StatementParserSpec.scala
@@ -21,12 +21,6 @@ object StatementParserSpec extends org.specs2.mutable.Specification {
SQL("SELECT name FROM t WHERE id = {id}").apply().
aka("query") must throwA[java.util.NoSuchElementException]
}
-
- "detect missing update parameter" in withQueryResult(stringList :+ "test") {
- implicit con =>
- SQL("EXEC proc {lang}, {c}").asBatch.addBatch("lang" -> "en").
- execute() aka "execute" must throwA[java.util.NoSuchElementException]
- }
}
"Value" should {

0 comments on commit f87ae8c

Please sign in to comment.