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

sangria.marshalling.circe.scala Maven / Gradle / Ivy

There is a newer version: 1.2.1
Show newest version
package sangria.marshalling

import io.circe._
import cats.data.Xor.{Right, Left}

object circe {
  implicit object CirceResultMarshaller extends ResultMarshaller {
    type Node = Json
    type MapBuilder = ArrayMapBuilder[Node]

    def emptyMapNode(keys: Seq[String]) = new ArrayMapBuilder[Node](keys)
    def addMapNodeElem(builder: MapBuilder, key: String, value: Node, optional: Boolean) = builder.add(key, value)

    def mapNode(builder: MapBuilder) = Json.obj(builder.toSeq: _*)
    def mapNode(keyValues: Seq[(String, Json)]) = Json.obj(keyValues: _*)

    def arrayNode(values: Vector[Json]) = Json.arr(values: _*)
    def optionalArrayNodeValue(value: Option[Json]) = value match {
      case Some(v) ⇒ v
      case None ⇒ nullNode
    }

    def scalarNode(value: Any, typeName: String, info: Set[ScalarValueInfo]) = value match {
      case v: String ⇒ Json.fromString(v)
      case v: Boolean ⇒ Json.fromBoolean(v)
      case v: Int ⇒ Json.fromInt(v)
      case v: Long ⇒ Json.fromLong(v)
      case v: Float ⇒ Json.fromDoubleOrNull(v)
      case v: Double ⇒ Json.fromDoubleOrNull(v)
      case v: BigInt ⇒ Json.fromBigInt(v)
      case v: BigDecimal ⇒ Json.fromBigDecimal(v)
      case v ⇒ throw new IllegalArgumentException("Unsupported scalar value: " + v)
    }

    def enumNode(value: String, typeName: String) = Json.fromString(value)

    def nullNode = Json.Null

    def renderCompact(node: Json) = node.noSpaces
    def renderPretty(node: Json) = node.spaces2
  }

  implicit object CirceMarshallerForType extends ResultMarshallerForType[Json] {
    val marshaller = CirceResultMarshaller
  }

  implicit object CirceInputUnmarshaller extends InputUnmarshaller[Json] {
    def getRootMapValue(node: Json, key: String) = node.asObject.get(key)

    def isMapNode(node: Json) = node.isObject
    def getMapValue(node: Json, key: String) = node.asObject.get(key)
    def getMapKeys(node: Json) = node.asObject.get.fields

    def isListNode(node: Json) = node.isArray
    def getListValue(node: Json) = node.asArray.get

    def isDefined(node: Json) = !node.isNull
    def getScalarValue(node: Json) = {
      def invalidScalar = throw new IllegalStateException(s"$node is not a scalar value")

      node.fold(
        jsonNull = invalidScalar,
        jsonBoolean = identity,
        jsonNumber = num ⇒ num.toBigInt orElse num.toBigDecimal getOrElse invalidScalar,
        jsonString = identity,
        jsonArray = _ ⇒ invalidScalar,
        jsonObject = _ ⇒ invalidScalar
      )
    }

    def getScalaScalarValue(node: Json) = getScalarValue(node)

    def isEnumNode(node: Json) = node.isString

    def isScalarNode(node: Json) =
      node.isBoolean || node.isNumber || node.isString

    def isVariableNode(node: Json) = false
    def getVariableName(node: Json) = throw new IllegalArgumentException("variables are not supported")

    def render(node: Json) = node.noSpaces
  }

  implicit object circeToInput extends ToInput[Json, Json] {
    def toInput(value: Json) = (value, CirceInputUnmarshaller)
  }

  implicit object circeFromInput extends FromInput[Json] {
    val marshaller = CirceResultMarshaller
    def fromResult(node: marshaller.Node) = node
  }

  implicit def circeEncoderToInput[T : Encoder]: ToInput[T, Json] =
    new ToInput[T, Json] {
      def toInput(value: T) = implicitly[Encoder[T]].apply(value) → CirceInputUnmarshaller
    }

  implicit def circeDecoderFromInput[T : Decoder]: FromInput[T] =
    new FromInput[T] {
      val marshaller = CirceResultMarshaller
      def fromResult(node: marshaller.Node) = implicitly[Decoder[T]].decodeJson(node) match {
        case Right(obj) ⇒ obj
        case Left(error) ⇒ throw InputParsingError(Vector(error.getMessage))
      }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy