pixeltrix-thinking-sphinx 1.1.5 → 1.2.1

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 (76) hide show
  1. data/README.textile +147 -0
  2. data/lib/thinking_sphinx/active_record/attribute_updates.rb +48 -0
  3. data/lib/thinking_sphinx/active_record/delta.rb +14 -1
  4. data/lib/thinking_sphinx/active_record/scopes.rb +37 -0
  5. data/lib/thinking_sphinx/active_record.rb +46 -12
  6. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +9 -1
  7. data/lib/thinking_sphinx/adapters/mysql_adapter.rb +3 -2
  8. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +12 -5
  9. data/lib/thinking_sphinx/association.rb +20 -0
  10. data/lib/thinking_sphinx/attribute.rb +187 -116
  11. data/lib/thinking_sphinx/class_facet.rb +15 -0
  12. data/lib/thinking_sphinx/configuration.rb +46 -14
  13. data/lib/thinking_sphinx/core/string.rb +3 -10
  14. data/lib/thinking_sphinx/deltas/datetime_delta.rb +3 -3
  15. data/lib/thinking_sphinx/deltas/default_delta.rb +9 -6
  16. data/lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb +1 -1
  17. data/lib/thinking_sphinx/deltas/delayed_delta.rb +4 -2
  18. data/lib/thinking_sphinx/deltas.rb +14 -6
  19. data/lib/thinking_sphinx/deploy/capistrano.rb +98 -0
  20. data/lib/thinking_sphinx/excerpter.rb +22 -0
  21. data/lib/thinking_sphinx/facet.rb +68 -18
  22. data/lib/thinking_sphinx/facet_search.rb +134 -0
  23. data/lib/thinking_sphinx/field.rb +7 -97
  24. data/lib/thinking_sphinx/index/builder.rb +255 -201
  25. data/lib/thinking_sphinx/index.rb +28 -343
  26. data/lib/thinking_sphinx/property.rb +160 -0
  27. data/lib/thinking_sphinx/rails_additions.rb +7 -4
  28. data/lib/thinking_sphinx/search.rb +593 -587
  29. data/lib/thinking_sphinx/search_methods.rb +421 -0
  30. data/lib/thinking_sphinx/source/internal_properties.rb +46 -0
  31. data/lib/thinking_sphinx/source/sql.rb +128 -0
  32. data/lib/thinking_sphinx/source.rb +150 -0
  33. data/lib/thinking_sphinx/tasks.rb +45 -11
  34. data/lib/thinking_sphinx.rb +88 -14
  35. data/rails/init.rb +14 -0
  36. data/spec/{unit → lib}/thinking_sphinx/active_record/delta_spec.rb +7 -7
  37. data/spec/{unit → lib}/thinking_sphinx/active_record/has_many_association_spec.rb +0 -0
  38. data/spec/lib/thinking_sphinx/active_record/scopes_spec.rb +92 -0
  39. data/spec/{unit → lib}/thinking_sphinx/active_record_spec.rb +115 -42
  40. data/spec/{unit → lib}/thinking_sphinx/association_spec.rb +4 -5
  41. data/spec/lib/thinking_sphinx/attribute_spec.rb +465 -0
  42. data/spec/{unit → lib}/thinking_sphinx/configuration_spec.rb +118 -7
  43. data/spec/{unit → lib}/thinking_sphinx/core/string_spec.rb +0 -0
  44. data/spec/lib/thinking_sphinx/excerpter_spec.rb +49 -0
  45. data/spec/lib/thinking_sphinx/facet_search_spec.rb +176 -0
  46. data/spec/lib/thinking_sphinx/facet_spec.rb +302 -0
  47. data/spec/{unit → lib}/thinking_sphinx/field_spec.rb +26 -17
  48. data/spec/lib/thinking_sphinx/index/builder_spec.rb +355 -0
  49. data/spec/{unit → lib}/thinking_sphinx/index/faux_column_spec.rb +0 -0
  50. data/spec/{unit → lib}/thinking_sphinx/index_spec.rb +3 -12
  51. data/spec/lib/thinking_sphinx/rails_additions_spec.rb +191 -0
  52. data/spec/lib/thinking_sphinx/search_methods_spec.rb +152 -0
  53. data/spec/lib/thinking_sphinx/search_spec.rb +887 -0
  54. data/spec/lib/thinking_sphinx/source_spec.rb +217 -0
  55. data/spec/{unit → lib}/thinking_sphinx_spec.rb +30 -8
  56. data/tasks/distribution.rb +20 -1
  57. data/tasks/testing.rb +7 -15
  58. data/vendor/after_commit/init.rb +3 -0
  59. data/vendor/after_commit/lib/after_commit/active_record.rb +27 -4
  60. data/vendor/after_commit/lib/after_commit/connection_adapters.rb +1 -1
  61. data/vendor/after_commit/lib/after_commit.rb +4 -1
  62. data/vendor/riddle/lib/riddle/client/message.rb +4 -3
  63. data/vendor/riddle/lib/riddle/client.rb +3 -0
  64. data/vendor/riddle/lib/riddle/configuration/section.rb +8 -2
  65. data/vendor/riddle/lib/riddle/controller.rb +1 -1
  66. data/vendor/riddle/lib/riddle.rb +1 -1
  67. metadata +75 -39
  68. data/README +0 -107
  69. data/lib/thinking_sphinx/active_record/search.rb +0 -57
  70. data/lib/thinking_sphinx/collection.rb +0 -142
  71. data/lib/thinking_sphinx/facet_collection.rb +0 -44
  72. data/spec/unit/thinking_sphinx/active_record/search_spec.rb +0 -107
  73. data/spec/unit/thinking_sphinx/attribute_spec.rb +0 -212
  74. data/spec/unit/thinking_sphinx/collection_spec.rb +0 -14
  75. data/spec/unit/thinking_sphinx/index/builder_spec.rb +0 -5
  76. data/spec/unit/thinking_sphinx/search_spec.rb +0 -59
