chewy 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/.travis.yml +5 -1
- data/CHANGELOG.md +21 -1
- data/README.md +12 -60
- data/chewy.gemspec +1 -1
- data/gemfiles/Gemfile.rails-3.2 +14 -0
- data/gemfiles/Gemfile.rails-4.0 +14 -0
- data/lib/chewy.rb +5 -0
- data/lib/chewy/fields/base.rb +2 -2
- data/lib/chewy/fields/root.rb +33 -0
- data/lib/chewy/index/actions.rb +6 -1
- data/lib/chewy/index/search.rb +1 -1
- data/lib/chewy/query.rb +30 -2
- data/lib/chewy/query/criteria.rb +10 -3
- data/lib/chewy/query/nodes/range.rb +2 -2
- data/lib/chewy/query/nodes/script.rb +1 -1
- data/lib/chewy/rspec/update_index.rb +95 -4
- data/lib/chewy/type/adapter/active_record.rb +16 -2
- data/lib/chewy/type/import.rb +6 -1
- data/lib/chewy/type/mapping.rb +129 -6
- data/lib/chewy/type/observe.rb +4 -2
- data/lib/chewy/version.rb +1 -1
- data/spec/chewy/fields/root_spec.rb +38 -0
- data/spec/chewy/index/actions_spec.rb +2 -2
- data/spec/chewy/query/criteria_spec.rb +11 -0
- data/spec/chewy/query/loading_spec.rb +2 -2
- data/spec/chewy/query/pagination_spec.rb +3 -2
- data/spec/chewy/query_spec.rb +72 -2
- data/spec/chewy/rspec/update_index_spec.rb +26 -0
- data/spec/chewy/type/adapter/active_record_spec.rb +86 -26
- data/spec/chewy/type/import_spec.rb +4 -4
- data/spec/spec_helper.rb +8 -1
- metadata +7 -5
@@ -1,14 +1,83 @@
|
|
1
|
+
require 'i18n/core_ext/hash'
|
2
|
+
|
3
|
+
# Rspec matcher `update_index`
|
4
|
+
# To use it - add `require 'chewy/rspec'` to the `spec_helper.rb`
|
5
|
+
# Simple usage - just pass type as argument.
|
6
|
+
#
|
7
|
+
# specify { expect { user.save! }.to update_index(UsersIndex::User) }
|
8
|
+
# specify { expect { user.save! }.to update_index('users#user') }
|
9
|
+
# specify { expect { user.save! }.not_to update_index('users#user') }
|
10
|
+
#
|
11
|
+
# This example will pass as well because user1 was reindexed
|
12
|
+
# and nothing was said about user2:
|
13
|
+
#
|
14
|
+
# specify { expect { [user1, user2].map(&:save!) }
|
15
|
+
# .to update_index(UsersIndex.user).and_reindex(user1) }
|
16
|
+
#
|
17
|
+
# If you need to specify reindexed records strictly - use `only` chain.
|
18
|
+
# Combined matcher chain methods:
|
19
|
+
#
|
20
|
+
# specify { expect { user1.destroy!; user2.save! } }
|
21
|
+
# .to update_index(UsersIndex:User).and_reindex(user2).and_delete(user1)
|
22
|
+
#
|
1
23
|
RSpec::Matchers.define :update_index do |type_name, options = {}|
|
24
|
+
|
25
|
+
# Specify indexed records by passing record itself or id.
|
26
|
+
#
|
27
|
+
# specify { expect { user.save! }.to update_index(UsersIndex::User).and_reindex(user)
|
28
|
+
# specify { expect { user.save! }.to update_index(UsersIndex::User).and_reindex(42)
|
29
|
+
# specify { expect { [user1, user2].map(&:save!) }
|
30
|
+
# .to update_index(UsersIndex::User).and_reindex(user1, user2) }
|
31
|
+
# specify { expect { [user1, user2].map(&:save!) }
|
32
|
+
# .to update_index(UsersIndex::User).and_reindex(user1).and_reindex(user2) }
|
33
|
+
#
|
34
|
+
# Specify indexing count for every particular record. Useful in case
|
35
|
+
# urgent index updates.
|
36
|
+
#
|
37
|
+
# specify { expect { 2.times { user.save! } }
|
38
|
+
# .to update_index(UsersIndex::User).and_reindex(user, times: 2) }
|
39
|
+
#
|
40
|
+
# Specify reindexed attributes. Note that arrays are
|
41
|
+
# compared position-independantly.
|
42
|
+
#
|
43
|
+
# specify { expect { user.update_attributes!(name: 'Duke') }
|
44
|
+
# .to update_index(UsersIndex.user).and_reindex(user, with: {name: 'Duke'}) }
|
45
|
+
#
|
46
|
+
# You can combine all the options and chain `and_reindex` method to
|
47
|
+
# specify options for every indexed record:
|
48
|
+
#
|
49
|
+
# specify { expect { 2.times { [user1, user2].map { |u| u.update_attributes!(name: "Duke#{u.id}") } } }
|
50
|
+
# .to update_index(UsersIndex.user)
|
51
|
+
# .and_reindex(user1, with: {name: 'Duke42'}) }
|
52
|
+
# .and_reindex(user2, times: 1, with: {name: 'Duke43'}) }
|
53
|
+
#
|
2
54
|
chain(:and_reindex) do |*args|
|
3
55
|
@reindex ||= {}
|
4
56
|
@reindex.merge!(extract_documents(*args))
|
5
57
|
end
|
6
58
|
|
59
|
+
# Specify deleted records with record itself or id passed.
|
60
|
+
#
|
61
|
+
# specify { expect { user.destroy! }.to update_index(UsersIndex::User).and_delete(user) }
|
62
|
+
# specify { expect { user.destroy! }.to update_index(UsersIndex::User).and_delete(user.id) }
|
63
|
+
#
|
7
64
|
chain(:and_delete) do |*args|
|
8
65
|
@delete ||= {}
|
9
66
|
@delete.merge!(extract_documents(*args))
|
10
67
|
end
|
11
68
|
|
69
|
+
# Used for specifying than no other records would be indexed or deleted:
|
70
|
+
#
|
71
|
+
# specify { expect { [user1, user2].map(&:save!) }
|
72
|
+
# .to update_index(UsersIndex.user).and_reindex(user1, user2).only }
|
73
|
+
# specify { expect { [user1, user2].map(&:destroy!) }
|
74
|
+
# .to update_index(UsersIndex.user).and_delete(user1, user2).only }
|
75
|
+
#
|
76
|
+
# This example will fail:
|
77
|
+
#
|
78
|
+
# specify { expect { [user1, user2].map(&:save!) }
|
79
|
+
# .to update_index(UsersIndex.user).and_reindex(user1).only }
|
80
|
+
#
|
12
81
|
chain(:only) do |*args|
|
13
82
|
@only = true
|
14
83
|
end
|
@@ -23,9 +92,8 @@ RSpec::Matchers.define :update_index do |type_name, options = {}|
|
|
23
92
|
updated = []
|
24
93
|
type.stub(:bulk) do |options|
|
25
94
|
updated += options[:body].map do |updated_document|
|
26
|
-
updated_document = updated_document.
|
95
|
+
updated_document = updated_document.deep_symbolize_keys
|
27
96
|
body = updated_document[:index] || updated_document[:delete]
|
28
|
-
body[:data] = body[:data].symbolize_keys if body[:data]
|
29
97
|
updated_document
|
30
98
|
end
|
31
99
|
{}
|
@@ -59,7 +127,7 @@ RSpec::Matchers.define :update_index do |type_name, options = {}|
|
|
59
127
|
document[:match_count] = (!document[:expected_count] && document[:real_count] > 0) ||
|
60
128
|
(document[:expected_count] && document[:expected_count] == document[:real_count])
|
61
129
|
document[:match_attributes] = document[:expected_attributes].blank? ||
|
62
|
-
|
130
|
+
compare_attributes(document[:expected_attributes], document[:real_attributes])
|
63
131
|
end
|
64
132
|
@delete.each do |_, document|
|
65
133
|
document[:match_count] = (!document[:expected_count] && document[:real_count] > 0) ||
|
@@ -123,7 +191,7 @@ RSpec::Matchers.define :update_index do |type_name, options = {}|
|
|
123
191
|
options = args.extract_options!
|
124
192
|
|
125
193
|
expected_count = options[:times] || options[:count]
|
126
|
-
expected_attributes = (options[:with] || options[:attributes] || {}).
|
194
|
+
expected_attributes = (options[:with] || options[:attributes] || {}).deep_symbolize_keys
|
127
195
|
|
128
196
|
Hash[args.flatten.map do |document|
|
129
197
|
id = document.respond_to?(:id) ? document.id.to_s : document.to_s
|
@@ -136,4 +204,27 @@ RSpec::Matchers.define :update_index do |type_name, options = {}|
|
|
136
204
|
}]
|
137
205
|
end]
|
138
206
|
end
|
207
|
+
|
208
|
+
def compare_attributes expected, real
|
209
|
+
expected.inject(true) do |result, (key, value)|
|
210
|
+
equal = if value.is_a?(Array) && real[key].is_a?(Array)
|
211
|
+
array_difference(value, real[key]) && array_difference(real[key], value)
|
212
|
+
elsif value.is_a?(Hash) && real[key].is_a?(Hash)
|
213
|
+
compare_attributes(value, real[key])
|
214
|
+
else
|
215
|
+
real[key] == value
|
216
|
+
end
|
217
|
+
result && equal
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def array_difference first, second
|
222
|
+
difference = first.to_ary.dup
|
223
|
+
second.to_ary.each do |element|
|
224
|
+
if index = difference.index(element)
|
225
|
+
difference.delete_at(index)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
difference.none?
|
229
|
+
end
|
139
230
|
end
|
@@ -36,6 +36,16 @@ module Chewy
|
|
36
36
|
#
|
37
37
|
# <tt>:batch_size</tt> - import batch size, 1000 objects by default
|
38
38
|
#
|
39
|
+
# Method handles destroyed objects as well. In case of objects AcriveRecord::Relation
|
40
|
+
# or array passed, objects, responding with true to `destroyed?` method will be deleted
|
41
|
+
# from index. In case of ids array passed - documents with missing records ids will be
|
42
|
+
# deleted from index:
|
43
|
+
#
|
44
|
+
# users = User.all
|
45
|
+
# users.each { |user| user.destroy if user.incative? }
|
46
|
+
# UsersIndex::User.import users # inactive users will be deleted from index
|
47
|
+
# UsersIndex::User.import users.map(&:id) # deleted user ids will be deleted from index
|
48
|
+
#
|
39
49
|
def import *args, &block
|
40
50
|
import_options = args.extract_options!
|
41
51
|
import_options[:batch_size] ||= BATCH_SIZE
|
@@ -65,7 +75,7 @@ module Chewy
|
|
65
75
|
|
66
76
|
additional_scope = load_options[load_options[:_type].type_name.to_sym].try(:[], :scope) || load_options[:scope]
|
67
77
|
|
68
|
-
scope =
|
78
|
+
scope = scoped_model(objects.map(&:id))
|
69
79
|
loaded_objects = if additional_scope.is_a?(Proc)
|
70
80
|
scope.instance_exec(&additional_scope)
|
71
81
|
elsif additional_scope.is_a?(::ActiveRecord::Relation)
|
@@ -85,7 +95,7 @@ module Chewy
|
|
85
95
|
ids = ids.map(&:to_i).uniq
|
86
96
|
|
87
97
|
indexed = true
|
88
|
-
merged_scope(
|
98
|
+
merged_scope(scoped_model(ids)).find_in_batches(import_options.slice(:batch_size)) do |objects|
|
89
99
|
ids -= objects.map(&:id)
|
90
100
|
indexed &= block.call index: objects
|
91
101
|
end
|
@@ -107,6 +117,10 @@ module Chewy
|
|
107
117
|
scope ? scope.clone.merge(target) : target
|
108
118
|
end
|
109
119
|
|
120
|
+
def scoped_model(ids)
|
121
|
+
model.where(Hash[model.primary_key.to_sym || :id, ids])
|
122
|
+
end
|
123
|
+
|
110
124
|
def model_all
|
111
125
|
::ActiveRecord::VERSION::MAJOR < 4 ? model.scoped : model.all
|
112
126
|
end
|
data/lib/chewy/type/import.rb
CHANGED
@@ -17,7 +17,9 @@ module Chewy
|
|
17
17
|
#
|
18
18
|
def import *args
|
19
19
|
import_options = args.extract_options!
|
20
|
-
bulk_options = import_options.
|
20
|
+
bulk_options = import_options.reject { |k, v| ![:refresh, :suffix].include?(k) }.reverse_merge!(refresh: true)
|
21
|
+
|
22
|
+
index.create!(bulk_options.slice(:suffix)) unless index.exists?
|
21
23
|
|
22
24
|
ActiveSupport::Notifications.instrument 'import_objects.chewy', type: self do |payload|
|
23
25
|
adapter.import(*args, import_options) do |action_objects|
|
@@ -57,6 +59,9 @@ module Chewy
|
|
57
59
|
# Adds `:suffix` option to bulk import to index with specified suffix.
|
58
60
|
def bulk options = {}
|
59
61
|
suffix = options.delete(:suffix)
|
62
|
+
|
63
|
+
Chewy.wait_for_status
|
64
|
+
|
60
65
|
result = client.bulk options.merge(index: index.build_index_name(suffix: suffix), type: type_name)
|
61
66
|
|
62
67
|
extract_errors result
|
data/lib/chewy/type/mapping.rb
CHANGED
@@ -5,17 +5,111 @@ module Chewy
|
|
5
5
|
|
6
6
|
included do
|
7
7
|
class_attribute :root_object, instance_reader: false, instance_writer: false
|
8
|
+
class_attribute :_templates
|
8
9
|
end
|
9
10
|
|
10
11
|
module ClassMethods
|
11
|
-
|
12
|
-
|
12
|
+
# Defines root object for mapping and is optional for type
|
13
|
+
# definition. Use it only if you need to pass options for root
|
14
|
+
# object mapping, such as `date_detection` or `dynamic_date_formats`
|
15
|
+
#
|
16
|
+
# class UsersIndex < Chewy::Index
|
17
|
+
# define_type User do
|
18
|
+
# # root object defined implicitly and optionless for current type
|
19
|
+
# field :full_name, type: 'string'
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# class CarsIndex < Chewy::Index
|
24
|
+
# define_type Car do
|
25
|
+
# # explicit root definition with additional options
|
26
|
+
# root dynamic_date_formats: ['yyyy-MM-dd'] do
|
27
|
+
# field :model_name, type: 'string'
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
def root options = {}, &block
|
33
|
+
raise "Root is already defined" if root_object
|
13
34
|
build_root(options, &block)
|
14
35
|
end
|
15
36
|
|
16
|
-
|
37
|
+
# Defines mapping field for current type
|
38
|
+
#
|
39
|
+
# class UsersIndex < Chewy::Index
|
40
|
+
# define_type User do
|
41
|
+
# # passing all the options to field definition:
|
42
|
+
# field :full_name, type: 'string', analyzer: 'special'
|
43
|
+
# end
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# The `type` is optional and defaults to `string` if not defined:
|
47
|
+
#
|
48
|
+
# field :full_name
|
49
|
+
#
|
50
|
+
# Also, multiple fields might be defined with one call and
|
51
|
+
# with the same options:
|
52
|
+
#
|
53
|
+
# field :first_name, :last_name, analyzer: 'special'
|
54
|
+
#
|
55
|
+
# The only special option in the field definition
|
56
|
+
# is `:value`. If no `:value` specified then just corresponding
|
57
|
+
# method will be called for the indexed object. Also
|
58
|
+
# `:value` might be a proc or indexed object method name:
|
59
|
+
#
|
60
|
+
# class User < ActiveRecord::Base
|
61
|
+
# def user_full_name
|
62
|
+
# [first_name, last_name].join(' ')
|
63
|
+
# end
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# field :full_name, type: 'string', value: :user_full_name
|
67
|
+
#
|
68
|
+
# The proc evaluates inside the indexed object context if
|
69
|
+
# its arity is 0 and in present contexts if there is an argument:
|
70
|
+
#
|
71
|
+
# field :full_name, type: 'string', value: -> { [first_name, last_name].join(' ') }
|
72
|
+
#
|
73
|
+
# separator = ' '
|
74
|
+
# field :full_name, type: 'string', value: ->(user) { [user.first_name, user.last_name].join(separator) }
|
75
|
+
#
|
76
|
+
# If array was returned as value - it will be put in index as well.
|
77
|
+
#
|
78
|
+
# field :tags, type: 'string', value: -> { tags.map(&:name) }
|
79
|
+
#
|
80
|
+
# Fields supports nesting in case of `object` field type. If
|
81
|
+
# `user.quiz` will return an array of objects, then result index content
|
82
|
+
# will be an array of hashes, if `user.quiz` is not a collection association
|
83
|
+
# then just values hash will be put in the index.
|
84
|
+
#
|
85
|
+
# field :quiz, type: 'object' do
|
86
|
+
# field :question, :answer
|
87
|
+
# field :score, type: 'integer'
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# Nested fields are composed from nested objects:
|
91
|
+
#
|
92
|
+
# field :name, type: 'object', value: -> { name_translations } do
|
93
|
+
# field :ru, value: ->(name) { name['ru'] }
|
94
|
+
# field :en, value: ->(name) { name['en'] }
|
95
|
+
# end
|
96
|
+
#
|
97
|
+
# Off course it is possible to define object fields contents dynamically
|
98
|
+
# but make sure evaluation proc returns hash:
|
99
|
+
#
|
100
|
+
# field :name, type: 'object', value: -> { name_translations }
|
101
|
+
#
|
102
|
+
# The special case is `multi_field`. In that case field composition
|
103
|
+
# changes satisfy elasticsearch rules:
|
104
|
+
#
|
105
|
+
# field :full_name, type: 'multi_field', value: ->{ full_name.try(:strip) } do
|
106
|
+
# field :full_name, index: 'analyzed', analyzer: 'name'
|
107
|
+
# field :sorted, index: 'analyzed', analyzer: 'sorted'
|
108
|
+
# end
|
109
|
+
#
|
110
|
+
def field *args, &block
|
17
111
|
options = args.extract_options!
|
18
|
-
build_root unless
|
112
|
+
build_root unless root_object
|
19
113
|
|
20
114
|
if args.size > 1
|
21
115
|
args.map { |name| field(name, options) }
|
@@ -24,13 +118,42 @@ module Chewy
|
|
24
118
|
end
|
25
119
|
end
|
26
120
|
|
121
|
+
# Defines dynamic template in mapping root objests
|
122
|
+
#
|
123
|
+
# class CarsIndex < Chewy::Index
|
124
|
+
# define_type Car do
|
125
|
+
# template 'model.*', type: 'string', analyzer: 'special'
|
126
|
+
# field 'model', type: 'object' # here we can put { ru: 'Мерседес', en: 'Mercedes' }
|
127
|
+
# # and template will be applyed to this field
|
128
|
+
# end
|
129
|
+
# end
|
130
|
+
#
|
131
|
+
# Name for each template is generated with the following
|
132
|
+
# rule: "template_#{dynamic_templates.size + 1}".
|
133
|
+
#
|
134
|
+
# template 'tit*', mapping_hash
|
135
|
+
# template 'title.*', mapping_hash # dot in template causes "path_match" using
|
136
|
+
# template /tit.+/, mapping_hash # using "match_pattern": "regexp"
|
137
|
+
# template /title\..+/, mapping_hash # "\." - escaped dot causes "path_match" using
|
138
|
+
# template /tit.+/, 'string' mapping_hash # "match_mapping_type" as the optionsl second argument
|
139
|
+
# template template42: {match: 'hello*', mapping: {type: 'object'}} # or even pass a template as is
|
140
|
+
#
|
141
|
+
def template *args
|
142
|
+
build_root unless root_object
|
143
|
+
|
144
|
+
root_object.dynamic_template *args
|
145
|
+
end
|
146
|
+
alias_method :dynamic_template, :template
|
147
|
+
|
148
|
+
# Returns compiled mappings hash for current type
|
149
|
+
#
|
27
150
|
def mappings_hash
|
28
151
|
root_object ? root_object.mappings_hash : {}
|
29
152
|
end
|
30
153
|
|
31
154
|
private
|
32
155
|
|
33
|
-
def expand_nested
|
156
|
+
def expand_nested field, &block
|
34
157
|
@_current_field.nested(field) if @_current_field
|
35
158
|
if block
|
36
159
|
previous_field, @_current_field = @_current_field, field
|
@@ -39,7 +162,7 @@ module Chewy
|
|
39
162
|
end
|
40
163
|
end
|
41
164
|
|
42
|
-
def build_root
|
165
|
+
def build_root options = {}, &block
|
43
166
|
self.root_object = Chewy::Fields::Root.new(type_name, options)
|
44
167
|
expand_nested(self.root_object, &block)
|
45
168
|
@_current_field = self.root_object
|
data/lib/chewy/type/observe.rb
CHANGED
@@ -9,6 +9,9 @@ module Chewy
|
|
9
9
|
method = args.first
|
10
10
|
|
11
11
|
update = Proc.new do
|
12
|
+
update_options = options.reverse_merge(urgent: Chewy.urgent_update)
|
13
|
+
clear_association_cache if update_options[:urgent]
|
14
|
+
|
12
15
|
backreference = if method && method.to_s == 'self'
|
13
16
|
self
|
14
17
|
elsif method
|
@@ -17,8 +20,7 @@ module Chewy
|
|
17
20
|
instance_eval(&block)
|
18
21
|
end
|
19
22
|
|
20
|
-
Chewy.derive_type(type_name).update_index(backreference,
|
21
|
-
options.reverse_merge(urgent: Chewy.urgent_update))
|
23
|
+
Chewy.derive_type(type_name).update_index(backreference, update_options)
|
22
24
|
end
|
23
25
|
|
24
26
|
after_save &update
|
data/lib/chewy/version.rb
CHANGED
@@ -3,4 +3,42 @@ require 'spec_helper'
|
|
3
3
|
describe Chewy::Fields::Root do
|
4
4
|
specify { described_class.new('name').value.should be_a(Proc) }
|
5
5
|
# TODO: add 'should_behave_like base_field'
|
6
|
+
|
7
|
+
subject(:field) { described_class.new('product') }
|
8
|
+
|
9
|
+
describe '#dynamic_template' do
|
10
|
+
specify do
|
11
|
+
field.dynamic_template 'hello', type: 'string'
|
12
|
+
field.dynamic_template 'hello*', :integer
|
13
|
+
field.dynamic_template 'hello.*'
|
14
|
+
field.dynamic_template /hello/
|
15
|
+
field.dynamic_template /hello.*/
|
16
|
+
field.dynamic_template template_42: {mapping: {}, match: ''}
|
17
|
+
field.dynamic_template /hello\..*/
|
18
|
+
|
19
|
+
field.mappings_hash.should == {product: {dynamic_templates: [
|
20
|
+
{template_1: {mapping: {type: 'string'}, match: 'hello'}},
|
21
|
+
{template_2: {mapping: {}, match_mapping_type: 'integer', match: 'hello*'}},
|
22
|
+
{template_3: {mapping: {}, path_match: 'hello.*'}},
|
23
|
+
{template_4: {mapping: {}, match: 'hello', match_pattern: 'regexp'}},
|
24
|
+
{template_5: {mapping: {}, match: 'hello.*', match_pattern: 'regexp'}},
|
25
|
+
{template_42: {mapping: {}, match: ''}},
|
26
|
+
{template_7: {mapping: {}, path_match: 'hello\..*', match_pattern: 'regexp'}}
|
27
|
+
]}}
|
28
|
+
end
|
29
|
+
|
30
|
+
context do
|
31
|
+
subject(:field) { described_class.new('product', dynamic_templates: [
|
32
|
+
{template_42: {mapping: {}, match: ''}}
|
33
|
+
]) }
|
34
|
+
|
35
|
+
specify do
|
36
|
+
field.dynamic_template 'hello', type: 'string'
|
37
|
+
field.mappings_hash.should == {product: {dynamic_templates: [
|
38
|
+
{template_42: {mapping: {}, match: ''}},
|
39
|
+
{template_1: {mapping: {type: 'string'}, match: 'hello'}}
|
40
|
+
]}}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
6
44
|
end
|
@@ -284,7 +284,7 @@ describe Chewy::Index::Actions do
|
|
284
284
|
define_type City do
|
285
285
|
field :name, type: 'object'
|
286
286
|
end
|
287
|
-
end
|
287
|
+
end
|
288
288
|
end
|
289
289
|
|
290
290
|
specify { CitiesIndex.import(city: dummy_cities).should == false }
|
@@ -308,7 +308,7 @@ describe Chewy::Index::Actions do
|
|
308
308
|
define_type City do
|
309
309
|
field :name, type: 'object'
|
310
310
|
end
|
311
|
-
end
|
311
|
+
end
|
312
312
|
end
|
313
313
|
|
314
314
|
specify { expect { CitiesIndex.import!(city: dummy_cities) }.to raise_error Chewy::FailedImport }
|