diff --git a/integration/src/it/scala/dynamodb/GameScore.scala b/integration/src/it/scala/dynamodb/GameScore.scala index 0da2de3..670b79f 100644 --- a/integration/src/it/scala/dynamodb/GameScore.scala +++ b/integration/src/it/scala/dynamodb/GameScore.scala @@ -27,7 +27,9 @@ case class GameScore( topScore: Long, topScoreDateTime: DateTime, wins: Long, - losses: Long + losses: Long, + extra: Map[String, String] = Map.empty, + seq: Seq[String] = Seq.empty ) object GameScore { @@ -69,6 +71,8 @@ object GameScore { val topScoreDateTime = "TopScoreDateTime" val wins = "Wins" val losses = "Losses" + val extra = "extra" + val seq = "seq" } implicit object sameScoreSerializer extends DynamoDBSerializer[GameScore] { @@ -91,7 +95,9 @@ object GameScore { Attributes.topScore -> score.topScore, Attributes.topScoreDateTime -> fmt.print(score.topScoreDateTime), Attributes.wins -> score.wins, - Attributes.losses -> score.losses + Attributes.losses -> score.losses, + mkAttribute(Attributes.extra -> score.extra), + mkAttribute(Attributes.seq -> score.seq) ) override def fromAttributeMap(item: collection.mutable.Map[String, AttributeValue]) = @@ -101,7 +107,9 @@ object GameScore { topScore = item(Attributes.topScore), topScoreDateTime = fmt.parseDateTime(item(Attributes.topScoreDateTime)), wins = item(Attributes.wins), - losses = item(Attributes.losses) + losses = item(Attributes.losses), + extra = item(Attributes.extra).as[Map[String, String]], // or .as + seq = item(Attributes.seq).as[Seq[String]] // or .as ) } } diff --git a/integration/src/it/scala/dynamodb/SampleData.scala b/integration/src/it/scala/dynamodb/SampleData.scala index a9a0f7c..7426eb1 100644 --- a/integration/src/it/scala/dynamodb/SampleData.scala +++ b/integration/src/it/scala/dynamodb/SampleData.scala @@ -114,7 +114,9 @@ object SampleData { topScore = 5842, topScoreDateTime = DateTime.now.minusDays(1), wins = 21, - losses = 72 + losses = 72, + extra = Map("key1" -> "value1"), + seq = Seq("1", "a") ), GameScore( userId = "101", @@ -130,7 +132,9 @@ object SampleData { topScore = 24, topScoreDateTime = DateTime.now.minusDays(3), wins = 4, - losses = 9 + losses = 9, + extra = Map("key2" -> "value2", "key3" -> "value3"), + seq = Seq("4", "d") ), GameScore( diff --git a/src/main/scala/dynamodb/mapper.scala b/src/main/scala/dynamodb/mapper.scala index 10f95c2..32a8c63 100644 --- a/src/main/scala/dynamodb/mapper.scala +++ b/src/main/scala/dynamodb/mapper.scala @@ -83,7 +83,7 @@ trait DynamoDBSerializer[T] { * {{{ * override def toAttributeMap(obj: Foo): Map[String, AttributeValue] = * Map( - * mkAtrribute("company", obj.company), + * mkAttribute("company", obj.company), * ... * ) * }}} @@ -97,7 +97,7 @@ trait DynamoDBSerializer[T] { * {{{ * override def toAttributeMap(obj: Foo): Map[String, AttributeValue] = * Map( - * mkAtrribute("company" -> obj.company), + * mkAttribute("company" -> obj.company), * ... * ) * }}} diff --git a/src/main/scala/dynamodb/package.scala b/src/main/scala/dynamodb/package.scala index d4ce9a3..97dfb47 100644 --- a/src/main/scala/dynamodb/package.scala +++ b/src/main/scala/dynamodb/package.scala @@ -17,10 +17,17 @@ package com.github.dwhjames.awswrap +import java.util + import scala.collection.JavaConverters._ import com.amazonaws.services.dynamodbv2.model._ +import scala.collection.generic.{IsTraversableOnce, CanBuildFrom} +import scala.language.higherKinds +import scala.language.implicitConversions + + package object dynamodb { /** @@ -134,7 +141,7 @@ package object dynamodb { /** String to a string AttributeValue */ implicit val stringToAttributeValue = (x: String) => new AttributeValue().withS(x) /** String collection to a string set AttributeValue */ - implicit val stringIterableToAttributeValue = (x: Iterable[String]) => new AttributeValue().withSS(x.asJavaCollection) + implicit val stringIterableToAttributeValue = (x: Set[String]) => new AttributeValue().withSS(x.asJavaCollection) /** Double to a numeric AttributeValue */ @@ -277,4 +284,31 @@ package object dynamodb { /** string set AttributeValue to Set[BigDecimal] */ implicit val attributeValueToBigDecimalSet = (x: AttributeValue) => catchAndRethrowConversion { x.getSS.asScala.map(BigDecimal(_)).toSet } + + + import scala.collection.JavaConversions._ + + implicit def attributeValueToMapString[T](implicit to: AttributeValue => T): AttributeValue => Map[String, T] = (x: AttributeValue) => catchAndRethrowConversion { x.getM.mapValues(to(_)).toMap } + + implicit def mapStringToAttributeValue[T](implicit to: T => AttributeValue): Map[String, T] => AttributeValue = (x: Map[String, T]) => new AttributeValue().withM(x.mapValues(to).asJava) + + implicit def decodeCanBuildFrom[A, C[_]](implicit bf: CanBuildFrom[Nothing, A, C[A]], conv: AttributeValue => A): AttributeValue => C[A] = { + (x: AttributeValue) => + val builder = bf() + val list = x.getL + builder ++= list.map(conv) + builder.result() + } + + implicit def encodeTraversableOnce[A0, C[_]](implicit + e: A0 => AttributeValue, + is: IsTraversableOnce[C[A0]] {type A = A0} + ): C[A0] => AttributeValue = { x => + val xx = is.conversion(x) + val list = new util.ArrayList[AttributeValue]() + xx.foreach { elem => + list.add(e(elem)) + } + new AttributeValue().withL(list) + } }