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

io.github.zeal18.zio.mongodb.bson.BsonTransformer.scala Maven / Gradle / Ivy

/*
 * Copyright 2008-present MongoDB, Inc.
 *
 * 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 io.github.zeal18.zio.mongodb.bson

import java.util.Date

import scala.annotation.implicitNotFound
import scala.jdk.CollectionConverters.*
import scala.util.matching.Regex

import io.github.zeal18.zio.mongodb.bson.collection.immutable.Document as IDocument
import io.github.zeal18.zio.mongodb.bson.collection.mutable.Document as MDocument

/** BsonTransformers allow the transformation of type `T` to their corresponding [[BsonValue]].
  *
  * Custom implementations can be written to implicitly to convert a `T` into a [[BsonValue]] so it can be stored in a `Document`.
  *
  * @tparam T the type of value to be transformed into a [[BsonValue]].
  */
@implicitNotFound(
  "No bson implicit transformer found for type ${T}. Implement or import an implicit BsonTransformer for this type.",
)
trait BsonTransformer[-T] {

  /** Convert the object into a [[BsonValue]]
    */
  def apply(value: T): BsonValue
}

/** Maps the following native scala types to BsonValues:
  *
  *  - `BsonValue => BsonValue`
  *  - `BigDecimal` => BsonDecimal128
  *  - `Boolean => BsonBoolean`
  *  - `String => BsonString`
  *  - `Array[Byte] => BsonBinary`
  *  - `Regex => BsonRegex`
  *  - `Date => BsonDateTime`
  *  - `Decimal128` => BsonDecimal128
  *  - `ObjectId => BsonObjectId`
  *  - `Int => BsonInt32`
  *  - `Long => BsonInt64`
  *  - `Double => BsonDouble`
  *  - `None => BsonNull`
  *  - `immutable.Document => BsonDocument`
  *  - `mutable.Document => BsonDocument`
  *  - `Option[T] => BsonValue` where `T` is one of the above types
  *  - `Seq[(String, T)] => BsonDocument` where `T` is one of the above types
  *  - `Seq[T] => BsonArray` where `T` is one of the above types
  */
object BsonTransformer extends DefaultBsonTransformers {}

/** Default BsonTransformers for native types.
  */
trait DefaultBsonTransformers extends LowPrio {

  /** Noop transformer for `BsonValue`s
    */
  implicit object TransformBsonValue extends BsonTransformer[BsonValue] {
    def apply(value: BsonValue): BsonValue = value
  }

  /** Transforms `BigDecimal` to `BsonDecimal128`
    */
  implicit object TransformBigDecimal extends BsonTransformer[BigDecimal] {
    def apply(value: BigDecimal): BsonDecimal128 = BsonDecimal128(value)
  }

  /** Transforms `Boolean` to `BsonBoolean`
    */
  implicit object TransformBoolean extends BsonTransformer[Boolean] {
    def apply(value: Boolean): BsonBoolean = BsonBoolean(value)
  }

  /** Transforms `String` to `BsonString`
    */
  implicit object TransformString extends BsonTransformer[String] {
    def apply(value: String): BsonString = BsonString(value)
  }

  /** Transforms `Array[Byte]` to `BsonBinary`
    */
  implicit object TransformBinary extends BsonTransformer[Array[Byte]] {
    def apply(value: Array[Byte]): BsonBinary = BsonBinary(value)
  }

  /** Transforms `Regex` to `BsonRegex`
    */
  implicit object TransformRegex extends BsonTransformer[Regex] {
    def apply(value: Regex): BsonRegularExpression = BsonRegularExpression(value)
  }

  /** Transforms `Date` to `BsonDateTime`
    */
  implicit object TransformDateTime extends BsonTransformer[Date] {
    def apply(value: Date): BsonDateTime = BsonDateTime(value)
  }

  /** Transforms `Decimal128` to `BsonDecimal128`
    */
  implicit object TransformDecimal128 extends BsonTransformer[Decimal128] {
    def apply(value: Decimal128): BsonDecimal128 = BsonDecimal128(value)
  }

  /** Transforms `ObjectId` to `BsonObjectId`
    */
  implicit object TransformObjectId extends BsonTransformer[ObjectId] {
    def apply(value: ObjectId): BsonObjectId = BsonObjectId(value)
  }

  /** Transforms `Int` to `BsonInt32`
    */
  implicit object TransformInt extends BsonTransformer[Int] {
    def apply(value: Int): BsonInt32 = BsonInt32(value)
  }

  /** Transforms `Long` to `BsonInt64`
    */
  implicit object TransformLong extends BsonTransformer[Long] {
    def apply(value: Long): BsonInt64 = BsonInt64(value)
  }

  /** Transforms `Double` to `BsonDouble`
    */
  implicit object TransformDouble extends BsonTransformer[Double] {
    def apply(value: Double): BsonDouble = BsonDouble(value)
  }

  /** Transforms `None` to `BsonNull`
    */
  implicit object TransformNone extends BsonTransformer[Option[Nothing]] {
    def apply(value: Option[Nothing]): BsonNull = BsonNull()
  }

  /** Transforms `Option[T]` to `BsonValue`
    */
  implicit def transformOption[T](implicit
    transformer: BsonTransformer[T],
  ): BsonTransformer[Option[T]] =
    new BsonTransformer[Option[T]] {
      def apply(value: Option[T]): BsonValue = value match {
        case Some(transformable) => transformer(transformable)
        case None                => BsonNull()
      }
    }

}

trait LowPrio {

  /** Transforms `immutable.Document` to `BsonDocument`
    */
  implicit object TransformImmutableDocument extends BsonTransformer[IDocument] {
    def apply(value: IDocument): BsonDocument = value.toBsonDocument
  }

  /** Transforms `mutable.Document` to `BsonDocument`
    */
  implicit object TransformMutableDocument extends BsonTransformer[MDocument] {
    def apply(value: MDocument): BsonDocument = value.underlying
  }

  /** Transforms `Seq[(String, T)]` to `BsonDocument`
    *
    * @param transformer implicit transformer for type `T`
    * @tparam T the type of the values
    * @return a BsonDocument containing the values
    */
  implicit def transformKeyValuePairs[T](implicit
    transformer: BsonTransformer[T],
  ): BsonTransformer[Seq[(String, T)]] =
    new BsonTransformer[Seq[(String, T)]] {
      def apply(values: Seq[(String, T)]): BsonDocument =
        BsonDocument(values.map(kv => (kv._1, transformer(kv._2))).toList)
    }

  /** Transforms `Seq[T]` to `BsonArray`
    *
    * @param transformer implicit transformer for type `T`
    * @tparam T the type of the values
    * @return a BsonArray containing all the values
    */
  implicit def transformSeq[T](implicit transformer: BsonTransformer[T]): BsonTransformer[Seq[T]] =
    new BsonTransformer[Seq[T]] {
      def apply(values: Seq[T]): BsonValue =
        new BsonArray(values.map(transformer.apply).toList.asJava)
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy