app/services/DynamoSuperMode.scala (57 lines of code) (raw):
package services
import com.typesafe.scalalogging.StrictLogging
import models.DynamoErrors.DynamoGetError
import models.SuperModeRow
import models.SuperModeRow._
import software.amazon.awssdk.services.dynamodb.DynamoDbClient
import software.amazon.awssdk.services.dynamodb.model.{AttributeValue, QueryRequest}
import utils.Circe.dynamoMapToJson
import zio.{ZEnv, ZIO}
import zio.blocking.effectBlocking
import java.text.SimpleDateFormat
import java.time.Instant
import java.time.temporal.ChronoUnit
import java.util.Date
import scala.jdk.CollectionConverters._
class DynamoSuperMode(client: DynamoDbClient) extends StrictLogging {
private val tableName = s"super-mode-calculator-PROD"
private val dateFormat = new SimpleDateFormat("yyyy-MM-dd")
private val timestampFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
private def get(endDate: String, endTimestamp: String): ZIO[ZEnv, DynamoGetError, java.util.List[java.util.Map[String, AttributeValue]]] =
effectBlocking {
client.query(
QueryRequest
.builder()
.tableName(tableName)
.indexName("end")
.keyConditionExpression("endDate = :endDate AND endTimestamp > :endTimestamp")
.expressionAttributeValues(Map(
":endDate" -> AttributeValue.builder.s(endDate).build,
":endTimestamp" -> AttributeValue.builder.s(endTimestamp).build
).asJava)
.build()
).items()
}.mapError(DynamoGetError)
private def getRowsForDate(date: String, endTimestamp: String): ZIO[ZEnv, DynamoGetError, List[SuperModeRow]] =
get(date, endTimestamp).map(results =>
results.asScala
.map(item => dynamoMapToJson(item).as[SuperModeRow])
.flatMap {
case Right(row) => Some(row)
case Left(error) =>
logger.error(s"Failed to decode item from Dynamo: ${error.getMessage}")
None
}
.toList
.sortBy(_.endTimestamp)
)
def getCurrentSuperModeRows(): ZIO[ZEnv, DynamoGetError, List[SuperModeRow]] = {
/**
* Articles that are currently in super mode will have an endTimestamp later than now.
* Because the index partition key is endDate, we have to make 2 queries for today and tomorrow
*/
val today = Instant.now()
val tomorrow = today.plus(1, ChronoUnit.DAYS)
val endTimestamp = timestampFormat.format(Date.from(today))
ZIO.collectAll(List(
getRowsForDate(dateFormat.format(Date.from(today)), endTimestamp),
getRowsForDate(dateFormat.format(Date.from(tomorrow)), endTimestamp)
)).map(_.flatten)
}
}