thinking-sphinx 1.3.20 → 1.4.0

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.
Files changed (33) hide show
  1. data/README.textile +3 -0
  2. data/VERSION +1 -1
  3. data/features/excerpts.feature +8 -0
  4. data/features/field_sorting.feature +18 -0
  5. data/features/searching_across_models.feature +1 -1
  6. data/features/searching_by_model.feature +0 -7
  7. data/features/sphinx_scopes.feature +18 -0
  8. data/features/step_definitions/common_steps.rb +4 -0
  9. data/features/step_definitions/search_steps.rb +5 -0
  10. data/features/support/env.rb +3 -5
  11. data/features/thinking_sphinx/db/fixtures/people.rb +1 -1
  12. data/features/thinking_sphinx/models/andrew.rb +17 -0
  13. data/features/thinking_sphinx/models/person.rb +2 -1
  14. data/lib/thinking_sphinx.rb +2 -0
  15. data/lib/thinking_sphinx/active_record.rb +1 -1
  16. data/lib/thinking_sphinx/active_record/scopes.rb +7 -0
  17. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +38 -8
  18. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +6 -2
  19. data/lib/thinking_sphinx/attribute.rb +5 -0
  20. data/lib/thinking_sphinx/configuration.rb +11 -7
  21. data/lib/thinking_sphinx/context.rb +4 -2
  22. data/lib/thinking_sphinx/property.rb +1 -0
  23. data/lib/thinking_sphinx/search.rb +66 -36
  24. data/lib/thinking_sphinx/tasks.rb +7 -0
  25. data/spec/thinking_sphinx/active_record/has_many_association_spec.rb +1 -0
  26. data/spec/thinking_sphinx/active_record/scopes_spec.rb +2 -3
  27. data/spec/thinking_sphinx/adapters/abstract_adapter_spec.rb +134 -0
  28. data/spec/thinking_sphinx/configuration_spec.rb +7 -0
  29. data/spec/thinking_sphinx/context_spec.rb +3 -2
  30. data/spec/thinking_sphinx/search_spec.rb +67 -25
  31. data/tasks/distribution.rb +0 -14
  32. data/tasks/testing.rb +29 -21
  33. metadata +227 -91
@@ -172,3 +172,6 @@ Since I first released this library, there's been quite a few people who have su
172
172
  * Ben Hutton
173
173
  * Alfonso Jiménez
174
174
  * Szymon Nowak
175
+ * Keith Pitt
176
+ * Lee Capps
177
+ * Sam Goldstein
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.3.20
1
+ 1.4.0
@@ -11,3 +11,11 @@ Feature: Generate excerpts for search results
11
11
  And I am searching on comments
12
12
  And I search for "lorem"
13
13
  Then calling content on the first result excerpts object should return "de un sitio mientras que mira su diseño. El punto de usar <span class="match">Lorem</span> Ipsum es que tiene una distribución"
14
+
15
+ Scenario: Excerpt Options
16
+ Given Sphinx is running
17
+ And I am searching on comments
18
+ And I search for "lorem"
19
+ And I provide excerpt option "before_match" with value "<em>"
20
+ And I provide excerpt option "after_match" with value "</em>"
21
+ Then calling content on the first result excerpts object should return "de un sitio mientras que mira su diseño. El punto de usar <em>Lorem</em> Ipsum es que tiene una distribución"
@@ -0,0 +1,18 @@
1
+ Feature: Field Sorting
2
+ In order to sort by strings
3
+ As a developer
4
+ I want to enable sorting by existing fields
5
+
6
+ Background:
7
+ Given Sphinx is running
8
+ And I am searching on people
9
+
10
+ Scenario: Searching with ordering on a sortable field
11
+ When I order by first_name
12
+ Then I should get 20 results
13
+ And the first_name of each result should indicate order
14
+
15
+ Scenario: Sort on a case insensitive sortable field
16
+ When I order by last_name
17
+ Then the first result's "last_name" should be "abbott"
18
+
@@ -7,7 +7,7 @@ Feature: Searching across multiple model
7
7
  Given Sphinx is running
