Многократная ИЛИ фильтрация с Slick - PullRequest
1 голос
/ 04 мая 2019

Здесь я фильтрую таблицу по 1 столбцу (keyId) и 1 значению (keyId), а тип результата - Необязательно, это правильно.

override def findByKeyId(keyId: String): Future[Option[Event]] =
    db.run(events.filter(_.keyId === keyId).result.headOption)

Теперь мне нужен фильтр по 1 столбцу (keyId) и нескольким значениям.

override def findByKeyIdBulk(keyIdSeq: Seq[Option[String]]): Future[Seq[Option[Event]]] = {

    db.run(
      events.filter { event =>
        keyIdSeq
          .map(_.map(keyId => event.keyId === keyId))
          .collect({ case Some(criteria) => criteria })
          .reduceLeftOption(_ || _)
          .getOrElse(true: Rep[Boolean])
      }.result
    ) // Future[Seq[Event]]

  }

В этом коде выражение типа Future[Seq[Event]] не соответствует Future[Seq[Option[Event]]]

Как исправить?

Ответы [ 2 ]

2 голосов
/ 05 мая 2019

Я думаю, вы неправильно поняли смысл Option[T] в качестве возвращаемого значения.Возвращение Seq[Option[T]] - это анти-паттерн, и вот почему:

Option[T] имеет смысл, когда нет гарантии, что вы что-нибудь найдете.FindById - отличный пример того, где это полезно - мы либо находим что-то и получаем Some(value), либо не получаем и получаем None.

Но если вы планируете найти по нескольким идентификаторам и хотите Seq найденных значений, тогда есть два случая: либо Seq пусто и ничего не найдено, либо Seq содержит некоторые элементы.Нет смысла иметь Option[T] внутри Seq, потому что внутри последовательности не будет никаких None s.Вы будете вынуждены использовать дополнительное сопоставление с образцом или дополнительную карту, которая абсолютно бессмысленна.

Я думаю, вам будет лучше изменить сигнатуру типа на Future[Seq[Event]]

1 голос
/ 04 мая 2019

Вызов events.result приведет к возврату Future[Seq[Event]].Использование filter не изменит этого, поэтому результирующий тип по-прежнему будет Future[Seq[Event]].Чтобы изменить его на Future[Seq[Option[Event]]], вам нужно поднять значения до Option[Event]:

db.run(
  events.filter { event =>
    keyIdSeq
      .map(_.map(keyId => event.keyId === keyId))
      .collect({ case Some(criteria) => criteria })
      .reduceLeftOption(_ || _)
      .getOrElse(true: Rep[Boolean])
  }
  .map(_.map(Option(_))) //lifting Event to Option[Event]
  .result
) // Future[Seq[Option[Event]]]
...