load_balanced_tire 0.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 (121) hide show
  1. data/.gitignore +14 -0
  2. data/.travis.yml +29 -0
  3. data/Gemfile +4 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.markdown +760 -0
  6. data/Rakefile +78 -0
  7. data/examples/rails-application-template.rb +249 -0
  8. data/examples/tire-dsl.rb +876 -0
  9. data/lib/tire.rb +55 -0
  10. data/lib/tire/alias.rb +296 -0
  11. data/lib/tire/configuration.rb +30 -0
  12. data/lib/tire/dsl.rb +43 -0
  13. data/lib/tire/http/client.rb +62 -0
  14. data/lib/tire/http/clients/curb.rb +61 -0
  15. data/lib/tire/http/clients/faraday.rb +71 -0
  16. data/lib/tire/http/response.rb +27 -0
  17. data/lib/tire/index.rb +361 -0
  18. data/lib/tire/logger.rb +60 -0
  19. data/lib/tire/model/callbacks.rb +40 -0
  20. data/lib/tire/model/import.rb +26 -0
  21. data/lib/tire/model/indexing.rb +128 -0
  22. data/lib/tire/model/naming.rb +100 -0
  23. data/lib/tire/model/percolate.rb +99 -0
  24. data/lib/tire/model/persistence.rb +71 -0
  25. data/lib/tire/model/persistence/attributes.rb +143 -0
  26. data/lib/tire/model/persistence/finders.rb +66 -0
  27. data/lib/tire/model/persistence/storage.rb +69 -0
  28. data/lib/tire/model/search.rb +307 -0
  29. data/lib/tire/results/collection.rb +114 -0
  30. data/lib/tire/results/item.rb +86 -0
  31. data/lib/tire/results/pagination.rb +54 -0
  32. data/lib/tire/rubyext/hash.rb +8 -0
  33. data/lib/tire/rubyext/ruby_1_8.rb +7 -0
  34. data/lib/tire/rubyext/symbol.rb +11 -0
  35. data/lib/tire/search.rb +188 -0
  36. data/lib/tire/search/facet.rb +74 -0
  37. data/lib/tire/search/filter.rb +28 -0
  38. data/lib/tire/search/highlight.rb +37 -0
  39. data/lib/tire/search/query.rb +186 -0
  40. data/lib/tire/search/scan.rb +114 -0
  41. data/lib/tire/search/script_field.rb +23 -0
  42. data/lib/tire/search/sort.rb +25 -0
  43. data/lib/tire/tasks.rb +135 -0
  44. data/lib/tire/utils.rb +17 -0
  45. data/lib/tire/version.rb +22 -0
  46. data/test/fixtures/articles/1.json +1 -0
  47. data/test/fixtures/articles/2.json +1 -0
  48. data/test/fixtures/articles/3.json +1 -0
  49. data/test/fixtures/articles/4.json +1 -0
  50. data/test/fixtures/articles/5.json +1 -0
  51. data/test/integration/active_model_indexing_test.rb +51 -0
  52. data/test/integration/active_model_searchable_test.rb +114 -0
  53. data/test/integration/active_record_searchable_test.rb +446 -0
  54. data/test/integration/boolean_queries_test.rb +43 -0
  55. data/test/integration/count_test.rb +34 -0
  56. data/test/integration/custom_score_queries_test.rb +88 -0
  57. data/test/integration/dis_max_queries_test.rb +68 -0
  58. data/test/integration/dsl_search_test.rb +22 -0
  59. data/test/integration/explanation_test.rb +44 -0
  60. data/test/integration/facets_test.rb +259 -0
  61. data/test/integration/filtered_queries_test.rb +66 -0
  62. data/test/integration/filters_test.rb +63 -0
  63. data/test/integration/fuzzy_queries_test.rb +20 -0
  64. data/test/integration/highlight_test.rb +64 -0
  65. data/test/integration/index_aliases_test.rb +122 -0
  66. data/test/integration/index_mapping_test.rb +43 -0
  67. data/test/integration/index_store_test.rb +96 -0
  68. data/test/integration/index_update_document_test.rb +111 -0
  69. data/test/integration/mongoid_searchable_test.rb +309 -0
  70. data/test/integration/percolator_test.rb +111 -0
  71. data/test/integration/persistent_model_test.rb +130 -0
  72. data/test/integration/prefix_query_test.rb +43 -0
  73. data/test/integration/query_return_version_test.rb +70 -0
  74. data/test/integration/query_string_test.rb +52 -0
  75. data/test/integration/range_queries_test.rb +36 -0
  76. data/test/integration/reindex_test.rb +46 -0
  77. data/test/integration/results_test.rb +39 -0
  78. data/test/integration/scan_test.rb +56 -0
  79. data/test/integration/script_fields_test.rb +38 -0
  80. data/test/integration/sort_test.rb +36 -0
  81. data/test/integration/text_query_test.rb +39 -0
  82. data/test/models/active_model_article.rb +31 -0
  83. data/test/models/active_model_article_with_callbacks.rb +49 -0
  84. data/test/models/active_model_article_with_custom_document_type.rb +7 -0
  85. data/test/models/active_model_article_with_custom_index_name.rb +7 -0
  86. data/test/models/active_record_models.rb +122 -0
  87. data/test/models/article.rb +15 -0
  88. data/test/models/mongoid_models.rb +97 -0
  89. data/test/models/persistent_article.rb +11 -0
  90. data/test/models/persistent_article_in_namespace.rb +12 -0
  91. data/test/models/persistent_article_with_casting.rb +28 -0
  92. data/test/models/persistent_article_with_defaults.rb +11 -0
  93. data/test/models/persistent_articles_with_custom_index_name.rb +10 -0
  94. data/test/models/supermodel_article.rb +17 -0
  95. data/test/models/validated_model.rb +11 -0
  96. data/test/test_helper.rb +93 -0
  97. data/test/unit/active_model_lint_test.rb +17 -0
  98. data/test/unit/configuration_test.rb +74 -0
  99. data/test/unit/http_client_test.rb +76 -0
  100. data/test/unit/http_response_test.rb +49 -0
  101. data/test/unit/index_alias_test.rb +275 -0
  102. data/test/unit/index_test.rb +894 -0
  103. data/test/unit/logger_test.rb +125 -0
  104. data/test/unit/model_callbacks_test.rb +116 -0
  105. data/test/unit/model_import_test.rb +71 -0
  106. data/test/unit/model_persistence_test.rb +528 -0
  107. data/test/unit/model_search_test.rb +913 -0
  108. data/test/unit/results_collection_test.rb +281 -0
  109. data/test/unit/results_item_test.rb +162 -0
  110. data/test/unit/rubyext_test.rb +66 -0
  111. data/test/unit/search_facet_test.rb +153 -0
  112. data/test/unit/search_filter_test.rb +42 -0
  113. data/test/unit/search_highlight_test.rb +46 -0
  114. data/test/unit/search_query_test.rb +301 -0
  115. data/test/unit/search_scan_test.rb +113 -0
  116. data/test/unit/search_script_field_test.rb +26 -0
  117. data/test/unit/search_sort_test.rb +50 -0
  118. data/test/unit/search_test.rb +499 -0
  119. data/test/unit/tire_test.rb +126 -0
  120. data/tire.gemspec +90 -0
  121. metadata +549 -0
