esse 0.3.5 → 0.4.0.rc1
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/lib/esse/cli/index.rb +8 -9
- data/lib/esse/core.rb +7 -0
- data/lib/esse/document.rb +19 -6
- data/lib/esse/document_for_partial_update.rb +16 -0
- data/lib/esse/import/bulk.rb +17 -13
- data/lib/esse/index/documents.rb +92 -27
- data/lib/esse/index/indices.rb +3 -1
- data/lib/esse/index/object_document_mapper.rb +1 -1
- data/lib/esse/lazy_document_header.rb +39 -27
- data/lib/esse/repository/documents.rb +5 -6
- data/lib/esse/repository/object_document_mapper.rb +47 -9
- data/lib/esse/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f6023e2f4fe6b5d8e45dd09e7c98bb250d8862ea3adc769f119011efc07191c5
|
4
|
+
data.tar.gz: 852a46c60435d7c0848254d6b79a4a29ee89efe9e0700975d7d651660ad874d8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 40b5c6d0ed7ff8ce793cd8be088c01f9377c62cf58366b201c8ee988f04e9f2f3e53118a48c165857394dc100c26fd06b300d653f2afdead076430d19210c554
|
7
|
+
data.tar.gz: f3b4f4acadea569ef1108c1d3d3a2745c965177c29f307e5076357d89aec1f050f778933a350ccb75c0128a295d0f1349899452ea041551fae8ae574fb75793d
|
data/lib/esse/cli/index.rb
CHANGED
@@ -97,18 +97,17 @@ module Esse
|
|
97
97
|
option :suffix, type: :string, default: nil, aliases: '-s', desc: 'Suffix to append to index name'
|
98
98
|
option :context, type: :hash, default: {}, required: true, desc: 'List of options to pass to the index class'
|
99
99
|
option :repo, type: :string, default: nil, alias: '-r', desc: 'Repository to use for import'
|
100
|
-
option :
|
101
|
-
option :
|
100
|
+
option :preload_lazy_attributes, type: :string, default: nil, desc: 'Command separated list of lazy document attributes to preload using search API before the bulk import. Or pass `true` to preload all lazy attributes'
|
101
|
+
option :eager_load_lazy_attributes, type: :string, default: nil, desc: 'Comma separated list of lazy document attributes to include to the bulk index request. Or pass `true` to include all lazy attributes'
|
102
|
+
option :update_lazy_attributes, type: :string, default: nil, desc: 'Comma separated list of lazy document attributes to bulk update after the bulk index request Or pass `true` to include all lazy attributes'
|
103
|
+
|
102
104
|
def import(*index_classes)
|
103
105
|
require_relative 'index/import'
|
104
106
|
opts = HashUtils.deep_transform_keys(options.to_h, &:to_sym)
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
end
|
110
|
-
if (val = opts[:lazy_update_document_attributes])
|
111
|
-
opts[:lazy_update_document_attributes] = (val == 'true') ? true : val.split(',')
|
107
|
+
%i[preload_lazy_attributes eager_load_lazy_attributes update_lazy_attributes].each do |key|
|
108
|
+
if (val = opts.delete(key)) && val != 'false'
|
109
|
+
opts[key] = (val == 'true') ? true : val.split(',')
|
110
|
+
end
|
112
111
|
end
|
113
112
|
Import.new(indices: index_classes, **opts).run
|
114
113
|
end
|
data/lib/esse/core.rb
CHANGED
@@ -6,6 +6,7 @@ module Esse
|
|
6
6
|
require_relative 'primitives'
|
7
7
|
require_relative 'collection'
|
8
8
|
require_relative 'document'
|
9
|
+
require_relative 'document_for_partial_update'
|
9
10
|
require_relative 'document_lazy_attribute'
|
10
11
|
require_relative 'lazy_document_header'
|
11
12
|
require_relative 'hash_document'
|
@@ -91,4 +92,10 @@ module Esse
|
|
91
92
|
|
92
93
|
!!(object.is_a?(Esse::Document) && object.id)
|
93
94
|
end
|
95
|
+
|
96
|
+
def self.document_match_with_header?(document, id, routing, type)
|
97
|
+
id && id.to_s == document.id.to_s &&
|
98
|
+
routing == document.routing &&
|
99
|
+
(LazyDocumentHeader::ACCEPTABLE_DOC_TYPES.include?(document.type) && LazyDocumentHeader::ACCEPTABLE_DOC_TYPES.include?(type) || document.type == type)
|
100
|
+
end
|
94
101
|
end
|
data/lib/esse/document.rb
CHANGED
@@ -2,11 +2,13 @@
|
|
2
2
|
|
3
3
|
module Esse
|
4
4
|
class Document
|
5
|
+
MUTATIONS_FALLBACK = {}.freeze
|
6
|
+
|
5
7
|
attr_reader :object, :options
|
6
8
|
|
7
9
|
def initialize(object, **options)
|
8
10
|
@object = object
|
9
|
-
@options = options
|
11
|
+
@options = options.freeze
|
10
12
|
end
|
11
13
|
|
12
14
|
# @return [String, Number] the document ID
|
@@ -84,11 +86,16 @@ module Esse
|
|
84
86
|
id.nil?
|
85
87
|
end
|
86
88
|
|
87
|
-
def
|
88
|
-
|
89
|
-
|
90
|
-
|
89
|
+
def eql?(other, match_lazy_doc_header: false)
|
90
|
+
if match_lazy_doc_header
|
91
|
+
other.eql?(self)
|
92
|
+
else
|
93
|
+
other.is_a?(Esse::Document) && (
|
94
|
+
id.to_s == other.id.to_s && type == other.type && routing == other.routing && meta == other.meta
|
95
|
+
)
|
96
|
+
end
|
91
97
|
end
|
98
|
+
alias_method :==, :eql?
|
92
99
|
|
93
100
|
def doc_header
|
94
101
|
{ _id: id }.tap do |h|
|
@@ -97,6 +104,10 @@ module Esse
|
|
97
104
|
end
|
98
105
|
end
|
99
106
|
|
107
|
+
def document_for_partial_update(source)
|
108
|
+
DocumentForPartialUpdate.new(self, source: source)
|
109
|
+
end
|
110
|
+
|
100
111
|
def inspect
|
101
112
|
attributes = %i[id routing source].map do |attr|
|
102
113
|
value = send(attr)
|
@@ -115,7 +126,9 @@ module Esse
|
|
115
126
|
instance_variable_set(:@__mutated_source__, nil)
|
116
127
|
end
|
117
128
|
|
118
|
-
|
129
|
+
def mutations
|
130
|
+
@__mutations__ || MUTATIONS_FALLBACK
|
131
|
+
end
|
119
132
|
|
120
133
|
def mutated_source
|
121
134
|
return source unless @__mutations__
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Esse
|
4
|
+
class DocumentForPartialUpdate < Esse::Document
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
def_delegators :object, :id, :type, :routing, :options
|
8
|
+
|
9
|
+
attr_reader :source
|
10
|
+
|
11
|
+
def initialize(lazy_header, source:)
|
12
|
+
@source = source
|
13
|
+
super(lazy_header)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/esse/import/bulk.rb
CHANGED
@@ -1,27 +1,35 @@
|
|
1
1
|
module Esse
|
2
2
|
module Import
|
3
3
|
class Bulk
|
4
|
-
def
|
5
|
-
|
4
|
+
def self.build_from_documents(type: nil, index: nil, delete: nil, create: nil, update: nil)
|
5
|
+
index = Array(index).select(&Esse.method(:document?)).reject(&:ignore_on_index?).map do |doc|
|
6
6
|
value = doc.to_bulk
|
7
7
|
value[:_type] ||= type if type
|
8
|
-
|
8
|
+
value
|
9
9
|
end
|
10
|
-
|
10
|
+
create = Array(create).select(&Esse.method(:document?)).reject(&:ignore_on_index?).map do |doc|
|
11
11
|
value = doc.to_bulk
|
12
12
|
value[:_type] ||= type if type
|
13
|
-
|
13
|
+
value
|
14
14
|
end
|
15
|
-
|
15
|
+
update = Array(update).select(&Esse.method(:document?)).reject(&:ignore_on_index?).map do |doc|
|
16
16
|
value = doc.to_bulk(operation: :update)
|
17
17
|
value[:_type] ||= type if type
|
18
|
-
|
18
|
+
value
|
19
19
|
end
|
20
|
-
|
20
|
+
delete = Array(delete).select(&Esse.method(:document?)).reject(&:ignore_on_delete?).map do |doc|
|
21
21
|
value = doc.to_bulk(data: false)
|
22
22
|
value[:_type] ||= type if type
|
23
|
-
|
23
|
+
value
|
24
24
|
end
|
25
|
+
new(index: index, delete: delete, create: create, update: update)
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(index: nil, delete: nil, create: nil, update: nil)
|
29
|
+
@index = Esse::ArrayUtils.wrap(index).map { |payload| { index: payload } }
|
30
|
+
@create = Esse::ArrayUtils.wrap(create).map { |payload| { create: payload } }
|
31
|
+
@update = Esse::ArrayUtils.wrap(update).map { |payload| { update: payload } }
|
32
|
+
@delete = Esse::ArrayUtils.wrap(delete).map { |payload| { delete: payload } }
|
25
33
|
end
|
26
34
|
|
27
35
|
# Return an array of RequestBody instances
|
@@ -68,10 +76,6 @@ module Esse
|
|
68
76
|
|
69
77
|
private
|
70
78
|
|
71
|
-
def valid_doc?(doc)
|
72
|
-
Esse.document?(doc)
|
73
|
-
end
|
74
|
-
|
75
79
|
def optimistic_request
|
76
80
|
request = Import::RequestBodyAsJson.new
|
77
81
|
request.create = @create
|
data/lib/esse/index/documents.rb
CHANGED
@@ -114,7 +114,7 @@ module Esse
|
|
114
114
|
def update(doc = nil, suffix: nil, **options)
|
115
115
|
if document?(doc)
|
116
116
|
options[:id] = doc.id
|
117
|
-
options[:body] = { doc: doc.
|
117
|
+
options[:body] = { doc: doc.mutated_source }
|
118
118
|
options[:type] = doc.type if doc.type?
|
119
119
|
options[:routing] = doc.routing if doc.routing?
|
120
120
|
end
|
@@ -140,7 +140,7 @@ module Esse
|
|
140
140
|
def index(doc = nil, suffix: nil, **options)
|
141
141
|
if document?(doc)
|
142
142
|
options[:id] = doc.id
|
143
|
-
options[:body] = doc.
|
143
|
+
options[:body] = doc.mutated_source
|
144
144
|
options[:type] = doc.type if doc.type?
|
145
145
|
options[:routing] = doc.routing if doc.routing?
|
146
146
|
end
|
@@ -171,13 +171,53 @@ module Esse
|
|
171
171
|
}.merge(options)
|
172
172
|
cluster.may_update_type!(definition)
|
173
173
|
|
174
|
+
to_index = []
|
175
|
+
to_create = []
|
176
|
+
to_update = []
|
177
|
+
to_delete = []
|
178
|
+
Esse::ArrayUtils.wrap(index).each do |doc|
|
179
|
+
if doc.is_a?(Hash)
|
180
|
+
to_index << doc
|
181
|
+
elsif Esse.document?(doc) && !doc.ignore_on_index?
|
182
|
+
hash = doc.to_bulk
|
183
|
+
hash[:_type] ||= type if type
|
184
|
+
to_index << hash
|
185
|
+
end
|
186
|
+
end
|
187
|
+
Esse::ArrayUtils.wrap(create).each do |doc|
|
188
|
+
if doc.is_a?(Hash)
|
189
|
+
to_create << doc
|
190
|
+
elsif Esse.document?(doc) && !doc.ignore_on_index?
|
191
|
+
hash = doc.to_bulk
|
192
|
+
hash[:_type] ||= type if type
|
193
|
+
to_create << hash
|
194
|
+
end
|
195
|
+
end
|
196
|
+
Esse::ArrayUtils.wrap(update).each do |doc|
|
197
|
+
if doc.is_a?(Hash)
|
198
|
+
to_update << doc
|
199
|
+
elsif Esse.document?(doc) && !doc.ignore_on_index?
|
200
|
+
hash = doc.to_bulk(operation: :update)
|
201
|
+
hash[:_type] ||= type if type
|
202
|
+
to_update << hash
|
203
|
+
end
|
204
|
+
end
|
205
|
+
Esse::ArrayUtils.wrap(delete).each do |doc|
|
206
|
+
if doc.is_a?(Hash)
|
207
|
+
to_delete << doc
|
208
|
+
elsif Esse.document?(doc) && !doc.ignore_on_delete?
|
209
|
+
hash = doc.to_bulk(data: false)
|
210
|
+
hash[:_type] ||= type if type
|
211
|
+
to_delete << hash
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
174
215
|
# @TODO Wrap the return in a some other Stats object with more information
|
175
216
|
Esse::Import::Bulk.new(
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
update: update,
|
217
|
+
create: to_create,
|
218
|
+
delete: to_delete,
|
219
|
+
index: to_index,
|
220
|
+
update: to_update,
|
181
221
|
).each_request do |request_body|
|
182
222
|
cluster.api.bulk(**definition, body: request_body.body) do |event_payload|
|
183
223
|
event_payload[:body_stats] = request_body.stats
|
@@ -198,36 +238,61 @@ module Esse
|
|
198
238
|
# @option [String, nil] :suffix The index suffix. Defaults to the nil.
|
199
239
|
# @option [Hash] :context The collection context. This value will be passed as argument to the collection
|
200
240
|
# May be SQL condition or any other filter you have defined on the collection.
|
241
|
+
# @option [Boolean, Array<String>] :eager_load_lazy_attributes A list of lazy document attributes to include to the bulk index request.
|
242
|
+
# Or pass `true` to include all lazy attributes.
|
243
|
+
# @option [Boolean, Array<String>] :update_lazy_attributes A list of lazy document attributes to bulk update each after the bulk import.
|
244
|
+
# Or pass `true` to update all lazy attributes.
|
245
|
+
# @option [Boolean, Array<String>] :preload_lazy_attributes A list of lazy document attributes to preload using search API before the bulk import.
|
246
|
+
# Or pass `true` to preload all lazy attributes.
|
201
247
|
# @return [Numeric] The number of documents imported
|
202
|
-
def import(*repo_types, context: {},
|
248
|
+
def import(*repo_types, context: {}, eager_load_lazy_attributes: false, update_lazy_attributes: false, preload_lazy_attributes: false, suffix: nil, **options)
|
203
249
|
repo_types = repo_hash.keys if repo_types.empty?
|
204
250
|
count = 0
|
205
251
|
|
252
|
+
if options.key?(:eager_include_document_attributes)
|
253
|
+
warn 'The `eager_include_document_attributes` option is deprecated. Use `eager_load_lazy_attributes` instead.'
|
254
|
+
eager_load_lazy_attributes = options.delete(:eager_include_document_attributes)
|
255
|
+
end
|
256
|
+
if options.key?(:lazy_update_document_attributes)
|
257
|
+
warn 'The `lazy_update_document_attributes` option is deprecated. Use `update_lazy_attributes` instead.'
|
258
|
+
update_lazy_attributes = options.delete(:lazy_update_document_attributes)
|
259
|
+
end
|
260
|
+
|
206
261
|
repo_hash.slice(*repo_types).each do |repo_name, repo|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
262
|
+
# Elasticsearch 6.x and older have multiple types per index.
|
263
|
+
# This gem supports multiple types per index for backward compatibility, but we recommend to update
|
264
|
+
# your elasticsearch to a at least 7.x version and use a single type per index.
|
265
|
+
#
|
266
|
+
# Note that the repository name will be used as the document type.
|
267
|
+
# mapping_default_type
|
268
|
+
bulk_kwargs = { suffix: suffix, type: repo_name, **options }
|
269
|
+
cluster.may_update_type!(bulk_kwargs)
|
211
270
|
|
212
271
|
context ||= {}
|
213
|
-
context[:
|
272
|
+
context[:eager_load_lazy_attributes] = eager_load_lazy_attributes
|
273
|
+
context[:preload_lazy_attributes] = preload_lazy_attributes
|
214
274
|
repo.each_serialized_batch(**context) do |batch|
|
215
|
-
|
216
|
-
# This gem supports multiple types per index for backward compatibility, but we recommend to update
|
217
|
-
# your elasticsearch to a at least 7.x version and use a single type per index.
|
218
|
-
#
|
219
|
-
# Note that the repository name will be used as the document type.
|
220
|
-
# mapping_default_type
|
221
|
-
kwargs = { suffix: suffix, type: repo_name, **options }
|
222
|
-
cluster.may_update_type!(kwargs)
|
223
|
-
|
224
|
-
bulk(**kwargs, index: batch)
|
275
|
+
bulk(**bulk_kwargs, index: batch)
|
225
276
|
|
226
|
-
|
227
|
-
|
228
|
-
|
277
|
+
if update_lazy_attributes != false
|
278
|
+
attrs = repo.lazy_document_attribute_names(update_lazy_attributes)
|
279
|
+
attrs -= repo.lazy_document_attribute_names(eager_load_lazy_attributes)
|
280
|
+
update_attrs = attrs.each_with_object(Hash.new { |h, k| h[k] = {} }) do |attr_name, memo|
|
281
|
+
filtered_docs = batch.reject do |doc|
|
282
|
+
doc.ignore_on_index? || doc.mutations.key?(attr_name)
|
283
|
+
end
|
284
|
+
next if filtered_docs.empty?
|
229
285
|
|
230
|
-
|
286
|
+
repo.retrieve_lazy_attribute_values(attr_name, filtered_docs).each do |doc, value|
|
287
|
+
memo[doc.doc_header][attr_name] = value
|
288
|
+
end
|
289
|
+
end
|
290
|
+
if update_attrs.any?
|
291
|
+
bulk_update = update_attrs.map do |header, values|
|
292
|
+
header.merge(data: {doc: values})
|
293
|
+
end
|
294
|
+
bulk(**bulk_kwargs, update: bulk_update)
|
295
|
+
end
|
231
296
|
end
|
232
297
|
|
233
298
|
count += batch.size
|
data/lib/esse/index/indices.rb
CHANGED
@@ -69,7 +69,9 @@ module Esse
|
|
69
69
|
cluster.api.delete_index(index: index_name)
|
70
70
|
end
|
71
71
|
if import
|
72
|
-
import(
|
72
|
+
import_kwargs = import.is_a?(Hash) ? import : {}
|
73
|
+
import_kwargs[:refresh] ||= refresh if refresh
|
74
|
+
import(**options, **import_kwargs, suffix: suffix)
|
73
75
|
elsif reindex && (source_indexes = indices_pointing_to_alias).any?
|
74
76
|
reindex_kwargs = reindex.is_a?(Hash) ? reindex : {}
|
75
77
|
reindex_kwargs[:wait_for_completion] = true unless reindex_kwargs.key?(:wait_for_completion)
|
@@ -24,7 +24,7 @@ module Esse
|
|
24
24
|
# @return [Enumerator] All serialized entries
|
25
25
|
def documents(repo_name = nil, **kwargs)
|
26
26
|
Enumerator.new do |yielder|
|
27
|
-
each_serialized_batch(repo_name, **kwargs) do |documents
|
27
|
+
each_serialized_batch(repo_name, **kwargs) do |documents|
|
28
28
|
documents.each { |document| yielder.yield(document) }
|
29
29
|
end
|
30
30
|
end
|
@@ -2,11 +2,19 @@
|
|
2
2
|
|
3
3
|
module Esse
|
4
4
|
class LazyDocumentHeader
|
5
|
+
ACCEPTABLE_CLASSES = [Esse::LazyDocumentHeader, Esse::Document].freeze
|
6
|
+
ACCEPTABLE_DOC_TYPES = [nil, '_doc', 'doc'].freeze
|
7
|
+
|
5
8
|
def self.coerce_each(values)
|
9
|
+
values = Esse::ArrayUtils.wrap(values)
|
10
|
+
return values if values.all? do |value|
|
11
|
+
ACCEPTABLE_CLASSES.any? { |klass| value.is_a?(klass) }
|
12
|
+
end
|
13
|
+
|
6
14
|
arr = []
|
7
|
-
|
15
|
+
values.flatten.map do |value|
|
8
16
|
instance = coerce(value)
|
9
|
-
arr << instance if instance
|
17
|
+
arr << instance if instance && !instance.id.nil?
|
10
18
|
end
|
11
19
|
arr
|
12
20
|
end
|
@@ -17,57 +25,61 @@ module Esse
|
|
17
25
|
if value.is_a?(Esse::LazyDocumentHeader)
|
18
26
|
value
|
19
27
|
elsif value.is_a?(Esse::Document)
|
20
|
-
|
28
|
+
value
|
21
29
|
elsif value.is_a?(Hash)
|
22
30
|
resp = value.transform_keys do |key|
|
23
31
|
case key
|
24
32
|
when :_id, :id, '_id', 'id'
|
25
|
-
:
|
33
|
+
:id
|
26
34
|
when :_routing, :routing, '_routing', 'routing'
|
27
35
|
:routing
|
28
36
|
when :_type, :type, '_type', 'type'
|
29
|
-
:
|
37
|
+
:type
|
30
38
|
else
|
31
39
|
key.to_sym
|
32
40
|
end
|
33
41
|
end
|
34
|
-
|
42
|
+
resp[:id] ||= nil
|
43
|
+
new(**resp)
|
35
44
|
elsif String === value || Integer === value
|
36
|
-
new(
|
45
|
+
new(id: value)
|
37
46
|
end
|
38
47
|
end
|
39
48
|
|
40
|
-
|
41
|
-
@attributes = attributes
|
42
|
-
end
|
49
|
+
attr_reader :id, :type, :routing, :options
|
43
50
|
|
44
|
-
def
|
45
|
-
|
51
|
+
def initialize(id:, type: nil, routing: nil, **extra_attributes)
|
52
|
+
@id = id
|
53
|
+
@type = type
|
54
|
+
@routing = routing
|
55
|
+
@options = extra_attributes.freeze
|
46
56
|
end
|
47
57
|
|
48
58
|
def to_h
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
@attributes.fetch(:_id)
|
54
|
-
end
|
55
|
-
|
56
|
-
def type
|
57
|
-
@attributes[:_type]
|
59
|
+
options.merge(_id: id).tap do |hash|
|
60
|
+
hash[:_type] = type if type
|
61
|
+
hash[:routing] = routing if routing
|
62
|
+
end
|
58
63
|
end
|
59
64
|
|
60
|
-
def
|
61
|
-
|
65
|
+
def document_for_partial_update(source)
|
66
|
+
Esse::DocumentForPartialUpdate.new(self, source: source)
|
62
67
|
end
|
63
68
|
|
64
|
-
def
|
65
|
-
|
69
|
+
def doc_header
|
70
|
+
{ _id: id }.tap do |hash|
|
71
|
+
hash[:_type] = type if type
|
72
|
+
hash[:routing] = routing if routing
|
73
|
+
end
|
66
74
|
end
|
67
75
|
|
68
|
-
def eql?(other)
|
69
|
-
|
76
|
+
def eql?(other, **)
|
77
|
+
ACCEPTABLE_CLASSES.any? { |klass| other.is_a?(klass) } &&
|
78
|
+
id.to_s == other.id.to_s &&
|
79
|
+
routing == other.routing &&
|
80
|
+
((ACCEPTABLE_DOC_TYPES.include?(type) && ACCEPTABLE_DOC_TYPES.include?(other.type)) || type == other.type)
|
70
81
|
end
|
71
82
|
alias_method :==, :eql?
|
72
83
|
end
|
73
84
|
end
|
85
|
+
|
@@ -16,7 +16,7 @@ module Esse
|
|
16
16
|
|
17
17
|
def documents_for_lazy_attribute(name, ids_or_doc_headers)
|
18
18
|
retrieve_lazy_attribute_values(name, ids_or_doc_headers).map do |doc_header, datum|
|
19
|
-
doc_header.
|
19
|
+
doc_header.document_for_partial_update(name => datum)
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -36,11 +36,10 @@ module Esse
|
|
36
36
|
return [] unless result.is_a?(Hash)
|
37
37
|
|
38
38
|
result.each_with_object({}) do |(key, value), memo|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
end
|
39
|
+
val = docs.find { |doc| doc.eql?(key, match_lazy_doc_header: true) || doc.id == key }
|
40
|
+
next unless val
|
41
|
+
|
42
|
+
memo[val] = value
|
44
43
|
end
|
45
44
|
end
|
46
45
|
end
|
@@ -69,27 +69,65 @@ module Esse
|
|
69
69
|
@collection_proc = collection_klass || block
|
70
70
|
end
|
71
71
|
|
72
|
+
# Expose the collection class to let external plugins and extensions to access it.
|
73
|
+
# @return [Class, nil] The collection class
|
74
|
+
# IDEA: When collection is defined as a block, it should setup a class with the block content.
|
75
|
+
def collection_class
|
76
|
+
return unless @collection_proc.is_a?(Class)
|
77
|
+
|
78
|
+
@collection_proc
|
79
|
+
end
|
80
|
+
|
72
81
|
# Wrap collection data into serialized batches
|
73
82
|
#
|
74
83
|
# @param [Hash] kwargs The context
|
75
84
|
# @return [Enumerator] The enumerator
|
76
85
|
# @yield [Array, **context] serialized collection and the optional context from the collection
|
77
|
-
def each_serialized_batch(
|
86
|
+
def each_serialized_batch(eager_load_lazy_attributes: false, preload_lazy_attributes: false, **kwargs)
|
87
|
+
if kwargs.key?(:lazy_attributes)
|
88
|
+
warn 'The `lazy_attributes` option is deprecated. Use `eager_load_lazy_attributes` instead.'
|
89
|
+
eager_load_lazy_attributes = kwargs.delete(:lazy_attributes)
|
90
|
+
end
|
91
|
+
|
92
|
+
lazy_attrs_to_eager_load = lazy_document_attribute_names(eager_load_lazy_attributes)
|
93
|
+
lazy_attrs_to_search_preload = lazy_document_attribute_names(preload_lazy_attributes)
|
94
|
+
lazy_attrs_to_search_preload -= lazy_attrs_to_eager_load
|
95
|
+
|
78
96
|
each_batch(**kwargs) do |*args|
|
79
97
|
batch, collection_context = args
|
80
98
|
collection_context ||= {}
|
81
99
|
entries = [*batch].map { |entry| serialize(entry, **collection_context) }.compact
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
100
|
+
lazy_attrs_to_eager_load.each do |attr_name|
|
101
|
+
retrieve_lazy_attribute_values(attr_name, entries).each do |doc_header, value|
|
102
|
+
doc = entries.find { |d| d.eql?(doc_header, match_lazy_doc_header: true) }
|
103
|
+
doc&.mutate(attr_name) { value }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
if lazy_attrs_to_search_preload.any?
|
108
|
+
entries.group_by(&:routing).each do |routing, docs|
|
109
|
+
search_request = {
|
110
|
+
query: { ids: { values: docs.map(&:id) } },
|
111
|
+
size: docs.size,
|
112
|
+
_source: lazy_attrs_to_search_preload
|
113
|
+
}
|
114
|
+
search_request[:routing] = routing if routing
|
115
|
+
index.search(**search_request).response.hits.each do |hit|
|
116
|
+
header = [hit['_id'], hit['_routing'], hit['_type']]
|
117
|
+
next if header[0].nil?
|
118
|
+
|
119
|
+
hit.dig('_source')&.each do |attr_name, attr_value|
|
120
|
+
real_attr_name = lazy_document_attribute_names(attr_name).first
|
121
|
+
next if real_attr_name.nil?
|
122
|
+
|
123
|
+
doc = entries.find { |d| Esse.document_match_with_header?(d, *header) }
|
124
|
+
doc&.mutate(real_attr_name) { attr_value }
|
125
|
+
end
|
88
126
|
end
|
89
127
|
end
|
90
128
|
end
|
91
129
|
|
92
|
-
yield entries
|
130
|
+
yield entries
|
93
131
|
end
|
94
132
|
end
|
95
133
|
|
@@ -101,7 +139,7 @@ module Esse
|
|
101
139
|
# @return [Enumerator] All serialized entries
|
102
140
|
def documents(**kwargs)
|
103
141
|
Enumerator.new do |yielder|
|
104
|
-
each_serialized_batch(**kwargs) do |docs
|
142
|
+
each_serialized_batch(**kwargs) do |docs|
|
105
143
|
docs.each { |document| yielder.yield(document) }
|
106
144
|
end
|
107
145
|
end
|
data/lib/esse/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: esse
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marcos G. Zimmermann
|
8
8
|
autorequire:
|
9
9
|
bindir: exec
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-08-
|
11
|
+
date: 2024-08-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: multi_json
|
@@ -248,6 +248,7 @@ files:
|
|
248
248
|
- lib/esse/deprecations/repository_backend_delegator.rb
|
249
249
|
- lib/esse/deprecations/serializer.rb
|
250
250
|
- lib/esse/document.rb
|
251
|
+
- lib/esse/document_for_partial_update.rb
|
251
252
|
- lib/esse/document_lazy_attribute.rb
|
252
253
|
- lib/esse/dynamic_template.rb
|
253
254
|
- lib/esse/errors.rb
|
@@ -318,9 +319,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
318
319
|
version: 2.3.0
|
319
320
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
320
321
|
requirements:
|
321
|
-
- - "
|
322
|
+
- - ">"
|
322
323
|
- !ruby/object:Gem::Version
|
323
|
-
version:
|
324
|
+
version: 1.3.1
|
324
325
|
requirements: []
|
325
326
|
rubygems_version: 3.0.3.1
|
326
327
|
signing_key:
|