DrMark-thinking-sphinx 0.9.9 → 1.1.6

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 (77) hide show
  1. data/README +64 -2
  2. data/lib/thinking_sphinx.rb +88 -11
  3. data/lib/thinking_sphinx/active_record.rb +136 -21
  4. data/lib/thinking_sphinx/active_record/delta.rb +43 -62
  5. data/lib/thinking_sphinx/active_record/has_many_association.rb +1 -1
  6. data/lib/thinking_sphinx/active_record/search.rb +7 -0
  7. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +42 -0
  8. data/lib/thinking_sphinx/adapters/mysql_adapter.rb +54 -0
  9. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +130 -0
  10. data/lib/thinking_sphinx/association.rb +17 -0
  11. data/lib/thinking_sphinx/attribute.rb +171 -97
  12. data/lib/thinking_sphinx/collection.rb +126 -2
  13. data/lib/thinking_sphinx/configuration.rb +120 -171
  14. data/lib/thinking_sphinx/core/string.rb +15 -0
  15. data/lib/thinking_sphinx/deltas.rb +27 -0
  16. data/lib/thinking_sphinx/deltas/datetime_delta.rb +50 -0
  17. data/lib/thinking_sphinx/deltas/default_delta.rb +67 -0
  18. data/lib/thinking_sphinx/deltas/delayed_delta.rb +25 -0
  19. data/lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb +24 -0
  20. data/lib/thinking_sphinx/deltas/delayed_delta/flag_as_deleted_job.rb +27 -0
  21. data/lib/thinking_sphinx/deltas/delayed_delta/job.rb +26 -0
  22. data/lib/thinking_sphinx/facet.rb +58 -0
  23. data/lib/thinking_sphinx/facet_collection.rb +60 -0
  24. data/lib/thinking_sphinx/field.rb +18 -52
  25. data/lib/thinking_sphinx/index.rb +246 -199
  26. data/lib/thinking_sphinx/index/builder.rb +85 -16
  27. data/lib/thinking_sphinx/rails_additions.rb +85 -5
  28. data/lib/thinking_sphinx/search.rb +459 -190
  29. data/lib/thinking_sphinx/tasks.rb +128 -0
  30. data/spec/unit/thinking_sphinx/active_record/delta_spec.rb +53 -124
  31. data/spec/unit/thinking_sphinx/active_record/has_many_association_spec.rb +2 -2
  32. data/spec/unit/thinking_sphinx/active_record_spec.rb +110 -30
  33. data/spec/unit/thinking_sphinx/attribute_spec.rb +16 -149
  34. data/spec/unit/thinking_sphinx/collection_spec.rb +14 -0
  35. data/spec/unit/thinking_sphinx/configuration_spec.rb +54 -412
  36. data/spec/unit/thinking_sphinx/core/string_spec.rb +9 -0
  37. data/spec/unit/thinking_sphinx/field_spec.rb +0 -79
  38. data/spec/unit/thinking_sphinx/index/builder_spec.rb +1 -29
  39. data/spec/unit/thinking_sphinx/index/faux_column_spec.rb +1 -39
  40. data/spec/unit/thinking_sphinx/index_spec.rb +78 -226
  41. data/spec/unit/thinking_sphinx/search_spec.rb +29 -228
  42. data/spec/unit/thinking_sphinx_spec.rb +23 -19
  43. data/tasks/distribution.rb +48 -0
  44. data/tasks/rails.rake +1 -0
  45. data/tasks/testing.rb +86 -0
  46. data/vendor/after_commit/LICENSE +20 -0
  47. data/vendor/after_commit/README +16 -0
  48. data/vendor/after_commit/Rakefile +22 -0
  49. data/vendor/after_commit/init.rb +8 -0
  50. data/vendor/after_commit/lib/after_commit.rb +45 -0
  51. data/vendor/after_commit/lib/after_commit/active_record.rb +114 -0
  52. data/vendor/after_commit/lib/after_commit/connection_adapters.rb +103 -0
  53. data/vendor/after_commit/test/after_commit_test.rb +53 -0
  54. data/vendor/delayed_job/lib/delayed/job.rb +251 -0
  55. data/vendor/delayed_job/lib/delayed/message_sending.rb +7 -0
  56. data/vendor/delayed_job/lib/delayed/performable_method.rb +55 -0
  57. data/vendor/delayed_job/lib/delayed/worker.rb +54 -0
  58. data/{lib → vendor/riddle/lib}/riddle.rb +9 -5
  59. data/{lib → vendor/riddle/lib}/riddle/client.rb +6 -26
  60. data/{lib → vendor/riddle/lib}/riddle/client/filter.rb +10 -1
  61. data/{lib → vendor/riddle/lib}/riddle/client/message.rb +0 -0
  62. data/{lib → vendor/riddle/lib}/riddle/client/response.rb +0 -0
  63. data/vendor/riddle/lib/riddle/configuration.rb +33 -0
  64. data/vendor/riddle/lib/riddle/configuration/distributed_index.rb +48 -0
  65. data/vendor/riddle/lib/riddle/configuration/index.rb +142 -0
  66. data/vendor/riddle/lib/riddle/configuration/indexer.rb +19 -0
  67. data/vendor/riddle/lib/riddle/configuration/remote_index.rb +17 -0
  68. data/vendor/riddle/lib/riddle/configuration/searchd.rb +25 -0
  69. data/vendor/riddle/lib/riddle/configuration/section.rb +37 -0
  70. data/vendor/riddle/lib/riddle/configuration/source.rb +23 -0
  71. data/vendor/riddle/lib/riddle/configuration/sql_source.rb +34 -0
  72. data/vendor/riddle/lib/riddle/configuration/xml_source.rb +28 -0
  73. data/vendor/riddle/lib/riddle/controller.rb +44 -0
  74. metadata +63 -10
  75. data/lib/test.rb +0 -46
  76. data/tasks/thinking_sphinx_tasks.rake +0 -1
  77. data/tasks/thinking_sphinx_tasks.rb +0 -86
