Scalaquery: фильтр по «любой» -комбинации условий - PullRequest
3 голосов
/ 29 июня 2011

Я хочу присоединиться к списку фильтров произвольной длины с or. Если список будет фиксированной длины, он будет выглядеть так:

query.filter(filters(0) || filters(1) || … || filter(n))

Объединить фильтры с and будет легко:

for (filter ← filters)
    query = query.filter(filter)

Объединить вещи, которые оцениваются в Boolean s, с помощью or тоже легко:

val any = evaluateToBools.foldLeft(true)(
    (left: Boolean, right: Eval2Bool) =>
    left || right.evaluate
)

Обновление:

как я написал, было бы легко, если бы scalaquery filter был стандартным. к сожалению, scalaquery разрешает выполнение этих фильтров только механизмом sql.

поэтому мой конкретный вопрос будет: если у меня есть набор строковых кортежей:

val tms = Set( ("A","a"), ("B", "b"), ... )

и запрос с двумя столбцами «t» и «m»,

как мне сгенерировать фильтр, который представляет следующий SQL:

... WHERE/AND ( (t="A" and m="a") or (t="B" and m="b") or ... )

… или можно ли использовать операторы sql in с такими кортежами, как этот?

... WHERE (t,m) IN (("A","a"), ("B","b"), ...)

и если да, то как это сделать в скалярном запросе


Hack:

В настоящее время я делаю следующее:

val tms = markers map { tm ⇒ tm._1 +"||"+ tm._2 }
query.filter(d ⇒ d._4 ++"||"++ d._5 inSet tms)

... но это невыносимо нахально.

Решение

Я реализовал решение Стефана так:

rq = rq filter { d ⇒
    markers map { tm ⇒
        (d._4 is tm._1) && (d._5 is tm._2)
    } reduceLeft { _||_ }
}

Ответы [ 2 ]

4 голосов
/ 28 августа 2011

В Query.filter нет ничего, что отличало бы это от объединения предикатов для фильтрации коллекции Scala. Да, он имеет более сложный тип:

def filter[T](f: E => T)(implicit wt: CanBeQueryCondition[T]): Query[E, U] = ...

Но вы можете спокойно игнорировать класс типов CanBeQueryCondition и считать T равным Column[Boolean] или Column[Option[Boolean]], если вы используете этот тип для всех своих предикатов (что вы всегда можете сделать). *

Так, каков тип вашей последовательности filters? Я полагаю, в этом и заключается ваша проблема. Начнем с фильтрации коллекции Scala List[User]. Здесь предикаты должны иметь тип User => Boolean, и вы можете уменьшить примененные предикаты с ||, чтобы объединить их:

case class User(id: Int, name: String)

val users = List(
  User(1, "foo"),
  User(2, "bar"),
  User(3, "blub")
)

val filters = List(
  { u: User => u.id == 1 },
  { u: User => u.name == "bar" }
)

val filtered = users filter { u =>
  filters map { _(u) } reduceLeft { _ || _ }
}

Теперь мы добавим таблицу базы данных для этих User объектов:

class DBUsers extends Table[User]("USERS") {
  def id = column[Int]("ID")
  def name = column[String]("NAME")
  def * = id ~ name <> (User, User.unapply _)
}
object DBUsers extends DBUsers

Фильтрация Query[DBUsers] требует предикатов типа DBUsers => Column[Boolean]:

val dbFilters = List(
  { u: DBUsers => u.id === 1 },
  { u: DBUsers => u.name === "bar" }
)

Комбинация и применение фильтров точно такие же, как и раньше:

val dbFiltered = DBUsers filter { u =>
  dbFilters map { _(u) } reduceLeft { _ || _ }
}

Относительно inSet метода для кортежей: я думаю, что это хорошая идея. Пожалуйста, отправьте запрос на улучшение. Некоторые системы баз данных могут поддерживать его изначально, а для других может использоваться кодировка, описанная в этом ответе.

0 голосов
/ 29 июня 2011

Как насчет этого?

query.filter(filters reduceLeft (_ || _))
...