Skip to content

Commit

Permalink
Add borerSerialization example showing how to use the iron-borer
Browse files Browse the repository at this point in the history
…module.
  • Loading branch information
sirthias committed Jan 24, 2024
1 parent ab0c680 commit 0553439
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 0 deletions.
12 changes: 12 additions & 0 deletions build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,18 @@ object examples extends Module {
ivy"com.github.plokhotnyuk.jsoniter-scala::jsoniter-scala-macros:$jsoniterVersion"
)
}

object borerSerialization extends ScalaModule with ScalafmtModule {

def scalaVersion = versions.scala

def moduleDeps = Seq(main, borer)

def ivyDeps = Agg(
ivy"io.bullet::borer-core::1.13.0",
ivy"io.bullet::borer-derivation::1.13.0"
)
}
}

trait SubModule extends BaseModule {
Expand Down
25 changes: 25 additions & 0 deletions examples/borerSerialization/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Small Demo of borer integration
This example shows how to integrate _iron_ with [borer](https://sirthias.github.io/borer/).

After having added `"io.github.iltotore" %% "iron-borer" % "<version>"` as a dependency you can say this:

```scala
import io.github.iltotore.iron.borer.given
```

With this import in place all refined types `T` automatically have _borer_ `Encoder[T]` and `Decoder[T]`
instances available, as long as the respective Encoders and Decoders for the (unrefined) underlying types are already
`given`.

If a refinement error is triggered during decoding because the decoded value doesn't match the refinement condition(s)
decoding will fail with a `Borer.Error.ValidationFailure`.


## Run the example

Use the following command (in the Iron project root directory) to run the example:

```sh
mill examples.borerSerialization.run
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package io.github.iltotore.iron.formBorer

import io.bullet.borer.Codec
import io.bullet.borer.derivation.MapBasedCodecs
import io.github.iltotore.iron.constraint.all.*
import io.github.iltotore.iron.{*, given}
import io.github.iltotore.iron.borer.given // this enables borer <-> iron integration

type Username = (Alphanumeric & MinLength[3] & MaxLength[10]) DescribedAs
"Username should be alphanumeric and have a length between 3 and 10"

type Password = (Match["[A-Za-z].*[0-9]|[0-9].*[A-Za-z]"] & MinLength[6] & MaxLength[20]) DescribedAs
"Password must contain at least a letter, a digit and have a length between 6 and 20"

type Age = Greater[0] DescribedAs
"Age should be strictly positive"

case class Account(
name: String :| Username,
password: String :| Password,
age: Int :| Age
)

object Account:
given Codec[Account] = MapBasedCodecs.deriveCodec
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.github.iltotore.iron.formBorer

import io.bullet.borer.{Borer, Json}
import io.github.iltotore.iron.{*, given}

@main def main: Unit =

val account = Account(
name = "matt",
password = "bar123",
age = 42
)

val okValidEncoding = """{"name":"matt","password":"bar123","age":42}"""
val invalidEncoding = """{"name":"matt","password":"bar","age":42}"""

val encoding = Json.encode(account).toUtf8String
println(encoding)
assert(encoding == okValidEncoding)

val decoding = Json.decode(okValidEncoding.getBytes).to[Account].valueEither
println(decoding)
assert(decoding == Right(account))

val decoding2 = Json.decode(invalidEncoding.getBytes).to[Account].valueEither
decoding2 match {
case Left(e: Borer.Error.ValidationFailure[_]) =>
// "Password must contain at least a letter, a digit and have a length between 6 and 20 (input position 26)"
println(e.getMessage)
case _ => throw new IllegalStateException
}

0 comments on commit 0553439

Please sign in to comment.