Search code examples
performancescalasubquerysqueryl

Squeryl - Means of combinations of queries


I have the need to perform some queries that may depend on external supplied parameters via a REST interface. For instance a client may require an URL of the form

some/entities?foo=12&bar=17

The parameters, say foo, bar and quux are all optional. So I start from designing some queries with Squeryl, like

object Entity {
  def byFoo(id: Long) = from(DB.entities)(e =>
    where(e.foo === id)
    select(e)
  )
  // more criteria
}

But of course I want to avoid the combinatorial explosion that arises, so I only design three queries, which in turn may take their data from another query:

object Entity {
  def byFoo(id: Long, source: Query[Entity] = DB.entites) = from(source)(e =>
    where(e.foo === id)
    select(e)
  )
  def byBar(id: Long, source: Query[Entity] = DB.entites) = from(source)(e =>
    where(e.bar === id)
    select(e)
  )
  // more criteria
}

Now I can combine them and run a query like

val result = Entity.byFoo(12,
  source = Entity.byBar(17)
)

The only problem I have with this approach is that behind the scenes Squeryl is going to generate a subquery, which may be inefficient. With a more typical query builder, I would be able to combine the queries and get the equivalent of the following:

from(DB.entities)(e =>
  where(
    e.foo === 12 and
    e.bar === 17
  )
  select(e)
)

Is there a different way to dynamically combine queries in Squeryl that will lead to this more efficient form?


Solution

  • The first thing I think you should look into is inhibitWhen, which you can find in the documentation. The gist of it is that you model your query like:

    var foo: Option[Int] = None
    var bar: Option[Int] = None
    
    from(DB.entities)(e =>
      where(
        e.foo === foo.? and
        e.bar === bar.?)
      select(e))
    

    The ? operator in the first expression is equivalent to (e.foo === foo).inhibitWhen(foo == None)