freelancing-god-thinking-sphinx 0.9.8 → 0.9.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/README +20 -1
  2. data/lib/thinking_sphinx.rb +30 -2
  3. data/lib/thinking_sphinx/active_record.rb +25 -11
  4. data/lib/thinking_sphinx/active_record/delta.rb +46 -53
  5. data/lib/thinking_sphinx/active_record/has_many_association.rb +1 -1
  6. data/lib/thinking_sphinx/active_record/search.rb +8 -1
  7. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +27 -0
  8. data/lib/thinking_sphinx/adapters/mysql_adapter.rb +9 -0
  9. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +84 -0
  10. data/lib/thinking_sphinx/association.rb +4 -0
  11. data/lib/thinking_sphinx/attribute.rb +4 -2
  12. data/lib/thinking_sphinx/collection.rb +105 -0
  13. data/lib/thinking_sphinx/configuration.rb +112 -75
  14. data/lib/thinking_sphinx/field.rb +11 -3
  15. data/lib/thinking_sphinx/index.rb +119 -26
  16. data/lib/thinking_sphinx/index/builder.rb +30 -22
  17. data/lib/thinking_sphinx/index/faux_column.rb +13 -0
  18. data/lib/thinking_sphinx/rails_additions.rb +13 -1
  19. data/lib/thinking_sphinx/search.rb +40 -81
  20. data/spec/unit/thinking_sphinx/active_record/delta_spec.rb +73 -127
  21. data/spec/unit/thinking_sphinx/active_record/has_many_association_spec.rb +2 -2
  22. data/spec/unit/thinking_sphinx/active_record/search_spec.rb +26 -0
  23. data/spec/unit/thinking_sphinx/active_record_spec.rb +94 -22
  24. data/spec/unit/thinking_sphinx/attribute_spec.rb +8 -4
  25. data/spec/unit/thinking_sphinx/collection_spec.rb +71 -0
  26. data/spec/unit/thinking_sphinx/configuration_spec.rb +149 -113
  27. data/spec/unit/thinking_sphinx/field_spec.rb +13 -4
  28. data/spec/unit/thinking_sphinx/index/builder_spec.rb +1 -0
  29. data/spec/unit/thinking_sphinx/index/faux_column_spec.rb +27 -0
  30. data/spec/unit/thinking_sphinx/index_spec.rb +79 -29
  31. data/spec/unit/thinking_sphinx/search_spec.rb +114 -74
  32. data/spec/unit/thinking_sphinx_spec.rb +21 -0
  33. data/tasks/thinking_sphinx_tasks.rb +24 -10
  34. metadata +21 -8
  35. data/lib/riddle.rb +0 -26
  36. data/lib/riddle/client.rb +0 -639
  37. data/lib/riddle/client/filter.rb +0 -44
  38. data/lib/riddle/client/message.rb +0 -65
  39. data/lib/riddle/client/response.rb +0 -84
  40. data/lib/test.rb +0 -46
@@ -9,7 +9,8 @@ module ThinkingSphinx
9
9
  # Enjoy.
10
10
  #
11
11
  class Index
12
- attr_accessor :model, :fields, :attributes, :conditions, :delta, :options
12
+ attr_accessor :model, :fields, :attributes, :conditions, :groupings,
13
+ :delta, :options
13
14
 
14
15
  # Create a new index instance by passing in the model it is tied to, and
15
16
  # a block to build it with (optional but recommended). For documentation
@@ -31,6 +32,7 @@ module ThinkingSphinx
31
32
  @fields = []
32
33
  @attributes = []
33
34
  @conditions = []
35
+ @groupings = []
34
36
  @options = {}
35
37
  @delta = false
36
38
 
@@ -38,16 +40,21 @@ module ThinkingSphinx
38
40
  end
39
41
 
40
42
  def name
43
+ self.class.name(@model)
44
+ end
45
+
46
+ def self.name(model)
41
47
  model.name.underscore.tr(':/\\', '_')