@@ -1,6 +1,10 @@
1
1
  module ThinkingSphinx
2
2
  class Collection < ::Array
3
- attr_reader :total_entries, :total_pages, :current_page
3
+ attr_reader :total_entries, :total_pages, :current_page, :per_page
4
+ attr_accessor :results
5
+
6
+ # Compatibility with older versions of will_paginate
7
+ alias_method :page_count, :total_pages
4
8
 
5
9
  def initialize(page, per_page, entries, total_entries)
6
10
  @current_page, @per_page, @total_entries = page, per_page, total_entries
@@ -8,6 +12,94 @@ module ThinkingSphinx
8
12
  @total_pages = (entries / @per_page.to_f).ceil
9
13
  end
10
14
 
15
+ def self.ids_from_results(results, page, limit, options)
16
+ collection = self.new(page, limit,
17
+ results[:total] || 0, results[:total_found] || 0
18
+ )
19
+ collection.results = results
20
+ collection.replace results[:matches].collect { |match|
21
+ match[:attributes]["sphinx_internal_id"]
22
+ }
23
+ return collection
24
+ end
25
+
26
+ def self.create_from_results(results, page, limit, options)
27
+ collection = self.new(page, limit,
28
+ results[:total] || 0, results[:total_found] || 0
29
+ )
30
+ collection.results = results
31
+ collection.replace instances_from_matches(results[:matches], options)
32
+ return collection
33
+ end
34
+
35
+ def self.instances_from_matches(matches, options = {})
36
+ if klass = options[:class]
37
+ instances_from_class klass, matches, options
38
+ else
39
+ instances_from_classes matches, options
40
+ end
41
+ end
42
+
43
+ def self.instances_from_class(klass, matches, options = {})
44
+ index_options = klass.sphinx_index_options
45
+
46
+ ids = matches.collect { |match| match[:attributes]["sphinx_internal_id"] }
47
+ instances = ids.length > 0 ? klass.find(
48
+ :all,
49
+ :conditions => {klass.primary_key.to_sym => ids},
50
+ :include => (options[:include] || index_options[:include]),
51
+ :select => (options[:select] || index_options[:select]),
52
+ :order => (options[:sql_order] || index_options[:sql_order])
53
+ ) : []
54
+
55
+ # Raise an exception if we find records in Sphinx but not in the DB, so
56
+ # the search method can retry without them. See
57
+ # ThinkingSphinx::Search.retry_search_on_stale_index.
58
+ if options[:raise_on_stale] && instances.length < ids.length
59
+ stale_ids = ids - instances.map {|i| i.id }
60
+ raise StaleIdsException, stale_ids
61
+ end
62
+
63
+ # if the user has specified an SQL order, return the collection
64
+ # without rearranging it into the Sphinx order
65
+ return instances if options[:sql_order]
66
+
67
+ ids.collect { |obj_id|
68
+ instances.detect { |obj| obj.id == obj_id }
69
+ }
70
+ end
71
+
72
+ # Group results by class and call #find(:all) once for each group to reduce
73
+ # the number of #find's in multi-model searches.
74
+ #
75
+ def self.instances_from_classes(matches, options = {})
76
+ groups = matches.group_by { |match| match[:attributes]["class_crc"] }
77
+ groups.each do |crc, group|
78
+ group.replace(
79
+ instances_from_class(class_from_crc(crc), group, options)
80
+ )
81
+ end
82
+
83
+ matches.collect do |match|
84
+ groups.detect { |crc, group|
85
+ crc == match[:attributes]["class_crc"]
86
+ }[1].detect { |obj|
87
+ obj.id == match[:attributes]["sphinx_internal_id"]
88
+ }
89
+ end
90
+ end
91
+
92
+ def self.class_from_crc(crc)
93
+ @@models_by_crc ||= ThinkingSphinx.indexed_models.inject({}) do |hash, model|
94
+ hash[model.constantize.to_crc32] = model
95
+ model.constantize.subclasses.each { |subclass|
96
+ hash[subclass.to_crc32] = subclass.name
97
+ }
98
+ hash
99
+ end
100
+ @@models_by_crc[crc].constantize
101
+ end
102
+
11
103
  def previous_page