@@ -0,0 +1,61 @@
1
+ require 'curb'
2
+
3
+ module Tire
4
+
5
+ module HTTP
6
+
7
+ module Client
8
+
9
+ class Curb
10
+ @client = ::Curl::Easy.new
11
+ @client.resolve_mode = :ipv4
12
+
13
+ # @client.verbose = true
14
+
15
+ def self.get(url, data=nil)
16
+ @client.url = url
17
+
18
+ # FIXME: Curb cannot post bodies with GET requests?
19
+ # Roy Fielding seems to approve:
20
+ # <http://tech.groups.yahoo.com/group/rest-discuss/message/9962>
21
+ if data
22
+ @client.post_body = data
23
+ @client.http_post
24
+ else
25
+ @client.http_get
26
+ end
27
+ Response.new @client.body_str, @client.response_code
28
+ end
29
+
30
+ def self.post(url, data)
31
+ @client.url = url
32
+ @client.post_body = data
33
+ @client.http_post
34
+ Response.new @client.body_str, @client.response_code
35
+ end
36
+
37
+ def self.put(url, data)
38
+ @client.url = url
39
+ @client.http_put data
40
+ Response.new @client.body_str, @client.response_code
41
+ end
42
+
43
+ def self.delete(url)
44
+ @client.url = url
45
+ @client.http_delete
46
+ Response.new @client.body_str, @client.response_code
47
+ end
48
+
49
+ def self.head(url)
50
+ @client.url = url
51
+ @client.http_head
52
+ Response.new @client.body_str, @client.response_code
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,71 @@
1
+ require 'faraday'
2
+
3
+ # A Faraday-based HTTP client, which allows you to choose a HTTP client.
4
+ #
5
+ # See <https://github.com/technoweenie/faraday/tree/master/lib/faraday/adapter>
6
+ #
7
+ # NOTE: Tire will switch to Faraday for the HTTP abstraction layer. This client is a temporary solution.
8
+ #
9
+ # Example:
10
+ # --------
11
+ #
12
+ # require 'typhoeus'
13
+ # require 'tire/http/clients/faraday'
14
+ #
15
+ # Tire.configure do |config|
16
+ #
17
+ # # Unless specified, tire will use Faraday.default_adapter and no middleware
18
+ # Tire::HTTP::Client::Faraday.faraday_middleware = Proc.new do |builder|
19
+ # builder.adapter :typhoeus
20
+ # end
21
+ #
22
+ # config.client(Tire::HTTP::Client::Faraday)
23
+ #
24
+ # end
25
+ #
26
+ #
27
+ module Tire
28
+ module HTTP
29
+ module Client
30
+ class Faraday
31
+
32
+ # Default middleware stack.
33
+ DEFAULT_MIDDLEWARE = Proc.new do |builder|
34
+ builder.adapter ::Faraday.default_adapter
35
+ end
36
+
37
+ class << self
38
+ # A customized stack of Faraday middleware that will be used to make each request.
39
+ attr_accessor :faraday_middleware
40
+
41
+ def get(url, data = nil)
42
+ request(:get, url, data)
43
+ end
44
+
45
+ def post(url, data)
46
+ request(:post, url, data)
47
+ end
48
+
49
+ def put(url, data)
50
+ request(:put, url, data)
51
+ end
52
+
53
+ def delete(url, data = nil)
54
+ request(:delete, url, data)
55
+ end
56
+
57
+ def head(url)
58
+ request(:head, url)
59
+ end
60
+
61
+ private
62
+ def request(method, url, data = nil)
63
+ conn = ::Faraday.new( &(faraday_middleware || DEFAULT_MIDDLEWARE) )
64
+ response = conn.run_request(method, url, data, nil)
65
+ Response.new(response.body, response.status, response.headers)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,27 @@
1
+ module Tire
2
+
3
+ module HTTP
4
+
5
+ class Response
6
+ attr_reader :body, :code, :headers
7
+
8
+ def initialize(body, code, headers={})
9
+ @body, @code, @headers = body, code.to_i, headers
10
+ end
11
+
12
+ def success?
13
+ code > 0 && code < 400
14
+ end
15
+
16
+ def failure?
17
+ ! success?
18
+ end
19
+
20
+ def to_s
21
+ [code, body].join(' : ')
22
+ end
23
+ end
24
+
25
+ end
26
+
27
+ end
data/lib/tire/index.rb ADDED
@@ -0,0 +1,361 @@
1
+ module Tire
2
+ class Index
3
+
4
+ attr_reader :name, :response
5
+
6
+ def initialize(name, &block)
7
+ @name = name
8
+ block.arity < 1 ? instance_eval(&block) : block.call(self) if block_given?
9
+ end
10
+
11
+ def url
12
+ "#{Configuration.url}/#{@name}"
13
+ end
14
+
15
+ def exists?
16
+ @response = Configuration.client.head("#{url}")
17
+ @response.success?
18
+
19
+ ensure
20
+ curl = %Q|curl -I "#{url}"|
21
+ logged('HEAD', curl)
22
+ end
23
+
24
+ def delete
25
+ @response = Configuration.client.delete url
26
+ @response.success?
27
+
28
+ ensure
29
+ curl = %Q|curl -X DELETE #{url}|
30
+ logged('DELETE', curl)
31
+ end
32
+
33
+ def create(options={})
34
+ @options = options
35
+ @response = Configuration.client.post url, MultiJson.encode(options)
36
+ @response.success? ? @response : false
37
+
38
+ ensure
39
+ curl = %Q|curl -X POST #{url} -d '#{MultiJson.encode(options)}'|
40
+ logged('CREATE', curl)
41
+ end
42
+
43
+ def add_alias(alias_name, configuration={})
44
+ Alias.create(configuration.merge( :name => alias_name, :index => @name ) )
45
+ end
46
+
47
+ def remove_alias(alias_name)
48
+ Alias.find(alias_name) { |a| a.indices.delete @name }.save
49
+ end
50
+
51
+ def aliases(alias_name=nil)
52
+ alias_name ? Alias.all(@name).select { |a| a.name == alias_name }.first : Alias.all(@name)
53
+ end
54
+
55
+ def mapping
56
+ @response = Configuration.client.get("#{url}/_mapping")
57
+ MultiJson.decode(@response.body)[@name]
58
+ end
59
+
60
+ def settings
61
+ @response = Configuration.client.get("#{url}/_settings")
62
+ MultiJson.decode(@response.body)[@name]['settings']
63
+ end
64
+
65
+ def store(*args)
66
+ document, options = args
67
+ type = get_type_from_document(document)
68
+
69
+ if options
70
+ percolate = options[:percolate]
71
+ percolate = "*" if percolate === true
72
+ end
73
+
74
+ id = get_id_from_document(document)
75
+ document = convert_document_to_json(document)
76
+
77
+ url = id ? "#{self.url}/#{type}/#{id}" : "#{self.url}/#{type}/"
78
+ url += "?percolate=#{percolate}" if percolate
79
+
80
+ @response = Configuration.client.post url, document
81
+ MultiJson.decode(@response.body)
82
+
83
+ ensure
84
+ curl = %Q|curl -X POST "#{url}" -d '#{document}'|
85
+ logged([type, id].join('/'), curl)
86
+ end
87
+
88
+ def bulk_store(documents, options={})
89
+ payload = documents.map do |document|
90
+ type = get_type_from_document(document, :escape => false) # Do not URL-escape the _type
91
+ id = get_id_from_document(document)
92
+
93
+ STDERR.puts "[ERROR] Document #{document.inspect} does not have ID" unless id
94
+
95
+ output = []
96
+ output << %Q|{"index":{"_index":"#{@name}","_type":"#{type}","_id":"#{id}"}}|
97
+ output << convert_document_to_json(document)
98
+ output.join("\n")
99
+ end
100
+ payload << ""
101
+
102
+ tries = 5
103
+ count = 0
104
+
105
+ begin
106
+ @response = Configuration.client.post("#{url}/_bulk", payload.join("\n"))
107
+ raise RuntimeError, "#{@response.code} > #{@response.body}" if @response && @response.failure?
108
+ @response
109
+ rescue StandardError => error
110
+ if count < tries
111
+ count += 1
112
+ STDERR.puts "[ERROR] #{error.message}, retrying (#{count})..."
113
+ retry
114
+ else
115
+ STDERR.puts "[ERROR] Too many exceptions occured, giving up. The HTTP response was: #{error.message}"
116
+ raise if options[:raise]
117
+ end
118
+
119
+ ensure
120
+ curl = %Q|curl -X POST "#{url}/_bulk" -d '{... data omitted ...}'|
121
+ logged('BULK', curl)
122
+ end
123
+ end
124
+
125
+ def import(klass_or_collection, options={})
126
+ case
127
+ when method = options.delete(:method)
128
+ options = {:page => 1, :per_page => 1000}.merge options
129
+ while documents = klass_or_collection.send(method.to_sym, options.merge(:page => options[:page])) \
130
+ and documents.to_a.length > 0
131
+
132
+ documents = yield documents if block_given?
133
+
134
+ bulk_store documents, options
135
+ options[:page] += 1
136
+ end
137
+
138
+ when klass_or_collection.respond_to?(:map)
139
+ documents = block_given? ? yield(klass_or_collection) : klass_or_collection
140
+ bulk_store documents, options
141
+
142
+ else
143
+ raise ArgumentError, "Please pass either an Enumerable compatible class, or a collection object" +
144
+ "with a method for fetching records in batches (such as 'paginate')"
145
+ end
146
+ end
147
+
148
+ def reindex(name, options={}, &block)
149
+ new_index = Index.new(name)
150
+ new_index.create(options) unless new_index.exists?
151
+
152
+ Search::Scan.new(self.name, &block).each do |results|
153
+ new_index.bulk_store results.map do |document|
154
+ document.to_hash.except(:type, :_index, :_explanation, :_score, :_version, :highlight, :sort)
155
+ end
156
+ end
157
+ end
158
+
159
+ def remove(*args)
160
+ if args.size > 1
161
+ type, document = args
162
+ type = Utils.escape(type)
163
+ id = get_id_from_document(document) || document
164
+ else
165
+ document = args.pop
166
+ type = get_type_from_document(document)
167
+ id = get_id_from_document(document) || document
168
+ end
169
+ raise ArgumentError, "Please pass a document ID" unless id
170
+
171
+ url = "#{self.url}/#{type}/#{id}"
172
+ result = Configuration.client.delete url
173
+ MultiJson.decode(result.body) if result.success?
174
+
175
+ ensure
176
+ curl = %Q|curl -X DELETE "#{url}"|
177
+ logged(id, curl)
178
+ end
179
+
180
+ def retrieve(type, id)
181
+ raise ArgumentError, "Please pass a document ID" unless id
182
+
183
+ type = Utils.escape(type)
184
+ url = "#{self.url}/#{type}/#{id}"
185
+ @response = Configuration.client.get url
186
+
187
+ h = MultiJson.decode(@response.body)
188
+ if Configuration.wrapper == Hash then h
189
+ else
190
+ return nil if h['exists'] == false
191
+ document = h['_source'] || h['fields'] || {}
192
+ document.update('id' => h['_id'], '_type' => h['_type'], '_index' => h['_index'], '_version' => h['_version'])
193
+ Configuration.wrapper.new(document)
194
+ end
195
+
196
+ ensure
197
+ curl = %Q|curl -X GET "#{url}"|
198
+ logged(id, curl)
199
+ end
200
+
201
+ def update(type, id, payload={}, options={})
202
+ raise ArgumentError, "Please pass a document type" unless type
203
+ raise ArgumentError, "Please pass a document ID" unless id
204
+ raise ArgumentError, "Please pass a script in the payload hash" unless payload[:script]
205
+
206
+ type = Utils.escape(type)
207
+ url = "#{self.url}/#{type}/#{id}/_update"
208
+ url += "?#{options.to_param}" unless options.keys.empty?
209
+ @response = Configuration.client.post url, MultiJson.encode(payload)
210
+ MultiJson.decode(@response.body)
211
+
212
+ ensure
213
+ curl = %Q|curl -X POST "#{url}" -d '#{MultiJson.encode(payload)}'|
214
+ logged(id, curl)
215
+ end
216
+
217
+ def refresh
218
+ @response = Configuration.client.post "#{url}/_refresh", ''
219
+
220
+ ensure
221
+ curl = %Q|curl -X POST "#{url}/_refresh"|
222
+ logged('_refresh', curl)
223
+ end
224
+
225
+ def open(options={})
226
+ # TODO: Remove the duplication in the execute > rescue > ensure chain
227
+ @response = Configuration.client.post "#{url}/_open", MultiJson.encode(options)
228
+ MultiJson.decode(@response.body)['ok']
229
+
230
+ ensure
231
+ curl = %Q|curl -X POST "#{url}/_open"|
232
+ logged('_open', curl)
233
+ end
234
+
235
+ def close(options={})
236
+ @response = Configuration.client.post "#{url}/_close", MultiJson.encode(options)
237
+ MultiJson.decode(@response.body)['ok']
238
+
239
+ ensure
240
+ curl = %Q|curl -X POST "#{url}/_close"|
241
+ logged('_close', curl)
242
+ end
243
+
244
+ def analyze(text, options={})
245
+ options = {:pretty => true}.update(options)
246
+ params = options.to_param
247
+ @response = Configuration.client.get "#{url}/_analyze?#{params}", text
248
+ @response.success? ? MultiJson.decode(@response.body) : false
249
+
250
+ ensure
251
+ curl = %Q|curl -X GET "#{url}/_analyze?#{params}" -d '#{text}'|
252
+ logged('_analyze', curl)
253
+ end
254
+
255
+ def register_percolator_query(name, options={}, &block)
256
+ options[:query] = Search::Query.new(&block).to_hash if block_given?
257
+
258
+ @response = Configuration.client.put "#{Configuration.url}/_percolator/#{@name}/#{name}", MultiJson.encode(options)
259
+ MultiJson.decode(@response.body)['ok']
260
+
261
+ ensure
262
+ curl = %Q|curl -X PUT "#{Configuration.url}/_percolator/#{@name}/#{name}?pretty=1" -d '#{MultiJson.encode(options)}'|
263
+ logged('_percolator', curl)
264
+ end
265
+
266
+ def unregister_percolator_query(name)
267
+ @response = Configuration.client.delete "#{Configuration.url}/_percolator/#{@name}/#{name}"
268
+ MultiJson.decode(@response.body)['ok']
269
+
270
+ ensure
271
+ curl = %Q|curl -X DELETE "#{Configuration.url}/_percolator/#{@name}"|
272
+ logged('_percolator', curl)
273
+ end
274
+
275
+ def percolate(*args, &block)
276
+ document = args.shift
277
+ type = get_type_from_document(document)
278
+
279
+ document = MultiJson.decode convert_document_to_json(document)
280
+
281
+ query = Search::Query.new(&block).to_hash if block_given?
282
+
283
+ payload = { :doc => document }
284
+ payload.update( :query => query ) if query
285
+
286
+ @response = Configuration.client.get "#{url}/#{type}/_percolate", MultiJson.encode(payload)
287
+ MultiJson.decode(@response.body)['matches']
288
+
289
+ ensure
290
+ curl = %Q|curl -X GET "#{url}/#{type}/_percolate?pretty=1" -d '#{payload.to_json}'|
291
+ logged('_percolate', curl)
292
+ end
293
+
294
+ def logged(endpoint='/', curl='')
295
+ if Configuration.logger
296
+ error = $!
297
+
298
+ Configuration.logger.log_request endpoint, @name, curl
299
+
300
+ code = @response ? @response.code : error.class rescue 'N/A'
301
+
302
+ if Configuration.logger.level.to_s == 'debug'
303
+ body = if @response
304
+ defined?(Yajl) ? Yajl::Encoder.encode(@response.body, :pretty => true) : MultiJson.encode(@response.body)
305
+ else
306
+ error.message rescue ''
307
+ end
308
+ else
309
+ body = ''
310
+ end
311
+
312
+ Configuration.logger.log_response code, nil, body
313
+ end
314
+ end
315
+
316
+ def get_type_from_document(document, options={})
317
+ options = {:escape => true}.merge(options)
318
+
319
+ old_verbose, $VERBOSE = $VERBOSE, nil # Silence Object#type deprecation warnings
320
+ type = case
321
+ when document.respond_to?(:document_type)
322
+ document.document_type
323
+ when document.is_a?(Hash)
324
+ document[:_type] || document['_type'] || document[:type] || document['type']
325
+ when document.respond_to?(:_type)
326
+ document._type
327
+ when document.respond_to?(:type) && document.type != document.class
328
+ document.type
329
+ end
330
+ $VERBOSE = old_verbose
331
+
332
+ type ||= 'document'
333
+ options[:escape] ? Utils.escape(type) : type
334
+ end
335
+
336
+ def get_id_from_document(document)
337
+ old_verbose, $VERBOSE = $VERBOSE, nil # Silence Object#id deprecation warnings
338
+ id = case
339
+ when document.is_a?(Hash)
340
+ document[:_id] || document['_id'] || document[:id] || document['id']
341
+ when document.respond_to?(:id) && document.id != document.object_id
342
+ document.id
343
+ end
344
+ $VERBOSE = old_verbose
345
+ id
346
+ end
347
+
348
+ def convert_document_to_json(document)
349
+ document = case
350
+ when document.is_a?(String)
351
+ Tire.warn "Passing the document as JSON string in Index#store has been deprecated, " +
352
+ "please pass an object which responds to `to_indexed_json` or a plain Hash."
353
+ document
354
+ when document.respond_to?(:to_indexed_json) then document.to_indexed_json
355
+ else raise ArgumentError, "Please pass a JSON string or object with a 'to_indexed_json' method," +
356
+ "'#{document.class}' given."
357
+ end
358
+ end
359
+
360
+ end
361
+ end