在Sangria中编组嵌套的自定义对象

joh*_*ohn 7 scala playframework sangria

我有以下输入对象:

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)
  ))
Run Code Online (Sandbox Code Playgroud)

以下是定制编组定义的模型:

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])
      )
    }
  }


}
Run Code Online (Sandbox Code Playgroud)

我的问题是,当我有一个InputObject具有自定义编组的嵌套时,我没有看到在编组BusinessHoursInput之前调用的BusinessInput编组.我注意到了这一点,因为"嘿"的打印声明从未在"广告"的打印声明之前执行BusinessInput.当我尝试BusinessInput在DB中插入hours字段时,这会导致后来出现问题,因为它无法将其转换为BusinessHoursInput对象.在Sangria中,是否无法在父对象编组之前自定义Marshal嵌套对象?

ten*_*shi 5

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

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

案例类BusinessInput(用户ID:字符串,名称:字符串,地址:Option [String],电话号码:Option [String],电子邮件:Option [String],小时数: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]])
      )
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

在此版本中,我利用现有功能从原始输入中FromInput[BusinessHoursInput]反序列化BusinessHoursInput

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

import sangria.marshalling.circe._
import io.circe.generic.auto._
Run Code Online (Sandbox Code Playgroud)

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