@@ -0,0 +1,150 @@
1
+ require 'thinking_sphinx/source/internal_properties'
2
+ require 'thinking_sphinx/source/sql'
3
+
4
+ module ThinkingSphinx
5
+ class Source
6
+ include ThinkingSphinx::Source::InternalProperties
7
+ include ThinkingSphinx::Source::SQL
8
+
9
+ attr_accessor :model, :fields, :attributes, :conditions, :groupings,
10
+ :options
11
+ attr_reader :base, :index
12
+
13
+ def initialize(index, options = {})
14
+ @index = index
15
+ @model = index.model
16
+ @fields = []
17
+ @attributes = []
18
+ @conditions = []
19
+ @groupings = []
20
+ @options = options
21
+ @associations = {}
22
+
23
+ @base = ::ActiveRecord::Associations::ClassMethods::JoinDependency.new(
24
+ @model, [], nil
25
+ )
26
+
27
+ unless @model.descends_from_active_record?
28
+ stored_class = @model.store_full_sti_class ? @model.name : @model.name.demodulize
29
+ @conditions << "#{@model.quoted_table_name}.#{quote_column(@model.inheritance_column)} = '#{stored_class}'"
30
+ end
31
+
32
+ add_internal_attributes_and_facets
33
+ end
34
+
35
+ def name
36
+ @model.name.underscore.tr(':/\\', '_')
37
+ end
38
+
39
+ def to_riddle_for_core(offset, index)
40
+ source = Riddle::Configuration::SQLSource.new(
41
+ "#{name}_core_#{index}", adapter.sphinx_identifier
42
+ )
43
+
44
+ set_source_database_settings source
45
+ set_source_attributes source, offset
46
+ set_source_sql source, offset
47
+ set_source_settings source
48
+
49
+ source
50
+ end
51
+
52
+ def to_riddle_for_delta(offset, index)
53
+ source = Riddle::Configuration::SQLSource.new(
54
+ "#{name}_delta_#{index}", adapter.sphinx_identifier
55
+ )
56
+ source.parent = "#{name}_core_#{index}"
57
+
58
+ set_source_database_settings source
59
+ set_source_attributes source, offset, true
60
+ set_source_sql source, offset, true
61
+
62
+ source
63
+ end
64
+
65
+ def delta?
66
+ !@index.delta_object.nil?
67
+ end
68
+
69
+ # Gets the association stack for a specific key.
70
+ #
71
+ def association(key)
72
+ @associations[key] ||= Association.children(@model, key)
73
+ end
74
+
75
+ private
76
+
77
+ def adapter
78
+ @adapter ||= @model.sphinx_database_adapter
79
+ end
80
+
81
+ def set_source_database_settings(source)
82
+ config = @model.connection.instance_variable_get(:@config)
83
+
84
+ source.sql_host = config[:host] || "localhost"
85
+ source.sql_user = config[:username] || config[:user] || ""
86
+ source.sql_pass = (config[:password].to_s || "").gsub('#', '\#')
87
+ source.sql_db = config[:database]
88
+ source.sql_port = config[:port]
89
+ source.sql_sock = config[:socket]
90
+ end
91
+
92
+ def set_source_attributes(source, offset, delta = false)
93
+ attributes.each do |attrib|
94
+ source.send(attrib.type_to_config) << attrib.config_value(offset, delta)
95
+ end
96
+ end
97
+
98
+ def set_source_sql(source, offset, delta = false)
99
+ source.sql_query = to_sql(:offset => offset, :delta => delta).gsub(/\n/, ' ')
100
+ source.sql_query_range = to_sql_query_range(:delta => delta)
101
+ source.sql_query_info = to_sql_query_info(offset)
102
+
103
+ source.sql_query_pre += send(!delta ? :sql_query_pre_for_core : :sql_query_pre_for_delta)
104
+
105
+ if @index.local_options[:group_concat_max_len]
106
+ source.sql_query_pre << "SET SESSION group_concat_max_len = #{@index.local_options[:group_concat_max_len]}"
107
+ end
108
+
109
+ source.sql_query_pre += [adapter.utf8_query_pre].compact if utf8?
110
+ end
111
+
112
+ def set_source_settings(source)
113
+ config = ThinkingSphinx::Configuration.instance
114
+ config.source_options.each do |key, value|
115
+ source.send("#{key}=".to_sym, value)
116
+ end
117
+
118
+ source_options = ThinkingSphinx::Configuration::SourceOptions
119
+ @options.each do |key, value|
120
+ if source_options.include?(key.to_s) && !value.nil?
121
+ source.send("#{key}=".to_sym, value)
122
+ end
123
+ end
124
+ end
125
+
126
+ # Returns all associations used amongst all the fields and attributes.
127
+ # This includes all associations between the model and what the actual
128
+ # columns are from.
129
+ #
130
+ def all_associations
131
+ @all_associations ||= (
132
+ # field associations
133
+ @fields.collect { |field|
134
+ field.associations.values
135
+ }.flatten +
136
+ # attribute associations
137
+ @attributes.collect { |attrib|
138
+ attrib.associations.values if attrib.include_as_association?
139
+ }.compact.flatten
140
+ ).uniq.collect { |assoc|
141
+ # get ancestors as well as column-level associations
142
+ assoc.ancestors
143
+ }.flatten.uniq
144
+ end
145
+
146
+ def utf8?
147
+ @index.options[:charset_type] == "utf-8"
148
+ end
149
+ end
150
+ end
@@ -2,14 +2,23 @@ require 'fileutils'
2
2
 