8
8
  When I search for James
9
9
  And I am retrieving the result count
10
- Then I should get a value of 3
10
+ Then I should get a value of 6
11
11
 
12
12
  Scenario: Confirming existance of a document id in a given index
13
13
  Given Sphinx is running
@@ -97,13 +97,6 @@ Feature: Searching on a single model
97
97
  Then I should get 10 results
98
98
  And the value of each result should indicate order
99
99
 
100
- Scenario: Searching with ordering on a sortable field
101
- Given Sphinx is running
102
- And I am searching on people
103
- And I order by first_name
104
- Then I should get 20 results
105
- And the first_name of each result should indicate order
106
-
107
100
  Scenario: Intepreting Sphinx Internal Identifiers
108
101
  Given Sphinx is running
109
102
  And I am searching on people
@@ -48,3 +48,21 @@ Feature: Sphinx Scopes
48
48
  And I am retrieving the scoped result count for "Byrne"
49
49
  Then I should get a value of 1
50
50
 
51
+ Scenario: Default Scope
52
+ Given Sphinx is running
53
+ And I am searching on andrews
54
+ Then I should get 7 results
55
+
56
+ Scenario: Default Scope and additional query terms
57
+ Given Sphinx is running
58
+ And I am searching on andrews
59
+ When I search for "Byrne"
60
+ Then I should get 1 result
61
+
62
+ Scenario: Explicit scope plus search over a default scope
63
+ Given Sphinx is running
64
+ And I am searching on andrews
65
+ When I use the locked_last_name scope
66
+ And I search for "Cecil"
67
+ Then I should get 1 result
68
+
@@ -155,6 +155,10 @@ Then /^the (\w+) of each result should indicate order$/ do |attribute|
155
155
  end
156
156
  end
157
157
 
158
+ Then /^the first result's "([^"]*)" should be "([^"]*)"$/ do |attribute, value|
159
+ results.first.send(attribute.to_sym).should == value
160
+ end
161
+
158
162
  Then /^I can iterate by result and (\w+)$/ do |attribute|
159
163
  iteration = lambda { |result, attr_value|
160
164
  result.should be_kind_of(@model)
@@ -87,3 +87,8 @@ end
87
87
  Then /^the first result should have a (\w+\s?\w*) of (\d+)$/ do |attribute, value|
88
88
  results.first.sphinx_attributes[attribute.gsub(/\s+/, '_')].should == value.to_i
89
89
  end
90
+
91
+ Given /^I provide excerpt option "([a-z_]*)" with value "([^"]*)"$/ do |k, v|
92
+ @options[:excerpt_options] ||= {}
93
+ @options[:excerpt_options][k.to_sym] = v
94
+ end
@@ -1,10 +1,8 @@
1
1
  require 'rubygems'
2
- require 'cucumber'
3
- require 'spec'
4
2
  require 'fileutils'
5
- require 'ginger'
6
- require 'will_paginate'
7
- require 'active_record'
3
+ require 'bundler'
4
+
5
+ Bundler.require :default, :development
8
6
 
9
7
  $:.unshift File.dirname(__FILE__) + '/../../lib'
10
8
  Dir[File.join(File.dirname(__FILE__), '../../vendor/*/lib')].each do |path|
@@ -18,7 +18,7 @@ Person.create :gender => "male", :first_name => "Peter", :middle_initial => "C",
18
18
  Person.create :gender => "female", :first_name => "Hollie", :middle_initial => "C", :last_name => "Hunter", :street_address => "34 Cornish Street", :city => "Kensington", :state => "VIC", :postcode => "3031", :email => "Hollie.C.Hunter@mailinator.com", :birthday => "1954/2/16 00:00:00"
