esse 0.3.5 → 0.4.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b6c9d974dbe345e36fc5b8f286185735377309176016d9662900cec7510dd788
4
- data.tar.gz: 01ad7d8d5ee1d849e0dc67cdf1c812c7c44aa686e8b71af5f85137c75e911842
3
+ metadata.gz: f6023e2f4fe6b5d8e45dd09e7c98bb250d8862ea3adc769f119011efc07191c5
4
+ data.tar.gz: 852a46c60435d7c0848254d6b79a4a29ee89efe9e0700975d7d651660ad874d8
5
5
  SHA512:
6
- metadata.gz: b67855b65130b69443a88fe5f033c5437066f84b3ee377169c3ecb8f10c336b1f58e02751aa7fda5393eab308fbd022cc440465cfaa759a29fc943cdc85dc2b3
7
- data.tar.gz: c509f2960292c11144a0092befd0fd8c074faa341b0d4ffb028eb9819561fbf28d5af07c388b7712dcc7e576214fa679c009cd54757d364ca967674de643dedd
6
+ metadata.gz: 40b5c6d0ed7ff8ce793cd8be088c01f9377c62cf58366b201c8ee988f04e9f2f3e53118a48c165857394dc100c26fd06b300d653f2afdead076430d19210c554
7
+ data.tar.gz: f3b4f4acadea569ef1108c1d3d3a2745c965177c29f307e5076357d89aec1f050f778933a350ccb75c0128a295d0f1349899452ea041551fae8ae574fb75793d
@@ -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 :eager_include_document_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'
101
- option :lazy_update_document_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'
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
- opts.delete(:lazy_update_document_attributes) if opts[:lazy_update_document_attributes] == 'false'
106
- opts.delete(:eager_include_document_attributes) if opts[:eager_include_document_attributes] == 'false'
107
- if (val = opts[:eager_include_document_attributes])
108
- opts[:eager_include_document_attributes] = (val == 'true') ? true : val.split(',')
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 ==(other)
88
- other.is_a?(self.class) && (
89
- id == other.id && type == other.type && routing == other.routing && meta == other.meta && source == other.source
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
- protected
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
@@ -1,27 +1,35 @@
1
1
  module Esse
2
2
  module Import
3
3
  class Bulk
4
- def initialize(type: nil, index: nil, delete: nil, create: nil, update: nil)
5
- @index = Array(index).select(&method(:valid_doc?)).reject(&:ignore_on_index?).map do |doc|
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
- { index: value }
8
+ value
9
9
  end
10
- @create = Array(create).select(&method(:valid_doc?)).reject(&:ignore_on_index?).map do |doc|
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
- { create: value }
13
+ value
14
14
  end
15
- @update = Array(update).select(&method(:valid_doc?)).reject(&:ignore_on_index?).map do |doc|
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
- { update: value }
18
+ value
19
19
  end
20
- @delete = Array(delete).select(&method(:valid_doc?)).reject(&:ignore_on_delete?).map do |doc|
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
- { delete: value }
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
@@ -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.source }
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.source
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
- **definition.slice(:type),
177
- create: create,
178
- delete: delete,
179
- index: index,
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: {}, eager_include_document_attributes: false, lazy_update_document_attributes: false, suffix: nil, **options)
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
- doc_attrs = {eager: [], lazy: []}
208
- doc_attrs[:eager] = repo.lazy_document_attribute_names(eager_include_document_attributes)
209
- doc_attrs[:lazy] = repo.lazy_document_attribute_names(lazy_update_document_attributes)
210
- doc_attrs[:lazy] -= doc_attrs[:eager]
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[:lazy_attributes] = doc_attrs[:eager] if doc_attrs[:eager].any?
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
- # Elasticsearch 6.x and older have multiple types per index.
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
- doc_attrs[:lazy].each do |attr_name|
227
- partial_docs = repo.documents_for_lazy_attribute(attr_name, batch.reject(&:ignore_on_index?))
228
- next if partial_docs.empty?
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
- bulk(**kwargs, update: partial_docs)
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
@@ -69,7 +69,9 @@ module Esse
69
69
  cluster.api.delete_index(index: index_name)
70
70
  end
71
71
  if import
72
- import(**options, suffix: suffix, refresh: refresh)
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, **_collection_kargs|
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
- Esse::ArrayUtils.wrap(values).map do |value|
15
+ values.flatten.map do |value|
8
16
  instance = coerce(value)
9
- arr << instance if instance&.valid?
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
- new(value.doc_header)
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
- :_id
33
+ :id
26
34
  when :_routing, :routing, '_routing', 'routing'
27
35
  :routing
28
36
  when :_type, :type, '_type', 'type'
29
- :_type
37
+ :type
30
38
  else
31
39
  key.to_sym
32
40
  end
33
41
  end
34
- new(resp)
42
+ resp[:id] ||= nil
43
+ new(**resp)
35
44
  elsif String === value || Integer === value
36
- new(_id: value)
45
+ new(id: value)
37
46
  end
38
47
  end
39
48
 
40
- def initialize(attributes)
41
- @attributes = attributes
42
- end
49
+ attr_reader :id, :type, :routing, :options
43
50
 
44
- def valid?
45
- !@attributes[:_id].nil?
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
- @attributes
50
- end
51
-
52
- def id
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 routing
61
- @attributes[:routing]
65
+ def document_for_partial_update(source)
66
+ Esse::DocumentForPartialUpdate.new(self, source: source)
62
67
  end
63
68
 
64
- def to_doc(source = {})
65
- HashDocument.new(source.merge(@attributes))
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
- self.class == other.class && @attributes == other.instance_variable_get(:@attributes)
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.to_doc(name => datum)
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
- if key.is_a?(LazyDocumentHeader) && (doc = docs.find { |d| d == key || d.id == key.id })
40
- memo[doc] = value
41
- elsif (doc = docs.find { |d| d.id == key })
42
- memo[doc] = value
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(lazy_attributes: false, **kwargs)
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
- if lazy_attributes
83
- attrs = lazy_attributes.is_a?(Array) ? lazy_attributes : lazy_document_attribute_names(lazy_attributes)
84
- attrs.each do |attr_name|
85
- retrieve_lazy_attribute_values(attr_name, entries).each do |doc_header, value|
86
- doc = entries.find { |d| doc_header.id.to_s == d.id.to_s && doc_header.type == d.type && doc_header.routing == d.routing }
87
- doc&.mutate(attr_name) { value }
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, **kwargs
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, **_collection_kargs|
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Esse
4
- VERSION = '0.3.5'
4
+ VERSION = '0.4.0.rc1'
5
5
  end
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.3.5
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-02 00:00:00.000000000 Z
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: '0'
324
+ version: 1.3.1
324
325
  requirements: []
325
326
  rubygems_version: 3.0.3.1
326
327
  signing_key: