ssickles-tire 0.4.2 → 0.4.2.7

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 (59) hide show
  1. data/lib/tire.rb +3 -18
  2. data/lib/tire/alias.rb +35 -11
  3. data/lib/tire/index.rb +76 -34
  4. data/lib/tire/results/collection.rb +13 -38
  5. data/lib/tire/results/item.rb +0 -19
  6. data/lib/tire/rubyext/to_json.rb +21 -0
  7. data/lib/tire/search.rb +8 -7
  8. data/lib/tire/search/scan.rb +8 -8
  9. data/lib/tire/search/sort.rb +1 -1
  10. data/lib/tire/version.rb +38 -7
  11. data/test/integration/reindex_test.rb +2 -2
  12. data/test/integration/scan_test.rb +1 -1
  13. data/test/test_helper.rb +3 -27
  14. data/test/unit/index_alias_test.rb +17 -3
  15. data/test/unit/index_test.rb +18 -30
  16. data/test/unit/results_collection_test.rb +0 -60
  17. data/test/unit/results_item_test.rb +0 -37
  18. data/test/unit/rubyext_test.rb +3 -3
  19. data/test/unit/search_test.rb +6 -1
  20. data/test/unit/tire_test.rb +0 -15
  21. data/tire.gemspec +13 -30
  22. metadata +41 -153
  23. data/lib/tire/model/callbacks.rb +0 -40
  24. data/lib/tire/model/import.rb +0 -26
  25. data/lib/tire/model/indexing.rb +0 -128
  26. data/lib/tire/model/naming.rb +0 -100
  27. data/lib/tire/model/percolate.rb +0 -99
  28. data/lib/tire/model/persistence.rb +0 -72
  29. data/lib/tire/model/persistence/attributes.rb +0 -143
  30. data/lib/tire/model/persistence/finders.rb +0 -66
  31. data/lib/tire/model/persistence/storage.rb +0 -71
  32. data/lib/tire/model/search.rb +0 -305
  33. data/lib/tire/rubyext/hash.rb +0 -8
  34. data/lib/tire/rubyext/ruby_1_8.rb +0 -54
  35. data/lib/tire/rubyext/symbol.rb +0 -11
  36. data/lib/tire/utils.rb +0 -17
  37. data/test/integration/active_model_indexing_test.rb +0 -51
  38. data/test/integration/active_model_searchable_test.rb +0 -114
  39. data/test/integration/active_record_searchable_test.rb +0 -446
  40. data/test/integration/mongoid_searchable_test.rb +0 -309
  41. data/test/integration/persistent_model_test.rb +0 -117
  42. data/test/models/active_model_article.rb +0 -31
  43. data/test/models/active_model_article_with_callbacks.rb +0 -49
  44. data/test/models/active_model_article_with_custom_document_type.rb +0 -7
  45. data/test/models/active_model_article_with_custom_index_name.rb +0 -7
  46. data/test/models/active_record_models.rb +0 -122
  47. data/test/models/mongoid_models.rb +0 -97
  48. data/test/models/persistent_article.rb +0 -11
  49. data/test/models/persistent_article_in_namespace.rb +0 -12
  50. data/test/models/persistent_article_with_casting.rb +0 -28
  51. data/test/models/persistent_article_with_defaults.rb +0 -11
  52. data/test/models/persistent_articles_with_custom_index_name.rb +0 -10
  53. data/test/models/supermodel_article.rb +0 -17
  54. data/test/models/validated_model.rb +0 -11
  55. data/test/unit/active_model_lint_test.rb +0 -17
  56. data/test/unit/model_callbacks_test.rb +0 -116
  57. data/test/unit/model_import_test.rb +0 -71
  58. data/test/unit/model_persistence_test.rb +0 -516
  59. data/test/unit/model_search_test.rb +0 -899
@@ -1,17 +1,12 @@
1
1
  require 'rest_client'
