Skip to content

Commit

Permalink
Enumeratum support (#339)
Browse files Browse the repository at this point in the history
* New Enumeratum module
* Minor refactoring
  • Loading branch information
cchantep authored Mar 6, 2021
1 parent 66ba0e8 commit 0c4f9b2
Show file tree
Hide file tree
Showing 30 changed files with 936 additions and 50 deletions.
35 changes: 24 additions & 11 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,6 @@ import com.typesafe.tools.mima.plugin.MimaKeys.{
mimaBinaryIssueFilters, mimaPreviousArtifacts
}

ThisBuild / scalaVersion := "2.12.13"

ThisBuild / crossScalaVersions := Seq(
"2.11.12", (scalaVersion in ThisBuild).value, "2.13.4")

// Scalafix
inThisBuild(
List(
Expand Down Expand Up @@ -109,8 +104,17 @@ lazy val `anorm-core` = project.in(file("core"))
"-Xlog-free-terms",
"-P:silencer:globalFilters=missing\\ in\\ object\\ ToSql\\ is\\ deprecated;possibilities\\ in\\ class\\ ColumnNotFound\\ is\\ deprecated;DeprecatedSqlParser\\ in\\ package\\ anorm\\ is\\ deprecated;constructor\\ deprecatedName\\ in\\ class\\ deprecatedName\\ is\\ deprecated"
),
scalacOptions in Test ++= {
if (scalaBinaryVersion.value == "2.13") {
Seq(
"-Ypatmat-exhaust-depth", "off",
"-P:silencer:globalFilters=multiarg\\ infix\\ syntax")
} else {
Seq.empty
}
},
mimaPreviousArtifacts := {
if (scalaVersion.value startsWith "2.13") {
if (scalaBinaryVersion.value == "2.13") {
Set.empty
} else {
mimaPreviousArtifacts.value
Expand Down Expand Up @@ -190,10 +194,9 @@ lazy val `anorm-iteratee` = (project in file("iteratee"))
}).value,
publishTo := (Def.taskDyn {
val p = publishTo.value
val ver = scalaVersion.value

Def.task {
if (ver startsWith "2.13.") None
if (scalaBinaryVersion.value == "2.13") None
else p
}
}).value,
Expand Down Expand Up @@ -228,7 +231,8 @@ lazy val `anorm-akka` = (project in file("akka"))
"com.typesafe.akka" %% m % akkaVer.value % Provided
},
libraryDependencies ++= (acolyte +: specs2Test) ++ Seq(
"com.typesafe.akka" %% "akka-stream-contrib" % akkaContribVer.value % Test)
"com.typesafe.akka" %% "akka-stream-contrib" % akkaContribVer.value % Test),
scalacOptions += "-P:silencer:globalFilters=deprecated"
).dependsOn(`anorm-core`)

// ---
Expand All @@ -255,7 +259,16 @@ lazy val `anorm-postgres` = (project in file("postgres"))
"com.typesafe.play" %% "play-json" % playJsonVer
) ++ specs2Test :+ acolyte
}
).dependsOn(`anorm-core`)
).dependsOn(`anorm-core`)

lazy val `anorm-enumeratum` = (project in file("enumeratum"))
.settings(
scalariformAutoformat := true,
mimaPreviousArtifacts := Set.empty,
libraryDependencies ++= Seq(
"com.beachape" %% "enumeratum" % "1.6.1",
acolyte) ++ specs2Test
).dependsOn(`anorm-core`)

// ---

