elasticsearch-model-extensions 0.2.2 → 0.3.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 -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
|