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?
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)