Jdbi: [jdbi3] Support optional clauses in SQL for bound optional parameters.

Created on 31 May 2016  路  3Comments  路  Source: jdbi/jdbi

There are lots of scenarios where you want to include/exclude a fragment from the SQL statement depending on what is bound to a particular parameter:

String SELECT = "SELECT * FROM something { id => WHERE id = :id }";

// these queries would be executed with the WHERE clause excluded:
handle.createQuery(SELECT).list();
handle.createQuery(SELECT).bind("id", null).list();
handle.createQuery(SELECT).bind("id", Optional.empty()).list();

// these queries would be executed with the WHERE clause included:
handle.createQuery(SELECT).bind("id", 1).list();
handle.createQuery(SELECT).bind("id", Optional.of(1)).list();

The { id => WHERE id = :id } is certainly up for debate--we'd have to ensure that whatever syntax we picked didn't conflict with valid SQL tokens.

This could be implemented in our default statement rewriters.

Most helpful comment

The main value I was after was the ability to mix and match filters on queries, e.g. on a search form with multiple optional fields. However as @stevenschlansker pointed out, this is already possible within the SQL syntax:

SELECT FROM thing
WHERE (:createdOn.start IS NULL OR created_on >= :createdOn.start)
AND (:createdOn.end IS NULL OR created_on <= :createdOn.end)
AND (:name IS NULL OR name LIKE :name || '%')
AND (:id IS NULL OR id = :id)

Closing.

All 3 comments

YMMV, but IMO this shouldn't be a design goal. First, this is the sort of thing that the StringTemplate statement locator does very well. While StringTemplate does not know about bind specifically, I see that as a feature; I _want_ to be alerted when I forget to bind a variable, or bind one incorrectly. And I definitely want to think of LIST ALL and LIST WITH FILTER as distinct operations, because my database will treat them differently.

Using StringTemplate, the example provided is a straightforward as:

listAll() ::= <<
  SELECT id, data FROM something
>>

listById() ::= <<
  <listAll()> WHERE id = :id
>>

No, it's not as concise, but what it loses in brevity it gains in power; I can reuse the first part of the query in multiple variations, and have them be consistent, and I get protection from my own errors of forgetting to bind or accidentally binding in the wrong use case.

I too am somewhat "meh" on this feature. Another option that is not as concise but doesn't require any additional support:

... WHERE (id = :id OR :id IS NULL) which means if you do an explicit bind of NULL you get an "optional" parameter.

Maybe if you really want it, it's appropriate as a different standalone statement rewriter?

The main value I was after was the ability to mix and match filters on queries, e.g. on a search form with multiple optional fields. However as @stevenschlansker pointed out, this is already possible within the SQL syntax:

SELECT FROM thing
WHERE (:createdOn.start IS NULL OR created_on >= :createdOn.start)
AND (:createdOn.end IS NULL OR created_on <= :createdOn.end)
AND (:name IS NULL OR name LIKE :name || '%')
AND (:id IS NULL OR id = :id)

Closing.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

agavrilov76 picture agavrilov76  路  5Comments

keith-miller picture keith-miller  路  3Comments

electrum picture electrum  路  3Comments

dhardtke picture dhardtke  路  3Comments

goxr3plus picture goxr3plus  路  4Comments