12
104
  current_page > 1 ? (current_page - 1) : nil
13
105
  end
@@ -19,5 +111,37 @@ module ThinkingSphinx
19
111
  def offset
20
112
  (current_page - 1) * @per_page
21
113
  end
114
+
115
+ def method_missing(method, *args, &block)
116
+ super unless method.to_s[/^each_with_.*/]
117
+
118
+ each_with_attribute method.to_s.gsub(/^each_with_/, ''), &block
119
+ end
120
+
121
+ def each_with_groupby_and_count(&block)
122
+ results[:matches].each_with_index do |match, index|
123
+ yield self[index], match[:attributes]["@groupby"], match[:attributes]["@count"]
124
+ end
125
+ end
126
+
127
+ def each_with_attribute(attribute, &block)
128
+ results[:matches].each_with_index do |match, index|
129
+ yield self[index], (match[:attributes][attribute] || match[:attributes]["@#{attribute}"])
130
+ end
131
+ end
132
+
133
+ def each_with_weighting(&block)
134
+ results[:matches].each_with_index do |match, index|
135
+ yield self[index], match[:weight]
136
+ end
137
+ end
138
+
139
+ def inject_with_groupby_and_count(initial = nil, &block)
140
+ index = -1
141
+ results[:matches].inject(initial) do |memo, match|
142
+ index += 1
143
+ yield memo, self[index], match[:attributes]["@groupby"], match[:attributes]["@count"]
144
+ end
145
+ end
22
146
  end
23
- end
147
+ end
@@ -1,4 +1,5 @@
1
1
  require 'erb'
2
+ require 'singleton'
2
3
 
3
4
  module ThinkingSphinx
4
5
  # This class both keeps track of the configuration settings for Sphinx and
@@ -41,49 +42,66 @@ module ThinkingSphinx
41
42
  # don't set allow_star to true.
42
43
  #
43
44
  class Configuration
45
+ include Singleton
46
+
47
+ SourceOptions = %w( mysql_connect_flags sql_range_step sql_query_pre
48
+ sql_query_post sql_ranged_throttle sql_query_post_index )
49
+
50
+ IndexOptions = %w( charset_table charset_type docinfo enable_star
51
+ exceptions html_index_attrs html_remove_elements html_strip ignore_chars
52
+ min_infix_len min_prefix_len min_word_len mlock morphology ngram_chars
53
+ ngram_len phrase_boundary phrase_boundary_step preopen stopwords
54
+ wordforms )
55
+
44
56
  attr_accessor :config_file, :searchd_log_file, :query_log_file,
45
- :pid_file, :searchd_file_path, :address, :port, :enable_star,
46
- :allow_star, :min_prefix_len, :min_infix_len, :mem_limit, :max_matches,
47
- :morphology, :charset_type, :charset_table, :ignore_chars, :html_strip,
48
- :html_remove_elements, :database_yml_file, :app_root
57
+ :pid_file, :searchd_file_path, :address, :port, :allow_star,
58
+ :database_yml_file, :app_root, :bin_path, :model_directories
59
+
60
+ attr_accessor :source_options, :index_options
49
61
 
50
- attr_reader :environment
62
+ attr_reader :environment, :configuration
51
63
 