3
3
  namespace :thinking_sphinx do
4
4
  task :app_env do
5
- Rake::Task[:environment].invoke if defined?(RAILS_ROOT)
5
+ if defined?(RAILS_ROOT)
6
+ Rake::Task[:environment].invoke
7
+ Rails.configuration.cache_classes = false
8
+ end
9
+
6
10
  Rake::Task[:merb_env].invoke if defined?(Merb)
7
11
  end
8
12
 
13
+ desc "Output the current Thinking Sphinx version"
14
+ task :version => :app_env do
15
+ puts "Thinking Sphinx v" + ThinkingSphinx::Version::String
16
+ end
17
+
9
18
  desc "Stop if running, then start a Sphinx searchd daemon using Thinking Sphinx's settings"
10
19
  task :running_start => :app_env do
11
- Rake::Task["thinking_sphinx:stop"].invoke if sphinx_running?
12
- Rake::Task["thinking_sphinx:start"].invoke
20
+ Rake::Task["thinking_sphinx:stop"].invoke if sphinx_running?
21
+ Rake::Task["thinking_sphinx:start"].invoke
13
22
  end
14
23
 
15
24
  desc "Start a Sphinx searchd daemon using Thinking Sphinx's settings"
@@ -21,16 +30,14 @@ namespace :thinking_sphinx do
21
30
 
