elasticsearch-model-extensions 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -0
- data/Gemfile +2 -1
- data/README.md +5 -0
- data/gemfiles/rails41.gemfile +11 -0
- data/gemfiles/rails41.gemfile.lock +109 -0
- data/lib/elasticsearch/model/extensions/association_path_finding/association_path_finder.rb +19 -0
- data/lib/elasticsearch/model/extensions/association_path_finding/mapping_node.rb +68 -0
- data/lib/elasticsearch/model/extensions/association_path_finding/shortest_path.rb +108 -0
- data/lib/elasticsearch/model/extensions/batch_updating.rb +9 -52
- data/lib/elasticsearch/model/extensions/batch_updating/batch_updater.rb +68 -0
- data/lib/elasticsearch/model/extensions/configuration.rb +33 -5
- data/lib/elasticsearch/model/extensions/dependency_tracking.rb +17 -21
- data/lib/elasticsearch/model/extensions/dependency_tracking/dependency_tracker.rb +52 -0
- data/lib/elasticsearch/model/extensions/mapping_reflection.rb +7 -80
- data/lib/elasticsearch/model/extensions/mapping_reflection/mapping_reflector.rb +107 -0
- data/lib/elasticsearch/model/extensions/outer_document_updating.rb +0 -21
- data/lib/elasticsearch/model/extensions/partial_updating.rb +16 -116
- data/lib/elasticsearch/model/extensions/partial_updating/partial_updater.rb +149 -0
- data/lib/elasticsearch/model/extensions/proxy.rb +0 -0
- data/lib/elasticsearch/model/extensions/update_callback.rb +3 -2
- data/lib/elasticsearch/model/extensions/version.rb +1 -1
- data/spec/batch_updating/batch_updater_spec.rb +50 -0
- data/spec/batch_updating_spec.rb +134 -0
- data/spec/integration_spec.rb +350 -4
- data/spec/partial_updating_spec.rb +36 -6
- data/spec/setup/articles_with_comments.rb +2 -4
- data/spec/setup/articles_with_comments_and_delayed_jobs.rb +2 -4
- data/spec/setup/authors_and_books_with_tags.rb +183 -0
- data/spec/setup/items_and_categories.rb +0 -0
- data/spec/setup/sqlite.rb +1 -1
- data/spec/setup/undefine.rb +6 -6
- data/spec/spec_helper.rb +6 -0
- metadata +20 -4
- data/lib/elasticsearch/model/extensions/mapping_node.rb +0 -65
- data/lib/elasticsearch/model/extensions/shortest_path.rb +0 -106
@@ -1,4 +1,3 @@
|
|
1
|
-
require_relative 'mapping_node'
|
2
1
|
require_relative 'update_callback'
|
3
2
|
require_relative 'destroy_callback'
|
4
3
|
|
@@ -10,11 +9,6 @@ module Elasticsearch
|
|
10
9
|
klass.extend ClassMethods
|
11
10
|
end
|
12
11
|
|
13
|
-
def index_update_required?
|
14
|
-
(previous_changes.keys & self.class.nested_object_fields).size > 0 ||
|
15
|
-
(previous_changes.size > 0 && self.class.has_dependent_fields?)
|
16
|
-
end
|
17
|
-
|
18
12
|
class Update
|
19
13
|
def initialize(from:, to:)
|
20
14
|
@parent_class = from
|
@@ -96,21 +90,6 @@ module Elasticsearch
|
|
96
90
|
end
|
97
91
|
|
98
92
|
module ClassMethods
|
99
|
-
def nested_object_fields
|
100
|
-
@nested_object_fields
|
101
|
-
end
|
102
|
-
|
103
|
-
def has_dependent_fields?
|
104
|
-
@has_dependent_fields
|
105
|
-
end
|
106
|
-
|
107
|
-
def path_from(from)
|
108
|
-
Elasticsearch::Model::Extensions::MappingNode.
|
109
|
-
from_class(from).
|
110
|
-
breadth_first_search { |e| e.destination.relates_to_class?(self) }.
|
111
|
-
first
|
112
|
-
end
|
113
|
-
|
114
93
|
def initialize_active_record!(active_record_class, parent_class: parent_class, delayed:, only_if: -> r { true }, records_to_update_documents: nil, field_to_update: nil, block: block)
|
115
94
|
config = Elasticsearch::Model::Extensions::Configuration.new(active_record_class, parent_class: parent_class, delayed: delayed, only_if: binding.local_variable_get(:only_if), records_to_update_documents: records_to_update_documents,
|
116
95
|
field_to_update: field_to_update,
|
@@ -1,141 +1,41 @@
|
|
1
|
+
require_relative 'partial_updating/partial_updater'
|
2
|
+
|
1
3
|
module Elasticsearch
|
2
4
|
module Model
|
3
5
|
module Extensions
|
4
6
|
module PartialUpdating
|
5
7
|
def self.included(klass)
|
6
8
|
klass.extend ClassMethods
|
7
|
-
end
|
8
|
-
|
9
|
-
def self.build_as_json_options(klass:, props: )
|
10
|
-
indexed_attributes = props.keys
|
11
|
-
associations = klass.reflect_on_all_associations.select { |a| %i| has_one has_many belongs_to |.include? a.macro }
|
12
|
-
association_names = associations.map(&:name)
|
13
|
-
persisted_attributes = klass.attribute_names.map(&:intern)
|
14
9
|
|
15
|
-
|
16
|
-
method_attributes = indexed_attributes - persisted_attributes - nested_attributes
|
17
|
-
only_attributes = indexed_attributes - nested_attributes
|
18
|
-
|
19
|
-
options = {
|
20
|
-
root: false
|
21
|
-
}
|
22
|
-
|
23
|
-
if only_attributes.size > 1
|
24
|
-
options[:only] = only_attributes
|
25
|
-
elsif only_attributes.size == 1
|
26
|
-
options[:only] = only_attributes.first
|
27
|
-
end
|
28
|
-
|
29
|
-
if method_attributes.size > 1
|
30
|
-
options[:methods] = method_attributes
|
31
|
-
elsif method_attributes.size == 1
|
32
|
-
options[:methods] = method_attributes.first
|
33
|
-
end
|
34
|
-
|
35
|
-
nested_attributes.each do |n|
|
36
|
-
a = associations.find { |a| a.name == n.intern }
|
37
|
-
nested_klass = a.class_name.constantize
|
38
|
-
nested_prop = props[n]
|
39
|
-
if nested_prop.present?
|
40
|
-
options[:include] ||= {}
|
41
|
-
options[:include][n] = build_as_json_options(
|
42
|
-
klass: nested_klass,
|
43
|
-
props: nested_prop[:properties]
|
44
|
-
)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
options
|
10
|
+
klass.instance_variable_set :@__partial_updater__, PartialUpdater.new(klass)
|
49
11
|
end
|
50
12
|
|
51
13
|
def as_indexed_json(options={})
|
52
|
-
as_json(options.merge(self.class.as_json_options))
|
53
|
-
end
|
54
|
-
|
55
|
-
# @param [Array<Symbol>] changed_attributes
|
56
|
-
# @param [Proc<Symbol, Hash>] json_options
|
57
|
-
def build_partial_document_for_update(*changed_attributes, json_options: nil)
|
58
|
-
changes = {}
|
59
|
-
|
60
|
-
json_options ||= -> field { self.class.partial_as_json_options(field) || {} }
|
61
|
-
|
62
|
-
self.class.each_field_to_update_according_to_changed_fields(changed_attributes) do |field_to_update|
|
63
|
-
options = json_options.call field_to_update
|
64
|
-
|
65
|
-
json = __send__(:"#{field_to_update}").as_json(options)
|
66
|
-
|
67
|
-
changes[field_to_update] = json
|
68
|
-
end
|
69
|
-
|
70
|
-
changes
|
14
|
+
as_json(options.merge(self.class.__partial_updater__.as_json_options))
|
71
15
|
end
|
72
16
|
|
73
17
|
def partially_update_document(*changed_attributes)
|
74
18
|
if changed_attributes.empty?
|
75
19
|
__elasticsearch__.index_document
|
76
20
|
else
|
77
|
-
|
78
|
-
partial_document = build_partial_document_for_update(*changed_attributes)
|
79
|
-
rescue => e
|
80
|
-
if defined? ::Rails
|
81
|
-
::Rails.logger.error "Error in #partially_update_document: #{e.message}\n#{e.backtrace.join("\n")}"
|
82
|
-
else
|
83
|
-
warn "Error in #partially_update_document: #{e.message}\n#{e.backtrace.join("\n")}"
|
84
|
-
end
|
85
|
-
end
|
21
|
+
partial_updater = self.class.__partial_updater__
|
86
22
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
# @param [Hash] partial_document
|
92
|
-
def update_document(partial_document)
|
93
|
-
klass = self.class
|
94
|
-
|
95
|
-
__elasticsearch__.client.update(
|
96
|
-
{ index: klass.index_name,
|
97
|
-
type: klass.document_type,
|
98
|
-
id: self.id,
|
99
|
-
body: { doc: partial_document } }
|
100
|
-
) if partial_document.size > 0
|
101
|
-
end
|
102
|
-
|
103
|
-
module ClassMethods
|
104
|
-
def as_json_options
|
105
|
-
@as_json_options ||= Elasticsearch::Model::Extensions::PartialUpdating.build_as_json_options(
|
106
|
-
klass: self,
|
107
|
-
props: self.mappings.to_hash[self.document_type.intern][:properties]
|
23
|
+
partial_document = partial_updater.build_partial_document_for_update_with_error_logging(
|
24
|
+
record: self,
|
25
|
+
changed_attributes: changed_attributes
|
108
26
|
)
|
109
|
-
end
|
110
|
-
|
111
|
-
def partial_as_json_options(field)
|
112
|
-
as_json_options[:include][field]
|
113
|
-
end
|
114
27
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
changed_fields.each do |changed_field|
|
119
|
-
field_mapping = root_mapping_properties[:"#{changed_field}"]
|
120
|
-
|
121
|
-
next unless field_mapping
|
122
|
-
|
123
|
-
yield changed_field
|
124
|
-
end
|
125
|
-
|
126
|
-
each_dependent_attribute_for(changed_fields.map(&:to_s)) do |a|
|
127
|
-
a_sym = a.intern
|
128
|
-
|
129
|
-
yield a_sym
|
28
|
+
if partial_document
|
29
|
+
partial_updater.update_document(id: self.id, doc: partial_document)
|
130
30
|
end
|
131
31
|
end
|
132
32
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
33
|
+
true
|
34
|
+
end
|
35
|
+
|
36
|
+
module ClassMethods
|
37
|
+
def __partial_updater__
|
38
|
+
@__partial_updater__
|
139
39
|
end
|
140
40
|
end
|
141
41
|
|
@@ -0,0 +1,149 @@
|
|
1
|
+
module Elasticsearch
|
2
|
+
module Model
|
3
|
+
module Extensions
|
4
|
+
module PartialUpdating
|
5
|
+
class PartialUpdater
|
6
|
+
def initialize(base)
|
7
|
+
@base = base
|
8
|
+
end
|
9
|
+
|
10
|
+
def base
|
11
|
+
@base
|
12
|
+
end
|
13
|
+
|
14
|
+
def build_as_json_options(klass:, props: )
|
15
|
+
indexed_attributes = props.keys
|
16
|
+
associations = klass.reflect_on_all_associations.select { |a| %i| has_one has_many belongs_to |.include? a.macro }
|
17
|
+
association_names = associations.map(&:name)
|
18
|
+
persisted_attributes = klass.attribute_names.map(&:intern)
|
19
|
+
|
20
|
+
nested_attributes = indexed_attributes & association_names
|
21
|
+
method_attributes = indexed_attributes - persisted_attributes - nested_attributes
|
22
|
+
only_attributes = indexed_attributes - nested_attributes
|
23
|
+
|
24
|
+
options = {
|
25
|
+
root: false
|
26
|
+
}
|
27
|
+
|
28
|
+
nested_attributes.map!(&:to_s)
|
29
|
+
method_attributes.map!(&:to_s)
|
30
|
+
only_attributes.map!(&:to_s)
|
31
|
+
|
32
|
+
if only_attributes.size > 1
|
33
|
+
options[:only] = only_attributes
|
34
|
+
elsif only_attributes.size == 1
|
35
|
+
options[:only] = only_attributes.first
|
36
|
+
end
|
37
|
+
|
38
|
+
if method_attributes.size > 1
|
39
|
+
options[:methods] = method_attributes
|
40
|
+
elsif method_attributes.size == 1
|
41
|
+
options[:methods] = method_attributes.first
|
42
|
+
end
|
43
|
+
|
44
|
+
nested_attributes.each do |n|
|
45
|
+
n_as_sym = n.intern
|
46
|
+
a = associations.find { |a| a.name == n_as_sym }
|
47
|
+
nested_klass = a.class_name.constantize
|
48
|
+
nested_prop = props[n_as_sym]
|
49
|
+
if nested_prop.present?
|
50
|
+
options[:include] ||= {}
|
51
|
+
options[:include][n] = build_as_json_options(
|
52
|
+
klass: nested_klass,
|
53
|
+
props: nested_prop[:properties]
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
options
|
59
|
+
end
|
60
|
+
|
61
|
+
def as_json_options
|
62
|
+
@as_json_options ||= build_as_json_options(
|
63
|
+
klass: base,
|
64
|
+
props: base.mappings.to_hash[base.document_type.intern][:properties]
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
def partial_as_json_options(field)
|
69
|
+
as_json_options[:include][field.to_s]
|
70
|
+
end
|
71
|
+
|
72
|
+
def each_field_to_update_according_to_changed_fields(changed_fields)
|
73
|
+
root_mapping_properties = base.mappings.to_hash[:"#{base.document_type}"][:properties]
|
74
|
+
|
75
|
+
changed_fields.each do |changed_field|
|
76
|
+
field_mapping = root_mapping_properties[:"#{changed_field}"]
|
77
|
+
|
78
|
+
next unless field_mapping
|
79
|
+
|
80
|
+
yield changed_field
|
81
|
+
end
|
82
|
+
|
83
|
+
base.__dependency_tracker__.each_dependent_attribute_for(changed_fields.map(&:to_s)) do |a|
|
84
|
+
a_sym = a.intern
|
85
|
+
|
86
|
+
yield a_sym
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def fields_to_update_according_to_changed_fields(changed_fields)
|
91
|
+
fields = []
|
92
|
+
each_field_to_update_according_to_changed_fields changed_fields do |field_to_update|
|
93
|
+
fields << field_to_update
|
94
|
+
end
|
95
|
+
fields
|
96
|
+
end
|
97
|
+
|
98
|
+
def build_partial_document_for_update_with_error_logging(record:, changed_attributes:, json_options: nil)
|
99
|
+
begin
|
100
|
+
build_partial_document_for_update(
|
101
|
+
record: record,
|
102
|
+
changed_attributes: changed_attributes,
|
103
|
+
json_options: json_options
|
104
|
+
)
|
105
|
+
rescue => e
|
106
|
+
if defined? ::Rails
|
107
|
+
::Rails.logger.error "Error in #build_partial_document_for_update_with_error_logging: #{e.message}\n#{e.backtrace.join("\n")}"
|
108
|
+
else
|
109
|
+
warn "Error in #build_partial_document_for_update_with_error_logging: #{e.message}\n#{e.backtrace.join("\n")}"
|
110
|
+
end
|
111
|
+
|
112
|
+
nil
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# @param [ActiveRecord::Base] record
|
117
|
+
# @param [Array<Symbol>] changed_attributes
|
118
|
+
# @param [Proc<Symbol, Hash>] json_options
|
119
|
+
def build_partial_document_for_update(record:, changed_attributes:, json_options: nil)
|
120
|
+
changes = {}
|
121
|
+
|
122
|
+
json_options ||= -> field { partial_as_json_options(field) || {} }
|
123
|
+
|
124
|
+
each_field_to_update_according_to_changed_fields(changed_attributes) do |field_to_update|
|
125
|
+
options = json_options.call field_to_update
|
126
|
+
|
127
|
+
json = record.__send__(:"#{field_to_update}").as_json(options)
|
128
|
+
|
129
|
+
changes[field_to_update] = json
|
130
|
+
end
|
131
|
+
|
132
|
+
changes
|
133
|
+
end
|
134
|
+
|
135
|
+
# @param [Hash] doc
|
136
|
+
def update_document(id:, doc:)
|
137
|
+
base.__elasticsearch__.client.update(
|
138
|
+
{ index: base.index_name,
|
139
|
+
type: base.document_type,
|
140
|
+
id: id,
|
141
|
+
body: { doc: doc } }
|
142
|
+
) if doc.size > 0
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
File without changes
|
@@ -9,9 +9,10 @@ module Elasticsearch
|
|
9
9
|
records_to_update_documents = config.records_to_update_documents
|
10
10
|
only_if = config.only_if
|
11
11
|
callback = self
|
12
|
+
_config = config
|
12
13
|
|
13
14
|
record.instance_eval do
|
14
|
-
return unless only_if.call(self) && index_update_required?
|
15
|
+
return unless only_if.call(self) && _config.index_update_required?(self)
|
15
16
|
|
16
17
|
target = records_to_update_documents.call(self)
|
17
18
|
|
@@ -39,4 +40,4 @@ module Elasticsearch
|
|
39
40
|
end
|
40
41
|
end
|
41
42
|
end
|
42
|
-
end
|
43
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'elasticsearch/model/extensions/all'
|
2
|
+
|
3
|
+
RSpec.describe Elasticsearch::Model::Extensions::BatchUpdating::BatchUpdater do
|
4
|
+
before(:each) do
|
5
|
+
load 'setup/articles_with_comments.rb'
|
6
|
+
end
|
7
|
+
|
8
|
+
after :each do
|
9
|
+
ActiveRecord::Schema.define(:version => 2) do
|
10
|
+
drop_table :comments
|
11
|
+
drop_table :articles
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:batch_updater) {
|
16
|
+
Article.__batch_updater__
|
17
|
+
}
|
18
|
+
|
19
|
+
describe '#split_ids_into' do
|
20
|
+
subject {
|
21
|
+
batch_updater.split_ids_into(2, min: 0, max: 3)
|
22
|
+
}
|
23
|
+
|
24
|
+
specify {
|
25
|
+
expect(subject).to eq([0..1, 2..3])
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'the index dropped' do
|
30
|
+
before(:each) do
|
31
|
+
Article.__elasticsearch__.create_index! force: true
|
32
|
+
Article.__elasticsearch__.refresh_index!
|
33
|
+
end
|
34
|
+
|
35
|
+
def number_of_articles_about_coding
|
36
|
+
Article.search('Coding').records.size
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '.update_index_in_parallel' do
|
40
|
+
subject {
|
41
|
+
batch_updater.update_index_in_batch(Article.all.to_ary)
|
42
|
+
Article.__elasticsearch__.refresh_index!
|
43
|
+
}
|
44
|
+
|
45
|
+
specify {
|
46
|
+
expect { subject }.to change { number_of_articles_about_coding }.by(2)
|
47
|
+
}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'elasticsearch/model/extensions/all'
|
2
|
+
|
3
|
+
require 'parallel'
|
4
|
+
|
5
|
+
RSpec.describe Elasticsearch::Model::Extensions::BatchUpdating do
|
6
|
+
before(:each) do
|
7
|
+
load 'setup/articles_with_comments.rb'
|
8
|
+
end
|
9
|
+
|
10
|
+
after(:each) do
|
11
|
+
ActiveRecord::Schema.define(:version => 2) do
|
12
|
+
drop_table :comments
|
13
|
+
drop_table :articles
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '.with_indexed_tables_included' do
|
18
|
+
subject {
|
19
|
+
Article.with_indexed_tables_included
|
20
|
+
}
|
21
|
+
|
22
|
+
context 'without a `with_indexed_tables_included` implementation' do
|
23
|
+
specify {
|
24
|
+
expect { subject }.to raise_error
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'with a `with_indexed_tables_included` implementation' do
|
29
|
+
before(:each) do
|
30
|
+
Article.class_eval do
|
31
|
+
def self.with_indexed_tables_included
|
32
|
+
includes(:comments)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
specify {
|
38
|
+
expect { subject }.to_not raise_error
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '.elasticsearch_hosts' do
|
44
|
+
subject {
|
45
|
+
Article.elasticsearch_hosts
|
46
|
+
}
|
47
|
+
|
48
|
+
context 'without a `elasticsearch_hosts` implementation' do
|
49
|
+
specify {
|
50
|
+
expect { subject }.to raise_error
|
51
|
+
}
|
52
|
+
|
53
|
+
specify {
|
54
|
+
expect { Article.__batch_updater__.reconnect! }.to raise_error
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'with a `elasticsearch_hosts` implementation' do
|
59
|
+
before(:each) do
|
60
|
+
Article.class_eval do
|
61
|
+
def self.elasticsearch_hosts
|
62
|
+
'http://localhost:9250'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
specify {
|
68
|
+
expect { subject }.to_not raise_error
|
69
|
+
}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'the index dropped' do
|
74
|
+
before(:each) do
|
75
|
+
Article.__elasticsearch__.create_index! force: true
|
76
|
+
Article.__elasticsearch__.refresh_index!
|
77
|
+
|
78
|
+
Article.class_eval do
|
79
|
+
def self.elasticsearch_hosts
|
80
|
+
listened_port = (ENV['TEST_CLUSTER_PORT'] || 9250)
|
81
|
+
"http://localhost:#{listened_port}/"
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.with_indexed_tables_included
|
85
|
+
includes(:comments)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
shared_examples 'indexing all articles' do
|
91
|
+
def number_of_articles_about_coding
|
92
|
+
Article.search('Coding').records.size
|
93
|
+
end
|
94
|
+
|
95
|
+
specify {
|
96
|
+
expect { subject; Article.__elasticsearch__.refresh_index! }.to change { number_of_articles_about_coding }.by(2)
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
describe '.update_index_in_parallel' do
|
101
|
+
subject {
|
102
|
+
Article.update_index_in_parallel(parallelism: 2)
|
103
|
+
}
|
104
|
+
|
105
|
+
it_behaves_like 'indexing all articles'
|
106
|
+
end
|
107
|
+
|
108
|
+
describe '.update_index_in_batches' do
|
109
|
+
subject {
|
110
|
+
Article.update_index_in_batches
|
111
|
+
}
|
112
|
+
|
113
|
+
it_behaves_like 'indexing all articles'
|
114
|
+
end
|
115
|
+
|
116
|
+
describe 'Association/Extension' do
|
117
|
+
describe '.update_index_for_ids_in_range' do
|
118
|
+
subject {
|
119
|
+
Article.for_indexing.update_index_for_ids_in_range(Article.minimum(:id)..Article.maximum(:id))
|
120
|
+
}
|
121
|
+
|
122
|
+
it_behaves_like 'indexing all articles'
|
123
|
+
end
|
124
|
+
|
125
|
+
describe '.update_index_in_batches' do
|
126
|
+
subject {
|
127
|
+
Article.for_indexing.update_index_in_batches
|
128
|
+
}
|
129
|
+
|
130
|
+
it_behaves_like 'indexing all articles'
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|