Many apps duplicate logic in SQL and in model methods. This isn’t very
DRY. Can I factor out the conditions somehow, and leverage them in both
places, e.g.:
class Order
PRIORITY_CONDITIONS = “(status = 2 AND total > 100) or total > 1000”
def self.find_priority_orders
self.find(:all, :conditions => PRIORITY_CONDITIONS)
end
def priority?
# Using a fictional ‘meets?’ method which applies conditions
# to an object and returns true or false.
[self].select{|o| o.meets?(PRIORITY_CONDITIONS)}.size == 1
end
end
I know I’ve glossed over the handling of parameterized conditions, but
that’s a solvable problem. Does anyone know of a plugin (or API item I
missed) that supports this?
The ‘meets?’ method is testing a given order against the conditions, for
example:
o = Order.find(1)
Return true if the order meets these conditions
o.meets?("(status = 2 AND total > 100) or total > 1000")
meets? does NOT query the database; it simply evaluates the conditions
against the model at hand. This is, of course, sufficient to test a
single model or query an array of models, due to the implementation of
Array#select.
If non-standard SQL functions are used, meets would fail. Perhaps
vendor-specific ConnectionAdapters might override meets? to accomodate
their vendor-specific SQL syntax.
I was hoping that a plugin of this sort existed. The ‘duplicate logic
in SQL and instance methods’ problem has been around forever.
Thanks!
Roger P. wrote:
google for rails query plugins?
Did you want the select line to be done in SQL?
The ‘meets?’ method is testing a given order against the conditions, for
example:
o = Order.find(1)
Return true if the order meets these conditions
o.meets?("(status = 2 AND total > 100) or total > 1000")
meets? does NOT query the database; it simply evaluates the conditions
against the model at hand. This is, of course, sufficient to test a
single model or query an array of models, due to the implementation of
Array#select.
If non-standard SQL functions are used, meets would fail. Perhaps
vendor-specific ConnectionAdapters might override meets? to accomodate
their vendor-specific SQL syntax.
I was hoping that a plugin of this sort existed. The ‘duplicate logic
in SQL and instance methods’ problem has been around forever.
Thanks!
Roger P. wrote:
google for rails query plugins?
Did you want the select line to be done in SQL?
I was hoping that a plugin of this sort existed. The ‘duplicate logic
in SQL and instance methods’ problem has been around forever.
Thinking about it for a moment will tell you why. What happens if
your conditions include columns not in your model’s table through a
join, and those relationships are not defined in the ORM (or aren’t
eagerly loaded, or… )? What if a subquery appears (" id IN SELECT
id from …")? Even worse, consider the where clauses where more
complex calculations are made… ruby/rails would have to emulate precisely the math engine in the database, or make those numerical
queries anyway.
It seems so simple in the obvious case of just testing a tables
attributes, but making it work generically would be all but impossible
and be very tricky to use.
I know I’ve glossed over the handling of parameterized conditions, but
that’s a solvable problem. Does anyone know of a plugin (or API item I
missed) that supports this?
def meets?(conds)
conds[0] << " and id = ?"
conds << self.id
self.find(:first, :conditions=>conds).nil?
end
It does result in a wasted database call though unless your conditions
are super-complex and you can’t readily check them in-model (for
example, if you need to pull in tons of information from other tables).
I was hoping that a plugin of this sort existed. The ‘duplicate logic
in SQL and instance methods’ problem has been around forever.
Thinking about it for a moment will tell you why. What happens if
your conditions include columns not in your model’s table through a
join, and those relationships are not defined in the ORM (or aren’t
eagerly loaded, or… )? What if a subquery appears (" id IN SELECT
id from …")? Even worse, consider the where clauses where more
complex calculations are made… ruby/rails would have to emulate precisely the math engine in the database, or make those numerical
queries anyway.
It seems so simple in the obvious case of just testing a tables
attributes, but making it work generically would be all but impossible
and be very tricky to use.
Yeah, I knew that it would get tricky when you get to vendor-specific
stuff. I wonder how other frameworks, which have generic query
languages (.NET LINQ, Hibernate HQL, JPA JPQL, etc.), handle this. If I
tried to write a plugin for this, I think I’d just commit to handling a
subset of ANSI SQL functions for the model at hand and raise Exceptions
for any others.
I had considered hitting the DB for one row, as in your ‘meets?’
example, but that precludes running the test on an object that is in a
different state than the database, through either my unsaved changes or
someone else’s changes underneath me.
Thanks for the responses!
Brian
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.