Вычислить производный столбец в выбранном выводе - Scala Slick 3.2.3 - PullRequest
0 голосов
/ 08 марта 2020

Я пытаюсь написать REST API для извлечения данных, используя Scala Slick 3.2.3. Есть ли способ вычислить производный столбец и включить его в возвращенный вывод?

Моя модель:

case class Task(id: Option[TaskId], title: String, dueOn: String, status: String, createdAt: String, updatedAt: String)

Класс таблицы:

class TasksTable(tag: Tag) extends Table[Task](tag, _tableName = "TASKS") {
  def id: Rep[TaskId] = column[TaskId]("ID", O.PrimaryKey, O.AutoInc)
  def title: Rep[String] = column[String]("TITLE")
  def dueOn: Rep[String] = column[String]("DUE_ON")
  def status: Rep[String] = column[String]("STATUS")
  def createdAt: Rep[String] = column[String]("CREATED_AT")
  def updatedAt: Rep[String] = column[String]("UPDATED_AT")
  def * = (id.?, title, dueOn, status, createdAt, updatedAt) <> ((Task.apply _).tupled, Task.unapply)
}

DAO:

object TasksDao extends BaseDao {
  def findAll: Future[Seq[Task]] = tasksTable.result
}

Я хочу добавить столбец в ответ json с именем timeline со значениями "просрочено", "сегодня", "завтра", "наступает" и т. Д. c. рассчитано на основе значения dueOn.

Я попытался выполнить поиск, но не смог найти никакой помощи. Любая помощь с примером или указателями будет высоко ценится. Спасибо!

1 Ответ

1 голос
/ 08 марта 2020

Сначала я бы начал с определения модели enum для временной шкалы:

object Timelines extends Enumeration {
  type Timeline = Value
  val Overdue: Timeline = Value("overdue")
  val Today: Timeline = Value("today")
  val Tomorrow: Timeline = Value("tomorrow")
  val Upcoming: Timeline = Value("upcoming")
}

Затем я бы изменил тип столбца dueOne с обычного String на LocalDate - это будет легче сделать на уровне DAO, поэтому Slick будет обрабатывать ошибки парсинга для нас. Таким образом, необходимо определить пользовательский тип для LocalDate (см. Более подробную информацию: http://scala-slick.org/doc/3.0.0/userdefined.html#using -custom-scalar-types-in-query ).

// Define mapping between String and LocalDate
private val defaultDateFormat: DateTimeFormatter = DateTimeFormatter.ISO_DATE // replace it with formatter you use for a date

def stringDateColumnType(format: DateTimeFormatter): BaseColumnType[LocalDate] = {
 MappedColumnType.base[LocalDate, String](_.format(format), LocalDate.parse(_, format))
}

implicit val defaultStringDateColumnType: BaseColumnType[LocalDate] = stringDateColumnType(defaultDateFormat)

private val defaultDateFormat: DateTimeFormatter = DateTimeFormatter.ISO_DATE // replace it with formatter you use for a date

// Change `dueOn` from String to LocalDate
case class Task(id: Option[TaskId], title: String, dueOn: LocalDate, status: String, createdAt: String, updatedAt: String)

class TasksTable(tag: Tag) extends Table[Task](tag, _tableName = "TASKS") {
  def id: Rep[TaskId] = column[TaskId]("ID", O.PrimaryKey, O.AutoInc)
  def title: Rep[String] = column[String]("TITLE")
  def dueOn: Rep[LocalDate] = column[LocalDate]("DUE_ON") // Then replace column type
  def status: Rep[String] = column[String]("STATUS")
  def createdAt: Rep[String] = column[String]("CREATED_AT")
  def updatedAt: Rep[String] = column[String]("UPDATED_AT")
  def * = (id.?, title, dueOn, status, createdAt, updatedAt) <> ((Task.apply _).tupled, Task.unapply)
}

Затем определите Модель уровня API TaskResponse с новым дополнительным полем timeline:

case class TaskResponse(id: Option[TaskId], title: String, dueOn: LocalDate, status: String, createdAt: String, updatedAt: String, timeline: Timeline)

  object TaskResponse {
    import Timelines._
    def fromTask(task: Task): TaskResponse = {
      val timeline = dueOnToTimeline(task.dueOn)
     TaskResponse(task.id, task.title, task.dueOn, task.status, task.createdAt, task.updatedAt, timeline)
    }

    def dueOnToTimeline(dueOn: LocalDate): Timeline = {
      val today = LocalDate.now()
      Period.between(today, dueOn).getDays match {
        case days if days < 0 => Overdue
        case 0 => Today
        case 1 => Tomorrow
        case _ => Upcoming
      }
    }
  }

Затем вы можете создать TasksService, отвечающий за бизнес-логи c конвертации:

  class TasksService(dao: TasksDao)(implicit ec: ExecutionContext) {
    def findAll: Future[Seq[TaskResponse]] = {
      dao.findAll.map(_.map(TaskResponse.fromTask))
    }
  }

Надежда это помогает!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...