19
19
  Person.create :gender => "male", :first_name => "Jonathan", :middle_initial => "C", :last_name => "Turner", :street_address => "2 Kopkes Road", :city => "Carngham", :state => "VIC", :postcode => "3351", :email => "Jonathan.C.Turner@trashymail.com", :birthday => "1963/8/26 00:00:00"
20
20
  Person.create :gender => "female", :first_name => "Kate", :middle_initial => "S", :last_name => "Doyle", :street_address => "42 Gregory Way", :city => "Mungalup", :state => "WA", :postcode => "6225", :email => "Kate.S.Doyle@mailinator.com", :birthday => "1974/1/5 00:00:00"
21
- Person.create :gender => "male", :first_name => "Harley", :middle_initial => "M", :last_name => "Abbott", :street_address => "39 Faulkner Street", :city => "Tilbuster", :state => "NSW", :postcode => "2350", :email => "Harley.M.Abbott@trashymail.com", :birthday => "1953/10/4 00:00:00"
21
+ Person.create :gender => "male", :first_name => "Harley", :middle_initial => "M", :last_name => "abbott", :street_address => "39 Faulkner Street", :city => "Tilbuster", :state => "NSW", :postcode => "2350", :email => "Harley.M.Abbott@trashymail.com", :birthday => "1953/10/4 00:00:00"
22
22
  Person.create :gender => "male", :first_name => "Morgan", :middle_initial => "E", :last_name => "Iqbal", :street_address => "64 Carlisle Street", :city => "Dysart", :state => "VIC", :postcode => "3660", :email => "Morgan.E.Iqbal@spambob.com", :birthday => "1954/7/6 00:00:00"
23
23
  Person.create :gender => "female", :first_name => "Phoebe", :middle_initial => "T", :last_name => "Wells", :street_address => "10 Mnimbah Road", :city => "Eccleston", :state => "NSW", :postcode => "2311", :email => "Phoebe.T.Wells@trashymail.com", :birthday => "1949/5/27 00:00:00"
24
24
  Person.create :gender => "male", :first_name => "Finley", :middle_initial => "I", :last_name => "Martin", :street_address => "15 Thomas Lane", :city => "Epping", :state => "VIC", :postcode => "3076", :email => "Finley.I.Martin@dodgit.com", :birthday => "1983/3/12 00:00:00"
@@ -0,0 +1,17 @@
1
+ require "#{File.dirname(__FILE__)}/person"
2
+
3
+ class Andrew < ActiveRecord::Base
4
+ set_table_name 'people'
5
+
6
+ define_index do
7
+ indexes first_name, last_name, street_address
8
+ end
9
+
10
+ sphinx_scope(:locked_first_name) {
11
+ {:conditions => {:first_name => 'Andrew'}}
12
+ }
13
+ sphinx_scope(:locked_last_name) {
14
+ {:conditions => {:last_name => 'Byrne'}}
15
+ }
16
+ default_sphinx_scope :locked_first_name
17
+ end
@@ -1,6 +1,7 @@
1
1
  class Person < ActiveRecord::Base
2
2
  define_index do
3
- indexes first_name, last_name, :sortable => true
3
+ indexes first_name, :sortable => true
4
+ indexes last_name, :sortable => :insensitive
4
5
 
5
6
  has [first_name, middle_initial, last_name], :as => :name_sort
6
7
  has birthday
@@ -37,6 +37,8 @@ Merb::Plugins.add_rakefiles(
37
37
  ) if defined?(Merb)
38
38
 
39
39
  module ThinkingSphinx
40
+ mattr_accessor :database_adapter
41
+
40
42
  # A ConnectionError will get thrown when a connection to Sphinx can't be
41
43
  # made.
42
44
  class ConnectionError < StandardError
@@ -363,7 +363,7 @@ module ThinkingSphinx
363
363
  # @return [Integer] Unique record id for the purposes of Sphinx.
364
364
  #
365
365
  def primary_key_for_sphinx
