From bf6c413f1626747a4a30b15d1c6228c16d0362e4 Mon Sep 17 00:00:00 2001 From: Valerian Date: Wed, 9 Dec 2015 14:48:13 +0000 Subject: [PATCH 1/3] dynamodb : implicit Map[String, T] --- integration/src/it/scala/dynamodb/GameScore.scala | 10 +++++++--- src/main/scala/dynamodb/package.scala | 7 +++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/integration/src/it/scala/dynamodb/GameScore.scala b/integration/src/it/scala/dynamodb/GameScore.scala index 0da2de3..5430e03 100644 --- a/integration/src/it/scala/dynamodb/GameScore.scala +++ b/integration/src/it/scala/dynamodb/GameScore.scala @@ -27,7 +27,8 @@ case class GameScore( topScore: Long, topScoreDateTime: DateTime, wins: Long, - losses: Long + losses: Long, + extra: Map[String, String] = Map.empty ) object GameScore { @@ -69,6 +70,7 @@ object GameScore { val topScoreDateTime = "TopScoreDateTime" val wins = "Wins" val losses = "Losses" + val extra = "extra" } implicit object sameScoreSerializer extends DynamoDBSerializer[GameScore] { @@ -91,7 +93,8 @@ object GameScore { Attributes.topScore -> score.topScore, Attributes.topScoreDateTime -> fmt.print(score.topScoreDateTime), Attributes.wins -> score.wins, - Attributes.losses -> score.losses + Attributes.losses -> score.losses, + Attributes.extra -> implicitly[Map[String, String] => AttributeValue].apply(score.extra) ) override def fromAttributeMap(item: collection.mutable.Map[String, AttributeValue]) = @@ -101,7 +104,8 @@ 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 = implicitly[AttributeValue => Map[String, String]].apply(item(Attributes.extra)) ) } } diff --git a/src/main/scala/dynamodb/package.scala b/src/main/scala/dynamodb/package.scala index d4ce9a3..5b63351 100644 --- a/src/main/scala/dynamodb/package.scala +++ b/src/main/scala/dynamodb/package.scala @@ -277,4 +277,11 @@ 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) } From b25400e449f76f74138ab40be3f710af1e715567 Mon Sep 17 00:00:00 2001 From: Valerian Date: Fri, 11 Dec 2015 11:59:23 +0000 Subject: [PATCH 2/3] add support for traversable --- .../src/it/scala/dynamodb/GameScore.scala | 10 ++++--- .../src/it/scala/dynamodb/SampleData.scala | 8 ++++-- src/main/scala/dynamodb/mapper.scala | 4 +-- src/main/scala/dynamodb/package.scala | 27 +++++++++++++++++++ 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/integration/src/it/scala/dynamodb/GameScore.scala b/integration/src/it/scala/dynamodb/GameScore.scala index 5430e03..670b79f 100644 --- a/integration/src/it/scala/dynamodb/GameScore.scala +++ b/integration/src/it/scala/dynamodb/GameScore.scala @@ -28,7 +28,8 @@ case class GameScore( topScoreDateTime: DateTime, wins: Long, losses: Long, - extra: Map[String, String] = Map.empty + extra: Map[String, String] = Map.empty, + seq: Seq[String] = Seq.empty ) object GameScore { @@ -71,6 +72,7 @@ object GameScore { val wins = "Wins" val losses = "Losses" val extra = "extra" + val seq = "seq" } implicit object sameScoreSerializer extends DynamoDBSerializer[GameScore] { @@ -94,7 +96,8 @@ object GameScore { Attributes.topScoreDateTime -> fmt.print(score.topScoreDateTime), Attributes.wins -> score.wins, Attributes.losses -> score.losses, - Attributes.extra -> implicitly[Map[String, String] => AttributeValue].apply(score.extra) + mkAttribute(Attributes.extra -> score.extra), + mkAttribute(Attributes.seq -> score.seq) ) override def fromAttributeMap(item: collection.mutable.Map[String, AttributeValue]) = @@ -105,7 +108,8 @@ object GameScore { topScoreDateTime = fmt.parseDateTime(item(Attributes.topScoreDateTime)), wins = item(Attributes.wins), losses = item(Attributes.losses), - extra = implicitly[AttributeValue => Map[String, String]].apply(item(Attributes.extra)) + 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 5b63351..8ebf3a8 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 { /** @@ -284,4 +291,24 @@ package object dynamodb { 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) + } } From db37024a6df85137809abd1d0d8935f1a919abcf Mon Sep 17 00:00:00 2001 From: Valerian Date: Fri, 11 Dec 2015 12:28:13 +0000 Subject: [PATCH 3/3] maybe Iterable should be just Set --- src/main/scala/dynamodb/package.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/dynamodb/package.scala b/src/main/scala/dynamodb/package.scala index 8ebf3a8..97dfb47 100644 --- a/src/main/scala/dynamodb/package.scala +++ b/src/main/scala/dynamodb/package.scala @@ -141,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 */