Skip to content

Commit

Permalink
Adding sphinx_attributes to search results for access to attributes v…
Browse files Browse the repository at this point in the history
…ia Sphinx.
  • Loading branch information
pat committed Oct 3, 2009
1 parent c4416e6 commit 654bb50
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 18 deletions.
11 changes: 11 additions & 0 deletions features/direct_attributes.feature
@@ -0,0 +1,11 @@
Feature: Direct Attributes
In order to avoid unnecessary SQL queries
I want to access attribute values from Sphinx's response

Scenario: Accessing attribute values directly
Given Sphinx is running
And I am searching on posts
When I search
Then the first result should have a comments count of 9


4 changes: 4 additions & 0 deletions features/step_definitions/common_steps.rb
Expand Up @@ -31,6 +31,10 @@
@method = @model ? :search_count : :count
end

When /^I search$/ do
@results = nil
end

When /^I search for (\w+)$/ do |query|
@results = nil
@query = query
Expand Down
4 changes: 4 additions & 0 deletions features/step_definitions/search_steps.rb
Expand Up @@ -83,3 +83,7 @@

excerpt.should == string
end

Then /^the first result should have a (\w+\s?\w*) of (\d+)$/ do |attribute, value|
results.first.sphinx_attributes[attribute.gsub(/\s+/, '_')].should == value.to_i
end
3 changes: 2 additions & 1 deletion features/support/models/post.rb
Expand Up @@ -11,8 +11,9 @@ class Post < ActiveRecord::Base
indexes tags.text, :as => :tags
indexes comments.content, :as => :comments
indexes authors.name, :as => :authors

has comments(:id), :as => :comment_ids, :source => :ranged_query
has category.name, :facet => true, :as => :category_name, :type => :string
has 'COUNT(DISTINCT comments.id)', :as => :comments_count, :type => :integer
end
end
18 changes: 18 additions & 0 deletions lib/thinking_sphinx/search.rb
Expand Up @@ -244,6 +244,7 @@ def populate
else
replace instances_from_matches
add_excerpter
add_sphinx_attributes
end
end
end
Expand All @@ -261,6 +262,23 @@ def add_excerpter
end
end

def add_sphinx_attributes
each do |object|
next if object.nil? || object.respond_to?(:sphinx_attributes)

match = @results[:matches].detect { |match|
match[:attributes]['sphinx_internal_id'] == object.
primary_key_for_sphinx &&
match[:attributes]['class_crc'] == object.class.to_crc32
}
next if match.nil?

object.metaclass.instance_eval do
define_method(:sphinx_attributes) { match[:attributes] }
end
end
end

def self.log(message, method = :debug)
return if ::ActiveRecord::Base.logger.nil?
::ActiveRecord::Base.logger.send method, message
Expand Down
4 changes: 4 additions & 0 deletions spec/fixtures/models.rb
Expand Up @@ -105,6 +105,10 @@ class Alpha < ActiveRecord::Base
def big_name
name.upcase
end

def sphinx_attributes
:existing
end
end

class Beta < ActiveRecord::Base
Expand Down
60 changes: 43 additions & 17 deletions spec/lib/thinking_sphinx/search_spec.rb
Expand Up @@ -732,28 +732,54 @@
end
end

describe 'excerpts' do
before :each do
@search = ThinkingSphinx::Search.new
end
context 'result objects' do
describe '#excerpts' do
before :each do
@search = ThinkingSphinx::Search.new
end

it "should add excerpts method if objects don't already have one" do
@search.first.should respond_to(:excerpts)
end
it "should add excerpts method if objects don't already have one" do
@search.first.should respond_to(:excerpts)
end

it "should return an instance of ThinkingSphinx::Excerpter" do
@search.first.excerpts.should be_a(ThinkingSphinx::Excerpter)
end
it "should return an instance of ThinkingSphinx::Excerpter" do
@search.first.excerpts.should be_a(ThinkingSphinx::Excerpter)
end

it "should not add excerpts method if objects already have one" do
@search.last.excerpts.should_not be_a(ThinkingSphinx::Excerpter)
end
it "should not add excerpts method if objects already have one" do
@search.last.excerpts.should_not be_a(ThinkingSphinx::Excerpter)
end

it "should set up the excerpter with the instances and search" do
ThinkingSphinx::Excerpter.should_receive(:new).with(@search, @alpha_a)
ThinkingSphinx::Excerpter.should_receive(:new).with(@search, @alpha_b)
it "should set up the excerpter with the instances and search" do
ThinkingSphinx::Excerpter.should_receive(:new).with(@search, @alpha_a)
ThinkingSphinx::Excerpter.should_receive(:new).with(@search, @alpha_b)

@search.first
@search.first
end
end

describe '#sphinx_attributes' do
before :each do
@search = ThinkingSphinx::Search.new
end

it "should add sphinx_attributes method if objects don't already have one" do
@search.last.should respond_to(:sphinx_attributes)
end

it "should return a hash" do
@search.last.sphinx_attributes.should be_a(Hash)
end

it "should not add sphinx_attributes if objects have a method of that name already" do
@search.first.sphinx_attributes.should_not be_a(Hash)
end

it "should pair sphinx_attributes with the correct hash" do
hash = @search.last.sphinx_attributes
hash['sphinx_internal_id'].should == @search.last.id
hash['class_crc'].should == @search.last.class.to_crc32
end
end
end
end
Expand Down

0 comments on commit 654bb50

Please sign in to comment.