22
31
  Dir["#{config.searchd_file_path}/*.spl"].each { |file| File.delete(file) }
23
32
 
24
- cmd = "#{config.bin_path}searchd --pidfile --config #{config.config_file}"
25
- puts cmd
26
- system cmd
33
+ system! "#{config.bin_path}#{config.searchd_binary_name} --pidfile --config \"#{config.config_file}\""
27
34
 
28
35
  sleep(2)
29
36
 
30
37
  if sphinx_running?
31
38
  puts "Started successfully (pid #{sphinx_pid})."
32
39
  else
33
- puts "Failed to start searchd daemon. Check #{config.searchd_log_file}."
40
+ puts "Failed to start searchd daemon. Check #{config.searchd_log_file}"
34
41
  end
35
42
  end
36
43
 
@@ -39,7 +46,7 @@ namespace :thinking_sphinx do
39
46
  raise RuntimeError, "searchd is not running." unless sphinx_running?
40
47
  config = ThinkingSphinx::Configuration.instance
41
48
  pid = sphinx_pid
42
- system "searchd --stop --config #{config.config_file}"
49
+ system! "#{config.bin_path}#{config.searchd_binary_name} --stop --config \"#{config.config_file}\""
43
50
  puts "Stopped search daemon (pid #{pid})."
44
51
  end
45
52
 
@@ -64,10 +71,17 @@ namespace :thinking_sphinx do
64
71
  end
65
72
 
66
73
  FileUtils.mkdir_p config.searchd_file_path
67
- cmd = "#{config.bin_path}indexer --config #{config.config_file} --all"
74
+ cmd = "#{config.bin_path}#{config.indexer_binary_name} --config \"#{config.config_file}\" --all"
68
75
  cmd << " --rotate" if sphinx_running?
69
- puts cmd
70
- system cmd
76
+
77
+ system! cmd
78
+ end
79
+
80
+ desc "Stop Sphinx (if it's running), rebuild the indexes, and start Sphinx"
81
+ task :rebuild => :app_env do
82
+ Rake::Task["thinking_sphinx:stop"].invoke if sphinx_running?
83
+ Rake::Task["thinking_sphinx:index"].invoke
84
+ Rake::Task["thinking_sphinx:start"].invoke
71
85
  end
72
86
 
73
87
  namespace :index do
@@ -96,6 +110,8 @@ namespace :thinking_sphinx do
96
110
  end
97
111
 
98
112
  namespace :ts do
113
+ desc "Output the current Thinking Sphinx version"
114
+ task :version => "thinking_sphinx:version"
99
115
  desc "Stop if running, then start a Sphinx searchd daemon using Thinking Sphinx's settings"
100
116
  task :run => "thinking_sphinx:running_start"
101
117
  desc "Start a Sphinx searchd daemon using Thinking Sphinx's settings"
@@ -115,6 +131,8 @@ namespace :ts do
115
131
  task :conf => "thinking_sphinx:configure"
116
132
  desc "Generate the Sphinx configuration file using Thinking Sphinx's settings"
117
133
  task :config => "thinking_sphinx:configure"
134
+ desc "Stop Sphinx (if it's running), rebuild the indexes, and start Sphinx"
135
+ task :rebuild => "thinking_sphinx:rebuild"
118
136
  desc "Process stored delta index requests"
119
137
  task :dd => "thinking_sphinx:delayed_delta"
120
138
  end
@@ -126,3 +144,19 @@ end
126
144
  def sphinx_running?
127
145
  ThinkingSphinx.sphinx_running?
128
146
  end
