3

I'm trying to apply a series of optional filtering operations to a query by using a list of the operations and folding over the list.

val table = TableQuery[Fizz]
val filters = List(filter1(option1)_, filter2(option2)_, filter3(option3)_)
val filteredQuery = filters.foldLeft(table){(q, filter) => filter(q)}

The partially applied filter functions have a signature of

Query[Fizz, FizzRow, Seq] => Query[Fizz, FizzRow, Seq]

Basically, in each function, I am optionally applying the filtering if the filter parameter option* is present. However, the compiler does not like the fact that I am passing in a TableQuery to a function that takes Query, even though TableQuery is a subtype of Query. Is there a way to convert a TableQuery to Query? Or a better way to go about chaining filter functions on a query?

The compiler error in question is

type mismatch;

found :scala.slick.lifted.Query[generated.Tables.Farm,generated.Tables.FarmRow,Seq]

required: scala.slick.lifted.TableQuery[generated.Tables.Farm]

I can get it to compile by using table.drop(0) instead of table but obviously that seems like a poor workaround. I see that there's a to method on TableQuery that converts it to a Query but it also takes an implicit ctc: TypedCollectionTypeConstructor[D].

An example of one of the filterX functions listed above:

def filterCharacteristics(characteristics: Option[List[Int]])(table: Query[Farm,FarmRow,Seq]) = {
characteristics.map(chars =>
  (for {
    (fc, f) <- Farmcharacteristic.filter(_.characteristicId inSet chars) join table on (_.farmId === _.farmId)
  } yield f)).getOrElse(table)
}
kevin.qiu
  • 31
  • 1
  • 4
  • Can you add an example of your filters? – Carlos Vilchez Sep 28 '15 at 12:11
  • Sorry, couldn't figure out how to post code in comments so added to OP. Your solution below doesn't really work as is since I need to perform joins and filters that depend on the specific characteristics of the "filter" I am applying, thus why they are functions. – kevin.qiu Sep 29 '15 at 01:11

1 Answers1

0

I think you can try another approach. Instead of using a fold, you can use a collect to get only the Some values. Then you can apply a filter to each of the options you have:

val table = TableQuery[Fizz]
val filteredQueries = List(Some(option1), Some(option2), Some(option3)) collect {
  case Some(option) => option 
} map { currentOption =>
  table.filter(currentOption)
}

// We need to get the last value or the TableQuery
val lastValue = filteredQueries reverse headOption

// Or we have Some(Query) or None, In case it is a None, we will use table
lastValue.getOrElse(table)
Carlos Vilchez
  • 2,774
  • 28
  • 30