Scala 2.11 + Play Framework 2.3中的22个字段限制Case类和函数 [英] 22 fields limit in Scala 2.11 + Play Framework 2.3 Case classes and functions

查看:99
本文介绍了Scala 2.11 + Play Framework 2.3中的22个字段限制Case类和函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Scala 2.11已经发布,案例类别的22个字段限制似乎是固定的( Scala问题发行说明).

Scala 2.11 is out and the 22 fields limit for case classes seems to be fixed (Scala Issue, Release Notes).

这一直是我的一个问题,因为我使用案例类为Play + Postgres异步.我在Scala 2.10中的解决方案是将模型分为多个案例类,但是我发现这种解决方案难以维护和扩展,我希望在切换到Play 2.3.0-RC1 + Scala 2.11之后可以实现如下所述的功能. 0:

This has been an issue for me for a while because I use case classes to model database entities that have more than 22 fields in Play + Postgres Async. My solution in Scala 2.10 was to break the models into multiple case classes, but I find this solution hard to maintain and extend, and I was hoping I could implement something as described below after switching to Play 2.3.0-RC1 + Scala 2.11.0:

package entities

case class MyDbEntity(
  id: String,
  field1: String,
  field2: Boolean,
  field3: String,
  field4: String,
  field5: String,
  field6: String,
  field7: String,
  field8: String,
  field9: String,
  field10: String,
  field11: String,
  field12: String,
  field13: String,
  field14: String,
  field15: String,
  field16: String,
  field17: String,
  field18: String,
  field19: String,
  field20: String,
  field21: String,
  field22: String,
  field23: String,
) 

object MyDbEntity {
  import play.api.libs.json.Json
  import play.api.data._
  import play.api.data.Forms._

  implicit val entityReads = Json.reads[MyDbEntity]
  implicit val entityWrites = Json.writes[MyDbEntity]
}

对于读取"和写入",上面的代码无法使用以下消息进行编译:

The code above fails to compile with the following message for both the "Reads" and the "Writes":

No unapply function found

将读取"和写入"更新为:

Updating the "Reads" and "Writes" to:

  implicit val entityReads: Reads[MyDbEntity] = (
    (__ \ "id").read[Long] and
    (__ \ "field_1").read[String]
    ........
  )(MyDbEntity.apply _)  

  implicit val postWrites: Writes[MyDbEntity] = (
    (__ \ "id").write[Long] and
    (__ \ "user").write[String]
    ........
  )(unlift(MyDbEntity.unapply))

也不起作用:

  implementation restricts functions to 22 parameters

  value unapply is not a member of object models.MyDbEntity

我的理解是,Scala 2.11在功能上仍然有一些限制,并且像我上面所描述的那样尚无法实现.对于我来说,这似乎很奇怪,因为如果仍然不支持主要用户案例,我看不出取消对案例类的限制的好处,所以我想知道我是否缺少某些内容.

My understanding is that Scala 2.11 still has some limitations on functions and that something like what I described above is not possible yet. This seems weird to me as I don't see the benefit of lifting the restrictions on case classes if one it's major users cases is still not supported, so I'm wondering if I'm missing something.

非常欢迎提出问题或实施细节的指针!谢谢!

Pointers to issues or implementation details are more than welcome! Thanks!

推荐答案

开箱即用是有可能的,原因有以下几种:

This is not possible, out of the box, for several reasons:

  • 首先,正如 gourlaysama 指出的那样,play-json库使用了

  • First, as gourlaysama pointed it out, play-json library used scala macro to avoid bolierplate code, and the current code relies of the unapply and apply methods to retrieve fields. This explains the first error message in your question.

第二个play-json库依赖于功能库当前仅可用于

Secondly play-json library relies of a functional library which currently works only with a fixed number of parameters corresponding to previous case class fields arity limit. This explains the second error message in your question.

但是,可以通过以下任一方法绕过第二点:

However it is possible to bypass the second point by either:

  • using shapeless Automatic Typeclass Derivation feature. Naveen Gattu has written an excellent gist doing exaclty so.

覆盖默认的函数生成器

