Shapelessでジェネリック型のクラス(DynamoDBのコーデック)を派生しています。クラスのフィールドの順序がDynamoDBレスポンスの属性の順序と一致するというアイデアのみに基づいて、ケースクラスのフィールド名を使用せずに動作するバージョンがあります。これは、Generic
を使用し、通常はderiveHNil
,deriveHCons
アプローチを使用します(例:https://meta.plasm.us/posts/2015/11/08/type-classes-and-generic-derivation/)。ジェネリック型のクラス派生のためのShapelessレコードからのラベルの抽出方法
ここで、フィールド名を使用して関連するDynamoDB属性を検索するバージョンが必要です。私の現在の考え方は、ほとんどの場合、以前の(オーダーベースの)バージョンからのアプローチを再利用し、さらにコンパイラにLabelledGeneric
とshapeless.ops.record.Keys
を介してフィールド名を提供させることです。しかし、私は正しくKeys
機能を使用する方法に固執しています。
考え方は以下の通りです:その頭+尻尾にdecode
操作を実行するためにHList
を分解し、また、前述の頭からラベルを抽出:機能hconsDecoder
は一度に2つのことを行う必要があります。 LabelledGeneric
はのhconsDecoder
のタイプパラメータが関連情報を含むレコードのエントリになるように、フィールド上のラベルにHList
を提供する必要があります。しかし、Keys
はHList
でしか動作しないため、H :: HNil
を作成してKeys
を実行します。
は、ここで私が持っているコードの一部です:could not find implicit value for parameter c: shapeless.ops.hlist.IsHCons[m.Out]
:このコードを考えると
trait FieldDecoder[A] {
def decode(a: AttributeValue): Option[A]
}
trait RecordDecoder[A] {
def decode(s: Seq[Attribute]): Option[A]
}
object RecordDecoderInstances {
implicit val hnilDecoder = new RecordDecoder[HNil] {
override def decode(s: Seq[Attribute]): Option[HNil] = {
Some(HNil)
}
}
object toName extends Poly1 {
implicit def keyToName[A] = at[Symbol with A](_.name)
}
implicit def hconsDecoder[H: FieldDecoder, T <: HList: RecordDecoder](
implicit kk: Keys[H :: HNil]#Out,
m: Mapper[toName.type, Keys[H :: HNil]#Out]) =
new RecordDecoder[H :: T] {
override def decode(s: Seq[Attribute]): Option[H :: T] = {
val attrName = (kk map toName).head.asInstanceOf[String] // compile error here
for {
h <- implicitly[FieldDecoder[H]]
.decode(s.filter(_.name == attrName).head.value)
t <- implicitly[RecordDecoder[T]]
.decode(s.filterNot(_.name == attrName))
} yield h :: t
}
}
}
、コンパイルエラーは次のとおりです。私はimplicit not found
エラーのいくつかのバリエーションに直面して、同じものの異なるバージョンを試しました。結論としては、何らかの理由でH :: HNil
構成ではKeys
が機能しません。
これはShapelessでの私の最初の重大な試みであり、私が正しい方法をとっているかどうかはわかりません。私は、この特定のエラーと一般的な私のアプローチについての両方のフィードバックに感謝します。
このアプローチがネストされたケースクラスで機能するのだろうか? – Haspemulator