rails / arel

A Relational Algebra
2.06k stars 390 forks source link

Implement CASE Conditional Expression #400

Closed felixbuenemann closed 8 years ago

felixbuenemann commented 8 years ago

This implements the simple and extended variant of the SQL CASE conditional:

table = Table.new(:users)

# Simple variant with a single test case:
simple_case = Arel::Nodes::Case.new table[:name]
simple_case.when('foo').then(1).when('bar').then(2).else(0).to_sql
# => CASE "users"."name" WHEN 'foo' THEN 1 WHEN 'bar' THEN 2 ELSE 0 END

# Extended variant with multiple test cases:
extended_case = Arel::Nodes::Case.new
  .when(table[:name].eq('foo')).then(1)
  .when(table[:name].eq('bar')).then(2)
  .else(0).to_sql
# => CASE WHEN "users"."name" = 'foo' THEN 1 WHEN "users"."name" = 'bar' THEN 2 ELSE 0 END

# Simple variant using predicate chaining:
table[:name].when('foo').then(1).when('bar').then(2).else(0).to_sql
# => CASE "users"."name" WHEN 'foo' THEN 1 WHEN 'bar' THEN 2 ELSE 0 END

Both variants are supported by at least PostgreSQL, MySQL, SQLite and Oracle.

This resolves #168 and is based on original code from acts_as_ordered_tree. I've asked @take-five for permission and license of the code in take-five/acts_as_ordered_tree#34.

I'm not familiar with the arel code base, so please check if there are enough tests and if my usage of build_quoted is OK (using the node's api without it felt weird).

rails-bot commented 8 years ago

Thanks for the pull request, and welcome! The Rails team is excited to review your changes, and you should hear from @tenderlove (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see the contribution instructions for more information.

felixbuenemann commented 8 years ago

@rafaelfranca Do you mind taking a look? Seems @tenderlove is busy.

rafaelfranca commented 8 years ago

Code looks good but could you change the test syntax to use assert?

felixbuenemann commented 8 years ago

@rafaelfranca Updated to use assert/refute syntax and rebased on master.

kbrock commented 8 years ago

@felixbuenemann may want to just kick this. it looks like it should work

felixbuenemann commented 8 years ago

Seems Travis CI fixed the bundler problem, so I removed the fix and rebased on current master. (Deleted comments regarding unrelated Travis CI failures on jruby-head.)

pschambacher commented 8 years ago

Love it! Thanks :smile: