app/data/BakeLogs.scala (52 lines of code) (raw):

package data import com.amazonaws.services.dynamodbv2.model.AttributeValue import org.scanamo.query.{UniqueKeyConditions, UniqueKeys} import org.scanamo.syntax._ import models._ import org.scanamo.DynamoObject import services.Loggable import scala.annotation.tailrec import scala.jdk.CollectionConverters._ object BakeLogs extends Loggable { import Dynamo._ private val BATCH_SIZE = 25 private val BATCH_PAUSE = 1000 def save(bakeLog: BakeLog)(implicit dynamo: Dynamo): Unit = { // Make sure we don't try to save an empty string to Dynamo val safeMessageParts = bakeLog.messageParts.map(part => part.copy(text = if (part.text.nonEmpty) part.text else " ") ) val safeBakeLog = bakeLog.copy(messageParts = safeMessageParts) table.put(safeBakeLog).exec() } def list(bakeId: BakeId)(implicit dynamo: Dynamo): Iterable[BakeLog] = { table.query("bakeId" === bakeId).exec().flatMap(_.toOption) } def delete(bakeId: BakeId, attempt: Int = 0)(implicit dynamo: Dynamo ): Unit = { val logNumbers: Seq[Int] = table .query("bakeId" === bakeId) .exec() .flatMap(_.toOption) .map(_.logNumber) val uniqueKeyTuples: Seq[(BakeId, Int)] = logNumbers.map((bakeId, _)) uniqueKeyTuples.grouped(BATCH_SIZE).foreach { batch => val uniqueKeys: UniqueKeys[_] = (HashAndRangeKeyNames("bakeId", "logNumber"), batch.toSet) doDelete(uniqueKeys) // avoid overwhelming the DB by pausing briefly after each batch Thread.sleep(BATCH_PAUSE) } } type UniqueKeySet = Set[DynamoObject] implicit private val identityKeyConditions : UniqueKeyConditions[UniqueKeySet] = new UniqueKeyConditions[UniqueKeySet] { override def toDynamoObject(t: UniqueKeySet): Set[DynamoObject] = t } private def doDelete(logLines: UniqueKeys[_], attempt: Int = 0)(implicit dynamo: Dynamo ): Unit = { table.deleteAll(logLines).exec() } private def table(implicit dynamo: Dynamo) = dynamo.Tables.bakeLogs.table }