42
48
  end
43
49
 
44
50
  def empty?(part = :core)
45
- config = ThinkingSphinx::Configuration.new
51
+ config = ThinkingSphinx::Configuration.instance
46
52
  File.size?("#{config.searchd_file_path}/#{self.name}_#{part}.spa").nil?
47
53
  end
48
54
 
49
- def to_config(index, database_conf, charset_type)
55
+ def to_config(model, index, database_conf, offset)
50
56
  # Set up associations and joins
57
+ add_internal_attributes
51
58
  link!
52
59
 
53
60
  attr_sources = attributes.collect { |attrib|
@@ -65,33 +72,36 @@ module ThinkingSphinx
65
72
 
66
73
  config = <<-SOURCE
67
74
 
68
- source #{model.indexes.first.name}_#{index}_core
75
+ source #{self.class.name(model)}_#{index}_core
69
76
  {
70
77
  type = #{db_adapter}
71
78
  sql_host = #{database_conf[:host] || "localhost"}
72
- sql_user = #{database_conf[:username]}
73
- sql_pass = #{database_conf[:password]}
79
+ sql_user = #{database_conf[:username] || database_conf[:user]}
80
+ sql_pass = #{(database_conf[:password] || "").gsub('#', '\#')}
74
81
  sql_db = #{database_conf[:database]}
82
+ #{"sql_port = #{database_conf[:port]}" unless database_conf[:port].blank? }
83
+ #{"sql_sock = #{database_conf[:socket]}" unless database_conf[:socket].blank? }
75
84
 
76
- sql_query_pre = #{charset_type == "utf-8" && adapter == :mysql ? "SET NAMES utf8" : ""}
85
+ sql_query_pre = #{utf8? && adapter == :mysql ? "SET NAMES utf8" : ""}
77
86
  #{"sql_query_pre = SET SESSION group_concat_max_len = #{@options[:group_concat_max_len]}" if @options[:group_concat_max_len]}
78
87
  sql_query_pre = #{to_sql_query_pre}
79
- sql_query = #{to_sql.gsub(/\n/, ' ')}
88
+ sql_query = #{to_sql(:offset => offset).gsub(/\n/, ' ')}
80
89
  sql_query_range = #{to_sql_query_range}
81
- sql_query_info = #{to_sql_query_info}
90
+ sql_query_info = #{to_sql_query_info(offset)}
82
91
  #{attr_sources}
92
+ #{ThinkingSphinx::Configuration.instance.hash_to_config(self.source_options)}
83
93
  }
84
94
  SOURCE
85
95
 
86
96
  if delta?
87
97
  config += <<-SOURCE
88
98
 
89
- source #{model.indexes.first.name}_#{index}_delta : #{model.indexes.first.name}_#{index}_core
99
+ source #{self.class.name(model)}_#{index}_delta : #{self.class.name(model)}_#{index}_core
90
100
  {
91
101
  sql_query_pre =
92
- sql_query_pre = #{charset_type == "utf-8" && adapter == :mysql ? "SET NAMES utf8" : ""}
102
+ sql_query_pre = #{utf8? && adapter == :mysql ? "SET NAMES utf8" : ""}
93
103
  #{"sql_query_pre = SET SESSION group_concat_max_len = #{@options[:group_concat_max_len]}" if @options[:group_concat_max_len]}
94
- sql_query = #{to_sql(:delta => true).gsub(/\n/, ' ')}
104
+ sql_query = #{to_sql(:delta => true, :offset => offset).gsub(/\n/, ' ')}
95
105
  sql_query_range = #{to_sql_query_range :delta => true}
96
106
  }
97
107
  SOURCE
@@ -149,9 +159,16 @@ sql_query_range = #{to_sql_query_range :delta => true}
149
159
  where_clause << " AND " << @conditions.join(" AND ")
150
160
  end
151
161
 
162
+ internal_groupings = []
163
+ if @model.column_names.include?(@model.inheritance_column)
164
+ internal_groupings << "#{@model.quoted_table_name}.#{quote_column(@model.inheritance_column)}"
165
+ end
166
+
167
+ unique_id_expr = "* #{ThinkingSphinx.indexed_models.size} + #{options[:offset] || 0}"
168
+
152
169
  sql = <<-SQL
153
170
  SELECT #{ (
154
- ["#{@model.quoted_table_name}.#{quote_column(@model.primary_key)}"] +
171
+ ["#{@model.quoted_table_name}.#{quote_column(@model.primary_key)} #{unique_id_expr} AS #{quote_column(@model.primary_key)} "] +
155
172
  @fields.collect { |field| field.to_select_sql } +
156
173
  @attributes.collect { |attribute| attribute.to_select_sql }
157
174
  ).join(", ") }
