Getting Started with ZIO Bson
ZIO Bson is BSON library with tight ZIO integration.
Introduction
The goal of this project is to create the best all-round BSON library for Scala:
- Native BSON support to avoid intermediate JSON conversions and support BSON types.
- Future-Proof, prepared for Scala 3 and next-generation Java.
- Simple small codebase, concise documentation that covers everything.
- Helpful errors are readable by humans and machines.
- ZIO Integration so nothing more is required.
Installation
In order to use this library, we need to add the following lines in our build.sbt
file:
libraryDependencies += "dev.zio" %% "zio-bson" % "1.0.7"
libraryDependencies += "dev.zio" %% "zio-bson-magnolia" % "1.0.7"
zio-schema support
zio-bson-magnolia
projects provides typeclass derivation only for scala
2.13
.
You can use zio-schema-bson instead to get typeclass derivation on scala
2.12
, 2.13
and 3
.
Example
All the following code snippets assume that the following imports have been declared
import zio.bson._
import zio.bson.BsonBuilder._
Declaring codecs
Use DeriveBsonCodec.derive
to get a codec for your case class or sealed trait:
import zio.bson.magnolia._
case class Banana(curvature: Double)
object Banana {
implicit val codec: BsonCodec[Banana] = DeriveBsonCodec.derive
}
Converting to BsonValue
To use values in Filter
of Update
expressions you can convert them to BsonValue
this way:
"str".toBsonValue
Banana(0.2).toBsonValue
import org.bson._
def method[T: BsonEncoder](value: T): BsonDocument = doc("key" -> value.toBsonValue)
Creating CodecProvider
To get CodecProvider
for your BsonCodec
use zioBsonCodecProvider
:
val codecProvider = zioBsonCodecProvider[Banana]
Parsing BsonValue
In general CodecProvider
should parse your case class without intermediate BsonValue
representation.
But you can parse BsonValue
any way:
import BsonBuilder._
val bsonVal: BsonValue = doc("curvature" -> double(0.2))
bsonVal.as[Banana]
Errors
Bad BSON will produce an error with path and contextual information
scala> doc("curvature" -> Array[Byte](1, 2, 3).toBsonValue).as[Banana]
val res: Either[String,Banana] = Left(.curvature: Expected BSON type Double, but got BINARY.)
Configuration
You can configure typeclass derivation with annotations.
import zio.bson._
import zio.bson.BsonBuilder._
import zio.bson.magnolia._
sealed trait Fruit
object Fruit {
case class Banana(curvature: Double) extends Fruit
case class Apple(poison: Boolean) extends Fruit
implicit val codec: BsonCodec[Fruit] = DeriveBsonCodec.derive
}
val bsonFruit = doc( "Banana" -> doc( "curvature" -> double(0.5) ))
bsonFruit.as[Fruit]
//Right(Banana(0.5))
@bsonDiscriminator("$type")
sealed trait FruitConfigured
object FruitConfigured {
case class Banana(curvature: Double) extends FruitConfigured
@bsonHint("custom_type_name")
case class Apple(@bsonField("is_poisoned") poison: Boolean) extends FruitConfigured
implicit val codec: BsonCodec[FruitConfigured] = DeriveBsonCodec.derive
}
val bsonFruitConfigured = doc(
"$type" -> str("custom_type_name"),
"is_poisoned" -> bool(true)
)
bsonFruitConfigured.as[FruitConfigured]
//Right(Apple(true))