Andrei Markhel
Andrei Markhel

Reputation: 175

Scala Slick Multiply filters dependent on conditions. Refactoring

All. Here is my code -

def searchGames(location: Location, results: List[TournamentResult], roles: 
    List[Role], player: String, players: List[String], startPl: Int = 6, 
    endPl:Int = 30, startR: Int = 1, endR: Int = 1000, sy: Int = 2012, ey: 
    Int = 2017, sm: Int = 0, em: Int = 12, sd: Int = 0, ed: Int = 32) = {

  val filtered2 = if (location != Location.SUMRAK) games.filter(_.location === location.name) else games
  val filtered3 = if (startPl > 0) filtered2.filter(_.playersSize >= startPl) else filtered2
  val filtered4 = if (endPl > 0) filtered3.filter(_.playersSize <= endPl) else filtered3
  val filtered5 = if (startR > 0) filtered4.filter(_.rounds >= startR) else filtered4
  val filtered6 = if (endR > 0) filtered5.filter(_.rounds <= endR) else filtered5
  val filtered7 = if (results != Nil) {
    filtered6.filter(a => a.tournamentResult.inSet(results.map(r => r.descr)))
  } else filtered6
  val filtered8 = filtered7.filter(a => (a.year === sy && a.month >= sm && a.day >= sd) || (a.year === ey && a.month <= em && a.day <= ed) || (a.year > sy && a.year < ey))
  val filtered9 = if (player != null && !player.isEmpty) filtered8.filter(_.players like s"%$player%") else filtered8
  val filtered14 = filtered9.map(a => (a.gameId, a.location, a.tournamentResult, a.players, a.playersSize, a.rounds, a.year, a.month, a.day))
  filtered14.result
}

It looks nor functional nor pretty. I am relatively newbie to Slick, can you suggest how to refactor it? Slick version is 3.0. I think there should be some "pattern" to extract and simplify the code, but I can't figure out it.

Upvotes: 0

Views: 120

Answers (1)

Dan M
Dan M

Reputation: 111

The documentation for queries in slick provides a good example: Queries - Slick 3.0.0 documentation - Sorting and Filtering

In short, create a list of Option[criteria] (actually Rep[Boolean]), collect the ones that are valid and && them together.

Something like this:

val filters = (x:GamesTable) => List(
  if (startPl > 0) Some(x.playersSize >= startPl) else None,
  if (endPl > 0) Some(x.playersSize <= endPl) else None,
  if (startR > 0) Some(x.rounds >= startR) else None,
  if (endR > 0) Some(x.rounds <= endR) else None
).collect{case Some(criteria)  => criteria}.reduceLeft(_ && _) 

games.filter( filters ) 

Makes a nice clean dynamic query.

Upvotes: 2

Related Questions