negate search conditions
This commit is contained in:
parent
851aa49091
commit
5b86e640b0
3 changed files with 158 additions and 100 deletions
2
Gemfile
2
Gemfile
|
@ -2,6 +2,8 @@ source 'http://rubygems.org'
|
|||
|
||||
gem 'rails', '3.0.0.beta2'
|
||||
|
||||
gem 'arel', :git => 'http://github.com/ernie/arel.git'
|
||||
|
||||
gem 'sqlite3-ruby', :require => 'sqlite3'
|
||||
|
||||
group :test do
|
||||
|
|
|
@ -23,6 +23,8 @@ class Item < ActiveRecord::Base
|
|||
in_phrase = !in_phrase
|
||||
elsif c == ':' && !in_phrase
|
||||
query_conditions.last.to_property!
|
||||
elsif c == '-' && !in_phrase && query_conditions.last.empty?
|
||||
query_conditions.last.negate!
|
||||
else
|
||||
query_conditions.last << c
|
||||
end
|
||||
|
@ -35,26 +37,34 @@ class Item < ActiveRecord::Base
|
|||
private
|
||||
|
||||
class Condition < String
|
||||
attr_reader :property
|
||||
|
||||
def to_property!
|
||||
@property = self.clone
|
||||
self.replace ''
|
||||
end
|
||||
|
||||
def negate!
|
||||
@negative = true
|
||||
end
|
||||
|
||||
def narrow(scope)
|
||||
items = Table(:objects)
|
||||
if @property == 'species'
|
||||
species = Species.find_by_name(self)
|
||||
# TODO: add a many-to-many table to handle this relationship
|
||||
scope.where('species_support_ids = ? OR species_support_ids LIKE ? OR species_support_ids LIKE ? OR species_support_ids LIKE ?',
|
||||
condition = items[:species_support_ids].matches_any(
|
||||
species.id,
|
||||
"#{species.id},%",
|
||||
"%,#{species.id},%",
|
||||
"%,#{species.id}"
|
||||
)
|
||||
else
|
||||
scope.where('name LIKE :matcher OR description LIKE :matcher', :matcher => "%#{self}%")
|
||||
matcher = "%#{self}%"
|
||||
condition = items[:name].matches(matcher).or(
|
||||
items[:description].matches(matcher)
|
||||
)
|
||||
end
|
||||
condition = condition.not if @negative
|
||||
scope.where(condition)
|
||||
end
|
||||
|
||||
def inspect
|
||||
|
|
|
@ -1,105 +1,151 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Item do
|
||||
specify "should accept string or array for species_support_ids" do
|
||||
items = [
|
||||
Factory.build(:item, :species_support_ids => '1,2,3'),
|
||||
Factory.build(:item, :species_support_ids => [1,2,3])
|
||||
]
|
||||
items.each { |i| i.species_support_ids.should == [1,2,3] }
|
||||
end
|
||||
|
||||
specify "class should search name for word" do
|
||||
query_should 'blue',
|
||||
:return => [
|
||||
'A Hat That is Blue',
|
||||
'Blue Hat',
|
||||
'Blueish Hat',
|
||||
'Very Blue Hat'
|
||||
],
|
||||
:not_return => [
|
||||
'Green Hat',
|
||||
'Red Hat'
|
||||
context "an item" do
|
||||
specify "should accept string or array for species_support_ids" do
|
||||
items = [
|
||||
Factory.build(:item, :species_support_ids => '1,2,3'),
|
||||
Factory.build(:item, :species_support_ids => [1,2,3])
|
||||
]
|
||||
end
|
||||
|
||||
specify "class should search name for phrase" do
|
||||
query_should '"one two"',
|
||||
:return => [
|
||||
'Zero one two three',
|
||||
'Zero one two',
|
||||
'One two three'
|
||||
],
|
||||
:not_return => [
|
||||
'Zero one three',
|
||||
'Zero two three',
|
||||
'Zero one and two',
|
||||
'Three two one'
|
||||
]
|
||||
end
|
||||
|
||||
specify "class should search name for multiple words" do
|
||||
query_should 'one two',
|
||||
:return => [
|
||||
'Zero one two three',
|
||||
'Zero one two',
|
||||
'One two three',
|
||||
'Zero one and two',
|
||||
'Three two one'
|
||||
],
|
||||
:not_return => [
|
||||
'Zero one three',
|
||||
'Zero two three'
|
||||
]
|
||||
end
|
||||
|
||||
specify "class should search name for words and phrases" do
|
||||
query_should 'zero "one two" three',
|
||||
:return => [
|
||||
'zero one two three',
|
||||
'zero four one two three',
|
||||
'one two zero three',
|
||||
'three zero one two'
|
||||
],
|
||||
:not_return => [
|
||||
'one two three',
|
||||
'zero one two',
|
||||
'three one zero two',
|
||||
'two one three zero'
|
||||
]
|
||||
end
|
||||
|
||||
specify "class should search name and description" do
|
||||
query_should 'zero "one two"',
|
||||
:return => [
|
||||
'zero one two',
|
||||
['zero one', 'one two three'],
|
||||
['one two four', 'one three zero'],
|
||||
['three', 'one two four zero']
|
||||
],
|
||||
:not_return => [
|
||||
['zero one', 'two'],
|
||||
['one two four', 'three'],
|
||||
['five two', 'zero one three two']
|
||||
]
|
||||
end
|
||||
|
||||
specify "class should search by species" do
|
||||
[[2],[1,2,3],[2,3],[3],[1,3]].each do |ids|
|
||||
Factory.create :item, :species_support_ids => ids
|
||||
items.each { |i| i.species_support_ids.should == [1,2,3] }
|
||||
end
|
||||
Item.search('species:acara').count.should == 2
|
||||
Item.search('species:aisha').count.should == 3
|
||||
Item.search('species:blumaroo').count.should == 4
|
||||
end
|
||||
|
||||
specify "class should search by species and words" do
|
||||
Factory.create :item, :name => 'Blue Hat', :species_support_ids => [1]
|
||||
Factory.create :item, :name => 'Very Blue Hat', :species_support_ids => [1,2]
|
||||
Factory.create :item, :name => 'Red Hat', :species_support_ids => [2]
|
||||
Item.search('blue species:acara').count.should == 2
|
||||
Item.search('blue species:aisha').count.should == 1
|
||||
Item.search('red species:acara').count.should == 0
|
||||
Item.search('red species:aisha').count.should == 1
|
||||
context "class" do
|
||||
specify "should search name for word" do
|
||||
query_should 'blue',
|
||||
:return => [
|
||||
'A Hat That is Blue',
|
||||
'Blue Hat',
|
||||
'Blueish Hat',
|
||||
'Very Blue Hat'
|
||||
],
|
||||
:not_return => [
|
||||
'Green Hat',
|
||||
'Red Hat'
|
||||
]
|
||||
end
|
||||
|
||||
specify "should search name for phrase" do
|
||||
query_should '"one two"',
|
||||
:return => [
|
||||
'Zero one two three',
|
||||
'Zero one two',
|
||||
'One two three'
|
||||
],
|
||||
:not_return => [
|
||||
'Zero one three',
|
||||
'Zero two three',
|
||||
'Zero one and two',
|
||||
'Three two one'
|
||||
]
|
||||
end
|
||||
|
||||
specify "should search name for multiple words" do
|
||||
query_should 'one two',
|
||||
:return => [
|
||||
'Zero one two three',
|
||||
'Zero one two',
|
||||
'One two three',
|
||||
'Zero one and two',
|
||||
'Three two one'
|
||||
],
|
||||
:not_return => [
|
||||
'Zero one three',
|
||||
'Zero two three'
|
||||
]
|
||||
end
|
||||
|
||||
specify "should search name for words and phrases" do
|
||||
query_should 'zero "one two" three',
|
||||
:return => [
|
||||
'zero one two three',
|
||||
'zero four one two three',
|
||||
'one two zero three',
|
||||
'three zero one two'
|
||||
],
|
||||
:not_return => [
|
||||
'one two three',
|
||||
'zero one two',
|
||||
'three one zero two',
|
||||
'two one three zero'
|
||||
]
|
||||
end
|
||||
|
||||
specify "should search name and description" do
|
||||
query_should 'zero "one two"',
|
||||
:return => [
|
||||
'zero one two',
|
||||
['zero one', 'one two three'],
|
||||
['one two four', 'one three zero'],
|
||||
['three', 'one two four zero']
|
||||
],
|
||||
:not_return => [
|
||||
['zero one', 'two'],
|
||||
['one two four', 'three'],
|
||||
['five two', 'zero one three two']
|
||||
]
|
||||
end
|
||||
|
||||
specify "should search by species" do
|
||||
[[2],[1,2,3],[2,3],[3],[1,3]].each do |ids|
|
||||
Factory.create :item, :species_support_ids => ids
|
||||
end
|
||||
Item.search('species:acara').count.should == 2
|
||||
Item.search('species:aisha').count.should == 3
|
||||
Item.search('species:blumaroo').count.should == 4
|
||||
end
|
||||
|
||||
specify "should search by species and words" do
|
||||
Factory.create :item, :name => 'Blue Hat', :species_support_ids => [1]
|
||||
Factory.create :item, :name => 'Very Blue Hat', :species_support_ids => [1,2]
|
||||
Factory.create :item, :name => 'Red Hat', :species_support_ids => [2]
|
||||
Item.search('blue species:acara').count.should == 2
|
||||
Item.search('blue species:aisha').count.should == 1
|
||||
Item.search('red species:acara').count.should == 0
|
||||
Item.search('red 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
|
||||
|
||||
specify "should be able to negate species in search" do
|
||||
Factory.create :item, :name => 'Blue Hat', :species_support_ids => [1]
|
||||
Factory.create :item, :name => 'Very Blue Hat', :species_support_ids => [1,2]
|
||||
Factory.create :item, :name => 'Red Hat', :species_support_ids => [1,2]
|
||||
Factory.create :item, :name => 'Green Hat', :species_support_ids => [3]
|
||||
Factory.create :item, :name => 'Red Shirt', :species_support_ids => [3]
|
||||
Item.search('hat -species:acara').count.should == 1
|
||||
Item.search('hat -species:aisha').count.should == 2
|
||||
Item.search('hat -species:acara -species:aisha').count.should == 1
|
||||
end
|
||||
|
||||
specify "should be able to negate phrase in search" 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']
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue