ssickles-tire 0.4.2 → 0.4.2.7

Sign up to get free protection for your applications and to get access to all the features.
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