@@ -163,7 +180,8 @@ WHERE #{@model.quoted_table_name}.#{quote_column(@model.primary_key)} >= $start
163
180
  GROUP BY #{ (
164
181
  ["#{@model.quoted_table_name}.#{quote_column(@model.primary_key)}"] +
165
182
  @fields.collect { |field| field.to_group_sql }.compact +
166
- @attributes.collect { |attribute| attribute.to_group_sql }.compact
183
+ @attributes.collect { |attribute| attribute.to_group_sql }.compact +
184
+ @groupings + internal_groupings
167
185
  ).join(", ") }
168
186
  SQL
169
187
 
@@ -177,9 +195,9 @@ GROUP BY #{ (
177
195
  # Simple helper method for the query info SQL - which is a statement that
178
196
  # returns the single row for a corresponding id.
179
197
  #
180
- def to_sql_query_info
198
+ def to_sql_query_info(offset)
181
199
  "SELECT * FROM #{@model.quoted_table_name} WHERE " +
182
- " #{quote_column(@model.primary_key)} = $id"
200
+ " #{quote_column(@model.primary_key)} = (($id - #{offset}) / #{ThinkingSphinx.indexed_models.size})"
183
201
  end
184
202
 
185
203
  # Simple helper method for the query range SQL - which is a statement that
@@ -228,6 +246,10 @@ GROUP BY #{ (
228
246
  end
229
247
  end
230
248
 
249
+ def adapter_object
250
+ @adapter_object ||= ThinkingSphinx::AbstractAdapter.detect(@model)
251
+ end
252
+
231
253
  def prefix_fields
232
254
  @fields.select { |field| field.prefixes }
233
255
  end
@@ -236,8 +258,37 @@ GROUP BY #{ (
236
258
  @fields.select { |field| field.infixes }
237
259
  end
238
260
 
261
+ def local_index_options
262
+ @options.keys.inject({}) do |local_options, key|
263
+ if ThinkingSphinx::Configuration::IndexOptions.include?(key.to_s)
264
+ local_options[key.to_sym] = @options[key]
265
+ end
266
+ local_options
267
+ end
268
+ end
269
+
270
+ def index_options
271
+ all_index_options = ThinkingSphinx::Configuration.instance.index_options.clone
272
+ @options.keys.select { |key|
273
+ ThinkingSphinx::Configuration::IndexOptions.include?(key.to_s)
274
+ }.each { |key| all_index_options[key.to_sym] = @options[key] }
275
+ all_index_options
276
+ end
277
+
278
+ def source_options
279
+ all_source_options = ThinkingSphinx::Configuration.instance.source_options.clone
280
+ @options.keys.select { |key|
281
+ ThinkingSphinx::Configuration::SourceOptions.include?(key.to_s)
282
+ }.each { |key| all_source_options[key.to_sym] = @options[key] }
283
+ all_source_options
284
+ end
285
+
239
286
  private
240
287
 
288
+ def utf8?
289
+ self.index_options[:charset_type] == "utf-8"
290
+ end
291
+
241
292
  def quote_column(column)