首先,创建缺少的FunctionalBuilder:

class CustomFunctionalBuilder[M[_]](canBuild: FunctionalCanBuild[M]) extends FunctionalBuilder {

    class CustomCanBuild22[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22](m1: M[A1 ~ A2 ~ A3 ~ A4 ~ A5 ~ A6 ~ A7 ~ A8 ~ A9 ~ A10 ~ A11 ~ A12 ~ A13 ~ A14 ~ A15 ~ A16 ~ A17 ~ A18 ~ A19 ~ A20 ~ A21], m2: M[A22]) {
def ~[A23](m3: M[A23]) = new CustomCanBuild23[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23](canBuild(m1, m2), m3)

  def and[A23](m3: M[A23]) = this.~(m3)

  def apply[B](f: (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22) => B)(implicit fu: Functor[M]): M[B] =
  fu.fmap[A1 ~ A2 ~ A3 ~ A4 ~ A5 ~ A6 ~ A7 ~ A8 ~ A9 ~ A10 ~ A11 ~ A12 ~ A13 ~ A14 ~ A15 ~ A16 ~ A17 ~ A18 ~ A19 ~ A20 ~ A21 ~ A22, B](canBuild(m1, m2), { case a1 ~ a2 ~ a3 ~ a4 ~ a5 ~ a6 ~ a7 ~ a8 ~ a9 ~ a10 ~ a11 ~ a12 ~ a13 ~ a14 ~ a15 ~ a16 ~ a17 ~ a18 ~ a19 ~ a20 ~ a21 ~ a22 => f(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22) })

