diff --git a/app/models/item.rb b/app/models/item.rb index e52c868c..1f18994e 100644 --- a/app/models/item.rb +++ b/app/models/item.rb @@ -19,8 +19,9 @@ class Item < ActiveRecord::Base end def self.search(query) - query = query.strip if query - raise ArgumentError, "Please provide a search query" if query.blank? + raise ArgumentError, "Please provide a search query" unless query + query = query.strip + raise ArgumentError, "Search queries should be at least 3 characters" if query.length < 3 query_conditions = [Condition.new] in_phrase = false query.each_char do |c| @@ -58,17 +59,16 @@ class Item < ActiveRecord::Base if @property == 'species' species = Species.find_by_name(self) # TODO: add a many-to-many table to handle this relationship - condition = items[:species_support_ids].matches_any( + ids = items[:species_support_ids] + condition = ids.eq('').or(ids.matches_any( species.id, "#{species.id},%", "%,#{species.id},%", "%,#{species.id}" - ) + )) else - matcher = "%#{self}%" - condition = items[:name].matches(matcher).or( - items[:description].matches(matcher) - ) + column = @property ? @property : :name + condition = items[column].matches("%#{self}%") end condition = condition.not if @negative scope.where(condition) diff --git a/spec/models/item_spec.rb b/spec/models/item_spec.rb index e8b16e2f..ae033fe7 100644 --- a/spec/models/item_spec.rb +++ b/spec/models/item_spec.rb @@ -72,18 +72,17 @@ describe Item do ] end - specify "should search name and description" do - query_should 'zero "one two"', + specify "should search description for words and phrases" do + query_should 'description:zero description:"one two"', :return => [ - 'zero one two', - ['zero one', 'one two three'], - ['one two four', 'one three zero'], - ['three', 'one two four zero'] + ['Green Hat', 'zero one two three'], + ['Blue Hat', 'five one two four zero'] ], :not_return => [ - ['zero one', 'two'], - ['one two four', 'three'], - ['five two', 'zero one three two'] + 'Zero one two', + ['Zero one', 'two'], + ['Zero', 'One two'], + ['Three', 'One zero two'] ] end @@ -106,20 +105,28 @@ describe Item do Item.search('red species:aisha').count.should == 1 end + specify "should return items with no species requirements if a species condition is added" do + Factory.create :item, :species_support_ids => [1] + Factory.create :item, :species_support_ids => [1,2] + Factory.create :item, :species_support_ids => [] + Item.search('species:acara').count.should == 3 + Item.search('species:aisha').count.should == 2 + Item.search('species:acara species:aisha').count.should == 2 + Item.search('-species:acara').count.should == 0 + Item.search('-species:aisha').count.should == 1 + end + specify "should be able to negate word in search" do query_should 'hat -blue', :return => [ 'Green Hat', 'Red Hat', 'Blu E Hat', - ['Yellow Hat', 'This hat is not green!'] ], :not_return => [ 'Blue Hat', 'Green Shirt', 'Blue Shirt', - ['Orange Hat', 'This hat is not blue!'], - ['Blue Pants', 'This is not a hat!'] ] end @@ -138,23 +145,24 @@ describe Item do query_should 'zero -"one two"', :return => [ 'Zero two one', - ['Two one', 'Zero'], 'One three two zero' ], :not_return => [ 'Zero one two', - ['Zero', 'one two three'], - ['One two four', 'Zero one'] + 'One two three zero' ] end - specify "should return raise exception for a query with no conditions" do - Factory.create :item + specify "should raise exception for a query with no conditions" do [ lambda { Item.search('').all }, lambda { Item.search(nil).all }, lambda { Item.search(' ').all } ].each { |l| l.should raise_error(ArgumentError) } end + + specify "should raise exception for a query that's too short" do + lambda { Item.search('e').all }.should raise_error(ArgumentError) + end end end