52
64
  # Load in the configuration settings - this will look for config/sphinx.yml
53
65
  # and parse it according to the current environment.
54
66
  #
55
67
  def initialize(app_root = Dir.pwd)
68
+ self.reset
69
+ end
70
+
71
+ def reset
56
72
  self.app_root = RAILS_ROOT if defined?(RAILS_ROOT)
57
73
  self.app_root = Merb.root if defined?(Merb)
58
74
  self.app_root ||= app_root
59
75
 
76
+ @configuration = Riddle::Configuration.new
77
+ @configuration.searchd.address = "127.0.0.1"
78
+ @configuration.searchd.port = 3312
79
+ @configuration.searchd.pid_file = "#{self.app_root}/log/searchd.#{environment}.pid"
80
+ @configuration.searchd.log = "#{self.app_root}/log/searchd.log"
81
+ @configuration.searchd.query_log = "#{self.app_root}/log/searchd.query.log"
82
+
60
83
  self.database_yml_file = "#{self.app_root}/config/database.yml"
61
84
  self.config_file = "#{self.app_root}/config/#{environment}.sphinx.conf"
62
- self.searchd_log_file = "#{self.app_root}/log/searchd.log"
63
- self.query_log_file = "#{self.app_root}/log/searchd.query.log"
64
- self.pid_file = "#{self.app_root}/log/searchd.#{environment}.pid"
65
85
  self.searchd_file_path = "#{self.app_root}/db/sphinx/#{environment}"
66
- self.address = "127.0.0.1"
67
- self.port = 3312
68
86
  self.allow_star = false
69
- self.enable_star = false
70
- self.min_prefix_len = nil
71
- self.min_infix_len = nil
72
- self.mem_limit = "64M"
73
- self.max_matches = 1000
74
- self.morphology = "stem_en"
75
- self.charset_type = "utf-8"
76
- self.charset_table = nil
77
- self.ignore_chars = nil
78
- self.html_strip = false
79
- self.html_remove_elements = ""
87
+ self.bin_path = ""
88
+ self.model_directories = ["#{app_root}/app/models/"] +
89
+ Dir.glob("#{app_root}/vendor/plugins/*/app/models/")
80
90
 
91
+ self.source_options = {}
92
+ self.index_options = {
93
+ :charset_type => "utf-8",
94
+ :morphology => "stem_en"
95
+ }
96
+
81
97
  parse_config
98
+
99
+ self
82
100
  end
83
101
 
84
102
  def self.environment
85
103
  @@environment ||= (
86
- defined?(Merb) ? ENV['MERB_ENV'] : ENV['RAILS_ENV']
104
+ defined?(Merb) ? Merb.environment : ENV['RAILS_ENV']
87
105
  ) || "development"
88
106
  end
89
107
 
@@ -91,64 +109,26 @@ module ThinkingSphinx
91
109
  self.class.environment
92
110
  end
93
111
 
112
+ def controller
113
+ @controller ||= Riddle::Controller.new(@configuration, self.config_file)
114
+ end
115
+
94
116
  # Generate the config file for Sphinx by using all the settings defined and
95
117
  # looping through all the models with indexes to build the relevant
96
118
  # indexer and searchd configuration, and sources and indexes details.
97
119
  #
98
120
  def build(file_path=nil)
121
+ load_models
99
122
  file_path ||= "#{self.config_file}"
100
- database_confs = YAML::load(ERB.new(IO.read("#{self.database_yml_file}")).result)
101
- database_confs.symbolize_keys!
102
- database_conf = database_confs[environment.to_sym]
103
- database_conf.symbolize_keys!
123
+
124
+ @configuration.indexes.clear
125
+
126
+ ThinkingSphinx.indexed_models.each_with_index do |model, model_index|
127
+ @configuration.indexes.concat model.constantize.to_riddle(model_index)
128
+ end
104
129
 
105
130
  open(file_path, "w") do |file|