  def apply[B](f: B => (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22))(implicit fu: ContravariantFunctor[M]): M[B] =
  fu.contramap(canBuild(m1, m2), (b: B) => { val (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22) = f(b); new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(a1, a2), a3), a4), a5), a6), a7), a8), a9), a10), a11), a12), a13), a14), a15), a16), a17), a18), a19), a20), a21), a22) })

  def apply[B](f1: (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22) => B, f2: B => (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22))(implicit fu: InvariantFunctor[M]): M[B] =
  fu.inmap[A1 ~ A2 ~ A3 ~ A4 ~ A5 ~ A6 ~ A7 ~ A8 ~ A9 ~ A10 ~ A11 ~ A12 ~ A13 ~ A14 ~ A15 ~ A16 ~ A17 ~ A18 ~ A19 ~ A20 ~ A21 ~ A22, B](
    canBuild(m1, m2), { case a1 ~ a2 ~ a3 ~ a4 ~ a5 ~ a6 ~ a7 ~ a8 ~ a9 ~ a10 ~ a11 ~ a12 ~ a13 ~ a14 ~ a15 ~ a16 ~ a17 ~ a18 ~ a19 ~ a20 ~ a21 ~ a22 => f1(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22) },
    (b: B) => { val (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22) = f2(b); new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(new ~(a1, a2), a3), a4), a5), a6), a7), a8), a9), a10), a11), a12), a13), a14), a15), a16), a17), a18), a19), a20), a21), a22) }
  )

  def join[A >: A1](implicit witness1: <:<[A, A1], witness2: <:<[A, A2], witness3: <:<[A, A3], witness4: <:<[A, A4], witness5: <:<[A, A5], witness6: <:<[A, A6], witness7: <:<[A, A7], witness8: <:<[A, A8], witness9: <:<[A, A9], witness10: <:<[A, A10], witness11: <:<[A, A11], witness12: <:<[A, A12], witness13: <:<[A, A13], witness14: <:<[A, A14], witness15: <:<[A, A15], witness16: <:<[A, A16], witness17: <:<[A, A17], witness18: <:<[A, A18], witness19: <:<[A, A19], witness20: <:<[A, A20], witness21: <:<[A, A21], witness22: <:<[A, A22], fu: ContravariantFunctor[M]): M[A] =
  apply[A]((a: A) => (a: A1, a: A2, a: A3, a: A4, a: A5, a: A6, a: A7, a: A8, a: A9, a: A10, a: A11, a: A12, a: A13, a: A14, a: A15, a: A16, a: A17, a: A18, a: A19, a: A20, a: A21, a: A22))(fu)

  def reduce[A >: A1, B](implicit witness1: <:<[A1, A], witness2: <:<[A2, A], witness3: <:<[A3, A], witness4: <:<[A4, A], witness5: <:<[A5, A], witness6: <:<[A6, A], witness7: <:<[A7, A], witness8: <:<[A8, A], witness9: <:<[A9, A], witness10: <:<[A10, A], witness11: <:<[A11, A], witness12: <:<[A12, A], witness13: <:<[A13, A], witness14: <:<[A14, A], witness15: <:<[A15, A], witness16: <:<[A16, A], witness17: <:<[A17, A], witness18: <:<[A18, A], witness19: <:<[A19, A], witness20: <:<[A20, A], witness21: <:<[A21, A], witness22: <:<[A22, A], fu: Functor[M], reducer: Reducer[A, B]): M[B] =
  apply[B]((a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8, a9: A9, a10: A10, a11: A11, a12: A12, a13: A13, a14: A14, a15: A15, a16: A16, a17: A17, a18: A18, a19: A19, a20: A20, a21: A21, a22: A22) =>  reducer.append(reducer.append(reducer.append(reducer.append(reducer.append(reducer.append(reducer.append(reducer.append(reducer.append(reducer.append(reducer.append(reducer.append(reducer.append(reducer.append(reducer.append(reducer.append(reducer.append(reducer.append(reducer.append(reducer.append(reducer.append(reducer.unit(a1: A), a2: A), a3: A), a4: A), a5: A), a6: A), a7: A), a8: A), a9: A), a10: A), a11: A), a12: A), a13: A), a14: A), a15: A), a16: A), a17: A), a18: A), a19: A), a20: A), a21: A), a22: A))(fu)

  def tupled(implicit v: VariantExtractor[M]): M[(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22)] =
  v match {
    case FunctorExtractor(fu) => apply { (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8, a9: A9, a10: A10, a11: A11, a12: A12, a13: A13, a14: A14, a15: A15, a16: A16, a17: A17, a18: A18, a19: A19, a20: A20, a21: A21, a22: A22) => (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22) }(fu)
    case ContravariantFunctorExtractor(fu) => apply[(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22)] { (a: (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22)) => (a._1, a._2, a._3, a._4, a._5, a._6, a._7, a._8, a._9, a._10, a._11, a._12, a._13, a._14, a._15, a._16, a._17, a._18, a._19, a._20, a._21, a._22) }(fu)
    case InvariantFunctorExtractor(fu) => apply[(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22)]({ (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8, a9: A9, a10: A10, a11: A11, a12: A12, a13: A13, a14: A14, a15: A15, a16: A16, a17: A17, a18: A18, a19: A19, a20: A20, a21: A21, a22: A22) => (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22) }, { (a: (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22)) => (a._1, a._2, a._3, a._4, a._5, a._6, a._7, a._8, a._9, a._10, a._11, a._12, a._13, a._14, a._15, a._16, a._17, a._18, a._19, a._20, a._21, a._22) })(fu)
    }

  }

  class CustomCanBuild23[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23](m1: M[A1 ~ A2 ~ A3 ~ A4 ~ A5 ~ A6 ~ A7 ~ A8 ~ A9 ~ A10 ~ A11 ~ A12 ~ A13 ~ A14 ~ A15 ~ A16 ~ A17 ~ A18 ~ A19 ~ A20 ~ A21 ~ A22], m2: M[A23]) {
  }

}

,然后提供您自己的FunctionalBuilderOps实例:

and then by providing your own FunctionalBuilderOps instance:

implicit def customToFunctionalBuilderOps[M[_], A](a: M[A])(implicit fcb: FunctionalCanBuild[M]) = new CustomFunctionalBuilderOps[M, A](a)(fcb)

最后,关于第一点,我已发送拉动请求进行尝试以简化当前的实现.

Finally, regarding the first point, I have sent a pull request to try to simplify the current implementation.

这篇关于Scala 2.11 + Play Framework 2.3中的22个字段限制Case类和函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