7

我有以下输入对象:

val BusinessInputType = InputObjectType[BusinessInput]("BusinessInput", List(
    InputField("userId", StringType),
    InputField("name", StringType),
    InputField("address", OptionInputType(StringType)),
    InputField("phonenumber", OptionInputType(StringType)),
    InputField("email", OptionInputType(StringType)),
    InputField("hours", ListInputType(BusinessHoursInputType))

  ))


 val BusinessHoursInputType = InputObjectType[BusinessHoursInput]("hours",  List(
    InputField("weekDay", IntType),
    InputField("startTime", StringType),
    InputField("endTime", StringType)
  ))

这是我定义了自定义编组的模型:

case class BusinessInput(userId: String, name: String, address: Option[String], phonenumber: Option[String], email: Option[String], hours: Seq[BusinessHoursInput])

object BusinessInput {

  implicit val manual = new FromInput[BusinessInput] {
    val marshaller = CoercedScalaResultMarshaller.default

    def fromResult(node: marshaller.Node) = {
      val ad = node.asInstanceOf[Map[String, Any]]

      System.out.println(ad)
      BusinessInput(
        userId = ad("userId").asInstanceOf[String],
        name = ad("name").asInstanceOf[String],
        address = ad.get("address").flatMap(_.asInstanceOf[Option[String]]),
        phonenumber = ad.get("phonenumber").flatMap(_.asInstanceOf[Option[String]]),
        email = ad.get("email").flatMap(_.asInstanceOf[Option[String]]),
        hours = ad("hours").asInstanceOf[Seq[BusinessHoursInput]]

      )
    }
  }
}



case class BusinessHoursInput(weekDay: Int, startTime: Time, endTime: Time)

object BusinessHoursInput {

  implicit val manual = new FromInput[BusinessHoursInput] {
    val marshaller = CoercedScalaResultMarshaller.default
    def fromResult(node: marshaller.Node) = {
      val ad = node.asInstanceOf[Map[String, Any]]
      System.out.println("HEY")

      BusinessHoursInput(
        weekDay = ad("weekDay").asInstanceOf[Int],
        startTime = Time.valueOf(ad("startTime").asInstanceOf[String]),
        endTime = Time.valueOf(ad("endTime").asInstanceOf[String])
      )
    }
  }


}

我的问题是,当我有一个InputObject具有自定义编组的嵌套时,我看不到在编组BusinessHoursInput之前被调用的BusinessInput编组。我注意到了这一点,因为 "Hey" 的打印语句从未在 "ad" 的打印语句之前执行过BusinessInput。当我尝试BusinessInput在数据库中插入 hours 字段时,这会导致我以后遇到问题,因为它无法将其转换为BusinessHoursInput对象。在桑格利亚汽酒中,是否无法在编组父对象之前自定义编组嵌套对象?

4

2 回答 2

5

您可能正在BusinessInput用作参数类型。实际的隐式查找发生在Argument定义时并且仅针对BusinessInput类型。

由于FromInput是基于类型类的反序列化,因此您需要显式定义嵌​​套对象的反序列化器之间的依赖关系。例如,您可以像这样重写反序列化器:

case class BusinessInput(userId: String, name: String, address: Option[String], phonenumber: Option[String], email: Option[String], hours: Seq[BusinessHoursInput])

object BusinessInput {
  implicit def manual(implicit hoursFromInput: FromInput[BusinessHoursInput]) = new FromInput[BusinessInput] {
    val marshaller = CoercedScalaResultMarshaller.default

    def fromResult(node: marshaller.Node) = {
      val ad = node.asInstanceOf[Map[String, Any]]

      BusinessInput(
        userId = ad("userId").asInstanceOf[String],
        name = ad("name").asInstanceOf[String],
        address = ad.get("address").flatMap(_.asInstanceOf[Option[String]]),
        phonenumber = ad.get("phonenumber").flatMap(_.asInstanceOf[Option[String]]),
        email = ad.get("email").flatMap(_.asInstanceOf[Option[String]]),
        hours = hoursFromInput.fromResult(ad("hours").asInstanceOf[Seq[hoursFromInput.marshaller.Node]])
      )
    }
  }
}

在这个版本中,我利用现有的对原始输入FromInput[BusinessHoursInput]进行反序列化。BusinessHoursInput

作为替代方案,您可以FromInput通过利用现有的基于 JSON 的反序列化器来完全避免定义手动反序列化器。例如,在大多数情况下,circe 的自动推导工作得很好。您只需要这 2 个导入(在定义参数的文件中):

import sangria.marshalling.circe._
import io.circe.generic.auto._

这些导入将适当FromInput的实例放入范围。这些实例利用了 circe 自己的反序列化机制。

于 2018-03-05T15:53:23.693 回答
0
import io.circe.Decoder
import io.circe.generic.semiauto.deriveDecoder
import sangria.macros.derive.deriveInputObjectType
import sangria.marshalling.circe._
import sangria.schema.{Argument, InputObjectType}


object XXX {

  // when you have FromInput for all types in case class (Int, String) you can derive it
  case class BusinessHoursInput(weekDay: Int, startTime: String, endTime: String)

  object BusinessHoursInput {
    implicit val decoder: Decoder[BusinessHoursInput] = deriveDecoder
    implicit val inputType: InputObjectType[BusinessHoursInput] = deriveInputObjectType[BusinessHoursInput]()
  }

  // the same here, you need InputObjectType also for BusinessHoursInput
  case class BusinessInput(userId: String, name: String, address: Option[String], phonenumber: Option[String], email: Option[String], hours: Seq[BusinessHoursInput])

  object BusinessInput {
    implicit val decoder: Decoder[BusinessInput] = deriveDecoder
    implicit val inputType: InputObjectType[BusinessInput] = deriveInputObjectType[BusinessInput]()
  }

  // for this to work you need to have in scope InputType BusinessInput and FromInput for BusinessInput
  // FromInput you can get by having Decoder in scope and import sangria.marshalling.circe._
  private val businessInputArg = Argument("businessInput", BusinessInput.inputType)


}

如果你不使用 circe 但不同的 json 库,你当然应该有不同的类型类和范围内的正确导入

于 2019-04-02T13:32:39.110 回答