thinking-sphinx 1.4.12 → 1.4.13

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,16 +2,23 @@ module ThinkingSphinx
2
2
  module ActiveRecord
3
3
  module HasManyAssociation
4
4
  def search(*args)
5
- options = args.extract_options!
5
+ @reflection.klass.search(*association_args(args))
6
+ end
7
+
8
+ def facets(*args)
9
+ @reflection.klass.facets(*association_args(args))
10
+ end
11
+
12
+ private
13
+
14
+ def association_args(args)
15
+ options = args.extract_options!
6
16
  options[:with] ||= {}
7
17
  options[:with].merge! default_filter
8
-
9
- args << options
10
- @reflection.klass.search(*args)
18
+
19
+ args + [options]
11
20
  end
12
21
 
13
- private
14
-
15
22
  def attribute_for_foreign_key
16
23
  foreign_key = @reflection.primary_key_name
17
24
  stack = [@reflection.options[:through]].compact
@@ -33,9 +33,9 @@ module ThinkingSphinx
33
33
 
34
34
  def cast_to_datetime(clause)
35
35
  if ThinkingSphinx::Configuration.instance.use_64_bit
36
- "cast(extract(epoch from #{clause}) as bigint)"
36
+ "cast(floor(extract(epoch from #{clause})) as bigint)"
37
37
  else
38
- "cast(extract(epoch from #{clause}) as int)"
38
+ "cast(floor(extract(epoch from #{clause})) as int)"
39
39
  end
40
40
  end
41
41
 
@@ -109,7 +109,7 @@ module ThinkingSphinx
109
109
  end
110
110
 
111
111
  def create_array_accum_function
112
- if server_version >= 80400
112
+ if server_version >= 80311
113
113
  return
114
114
  elsif server_version > 80200
115
115
  execute <<-SQL
@@ -9,7 +9,7 @@ module ThinkingSphinx
9
9
  require 'riddle/1.10'
10
10
  when /2.0.[12]/
11
11
  require 'riddle/2.0.1'
12
- when /2.0.3/, /2.0.4/, /2.1.\d/
12
+ when /2.0.[^12]/, /2.1.\d/
13
13
  require 'riddle/2.1.0'
14
14
  else
