Patterns with Valuable - the ModelSearch

By: Johnathon Wright on: August 24, 2012

I find that I write a lot of "advanced search" stuff, and that modeling an advanced search, and having that be in a separate class, is very good for my sanity.

h2. DataSearch model

The schema is below if you're interested. These models usually start in lib, and then move to app/search once I have four or five.

describe DataSearch do it 'finds data' do datum = Factory.create(:datum) DataSearch.new.results.should include(datum) end end

So this is a "sanity check" test. I typically test what isn't included. But that could mean that I could get half-way through, write some poorly-thought-out condition that excludes everything, and then have to spend 30 minutes tracking it down. Instead, I just start by asserting that everything is included by default. In some cases, you want nothing to result if there are no conditions -- no problem, just write a test that does return some result.

``` class DataSearch < Valuable has_collection :codes

def results Datum.find(:all) end ```

h3. I want only certain fields


describe DataSearch do it 'filters by code' do datum = FactoryGirl.create(:datum, :code => 'hr') DataSearch.new(:codes => ['midi-chlorians']).results.should_not include(datum) end

end

and then


class DataSearch < Valuable

has_collection :codes

def condition_params { :codes => codes } end

def conditions out = [] out << 'code IN (:codes)' if codes.not.empty? out.join(' AND ') end

def results Datum.find(:all, :conditions => [conditions, condition_params]) end

end

h3. Filter by visit


describe DataSearch do it 'filters by visit' do one = FactoryGirl.create(:order) two = FactoryGirl.create(:order)

doppleganger = FactoryGirl.create(:datum, :order => one)
DataSearch.new(:visit_id => two.visit_id).results.should_not include(doppleganger)

end

end

and then


class DataSearch < Valuable

hascollection :codes hasvalue :visit_id, :klass => :integer

def conditionparams { :codes => codes, :visitid => visit_id } end

def conditions out = [] out << 'code IN (:codes)' if codes.not.empty? out << 'orders.visitid = :visitid' if visit_id out.join(' AND ') end

def joins out = [] out << 'LEFT OUTER JOIN orders ON data.orderid = orders.id' if visitid out.join(' ') unless out.empty? end

def results Datum.find(:all, :conditions => [conditions, condition_params], :joins => joins, :group => 'data.id') end

end

h2. The Schema

h3. Timepoint

A patient at a point in time. * patient_id * date * physician

h3. Order

a Physician orders some bloodwork or some other test. * timepointid * panelname

h3. Datum

  • order_id
  • code
  • value
  • units

Datum.validatesuniquenessof :code, :scope => :order_id





Comments:

Just checking that you are human. What would be the result of this code?

a = 3*(4/2); b = 1; a+b

Back