242
293
  @model.connection.quote_column_name(column)
243
294
  end
@@ -263,19 +314,20 @@ GROUP BY #{ (
263
314
  @fields = builder.fields
264
315
  @attributes = builder.attributes
265
316
  @conditions = builder.conditions
317
+ @groupings = builder.groupings
266
318
  @delta = builder.properties[:delta]
267
319
  @options = builder.properties.except(:delta)
268
320
 
269
- @attributes << Attribute.new(
270
- FauxColumn.new(@model.to_crc32.to_s),
271
- :type => :integer,
272
- :as => :class_crc
273
- )
274
- @attributes << Attribute.new(
275
- FauxColumn.new("0"),
276
- :type => :integer,
277
- :as => :sphinx_deleted
278
- )
321
+ # We want to make sure that if the database doesn't exist, then Thinking
322
+ # Sphinx doesn't mind when running non-TS tasks (like db:create, db:drop
323
+ # and db:migrate). It's a bit hacky, but I can't think of a better way.
324
+ rescue StandardError => err
325
+ case err.class.name
326
+ when "Mysql::Error", "ActiveRecord::StatementInvalid"
327
+ return
328
+ else
329
+ raise err
330
+ end
279
331
  end
280
332
 
281
333
  # Returns all associations used amongst all the fields and attributes.
@@ -335,5 +387,46 @@ GROUP BY #{ (
335
387
  val ? '1' : '0'
336
388
  end
337
389
  end
390
+
391
+ def crc_column
392
+ if @model.column_names.include?(@model.inheritance_column)
393
+ case adapter
394
+ when :postgres
395
+ "COALESCE(crc32(#{@model.quoted_table_name}.#{quote_column(@model.inheritance_column)}), #{@model.to_crc32.to_s})"
396
+ when :mysql
397
+ "IFNULL(CRC32(#{@model.quoted_table_name}.#{quote_column(@model.inheritance_column)}), #{@model.to_crc32.to_s})"
398
+ end
399
+ else
400
+ @model.to_crc32.to_s
401
+ end
402
+ end
403
+
404
+ def add_internal_attributes
405
+ @attributes << Attribute.new(
406
+ FauxColumn.new(@model.primary_key.to_sym),
407
+ :type => :integer,
408
+ :as => :sphinx_internal_id
409
+ ) unless @attributes.detect { |attr| attr.alias == :sphinx_internal_id }
410
+
411
+ @attributes << Attribute.new(
412
+ FauxColumn.new(crc_column),
413
+ :type => :integer,
414
+ :as => :class_crc
415
+ ) unless @attributes.detect { |attr| attr.alias == :class_crc }
416
+
417
+ @attributes << Attribute.new(
418
+ FauxColumn.new("'" + (@model.send(:subclasses).collect { |klass|
419
+ klass.to_crc32.to_s
420
+ } << @model.to_crc32.to_s).join(",") + "'"),
421
+ :type => :multi,
422
+ :as => :subclass_crcs
423
+ ) unless @attributes.detect { |attr| attr.alias == :subclass_crcs }
424
+
425
+ @attributes << Attribute.new(
426
+ FauxColumn.new("0"),
427
+ :type => :integer,
428
+ :as => :sphinx_deleted
429
+ ) unless @attributes.detect { |attr| attr.alias == :sphinx_deleted }
430
+ end
338
431
  end
339
432
  end
@@ -18,9 +18,13 @@ module ThinkingSphinx
18
18
  # rails documentation. It's not needed though, so it gets undef'd.
19
19
  # Hopefully the list of methods that get in the way doesn't get too
20
20
  # long.
21
- undef_method :parent
21
+ undef_method :parent if respond_to?(:parent)
22
+ undef_method :name if respond_to?(:name)
23
+ undef_method :id if respond_to?(:id)
24
+ undef_method :type if respond_to?(:type)
22
25
 