147
+
148
+ # a fail-fast, hopefully helpful version of system
149
+ def system!(cmd)
150
+ unless system(cmd)
151
+ raise <<-SYSTEM_CALL_FAILED
152
+ The following command failed:
153
+ #{cmd}
154
+
155
+ This could be caused by a PATH issue in the environment of cron/passenger/etc. Your current PATH:
156
+ #{ENV['PATH']}
157
+ You can set the path to your indexer and searchd binaries using the bin_path property in config/sphinx.yml:
158
+ production:
159
+ bin_path: '/usr/local/bin'
160
+ SYSTEM_CALL_FAILED
161
+ end
162
+ end
@@ -7,17 +7,21 @@ require 'riddle'
7
7
  require 'after_commit'
8
8
 
9
9
  require 'thinking_sphinx/core/string'
10
+ require 'thinking_sphinx/property'
10
11
  require 'thinking_sphinx/active_record'
11
12
  require 'thinking_sphinx/association'
12
13
  require 'thinking_sphinx/attribute'
13
- require 'thinking_sphinx/collection'
14
14
  require 'thinking_sphinx/configuration'
15
+ require 'thinking_sphinx/excerpter'
15
16
  require 'thinking_sphinx/facet'
16
- require 'thinking_sphinx/facet_collection'
17
+ require 'thinking_sphinx/class_facet'
18
+ require 'thinking_sphinx/facet_search'
17
19
  require 'thinking_sphinx/field'
18
20
  require 'thinking_sphinx/index'
21
+ require 'thinking_sphinx/source'
19
22
  require 'thinking_sphinx/rails_additions'
20
23
  require 'thinking_sphinx/search'
24
+ require 'thinking_sphinx/search_methods'
21
25
  require 'thinking_sphinx/deltas'
22
26
 
23
27
  require 'thinking_sphinx/adapters/abstract_adapter'
