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

ongo.reactivemongo-bson_2.10.0.11.13.source-code.handlers.scala Maven / Gradle / Ivy

/*
 * Copyright 2013 Stephane Godbillon (@sgodbillon)
 *
 * 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 reactivemongo.bson

import scala.collection.generic.CanBuildFrom
import scala.util.{ Failure, Success, Try }

sealed trait UnsafeBSONReader[T] {
  def readTry(value: BSONValue): Try[T]
}

/**
 * A reader that produces an instance of `T` from a subtype of [[BSONValue]].
 */
trait BSONReader[B <: BSONValue, T] { self =>

  /**
   * Reads a BSON value and produce an instance of `T`.
   *
   * This method may throw exceptions at runtime.
   * If used outside a reader, one should consider `readTry(bson: B): Try[T]` or `readOpt(bson: B): Option[T]`.
   */
  def read(bson: B): T

  /** Tries to produce an instance of `T` from the `bson` value, returns `None` if an error occurred. */
  def readOpt(bson: B): Option[T] = readTry(bson).toOption

  /** Tries to produce an instance of `T` from the `bson` value. */
  def readTry(bson: B): Try[T] = Try(read(bson))

  /**
   * Returns a BSON reader that returns the result of applying `f`
   * on the result of this reader.
   *
   * @param f the function to apply
   */
  final def afterRead[U](f: T => U): BSONReader[B, U] =
    BSONReader[B, U]((read _) andThen f)

  private[reactivemongo] def widenReader[U >: T]: UnsafeBSONReader[U] =
    new UnsafeBSONReader[U] {
      def readTry(value: BSONValue): Try[U] =
        Try(value.asInstanceOf[B]) match {
          case Failure(_) => Failure(exceptions.TypeDoesNotMatch(
            s"Cannot convert $value: ${value.getClass} with ${self.getClass}"))

          case Success(bson) => self.readTry(bson)
        }
    }
}

object BSONReader {
  private class Default[B <: BSONValue, T](
      _read: B => T) extends BSONReader[B, T] {
    def read(bson: B): T = _read(bson)
  }

  def apply[B <: BSONValue, T](read: B => T): BSONReader[B, T] =
    new Default[B, T](read)
}

/**
 * A writer that produces a subtype of [[BSONValue]] fron an instance of `T`.
 */
trait BSONWriter[T, B <: BSONValue] {
  /**
   * Writes an instance of `T` as a BSON value.
   *
   * This method may throw exceptions at runtime.
   * If used outside a reader, one should consider `writeTry(bson: B): Try[T]` or `writeOpt(bson: B): Option[T]`.
   */
  def write(t: T): B

  /** Tries to produce a BSON value from an instance of `T`, returns `None` if an error occurred. */
  def writeOpt(t: T): Option[B] = writeTry(t).toOption

  /** Tries to produce a BSON value from an instance of `T`. */
  def writeTry(t: T): Try[B] = Try(write(t))

  /**
   * Returns a BSON writer that returns the result of applying `f`
   * on the BSON value from this writer.
   *
   * @param f the function to apply
   */
  final def afterWrite[U <: BSONValue](f: B => U): BSONWriter[T, U] =
    BSONWriter[T, U]((write _) andThen f)

  final def beforeWrite[U](f: U => T): BSONWriter[U, B] =
    BSONWriter[U, B](f andThen (write _))
}

object BSONWriter {
  private class Default[T, B <: BSONValue](
      _write: T => B) extends BSONWriter[T, B] {
    def write(value: T): B = _write(value)
  }

  def apply[T, B <: BSONValue](write: T => B): BSONWriter[T, B] =
    new Default[T, B](write)
}

/**
 * A reader that produces an instance of `T` from a subtype of [[BSONValue]].
 */
trait VariantBSONReader[-B <: BSONValue, +T] {
  /**
   * Reads a BSON value and produce an instance of `T`.
   *
   * This method may throw exceptions at runtime.
   * If used outside a reader, one should consider `readTry(bson: B): Try[T]` or `readOpt(bson: B): Option[T]`.
   */
  def read(bson: B): T

  /** Tries to produce an instance of `T` from the `bson` value, returns `None` if an error occurred. */
  def readOpt(bson: B): Option[T] = readTry(bson).toOption

  /** Tries to produce an instance of `T` from the `bson` value. */
  def readTry(bson: B): Try[T] = Try(read(bson))
}

/**
 * A writer that produces a subtype of [[BSONValue]] fron an instance of `T`.
 */
trait VariantBSONWriter[-T, +B <: BSONValue] {
  /**
   * Writes an instance of `T` as a BSON value.
   *
   * This method may throw exceptions at runtime.
   * If used outside a reader, one should consider `writeTry(bson: B): Try[T]` or `writeOpt(bson: B): Option[T]`.
   */
  def write(t: T): B

  /** Tries to produce a BSON value from an instance of `T`, returns `None` if an error occurred. */
  def writeOpt(t: T): Option[B] = writeTry(t).toOption

