All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mongo4cats.zio.json.MongoJsonCodecs.scala Maven / Gradle / Ivy

There is a newer version: 0.7.10
Show newest version
/*
 * Copyright 2020 Kirill5k
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package mongo4cats.zio.json

import mongo4cats.bson.json._
import mongo4cats.bson._
import mongo4cats.codecs.MongoCodecProvider
import mongo4cats.errors.MongoJsonParsingException
import org.bson.codecs.configuration.CodecProvider
import zio.json.ast.Json
import zio.json.{JsonDecoder, JsonEncoder}

import java.time.{Instant, LocalDate}
import java.util.{Base64, UUID}
import scala.reflect.ClassTag
import scala.util.Try

trait MongoJsonCodecs {
  private val emptyJsonObject = Json.Obj()

  implicit def deriveJsonBsonValueEncoder[A](implicit e: JsonEncoder[A]): BsonValueEncoder[A] =
    value => ZioJsonMapper.toBson(e.toJsonAST(value).toOption.get)

  implicit def deriveJsonBsonValueDecoder[A](implicit d: JsonDecoder[A]): BsonValueDecoder[A] =
    bson => ZioJsonMapper.fromBson(bson).flatMap(d.fromJsonAST).toOption

  implicit val documentEncoder: JsonEncoder[Document] =
    Json.encoder.contramap[Document](d => ZioJsonMapper.fromBson(BsonValue.document(d)).getOrElse(emptyJsonObject))

  implicit val documentDecoder: JsonDecoder[Document] =
    Json.decoder.mapOrFail(j => ZioJsonMapper.toBson(j).asDocument.toRight(s"$j is not a valid document"))

  implicit val objectIdEncoder: JsonEncoder[ObjectId] =
    Json.encoder.contramap[ObjectId](ZioJsonMapper.objectIdToJson)

  implicit val objectIdDecoder: JsonDecoder[ObjectId] =
    Json.decoder.mapOrFail[ObjectId] { id =>
      ZioJsonMapper.jsonToObjectIdString(id).toRight(s"$id is not a valid object id").flatMap(ObjectId.from)
    }

  implicit val instantEncoder: JsonEncoder[Instant] =
    Json.encoder.contramap[Instant](ZioJsonMapper.instantToJson)

  implicit val instantDecoder: JsonDecoder[Instant] =
    Json.decoder.mapOrFail[Instant] { dateObj =>
      ZioJsonMapper
        .jsonToDateString(dateObj)
        .flatMap(tsStr => Try(Instant.parse(tsStr)).toOption)
        .toRight(s"$dateObj is not a valid instant object")
    }

  implicit val localDateEncoder: JsonEncoder[LocalDate] =
    Json.encoder.contramap[LocalDate](ZioJsonMapper.localDateToJson)

  implicit val localDateDecoder: JsonDecoder[LocalDate] =
    Json.decoder.mapOrFail[LocalDate] { dateObj =>
      ZioJsonMapper
        .jsonToDateString(dateObj)
        .flatMap(ldStr => Try(LocalDate.parse(ldStr.slice(0, 10))).toOption)
        .toRight(s"$dateObj is not a valid local date object")
    }

  implicit val uuidEncoder: JsonEncoder[UUID] =
    Json.encoder.contramap[UUID](ZioJsonMapper.uuidToJson)

  implicit val uuidDecoder: JsonDecoder[UUID] =
    Json.decoder.mapOrFail[UUID] { uuidObj =>
      Try(ZioJsonMapper.jsonToUuid(uuidObj)).toEither.left.map(_.getMessage)
    }

  implicit val binaryEncoder: JsonEncoder[Array[Byte]] =
    Json.encoder.contramap[Array[Byte]](ZioJsonMapper.binaryArrayToJson)

  implicit val binaryDecoder: JsonDecoder[Array[Byte]] =
    Json.decoder.mapOrFail[Array[Byte]] { json =>
      ZioJsonMapper
        .jsonToBinaryBase64(json)
        .toRight(s"$json is not a valid binary object")
        .flatMap(base64 => Try(Base64.getDecoder.decode(base64)).toEither.left.map(_.getMessage))
    }

  implicit def deriveZioJsonCodecProvider[T: ClassTag](implicit enc: JsonEncoder[T], dec: JsonDecoder[T]): MongoCodecProvider[T] =
    new MongoCodecProvider[T] {
      override def get: CodecProvider = codecProvider[T](
        enc.toJsonAST(_).left.map(MongoJsonParsingException(_, None)).fold(throw _, ZioJsonMapper.toBson),
        ZioJsonMapper.fromBson(_).flatMap(j => dec.fromJsonAST(j).left.map(e => MongoJsonParsingException(e, Some(j.toString))))
      )
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy