Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
43 changes: 21 additions & 22 deletions circe/src/main/scala/mongo4cats/circe.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,31 +39,30 @@ object circe extends JsonCodecs {
}

object implicits {
implicit def circeEncoderToEncoder[A: Encoder]: BsonEncoder[A] = new BsonEncoder[A] {
def apply(a: A): BsonValue = {
val json = a.asJson
val wrapped = Json.obj(RootTag := json)
val bson = BsonDocument.parse(wrapped.noSpaces)
bson.get(RootTag)
}
}

implicit def circeDecoderToDecoder[A: Decoder]: BsonDecoder[A] = new BsonDecoder[A] {

val decoder = Decoder.instance[A](_.as[A])
implicit def circeEncoderToEncoder[A: Encoder]: BsonEncoder[A] =
jsonEncoder.contramap(_.asJson)

def apply(b: BsonValue) = {
val doc = BsonDocument(RootTag -> (if (b == null) new BsonNull else b)).toJson()
val json = parser.parse(doc)
val jsonWithoutRoot = json.flatMap(_.hcursor.get[Json](RootTag))
jsonWithoutRoot
.flatMap(decoder.decodeJson(_))
.leftMap(x =>
BsonDecodeError {
s"An error occured during decoding BsonValue ${b}: $x"
}
)
implicit def circeDecoderToDecoder[A: Decoder]: BsonDecoder[A] =
jsonDecoder.flatMap { json =>
Decoder
.instance[A](_.as[A])
.decodeJson(json)
.leftMap(x => BsonDecodeError(x.toString))
}

implicit val jsonEncoder: BsonEncoder[Json] = BsonEncoder.instance { json =>
val wrapped = Json.obj(RootTag := json)
val bson = BsonDocument.parse(wrapped.noSpaces)
bson.get(RootTag)
}

implicit val jsonDecoder: BsonDecoder[Json] = BsonDecoder.instance { b =>
val doc = BsonDocument(RootTag -> (if (b == null) new BsonNull else b)).toJson()
val json = parser.parse(doc)
val jsonWithoutRoot = json.flatMap(_.hcursor.get[Json](RootTag))
jsonWithoutRoot
.leftMap(x => BsonDecodeError(s"An error occured during decoding BsonValue ${b}: $x"))
}
}

Expand Down
26 changes: 25 additions & 1 deletion circe/src/test/scala/mongo4cats/circe.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,34 @@ import org.bson.BsonString
import io.circe.Decoder
import org.scalatest.EitherValues
import io.circe.DecodingFailure
import org.bson.BsonBoolean
import mongo4cats.bson.BsonDocument
import io.circe.Json
import mongo4cats.bson.BsonDecoder
import io.circe.JsonObject

class CirceSpec extends AnyWordSpec with Matchers with EitherValues {

"circe conversions" should {

"decode a bson document as a json object" in {
import circe.implicits._

val bson = BsonDocument("a" -> new BsonString("b"), "c" -> new BsonBoolean(false))
val json = JsonObject("a" -> Json.fromString("b"), "c" -> Json.False).toJson

BsonDecoder[Json].apply(bson) shouldBe Right(json)
}

"decode a bson literal as a json literal" in {
import circe.implicits._

val bson = new BsonString("hello there")
val json = Json.fromString("hello there")

BsonDecoder[Json].apply(bson) shouldBe Right(json)
}

"decode null as if it was Json.null" in {
circe.implicits
.circeDecoderToDecoder[Unit](Decoder.instance { c =>
Expand All @@ -41,7 +65,7 @@ class CirceSpec extends AnyWordSpec with Matchers with EitherValues {

val res = circe.implicits.circeDecoderToDecoder[String](deco).apply(new BsonString("hek"))

res.left.value.msg shouldBe "An error occured during decoding BsonValue BsonString{value='hek'}: DecodingFailure at .hek: Missing required field"
res.left.value.msg shouldBe "DecodingFailure at .hek: Missing required field"

}
}
Expand Down