From 6e19c9b5eedff92d125ce59c55950098e28ff56b Mon Sep 17 00:00:00 2001 From: Avinder Bahra Date: Tue, 30 Jan 2024 08:15:33 +0000 Subject: [PATCH] add `maybeFound` convenience extension method (#376) --- .../zio/dynamodb/TypeSafeApiCrudSpec.scala | 24 ++++++++++++++++++- .../src/main/scala/zio/dynamodb/syntax.scala | 20 ++++++++++++++++ .../dynamodblocal/DynamoDBLocalMain.scala | 7 +++--- 3 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 dynamodb/src/main/scala/zio/dynamodb/syntax.scala diff --git a/dynamodb/src/it/scala/zio/dynamodb/TypeSafeApiCrudSpec.scala b/dynamodb/src/it/scala/zio/dynamodb/TypeSafeApiCrudSpec.scala index 74bcd6d6..db15b34d 100644 --- a/dynamodb/src/it/scala/zio/dynamodb/TypeSafeApiCrudSpec.scala +++ b/dynamodb/src/it/scala/zio/dynamodb/TypeSafeApiCrudSpec.scala @@ -5,7 +5,8 @@ import zio.test._ import zio.test.assertTrue import zio.test.Assertion._ import zio.dynamodb.DynamoDBError.ItemError -import zio.dynamodb.DynamoDBQuery.{ deleteFrom, forEach, get, put, scanAll, update } +import zio.dynamodb.DynamoDBQuery.{ deleteFrom, forEach, get, put, putItem, scanAll, update } +import zio.dynamodb.syntax._ import zio.Chunk import software.amazon.awssdk.services.dynamodb.model.ConditionalCheckFailedException import zio.stream.ZStream @@ -51,6 +52,27 @@ object TypeSafeApiCrudSpec extends DynamoDBLocalSpec { } yield assertTrue(p == person) } }, + test("and get using maybeFound extension method") { + withSingleIdKeyTable { tableName => + val person = Person("1", "Smith", Some("John"), 21) + for { + _ <- put(tableName, person).execute + personFound <- get(tableName)(Person.id.partitionKey === "1").execute.maybeFound + personNotFound <- get(tableName)(Person.id.partitionKey === "DOES_NOT_EXIST").execute.maybeFound + _ <- putItem(tableName, Item("id" -> "WILL_GIVE_DECODE_ERROR")).execute + decodeErrorExit <- + get(tableName)(Person.id.partitionKey === "WILL_GIVE_DECODE_ERROR").execute.maybeFound.exit + } yield assertTrue(personFound == Some(person) && personNotFound == None) && assert(decodeErrorExit)( + fails( + equalTo( + DynamoDBError.ItemError.DecodingError( + "field 'surname' not found in Map(Map(String(id) -> String(WILL_GIVE_DECODE_ERROR)))" + ) + ) + ) + ) + } + }, test("with condition expression that id not exists fails when item exists") { withSingleIdKeyTable { tableName => val person = Person("1", "Smith", Some("John"), 21) diff --git a/dynamodb/src/main/scala/zio/dynamodb/syntax.scala b/dynamodb/src/main/scala/zio/dynamodb/syntax.scala new file mode 100644 index 00000000..8fa6a9fa --- /dev/null +++ b/dynamodb/src/main/scala/zio/dynamodb/syntax.scala @@ -0,0 +1,20 @@ +package zio.dynamodb + +import zio.ZIO + +object syntax { + implicit class MaybeFound[R, A](zio: ZIO[R, DynamoDBError, Either[DynamoDBError.ItemError, A]]) { + + /** + * Moves Left[ItemError.DecodingError] to the error channel and returns Some(a) if the item is found else None + * eg {{{ DynamoDBQuery.get("table")(Person.id.partitionKey === 1).execute.maybeFound }}} + */ + def maybeFound: ZIO[R, DynamoDBError, Option[A]] = + zio.flatMap { + case Left(e @ DynamoDBError.ItemError.DecodingError(_)) => ZIO.fail(e) + case Left(DynamoDBError.ItemError.ValueNotFound(_)) => ZIO.succeed(None) + case Right(a) => ZIO.succeed(Some(a)) + } + } + +} diff --git a/examples/src/main/scala/zio/dynamodb/examples/dynamodblocal/DynamoDBLocalMain.scala b/examples/src/main/scala/zio/dynamodb/examples/dynamodblocal/DynamoDBLocalMain.scala index 290de7bc..12b58277 100644 --- a/examples/src/main/scala/zio/dynamodb/examples/dynamodblocal/DynamoDBLocalMain.scala +++ b/examples/src/main/scala/zio/dynamodb/examples/dynamodblocal/DynamoDBLocalMain.scala @@ -13,6 +13,7 @@ import zio.dynamodb.DynamoDBExecutor import zio.dynamodb.DynamoDBQuery.get import zio.dynamodb.DynamoDBQuery.put import zio.dynamodb.ProjectionExpression +import zio.dynamodb.syntax._ import zio.schema.DeriveSchema import zio.schema.Schema @@ -66,9 +67,9 @@ object DynamoDBLocalMain extends ZIOAppDefault { val examplePerson = Person(1, "avi") private val program = for { - _ <- put("person", examplePerson).execute - person <- get("person")(Person.id.partitionKey === 1).execute - _ <- zio.Console.printLine(s"hello $person") + _ <- put("person", examplePerson).execute + maybePerson <- get("person")(Person.id.partitionKey === 1).execute.maybeFound + _ <- zio.Console.printLine(s"hello $maybePerson") } yield () override def run =