chewy 0.4.1 → 0.5.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +3 -3
- data/CHANGELOG.md +43 -1
- data/Gemfile +3 -0
- data/README.md +49 -11
- data/chewy.gemspec +1 -2
- data/gemfiles/Gemfile.rails-3.2 +1 -0
- data/gemfiles/Gemfile.rails-4.0 +1 -0
- data/lib/chewy.rb +8 -2
- data/lib/chewy/backports/deep_dup.rb +46 -0
- data/lib/chewy/backports/duplicable.rb +90 -0
- data/lib/chewy/config.rb +33 -6
- data/lib/chewy/errors.rb +1 -1
- data/lib/chewy/fields/base.rb +19 -7
- data/lib/chewy/fields/root.rb +13 -0
- data/lib/chewy/index/actions.rb +14 -6
- data/lib/chewy/index/search.rb +3 -2
- data/lib/chewy/query.rb +131 -17
- data/lib/chewy/query/compose.rb +27 -17
- data/lib/chewy/query/criteria.rb +34 -22
- data/lib/chewy/query/loading.rb +94 -10
- data/lib/chewy/query/nodes/exists.rb +1 -1
- data/lib/chewy/query/nodes/has_relation.rb +1 -1
- data/lib/chewy/query/nodes/missing.rb +1 -1
- data/lib/chewy/query/pagination.rb +8 -38
- data/lib/chewy/query/pagination/kaminari.rb +37 -0
- data/lib/chewy/runtime.rb +9 -0
- data/lib/chewy/runtime/version.rb +25 -0
- data/lib/chewy/type/adapter/active_record.rb +21 -7
- data/lib/chewy/type/adapter/base.rb +1 -1
- data/lib/chewy/type/adapter/object.rb +9 -6
- data/lib/chewy/type/import.rb +7 -4
- data/lib/chewy/type/mapping.rb +9 -9
- data/lib/chewy/type/wrapper.rb +1 -1
- data/lib/chewy/version.rb +1 -1
- data/lib/tasks/chewy.rake +40 -21
- data/spec/chewy/config_spec.rb +1 -1
- data/spec/chewy/fields/base_spec.rb +273 -8
- data/spec/chewy/index/actions_spec.rb +1 -2
- data/spec/chewy/index/aliases_spec.rb +0 -1
- data/spec/chewy/index/search_spec.rb +0 -8
- data/spec/chewy/index/settings_spec.rb +0 -2
- data/spec/chewy/index_spec.rb +0 -2
- data/spec/chewy/query/criteria_spec.rb +85 -18
- data/spec/chewy/query/loading_spec.rb +26 -9
- data/spec/chewy/query/nodes/and_spec.rb +2 -2
- data/spec/chewy/query/nodes/exists_spec.rb +6 -6
- data/spec/chewy/query/nodes/missing_spec.rb +4 -4
- data/spec/chewy/query/nodes/or_spec.rb +2 -2
- data/spec/chewy/query/pagination/kaminari_spec.rb +55 -0
- data/spec/chewy/query/pagination_spec.rb +15 -22
- data/spec/chewy/query_spec.rb +121 -52
- data/spec/chewy/rspec/update_index_spec.rb +0 -1
- data/spec/chewy/runtime/version_spec.rb +48 -0
- data/spec/chewy/runtime_spec.rb +9 -0
- data/spec/chewy/type/adapter/active_record_spec.rb +52 -0
- data/spec/chewy/type/adapter/object_spec.rb +33 -0
- data/spec/chewy/type/import_spec.rb +1 -3
- data/spec/chewy/type/mapping_spec.rb +4 -6
- data/spec/chewy/type/observe_spec.rb +0 -2
- data/spec/chewy/type/wrapper_spec.rb +0 -2
- data/spec/chewy/type_spec.rb +26 -5
- data/spec/chewy_spec.rb +0 -2
- data/spec/spec_helper.rb +2 -2
- metadata +15 -21
- data/lib/chewy/fields/default.rb +0 -10
- data/spec/chewy/fields/default_spec.rb +0 -6
data/lib/chewy/type/wrapper.rb
CHANGED
data/lib/chewy/version.rb
CHANGED
data/lib/tasks/chewy.rake
CHANGED
@@ -12,49 +12,68 @@ def subscribe_task_stats!
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
+
def eager_load_chewy!
|
16
|
+
Rails.application.config.paths['app/chewy'].existent.each do |dir|
|
17
|
+
Dir.glob(File.join(dir, '**/*.rb')).each { |file| require file }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def normalize_index index
|
22
|
+
"#{index.to_s.gsub(/index$/i, '').camelize}Index".constantize
|
23
|
+
end
|
24
|
+
|
25
|
+
def reset_index index
|
26
|
+
index = normalize_index(index)
|
27
|
+
puts "Resetting #{index}"
|
28
|
+
index.reset! (Time.now.to_f * 1000).round
|
29
|
+
end
|
30
|
+
|
31
|
+
def reset_all
|
32
|
+
eager_load_chewy!
|
33
|
+
Chewy::Index.descendants.each { |index| reset_index index }
|
34
|
+
end
|
35
|
+
|
36
|
+
def update_index index
|
37
|
+
index = normalize_index(index)
|
38
|
+
puts "Updating #{index}"
|
39
|
+
if index.exists?
|
40
|
+
index.import
|
41
|
+
else
|
42
|
+
puts "Index `#{index.index_name}` does not exists. Use rake chewy:reset[#{index.index_name}] to create and update it."
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def update_all
|
47
|
+
eager_load_chewy!
|
48
|
+
Chewy::Index.descendants.each { |index| update_index index }
|
49
|
+
end
|
50
|
+
|
15
51
|
namespace :chewy do
|
16
52
|
desc 'Destroy, recreate and import data to specified index'
|
17
53
|
task :reset, [:index] => :environment do |task, args|
|
18
54
|
subscribe_task_stats!
|
19
|
-
|
55
|
+
args[:index].present? ? reset_index(args[:index]) : reset_all
|
20
56
|
end
|
21
57
|
|
22
58
|
namespace :reset do
|
23
59
|
desc 'Destroy, recreate and import data for all found indexes'
|
24
60
|
task all: :environment do
|
25
61
|
subscribe_task_stats!
|
26
|
-
|
27
|
-
Dir.glob(File.join(dir, '**/*.rb')).each { |file| require file }
|
28
|
-
end
|
29
|
-
|
30
|
-
Chewy::Index.descendants.each do |index|
|
31
|
-
puts "Resetting #{index}"
|
32
|
-
index.reset! (Time.now.to_f * 1000).round
|
33
|
-
end
|
62
|
+
reset_all
|
34
63
|
end
|
35
64
|
end
|
36
65
|
|
37
66
|
desc 'Updates data specified index'
|
38
67
|
task :update, [:index] => :environment do |task, args|
|
39
68
|
subscribe_task_stats!
|
40
|
-
index
|
41
|
-
raise "Index `#{index.index_name}` does not exists. Use rake chewy:reset[#{index.index_name}] to create and update it." unless index.exists?
|
42
|
-
index.import
|
69
|
+
args[:index].present? ? update_index(args[:index]) : update_all
|
43
70
|
end
|
44
71
|
|
45
72
|
namespace :update do
|
46
73
|
desc 'Updates data for all found indexes'
|
47
74
|
task all: :environment do
|
48
75
|
subscribe_task_stats!
|
49
|
-
|
50
|
-
Dir.glob(File.join(dir, '**/*.rb')).each { |file| require file }
|
51
|
-
end
|
52
|
-
|
53
|
-
Chewy::Index.descendants.each do |index|
|
54
|
-
puts "Updating #{index}"
|
55
|
-
puts "Index `#{index.index_name}` does not exists. Use rake chewy:reset[#{index.index_name}] to create and update it." unless index.exists?
|
56
|
-
index.import
|
57
|
-
end
|
76
|
+
update_all
|
58
77
|
end
|
59
78
|
end
|
60
79
|
end
|
data/spec/chewy/config_spec.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Chewy::Config do
|
4
|
-
include ClassHelpers
|
5
4
|
subject { described_class.send(:new) }
|
6
5
|
|
7
6
|
its(:query_mode) { should == :must }
|
8
7
|
its(:filter_mode) { should == :and }
|
8
|
+
its(:post_filter_mode) { should be_nil }
|
9
9
|
its(:logger) { should be_nil }
|
10
10
|
its(:configuration) { should_not have_key :logger }
|
11
11
|
its(:analyzers) { should == {} }
|
@@ -31,7 +31,7 @@ describe Chewy::Fields::Base do
|
|
31
31
|
end
|
32
32
|
|
33
33
|
context do
|
34
|
-
let(:field) { described_class.new(:name, type: '
|
34
|
+
let(:field) { described_class.new(:name, type: 'string') }
|
35
35
|
before do
|
36
36
|
field.nested(described_class.new(:name))
|
37
37
|
field.nested(described_class.new(:untouched))
|
@@ -61,7 +61,7 @@ describe Chewy::Fields::Base do
|
|
61
61
|
end
|
62
62
|
|
63
63
|
describe '#mappings_hash' do
|
64
|
-
let(:field) { described_class.new(:name, type:
|
64
|
+
let(:field) { described_class.new(:name, type: :object) }
|
65
65
|
let(:fields1) { 2.times.map { |i| described_class.new("name#{i+1}", type: "string#{i+1}") } }
|
66
66
|
let(:fields2) { 2.times.map { |i| described_class.new("name#{i+3}", type: "string#{i+3}") } }
|
67
67
|
before do
|
@@ -69,20 +69,285 @@ describe Chewy::Fields::Base do
|
|
69
69
|
fields2.each { |m| fields1[0].nested(m) }
|
70
70
|
end
|
71
71
|
|
72
|
-
specify { field.mappings_hash.should == {name: {type:
|
73
|
-
name1: {type: 'string1',
|
72
|
+
specify { field.mappings_hash.should == {name: {type: :object, properties: {
|
73
|
+
name1: {type: 'string1', fields: {
|
74
74
|
name3: {type: 'string3'}, name4: {type: 'string4'}
|
75
75
|
}}, name2: {type: 'string2'}
|
76
76
|
}}} }
|
77
77
|
|
78
78
|
context do
|
79
|
-
let(:field) { described_class.new(:name, type:
|
79
|
+
let(:field) { described_class.new(:name, type: :string) }
|
80
|
+
let(:fields1) { 2.times.map { |i| described_class.new("name#{i+1}") } }
|
80
81
|
|
81
|
-
specify { field.mappings_hash.should == {name: {type:
|
82
|
-
name1: {type: '
|
82
|
+
specify { field.mappings_hash.should == {name: {type: :string, fields: {
|
83
|
+
name1: {type: 'object', properties: {
|
83
84
|
name3: {type: 'string3'}, name4: {type: 'string4'}
|
84
|
-
}}, name2: {type: '
|
85
|
+
}}, name2: {type: 'string'}
|
85
86
|
}}} }
|
86
87
|
end
|
87
88
|
end
|
89
|
+
|
90
|
+
context 'integration' do
|
91
|
+
context 'objects, hashes and arrays' do
|
92
|
+
before do
|
93
|
+
stub_index(:events) do
|
94
|
+
define_type :event do
|
95
|
+
field :id
|
96
|
+
field :category do
|
97
|
+
field :id
|
98
|
+
field :licenses do
|
99
|
+
field :id
|
100
|
+
field :name
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
specify do
|
108
|
+
EventsIndex::Event.mappings_hash.should == { event: {
|
109
|
+
properties: {
|
110
|
+
id: { type: 'string' },
|
111
|
+
category: {
|
112
|
+
type: 'object',
|
113
|
+
properties: {
|
114
|
+
id: { type: 'string' },
|
115
|
+
licenses: {
|
116
|
+
type: 'object',
|
117
|
+
properties: {
|
118
|
+
id: { type: 'string' },
|
119
|
+
name: { type: 'string' } } } } } } } }
|
120
|
+
end
|
121
|
+
|
122
|
+
specify do
|
123
|
+
EventsIndex::Event.root_object.compose(
|
124
|
+
id: 1, category: { id: 2, licenses: { id: 3, name: 'Name' } }
|
125
|
+
).should == {
|
126
|
+
event: { 'id' => 1, 'category' => { 'id' => 2, 'licenses' => {'id' => 3, 'name' => 'Name'}}}
|
127
|
+
}
|
128
|
+
end
|
129
|
+
|
130
|
+
specify do
|
131
|
+
EventsIndex::Event.root_object.compose(id: 1, category: [
|
132
|
+
{ id: 2, 'licenses' => { id: 3, name: 'Name1' } },
|
133
|
+
{ id: 4, licenses: nil}
|
134
|
+
]).should == {
|
135
|
+
event: { 'id' => 1, 'category' => [
|
136
|
+
{ 'id' => 2, 'licenses' => { 'id' => 3, 'name' => 'Name1' } },
|
137
|
+
{'id' => 4, 'licenses' => nil }
|
138
|
+
] }
|
139
|
+
}
|
140
|
+
end
|
141
|
+
|
142
|
+
specify do
|
143
|
+
EventsIndex::Event.root_object.compose('id' => 1, category: { id: 2, licenses: [
|
144
|
+
{ id: 3, name: 'Name1' }, { id: 4, name: 'Name2' }
|
145
|
+
] }).should == {
|
146
|
+
event: { 'id' => 1, 'category' => { 'id' => 2, 'licenses' => [
|
147
|
+
{'id' => 3, 'name' => 'Name1'}, {'id' => 4, 'name' => 'Name2'}
|
148
|
+
] } }
|
149
|
+
}
|
150
|
+
end
|
151
|
+
|
152
|
+
specify do
|
153
|
+
EventsIndex::Event.root_object.compose(id: 1, category: [
|
154
|
+
{ id: 2, licenses: [
|
155
|
+
{ id: 3, 'name' => 'Name1' }, { id: 4, name: 'Name2' }
|
156
|
+
] },
|
157
|
+
{ id: 5, licenses: [] }
|
158
|
+
]).should == {
|
159
|
+
event: { 'id' => 1, 'category' => [
|
160
|
+
{ 'id' => 2, 'licenses' => [
|
161
|
+
{ 'id' => 3, 'name' => 'Name1' }, { 'id' => 4, 'name' => 'Name2' }
|
162
|
+
] },
|
163
|
+
{'id' => 5, 'licenses' => [] }
|
164
|
+
] }
|
165
|
+
}
|
166
|
+
end
|
167
|
+
|
168
|
+
specify do
|
169
|
+
EventsIndex::Event.root_object.compose(
|
170
|
+
double(id: 1, category: double(id: 2, licenses: double(id: 3, name: 'Name')))
|
171
|
+
).should == {
|
172
|
+
event: { 'id' => 1, 'category' => { 'id' => 2, 'licenses' => {'id' => 3, 'name' => 'Name'}}}
|
173
|
+
}
|
174
|
+
end
|
175
|
+
|
176
|
+
specify do
|
177
|
+
EventsIndex::Event.root_object.compose(double(id: 1, category: [
|
178
|
+
double(id: 2, licenses: double(id: 3, name: 'Name1')),
|
179
|
+
double(id: 4, licenses: nil)
|
180
|
+
])).should == {
|
181
|
+
event: { 'id' => 1, 'category' => [
|
182
|
+
{ 'id' => 2, 'licenses' => { 'id' => 3, 'name' => 'Name1' } },
|
183
|
+
{'id' => 4, 'licenses' => nil }
|
184
|
+
] }
|
185
|
+
}
|
186
|
+
end
|
187
|
+
|
188
|
+
specify do
|
189
|
+
EventsIndex::Event.root_object.compose(double(id: 1, category: double(id: 2, licenses: [
|
190
|
+
double(id: 3, name: 'Name1'), double(id: 4, name: 'Name2')
|
191
|
+
]))).should == {
|
192
|
+
event: { 'id' => 1, 'category' => { 'id' => 2, 'licenses' => [
|
193
|
+
{'id' => 3, 'name' => 'Name1'}, {'id' => 4, 'name' => 'Name2'}
|
194
|
+
] } }
|
195
|
+
}
|
196
|
+
end
|
197
|
+
|
198
|
+
specify do
|
199
|
+
EventsIndex::Event.root_object.compose(double(id: 1, category: [
|
200
|
+
double(id: 2, licenses: [
|
201
|
+
double(id: 3, name: 'Name1'), double(id: 4, name: 'Name2')
|
202
|
+
]),
|
203
|
+
double(id: 5, licenses: [])
|
204
|
+
])).should == {
|
205
|
+
event: { 'id' => 1, 'category' => [
|
206
|
+
{ 'id' => 2, 'licenses' => [
|
207
|
+
{ 'id' => 3, 'name' => 'Name1' }, { 'id' => 4, 'name' => 'Name2' }
|
208
|
+
] },
|
209
|
+
{'id' => 5, 'licenses' => [] }
|
210
|
+
] }
|
211
|
+
}
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
context 'custom methods' do
|
216
|
+
before do
|
217
|
+
stub_index(:events) do
|
218
|
+
define_type :event do
|
219
|
+
field :id
|
220
|
+
field :category, value: ->{ categories } do
|
221
|
+
field :id
|
222
|
+
field :licenses, value: ->{ license } do
|
223
|
+
field :id
|
224
|
+
field :name
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
specify do
|
232
|
+
EventsIndex::Event.root_object.compose(
|
233
|
+
double(id: 1, categories: double(id: 2, license: double(id: 3, name: 'Name')))
|
234
|
+
).should == {
|
235
|
+
event: { 'id' => 1, 'category' => { 'id' => 2, 'licenses' => {'id' => 3, 'name' => 'Name'}}}
|
236
|
+
}
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
context 'objects and multi_fields' do
|
241
|
+
before do
|
242
|
+
stub_index(:events) do
|
243
|
+
define_type :event do
|
244
|
+
field :id
|
245
|
+
field :name, type: 'string' do
|
246
|
+
field :raw, analyzer: 'my_own'
|
247
|
+
end
|
248
|
+
field :category, type: 'object'
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
specify do
|
254
|
+
EventsIndex::Event.mappings_hash.should == { event: {
|
255
|
+
properties: {
|
256
|
+
id: { type: 'string' },
|
257
|
+
name: {
|
258
|
+
type: 'string',
|
259
|
+
fields: {
|
260
|
+
raw: { analyzer: 'my_own', type: 'string' }
|
261
|
+
}
|
262
|
+
},
|
263
|
+
category: { type: 'object' }
|
264
|
+
}
|
265
|
+
} }
|
266
|
+
end
|
267
|
+
|
268
|
+
specify do
|
269
|
+
EventsIndex::Event.root_object.compose(
|
270
|
+
double(id: 1, name: 'Jonny', category: double(id: 2, as_json: {name: 'Borogoves'}))
|
271
|
+
).should == {
|
272
|
+
event: {
|
273
|
+
'id' => 1,
|
274
|
+
'name' => 'Jonny',
|
275
|
+
'category' => { 'name' => 'Borogoves' }
|
276
|
+
}
|
277
|
+
}
|
278
|
+
end
|
279
|
+
|
280
|
+
specify do
|
281
|
+
EventsIndex::Event.root_object.compose(
|
282
|
+
double(id: 1, name: 'Jonny', category: [
|
283
|
+
double(id: 2, as_json: { name: 'Borogoves1' }),
|
284
|
+
double(id: 3, as_json: { name: 'Borogoves2' })
|
285
|
+
])
|
286
|
+
).should == {
|
287
|
+
event: {
|
288
|
+
'id' => 1,
|
289
|
+
'name' => 'Jonny',
|
290
|
+
'category' => [
|
291
|
+
{ 'name' => 'Borogoves1' },
|
292
|
+
{ 'name' => 'Borogoves2' }
|
293
|
+
]
|
294
|
+
}
|
295
|
+
}
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
context 'objects and scopes' do
|
300
|
+
before do
|
301
|
+
stub_model(:city) do
|
302
|
+
belongs_to :country
|
303
|
+
end
|
304
|
+
|
305
|
+
stub_model(:country) do
|
306
|
+
has_many :cities
|
307
|
+
end
|
308
|
+
|
309
|
+
stub_index(:countries) do
|
310
|
+
define_type Country do
|
311
|
+
field :id
|
312
|
+
field :cities do
|
313
|
+
field :id
|
314
|
+
field :name
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
specify do
|
321
|
+
CountriesIndex::Country.root_object.compose(
|
322
|
+
Country.create!(cities: [City.create!(name: 'City1'), City.create!(name: 'City2')])
|
323
|
+
).should == {
|
324
|
+
country: { 'id' => 1, 'cities' => [
|
325
|
+
{ 'id' => 1, 'name' => 'City1' }, { 'id' => 2, 'name' => 'City2' }
|
326
|
+
] }
|
327
|
+
}
|
328
|
+
end
|
329
|
+
|
330
|
+
context 'nested object' do
|
331
|
+
before do
|
332
|
+
stub_index(:cities) do
|
333
|
+
define_type City do
|
334
|
+
field :id
|
335
|
+
field :country do
|
336
|
+
field :id
|
337
|
+
field :name
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
specify do
|
344
|
+
CitiesIndex::City.root_object.compose(
|
345
|
+
City.create!(country: Country.create!(name: 'Country'))
|
346
|
+
).should == {
|
347
|
+
city: { 'id' => 1, 'country' => { 'id' => 1, 'name' => 'Country' } }
|
348
|
+
}
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
88
353
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Chewy::Index::Actions do
|
4
|
-
include ClassHelpers
|
5
4
|
before { Chewy.client.indices.delete index: '*' }
|
6
5
|
|
7
6
|
before { stub_index :dummies }
|
@@ -311,7 +310,7 @@ describe Chewy::Index::Actions do
|
|
311
310
|
end
|
312
311
|
end
|
313
312
|
|
314
|
-
specify { expect { CitiesIndex.import!(city: dummy_cities) }.to raise_error Chewy::
|
313
|
+
specify { expect { CitiesIndex.import!(city: dummy_cities) }.to raise_error Chewy::ImportFailed }
|
315
314
|
end
|
316
315
|
end
|
317
316
|
|