366
- @primary_key_for_sphinx ||= read_attribute(self.class.primary_key_for_sphinx)
366
+ read_attribute(self.class.primary_key_for_sphinx)
367
367
  end
368
368
 
369
369
  def sphinx_document_id
@@ -53,6 +53,13 @@ module ThinkingSphinx
53
53
 
54
54
  ThinkingSphinx::Search.new(options)
55
55
  end
56
+
57
+ define_method("#{method}_without_default".to_sym) do |*args|
58
+ options = {:classes => classes_option, :ignore_default => true}
59
+ options.merge! block.call(*args)
60
+
61
+ ThinkingSphinx::Search.new(options)
62
+ end
56
63
  end
57
64
  end
58
65
 
@@ -10,24 +10,50 @@ module ThinkingSphinx
10
10
  end
11
11
 
12
12
  def self.detect(model)
13
+ adapter = adapter_for_model model
14
+ case adapter
15
+ when :mysql
16
+ ThinkingSphinx::MysqlAdapter.new model
17
+ when :postgresql
18
+ ThinkingSphinx::PostgreSQLAdapter.new model
19
+ else
20
+ raise "Invalid Database Adapter: Sphinx only supports MySQL and PostgreSQL, not #{adapter}"
21
+ end
22
+ end
23
+
24
+ def self.adapter_for_model(model)
25
+ case ThinkingSphinx.database_adapter
26
+ when String
27
+ ThinkingSphinx.database_adapter.to_sym
28
+ when NilClass
29
+ standard_adapter_for_model model
30
+ when Proc
31
+ ThinkingSphinx.database_adapter.call model
32
+ else
33
+ ThinkingSphinx.database_adapter
34
+ end
35
+ end
36
+
37
+ def self.standard_adapter_for_model(model)
13
38
  case model.connection.class.name
14
39
  when "ActiveRecord::ConnectionAdapters::MysqlAdapter",
15
40
  "ActiveRecord::ConnectionAdapters::MysqlplusAdapter",
16
41
  "ActiveRecord::ConnectionAdapters::Mysql2Adapter",
17
42
  "ActiveRecord::ConnectionAdapters::NullDBAdapter"
18
- ThinkingSphinx::MysqlAdapter.new model
43
+ :mysql
19
44
  when "ActiveRecord::ConnectionAdapters::PostgreSQLAdapter"
20
- ThinkingSphinx::PostgreSQLAdapter.new model
45
+ :postgresql
21
46
  when "ActiveRecord::ConnectionAdapters::JdbcAdapter"
22
- if model.connection.config[:adapter] == "jdbcmysql"
23
- ThinkingSphinx::MysqlAdapter.new model
24
- elsif model.connection.config[:adapter] == "jdbcpostgresql"
25
- ThinkingSphinx::PostgreSQLAdapter.new model
47
+ case model.connection.config[:adapter]
48
+ when "jdbcmysql"
49
+ :mysql
50
+ when "jdbcpostgresql"
51
+ :postgresql
26
52
  else
27
- raise "Invalid Database Adapter: Sphinx only supports MySQL and PostgreSQL"
53
+ model.connection.config[:adapter]
28
54
  end
29
55
  else
30
- raise "Invalid Database Adapter: Sphinx only supports MySQL and PostgreSQL, not #{model.connection.class.name}"
56
+ model.connection.class.name
31
57
  end
32
58
  end
33
59
 
@@ -39,6 +65,10 @@ module ThinkingSphinx
39
65
  /bigint/i
40
66
  end
41
67
 
68
+ def downcase(clause)
69
+ "LOWER(#{clause})"
70
+ end
71
+
42
72
  protected
43
73
 
44
74
  def connection
@@ -68,7 +68,7 @@ module ThinkingSphinx
68
68
  end
69
69
 
70
70
  def utc_query_pre
71
- 'SET TIME ZONE UTC'
71
+ "SET TIME ZONE 'UTC'"
72
72
  end
73
73
 
74
74
  private
