Skip to content

Commit

Permalink
Support DynamoDB's UpdateItemRequest (#288)
Browse files Browse the repository at this point in the history
* Add decodeItemResponse()

* Use Long.MaxValue instead of magic number
  • Loading branch information
saeltz authored Oct 7, 2021
1 parent 475953a commit 635dff9
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 9 deletions.
9 changes: 7 additions & 2 deletions src/main/scala/scynamo/Scynamo.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package scynamo

import cats.data.EitherNec
import software.amazon.awssdk.services.dynamodb.model.{GetItemResponse, QueryResponse, ScanResponse}
import software.amazon.awssdk.services.dynamodb.model.{GetItemResponse, QueryResponse, ScanResponse, UpdateItemResponse}
import cats.syntax.all._

import scala.jdk.CollectionConverters._
Expand All @@ -14,10 +14,15 @@ trait ScynamoFunctions {
else
Right(None)

def decodeUpdateItemResponse[A: ObjectScynamoDecoder](response: UpdateItemResponse): EitherNec[ScynamoDecodeError, Option[A]] =
if (response.hasAttributes)
ObjectScynamoDecoder[A].decodeMap(response.attributes()).map(Some(_))
else
Right(None)

def decodeQueryResponse[A: ObjectScynamoDecoder](response: QueryResponse): EitherNec[ScynamoDecodeError, List[A]] =
response.items().asScala.toList.traverse(ObjectScynamoDecoder[A].decodeMap(_))

def decodeScanResponse[A: ObjectScynamoDecoder](response: ScanResponse): EitherNec[ScynamoDecodeError, List[A]] =
response.items().asScala.toList.traverse(ObjectScynamoDecoder[A].decodeMap(_))

}
12 changes: 6 additions & 6 deletions src/test/scala/scynamo/ScynamoCodecProps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,15 @@ class ScynamoCodecProps extends Properties("ScynamoCodec") {

propertyWithSeed("decode.encode === id (option)", propertySeed) = Prop.forAll { value: Option[Int] => decodeAfterEncodeIsIdentity(value) }

propertyWithSeed("decode.encode === id (finite duration)", propertySeed) =
Prop.forAll(Gen.chooseNum(-9223372036854775807L, 9223372036854775807L)) { value =>
propertyWithSeed("decode.encode === id (finite duration)", propertySeed) = Prop.forAll(Gen.chooseNum(Long.MinValue + 1, Long.MaxValue)) {
value: Long =>
decodeAfterEncodeIsIdentity(Duration.fromNanos(value))
}
}

propertyWithSeed("decode.encode === id (duration)", propertySeed) =
Prop.forAll(Gen.chooseNum(-9223372036854775807L, 9223372036854775807L)) { value =>
propertyWithSeed("decode.encode === id (duration)", propertySeed) = Prop.forAll(Gen.chooseNum(Long.MinValue + 1, Long.MaxValue)) {
value: Long =>
decodeAfterEncodeIsIdentity(Duration.fromNanos(value): Duration)
}
}

propertyWithSeed("decode.encode === id (java duration)", propertySeed) = Prop.forAll { value: Long =>
decodeAfterEncodeIsIdentity(java.time.Duration.ofNanos(value))
Expand Down
23 changes: 22 additions & 1 deletion src/test/scala/scynamo/ScynamoTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ class ScynamoTest extends UnitTest {
result should ===(Right(None))
}

"return None if the update item response has no item" in {
val response = UpdateItemResponse.builder().build()
val result = for {
result <- Scynamo.decodeUpdateItemResponse[Map[String, AttributeValue]](response)
} yield result

result should ===(Right(None))
}

"return an empty List if the query response has no items" in {
val response = QueryResponse.builder().build()

Expand All @@ -37,7 +46,7 @@ class ScynamoTest extends UnitTest {
result should ===(Right(List.empty))
}

"return the decoded result if it has an item that is well formed" in {
"return the decoded get item result if it has an item that is well formed" in {
val input = Map("foo" -> "bar")

val result = for {
Expand All @@ -49,6 +58,18 @@ class ScynamoTest extends UnitTest {
result should ===(Right(Some(input)))
}

"return the decoded update item result if it has an item that is well formed" in {
val input = Map("foo" -> "bar")

val result = for {
encodedInput <- input.encodedMap
response = UpdateItemResponse.builder().attributes(encodedInput).build()
result <- Scynamo.decodeUpdateItemResponse[Map[String, String]](response)
} yield result

result should ===(Right(Some(input)))
}

"return the decoded query result if it has multiple items that are well formed" in {
val input1 = Map("foo" -> "bar")
val input2 = Map("Miami" -> "Ibiza")
Expand Down

0 comments on commit 635dff9

Please sign in to comment.