thinking-sphinx 2.0.3 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.textile +5 -0
- data/VERSION +1 -1
- data/features/support/env.rb +5 -0
- data/features/thinking_sphinx/models/developer.rb +0 -11
- data/lib/thinking_sphinx.rb +93 -42
- data/lib/thinking_sphinx/active_record.rb +11 -31
- data/lib/thinking_sphinx/active_record/delta.rb +27 -0
- data/lib/thinking_sphinx/auto_version.rb +18 -7
- data/lib/thinking_sphinx/configuration.rb +28 -12
- data/lib/thinking_sphinx/deploy/capistrano.rb +19 -19
- data/lib/thinking_sphinx/excerpter.rb +2 -1
- data/lib/thinking_sphinx/facet.rb +9 -10
- data/lib/thinking_sphinx/index/builder.rb +10 -0
- data/lib/thinking_sphinx/railtie.rb +4 -0
- data/lib/thinking_sphinx/search.rb +7 -4
- data/lib/thinking_sphinx/tasks.rb +4 -2
- data/spec/thinking_sphinx/active_record/delta_spec.rb +7 -7
- data/spec/thinking_sphinx/active_record_spec.rb +4 -0
- data/spec/thinking_sphinx/attribute_spec.rb +6 -3
- data/spec/thinking_sphinx/auto_version_spec.rb +12 -4
- data/spec/thinking_sphinx/configuration_spec.rb +1 -1
- data/spec/thinking_sphinx/context_spec.rb +1 -0
- data/spec/thinking_sphinx/facet_search_spec.rb +0 -8
- data/spec/thinking_sphinx/facet_spec.rb +12 -0
- data/spec/thinking_sphinx/field_spec.rb +6 -3
- data/spec/thinking_sphinx/index/builder_spec.rb +13 -0
- data/spec/thinking_sphinx/search_spec.rb +2 -1
- data/spec/thinking_sphinx_spec.rb +2 -3
- metadata +62 -151
- data/lib/thinking_sphinx/core/array.rb +0 -13
@@ -3,13 +3,13 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
3
3
|
namespace :install do
|
4
4
|
desc <<-DESC
|
5
5
|
Install Sphinx by source
|
6
|
-
|
6
|
+
|
7
7
|
If Postgres is available, Sphinx will use it.
|
8
|
-
|
8
|
+
|
9
9
|
If the variable :thinking_sphinx_configure_args is set, it will
|
10
10
|
be passed to the Sphinx configure script. You can use this to
|
11
11
|
install Sphinx in a non-standard location:
|
12
|
-
|
12
|
+
|
13
13
|
set :thinking_sphinx_configure_args, "--prefix=$HOME/software"
|
14
14
|
DESC
|
15
15
|
|
@@ -22,7 +22,7 @@ DESC
|
|
22
22
|
rescue Capistrano::CommandError => e
|
23
23
|
puts "Continuing despite error: #{e.message}"
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
args = []
|
27
27
|
if with_postgres
|
28
28
|
run "pg_config --pkgincludedir" do |channel, stream, data|
|
@@ -30,60 +30,60 @@ DESC
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
args << fetch(:thinking_sphinx_configure_args, '')
|
33
|
-
|
33
|
+
|
34
34
|
commands = <<-CMD
|
35
|
-
wget -q http://
|
36
|
-
tar xzvf sphinx-0.9.
|
37
|
-
cd sphinx-0.9.
|
35
|
+
wget -q http://sphinxsearch.com/downloads/sphinx-0.9.9.tar.gz >> sphinx.log
|
36
|
+
tar xzvf sphinx-0.9.9.tar.gz
|
37
|
+
cd sphinx-0.9.9
|
38
38
|
./configure #{args.join(" ")}
|
39
39
|
make
|
40
40
|
#{try_sudo} make install
|
41
|
-
rm -rf sphinx-0.9.
|
41
|
+
rm -rf sphinx-0.9.9 sphinx-0.9.9.tar.gz
|
42
42
|
CMD
|
43
43
|
run commands.split(/\n\s+/).join(" && ")
|
44
44
|
end
|
45
|
-
|
46
|
-
desc "Install Thinking Sphinx as a gem
|
45
|
+
|
46
|
+
desc "Install Thinking Sphinx as a gem"
|
47
47
|
task :ts do
|
48
|
-
run "#{try_sudo} gem install thinking-sphinx
|
48
|
+
run "#{try_sudo} gem install thinking-sphinx"
|
49
49
|
end
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
desc "Generate the Sphinx configuration file"
|
53
53
|
task :configure do
|
54
54
|
rake "thinking_sphinx:configure"
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
desc "Index data"
|
58
58
|
task :index do
|
59
59
|
rake "thinking_sphinx:index"
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
desc "Start the Sphinx daemon"
|
63
63
|
task :start do
|
64
64
|
configure
|
65
65
|
rake "thinking_sphinx:start"
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
desc "Stop the Sphinx daemon"
|
69
69
|
task :stop do
|
70
70
|
configure
|
71
71
|
rake "thinking_sphinx:stop"
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
desc "Stop and then start the Sphinx daemon"
|
75
75
|
task :restart do
|
76
76
|
stop
|
77
77
|
start
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
desc "Stop, re-index and then start the Sphinx daemon"
|
81
81
|
task :rebuild do
|
82
82
|
stop
|
83
83
|
index
|
84
84
|
start
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
desc "Add the shared folder for sphinx files"
|
88
88
|
task :shared_sphinx_folder, :roles => :web do
|
89
89
|
rails_env = fetch(:rails_env, "production")
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module ThinkingSphinx
|
2
2
|
class Excerpter
|
3
|
-
CoreMethods = %w( kind_of? object_id respond_to? should
|
3
|
+
CoreMethods = %w( kind_of? object_id respond_to? respond_to_missing? should
|
4
|
+
should_not stub! )
|
4
5
|
# Hide most methods, to allow them to be passed through to the instance.
|
5
6
|
instance_methods.select { |method|
|
6
7
|
method.to_s[/^__/].nil? && !CoreMethods.include?(method.to_s)
|
@@ -98,16 +98,15 @@ module ThinkingSphinx
|
|
98
98
|
|
99
99
|
def translate(object, attribute_value)
|
100
100
|
objects = source_objects(object)
|
101
|
-
return
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
end
|
101
|
+
return if objects.blank?
|
102
|
+
|
103
|
+
method = value_source || column.__name
|
104
|
+
object = objects.one? ? objects.first : objects.detect { |item|
|
105
|
+
result = item.send(method)
|
106
|
+
result && result.to_crc32 == attribute_value
|
107
|
+
}
|
108
|
+
|
109
|
+
object.try(method)
|
111
110
|
end
|
112
111
|
|
113
112
|
def source_objects(object)
|
@@ -251,6 +251,16 @@ module ThinkingSphinx
|
|
251
251
|
FauxColumn.new(assoc, *args)
|
252
252
|
end
|
253
253
|
|
254
|
+
# Use this method to generate SQL for your attributes, conditions, etc.
|
255
|
+
# You can pass in as whatever ActiveRecord::Base.sanitize_sql accepts.
|
256
|
+
#
|
257
|
+
# where sanitize_sql(["active = ?", true])
|
258
|
+
# #=> WHERE active = 1
|
259
|
+
#
|
260
|
+
def sanitize_sql(*args)
|
261
|
+
@index.model.send(:sanitize_sql, *args)
|
262
|
+
end
|
263
|
+
|
254
264
|
private
|
255
265
|
|
256
266
|
def source
|
@@ -7,12 +7,12 @@ module ThinkingSphinx
|
|
7
7
|
# search_for_ids methods will do the job in exactly the same manner when
|
8
8
|
# called from a model.
|
9
9
|
#
|
10
|
-
class Search
|
10
|
+
class Search < Array
|
11
11
|
CoreMethods = %w( == class class_eval extend frozen? id instance_eval
|
12
12
|
instance_of? instance_values instance_variable_defined?
|
13
13
|
instance_variable_get instance_variable_set instance_variables is_a?
|
14
|
-
kind_of? member? method methods nil? object_id respond_to?
|
15
|
-
type )
|
14
|
+
kind_of? member? method methods nil? object_id respond_to?
|
15
|
+
respond_to_missing? send should type )
|
16
16
|
SafeMethods = %w( partition private_methods protected_methods
|
17
17
|
public_methods send class )
|
18
18
|
|
@@ -489,7 +489,10 @@ module ThinkingSphinx
|
|
489
489
|
end
|
490
490
|
|
491
491
|
def self.log(message, &block)
|
492
|
-
|
492
|
+
if ThinkingSphinx::ActiveRecord::LogSubscriber.logger.nil?
|
493
|
+
yield if block_given?
|
494
|
+
return
|
495
|
+
end
|
493
496
|
|
494
497
|
if block_given?
|
495
498
|
::ActiveSupport::Notifications.
|
@@ -6,9 +6,11 @@ namespace :thinking_sphinx do
|
|
6
6
|
if defined?(Rails)
|
7
7
|
Rails.application.require_environment!
|
8
8
|
Rails.configuration.cache_classes = false
|
9
|
+
elsif defined?(Merb)
|
10
|
+
Rake::Task[:merb_env].invoke
|
11
|
+
elsif defined?(Sinatra)
|
12
|
+
Sinatra::Application.environment = ENV['RACK_ENV']
|
9
13
|
end
|
10
|
-
|
11
|
-
Rake::Task[:merb_env].invoke if defined?(Merb)
|
12
14
|
end
|
13
15
|
|
14
16
|
desc "Output the current Thinking Sphinx version"
|
@@ -17,27 +17,27 @@ describe "ThinkingSphinx::ActiveRecord::Delta" do
|
|
17
17
|
|
18
18
|
describe "suspended_delta method" do
|
19
19
|
before :each do
|
20
|
-
ThinkingSphinx.
|
20
|
+
ThinkingSphinx.deltas_suspended = false
|
21
21
|
Person.sphinx_indexes.first.delta_object.stub!(:` => "")
|
22
22
|
end
|
23
23
|
|
24
24
|
it "should execute the argument block with deltas disabled" do
|
25
|
-
ThinkingSphinx.should_receive(:
|
26
|
-
ThinkingSphinx.should_receive(:
|
25
|
+
ThinkingSphinx.should_receive(:deltas_suspended=).once.with(true)
|
26
|
+
ThinkingSphinx.should_receive(:deltas_suspended=).once.with(false)
|
27
27
|
lambda { Person.suspended_delta { raise 'i was called' } }.should(
|
28
28
|
raise_error(Exception)
|
29
29
|
)
|
30
30
|
end
|
31
31
|
|
32
32
|
it "should restore deltas_enabled to its original setting" do
|
33
|
-
ThinkingSphinx.
|
34
|
-
ThinkingSphinx.should_receive(:
|
33
|
+
ThinkingSphinx.deltas_suspended = true
|
34
|
+
ThinkingSphinx.should_receive(:deltas_suspended=).twice.with(true)
|
35
35
|
Person.suspended_delta { 'no-op' }
|
36
36
|
end
|
37
37
|
|
38
38
|
it "should restore deltas_enabled to its original setting even if there was an exception" do
|
39
|
-
ThinkingSphinx.
|
40
|
-
ThinkingSphinx.should_receive(:
|
39
|
+
ThinkingSphinx.deltas_suspended = true
|
40
|
+
ThinkingSphinx.should_receive(:deltas_suspended=).twice.with(true)
|
41
41
|
lambda { Person.suspended_delta { raise 'bad error' } }.should(
|
42
42
|
raise_error(Exception)
|
43
43
|
)
|
@@ -81,9 +81,9 @@ describe ThinkingSphinx::Attribute do
|
|
81
81
|
|
82
82
|
describe '#is_many?' do
|
83
83
|
before :each do
|
84
|
-
@assoc_a =
|
85
|
-
@assoc_b =
|
86
|
-
@assoc_c =
|
84
|
+
@assoc_a = ThinkingSphinx::Association.new(nil, nil)
|
85
|
+
@assoc_b = ThinkingSphinx::Association.new(nil, nil)
|
86
|
+
@assoc_c = ThinkingSphinx::Association.new(nil, nil)
|
87
87
|
|
88
88
|
@attribute = ThinkingSphinx::Attribute.new(
|
89
89
|
@source, [ThinkingSphinx::Index::FauxColumn.new(:col_name)]
|
@@ -91,6 +91,9 @@ describe ThinkingSphinx::Attribute do
|
|
91
91
|
@attribute.associations = {
|
92
92
|
:a => @assoc_a, :b => @assoc_b, :c => @assoc_c
|
93
93
|
}
|
94
|
+
@attribute.associations.values.each { |assoc|
|
95
|
+
assoc.stub!(:is_many? => true)
|
96
|
+
}
|
94
97
|
end
|
95
98
|
|
96
99
|
it "should return true if all associations return true to is_many?" do
|
@@ -30,7 +30,7 @@ describe ThinkingSphinx::AutoVersion do
|
|
30
30
|
ThinkingSphinx::AutoVersion.detect
|
31
31
|
end
|
32
32
|
|
33
|
-
it "should require 1.10-beta if
|
33
|
+
it "should require 1.10-beta if using 1.10-beta compiled with id64 support" do
|
34
34
|
ThinkingSphinx::AutoVersion.should_receive(:require).
|
35
35
|
with('riddle/1.10')
|
36
36
|
|
@@ -38,15 +38,23 @@ describe ThinkingSphinx::AutoVersion do
|
|
38
38
|
ThinkingSphinx::AutoVersion.detect
|
39
39
|
end
|
40
40
|
|
41
|
-
it "should
|
42
|
-
|
41
|
+
it "should require 2.0.1 if using Sphinx 2.0.1 beta" do
|
42
|
+
ThinkingSphinx::AutoVersion.should_receive(:require).
|
43
|
+
with('riddle/2.0.1')
|
44
|
+
|
45
|
+
@config.stub!(:version => '2.0.1-beta')
|
46
|
+
ThinkingSphinx::AutoVersion.detect
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should output a warning if the detected version is unsupported" do
|
50
|
+
STDERR.should_receive(:puts).with(/unsupported/i)
|
43
51
|
|
44
52
|
@config.stub!(:version => '0.9.7')
|
45
53
|
ThinkingSphinx::AutoVersion.detect
|
46
54
|
end
|
47
55
|
|
48
56
|
it "should output a warning if the version cannot be determined" do
|
49
|
-
STDERR.should_receive(:puts)
|
57
|
+
STDERR.should_receive(:puts).at_least(:once)
|
50
58
|
|
51
59
|
@config.stub!(:version => nil)
|
52
60
|
ThinkingSphinx::AutoVersion.detect
|
@@ -41,6 +41,7 @@ describe ThinkingSphinx::Context do
|
|
41
41
|
}.should_not raise_error
|
42
42
|
end
|
43
43
|
|
44
|
+
# Fails in Ruby 1.9 (or maybe it's an RSpec update). Not sure why.
|
44
45
|
it "should retry if the first pass fails and contains a directory" do
|
45
46
|
@model_name_lower.stub!(:gsub!).and_return(true, nil)
|
46
47
|
@class_name.stub(:constantize).and_raise(LoadError)
|
@@ -98,14 +98,6 @@ describe ThinkingSphinx::FacetSearch do
|
|
98
98
|
:classes => [Person], :facets => :state
|
99
99
|
)
|
100
100
|
end
|
101
|
-
|
102
|
-
it "should handle multiple facets" do
|
103
|
-
ThinkingSphinx.should_receive(:search).twice.and_return(search)
|
104
|
-
|
105
|
-
ThinkingSphinx::FacetSearch.new(
|
106
|
-
:classes => [Person], :facets => [:state, :city]
|
107
|
-
)
|
108
|
-
end
|
109
101
|
end
|
110
102
|
|
111
103
|
describe "empty result set for attributes" do
|
@@ -311,6 +311,18 @@ describe ThinkingSphinx::Facet do
|
|
311
311
|
ThinkingSphinx::Facet.new(field).value(friendship, {'name_facet' => 'buried'.to_crc32}).
|
312
312
|
should == 'buried'
|
313
313
|
end
|
314
|
+
|
315
|
+
it "should not error with multi-level association values containing a nil value" do
|
316
|
+
person = Person.find(:first)
|
317
|
+
tag = person.tags.build(:name => nil)
|
318
|
+
tag = person.tags.build(:name => "buried")
|
319
|
+
friendship = Friendship.new(:person => person)
|
320
|
+
|
321
|
+
field = ThinkingSphinx::Field.new(
|
322
|
+
@source, ThinkingSphinx::Index::FauxColumn.new(:person, :tags, :name)
|
323
|
+
)
|
324
|
+
lambda{ThinkingSphinx::Facet.new(field).value(friendship, {'name_facet' => 'buried'.to_crc32})}.should_not raise_error
|
325
|
+
end
|
314
326
|
end
|
315
327
|
|
316
328
|
describe 'for float attributes' do
|
@@ -90,9 +90,9 @@ describe ThinkingSphinx::Field do
|
|
90
90
|
|
91
91
|
describe "is_many? method" do
|
92
92
|
before :each do
|
93
|
-
@assoc_a =
|
94
|
-
@assoc_b =
|
95
|
-
@assoc_c =
|
93
|
+
@assoc_a = ThinkingSphinx::Association.new(nil, nil)
|
94
|
+
@assoc_b = ThinkingSphinx::Association.new(nil, nil)
|
95
|
+
@assoc_c = ThinkingSphinx::Association.new(nil, nil)
|
96
96
|
|
97
97
|
@field = ThinkingSphinx::Field.new(
|
98
98
|
@source, [ThinkingSphinx::Index::FauxColumn.new(:col_name)]
|
@@ -100,6 +100,9 @@ describe ThinkingSphinx::Field do
|
|
100
100
|
@field.associations = {
|
101
101
|
:a => @assoc_a, :b => @assoc_b, :c => @assoc_c
|
102
102
|
}
|
103
|
+
@field.associations.values.each { |assoc|
|
104
|
+
assoc.stub!(:is_many? => true)
|
105
|
+
}
|
103
106
|
end
|
104
107
|
|
105
108
|
it "should return true if all associations return true to is_many?" do
|
@@ -492,4 +492,17 @@ describe ThinkingSphinx::Index::Builder do
|
|
492
492
|
index.name.should == 'custom'
|
493
493
|
end
|
494
494
|
end
|
495
|
+
|
496
|
+
describe "sanitize_sql" do
|
497
|
+
def index
|
498
|
+
@index ||= ThinkingSphinx::Index::Builder.generate(Person) do
|
499
|
+
indexes first_name, last_name
|
500
|
+
where sanitize_sql(["gender = ?", "female"])
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
it "should be aliased to ActiveRecord::Base.sanitize_sql" do
|
505
|
+
index.sources.first.conditions.first.should == index.model.send(:sanitize_sql, ["gender = ?", "female"])
|
506
|
+
end
|
507
|
+
end
|
495
508
|
end
|
@@ -924,7 +924,8 @@ describe ThinkingSphinx::Search do
|
|
924
924
|
it "should not add excerpts method if objects already have one" do
|
925
925
|
@search.last.excerpts.should_not be_a(ThinkingSphinx::Excerpter)
|
926
926
|
end
|
927
|
-
|
927
|
+
|
928
|
+
# Fails in Ruby 1.9 (or maybe it's an RSpec update). Not sure why.
|
928
929
|
it "should set up the excerpter with the instances and search" do
|
929
930
|
[@alpha_a, @beta_b, @alpha_b, @beta_a].each do |object|
|
930
931
|
ThinkingSphinx::Excerpter.should_receive(:new).with(@search, object)
|
@@ -23,7 +23,7 @@ describe ThinkingSphinx do
|
|
23
23
|
ThinkingSphinx.reset_context!
|
24
24
|
ThinkingSphinx.context.should_not == existing
|
25
25
|
|
26
|
-
|
26
|
+
ThinkingSphinx.reset_context! existing
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
@@ -49,7 +49,6 @@ describe ThinkingSphinx do
|
|
49
49
|
|
50
50
|
describe '.deltas_enabled?' do
|
51
51
|
it "should index deltas by default" do
|
52
|
-
ThinkingSphinx.deltas_enabled = nil
|
53
52
|
ThinkingSphinx.deltas_enabled?.should be_true
|
54
53
|
end
|
55
54
|
end
|
@@ -134,7 +133,7 @@ describe ThinkingSphinx do
|
|
134
133
|
:connection => @connection
|
135
134
|
)
|
136
135
|
|
137
|
-
|
136
|
+
ThinkingSphinx.reset_use_group_by_shortcut
|
138
137
|
end
|
139
138
|
|
140
139
|
it "should return true if no ONLY_FULL_GROUP_BY" do
|