23
- attr_accessor :fields, :attributes, :properties, :conditions
26
+ attr_accessor :fields, :attributes, :properties, :conditions,
27
+ :groupings
24
28
 
25
29
  # Set up all the collections. Consider this the equivalent of an
26
30
  # instance's initialize method.
@@ -30,6 +34,7 @@ module ThinkingSphinx
30
34
  @attributes = []
31
35
  @properties = {}
32
36
  @conditions = []
37
+ @groupings = []
33
38
  end
34
39
 
35
40
  # This is how you add fields - the strings Sphinx looks at - to your
@@ -81,8 +86,7 @@ module ThinkingSphinx
81
86
  def indexes(*args)
82
87
  options = args.extract_options!
83
88
  args.each do |columns|
84
- columns = FauxColumn.new(columns) if columns.is_a?(Symbol)
85
- fields << Field.new(columns, options)
89
+ fields << Field.new(FauxColumn.coerce(columns), options)
86
90
 
87
91
  if fields.last.sortable
88
92
  attributes << Attribute.new(
@@ -137,23 +141,7 @@ module ThinkingSphinx
137
141
  def has(*args)
138
142
  options = args.extract_options!
139
143
  args.each do |columns|
140
- columns = case columns
141
- when Symbol, String
142
- FauxColumn.new(columns)
143
- when Array
144
- columns.collect { |col|
145
- case col
146
- when Symbol, String
147
- FauxColumn.new(col)
148
- else
149
- col
150
- end
151
- }
152
- else
153
- columns
154
- end
155
-
156
- attributes << Attribute.new(columns, options)
144
+ attributes << Attribute.new(FauxColumn.coerce(columns), options)
157
145
  end
158
146
  end
159
147
  alias_method :attribute, :has
@@ -169,6 +157,16 @@ module ThinkingSphinx
169
157
  @conditions += args
170
158
  end
171
159
 
160
+ # Use this method to add some manual SQL strings to the GROUP BY
161
+ # clause. You can pass in as many strings as you'd like, they'll get
162
+ # joined together with commas later on.
163
+ #
164
+ # group_by "lat", "lng"
165
+ #
166
+ def group_by(*args)
167
+ @groupings += args
168
+ end
169
+
172
170
  # This is what to use to set properties on the index. Chief amongst
173
171
  # those is the delta property - to allow automatic updates to your
174
172
  # indexes as new models are added and edited - but also you can
@@ -185,7 +183,7 @@ module ThinkingSphinx
185
183
  # when defining the index, so you don't need to specify them for every
186
184
  # geo-related search.
187
185
  #
188
- # set_property :latitude_attr => "lt", :longitude => "lg"
186
+ # set_property :latitude_attr => "lt", :longitude_attr => "lg"
189
187
  #
190
188
  # Please don't forget to add a boolean field named 'delta' to your
191
189
  # model's database table if enabling the delta index for it.
@@ -206,6 +204,16 @@ module ThinkingSphinx
206
204
  def method_missing(method, *args)
207
205
  FauxColumn.new(method, *args)
208
206
  end
207
+
208
+ # A method to allow adding fields from associations which have names
209
+ # that clash with method names in the Builder class (ie: properties,
210
+ # fields, attributes).
211
+ #
212
+ # Example: indexes assoc(:properties).column
213
+ #
214
+ def assoc(assoc)
215
+ FauxColumn.new(method)
216
+ end
209
217
  end
210
218
  end
211
219
  end
@@ -15,6 +15,19 @@ module ThinkingSphinx
15
15
  @stack = stack
16
16
  end
17
17
 
18
+ def self.coerce(columns)
19
+ case columns
20
+ when Symbol, String
21
+ FauxColumn.new(columns)
22
+ when Array
23
+ columns.collect { |col| FauxColumn.coerce(col) }
24
+ when FauxColumn
25
+ columns
26
+ else
27
+ nil
28
+ end
29
+ end
30
+
18
31
  # Can't use normal method name, as that could be an association or
19
32
  # column name.
20
33
  #
@@ -53,4 +53,16 @@ end
53
53
 
54
54
  ActiveRecord::Base.extend(
55
55
  ThinkingSphinx::ActiveRecordQuotedName
56
- ) unless ActiveRecord::Base.respond_to?("quoted_table_name")
56
+ ) unless ActiveRecord::Base.respond_to?("quoted_table_name")
57
+
58
+ module ThinkingSphinx
59
+ module ActiveRecordStoreFullSTIClass
60
+ def store_full_sti_class
61
+ false
62
+ end
63
+ end
64
+ end
65
+
66
+ ActiveRecord::Base.extend(
67
+ ThinkingSphinx::ActiveRecordStoreFullSTIClass
68
+ ) unless ActiveRecord::Base.respond_to?(:store_full_sti_class)
@@ -17,16 +17,8 @@ module ThinkingSphinx
17
17
 