  /** Tries to produce a BSON value from an instance of `T`. */
  def writeTry(t: T): Try[B] = Try(write(t))
}

trait BSONDocumentReader[T] extends BSONReader[BSONDocument, T]

object BSONDocumentReader {
  private class Default[T](
      _read: BSONDocument => T) extends BSONDocumentReader[T] {

    def read(value: BSONDocument): T = _read(value)
  }

  def apply[T](read: BSONDocument => T): BSONDocumentReader[T] =
    new Default[T](read)
}

trait BSONDocumentWriter[T] extends BSONWriter[T, BSONDocument]

object BSONDocumentWriter {
  private class Default[T](
      _write: T => BSONDocument) extends BSONDocumentWriter[T] {

    def write(value: T): BSONDocument = _write(value)
  }

  def apply[T](write: T => BSONDocument): BSONDocumentWriter[T] =
    new Default[T](write)
}

trait VariantBSONDocumentReader[+T] extends VariantBSONReader[BSONDocument, T]
trait VariantBSONDocumentWriter[-T] extends VariantBSONWriter[T, BSONDocument]

class VariantBSONWriterWrapper[T, B <: BSONValue](writer: VariantBSONWriter[T, B]) extends BSONWriter[T, B] {
  def write(t: T) = writer.write(t)
}

class VariantBSONReaderWrapper[B <: BSONValue, T](reader: VariantBSONReader[B, T]) extends BSONReader[B, T] {
  def read(b: B) = reader.read(b)
}

trait BSONHandler[B <: BSONValue, T] extends BSONReader[B, T] with BSONWriter[T, B] {
  def as[R](to: T => R, from: R => T): BSONHandler[B, R] =
    new BSONHandler.MappedHandler(this, to, from)
}

object BSONHandler {
  private[bson] class MappedHandler[B <: BSONValue, T, U](
      parent: BSONHandler[B, T],
      to: T => U,
      from: U => T) extends BSONHandler[B, U] {
    def write(u: U) = parent.write(from(u))
    def read(b: B) = to(parent.read(b))
  }

  private[bson] class DefaultHandler[B <: BSONValue, T](r: B => T, w: T => B)
      extends BSONHandler[B, T] {
    def read(x: B): T = r(x)
    def write(x: T): B = w(x)
  }

  def apply[B <: BSONValue, T](read: B => T, write: T => B): BSONHandler[B, T] =
    new DefaultHandler(read, write)
}

trait DefaultBSONHandlers {
  implicit object BSONIntegerHandler extends BSONHandler[BSONInteger, Int] {
    def read(int: BSONInteger) = int.value
    def write(int: Int) = BSONInteger(int)
  }
  implicit object BSONLongHandler extends BSONHandler[BSONLong, Long] {
    def read(long: BSONLong) = long.value
    def write(long: Long) = BSONLong(long)
  }
  implicit object BSONDoubleHandler extends BSONHandler[BSONDouble, Double] {
    def read(double: BSONDouble) = double.value
    def write(double: Double) = BSONDouble(double)
  }

  implicit object BSONStringHandler extends BSONHandler[BSONString, String] {
    def read(string: BSONString) = string.value
    def write(string: String) = BSONString(string)
  }
  implicit object BSONBooleanHandler extends BSONHandler[BSONBoolean, Boolean] {
    def read(boolean: BSONBoolean) = boolean.value
    def write(boolean: Boolean) = BSONBoolean(boolean)
  }

  implicit object BSONBinaryHandler extends BSONHandler[BSONBinary, Array[Byte]] {
    def read(bin: BSONBinary) = bin.value.readArray(bin.value.size)
    def write(xs: Array[Byte]) = BSONBinary(xs, Subtype.GenericBinarySubtype)
  }

  import java.util.Date

  implicit object BSONDateTimeHandler extends BSONHandler[BSONDateTime, Date] {
    def read(bson: BSONDateTime) = new Date(bson.value)
    def write(date: Date) = BSONDateTime(date.getTime)
  }

  // Typeclasses Handlers
  import BSONNumberLike._
  import BSONBooleanLike._

  class BSONNumberLikeReader[B <: BSONValue] extends BSONReader[B, BSONNumberLike] {
    def read(bson: B) = bson match {
      case int: BSONInteger   => BSONIntegerNumberLike(int)
      case long: BSONLong     => BSONLongNumberLike(long)
      case double: BSONDouble => BSONDoubleNumberLike(double)
      case dt: BSONDateTime   => BSONDateTimeNumberLike(dt)
      case ts: BSONTimestamp  => BSONTimestampNumberLike(ts)
      case _                  => throw new UnsupportedOperationException()
    }
  }

  implicit object BSONNumberLikeWriter extends VariantBSONWriter[BSONNumberLike, BSONValue] {
    def write(number: BSONNumberLike) = number.underlying
  }

  implicit def bsonNumberLikeReader[B <: BSONValue] = new BSONNumberLikeReader[B]