2
2
  require 'multi_json'
3
- #require 'active_model'
4
3
  require 'hashr'
5
4
  require 'cgi'
5
+ require 'escape_utils'
6
6
 
7
- require 'active_support'
7
+ require 'active_support/core_ext'
8
8
 
9
- # Ruby 1.8 compatibility
10
- require 'tire/rubyext/ruby_1_8' if defined?(RUBY_VERSION) && RUBY_VERSION < '1.9'
11
-
12
- require 'tire/rubyext/hash'
13
- require 'tire/rubyext/symbol'
14
- require 'tire/utils'
9
+ require 'tire/rubyext/to_json'
15
10
  require 'tire/logger'
16
11
  require 'tire/configuration'
17
12
  require 'tire/http/response'
@@ -29,16 +24,6 @@ require 'tire/results/item'
29
24
  require 'tire/index'
30
25
  require 'tire/alias'
31
26
  require 'tire/dsl'
32
- require 'tire/model/naming'
33
- require 'tire/model/callbacks'
34
- require 'tire/model/percolate'
35
- require 'tire/model/indexing'
36
- require 'tire/model/import'
37
- require 'tire/model/search'
38
- require 'tire/model/persistence/finders'
39
- require 'tire/model/persistence/attributes'
40
- require 'tire/model/persistence/storage'
41
- require 'tire/model/persistence'
42
27
  require 'tire/tasks'
43
28
 
44
29
  module Tire
@@ -74,6 +74,7 @@ module Tire
74
74
  def initialize(attributes={}, &block)
75
75
  raise ArgumentError, "Please pass a Hash-like object" unless attributes.respond_to?(:each_pair)
76
76
 
77
+ @url = attributes.delete(:url) || Configuration.url
77
78
  @attributes = { :indices => IndexCollection.new([]) }
78
79
 
79
80
  attributes.each_pair do |key, value|
@@ -87,34 +88,57 @@ module Tire
87
88
  block.arity < 1 ? instance_eval(&block) : block.call(self) if block_given?
88
89
  end
89
90
 
91
+ attr_accessor :url
92
+
90
93
  # Returns a collection of Tire::Alias objects for all aliases defined in the cluster, or for a specific index.
91
94
  #
92
- def self.all(index=nil)
93
- @response = Configuration.client.get [Configuration.url, index, '_aliases'].compact.join('/')
95
+ def self.all(url=nil, index=nil)
96
+ if url and url !~ /^https?:\/\//i
97
+ index, url = url, Configuration.url
98
+ elsif url.nil?
99
+ url = Configuration.url
100
+ end
94
101
 
95
- aliases = MultiJson.decode(@response.body).inject({}) do |result, (index, value)|
102
+ @response = Configuration.client.get [url, index, '_aliases'].compact.join('/')
103
+
104
+ aliases = MultiJson.decode(@response.body).inject({}) do |result, (name, value)|
96
105
  # 1] Skip indices without aliases
97
106
  next result if value['aliases'].empty?
98
107
 
99
108
  # 2] Build a reverse map of hashes (alias => indices, config)
100
- value['aliases'].each do |key, value| (result[key] ||= { 'indices' => [] }).update(value)['indices'].push(index) end
109
+ value['aliases'].each do |key, v| (result[key] ||= { 'indices' => [] }).update(v)['indices'].push(name) end
101
110
  result
102
111
  end
103
112
 
104
113
  # 3] Build a collection of Alias objects from hashes
105
114
  aliases.map do |key, value|
106
- self.new(value.update('name' => key))
115
+ self.new(value.update('name' => key, :url => url))
107
116
  end
108
117
 
109
118
  ensure
110
119
  # FIXME: Extract the `logged` method
111
- Alias.new.logged '_aliases', %Q|curl "#{Configuration.url}/_aliases"|
120
+ Alias.new.logged '_aliases', %Q|curl "#{url}/_aliases"|
112
121
  end
