Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add enumeratum-quill #170

Merged
merged 8 commits into from
Feb 13, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 83 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Integrations are available for:
- [Argonaut](http://argonaut.io): JVM and ScalaJS
- [Json4s](http://json4s.org): JVM only
- [ScalaCheck](https://www.scalacheck.org): JVM only
- [Quill](http://getquill.io): JVM and ScalaJS

### Table of Contents

Expand All @@ -54,8 +55,9 @@ Integrations are available for:
10. [Json4s integration](#json4s)
11. [Slick integration](#slick-integration)
12. [ScalaCheck](#scalacheck)
13. [Benchmarking](#benchmarking)
14. [Publishing](#publishing)
13. [Quill integration](#quill)
14. [Benchmarking](#benchmarking)
15. [Publishing](#publishing)


## Quick start
Expand Down Expand Up @@ -848,6 +850,85 @@ Similarly, you can get `Arbitrary` and `Cogen` instances for every `ValueEnum` s
import enumeratum.values.scalacheck._
```

## Quill
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.beachape/enumeratum-quill_2.11/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.beachape/enumeratum-quill_2.11)

### SBT

To use enumeratum with [Quill](http://getquill.io):

```scala
libraryDependencies ++= Seq(
"com.beachape" %% "enumeratum-quill" % enumeratumQuillVersion
)
```

To use with ScalaJS:

```scala
libraryDependencies ++= Seq(
"com.beachape" %%% "enumeratum-quill" % enumeratumQuillVersion
)
```

### Usage

#### Enum

```scala
import enumeratum._

sealed trait ShirtSize extends EnumEntry

case object ShirtSize extends Enum[ShirtSize] with QuillEnum[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 io.getquill._

val ctx = new SqlMirrorContext(MirrorSqlDialect, Literal)
import ctx._

val sql = ctx.run(query[Shirt].insert(_.size -> lift(ShirtSize.Small: ShirtSize))).string
assert(sql == "INSERT INTO Shirt (size) VALUES (?)")
```

#### ValueEnum

```scala
import enumeratum._

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

case object ShirtSize extends IntEnum[ShirtSize] with IntQuillEnum[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 io.getquill._

val ctx = new SqlMirrorContext(MirrorSqlDialect, Literal)
import ctx._

val sql = ctx.run(query[Shirt].insert(_.size -> lift(ShirtSize.Small: ShirtSize))).string
assert(sql == "INSERT INTO Shirt (size) VALUES (?)")
```

## Slick integration

[Slick](http://slick.lightbend.com) doesn't have a separate integration at the moment. You just have to provide a `MappedColumnType` for each database column that should be represented as an enum on the Scala side.
Expand Down
28 changes: 28 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ lazy val circeVersion = "0.9.0"
lazy val uPickleVersion = "0.4.4"
lazy val argonautVersion = "6.2"
lazy val json4sVersion = "3.5.1"
lazy val quillVersion = "2.3.2"

def thePlayVersion(scalaVersion: String) =
CrossVersion.partialVersion(scalaVersion) match {
Expand Down Expand Up @@ -301,6 +302,33 @@ lazy val enumeratumScalacheck =
)
)

lazy val quillAggregate = aggregateProject("quill", enumeratumQuillJs, enumeratumQuillJvm)
lazy val enumeratumQuill = crossProject
.crossType(CrossType.Pure)
.in(file("enumeratum-quill"))
.settings(commonWithPublishSettings: _*)
.settings(testSettings: _*)
.settings(
name := "enumeratum-quill",
version := "0.1.0-SNAPSHOT",
libraryDependencies ++= {
import org.scalajs.sbtplugin._
val cross = {
if (ScalaJSPlugin.autoImport.jsDependencies.?.value.isDefined)
ScalaJSCrossVersion.binary
else
CrossVersion.binary
}
Seq(
impl.ScalaJSGroupID.withCross("io.getquill", "quill-core", cross) % quillVersion,
impl.ScalaJSGroupID.withCross("io.getquill", "quill-sql", cross) % quillVersion % Test,
impl.ScalaJSGroupID.withCross("com.beachape", "enumeratum", cross) % Versions.Core.stable
)
}
)
lazy val enumeratumQuillJs = enumeratumQuill.js
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL: Quill works with ScalaJS O_o

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha I was shocked as well

lazy val enumeratumQuillJvm = enumeratumQuill.jvm

lazy val commonSettings = Seq(
organization := "com.beachape",
scalafmtOnCompile := true,
Expand Down
15 changes: 15 additions & 0 deletions enumeratum-quill/src/main/scala/enumeratum/Quill.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package enumeratum

import io.getquill.MappedEncoding

object Quill {
/**
* Returns an Encoder for the given enum
*/
def encoder[A <: EnumEntry](enum: Enum[A]): MappedEncoding[A, String] = MappedEncoding(_.entryName)

/**
* Returns a Decoder for the given enum
*/
def decoder[A <: EnumEntry](enum: Enum[A]): MappedEncoding[String, A] = MappedEncoding(enum.withName)
}
45 changes: 45 additions & 0 deletions enumeratum-quill/src/main/scala/enumeratum/QuillEnum.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package enumeratum

import io.getquill.MappedEncoding

/**
* Helper trait that adds implicit Quill encoders and decoders for an [[Enum]]'s members
*
* Example:
*
* {{{
* scala> import enumeratum._
* scala> import io.getquill._
*
* scala> sealed trait ShirtSize extends EnumEntry
* scala> case object ShirtSize extends Enum[ShirtSize] with QuillEnum[ShirtSize] {
* | case object Small extends ShirtSize
* | case object Medium extends ShirtSize
* | case object Large extends ShirtSize
* | val values = findValues
* | }
*
* scala> case class Shirt(size: ShirtSize)
*
* scala> val ctx = new SqlMirrorContext(MirrorSqlDialect, Literal)
* scala> import ctx._
*
* scala> val size: ShirtSize = ShirtSize.Small
*
* scala> ctx.run(query[Shirt].insert(_.size -> lift(size))).string
* res0: String = INSERT INTO Shirt (size) VALUES (?)
* }}}
*/
trait QuillEnum[A <: EnumEntry] { this: Enum[A] =>

/**
* Implicit Encoder for this enum
*/
implicit lazy val enumEncoder: MappedEncoding[A, String] = Quill.encoder(this)

/**
* Implicit Decoder for this enum
*/
implicit lazy val enumDecoder: MappedEncoding[String, A] = Quill.decoder(this)

}
20 changes: 20 additions & 0 deletions enumeratum-quill/src/main/scala/enumeratum/values/Quill.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package enumeratum.values

import io.getquill.MappedEncoding

object Quill {

/**
* Returns an Encoder for the provided ValueEnum
*/
def encoder[ValueType, EntryType <: ValueEnumEntry[ValueType]](
enum: ValueEnum[ValueType, EntryType]
): MappedEncoding[EntryType, ValueType] = MappedEncoding(_.value)

/**
* Returns a Decoder for the provided ValueEnum
*/
def decoder[ValueType, EntryType <: ValueEnumEntry[ValueType]](
enum: ValueEnum[ValueType, EntryType]
): MappedEncoding[ValueType, EntryType] = MappedEncoding(enum.withValue)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package enumeratum.values

import io.getquill.MappedEncoding

sealed trait QuillValueEnum[ValueType, EntryType <: ValueEnumEntry[ValueType]] {
this: ValueEnum[ValueType, EntryType] =>

/**
* Implicit Encoder for this enum
*/
implicit val quillEncoder: MappedEncoding[EntryType, ValueType] = Quill.encoder(this)

/**
* Implicit Decoder for this enum
*/
implicit val quillDecoder: MappedEncoding[ValueType, EntryType] = Quill.decoder(this)
}

/**
* QuillEnum for IntEnumEntry
*
* {{{
* scala> import enumeratum.values._
* scala> import io.getquill._
*
* scala> sealed abstract class ShirtSize(val value:Int) extends IntEnumEntry
* scala> case object ShirtSize extends IntEnum[ShirtSize] with IntQuillEnum[ShirtSize] {
* | case object Small extends ShirtSize(1)
* | case object Medium extends ShirtSize(2)
* | case object Large extends ShirtSize(3)
* | val values = findValues
* | }
*
* scala> case class Shirt(size: ShirtSize)
*
* scala> val ctx = new SqlMirrorContext(MirrorSqlDialect, Literal)
* scala> import ctx._
*
* scala> val size: ShirtSize = ShirtSize.Small
*
* scala> ctx.run(query[Shirt].insert(_.size -> lift(size))).string
* res0: String = INSERT INTO Shirt (size) VALUES (?)
* }}}
*/
trait IntQuillEnum[EntryType <: IntEnumEntry] extends QuillValueEnum[Int, EntryType] {
this: ValueEnum[Int, EntryType] =>
}

/**
* QuillEnum for LongEnumEntry
*/
trait LongQuillEnum[EntryType <: LongEnumEntry] extends QuillValueEnum[Long, EntryType] {
this: ValueEnum[Long, EntryType] =>
}

/**
* QuillEnum for ShortEnumEntry
*/
trait ShortQuillEnum[EntryType <: ShortEnumEntry] extends QuillValueEnum[Short, EntryType] {
this: ValueEnum[Short, EntryType] =>
}

/**
* QuillEnum for StringEnumEntry
*/
trait StringQuillEnum[EntryType <: StringEnumEntry] extends QuillValueEnum[String, EntryType] {
this: ValueEnum[String, EntryType] =>
}

/**
* QuillEnum for CharEnumEntry
*/
trait CharQuillEnum[EntryType <: CharEnumEntry] extends QuillValueEnum[Char, EntryType] {
this: ValueEnum[Char, EntryType] =>
}

/**
* QuillEnum for ByteEnumEntry
*/
trait ByteQuillEnum[EntryType <: ByteEnumEntry] extends QuillValueEnum[Byte, EntryType] {
this: ValueEnum[Byte, EntryType] =>
}
50 changes: 50 additions & 0 deletions enumeratum-quill/src/test/scala/enumeratum/QuillEnumSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package enumeratum

import org.scalatest.{FunSpec, Matchers}

import scala.collection.immutable

class QuillEnumSpec extends FunSpec with Matchers {

describe("to SQL String") {

// we only need to test whether it can compile because Quill will fail compilation if an Encoder is not found
it("should compile") {
"""
| import io.getquill._
| val ctx = new SqlMirrorContext(MirrorSqlDialect, Literal)
| import ctx._
| ctx.run(query[Shirt].insert(_.size -> lift(ShirtSize.Small: ShirtSize)))
""".stripMargin should compile
}

}

describe("from SQL String") {

// we only need to test whether it can compile because Quill will fail compilation if a Decoder is not found
it("should compile") {
"""
| import io.getquill._
| val ctx = new SqlMirrorContext(MirrorSqlDialect, Literal)
| import ctx._
| ctx.run(query[Shirt])
""".stripMargin should compile
}

}
}

sealed trait ShirtSize extends EnumEntry

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

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

override val values: immutable.IndexedSeq[ShirtSize] = findValues

}

case class Shirt(size: ShirtSize)
Loading