Skip to content

Commit

Permalink
Merge branch 'master' into enum-withname-either
Browse files Browse the repository at this point in the history
  • Loading branch information
lloydmeta committed Dec 30, 2019
2 parents 1219b79 + ed45b0e commit 06ad65a
Show file tree
Hide file tree
Showing 20 changed files with 344 additions and 207 deletions.
146 changes: 135 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Integrations are available for:
- [Play](https://www.playframework.com/): JVM only
- [Play JSON](https://www.playframework.com/documentation/2.5.x/ScalaJson): JVM (included in Play integration but also available separately) and ScalaJS
- [Circe](https://github.com/travisbrown/circe): JVM and ScalaJS
- [ReactiveMongo BSON](http://reactivemongo.org/releases/0.11/documentation/bson/overview.html): JVM only
- [ReactiveMongo BSON](http://reactivemongo.org/releases/0.1x/documentation/bson/overview.html): JVM only
- [Argonaut](http://argonaut.io): JVM and ScalaJS
- [Json4s](http://json4s.org): JVM only
- [ScalaCheck](https://www.scalacheck.org): JVM and ScalaJS
Expand All @@ -38,13 +38,13 @@ Integrations are available for:
### Table of Contents

1. [Quick start](#quick-start)
- [SBT](#sbt)
- [Usage](#usage)
- [SBT](#sbt)
- [Usage](#usage)
2. [More examples](#more-examples)
- [Enum](#enum)
- [Manual override of name](#manual-override-of-name)
- [Mixins to override the name](#mixins-to-override-the-name)
- [ValueEnum](#valueenum)
- [Enum](#enum)
- [Manual override of name](#manual-override-of-name)
- [Mixins to override the name](#mixins-to-override-the-name)
- [ValueEnum](#valueenum)
3. [ScalaJS](#scalajs)
4. [Play integration](#play-integration)
5. [Play JSON integration](#play-json)
Expand Down Expand Up @@ -245,7 +245,7 @@ import enumeratum.values._

sealed abstract class LibraryItem(val value: Int, val name: String) extends IntEnumEntry

case object LibraryItem extends IntEnum[LibraryItem] {
object LibraryItem extends IntEnum[LibraryItem] {


case object Book extends LibraryItem(value = 1, name = "book")
Expand All @@ -268,6 +268,32 @@ assert(LibraryItem.withValue(1) == LibraryItem.Book)
LibraryItem.withValue(10) // => java.util.NoSuchElementException:
```

If you want to allow aliases in your enumeration, i.e. multiple entries that share the same value, you can extend the
`enumeratum.values.AllowAlias` trait:

```scala
import enumeratum.values._

sealed abstract class Judgement(val value: Int) extends IntEnumEntry with AllowAlias

object Judgement extends IntEnum[Judgement] {

case object Good extends Judgement(1)
case object OK extends Judgement(2)
case object Meh extends Judgement(2)
case object Bad extends Judgement(3)

val values = findValues

}
```

Calling `withValue` with an aliased value will return one of the corresponding entries. Which one it returns is undefined:

```scala
assert(Judgement.withValue(2) == Judgement.OK || Judgement.withValue(2) == Judgement.Meh)
```

**Restrictions**
- `ValueEnum`s must have their value members implemented as literal values.

Expand Down Expand Up @@ -636,16 +662,16 @@ case object BsonDrinks extends ShortEnum[BsonDrinks] with ShortReactiveMongoBson

}

import reactivemongo.bson._
import reactivemongo.api.bson._

// Use to deserialise numbers to enum members directly
BsonDrinks.values.foreach { drink =>
val writer = implicitly[BSONWriter[BsonDrinks, BSONValue]]
val writer = implicitly[BSONWriter[BsonDrinks]]

assert(writer.write(drink) == BSONInteger(drink.value))
}

val reader = implicitly[BSONReader[BSONValue, BsonDrinks]]
val reader = implicitly[BSONReader[BsonDrinks]]

assert(reader.read(BSONInteger(3)) == BsonDrinks.Cola)
```
Expand Down Expand Up @@ -1106,6 +1132,104 @@ libraryDependencies ++= Seq(
)
```

### Usage

#### Enum

```scala
import enumeratum._

sealed trait ShirtSize extends EnumEntry

case object ShirtSize extends Enum[ShirtSize] with DoobieEnum[ShirtSize] {

case object Small extends ShirtSize
case object Medium extends ShirtSize
case object Large extends ShirtSize

val values = findValues

}

case class Shirt(size: ShirtSize)

import doobie._
import doobie.implicits._
import doobie.util.ExecutionContexts
import cats.effect._

implicit val cs = IO.contextShift(ExecutionContexts.synchronous)

val xa = Transactor.fromDriverManager[IO](
"org.postgresql.Driver",
"jdbc:postgresql:world",
"postgres",
"",
Blocker.liftExecutionContext(ExecutionContexts.synchronous)
)

sql"insert into clothes (shirt) values (${Shirt(ShirtSize.Small)})".update.run
.transact(xa)
.unsafeRunSync

sql"select shirt from clothes"
.query[Shirt]
.to[List]
.transact(xa)
.unsafeRunSync
.take(5)
.foreach(println)
```
- Note that a type ascription to the `EnumEntry` trait (eg. `ShirtSize.Small: ShirtSize`) is required when binding hardcoded `EnumEntry`s

#### ValueEnum

```scala
import enumeratum.values.{ IntDoobieEnum, IntEnum, IntEnumEntry }

sealed abstract class ShirtSize(val value: Int) extends IntEnumEntry

case object ShirtSize extends IntEnum[ShirtSize] with IntDoobieEnum[ShirtSize] {

case object Small extends ShirtSize(1)
case object Medium extends ShirtSize(2)
case object Large extends ShirtSize(3)

val values = findValues

}

case class Shirt(size: ShirtSize)

import doobie._
import doobie.implicits._
import doobie.util.ExecutionContexts
import cats.effect._

implicit val cs = IO.contextShift(ExecutionContexts.synchronous)

val xa = Transactor.fromDriverManager[IO](
"org.postgresql.Driver",
"jdbc:postgresql:world",
"postgres",
"",
Blocker.liftExecutionContext(ExecutionContexts.synchronous)
)

sql"insert into clothes (shirt) values (${Shirt(ShirtSize.Small)})".update.run
.transact(xa)
.unsafeRunSync

sql"select shirt from clothes"
.query[Shirt]
.to[List]
.transact(xa)
.unsafeRunSync
.take(5)
.foreach(println)
```
- Note that a type ascription to the `ValueEnumEntry` abstract class (eg. `ShirtSize.Small: ShirtSize`) is required when binding hardcoded `ValueEnumEntry`s

## Benchmarking

Benchmarking is in the unpublished `benchmarking` project. It uses JMH and you can run them in the sbt console by issuing the following command from your command line:
Expand Down
45 changes: 31 additions & 14 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import com.typesafe.sbt.SbtGit.{GitKeys => git}
import sbtcrossproject.CrossPlugin.autoImport.{crossProject, CrossType}
import sbtbuildinfo.BuildInfoPlugin.autoImport._
import sbtcrossproject.CrossPlugin.autoImport.{CrossType, crossProject}

lazy val theScalaVersion = "2.12.8"

Expand All @@ -10,18 +10,25 @@ lazy val theScalaVersion = "2.12.8"
*/
lazy val scalaVersions = Seq(theScalaVersion, "2.10.7", "2.11.12")
lazy val scalaVersionsAbove_2_11 = Seq("2.11.12", "2.12.8")
lazy val scala_2_13Version = "2.13.0"
lazy val scala_2_13Version = "2.13.1"
lazy val scalaVersionsAll = scalaVersions :+ scala_2_13Version

lazy val scalaTestVersion = "3.0.8"
lazy val scalacheckVersion = "1.14.0"

// Library versions
lazy val reactiveMongoVersion = "0.18.6"
lazy val reactiveMongoVersion = "0.19.4"
lazy val argonautVersion = "6.2.3"
lazy val json4sVersion = "3.6.6"
lazy val quillVersion = "3.2.1"
lazy val doobieVersion = "0.7.0"
lazy val quillVersion = "3.5.0"

def theDoobieVersion(scalaVersion: String) =
CrossVersion.partialVersion(scalaVersion) match {
case Some((2, scalaMajor)) if scalaMajor >= 12 => "0.8.8"
case Some((2, scalaMajor)) if scalaMajor <= 11 => "0.7.0"
case _ =>
throw new IllegalArgumentException(s"Unsupported Scala version $scalaVersion")
}

def theArgonautVersion(scalaVersion: String) =
CrossVersion.partialVersion(scalaVersion) match {
Expand Down Expand Up @@ -110,7 +117,9 @@ lazy val scala213ProjectRefs = Seq(
enumeratumCirceJs,
enumeratumReactiveMongoBson,
enumeratumCatsJvm,
enumeratumCatsJs
enumeratumCatsJs,
enumeratumQuillJvm,
enumeratumQuillJs
).map(Project.projectToRef)

lazy val scala_2_13 = Project(id = "scala_2_13", base = file("scala_2_13"))
Expand Down Expand Up @@ -251,8 +260,8 @@ lazy val enumeratumReactiveMongoBson =
.settings(commonWithPublishSettings: _*)
.settings(testSettings: _*)
.settings(
version := "1.5.15-SNAPSHOT",
crossScalaVersions := scalaVersionsAll,
version := "1.5.16-SNAPSHOT",
crossScalaVersions := scalaVersionsAbove_2_11 :+ scala_2_13Version,
libraryDependencies ++= Seq(
"org.reactivemongo" %% "reactivemongo" % reactiveMongoVersion,
"com.beachape" %% "enumeratum" % Versions.Core.stable,
Expand Down Expand Up @@ -400,7 +409,7 @@ lazy val enumeratumScalacheckJs = enumeratumScalacheck.js
lazy val enumeratumScalacheckJvm = enumeratumScalacheck.jvm

lazy val quillAggregate = aggregateProject("quill", enumeratumQuillJs, enumeratumQuillJvm).settings(
crossScalaVersions := post210Only(crossScalaVersions.value)
crossScalaVersions := post210Only(scalaVersionsAbove_2_11 :+ scala_2_13Version)
)
lazy val enumeratumQuill = crossProject(JSPlatform, JVMPlatform)
.crossType(CrossType.Pure)
Expand All @@ -409,14 +418,22 @@ lazy val enumeratumQuill = crossProject(JSPlatform, JVMPlatform)
.settings(testSettings: _*)
.settings(
name := "enumeratum-quill",
version := "1.5.15-SNAPSHOT",
crossScalaVersions := post210Only(crossScalaVersions.value),
version := "1.5.16-SNAPSHOT",
crossScalaVersions := post210Only(scalaVersionsAbove_2_11 :+ scala_2_13Version),
libraryDependencies ++= {
Seq(
"com.beachape" %%% "enumeratum" % Versions.Core.stable,
"io.getquill" %%% "quill-core" % quillVersion,
"io.getquill" %%% "quill-sql" % quillVersion % Test
)
},
dependencyOverrides ++= {
def pprintVersion(v: String) = {
if (v.startsWith("2.11")) "0.5.4" else "0.5.5"
}
Seq(
"com.lihaoyi" %%% "pprint" % pprintVersion(scalaVersion.value)
)
}
)
lazy val enumeratumQuillJs = enumeratumQuill.js
Expand All @@ -427,12 +444,12 @@ lazy val enumeratumDoobie =
.settings(commonWithPublishSettings: _*)
.settings(testSettings: _*)
.settings(
crossScalaVersions := scalaVersionsAbove_2_11,
version := "1.5.16-SNAPSHOT",
crossScalaVersions := scalaVersionsAbove_2_11 :+ scala_2_13Version,
version := "1.5.18-SNAPSHOT",
libraryDependencies ++= {
Seq(
"com.beachape" %%% "enumeratum" % Versions.Core.stable,
"org.tpolecat" %% "doobie-core" % doobieVersion
"org.tpolecat" %% "doobie-core" % theDoobieVersion(scalaVersion.value)
)
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,23 @@ class ValueEnumSpec extends FunSpec with Matchers with ValueEnumHelpers {
""" shouldNot compile
}

it("should compile even when values are repeated if AllowAlias is extended") {
"""
sealed abstract class ContentTypeRepeated(val value: Long, name: String) extends LongEnumEntry with AllowAlias
case object ContentTypeRepeated extends LongEnum[ContentTypeRepeated] {
case object Text extends ContentTypeRepeated(value = 1L, name = "text")
case object Image extends ContentTypeRepeated(value = 2L, name = "image")
case object Video extends ContentTypeRepeated(value = 2L, name = "video")
case object Audio extends ContentTypeRepeated(value = 4L, name = "audio")
val values = findValues
}
""" should (compile)
}

it("should fail to compile when there are non literal values") {
"""
sealed abstract class ContentTypeRepeated(val value: Long, name: String) extends LongEnumEntry
Expand Down
1 change: 1 addition & 0 deletions enumeratum-doobie/src/main/scala/enumeratum/Doobie.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package enumeratum

import doobie.util._
import doobie.Meta

object Doobie {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package enumeratum

import doobie.util._
import doobie.Meta

/**
* Helper trait that adds implicit Doobie Get and Put for an [[Enum]]'s members
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package enumeratum.values

import doobie.util._
import doobie.Meta

object Doobie {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package enumeratum.values

import doobie.util._
import doobie.Meta

sealed trait DoobieValueEnum[ValueType, EntryType <: ValueEnumEntry[ValueType], DoobieType] {
this: ValueEnum[ValueType, EntryType] =>
Expand Down
Loading

0 comments on commit 06ad65a

Please sign in to comment.