113
122
 
114
123
  # Returns an alias by name
115
124
  #
116
- def self.find(name, &block)
117
- a = all.select { |a| a.name == name }.first
125
+ # Examples
126
+ #
127
+ # Alias.find( url, name )
128
+ # Alias.find( name )
129
+ #
130
+ def self.find(*args, &block)
131
+ case args.length
132
+ when 2
133
+ url, name = args
134
+ when 1
135
+ url = Configuration.url
136
+ name = args.first
137
+ else
138
+ raise ArgumentError, "wrong number of arguments (#{args.length} for 2)"
139
+ end
140
+
141
+ a = all(url).select { |b| b.name == name }.first
118
142
  block.call(a) if block_given?
119
143
  return a
120
144
  end
@@ -159,10 +183,10 @@ module Tire
159
183
  # Save the alias in _ElasticSearch_
160
184
  #
161
185
  def save
162
- @response = Configuration.client.post "#{Configuration.url}/_aliases", to_json
186
+ @response = Configuration.client.post "#{url}/_aliases", to_json
163
187
 
164
188
  ensure
165
- logged '_aliases', %Q|curl -X POST "#{Configuration.url}/_aliases" -d '#{to_json}'|
189
+ logged '_aliases', %Q|curl -X POST "#{url}/_aliases" -d '#{to_json}'|
166
190
  end
167
191
 
168
192
  # Return a Hash suitable for JSON serialization
@@ -187,7 +211,7 @@ module Tire
187
211
  # Return alias serialized in JSON for _ElasticSearch_
188
212
  #
189
213
  def to_json(options=nil)
190
- as_json.to_json
214
+ MultiJson.encode(as_json)
191
215
  end
192
216
 
193
217
  def inspect
@@ -1,15 +1,27 @@
1
1
  module Tire
2
2
  class Index
3
3
 
4
- attr_reader :name, :response
4
+ attr_reader :name, :response, :url
5
+
6
+ def initialize(*args, &block)
7
+ case args.length
8
+ when 2
9
+ @name = args.last
10
+ self.url = args.first
11
+ when 1
12
+ @name = args.first
13
+ self.url = Configuration.url
14
+ else
15
+ raise ArgumentError, "wrong number of arguments (#{args.length} for 2)"
16
+ end
5
17
 
6
- def initialize(name, &block)
7
- @name = name
8
18
  block.arity < 1 ? instance_eval(&block) : block.call(self) if block_given?
9
19
  end
10
20
 
11
- def url
12
- "#{Configuration.url}/#{@name}"
21
+ def url=( url )
22
+ @base_url = url.dup
23
+ @url = "#@base_url/#@name"
24
+ @percolator_url = "#@base_url/_percolator/#@name"
13
25
  end
14
26
 
15
27
  def exists?
@@ -41,15 +53,15 @@ module Tire
41
53
  end
42
54
 
43
55
  def add_alias(alias_name, configuration={})
44
- Alias.create(configuration.merge( :name => alias_name, :index => @name ) )
56
+ Alias.create(configuration.merge( :name => alias_name, :index => @name, :url => @base_url ) )
45
57
  end
46
58
 
47
59
  def remove_alias(alias_name)
48
- Alias.find(alias_name) { |a| a.indices.delete @name }.save
60
+ Alias.find(@base_url, alias_name) { |a| a.indices.delete @name }.save
49
61
  end
50
62
 
51
63
  def aliases(alias_name=nil)
52
- alias_name ? Alias.all(@name).select { |a| a.name == alias_name }.first : Alias.all(@name)
64
+ alias_name ? Alias.all(@base_url, @name).select { |a| a.name == alias_name }.first : Alias.all(@base_url, @name)
53
65
  end
54
66
 
55
67
  def mapping
@@ -63,23 +75,24 @@ module Tire
63
75
  end
64
76
 
65
77
  def store(*args)