18
18
  options = args.extract_options!
19
19
  page = options[:page] ? options[:page].to_i : 1
20
-
21
- begin
22
- pager = WillPaginate::Collection.create(page,
23
- client.limit, results[:total_found] || 0) do |collection|
24
- collection.replace results[:matches].collect { |match| match[:doc] }
25
- collection.instance_variable_set :@total_entries, results[:total_found]
26
- end
27
- rescue
28
- results[:matches].collect { |match| match[:doc] }
29
- end
20
+
21
+ ThinkingSphinx::Collection.ids_from_results(results, page, client.limit, options)
30
22
  end
31
23
 
32
24
  # Searches through the Sphinx indexes for relevant matches. There's
@@ -149,8 +141,8 @@ module ThinkingSphinx
149
141
  # attributes. To search with that point, you can then use one of the
150
142
  # following syntax examples:
151
143
  #
152
- # Address.search "Melbourne", :geo => [1.4, -2.217]
153
- # Address.search "Australia", :geo => [-0.55, 3.108],
144
+ # Address.search "Melbourne", :geo => [1.4, -2.217], :order => "@geodist asc"
145
+ # Address.search "Australia", :geo => [-0.55, 3.108], :order => "@geodist asc"
154
146
  # :latitude_attr => "latit", :longitude_attr => "longit"
155
147
  #
156
148
  # The first example applies when your latitude and longitude attributes
@@ -168,9 +160,9 @@ module ThinkingSphinx
168
160
  #
169
161
  # Now, geo-location searching really only has an affect if you have a
170
162
  # filter, sort or grouping clause related to it - otherwise it's just a
171
- # normal search. To make use of the positioning difference, use the
172
- # special attribute "@geodist" in any of your filters or sorting or grouping
173
- # clauses.
163
+ # normal search, and _will not_ return a distance value otherwise. To
164
+ # make use of the positioning difference, use the special attribute
165
+ # "@geodist" in any of your filters or sorting or grouping clauses.
174
166
  #
175
167
  # And don't forget - both the latitude and longitude you use in your
176
168
  # search, and the values in your indexes, need to be stored as a float in radians,
@@ -182,6 +174,16 @@ module ThinkingSphinx
182
174
  # # ...
183
175
  # end
184
176
  #
177
+ # Once you've got your results set, you can access the distances as
178
+ # follows:
179
+ #
180
+ # @results.each_with_geodist do |result, distance|
181
+ # # ...
182
+ # end
183
+ #
184
+ # The distance value is returned as a float, representing the distance in
185
+ # metres.
186
+ #
185
187
  def search(*args)
186
188
  results, client = search_results(*args.clone)
187
189
 
@@ -193,17 +195,14 @@ module ThinkingSphinx
193
195
  klass = options[:class]
194
196
  page = options[:page] ? options[:page].to_i : 1
195
197
 