Expand All @@ -264,7 +277,7 @@ lazy val `anorm-parent` = (project in file("."))
.aggregate(
`anorm-tokenizer`, `anorm-core`,
`anorm-iteratee`, `anorm-akka`,
`anorm-postgres`)
`anorm-postgres`, `anorm-enumeratum`)
.settings(
mimaPreviousArtifacts := Set.empty)

Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/anorm/MetaData.scala
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ object ColumnAliaser {
* import anorm.{ ColumnAliaser, ColumnName }
*
* ColumnAliaser({
* case (1, cn) => "my_id"
* case (1, _) => "my_id"
* case (_, ColumnName(".foo", _)) => "prefix.foo"
* })
* }}}
Expand Down
14 changes: 7 additions & 7 deletions core/src/main/scala/anorm/ToStatementMisc.scala
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ sealed trait ToStatementPriority0 {
* Sets double value on statement.
*
* {{{
* anorm.SQL("SELECT * FROM Test WHERE flag = {b}").on('b -> 1d)
* anorm.SQL("SELECT * FROM Test WHERE flag = {b}").on('b -> 1D)
* }}}
*/
implicit object doubleToStatement extends ToStatement[Double] {
Expand All @@ -158,7 +158,7 @@ sealed trait ToStatementPriority0 {
*
* {{{
* anorm.SQL("SELECT * FROM Test WHERE flag = {b}").
* on('b -> new java.lang.Double(1d))
* on('b -> new java.lang.Double(1D))
* }}}
*/
implicit object javaDoubleToStatement extends ToStatement[JDouble] {
Expand All @@ -171,7 +171,7 @@ sealed trait ToStatementPriority0 {
* Sets float value on statement.
*
* {{{
* anorm.SQL("SELECT * FROM Test WHERE flag = {b}").on('b -> 1f)
* anorm.SQL("SELECT * FROM Test WHERE flag = {b}").on('b -> 1F)
* }}}
*/
implicit object floatToStatement extends ToStatement[Float] {
Expand All @@ -184,7 +184,7 @@ sealed trait ToStatementPriority0 {
*
* {{{
* anorm.SQL("SELECT * FROM Test WHERE flag = {b}").
* on('b -> new java.lang.Float(1f))
* on('b -> new java.lang.Float(1F))
* }}}
*/
implicit object javaFloatToStatement extends ToStatement[JFloat] {
Expand All @@ -197,7 +197,7 @@ sealed trait ToStatementPriority0 {
* Sets long value on statement.
*
* {{{
* anorm.SQL("SELECT * FROM Test WHERE flag = {b}").on('b -> 1l)
* anorm.SQL("SELECT * FROM Test WHERE flag = {b}").on('b -> 1L)
* }}}
*/
implicit object longToStatement extends ToStatement[Long] {
Expand All @@ -210,7 +210,7 @@ sealed trait ToStatementPriority0 {
*
* {{{
* anorm.SQL("SELECT * FROM Test WHERE flag = {b}").
* on('b -> new java.lang.Long(1l))
* on('b -> new java.lang.Long(1L))
* }}}
*/
implicit object javaLongToStatement extends ToStatement[JLong] {
Expand Down Expand Up @@ -395,7 +395,7 @@ sealed trait ToStatementPriority0 {
*
* {{{
* anorm.SQL("UPDATE tbl SET max = {m}").
* on('m -> new java.math.BigDecimal(10.02f))
* on('m -> new java.math.BigDecimal(10.02F))
* }}}
*/
implicit object javaBigDecimalToStatement extends ToStatement[JBigDec] {
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/anorm/macros/Inspect.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ private[anorm] object Inspect {
import c.universe._

val tpeArgs: List[c.Type] = tpe match {
case SingleType(_, _) => List.empty
case TypeRef(_, _, args) => args
case i @ ClassInfoType(_, _, _) => i.typeArgs
case _ => List.empty
}

val companion = tpe.typeSymbol.companion.typeSignature
Expand Down
20 changes: 17 additions & 3 deletions core/src/main/scala/anorm/macros/RowParserImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ private[anorm] object RowParserImpl {
case ((xa, ma, bs, ia, sr), pss) =>
val (xb, mb, vs, ib, selfRef) =
pss.foldLeft((xa, ma, List.empty[Tree], ia, sr)) {
case ((xtr, mp, ps, pi, sref), term: TermSymbol) =>
case ((xtr, mp, ps, pi, sref), term: TermSymbol) => {
val tn = term.name.toString
val tt = {
val t = term.typeSignature
Expand All @@ -57,7 +57,7 @@ private[anorm] object RowParserImpl {
case Implicit(_, _, pr, _, s) => {
// Use an existing `RowParser[T]` as part
pq"${term.name}" match {
case b @ Bind(bn, _) =>
case b @ Bind(bn, _) => {
val bt = q"${bn.toTermName}"

xtr match {
Expand All @@ -68,6 +68,10 @@ private[anorm] object RowParserImpl {
pq"anorm.~($mp, $b)", bt :: ps, pi + 1, s || sref)

}
}

case _ =>
abort(s"unsupported $colTpe nor $parserTpe for ${term.name}:$tt in $ctor")
}
}
}
Expand All @@ -77,7 +81,7 @@ private[anorm] object RowParserImpl {
val get = genGet(tt, tn, pi)

pq"${term.name}" match {
case b @ Bind(bn, _) =>
case b @ Bind(bn, _) => {
val bt = q"${bn.toTermName}"

xtr match {
Expand All @@ -88,9 +92,19 @@ private[anorm] object RowParserImpl {
pq"anorm.~($mp, $b)", bt :: ps, pi + 1, sref)

}
}

case _ =>
abort(s"unsupported $colTpe nor $parserTpe for ${term.name}:$tt: ${show(itree)}")
}
}
}
}

case (state, sym) => {
c.warning(c.enclosingPosition, s"unexpected symbol: $sym")
state
}
}

val by = bs match {
Expand Down
3 changes: 3 additions & 0 deletions core/src/main/scala/anorm/macros/ValueToStatementImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ private[anorm] object ValueToStatement {
}
}
}

case _ =>
abort(s"cannot supported ${show(ctor)} for ${tpe}")
}
}
}
2 changes: 1 addition & 1 deletion core/src/main/scala/anorm/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ package object anorm {
val groups = ((gs match {
case TokenGroup(List(StringToken("")), None) :: tgs => tgs // trim end
case _ => gs
}) map {
}).collect {
case TokenGroup(pr, pl) => TokenGroup(pr.reverse, pl)
}).reverse

Expand Down
52 changes: 33 additions & 19 deletions core/src/test/scala/anorm/AnormSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,8 @@ final class AnormSpec extends Specification with H2Database with AnormTest {
"Aggregation over all rows" should {
"be empty when there is no result" in withQueryResult(QueryResult.Nil) {
implicit c =>
SQL"EXEC test".fold[Option[Int]](None)({ (_, _) => Some(0) }).
SQL"EXEC test".fold[Option[Int]](None, ColumnAliaser.empty)(
{ (_, _) => Some(0) }).
aka("aggregated value") must beRight(Option.empty[Int])

}
Expand All @@ -324,17 +325,20 @@ final class AnormSpec extends Specification with H2Database with AnormTest {
rowList2(classOf[String] -> "foo", classOf[Int] -> "bar").
append("row1", 100) :+ ("row2", 200)) { implicit c =>

SQL"SELECT * FROM test".fold(List[(String, Int)]())(
{ (l, row) => l :+ (row[String]("foo") -> row[Int]("bar")) }).
aka("tuple stream") must_=== Right(List("row1" -> 100, "row2" -> 200))
SQL"SELECT * FROM test".fold(
List.empty[(String, Int)], ColumnAliaser.empty)(
{ (l, row) => l :+ (row[String]("foo") -> row[Int]("bar")) }).
aka("tuple stream") must_=== Right(List("row1" -> 100, "row2" -> 200))

}

"handle failure" in withQueryResult(
rowList1(classOf[String] -> "foo") :+ "A" :+ "B") { implicit c =>
var i = 0
SQL"SELECT str".fold(Set[String]()) { (l, row) =>
if (i == 0) { i = i + 1; l + row[String]("foo") } else sys.error("Failure")

SQL"SELECT str".fold(Set.empty[String], ColumnAliaser.empty) {
(l, row) =>
if (i == 0) { i = i + 1; l + row[String]("foo") } else sys.error("Failure")

} aka "aggregate on failure" must beLike {
case Left(err :: Nil) => err.getMessage aka "failure" must_=== "Failure"
Expand All @@ -355,31 +359,36 @@ final class AnormSpec extends Specification with H2Database with AnormTest {
rowList2(classOf[String] -> "foo", classOf[Int] -> "bar").
append("row1", 100) :+ ("row2", 200)) { implicit c =>

SQL"SELECT * FROM test".foldWhile(List[(String, Int)]())({ (l, row) =>
(l :+ (row[String]("foo") -> row[Int]("bar"))) -> true
}) aka "tuple stream" must_=== Right(List("row1" -> 100, "row2" -> 200))
SQL"SELECT * FROM test".foldWhile(
List.empty[(String, Int)], ColumnAliaser.empty)({ (l, row) =>
(l :+ (row[String]("foo") -> row[Int]("bar"))) -> true
}) aka "tuple stream" must_=== Right(List("row1" -> 100, "row2" -> 200))
}

"handle failure" in withQueryResult(
rowList1(classOf[String] -> "foo") :+ "A" :+ "B") { implicit c =>
var i = 0
SQL"SELECT str".foldWhile(Set[String]()) { (l, row) =>
if (i == 0) { i = i + 1; (l + row[String]("foo")) -> true }
else sys.error("Failure")

} aka "aggregate on failure" must beLike {
case Left(err :: Nil) => err.getMessage aka "failure" must_=== "Failure"
} and (i aka "row count" must_=== 1)
SQL"SELECT str".foldWhile(
Set.empty[String], ColumnAliaser.empty) { (l, row) =>
if (i == 0) { i = i + 1; (l + row[String]("foo")) -> true }
else sys.error("Failure")

} aka "aggregate on failure" must beLike {
case Left(err :: Nil) => err.getMessage aka "failure" must_=== "Failure"
} and (i aka "row count" must_=== 1)
}

"stop after first row" in withQueryResult(
rowList1(classOf[String] -> "foo") :+ "A" :+ "B") { implicit c =>
var i = 0
SQL"SELECT str".foldWhile(Set[String]()) { (l, row) =>
if (i == 0) { i = i + 1; (l + row[String]("foo")) -> true }
else (l, false)

} aka "partial aggregate" must_=== Right(Set("A"))
SQL"SELECT str".foldWhile(
Set.empty[String], ColumnAliaser.empty) { (l, row) =>
if (i == 0) { i = i + 1; (l + row[String]("foo")) -> true }
else (l, false)

} aka "partial aggregate" must_=== Right(Set("A"))
}
}

Expand Down Expand Up @@ -456,11 +465,16 @@ final class AnormSpec extends Specification with H2Database with AnormTest {
"Insertion" should {
def con = connection(handleStatement withUpdateHandler {
case UpdateExecution("INSERT ?", ExecutedParameter(1) :: Nil) => 1

case UpdateExecution("INSERT ?", ExecutedParameter(2) :: Nil) =>
updateResult(2, longList :+ 3L)

case UpdateExecution("INSERT ?", ExecutedParameter(3) :: Nil) =>
updateResult(3, stringList :+ "generated")

case exec =>
sys.error(s"Unexpected execution: $exec")

})

"return no generated key" in {
Expand Down
2 changes: 1 addition & 1 deletion core/src/test/scala/anorm/ColumnSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import java.math.BigInteger
import java.net.{ URI, URL }

import java.sql.{ Array => SqlArray }
import javax.sql.rowset.serial.{ SerialBlob, SerialClob }
import java.time.LocalDateTime
import javax.sql.rowset.serial.{ SerialBlob, SerialClob }

import scala.util.Random

Expand Down
4 changes: 4 additions & 0 deletions core/src/test/scala/anorm/JavaTimeSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,10 @@ object JavaTimeParameterSpec extends Specification {
DParam(t: java.sql.Timestamp, SqlTimestamp) :: Nil) if t.getTime == 123456789000L => 1 /* case ok */
case UpdateExecution("set-null-zoned-date-time ?",
DParam(null, SqlTimestamp) :: Nil) => 1 /* case ok */

case exec =>
sys.error(s"Unexpected execution: $exec")

}, ps: _*))

"Java time named parameters" should {
Expand Down
5 changes: 3 additions & 2 deletions core/src/test/scala/anorm/ParameterSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -714,8 +714,9 @@ val params: Seq[NamedParameter] = Seq("mod" -> d, "id" -> "idv")

"accept value wrapped as opaque parameter object" in withConnection() {
implicit c =>
SQL("set-date {d}").on(Symbol("d") -> anorm.Object(new java.util.Date())).
execute aka "execution" must throwA[SQLFeatureNotSupportedException](
SQL("set-date {d}").on(
Symbol("d") -> anorm.Object(new java.util.Date())).
execute() must throwA[SQLFeatureNotSupportedException](
message = "Unsupported parameter type: java.util.Date")

}
Expand Down
Loading

0 comments on commit 0c4f9b2

Please sign in to comment.