Politics, Programming and Possibilities
4 Jan
I released version 0.5 of this Ruby on Rails plugin a few months ago and have since updated it to include ‘and’ and ‘or’ methods, as well as the ability to use sub-conditions.
Here are some code samples:
Condition.block { |c|
c.and "one", 1
c.and "two", 2
c.and { |d|
d.or "three", 3
d.or "four", 4
}
}
# => ["one = ? AND two = ? AND (three = ? OR four = ?)", 1, 2, 3, 4]
Since this uses Ruby’s blocks to construct a Rails condition array, you can use all of Ruby’s familiar logical constructs to achieve cleaner code in some cases. For example:
Condition.block { |c|
c.and "user_id", @user_id
c.and { |d|
d.or "admin", true
d.or "joined_at", "<", Date.new(2007, 1, 1)
} unless @dont_override_user_id
}
# If @dont_override_user_id is false, then
# => ["user_id = ? AND (admin = ? OR joined_at < ?)", 10, true, Date.new(2007, 1, 1)]
#
# If @dont_override_user_id is true, then
# => ["user_id = ?", 10]
I use this directly in my ActiveRecord queries, like this:
Book.find(:all,
:include => {:content_pointer => :invitees},
:conditions => Condition.block { |c|
c.and "invitees.user_id", self.id
c.and "content_pointers.created_by_id", self.id
c.and "content_pointers.company_id", company.id if company
})
Note: You may get some unexpected results if you try mixing ‘and’ and ‘or’ within the same block. The current implementation assumes that you will be consistent, and use a new block whenever you wish to switch logical operators. As an example, don’t do this:
Condition.block { |c|
c.and "user_id", 1
c.and "book_id", 2
c.or "company_id", 3
}
# BAD
# Output will be: ["user_id = ? OR book_id = ? OR company_id = ?", 1, 2, 3]
# Do this instead:
Condition.block { |c|
c.and "user_id", 1
c.and { |d|
d.or "book_id", 2
d.or "company_id", 3
}
}
# OK
# Output will be: ["user_id = ? AND (book_id = ? OR company_id = ?)", 1, 2, 3]
The Condition Builder plugin is available as a tar/gz file. Download it here.
13 Responses for "Condition Builder 1.0 Released"
[...] Duane Johnson has released v1.0 of Condition Builder, his Ruby on Rails plugin for building conditions, e.g. for parameterised queries in ActiveRecord. If you have complex queries that need constructing, or queries that cannot easily be described non-programmatically, this may be worth considering. [...]
Duane have you ever looked into ez-where. It covers all your above examples(slightly different syntax) and does quite a few more things, joins and likes for example. Neat nonetheless!
Thanks, atmos. I tried Ezra’s plugin early on, but gave up for a number of reasons. My hope for this plugin was that it would be something a little lighter weight, and hopefully easier to use. (ez-where’s SQL-to-Ruby mappings weren’t very intuitive to me, for example, and I hit some snags when trying to disambiguate columns that belonged to specific tables).
How do you construct a quiery like this:
and name like ‘alex%’
Thank you.
andre:
c.and ‘name’, ‘like’, ‘alex%’
Thank you, Duane.
Another question: how do I construct a query of the type
and account_type in (’editor’,'publisher’)
Thank you in advance.
Also, I use the condition builder to add conditions only if certain parameters exist, like:
c.and “name”, “like”, params[:name]+”%” unless params[:name].empty?
and sometimes I end up with an empty condition block which produced an error.
I remedied this by adding
c.and “1″,1
at the beginning of the block.
Thank you for this simple and elegant tool.
– Andre
I looked at the plugin code and got the “in”:
c.and “name”, “in”, %w[editor publisher]
Thanks, andre!
[...] Condition Builder [...]
Hi Duane,
Thanks for a neat plugin ! I would like to contribute a patch to fix a problem I have encountered regarding handling of array arguments and the IN operator.
What is the best way to get the patch to you ?
Regards,
Andre
Is it posible to specify IS NULL ?
Actually it could be solved by a small patch, just change
from:
case values.size
raise “No value specified for Condition”
to:
case values.size
when 0
if column.include?(”IS NULL”)
left
Hi Duane,
thanks for your nice plugin.
Maybe you’ll find my suggestion useful:
line 69-73:
69 elsif column.to_s.downcase == “sql”
70 # Treat the first ‘value’ as pure SQL
71 left << values.shift
72 next
73 end
adding following line:
right.concat(values)
after line 71 would allow the usage of questionmark-placeholders in pure SQL strings useful for example for case insensitive stringcompares:
c.and ’sql’, “upper(columnname) = upper(?)”, value
Leave a reply