blob: fc7f1ce75aa608afb0c73c9082155ff89e8b9394 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.s2graph.graphql.types
import play.api.libs.json._
import sangria.ast
import sangria.execution.Executor
import sangria.marshalling.{ArrayMapBuilder, InputUnmarshaller, ResultMarshaller, ScalarValueInfo}
import sangria.schema._
import sangria.validation.{BigIntCoercionViolation, IntCoercionViolation, ValueCoercionViolation}
import sangria.macros._
import scala.concurrent.ExecutionContext.Implicits.global
object PlayJsonScalarType {
implicit object CustomPlayJsonResultMarshaller extends ResultMarshaller {
type Node = JsValue
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) = JsObject(builder.toMap)
def mapNode(keyValues: Seq[(String, JsValue)]) = Json.toJson(keyValues.toMap)
def arrayNode(values: Vector[JsValue]) = JsArray(values)
def optionalArrayNodeValue(value: Option[JsValue]) = value match {
case Some(v) ⇒ v
case None ⇒ nullNode
}
def scalarNode(value: Any, typeName: String, info: Set[ScalarValueInfo]) = value match {
case v: StringJsString(v)
case v: BooleanJsBoolean(v)
case v: IntJsNumber(v)
case v: LongJsNumber(v)
case v: FloatJsNumber(BigDecimal(v))
case v: DoubleJsNumber(v)
case v: BigIntJsNumber(BigDecimal(v))
case v: BigDecimalJsNumber(v)
case v: JsValue ⇒ v
case v ⇒ throw new IllegalArgumentException("Unsupported scalar value: " + v)
}
def enumNode(value: String, typeName: String) = JsString(value)
def nullNode = JsNull
def renderCompact(node: JsValue) = Json.stringify(node)
def renderPretty(node: JsValue) = Json.prettyPrint(node)
}
implicit object PlayJsonInputUnmarshaller extends InputUnmarshaller[JsValue] {
def getRootMapValue(node: JsValue, key: String) = node.asInstanceOf[JsObject].value get key
def isListNode(node: JsValue) = node.isInstanceOf[JsArray]
def getListValue(node: JsValue) = node.asInstanceOf[JsArray].value
def isMapNode(node: JsValue) = node.isInstanceOf[JsObject]
def getMapValue(node: JsValue, key: String) = node.asInstanceOf[JsObject].value get key
def getMapKeys(node: JsValue) = node.asInstanceOf[JsObject].fields.map(_._1)
def isDefined(node: JsValue) = node != JsNull
def getScalarValue(node: JsValue) = node match {
case JsBoolean(b) ⇒ b
case JsNumber(d) ⇒ d.toBigIntExact getOrElse d
case JsString(s) ⇒ s
case n ⇒ n
}
def getScalaScalarValue(node: JsValue) = getScalarValue(node)
def isEnumNode(node: JsValue) = node.isInstanceOf[JsString]
def isScalarNode(node: JsValue) = true
def isVariableNode(node: JsValue) = false
def getVariableName(node: JsValue) = throw new IllegalArgumentException("variables are not supported")
def render(node: JsValue) = Json.stringify(node)
}
case object JsonCoercionViolation extends ValueCoercionViolation("Not valid JSON")
implicit val JsonType = ScalarType[JsValue]("Json",
description = Some("Raw PlayJson value"),
coerceOutput = (value, _) ⇒ value,
coerceUserInput = {
case v: StringRight(JsString(v))
case v: BooleanRight(JsBoolean(v))
case v: IntRight(JsNumber(v))
case v: LongRight(JsNumber(v))
case v: FloatRight(JsNumber(BigDecimal(v)))
case v: DoubleRight(JsNumber(v))
case v: BigIntRight(JsNumber(BigDecimal(v)))
case v: BigDecimalRight(JsNumber(v))
case v: JsValueRight(v)
},
coerceInput = {
case sv: ast.StringValue => Right(Json.parse(sv.value))
case _ ⇒
Left(JsonCoercionViolation)
})
}