Can I use conditions outside of find(...)?

Hi all,

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?

Thanks,

Brian H.

google for rails query plugins?
Did you want the select line to be done in SQL?

[self].select{|o| o.meets?(PRIORITY_CONDITIONS)}.size == 1

Roger,

Thanks for the response. I might not have been clear about this line:

[self].select{|o| o.meets?(PRIORITY_CONDITIONS)}.size == 1

I should have simply written:

o.meets?(PRIORITY_CONDITIONS)

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?

[self].select{|o| o.meets?(PRIORITY_CONDITIONS)}.size == 1

I see so you’d like to basically be able to re-use code

which you do use:

all_good = collection.accept{|member| member.good?}

and you’d like to use it later.
all_good_from_sql = Collection.find :all, :conditions => SOMETHING

Yeah google for rails query plugins there may be one.
Or you could just stick with SQL only :slight_smile:
-R

Brian H. wrote:

Roger,

Thanks for the response. I might not have been clear about this line:

[self].select{|o| o.meets?(PRIORITY_CONDITIONS)}.size == 1

I should have simply written:

o.meets?(PRIORITY_CONDITIONS)

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?

[self].select{|o| o.meets?(PRIORITY_CONDITIONS)}.size == 1

On Apr 16, 1:48 pm, Brian H. [email protected]
wrote:

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.

On Apr 16, 1:16 pm, Brian H. [email protected]
wrote:

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?

Not that I know of.

However, you can do something like this:

conds = ["blah blah ? ", some_var]

def meets?(conds)
temp = []; self.find(:all, :conditions => conds[0].app).each{|rec|
temp << rec.id}; temp.index(self.id).nil?
end

or

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).

Clever N. wrote:

On Apr 16, 1:48 pm, Brian H. [email protected]
wrote:

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