@@ -33,8 +37,8 @@ Merb::Plugins.add_rakefiles(
33
37
  module ThinkingSphinx
34
38
  module Version #:nodoc:
35
39
  Major = 1
36
- Minor = 1
37
- Tiny = 3
40
+ Minor = 2
41
+ Tiny = 1
38
42
 
39
43
  String = [Major, Minor, Tiny].join('.')
40
44
  end
@@ -60,6 +64,10 @@ module ThinkingSphinx
60
64
  @@indexed_models ||= []
61
65
  end
62
66
 
67
+ def self.unique_id_expression(offset = nil)
68
+ "* #{ThinkingSphinx.indexed_models.size} + #{offset || 0}"
69
+ end
70
+
63
71
  # Check if index definition is disabled.
64
72
  #
65
73
  def self.define_indexes?
@@ -124,21 +132,87 @@ module ThinkingSphinx
124
132
  # or if not using MySQL, this will return false.
125
133
  #
126
134
  def self.use_group_by_shortcut?
127
- ::ActiveRecord::ConnectionAdapters.constants.include?("MysqlAdapter") &&
128
- ::ActiveRecord::Base.connection.is_a?(
129
- ::ActiveRecord::ConnectionAdapters::MysqlAdapter
130
- ) &&
131
- ::ActiveRecord::Base.connection.select_all(
132
- "SELECT @@global.sql_mode, @@session.sql_mode;"
133
- ).all? { |key,value| value.nil? || value[/ONLY_FULL_GROUP_BY/].nil? }
135
+ !!(
136
+ mysql? && ::ActiveRecord::Base.connection.select_all(
137
+ "SELECT @@global.sql_mode, @@session.sql_mode;"
138
+ ).all? { |key,value| value.nil? || value[/ONLY_FULL_GROUP_BY/].nil? }
139
+ )
140
+ end
141
+
142
+ @@remote_sphinx = false
143
+
144
+ # An indication of whether Sphinx is running on a remote machine instead of
145
+ # the same machine.
146
+ #
147
+ def self.remote_sphinx?
148
+ @@remote_sphinx
134
149
  end
135
150
 
151
+ # Tells Thinking Sphinx that Sphinx is running on a different machine, and
152
+ # thus it can't reliably guess whether it is running or not (ie: the
153
+ # #sphinx_running? method), and so just assumes it is.
154
+ #
155
+ # Useful for multi-machine deployments. Set it in your production.rb file.
156
+ #
157
+ # ThinkingSphinx.remote_sphinx = true
158
+ #
159
+ def self.remote_sphinx=(value)
160
+ @@remote_sphinx = value
161
+ end
162
+
163
+ # Check if Sphinx is running. If remote_sphinx is set to true (indicating
164
+ # Sphinx is on a different machine), this will always return true, and you
165
+ # will have to handle any connection errors yourself.
166
+ #
136
167
  def self.sphinx_running?
137
- !!sphinx_pid
168
+ remote_sphinx? || sphinx_running_by_pid?
169
+ end
170
+
171
+ # Check if Sphinx is actually running, provided the pid is on the same
172
+ # machine as this code.
173
+ #
174
+ def self.sphinx_running_by_pid?
175
+ !!sphinx_pid && pid_active?(sphinx_pid)
138
176
  end
139
177
 
140
178
  def self.sphinx_pid
141
- pid_file = ThinkingSphinx::Configuration.instance.pid_file
142
- `cat #{pid_file}`[/\d+/] if File.exists?(pid_file)
179
+ pid_file = ThinkingSphinx::Configuration.instance.pid_file
180
+ cat_command = 'cat'
181
+ return nil unless File.exists?(pid_file)
182
+
183
+ if microsoft?
184
+ pid_file.gsub!('/', '\\')
185
+ cat_command = 'type'
186
+ end
187
+
188
+ `#{cat_command} \"#{pid_file}\"`[/\d+/]
189
+ end
190
+
191
+ def self.pid_active?(pid)
192
+ return true if microsoft?
193
+
194
+ begin
195
+ # In JRuby this returns -1 if the process doesn't exist
196
+ Process.getpgid(pid.to_i) != -1
197
+ rescue Exception => e
198
+ false
199
+ end
143
200
  end
201
+
202
+ def self.microsoft?
203
+ RUBY_PLATFORM =~ /mswin/
204
+ end
205
+
206
+ def self.jruby?
207
+ defined?(JRUBY_VERSION)
208
+ end
209
+
210
+ def self.mysql?
211
+ ::ActiveRecord::Base.connection.class.name.demodulize == "MysqlAdapter" ||
212
+ ::ActiveRecord::Base.connection.class.name.demodulize == "MysqlplusAdapter" || (
213
+ jruby? && ::ActiveRecord::Base.connection.config[:adapter] == "jdbcmysql"
214
+ )
215
+ end
216
+
217
+ extend ThinkingSphinx::SearchMethods::ClassMethods
144
218
  end
data/rails/init.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'thinking_sphinx'
2
+ require 'action_controller/dispatcher'
3
+
4
+ ActionController::Dispatcher.to_prepare :thinking_sphinx do
5
+ # Force internationalisation to be loaded.
6
+ if Rails::VERSION::STRING.to_f > 2.2
7
+ I18n.backend.reload!
8
+ I18n.backend.available_locales
9
+ elsif Rails::VERSION::STRING.to_f > 2.1
10
+ I18n.backend.load_translations(*I18n.load_path)
11
+ end
12
+
13
+ ThinkingSphinx::Configuration.instance.load_models
14
+ end
@@ -76,11 +76,12 @@ describe "ThinkingSphinx::ActiveRecord::Delta" do
76
76
 
77
77
  @person = Person.new
78
78
  @person.stub_method(
79
- :in_core_index? => false,
79
+ :in_both_indexes? => false,
80
80
  :sphinx_document_id => 1
81
81
  )
82
82
 
83
- @client = Riddle::Client.stub_instance(:update => true)
83
+ @client = Riddle::Client.new
84
+ @client.stub!(:update => true)
84
85
  Riddle::Client.stub_method(:new => @client)
85
86
  end
86
87
 
@@ -120,17 +121,16 @@ describe "ThinkingSphinx::ActiveRecord::Delta" do
120
121
  end
121
122
 
122
123
  it "shouldn't update the deleted attribute if not in the index" do
123
- @person.send(:index_delta)
124
+ @client.should_not_receive(:update)
124
125
 
125
- @client.should_not have_received(:update)
126
+ @person.send(:index_delta)
126
127
  end
127
128
 
128
129
  it "should update the deleted attribute if in the core index" do
129
- @person.stub_method(:in_core_index? => true)
130
+ @person.stub_method(:in_both_indexes? => true)
131
+ @client.should_receive(:update)
130
132
 
131
133
  @person.send(:index_delta)
132
-
133
- @client.should have_received(:update)
134
134
  end
135
135
  end
136
136
  end
@@ -0,0 +1,92 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ThinkingSphinx::ActiveRecord::Scopes do
4
+ after :each do
5
+ Alpha.remove_sphinx_scopes
6
+ end
7
+
8
+ it "should be included into models with indexes" do
9
+ Alpha.included_modules.should include(ThinkingSphinx::ActiveRecord::Scopes)
10
+ end
11
+
12
+ it "should not be included into models without indexes" do
13
+ Gamma.included_modules.should_not include(
14
+ ThinkingSphinx::ActiveRecord::Scopes
15
+ )
16
+ end
17
+
18
+ describe '.sphinx_scope' do
19
+ before :each do
20
+ Alpha.sphinx_scope(:by_name) { |name| {:conditions => {:name => name}} }
21
+ end
22
+
23
+ it "should define a method on the model" do
24
+ Alpha.should respond_to(:by_name)
25
+ end
26
+ end
27
+
28
+ describe '.sphinx_scopes' do
29
+ before :each do
30
+ Alpha.sphinx_scope(:by_name) { |name| {:conditions => {:name => name}} }
31
+ end
32
+
33
+ it "should return an array of defined scope names as symbols" do
34
+ Alpha.sphinx_scopes.should == [:by_name]
35
+ end
36
+ end
37
+
38
+ describe '.remove_sphinx_scopes' do
39
+ before :each do
40
+ Alpha.sphinx_scope(:by_name) { |name| {:conditions => {:name => name}} }
41
+ Alpha.remove_sphinx_scopes
42
+ end
43
+
44
+ it "should remove sphinx scope methods" do
45
+ Alpha.should_not respond_to(:by_name)
46
+ end
47
+
48
+ it "should empty the list of sphinx scopes" do
49
+ Alpha.sphinx_scopes.should be_empty
50
+ end
51
+ end
52
+
53
+ describe '.example_scope' do
54
+ before :each do
55
+ Alpha.sphinx_scope(:by_name) { |name| {:conditions => {:name => name}} }
56
+ Alpha.sphinx_scope(:by_foo) { |foo| {:conditions => {:foo => foo}} }
57
+ Alpha.sphinx_scope(:with_betas) { {:classes => [Beta]} }
58
+ end
59
+
60
+ it "should return a ThinkingSphinx object" do
61
+ Alpha.by_name('foo').should be_a(ThinkingSphinx::Search)
62
+ end
63
+
64
+ it "should be able to be called on a ThinkingSphinx::Search object" do
65
+ search = ThinkingSphinx::Search.new(:classes => [Alpha])
66
+ lambda {
67
+ search.by_name('foo')
68
+ }.should_not raise_error
69
+ end
70
+
71
+ it "should return the search object it gets called upon" do
72
+ search = ThinkingSphinx::Search.new(:classes => [Alpha])
73
+ search.by_name('foo').should == search
74
+ end
75
+
76
+ it "should apply the scope options to the underlying search object" do
77
+ search = ThinkingSphinx::Search.new(:classes => [Alpha])
78
+ search.by_name('foo').options[:conditions].should == {:name => 'foo'}
79
+ end
80
+
81
+ it "should combine hash option scopes such as :conditions" do
82
+ search = ThinkingSphinx::Search.new(:classes => [Alpha])
83
+ search.by_name('foo').by_foo('bar').options[:conditions].
84
+ should == {:name => 'foo', :foo => 'bar'}
85
+ end
86
+
87
+ it "should combine array option scopes such as :classes" do
88
+ search = ThinkingSphinx::Search.new(:classes => [Alpha])
89
+ search.with_betas.options[:classes].should == [Alpha, Beta]
90
+ end
91
+ end
92
+ end