  class BSONBooleanLikeReader[B <: BSONValue] extends BSONReader[B, BSONBooleanLike] {
    def read(bson: B) = bson match {
      case int: BSONInteger        => BSONIntegerBooleanLike(int)
      case double: BSONDouble      => BSONDoubleBooleanLike(double)
      case long: BSONLong          => BSONLongBooleanLike(long)
      case boolean: BSONBoolean    => BSONBooleanBooleanLike(boolean)
      case nll: BSONNull.type      => BSONNullBooleanLike(BSONNull)
      case udf: BSONUndefined.type => BSONUndefinedBooleanLike(BSONUndefined)
      case _                       => throw new UnsupportedOperationException()
    }
  }

  implicit object BSONBooleanLikeWriter extends VariantBSONWriter[BSONBooleanLike, BSONValue] {
    def write(number: BSONBooleanLike) = number.underlying
  }

  implicit def bsonBooleanLikeReader[B <: BSONValue] = new BSONBooleanLikeReader[B]

  // Collections Handlers
  class BSONArrayCollectionReader[M[_], T](implicit cbf: CanBuildFrom[M[_], T, M[T]], reader: BSONReader[_ <: BSONValue, T]) extends BSONReader[BSONArray, M[T]] {
    def read(array: BSONArray) =
      array.stream.filter(_.isSuccess).map { v =>
        reader.asInstanceOf[BSONReader[BSONValue, T]].read(v.get)
      }.to[M]
  }

  class BSONArrayCollectionWriter[T, Repr <% Traversable[T]](implicit writer: BSONWriter[T, _ <: BSONValue]) extends VariantBSONWriter[Repr, BSONArray] {
    def write(repr: Repr) = {
      new BSONArray(repr.map(s => Try(writer.write(s))).to[Stream])
    }
  }

  implicit def collectionToBSONArrayCollectionWriter[T, Repr <% Traversable[T]](implicit writer: BSONWriter[T, _ <: BSONValue]): VariantBSONWriter[Repr, BSONArray] = {
    new BSONArrayCollectionWriter[T, Repr]
  }

  implicit def bsonArrayToCollectionReader[M[_], T](implicit cbf: CanBuildFrom[M[_], T, M[T]], reader: BSONReader[_ <: BSONValue, T]): BSONReader[BSONArray, M[T]] = {
    new BSONArrayCollectionReader
  }

  abstract class IdentityBSONConverter[T <: BSONValue](implicit m: Manifest[T]) extends BSONReader[T, T] with BSONWriter[T, T] {
    override def write(t: T): T = m.runtimeClass.cast(t).asInstanceOf[T]
    override def writeOpt(t: T): Option[T] = if (m.runtimeClass.isInstance(t)) Some(t.asInstanceOf[T]) else None
    override def read(bson: T): T = m.runtimeClass.cast(bson).asInstanceOf[T]
    override def readOpt(bson: T): Option[T] = if (m.runtimeClass.isInstance(bson)) Some(bson.asInstanceOf[T]) else None
  }

  implicit object BSONStringIdentity extends IdentityBSONConverter[BSONString]

  implicit object BSONIntegerIdentity extends IdentityBSONConverter[BSONInteger]

  implicit object BSONArrayIdentity extends IdentityBSONConverter[BSONArray]

  implicit object BSONDocumentIdentity extends IdentityBSONConverter[BSONDocument] with BSONDocumentReader[BSONDocument] with BSONDocumentWriter[BSONDocument]

  implicit object BSONBooleanIdentity extends IdentityBSONConverter[BSONBoolean]

  implicit object BSONLongIdentity extends IdentityBSONConverter[BSONLong]

  implicit object BSONDoubleIdentity extends IdentityBSONConverter[BSONDouble]

  implicit object BSONValueIdentity extends IdentityBSONConverter[BSONValue]

  implicit object BSONObjectIDIdentity extends IdentityBSONConverter[BSONObjectID]

  implicit object BSONBinaryIdentity extends IdentityBSONConverter[BSONBinary]

  implicit object BSONDateTimeIdentity extends IdentityBSONConverter[BSONDateTime]

  implicit object BSONNullIdentity extends IdentityBSONConverter[BSONNull.type]

  implicit object BSONUndefinedIdentity extends IdentityBSONConverter[BSONUndefined.type]

  implicit object BSONRegexIdentity extends IdentityBSONConverter[BSONRegex]

  implicit object BSONJavaScriptIdentity extends BSONReader[BSONJavaScript, BSONJavaScript] with BSONWriter[BSONJavaScript, BSONJavaScript] {
    def read(b: BSONJavaScript) = b
    def write(b: BSONJavaScript) = b
  }

  implicit def findWriter[T](implicit writer: VariantBSONWriter[T, _ <: BSONValue]): BSONWriter[T, _ <: BSONValue] =
    new VariantBSONWriterWrapper(writer)

  implicit def findReader[T](implicit reader: VariantBSONReader[_ <: BSONValue, T]): BSONReader[_ <: BSONValue, T] =
    new VariantBSONReaderWrapper(reader)
}

object DefaultBSONHandlers extends DefaultBSONHandlers




© 2015 - 2025 Weber Informatics LLC | Privacy Policy