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.
- data/lib/tire.rb +3 -18
- data/lib/tire/alias.rb +35 -11
- data/lib/tire/index.rb +76 -34
- data/lib/tire/results/collection.rb +13 -38
- data/lib/tire/results/item.rb +0 -19
- data/lib/tire/rubyext/to_json.rb +21 -0
- data/lib/tire/search.rb +8 -7
- data/lib/tire/search/scan.rb +8 -8
- data/lib/tire/search/sort.rb +1 -1
- data/lib/tire/version.rb +38 -7
- data/test/integration/reindex_test.rb +2 -2
- data/test/integration/scan_test.rb +1 -1
- data/test/test_helper.rb +3 -27
- data/test/unit/index_alias_test.rb +17 -3
- data/test/unit/index_test.rb +18 -30
- data/test/unit/results_collection_test.rb +0 -60
- data/test/unit/results_item_test.rb +0 -37
- data/test/unit/rubyext_test.rb +3 -3
- data/test/unit/search_test.rb +6 -1
- data/test/unit/tire_test.rb +0 -15
- data/tire.gemspec +13 -30
- metadata +41 -153
- data/lib/tire/model/callbacks.rb +0 -40
- data/lib/tire/model/import.rb +0 -26
- data/lib/tire/model/indexing.rb +0 -128
- data/lib/tire/model/naming.rb +0 -100
- data/lib/tire/model/percolate.rb +0 -99
- data/lib/tire/model/persistence.rb +0 -72
- data/lib/tire/model/persistence/attributes.rb +0 -143
- data/lib/tire/model/persistence/finders.rb +0 -66
- data/lib/tire/model/persistence/storage.rb +0 -71
- data/lib/tire/model/search.rb +0 -305
- data/lib/tire/rubyext/hash.rb +0 -8
- data/lib/tire/rubyext/ruby_1_8.rb +0 -54
- data/lib/tire/rubyext/symbol.rb +0 -11
- data/lib/tire/utils.rb +0 -17
- data/test/integration/active_model_indexing_test.rb +0 -51
- data/test/integration/active_model_searchable_test.rb +0 -114
- data/test/integration/active_record_searchable_test.rb +0 -446
- data/test/integration/mongoid_searchable_test.rb +0 -309
- data/test/integration/persistent_model_test.rb +0 -117
- data/test/models/active_model_article.rb +0 -31
- data/test/models/active_model_article_with_callbacks.rb +0 -49
- data/test/models/active_model_article_with_custom_document_type.rb +0 -7
- data/test/models/active_model_article_with_custom_index_name.rb +0 -7
- data/test/models/active_record_models.rb +0 -122
- data/test/models/mongoid_models.rb +0 -97
- data/test/models/persistent_article.rb +0 -11
- data/test/models/persistent_article_in_namespace.rb +0 -12
- data/test/models/persistent_article_with_casting.rb +0 -28
- data/test/models/persistent_article_with_defaults.rb +0 -11
- data/test/models/persistent_articles_with_custom_index_name.rb +0 -10
- data/test/models/supermodel_article.rb +0 -17
- data/test/models/validated_model.rb +0 -11
- data/test/unit/active_model_lint_test.rb +0 -17
- data/test/unit/model_callbacks_test.rb +0 -116
- data/test/unit/model_import_test.rb +0 -71
- data/test/unit/model_persistence_test.rb +0 -516
- data/test/unit/model_search_test.rb +0 -899
data/lib/tire.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/tire/alias.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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,
|
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 "#{
|
120
|
+
Alias.new.logged '_aliases', %Q|curl "#{url}/_aliases"|
|
112
121
|
end
|
113
122
|
|
114
123
|
# Returns an alias by name
|
115
124
|
#
|
116
|
-
|
117
|
-
|
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 "#{
|
186
|
+
@response = Configuration.client.post "#{url}/_aliases", to_json
|
163
187
|
|
164
188
|
ensure
|
165
|
-
logged '_aliases', %Q|curl -X POST "#{
|
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
|
214
|
+
MultiJson.encode(as_json)
|
191
215
|
end
|
192
216
|
|
193
217
|
def inspect
|
data/lib/tire/index.rb
CHANGED
@@ -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
|
-
|
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,
|
67
|
-
|
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
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
84
|
+
params ||= {}
|
85
|
+
params[:routing] = routing if routing
|
86
|
+
params[:parent] = parent if parent
|
87
|
+
params[:percolate] = '*' if params[:percolate] === true
|
73
88
|
|
74
|
-
|
75
|
-
|
89
|
+
url = id ? "#{self.url}/#{type}/#{id}" : "#{self.url}/#{type}"
|
90
|
+
url << "?#{params.to_param}" unless params.empty?
|
76
91
|
|
77
|
-
|
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 =
|
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
|
-
|
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
|
184
|
-
url
|
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
|
-
|
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 "#{
|
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
|
-
|
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 "#{
|
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
|
317
|
-
options[:escape] ?
|
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
|
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' =>
|
21
|
+
hits = @response['hits']['hits'].map { |d| d.update '_type' => EscapeUtils.unescape_url(d['_type']) }
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
document = {}
|
23
|
+
if @wrapper == Hash
|
24
|
+
hits
|
25
|
+
else
|
26
|
+
hits.map do |h|
|
27
|
+
document = {}
|
29
28
|
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
-
|
35
|
-
|
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
|
-
|
38
|
-
|
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
|
data/lib/tire/results/item.rb
CHANGED
@@ -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
|