@@ -119,6 +119,10 @@ module ThinkingSphinx
119
119
  DECLARE j int;
120
120
  DECLARE word_array bytea;
121
121
  BEGIN
122
+ IF COALESCE(word, '') = '' THEN
123
+ return 0;
124
+ END IF;
125
+
122
126
  i = 0;
123
127
  tmp = 4294967295;
124
128
  word_array = decode(replace(word, E'\\\\', E'\\\\\\\\'), 'escape');
@@ -139,7 +143,7 @@ module ThinkingSphinx
139
143
  END LOOP;
140
144
  return (tmp # 4294967295);
141
145
  END
142
- $$ IMMUTABLE STRICT LANGUAGE plpgsql;
146
+ $$ IMMUTABLE LANGUAGE plpgsql;
143
147
  SQL
144
148
  execute function, true
145
149
  end
@@ -111,6 +111,7 @@ module ThinkingSphinx
111
111
  clause = adapter.crc(clause) if @crc
112
112
  clause = adapter.concatenate(clause, separator) if concat_ws?
113
113
  clause = adapter.group_concatenate(clause, separator) if is_many?
114
+ clause = adapter.downcase(clause) if insensitive?
114
115
 
115
116
  "#{clause} AS #{quote_column(unique_name)}"
116
117
  end
@@ -376,5 +377,9 @@ block:
376
377
  value
377
378
  end
378
379
  end
380
+
381
+ def insensitive?
382
+ @sortable == :insensitive
383
+ end
379
384
  end
380
385
  end
@@ -54,13 +54,14 @@ module ThinkingSphinx
54
54
  sql_query_killlist sql_ranged_throttle sql_query_post_index unpack_zlib
55
55
  unpack_mysqlcompress unpack_mysqlcompress_maxsize )
56
56
 
57
- IndexOptions = %w( charset_table charset_type charset_dictpath docinfo
58
- enable_star exceptions html_index_attrs html_remove_elements html_strip
59
- index_exact_words ignore_chars inplace_docinfo_gap inplace_enable
60
- inplace_hit_gap inplace_reloc_factor inplace_write_factor min_infix_len
61
- min_prefix_len min_stemming_len min_word_len mlock morphology ngram_chars
62
- ngram_len ondisk_dict overshort_step phrase_boundary phrase_boundary_step
63
- preopen stopwords stopwords_step wordforms )
57
+ IndexOptions = %w( blend_chars charset_table charset_type charset_dictpath
58
+ docinfo enable_star exceptions expand_keywords hitless_words
59
+ html_index_attrs html_remove_elements html_strip index_exact_words
60
+ ignore_chars inplace_docinfo_gap inplace_enable inplace_hit_gap
61
+ inplace_reloc_factor inplace_write_factor min_infix_len min_prefix_len
62
+ min_stemming_len min_word_len mlock morphology ngram_chars ngram_len
63
+ ondisk_dict overshort_step phrase_boundary phrase_boundary_step preopen
64
+ stopwords stopwords_step wordforms )
64
65
 
65
66
  CustomOptions = %w( disable_range )
66
67
 
@@ -233,9 +234,12 @@ module ThinkingSphinx
233
234
  @controller.indexer_binary_name = name
234
235
  end
235
236
 
237
+ attr_accessor :timeout
238
+
236
239
  def client
237
240
  client = Riddle::Client.new address, port
238
241
  client.max_matches = configuration.searchd.max_matches || 1000
242
+ client.timeout = timeout || 0
239
243
  client
240
244
  end
241
245
 
@@ -65,8 +65,10 @@ class ThinkingSphinx::Context
65
65
  model_name.gsub!(/.*[\/\\]/, '').nil? ? next : retry
66
66
  rescue NameError
67
67
  next
68
- rescue StandardError
69
- STDERR.puts "Warning: Error loading #{file}"
68
+ rescue StandardError => err
69
+ STDERR.puts "Warning: Error loading #{file}:"
70
+ STDERR.puts err.message
71
+ STDERR.puts err.backtrace.join("\n"), ''
70
72
  end
