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

io.atlassian.aws.dynamodb.Write.scala Maven / Gradle / Ivy

The newest version!
package io.atlassian.aws.dynamodb

import scalaz.Equal

object Write {
  sealed trait Mode {
    type Mode = this.type

    private[dynamodb] def result[V]: Option[V] => Result[V, Mode]
    private[dynamodb] def fail[V]: Result[V, Mode]
  }
  /**
   * A successful result should always return the written value,
   * it may be different for instance have a write time-stamp.
   *
   * Use UpdateValue to control this
   */
  sealed trait Result[+A, M <: Mode]

  object Mode {
    /**
     * Overwrite any existing value, provides no protection against multiple writers.
     *
     * PUT semantics.
     */
    case object Overwrite extends Mode {
      case class Replaced[V](old: V) extends Result[V, Overwrite.type]
      case object New extends Result[Nothing, Overwrite.type]

      private[dynamodb] def result[V]: Option[V] => Result[V, Overwrite.type] = {
        case Some(v) => Replaced(v)
        case None    => New
      }
      private[dynamodb] def fail[V]: Result[V, Overwrite.type] =
        ??? // should never happen, cannot fail
    }

    /**
     * Only put a value if there is no value currently.
     *
     * PutIfAbsent semantics.
     */
    case object Insert extends Mode {
      /** return the written value, it may be different for instance have a write time-stamp */
      case object New extends Result[Nothing, Insert.type]
      case object Failed extends Result[Nothing, Insert.type]

      // if Insert fails we get exception
      private[dynamodb] def result[V]: Option[V] => Result[V, Insert.type] = {
        case None    => New
        case Some(v) => throw new AssertionError(s"we should never get back old data if we are Inserting only, got $v")
      }
      private[dynamodb] def fail[V] = Failed
    }

    /**
     * Only put a value if there is a specific value currently.
     *
     * Update semantics
     */
    //    // this being a case class and not a case object means some funky casts, but they're safe
    //    case class Replace[A](a: A) extends Mode {
    //    }
    case object Replace extends Mode {
      /** return the written value */
      case object Wrote extends Result[Nothing, Replace.type]
      case object Failed extends Result[Nothing, Replace.type]

      private[dynamodb] def result[V]: Option[V] => Result[V, Replace.type] = {
        case Some(v) => Wrote
        case None    => throw new AssertionError(s"we should always get back old data if we are Replacing")
      }
      private[dynamodb] def fail[V] = Failed
    }
  }

  object Result {
    import Mode._
    implicit def ResultEqual[A: Equal, M <: Mode]: Equal[Result[A, M]] =
      Equal.equal {
        case (Overwrite.Replaced(a1), Overwrite.Replaced(a2)) => Equal[A].equal(a1.asInstanceOf[A], a2.asInstanceOf[A]) // cast required for 2.10
        case (Overwrite.New, Overwrite.New) => true
        case (Insert.New, Insert.New) => true
        case (Insert.Failed, Insert.Failed) => true
        case (Replace.Wrote, Replace.Wrote) => true
        case (Replace.Failed, Replace.Failed) => true
        case (_, _) => false
      }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy