Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[jdbi3] Support optional clauses in SQL for bound optional parameters. #381

Closed
qualidafial opened this issue May 31, 2016 · 3 comments
Closed

Comments

@qualidafial
Copy link
Member

@qualidafial qualidafial commented May 31, 2016

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.

@christophercurrie
Copy link
Contributor

@christophercurrie christophercurrie commented May 31, 2016

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.

@stevenschlansker
Copy link
Member

@stevenschlansker stevenschlansker commented May 31, 2016

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?

@qualidafial
Copy link
Member Author

@qualidafial qualidafial commented May 31, 2016

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants
You can’t perform that action at this time.