196
- begin
197
- pager = WillPaginate::Collection.create(page,
198
- client.limit, results[:total] || 0) do |collection|
199
- collection.replace instances_from_results(results[:matches], options, klass)
200
- collection.instance_variable_set :@total_entries, results[:total_found]
201
- end
202
- rescue StandardError => err
203
- instances_from_results(results[:matches], options, klass)
204
- end
198
+ ThinkingSphinx::Collection.create_from_results(results, page, client.limit, options)
205
199
  end
206
-
200
+
201
+ def count(*args)
202
+ results, client = search_results(*args.clone)
203
+ results[:total] || 0
204
+ end
205
+
207
206
  # Checks if a document with the given id exists within a specific index.
208
207
  # Expected parameters:
209
208
  #
@@ -259,7 +258,7 @@ module ThinkingSphinx
259
258
  begin
260
259
  ::ActiveRecord::Base.logger.debug "Sphinx: #{query}"
261
260
  results = client.query query
262
- ::ActiveRecord::Base.logger.debug "Sphinx Result: #{results[:matches].collect{|m| m[:doc]}.inspect}"
261
+ ::ActiveRecord::Base.logger.debug "Sphinx Result: #{results[:matches].collect{|m| m[:attributes]["sphinx_internal_id"]}.inspect}"
263
262
  rescue Errno::ECONNREFUSED => err
264
263
  raise ThinkingSphinx::ConnectionError, "Connection to Sphinx Daemon (searchd) failed."
265
264
  end
@@ -267,53 +266,14 @@ module ThinkingSphinx
267
266
  return results, client
268
267
  end
269
268
 
270
- def instances_from_results(results, options = {}, klass = nil)
271
- if klass.nil?
272
- results.collect { |result| instance_from_result result, options }
273
- else
274
- ids = results.collect { |result| result[:doc] }
275
- instances = klass.find(
276
- :all,
277
- :conditions => {klass.primary_key.to_sym => ids},
278
- :include => options[:include],
279
- :select => options[:select]
280
- )
281
- ids.collect { |obj_id| instances.detect { |obj| obj.id == obj_id } }
282
- end
283
- end
284
-
285
- # Either use the provided class to instantiate a result from a model, or
286
- # get the result's CRC value and determine the class from that.
287
- #
288
- def instance_from_result(result, options)
289
- class_from_crc(result[:attributes]["class_crc"]).find(
290
- result[:doc], :include => options[:include], :select => options[:select]
291
- )
292
- end
293
-
294
- # Convert a CRC value to the corresponding class.
295
- #
296
- def class_from_crc(crc)
297
- unless @models_by_crc
298
- Configuration.new.load_models
299
-
300
- @models_by_crc = ThinkingSphinx.indexed_models.inject({}) do |hash, model|
301
- hash[model.constantize.to_crc32] = model
302
- hash
303
- end
304
- end
305
-
306
- @models_by_crc[crc].constantize
307
- end
308
-
309
269
  # Set all the appropriate settings for the client, using the provided
310
270
  # options hash.
311
271
  #
312
272
  def client_from_options(options = {})
313
- config = ThinkingSphinx::Configuration.new
273
+ config = ThinkingSphinx::Configuration.instance
314
274
  client = Riddle::Client.new config.address, config.port
315
275
  klass = options[:class]
316
- index_options = klass ? klass.indexes.last.options : {}
276
+ index_options = klass ? klass.sphinx_indexes.last.options : {}
317
277
 
318
278
  [
319
279
  :max_matches, :match_mode, :sort_mode, :sort_by, :id_range,
@@ -327,14 +287,17 @@ module ThinkingSphinx
327
287
  )
328
288
  end
329
289
 
290
+ options[:classes] = [klass] if klass
291
+
330
292
  client.anchor = anchor_conditions(klass, options) || {} if client.anchor.empty?
331
293
 
