All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.scanamo.ops.AsyncFrameworks.scala Maven / Gradle / Ivy

package org.scanamo.ops

import cats.~>
import org.scanamo.ops.ScanamoOps.Results.*
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient
import software.amazon.awssdk.services.dynamodb.model.{ ConditionalCheckFailedException, TransactionCanceledException }

import java.util.concurrent.{ CompletableFuture, CompletionException }

object AsyncFrameworks {
  private[ops] val unwrapCompletionException: PartialFunction[Throwable, Throwable] = { case e: CompletionException =>
    e.getCause
  }

  /** Adapter for the framework-specific actions needed for dealing with Scanamo/DynamoDbAsyncClient.
    * DynamoDbAsyncClient uses java.util.concurrent.CompletableFuture, so there needs to be a way of converting that to
    * the framework's own asynchronous type (eg Future, IO, etc). We also need to be able to extract specific exceptions
    * from that type.
    */
  trait Adapter[F[_]] {
    def run[Out](fut: => CompletableFuture[Out]): F[Out]

    def exposeException[Out, E <: Exception](o: F[Out])(rF: PartialFunction[Throwable, E]): F[Either[E, Out]]
  }

  /** Helper for creating Scanamo interpreters for async frameworks like Future, Cats Effect, ZIO, all of which can use
    * DynamoDbAsyncClient and translate java.util.concurrent.CompletableFuture into their own types (eg IO, Future, etc)
    * for representing asynchronous processes.
    */
  class Interpreter[F[_]](client: DynamoDbAsyncClient, frameworkAdapter: Adapter[F]) extends (ScanamoOpsA ~> F) {

    import frameworkAdapter.*

    def runConditional[Out](fut: => CompletableFuture[Out]): F[Conditional[Out]] =
      exposeException(run(fut)) { case e: ConditionalCheckFailedException => e }

    def runTransact[Out](fut: => CompletableFuture[Out]): F[Transact[Out]] =
      exposeException(run(fut)) { case e: TransactionCanceledException => e }

    def apply[A](ops: ScanamoOpsA[A]): F[A] = ops match {
      case Put(req)               => run(client.putItem(JavaRequests.put(req)))
      case ConditionalPut(req)    => runConditional(client.putItem(JavaRequests.put(req)))
      case Get(req)               => run(client.getItem(req))
      case Delete(req)            => run(client.deleteItem(JavaRequests.delete(req)))
      case ConditionalDelete(req) => runConditional(client.deleteItem(JavaRequests.delete(req)))
      case Scan(req)              => run(client.scan(JavaRequests.scan(req)))
      case Query(req)             => run(client.query(JavaRequests.query(req)))
      case BatchWrite(req)        => run(client.batchWriteItem(req))
      case BatchGet(req)          => run(client.batchGetItem(req))
      case Update(req)            => run(client.updateItem(JavaRequests.update(req)))
      case ConditionalUpdate(req) => runConditional(client.updateItem(JavaRequests.update(req)))
      case TransactWriteAll(req)  => runTransact(client.transactWriteItems(JavaRequests.transactItems(req)))
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy