Item
?例如在某些情况下忽略输入参数我不满意!
import shapeless.labelled.FieldType
import shapeless.{::, DepFn2, HList, HNil, LabelledGeneric, Witness}
import scala.collection.mutable
// mock of sdk item
class Item(val map: mutable.Map[String, Any] = mutable.Map[String, Any]()) {
def getString(attrName: String): String = map.get(attrName).get.asInstanceOf[String]
def getInt(attrName: String): Int = map.get(attrName).get.asInstanceOf[Int]
def getBoolean(attrName: String): Boolean = map.get(attrName).get.asInstanceOf[Boolean]
// def getMap(attrName: String): Map[String, String] = Map("attrName" -> "attrValue")
def setString(attrName: String, value: String): Unit = map.put(attrName, value)
def setInt(attrName: String, value: Int): Unit = map.put(attrName, value)
def setBoolean(attrName: String, value: Boolean): Unit = map.put(attrName, value)
override def toString() = map.toString()
}
trait ItemEncoder[A] extends DepFn2[String, A] {
type Out = Item
}
object ItemEncoder {
def apply[A](implicit encoder: ItemEncoder[A]): ItemEncoder[A] = encoder
def instance[A](f: (String, A) => Item): ItemEncoder[A] =
new ItemEncoder[A] {
override def apply(attrName: String, value: A): Out = f(attrName, value)
}
}
implicit val stringEncoder: ItemEncoder[String] =
ItemEncoder.instance { (attrName, value) =>
val item = new Item()
item.setString(attrName, value)
item
}
implicit val intEncoder: ItemEncoder[Int] =
ItemEncoder.instance { (attrName, value) =>
val item = new Item()
item.setInt(attrName, value)
item
}
implicit val booleanEncoder: ItemEncoder[Boolean] =
ItemEncoder.instance { (attrName, value) =>
val item = new Item()
item.setBoolean(attrName, value)
item
}
implicit val hnilEncoder: ItemEncoder[HNil] =
ItemEncoder.instance((attrName, value) => new Item())
def merge(i1: Item, i2: Item): Item = new Item(i1.map ++ i2.map)
implicit def hlistEncoder[K <: Symbol, L, H, T <: HList](
implicit
witness: Witness.Aux[K],
hEncoder: ItemEncoder[H],
tEncoder: ItemEncoder[T]
): ItemEncoder[FieldType[K, H] :: T] = {
ItemEncoder.instance { (_, value) =>
val attrName = witness.value.name
merge(hEncoder.apply(attrName, value.head), tEncoder.apply(attrName, value.tail))
}
}
implicit def genericEncoder[A, R](
implicit
generic: LabelledGeneric.Aux[A, R],
itemEncoder: ItemEncoder[R]
): ItemEncoder[A] =
ItemEncoder.instance { (attrName, value) =>
itemEncoder.apply(attrName, generic.to(value))
}
case class Person(name: String, age: Int, married: Boolean, manager: Boolean)
case class IceCream(name: String, subName: String, price: Int)
val genericPerson = LabelledGeneric[Person].to(Person("bob", 37, true, true))
def encode[A](toEncode: A)(implicit itemEncoder: ItemEncoder[A]) =
itemEncoder("", toEncode)
也许最好使用ToMap
或类似的内容,然后将其转换为Item
答案 0 :(得分:0)
在深入讨论该主题后,我设法实现ItemEncoder
,将具有任意嵌套的案例类转换为Item
,如下所示:
import com.amazonaws.services.dynamodbv2.document.Item
import shapeless.labelled.FieldType
import shapeless.{::, HList, HNil, LabelledGeneric, Witness, _}
trait ItemEncoder[A] {
def encode(value: A): Item
}
object ItemEncoder {
def apply[A](implicit encoder: ItemEncoder[A]): ItemEncoder[A] = encoder
def instance[A](f: A => Item): ItemEncoder[A] =
new ItemEncoder[A] {
override def encode(value: A): Item = f(value)
}
implicit def stringEncoder[K <: Symbol, V <: String](
implicit witness: Witness.Aux[K]
): ItemEncoder[FieldType[K, V]] =
instance { value =>
val item = new Item
item.withString(witness.value.name, value)
item
}
implicit def intEncoder[K <: Symbol, V <: Int](
implicit witness: Witness.Aux[K]
): ItemEncoder[FieldType[K, V]] =
instance { value =>
val item = new Item
item.withInt(witness.value.name, value)
item
}
implicit def booleanEncoder[K <: Symbol, V <: Boolean](
implicit witness: Witness.Aux[K]
): ItemEncoder[FieldType[K, V]] =
instance { value =>
val item = new Item
item.withBoolean(witness.value.name, value)
item
}
// K is key, A is value, R is HList representation of A
implicit def nestedClassEncoder[K <: Symbol, A, R](
implicit
witness: Witness.Aux[K],
generic: LabelledGeneric.Aux[A, R],
encoder: ItemEncoder[R]
): ItemEncoder[FieldType[K, A]] =
instance { value =>
val i = encoder.encode(generic.to(value))
val item = new Item
val m = new java.util.HashMap[String, Any]()
item.withMap(witness.value.name, i.asMap())
item
}
import cats.Monoid
implicit val itemMonoid: Monoid[Item] = new Monoid[Item] {
override def empty: Item = new Item()
override def combine(x: Item, y: Item): Item = {
val m = x.asMap
m.putAll(y.asMap())
Item.fromMap(m)
}
}
implicit val hnilEncoder: ItemEncoder[HNil] =
instance(_ => new Item())
implicit def hlistEncoder[H, T <: HList](
implicit
hEncoder: Lazy[ItemEncoder[H]],
tEncoder: ItemEncoder[T],
monoid: Monoid[Item]
): ItemEncoder[H :: T] =
instance { value =>
// println("hlist enc")
val itemX = hEncoder.value.encode(value.head)
val itemY = tEncoder.encode(value.tail)
monoid.combine(itemX, itemY)
}
implicit def genericEncoder[A, R](
implicit
generic: LabelledGeneric.Aux[A, R],
itemEncoder: Lazy[ItemEncoder[R]]
): ItemEncoder[A] =
instance { value =>
// println("gen enc")
itemEncoder.value.encode(generic.to(value))
}
def encode[A](toEncode: A)(implicit itemEncoder: ItemEncoder[A]) =
itemEncoder.encode(toEncode)
}
目前的实施有点简化。因此,它仅包含ItemEncoder
,String
和Int
等基本类型的Boolean
实现。但是其他原始类型可以通过使用现有的类型来轻松添加。
您可以在Git
上找到QuickCheck测试的完整实施