66
- document, options = args
67
- type = get_type_from_document(document)
78
+ document, params = args
79
+ id = get_id_from_document(document)
80
+ type = get_type_from_document(document)
81
+ routing = get_routing_from_document(document)
82
+ parent = get_parent_from_document(document)
68
83
 
69
- if options
70
- percolate = options[:percolate]
71
- percolate = "*" if percolate === true
72
- end
84
+ params ||= {}
85
+ params[:routing] = routing if routing
86
+ params[:parent] = parent if parent
87
+ params[:percolate] = '*' if params[:percolate] === true
73
88
 
74
- id = get_id_from_document(document)
75
- document = convert_document_to_json(document)
89
+ url = id ? "#{self.url}/#{type}/#{id}" : "#{self.url}/#{type}"
90
+ url << "?#{params.to_param}" unless params.empty?
76
91
 
77
- url = id ? "#{self.url}/#{type}/#{id}" : "#{self.url}/#{type}/"
78
- url += "?percolate=#{percolate}" if percolate
92
+ document = convert_document_to_json(document)
79
93
 
80
94
  @response = Configuration.client.post url, document
81
95
  MultiJson.decode(@response.body)
82
-
83
96
  ensure
84
97
  curl = %Q|curl -X POST "#{url}" -d '#{document}'|
85
98
  logged([type, id].join('/'), curl)
@@ -159,7 +172,7 @@ module Tire
159
172
  def remove(*args)
160
173
  if args.size > 1
161
174
  type, document = args
162
- type = Utils.escape(type)
175
+ type = EscapeUtils.escape_url(type.to_s)
163
176
  id = get_id_from_document(document) || document
164
177
  else
165
178
  document = args.pop
@@ -168,20 +181,25 @@ module Tire
168
181
  end
169
182
  raise ArgumentError, "Please pass a document ID" unless id
170
183
 
171
- url = "#{self.url}/#{type}/#{id}"
184
+ routing = get_routing_from_document(document)
185
+
186
+ url = "#{self.url}/#{type}/#{id}"
187
+ url << "?routing=#{EscapeUtils.escape_url(routing)}" if routing
188
+
172
189
  result = Configuration.client.delete url
173
190
  MultiJson.decode(result.body) if result.success?
174
-
175
191
  ensure
176
192
  curl = %Q|curl -X DELETE "#{url}"|
177
193
  logged(id, curl)
178
194
  end
179
195
 
180
- def retrieve(type, id)
196
+ def retrieve(type, id, params = {})
181
197
  raise ArgumentError, "Please pass a document ID" unless id
182
198
 
183
- type = Utils.escape(type)
184
- url = "#{self.url}/#{type}/#{id}"
199
+ type = EscapeUtils.escape_url(type.to_s)
200
+ url = "#{self.url}/#{type}/#{id}"
201
+ url << "?#{params.to_param}" unless params.empty?
202
+
185
203
  @response = Configuration.client.get url
186
204
 
187
205
  h = MultiJson.decode(@response.body)
@@ -239,20 +257,22 @@ module Tire
239
257
  def register_percolator_query(name, options={}, &block)
240
258
  options[:query] = Search::Query.new(&block).to_hash if block_given?
241
259
 
242
- @response = Configuration.client.put "#{Configuration.url}/_percolator/#{@name}/#{name}", MultiJson.encode(options)
260
+ url = "#@percolator_url/#{name}"
261
+ @response = Configuration.client.put url, MultiJson.encode(options)
243
262
  MultiJson.decode(@response.body)['ok']
244
263
 
245
264
  ensure
246
- curl = %Q|curl -X PUT "#{Configuration.url}/_percolator/#{@name}/?pretty=1" -d '#{MultiJson.encode(options)}'|
265
+ curl = %Q|curl -X PUT "#{url}?pretty=true" -d '#{MultiJson.encode(options)}'|
247
266
  logged('_percolator', curl)