106
- file.write <<-CONFIG
107
- indexer
108
- {
109
- mem_limit = #{self.mem_limit}
110
- }
111
-
112
- searchd
113
- {
114
- address = #{self.address}
115
- port = #{self.port}
116
- log = #{self.searchd_log_file}
117
- query_log = #{self.query_log_file}
118
- read_timeout = 5
119
- max_children = 30
120
- pid_file = #{self.pid_file}
121
- max_matches = #{self.max_matches}
122
- }
123
- CONFIG
124
-
125
- ThinkingSphinx.indexed_models.each_with_index do |model, model_index|
126
- model = model.constantize
127
- sources = []
128
- delta_sources = []
129
- prefixed_fields = []
130
- infixed_fields = []
131
-
132
- model.indexes.select { |index| index.model == model }.each_with_index do |index, i|
133
- file.write index.to_config(model, i, database_conf, charset_type, model_index)
134
-
135
- create_array_accum if index.adapter == :postgres
136
- sources << "#{ThinkingSphinx::Index.name(model)}_#{i}_core"
137
- delta_sources << "#{ThinkingSphinx::Index.name(model)}_#{i}_delta" if index.delta?
138
- end
139
-
140
- next if sources.empty?
141
-
142
- source_list = sources.collect { |s| "source = #{s}" }.join("\n")
143
- delta_list = delta_sources.collect { |s| "source = #{s}" }.join("\n")
144
-
145
- file.write core_index_for_model(model, source_list)
146
- unless delta_list.blank?
147
- file.write delta_index_for_model(model, delta_list)
148
- end
149
-
150
- file.write distributed_index_for_model(model)
151
- end
131
+ file.write @configuration.render
152
132
  end
153
133
  end
154
134
 
@@ -157,25 +137,66 @@ searchd
157
137
  # messy dependencies issues).
158
138
  #
159
139
  def load_models
