3
votes

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)
}
1
Can you add an example of your filters?Carlos Vilchez
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

1 Answers

0
votes

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)