71
73
  end
72
74
  end
@@ -13,6 +13,7 @@ module ThinkingSphinx
13
13
  @alias = options[:as]
14
14
  @faceted = options[:facet]
15
15
  @admin = options[:admin]
16
+ @sortable = options[:sortable] || false
16
17
 
17
18
  @alias = @alias.to_sym unless @alias.blank?
18
19
 
@@ -86,6 +86,8 @@ module ThinkingSphinx
86
86
  @options = args.extract_options!
87
87
  @args = args
88
88
 
89
+ add_default_scope unless options[:ignore_default]
90
+
89
91
  populate if @options[:populate]
90
92
  end
91
93
 
@@ -123,7 +125,7 @@ module ThinkingSphinx
123
125
  add_scope(method, *args, &block)
124
126
  return self
125
127
  elsif method == :search_count
126
- merge_search one_class.search(*args)
128
+ merge_search one_class.search(*args), self.args, options
127
129
  return scoped_count
128
130
  elsif method.to_s[/^each_with_.*/].nil? && !@array.respond_to?(method)
129
131
  super
@@ -270,18 +272,43 @@ module ThinkingSphinx
270
272
 
271
273
  populate
272
274
  client.excerpts(
273
- :docs => [string],
274
- :words => results[:words].keys.join(' '),
275
- :index => options[:index] || "#{model.source_of_sphinx_index.sphinx_name}_core"
275
+ {
276
+ :docs => [string.to_s],
277
+ :words => results[:words].keys.join(' '),
278
+ :index => options[:index] || "#{model.source_of_sphinx_index.sphinx_name}_core"
279
+ }.merge(options[:excerpt_options] || {})
276
280
  ).first
277
281
  end
278
282
 
279
283
  def search(*args)
280
- add_default_scope
281
- merge_search ThinkingSphinx::Search.new(*args)
284
+ args << args.extract_options!.merge(:ignore_default => true)
285
+ merge_search ThinkingSphinx::Search.new(*args), self.args, options
282
286
  self
283
287
  end
284
288
 
289
+ def search_for_ids(*args)
290
+ args << args.extract_options!.merge(
291
+ :ignore_default => true,
292
+ :ids_only => true
293
+ )
294
+ merge_search ThinkingSphinx::Search.new(*args), self.args, options
295
+ self
296
+ end
297
+
298
+ def facets(*args)
299
+ options = args.extract_options!
300
+ merge_search self, args, options
301
+ args << options
302
+
303
+ ThinkingSphinx::FacetSearch.new *args
304
+ end
305
+
306
+ def client
307
+ client = options[:client] || config.client
308
+
309
+ prepare client
310
+ end
311
+
285
312
  def append_to(client)
286
313
  prepare client
287
314
  client.append_query query, indexes, comment
@@ -382,9 +409,16 @@ module ThinkingSphinx
382
409
 
383
410
  def self.log(message, method = :debug, identifier = 'Sphinx')
384
411
  return if ::ActiveRecord::Base.logger.nil?
385
- identifier_color, message_color = "4;32;1", "0" # 0;1 = Bold
386
- info = " \e[#{identifier_color}m#{identifier}\e[0m "
387
- info << "\e[#{message_color}m#{message}\e[0m"
412
+
413
+ info = ''
414
+ if ::ActiveRecord::Base.colorize_logging
415
+ identifier_color, message_color = "4;32;1", "0" # 0;1 = Bold
416
+ info << " \e[#{identifier_color}m#{identifier}\e[0m "
417
+ info << "\e[#{message_color}m#{message}\e[0m"
418
+ else
419
+ info = "#{identifier} #{message}"
420
+ end
421
+
388
422
  ::ActiveRecord::Base.logger.send method, info
389
423
  end
390
424
 
@@ -392,12 +426,6 @@ module ThinkingSphinx
392
426
  self.class.log(*args)