160
- base = "#{app_root}/app/models/"
161
- Dir["#{base}**/*.rb"].each do |file|
162
- model_name = file.gsub(/^#{base}([\w_\/\\]+)\.rb/, '\1')
140
+ self.model_directories.each do |base|
141
+ Dir["#{base}**/*.rb"].each do |file|
142
+ model_name = file.gsub(/^#{base}([\w_\/\\]+)\.rb/, '\1')
163
143
 
164
- next if model_name.nil?
165
- next if ::ActiveRecord::Base.send(:subclasses).detect { |model|
166
- model.name == model_name
167
- }
144
+ next if model_name.nil?
145
+ next if ::ActiveRecord::Base.send(:subclasses).detect { |model|
146
+ model.name == model_name
147
+ }
168
148
 
169
- begin
170
- model_name.camelize.constantize
171
- rescue LoadError
172
- model_name.gsub!(/.*[\/\\]/, '').nil? ? next : retry
173
- rescue NameError
174
- next
149
+ begin
150
+ model_name.camelize.constantize
151
+ rescue LoadError
152
+ model_name.gsub!(/.*[\/\\]/, '').nil? ? next : retry
153
+ rescue NameError
154
+ next
155
+ end
175
156
  end
176
157
  end
177
158
  end
178
159
 
160
+ def address
161
+ @configuration.searchd.address
162
+ end
163
+
164
+ def address=(address)
165
+ @configuration.searchd.address = address
166
+ end
167
+
168
+ def port
169
+ @configuration.searchd.port
170
+ end
171
+
172
+ def port=(port)
173
+ @configuration.searchd.port = port
174
+ end
175
+
176
+ def pid_file
177
+ @configuration.searchd.pid_file
178
+ end
179
+
180
+ def pid_file=(pid_file)
181
+ @configuration.searchd.pid_file = pid_file
182
+ end
183
+
184
+ def searchd_log_file
185
+ @configuration.searchd.log
186
+ end
187
+
188
+ def searchd_log_file=(file)
189
+ @configuration.searchd.log = file
190
+ end
191
+
192
+ def query_log_file
193
+ @configuration.searchd.query_log
194
+ end
195
+
196
+ def query_log_file=(file)
197
+ @configuration.searchd.query_log = file
198
+ end
199
+
179
200
  private
180
201
 
181
202
  # Parse the config/sphinx.yml file - if it exists - then use the attribute
@@ -189,100 +210,28 @@ searchd
189
210
 
190
211
  conf.each do |key,value|
191
212
  self.send("#{key}=", value) if self.methods.include?("#{key}=")
213
+
214
+ set_sphinx_setting self.source_options, key, value, SourceOptions
215
+ set_sphinx_setting self.index_options, key, value, IndexOptions
216
+ set_sphinx_setting @configuration.searchd, key, value
217
+ set_sphinx_setting @configuration.indexer, key, value
192
218
  end unless conf.nil?
193
- end
194
-
195
- def core_index_for_model(model, sources)
196
- output = <<-INDEX
197
-
198
- index #{ThinkingSphinx::Index.name(model)}_core
199
- {
200
- #{sources}
201
- path = #{self.searchd_file_path}/#{ThinkingSphinx::Index.name(model)}_core
202
- charset_type = #{self.charset_type}
203
- INDEX
204
219
 
205
- morphology = model.indexes.inject(self.morphology) { |morph, index|
206
- index.options[:morphology] || morph
207
- }
208
- output += " morphology = #{morphology}\n" unless morphology.blank?
209
- output += " charset_table = #{self.charset_table}\n" unless self.charset_table.nil?
210
- output += " ignore_chars = #{self.ignore_chars}\n" unless self.ignore_chars.nil?
220
+ self.bin_path += '/' unless self.bin_path.blank?
211
221
 
212
222
  if self.allow_star
213
- # Ye Olde way of turning on enable_star
214
- output += " enable_star = 1\n"
215
- output += " min_prefix_len = #{self.min_prefix_len}\n"
216
- else
217
- # New, better way of turning on enable_star - thanks to James Healy
218
- output += " enable_star = 1\n" if self.enable_star
219
- output += " min_prefix_len = #{self.min_prefix_len}\n" unless self.min_prefix_len.nil?
220
- output += " min_infix_len = #{self.min_infix_len}\n" unless self.min_infix_len.nil?
223
+ self.index_options[:enable_star] = true
224
+ self.index_options[:min_prefix_len] = 1
221
225
  end
222
-
223
-
224
- output += " html_strip = 1\n" if self.html_strip
225
- output += " html_remove_elements = #{self.html_remove_elements}\n" unless self.html_remove_elements.blank?
226
-
227
- unless model.indexes.collect(&:prefix_fields).flatten.empty?
228
- output += " prefix_fields = #{model.indexes.collect(&:prefix_fields).flatten.map(&:unique_name).join(', ')}\n"
229
- else
230
- output += " prefix_fields = _\n" unless model.indexes.collect(&:infix_fields).flatten.empty?
231
- end
232
-
233
- unless model.indexes.collect(&:infix_fields).flatten.empty?
234
- output += " infix_fields = #{model.indexes.collect(&:infix_fields).flatten.map(&:unique_name).join(', ')}\n"
235
- else
236
- output += " infix_fields = -\n" unless model.indexes.collect(&:prefix_fields).flatten.empty?
237
- end
238
-
239
- output + "}\n"
240
- end
241
-
242
- def delta_index_for_model(model, sources)
243
- <<-INDEX
244
- index #{ThinkingSphinx::Index.name(model)}_delta : #{ThinkingSphinx::Index.name(model)}_core
245
- {
246
- #{sources}
247
- path = #{self.searchd_file_path}/#{ThinkingSphinx::Index.name(model)}_delta
248
- }
249
- INDEX
250
- end
251
-
252
- def distributed_index_for_model(model)
253
- sources = ["local = #{ThinkingSphinx::Index.name(model)}_core"]
254
- if model.indexes.any? { |index| index.delta? }
255
- sources << "local = #{ThinkingSphinx::Index.name(model)}_delta"
256
- end
257
-
258
- <<-INDEX
259
- index #{ThinkingSphinx::Index.name(model)}
260
- {
261
- type = distributed
262
- #{ sources.join("\n ") }
263
- charset_type = #{self.charset_type}
264
- }
265
- INDEX
266
226
  end
267
227
 
268
- def create_array_accum
269
- ::ActiveRecord::Base.connection.execute "begin"
270
- ::ActiveRecord::Base.connection.execute "savepoint ts"
271
- begin
272
- ::ActiveRecord::Base.connection.execute <<-SQL
273
- CREATE AGGREGATE array_accum (anyelement)
274
- (
275
- sfunc = array_append,
276
- stype = anyarray,
277
- initcond = '{}'
278
- );
279
- SQL
280
- rescue
281
- raise unless $!.to_s =~ /already exists with same argument types/
282
- ::ActiveRecord::Base.connection.execute "rollback to savepoint ts"
228
+ def set_sphinx_setting(object, key, value, allowed = {})
229
+ if object.is_a?(Hash)
230
+ object[key.to_sym] = value if allowed.include?(key.to_s)
231
+ else
232
+ object.send("#{key}=", value) if object.methods.include?("#{key}")
233
+ send("#{key}=", value) if self.methods.include?("#{key}")
283
234
  end
284
- ::ActiveRecord::Base.connection.execute "release savepoint ts"
285
- ::ActiveRecord::Base.connection.execute "commit"
286
235
  end
287
236
  end
288
237
  end