332
294
  client.filters << Riddle::Client::Filter.new(
333
295
  "sphinx_deleted", [0]
334
296
  )
297
+
335
298
  # class filters
336
299
  client.filters << Riddle::Client::Filter.new(
337
- "class_crc", options[:classes].collect { |klass| klass.to_crc32 }
300
+ "class_crc", options[:classes].collect { |k| k.to_crc32s }.flatten
338
301
  ) if options[:classes]
339
302
 
340
303
  # normal attribute filters
@@ -365,7 +328,7 @@ module ThinkingSphinx
365
328
  # and filters.
366
329
  #
367
330
  def search_conditions(klass, conditions={})
368
- attributes = klass ? klass.indexes.collect { |index|
331
+ attributes = klass ? klass.sphinx_indexes.collect { |index|
369
332
  index.attributes.collect { |attrib| attrib.unique_name }
370
333
  }.flatten : []
371
334
 
@@ -375,18 +338,13 @@ module ThinkingSphinx
375
338
  conditions.each do |key,val|
376
339
  if attributes.include?(key.to_sym)
377
340
  filters << Riddle::Client::Filter.new(
378
- key.to_s,
379
- val.is_a?(Range) ? val : Array(val)
341
+ key.to_s, filter_value(val)
380
342
  )
381
343
  else
382
344
  search_string << "@#{key} #{val} "
383
345
  end
384
346
  end
385
347
 
386
- filters << Riddle::Client::Filter.new(
387
- "class_crc", [klass.to_crc32]
388
- ) if klass
389
-
390
348
  return search_string, filters
391
349
  end
392
350
 
@@ -395,15 +353,15 @@ module ThinkingSphinx
395
353
  # there's actually any values.
396
354
  #
397
355
  def anchor_conditions(klass, options)
398
- attributes = klass ? klass.indexes.collect { |index|
356
+ attributes = klass ? klass.sphinx_indexes.collect { |index|
399
357
  index.attributes.collect { |attrib| attrib.unique_name }
400
358
  }.flatten : []
401
359
 
402
- lat_attr = klass ? klass.indexes.collect { |index|
360
+ lat_attr = klass ? klass.sphinx_indexes.collect { |index|
403
361
  index.options[:latitude_attr]
404
362
  }.compact.first : nil
405
363
 
406
- lon_attr = klass ? klass.indexes.collect { |index|
364
+ lon_attr = klass ? klass.sphinx_indexes.collect { |index|
407
365
  index.options[:longitude_attr]
408
366
  }.compact.first : nil
409
367
 
@@ -412,6 +370,7 @@ module ThinkingSphinx
412
370
  lat_attr ||= :latitude if attributes.include?(:latitude)
413
371
 
414
372
  lon_attr = options[:longitude_attr] if options[:longitude_attr]
373
+ lon_attr ||= :lng if attributes.include?(:lng)
415
374
  lon_attr ||= :lon if attributes.include?(:lon)
416
375
  lon_attr ||= :long if attributes.include?(:long)
417
376
  lon_attr ||= :longitude if attributes.include?(:longitude)
@@ -425,9 +384,9 @@ module ThinkingSphinx
425
384
  end
426
385
 
427
386
  lat && lon ? {
428
- :latitude_attribute => lat_attr,
387
+ :latitude_attribute => lat_attr.to_s,
429
388
  :latitude => lat,
430
- :longitude_attribute => lon_attr,
389
+ :longitude_attribute => lon_attr.to_s,
431
390
  :longitude => lon
432
391
  } : nil
433
392
  end
@@ -437,7 +396,7 @@ module ThinkingSphinx
437
396
  #
438
397
  def set_sort_options!(client, options)
439
398
  klass = options[:class]
440
- fields = klass ? klass.indexes.collect { |index|
399
+ fields = klass ? klass.sphinx_indexes.collect { |index|
441
400
  index.fields.collect { |field| field.unique_name }
442
401
  }.flatten : []
443
402