393
427
  end
394
428
 
395
- def client
396
- client = config.client
397
-
398
- prepare client
399
- end
400
-
401
429
  def prepare(client)
402
430
  index_options = one_class ?
403
431
  one_class.sphinx_indexes.first.local_options : {}
@@ -489,7 +517,8 @@ module ThinkingSphinx
489
517
  query.gsub(/("#{token}(.*?#{token})?"|(?![!-])#{token})/u) do
490
518
  pre, proper, post = $`, $&, $'
491
519
  # E.g. "@foo", "/2", "~3", but not as part of a token
492
- is_operator = pre.match(%r{(\W|^)[@~/]\Z})
520
+ is_operator = pre.match(%r{(\W|^)[@~/]\Z}) ||
521
+ pre.match(%r{(\W|^)@\([^\)]*$})
493
522
  # E.g. "foo bar", with quotes
494
523
  is_quote = proper.starts_with?('"') && proper.ends_with?('"')
495
524
  has_star = pre.ends_with?("*") || post.starts_with?("*")
@@ -603,24 +632,8 @@ module ThinkingSphinx
603
632
  filters
604
633
  end
605
634
 
606
- def condition_filters
607
- (options[:conditions] || {}).collect { |attrib, value|
608
- if attributes.include?(attrib.to_sym)
609
- puts <<-MSG
610
- Deprecation Warning: filters on attributes should be done using the :with
611
- option, not :conditions. For example:
612
- :with => {:#{attrib} => #{value.inspect}}
613
- MSG
614
- Riddle::Client::Filter.new attrib.to_s, filter_value(value)
615
- else
616
- nil
617
- end
618
- }.compact
619
- end
620
-
621
635
  def filters
622
636
  internal_filters +
623
- condition_filters +
624
637
  (options[:with] || {}).collect { |attrib, value|
625
638
  Riddle::Client::Filter.new attrib.to_s, filter_value(value)
626
639
  } +
@@ -708,6 +721,21 @@ MSG
708
721
  end
709
722
  end
710
723
 
724
+ def include_for_class(klass)
725
+ includes = options[:include] || klass.sphinx_index_options[:include]
726
+
727
+ case includes
728
+ when NilClass
729
+ nil
730
+ when Array
731
+ includes.select { |inc| klass.reflections[inc] }
732
+ when Symbol
733
+ klass.reflections[includes].nil? ? nil : includes
734
+ else
735
+ includes
736
+ end
737
+ end
738
+
711
739
  def instances_from_class(klass, matches)
712
740
  index_options = klass.sphinx_index_options
713
741
 
@@ -716,7 +744,7 @@ MSG
716
744
  :all,
717
745
  :joins => options[:joins],
718
746
  :conditions => {klass.primary_key_for_sphinx.to_sym => ids},
719
- :include => (options[:include] || index_options[:include]),
747
+ :include => include_for_class(klass),
720
748
  :select => (options[:select] || index_options[:select]),
721
749
  :order => (options[:sql_order] || index_options[:sql_order])
722
750
  ) : []
@@ -786,14 +814,16 @@ MSG
786
814
 
787
815
  # Adds the default_sphinx_scope if set.
788
816
  def add_default_scope
789
- add_scope(one_class.get_default_sphinx_scope) if one_class && one_class.has_default_sphinx_scope?
817
+ return unless one_class && one_class.has_default_sphinx_scope?
818
+ add_scope(one_class.get_default_sphinx_scope.to_sym)
790
819
  end
791
820
 
792
821
  def add_scope(method, *args, &block)
793
- merge_search one_class.send(method, *args, &block)
822
+ method = "#{method}_without_default".to_sym
823
+ merge_search one_class.send(method, *args, &block), self.args, options
794
824
  end
795
825
 
796
- def merge_search(search)
826
+ def merge_search(search, args, options)
797
827
  search.args.each { |arg| args << arg }
798
828
 
799
829
  search.options.keys.each do |key|