248
267
  end
249
268
 
250
269
  def unregister_percolator_query(name)
251
- @response = Configuration.client.delete "#{Configuration.url}/_percolator/#{@name}/#{name}"
270
+ url = "#@percolator_url/#{name}"
271
+ @response = Configuration.client.delete url
252
272
  MultiJson.decode(@response.body)['ok']
253
273
 
254
274
  ensure
255
- curl = %Q|curl -X DELETE "#{Configuration.url}/_percolator/#{@name}"|
275
+ curl = %Q|curl -X DELETE "#{url}"|
256
276
  logged('_percolator', curl)
257
277
  end
258
278
 
@@ -302,10 +322,10 @@ module Tire
302
322
 
303
323
  old_verbose, $VERBOSE = $VERBOSE, nil # Silence Object#type deprecation warnings
304
324
  type = case
325
+ when document.is_a?(Hash)
326
+ document.delete(:_type) || document.delete('_type') || document[:type] || document['type']
305
327
  when document.respond_to?(:document_type)
306
328
  document.document_type
307
- when document.is_a?(Hash)
308
- document[:_type] || document['_type'] || document[:type] || document['type']
309
329
  when document.respond_to?(:_type)
310
330
  document._type
311
331
  when document.respond_to?(:type) && document.type != document.class
@@ -313,15 +333,15 @@ module Tire
313
333
  end
314
334
  $VERBOSE = old_verbose
315
335
 
316
- type ||= 'document'
317
- options[:escape] ? Utils.escape(type) : type
336
+ type = type ? type.to_s : 'document'
337
+ options[:escape] ? EscapeUtils.escape_url(type) : type
318
338
  end
319
339
 
320
340
  def get_id_from_document(document)
321
341
  old_verbose, $VERBOSE = $VERBOSE, nil # Silence Object#id deprecation warnings
322
342
  id = case
323
343
  when document.is_a?(Hash)
324
- document[:_id] || document['_id'] || document[:id] || document['id']
344
+ document.delete(:_id) || document.delete('_id') || document[:id] || document['id']
325
345
  when document.respond_to?(:id) && document.id != document.object_id
326
346
  document.id
327
347
  end
@@ -329,6 +349,28 @@ module Tire
329
349
  id
330
350
  end
331
351
 
352
+ def get_routing_from_document(document)
353
+ case
354
+ when document.is_a?(Hash)
355
+ document.delete(:_routing) || document.delete('_routing')
356
+ when document.respond_to?(:routing)
357
+ document.routing
358
+ when document.respond_to?(:_routing)
359
+ document._routing
360
+ end
361
+ end
362
+
363
+ def get_parent_from_document(document)
364
+ case
365
+ when document.is_a?(Hash)
366
+ document.delete(:_parent) || document.delete('_parent')
367
+ when document.respond_to?(:parent)
368
+ document.parent
369
+ when document.respond_to?(:_parent)
370
+ document._parent
371
+ end
372
+ end
373
+
332
374
  def convert_document_to_json(document)
333
375
  document = case
334
376
  when document.is_a?(String)
@@ -18,49 +18,24 @@ module Tire
18
18
 
19
19
  def results
20
20
  @results ||= begin
21
- hits = @response['hits']['hits'].map { |d| d.update '_type' => Utils.unescape(d['_type']) }
21
+ hits = @response['hits']['hits'].map { |d| d.update '_type' => EscapeUtils.unescape_url(d['_type']) }
22
22
 
23
- unless @options[:load]
24
- if @wrapper == Hash
25
- hits
26
- else
27
- hits.map do |h|
28
- document = {}
23
+ if @wrapper == Hash
24
+ hits
25
+ else
26
+ hits.map do |h|
27
+ document = {}
29
28
 