15
15
  documentation_link = %Q{
@@ -1,41 +1,41 @@
1
1
  module ThinkingSphinx
2
2
  class BundledSearch
3
3
  attr_reader :client
4
-
4
+
5
5
  def initialize
6
6
  @searches = []
7
7
  end
8
-
8
+
9
9
  def search(*args)
10
10
  @searches << ThinkingSphinx.search(*args)
11
11
  @searches.last.append_to client
12
12
  end
13
-
13
+
14
14
  def search_for_ids(*args)
15
15
  @searches << ThinkingSphinx.search_for_ids(*args)
16
16
  @searches.last.append_to client
17
17
  end
18
-
18
+
19
19
  def searches
20
20
  populate
21
21
  @searches
22
22
  end
23
-
23
+
24
24
  private
25
-
25
+
26
26
  def client
27
27
  @client ||= ThinkingSphinx::Configuration.instance.client
28
28
  end
29
-
29
+
30
30
  def populated?
31
31
  @populated
32
32
  end
33
-
33
+
34
34
  def populate
35
35
  return if populated?
36
-
36
+
37
37
  @populated = true
38
-
38
+
39
39
  client.run.each_with_index do |results, index|
40
40
  searches[index].populate_from_queue results
41
41
  end
@@ -28,6 +28,7 @@ module ThinkingSphinx
28
28
  # html remove elements:: ''
29
29
  # searchd_binary_name:: searchd
30
30
  # indexer_binary_name:: indexer
31
+ # hard_retry_count:: 0
31
32
  #
32
33
  # If you want to change these settings, create a YAML file at
33
34
  # config/sphinx.yml with settings for each environment, in a similar
@@ -64,7 +65,8 @@ module ThinkingSphinx
64
65
 
65
66
  attr_accessor :searchd_file_path, :allow_star, :app_root,
66
67
  :model_directories, :delayed_job_priority, :indexed_models, :use_64_bit,
67
- :touched_reindex_file, :stop_timeout, :version, :shuffle
68
+ :touched_reindex_file, :stop_timeout, :version, :shuffle,
69
+ :hard_retry_count
68
70
 
69
71
  attr_accessor :source_options, :index_options
70
72
 
@@ -112,6 +114,7 @@ module ThinkingSphinx
112
114
  self.delayed_job_priority = 0
113
115
  self.indexed_models = []
114
116
  self.shuffle = false
117
+ self.hard_retry_count = 0
115
118
 
116
119
  self.source_options = {}
117
120
  self.index_options = {
@@ -405,28 +405,41 @@ module ThinkingSphinx
405
405
  def populate
406
406
  return if @populated
407
407
  @populated = true
408
+ retries = hard_retries
408
409
 
409
- retry_on_stale_index do
410
- begin
411
- log "Querying: '#{query}'"
412
- runtime = Benchmark.realtime {
413
- @results = client.query query, indexes, comment
414
- }
415
- log "Found #{@results[:total_found]} results", :debug,
416
- "Sphinx (#{sprintf("%f", runtime)}s)"
417
-
418
- log "Sphinx Daemon returned warning: #{warning}", :error if warning?
419
-
420
- if error?
421
- log "Sphinx Daemon returned error: #{error}", :error
422
- raise SphinxError.new(error, @results) unless options[:ignore_errors]
410
+ begin
411
+ retry_on_stale_index do
412
+ begin
413
+ log "Querying: '#{query}'"
414
+ runtime = Benchmark.realtime {
415
+ @results = client.query query, indexes, comment
416
+ }
417
+ log "Found #{@results[:total_found]} results", :debug,
418
+ "Sphinx (#{sprintf("%f", runtime)}s)"
419
+
420
+ log "Sphinx Daemon returned warning: #{warning}", :error if warning?
421
+
422
+ if error?
423
+ log "Sphinx Daemon returned error: #{error}", :error
424
+ raise SphinxError.new(error, @results) unless options[:ignore_errors]
425
+ end
426
+ rescue Errno::ECONNREFUSED => err
427
+ raise ThinkingSphinx::ConnectionError,
428
+ 'Connection to Sphinx Daemon (searchd) failed.'
423
429
  end
424
- rescue Errno::ECONNREFUSED => err
425
- raise ThinkingSphinx::ConnectionError,
426
- 'Connection to Sphinx Daemon (searchd) failed.'
427
- end
428
430
 
429
- compose_results
431
+ compose_results
432
+ end
433
+ rescue => e
434
+ log 'Caught Sphinx exception: %s (%s %s left)' % [
435
+ e.message, retries, (retries == 1 ? 'try' : 'tries')
436
+ ]
437
+ retries -= 1
438
+ if retries >= 0
439
+ retry
440
+ else
441
+ raise e
442
+ end
430
443
  end
431
444
  end
432
445
 
@@ -847,6 +860,10 @@ module ThinkingSphinx
847
860
  end
848
861
  end
849
862
 
863
+ def hard_retries
864
+ options[:hard_retry_count] || config.hard_retry_count
865
+ end
866
+
850
867
  def include_for_class(klass)
851
868
  includes = options[:include] || klass.sphinx_index_options[:include]
852
869
 
@@ -1,3 +1,3 @@
1
1
  module ThinkingSphinx
2
- Version = '1.4.12'
2
+ Version = '1.4.13'
3
3
  end
@@ -41,6 +41,46 @@ describe 'ThinkingSphinx::ActiveRecord::HasManyAssociation' do
41
41
  end
42
42
  end
43
43
 
44
+ describe "facets method" do
45
+ before :each do
46
+ Friendship.stub!(:facets => true)
47
+
48
+ @person = Person.find(:first)
49
+ @index = Friendship.sphinx_indexes.first
50
+ end
51
+
52
+ it "should raise an error if the required attribute doesn't exist" do
53
+ @index.stub!(:attributes => [])
54
+
55
+ lambda { @person.friendships.facets "test" }.should raise_error(RuntimeError)
56
+ end
57
+
58
+ it "should add a filter for the attribute into a normal facets call" do
59
+ Friendship.should_receive(:facets) do |query, options|
60
+ options[:with][:person_id].should == @person.id
61
+ end
62
+
63
+ @person.friendships.facets "test"
64
+ end
65
+
66
+ it "should add a filter for an aliased attribute into a normal facets call" do
67
+ @team = CricketTeam.new
68
+ @team.stub!(:id => 1)
69
+
70
+ Person.should_receive(:facets).with do |query, options|
71
+ options[:with][:team_id].should == @team.id
72
+ end
73
+
74
+ @team.people.facets "test"
75
+ end
76
+
77
+ it "should define indexes for the reflection class" do
78
+ Friendship.should_receive(:define_indexes)
79
+
80
+ @person.friendships.facets 'test'
81
+ end
82
+ end
83
+
44
84
  describe "search method for has_many :through" do
45
85
  before :each do
46
86
  Person.stub!(:search => true)
@@ -75,6 +115,40 @@ describe 'ThinkingSphinx::ActiveRecord::HasManyAssociation' do
75
115
  end
76
116
  end
77
117
 
118
+ describe "facets method for has_many :through" do
119
+ before :each do
120
+ Person.stub!(:facets => true)
121
+
122
+ @person = Person.find(:first)
123
+ @index = Person.sphinx_indexes.first
124
+ end
125
+
126
+ it "should raise an error if the required attribute doesn't exist" do
127
+ @index.stub!(:attributes => [])
128
+
129
+ lambda { @person.friends.facets "test" }.should raise_error(RuntimeError)
130
+ end
131
+
132
+ it "should add a filter for the attribute into a normal facets call" do
133
+ Person.should_receive(:facets).with do |query, options|
134
+ options[:with][:friendly_ids].should == @person.id
135
+ end
136
+
137
+ @person.friends.facets "test"
138
+ end
139
+
140
+ it "should add a filter for an aliased attribute into a normal facets call" do
141
+ @team = FootballTeam.new
142
+ @team.stub!(:id => 1)
143
+
144
+ Person.should_receive(:facets).with do |query, options|
145
+ options[:with][:football_team_id].should == @team.id
146
+ end
147
+
148
+ @team.people.facets "test"
149
+ end
150
+ end
151
+
78
152
  describe 'filtering sphinx scopes' do
79
153
  before :each do
80
154
  Friendship.stub!(:search => Friendship)
@@ -62,6 +62,22 @@ describe ThinkingSphinx::AutoVersion do
62
62
  ThinkingSphinx::AutoVersion.detect
63
63
  end
64
64
 
65
+ it "should require 2.1.0 if using Sphinx 2.0.3" do
66
+ ThinkingSphinx::AutoVersion.should_receive(:require).
67
+ with('riddle/2.1.0')
68
+
69
+ @config.stub!(:version => '2.0.4-release')
70
+ ThinkingSphinx::AutoVersion.detect
71
+ end
72
+
73
+ it "should require 2.1.0 if using Sphinx 2.0.3" do
74
+ ThinkingSphinx::AutoVersion.should_receive(:require).
75
+ with('riddle/2.1.0')
76
+
77
+ @config.stub!(:version => '2.0.5-release')
78
+ ThinkingSphinx::AutoVersion.detect
79
+ end
80
+
65
81
  it "should require 2.1.0 if using Sphinx 2.1.0 dev" do
66
82
  ThinkingSphinx::AutoVersion.should_receive(:require).
67
83
  with('riddle/2.1.0')
@@ -411,6 +411,38 @@ describe ThinkingSphinx::Search do
411
411
  'baz @foo bar @(foo,bar) baz', :star => true
412
412
  ).first
413
413
  end
414
+
415
+ it "should try retry query up to the hard_retry_count option times if it catches an exception" do
416
+ @client.should_receive(:query).exactly(4).and_raise("Test Exception")
417
+
418
+ expect { ThinkingSphinx::Search.new(:hard_retry_count => 3).first }.
419
+ to raise_error("Test Exception")
420
+ end
421
+
422
+ it "should not retry query if hard_retry_count option is not set" do
423
+ @client.should_receive(:query).exactly(1).and_raise("Test Exception")
424
+
425
+ expect { ThinkingSphinx::Search.new.first }.
426
+ to raise_error("Test Exception")
427
+ end
428
+
429
+ it "should allow the hard_retry_count to be globally set as a configuration option" do
430
+ @config.hard_retry_count = 2
431
+
432
+ @client.should_receive(:query).exactly(3).and_raise("Test Exception")
433
+
434
+ expect { ThinkingSphinx::Search.new.first }.
435
+ to raise_error("Test Exception")
436
+ end
437
+
438
+ it "should give priority to the hard_retry_count search option over the globally configured option" do
439
+ @config.hard_retry_count = 4
440
+
441
+ @client.should_receive(:query).exactly(2).and_raise("Test Exception")
442
+
443
+ expect { ThinkingSphinx::Search.new(:hard_retry_count => 1).first }.
444
+ to raise_error("Test Exception")
445
+ end
414
446
  end
415
447
 
416
448
  describe 'comment' do
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thinking-sphinx
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
4
+ hash: 29
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 4
9
- - 12
10
- version: 1.4.12
9
+ - 13
10
+ version: 1.4.13
11
11
  platform: ruby
12
12
  authors:
13
13
  - Pat Allan
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-05-14 00:00:00 Z
18
+ date: 2012-08-10 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  type: :runtime
@@ -64,12 +64,12 @@ dependencies:
64
64
  requirements:
65
65
  - - ">="
66
66
  - !ruby/object:Gem::Version
67
- hash: 7
67
+ hash: 5
68
68
  segments:
69
69
  - 1
70
70
  - 5
71
- - 2
72
- version: 1.5.2
71
+ - 3
72
+ version: 1.5.3
73
73
  version_requirements: *id003
74
74
  prerelease: false
75
75
  name: riddle