30
- # Update the document with content and ID
31
- document = h['_source'] ? document.update( h['_source'] || {} ) : document.update( __parse_fields__(h['fields']) )
32
- document.update( {'id' => h['_id']} )
29
+ # Update the document with content and ID
30
+ document = h['_source'] ? document.update( h['_source'] || {} ) : document.update( __parse_fields__(h['fields']) )
31
+ document.update( {'id' => h['_id']} )
33
32
 
34
- # Update the document with meta information
35
- ['_score', '_type', '_index', '_version', 'sort', 'highlight', '_explanation'].each { |key| document.update( {key => h[key]} || {} ) }
33
+ # Update the document with meta information
34
+ ['_score', '_type', '_index', '_version', 'sort', 'highlight', '_explanation'].each { |key| document.update( {key => h[key]} || {} ) }
36
35
 
37
- # Return an instance of the "wrapper" class
38
- @wrapper.new(document)
39
- end
36
+ # Return an instance of the "wrapper" class
37
+ @wrapper.new(document)
40
38
  end
41
-
42
- else
43
- return [] if hits.empty?
44
-
45
- records = {}
46
- @response['hits']['hits'].group_by { |item| item['_type'] }.each do |type, items|
47
- raise NoMethodError, "You have tried to eager load the model instances, " +
48
- "but Tire cannot find the model class because " +
49
- "document has no _type property." unless type
50
-
51
- begin
52
- klass = type.camelize.constantize
53
- rescue NameError => e
54
- raise NameError, "You have tried to eager load the model instances, but " +
55
- "Tire cannot find the model class '#{type.camelize}' " +
56
- "based on _type '#{type}'.", e.backtrace
57
- end
58
- ids = items.map { |h| h['_id'] }
59
- records[type] = @options[:load] === true ? klass.find(ids) : klass.find(ids, @options[:load])
60
- end
61
-
62
- # Reorder records to preserve order from search results
63
- @response['hits']['hits'].map { |item| records[item['_type']].detect { |record| record.id.to_s == item['_id'].to_s } }
64
39
  end
65
40
  end
66
41
  end
@@ -2,9 +2,6 @@ module Tire
2
2
  module Results
3
3
 
4
4
  class Item
5
- #extend ActiveModel::Naming
6
- #include ActiveModel::Conversion
7
-
8
5
  # Create new instance, recursively converting all Hashes to Item
9
6
  # and leaving everything else alone.
10
7
  #
@@ -43,14 +40,6 @@ module Tire
43
40
  !!id
44
41
  end
45
42
 
46
- def errors
47
- ActiveModel::Errors.new(self)
48
- end
49
-
50
- def valid?
51
- true
52
- end
53
-
54
43
  def to_key
55
44
  persisted? ? [id] : nil
56
45
  end
@@ -59,14 +48,6 @@ module Tire
59
48
  @attributes
60
49
  end
61
50
 
62
- # Let's pretend we're someone else in Rails
63
- #
64
- def class
65
- defined?(::Rails) && @attributes[:_type] ? @attributes[:_type].camelize.constantize : super
66
- rescue NameError
67
- super
68
- end
69
-
70
51
  def inspect
71
52
  s = []; @attributes.each { |k,v| s << "#{k}: #{v.inspect}" }
72
53
  %Q|<Item#{self.class.to_s == 'Tire::Results::Item' ? '' : " (#{self.class})"} #{s.join(', ')}>|
@@ -0,0 +1,21 @@
1
+ require 'time'
2
+
3
+ class Array
4
+ def to_json(options=nil)
5
+ MultiJson.encode(self)
6
+ end unless method_defined? :to_json
7
+ end
8
+
9
+ class Hash
10
+ def to_json(options=nil)
11
+ MultiJson.encode(self)
12
+ end unless method_defined? :to_json
13
+
14
+ alias_method :to_indexed_json, :to_json
15
+ end
16
+
17
+ class Time
18
+ def to_json(options=nil)
19
+ %Q/"#{self.iso8601}"/
20
+ end
21
+ end