serega 0.11.1 → 0.12.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/README.md +62 -13
- data/VERSION +1 -1
- data/lib/serega/attribute.rb +9 -4
- data/lib/serega/attribute_normalizer.rb +4 -13
- data/lib/serega/object_serializer.rb +11 -0
- data/lib/serega/plan.rb +20 -25
- data/lib/serega/plan_point.rb +13 -16
- data/lib/serega/plugins/batch/batch.rb +7 -245
- data/lib/serega/plugins/batch/lib/batch_config.rb +82 -0
- data/lib/serega/plugins/batch/lib/loader.rb +25 -7
- data/lib/serega/plugins/batch/lib/modules/attribute.rb +26 -0
- data/lib/serega/plugins/batch/lib/modules/attribute_normalizer.rb +65 -0
- data/lib/serega/plugins/batch/lib/modules/check_attribute_params.rb +22 -0
- data/lib/serega/plugins/batch/lib/modules/config.rb +23 -0
- data/lib/serega/plugins/batch/lib/modules/object_serializer.rb +46 -0
- data/lib/serega/plugins/batch/lib/modules/plan_point.rb +39 -0
- data/lib/serega/plugins/metadata/metadata.rb +5 -0
- data/lib/serega/plugins/preloads/lib/modules/attribute.rb +28 -0
- data/lib/serega/plugins/preloads/lib/modules/attribute_normalizer.rb +99 -0
- data/lib/serega/plugins/preloads/lib/modules/check_attribute_params.rb +22 -0
- data/lib/serega/plugins/preloads/lib/modules/config.rb +19 -0
- data/lib/serega/plugins/preloads/lib/modules/plan_point.rb +41 -0
- data/lib/serega/plugins/preloads/lib/preload_paths.rb +46 -0
- data/lib/serega/plugins/preloads/lib/preloads_config.rb +62 -0
- data/lib/serega/plugins/preloads/lib/preloads_constructor.rb +20 -7
- data/lib/serega/plugins/preloads/preloads.rb +12 -210
- data/lib/serega/plugins/preloads/validations/check_opt_preload_path.rb +54 -15
- metadata +16 -3
- data/lib/serega/plugins/preloads/lib/main_preload_path.rb +0 -53
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 52535c7fab3897f65aec4e156ab5681e8595b4519df1e79a777688cee486a480
|
4
|
+
data.tar.gz: 16adbd9f036b0e23928049df873966f264db1004d2c4c1bc9e28422d687efd12
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 93a6aaefdf954556e31bd604ead1e376d5ffbb74225251e635bf5133af53da26f47e924f1f88349fa4656e228ddca573347d9f8fa15cc30bc6052f7e5dfec3bd
|
7
|
+
data.tar.gz: c84135d04c79aae1ccd03a3f3ac7dbed53dbf75165575afbb61ad6e32a558318cac2a8311c31b76df90fb74823facdf4677821d8f7ae8284f04782d33b04ad41
|
data/README.md
CHANGED
@@ -415,30 +415,79 @@ UserSerializer.new(
|
|
415
415
|
```
|
416
416
|
|
417
417
|
---
|
418
|
-
One tricky case, that you will probably never see in real life:
|
419
418
|
|
420
|
-
|
419
|
+
#### SPECIFIC CASE #1: Serializing same object as association
|
420
|
+
|
421
|
+
For example you decided to show your current user as "user" and "user_stats".
|
422
|
+
Where stats rely on user fields and some other associations.
|
423
|
+
You should specify `preload: nil` to preload nested associations, if any, to "user".
|
421
424
|
|
422
425
|
```ruby
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
426
|
+
class AppSerializer < Serega
|
427
|
+
plugin :preloads,
|
428
|
+
auto_preload_attributes_with_delegate: true,
|
429
|
+
auto_preload_attributes_with_serializer: true,
|
430
|
+
auto_hide_attributes_with_preload: true
|
431
|
+
end
|
432
|
+
|
433
|
+
class UserSerializer < AppSerializer
|
434
|
+
attribute :username
|
435
|
+
attribute :user_stats,
|
436
|
+
serializer: 'UserStatSerializer'
|
437
|
+
value: proc { |user| user },
|
438
|
+
preload: nil
|
439
|
+
end
|
427
440
|
```
|
428
441
|
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
442
|
+
#### SPECIFIC CASE #2: Serializing multiple associations as single relation
|
443
|
+
|
444
|
+
For example "user" has two relations - "new_profile", "old_profile", and also
|
445
|
+
profiles have "avatar" association. And you decided to serialize profiles in one
|
446
|
+
array. You can specify `preload_path: [[:new_profile], [:old_profile]]` to
|
447
|
+
achieve this:
|
448
|
+
|
449
|
+
```ruby
|
450
|
+
class AppSerializer < Serega
|
451
|
+
plugin :preloads,
|
452
|
+
auto_preload_attributes_with_delegate: true,
|
453
|
+
auto_preload_attributes_with_serializer: true
|
454
|
+
end
|
455
|
+
|
456
|
+
class UserSerializer < AppSerializer
|
457
|
+
attribute :username
|
458
|
+
attribute :profiles,
|
459
|
+
serializer: 'ProfileSerializer',
|
460
|
+
value: proc { |user| [user.new_profile, user.old_profile] },
|
461
|
+
preload: [:new_profile, :old_profile],
|
462
|
+
preload_path: [[:new_profile], [:old_profile]] # <--- like here
|
463
|
+
end
|
464
|
+
|
465
|
+
class ProfileSerializer < AppSerializer
|
466
|
+
attribute :avatar, serializer: 'AvatarSerializer'
|
467
|
+
end
|
468
|
+
|
469
|
+
class AvatarSerializer < AppSerializer
|
470
|
+
end
|
471
|
+
|
472
|
+
UserSerializer.new.preloads
|
473
|
+
# => {:new_profile=>{:avatar=>{}}, :old_profile=>{:avatar=>{}}}
|
474
|
+
```
|
475
|
+
|
476
|
+
#### SPECIFIC CASE #3: Preload association through another association
|
433
477
|
|
434
478
|
```ruby
|
435
479
|
attribute :image,
|
480
|
+
preload: { attachment: :blob }, # <--------- like this one
|
481
|
+
value: proc { |record| record.attachment },
|
436
482
|
serializer: ImageSerializer,
|
437
|
-
|
438
|
-
preload_path: %i[attachment],
|
439
|
-
value: proc { |record| record.attachment }
|
483
|
+
preload_path: [:attachment] # or preload_path: [:attachment, :blob]
|
440
484
|
```
|
441
485
|
|
486
|
+
In this case we don't know if preloads defined in ImageSerializer, should be
|
487
|
+
preloaded to `attachment` or `blob`, so please specify `preload_path` manually.
|
488
|
+
You can specify `preload_path: nil` if you are sure that there are no preloads
|
489
|
+
inside ImageSerializer.
|
490
|
+
|
442
491
|
---
|
443
492
|
|
444
493
|
📌 Plugin `:preloads` only allows to group preloads together in single Hash, but
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.12.0
|
data/lib/serega/attribute.rb
CHANGED
@@ -82,13 +82,18 @@ class Serega
|
|
82
82
|
#
|
83
83
|
# Checks if attribute must be added to serialized response
|
84
84
|
#
|
85
|
-
# @param
|
86
|
-
# @
|
87
|
-
# @
|
85
|
+
# @param modifiers [Hash] Serialization modifiers
|
86
|
+
# @option modifiers [Hash] :only The only attributes to serialize
|
87
|
+
# @option modifiers [Hash] :except Attributes to hide
|
88
|
+
# @option modifiers [Hash] :with Hidden attributes to serialize additionally
|
88
89
|
#
|
89
90
|
# @return [Boolean]
|
90
91
|
#
|
91
|
-
def visible?(
|
92
|
+
def visible?(modifiers)
|
93
|
+
except = modifiers[:except] || FROZEN_EMPTY_HASH
|
94
|
+
only = modifiers[:only] || FROZEN_EMPTY_HASH
|
95
|
+
with = modifiers[:with] || FROZEN_EMPTY_HASH
|
96
|
+
|
92
97
|
return false if except.member?(name) && except[name].empty?
|
93
98
|
return true if only.member?(name)
|
94
99
|
return true if with.member?(name)
|
@@ -107,6 +107,7 @@ class Serega
|
|
107
107
|
#
|
108
108
|
# Patched in:
|
109
109
|
# - plugin :preloads (returns true by default if config option auto_hide_attribute_with_preloads is enabled)
|
110
|
+
# - plugin :batch (returns true by default if auto_hide option was set and attribute has batch loader)
|
110
111
|
#
|
111
112
|
def prepare_hide
|
112
113
|
init_opts[:hide]
|
@@ -135,7 +136,7 @@ class Serega
|
|
135
136
|
def prepare_keyword_block
|
136
137
|
key_method_name = key
|
137
138
|
proc do |object|
|
138
|
-
|
139
|
+
object.public_send(key_method_name)
|
139
140
|
end
|
140
141
|
end
|
141
142
|
|
@@ -150,24 +151,14 @@ class Serega
|
|
150
151
|
|
151
152
|
if allow_nil
|
152
153
|
proc do |object|
|
153
|
-
|
154
|
-
object.public_send(delegate_to)&.public_send(key_method_name)
|
155
|
-
end
|
154
|
+
object.public_send(delegate_to)&.public_send(key_method_name)
|
156
155
|
end
|
157
156
|
else
|
158
157
|
proc do |object|
|
159
|
-
|
160
|
-
object.public_send(delegate_to).public_send(key_method_name)
|
161
|
-
end
|
158
|
+
object.public_send(delegate_to).public_send(key_method_name)
|
162
159
|
end
|
163
160
|
end
|
164
161
|
end
|
165
|
-
|
166
|
-
def handle_no_method_error
|
167
|
-
yield
|
168
|
-
rescue NoMethodError => error
|
169
|
-
raise error, "NoMethodError when serializing '#{name}' attribute in #{self.class.serializer_class}\n\n#{error.message}", error.backtrace
|
170
|
-
end
|
171
162
|
end
|
172
163
|
|
173
164
|
extend Serega::SeregaHelpers::SerializerClassHelper
|
@@ -47,6 +47,10 @@ class Serega
|
|
47
47
|
def serialize_object(object)
|
48
48
|
plan.points.each_with_object({}) do |point, container|
|
49
49
|
serialize_point(object, point, container)
|
50
|
+
rescue SeregaError
|
51
|
+
raise
|
52
|
+
rescue => error
|
53
|
+
reraise_with_serialized_attribute_details(error, point)
|
50
54
|
end
|
51
55
|
end
|
52
56
|
|
@@ -85,6 +89,13 @@ class Serega
|
|
85
89
|
def array?(object, many)
|
86
90
|
many.nil? ? object.is_a?(Enumerable) : many
|
87
91
|
end
|
92
|
+
|
93
|
+
def reraise_with_serialized_attribute_details(error, point)
|
94
|
+
raise error.exception(<<~MESSAGE.strip)
|
95
|
+
#{error.message}
|
96
|
+
(when serializing '#{point.name}' attribute in #{self.class.serializer_class})
|
97
|
+
MESSAGE
|
98
|
+
end
|
88
99
|
end
|
89
100
|
|
90
101
|
extend Serega::SeregaHelpers::SerializerClassHelper
|
data/lib/serega/plan.rb
CHANGED
@@ -22,34 +22,22 @@ class Serega
|
|
22
22
|
#
|
23
23
|
def call(opts)
|
24
24
|
max_cache_size = serializer_class.config.max_cached_plans_per_serializer_count
|
25
|
-
return
|
25
|
+
return new(opts) if max_cache_size.zero?
|
26
26
|
|
27
27
|
cached_plan_for(opts, max_cache_size)
|
28
28
|
end
|
29
29
|
|
30
30
|
private
|
31
31
|
|
32
|
-
def plan_for(opts)
|
33
|
-
new(**modifiers(opts))
|
34
|
-
end
|
35
|
-
|
36
32
|
def cached_plan_for(opts, max_cache_size)
|
37
33
|
@cache ||= {}
|
38
34
|
cache_key = construct_cache_key(opts)
|
39
35
|
|
40
|
-
plan = @cache[cache_key] ||=
|
36
|
+
plan = @cache[cache_key] ||= new(opts)
|
41
37
|
@cache.shift if @cache.length > max_cache_size
|
42
38
|
plan
|
43
39
|
end
|
44
40
|
|
45
|
-
def modifiers(opts)
|
46
|
-
{
|
47
|
-
only: opts[:only] || FROZEN_EMPTY_HASH,
|
48
|
-
except: opts[:except] || FROZEN_EMPTY_HASH,
|
49
|
-
with: opts[:with] || FROZEN_EMPTY_HASH
|
50
|
-
}
|
51
|
-
end
|
52
|
-
|
53
41
|
def construct_cache_key(opts, cache_key = nil)
|
54
42
|
return nil if opts.empty?
|
55
43
|
|
@@ -69,10 +57,14 @@ class Serega
|
|
69
57
|
# SeregaPlan instance methods
|
70
58
|
#
|
71
59
|
module InstanceMethods
|
72
|
-
# Parent plan point
|
60
|
+
# Parent plan point
|
73
61
|
# @return [SeregaPlanPoint, nil]
|
74
62
|
attr_reader :parent_plan_point
|
75
63
|
|
64
|
+
# Sets new parent plan point
|
65
|
+
# @return [SeregaPlanPoint] new parent plan point
|
66
|
+
attr_writer :parent_plan_point
|
67
|
+
|
76
68
|
# Serialization points
|
77
69
|
# @return [Array<SeregaPlanPoint>] points to serialize
|
78
70
|
attr_reader :points
|
@@ -80,17 +72,15 @@ class Serega
|
|
80
72
|
#
|
81
73
|
# Instantiate new serialization plan.
|
82
74
|
#
|
83
|
-
# @param
|
84
|
-
# @option
|
85
|
-
# @option
|
86
|
-
# @option
|
87
|
-
# @option opts [Hash] :with Attributes (usually marked hide: true`) to serialize additionally
|
75
|
+
# @param modifiers Serialization parameters
|
76
|
+
# @option modifiers [Hash] :only The only attributes to serialize
|
77
|
+
# @option modifiers [Hash] :except Attributes to hide
|
78
|
+
# @option modifiers [Hash] :with Hidden attributes to serialize additionally
|
88
79
|
#
|
89
80
|
# @return [SeregaPlan] Serialization plan
|
90
81
|
#
|
91
|
-
def initialize(
|
92
|
-
@
|
93
|
-
@points = attributes_points(only: only, except: except, with: with)
|
82
|
+
def initialize(modifiers)
|
83
|
+
@points = attributes_points(modifiers)
|
94
84
|
end
|
95
85
|
|
96
86
|
#
|
@@ -102,7 +92,10 @@ class Serega
|
|
102
92
|
|
103
93
|
private
|
104
94
|
|
105
|
-
def attributes_points(
|
95
|
+
def attributes_points(modifiers)
|
96
|
+
only = modifiers[:only] || FROZEN_EMPTY_HASH
|
97
|
+
except = modifiers[:except] || FROZEN_EMPTY_HASH
|
98
|
+
with = modifiers[:with] || FROZEN_EMPTY_HASH
|
106
99
|
points = []
|
107
100
|
|
108
101
|
serializer_class.attributes.each_value do |attribute|
|
@@ -114,7 +107,9 @@ class Serega
|
|
114
107
|
{only: only[name], with: with[name], except: except[name]}
|
115
108
|
end
|
116
109
|
|
117
|
-
|
110
|
+
point = serializer_class::SeregaPlanPoint.new(attribute, child_fields)
|
111
|
+
point.plan = self
|
112
|
+
points << point.freeze
|
118
113
|
end
|
119
114
|
|
120
115
|
points.freeze
|
data/lib/serega/plan_point.rb
CHANGED
@@ -13,7 +13,7 @@ class Serega
|
|
13
13
|
|
14
14
|
# Link to current plan this point belongs to
|
15
15
|
# @return [SeregaAttribute] Current plan
|
16
|
-
|
16
|
+
attr_accessor :plan
|
17
17
|
|
18
18
|
# Shows current attribute
|
19
19
|
# @return [SeregaAttribute] Current attribute
|
@@ -24,8 +24,8 @@ class Serega
|
|
24
24
|
attr_reader :child_plan
|
25
25
|
|
26
26
|
# Child fields to serialize
|
27
|
-
# @return [
|
28
|
-
attr_reader :
|
27
|
+
# @return [Hash] Attributes to serialize
|
28
|
+
attr_reader :modifiers
|
29
29
|
|
30
30
|
# @!method name
|
31
31
|
# Attribute `name`
|
@@ -44,18 +44,18 @@ class Serega
|
|
44
44
|
#
|
45
45
|
# Initializes plan point
|
46
46
|
#
|
47
|
-
# @param plan [SeregaPlan] Plan where this point belongs to.
|
48
47
|
# @param attribute [SeregaAttribute] Attribute to construct plan point
|
49
|
-
# @param
|
48
|
+
# @param modifiers Serialization parameters
|
49
|
+
# @option modifiers [Hash] :only The only attributes to serialize
|
50
|
+
# @option modifiers [Hash] :except Attributes to hide
|
51
|
+
# @option modifiers [Hash] :with Hidden attributes to serialize additionally
|
50
52
|
#
|
51
53
|
# @return [SeregaPlanPoint] New plan point
|
52
54
|
#
|
53
|
-
def initialize(attribute,
|
54
|
-
@plan = plan
|
55
|
+
def initialize(attribute, modifiers = nil)
|
55
56
|
@attribute = attribute
|
56
|
-
@
|
57
|
+
@modifiers = modifiers
|
57
58
|
set_normalized_vars
|
58
|
-
freeze
|
59
59
|
end
|
60
60
|
|
61
61
|
#
|
@@ -77,14 +77,11 @@ class Serega
|
|
77
77
|
def prepare_child_plan
|
78
78
|
return unless serializer
|
79
79
|
|
80
|
-
fields =
|
80
|
+
fields = modifiers || FROZEN_EMPTY_HASH
|
81
81
|
|
82
|
-
serializer::SeregaPlan.new(
|
83
|
-
|
84
|
-
|
85
|
-
with: fields[:with] || FROZEN_EMPTY_HASH,
|
86
|
-
except: fields[:except] || FROZEN_EMPTY_HASH
|
87
|
-
)
|
82
|
+
plan = serializer::SeregaPlan.new(fields)
|
83
|
+
plan.parent_plan_point = self
|
84
|
+
plan
|
88
85
|
end
|
89
86
|
end
|
90
87
|
|
@@ -79,8 +79,15 @@ class Serega
|
|
79
79
|
# @return [void]
|
80
80
|
#
|
81
81
|
def self.load_plugin(serializer_class, **_opts)
|
82
|
+
require_relative "./lib/batch_config"
|
82
83
|
require_relative "./lib/loader"
|
83
84
|
require_relative "./lib/loaders"
|
85
|
+
require_relative "./lib/modules/attribute"
|
86
|
+
require_relative "./lib/modules/attribute_normalizer"
|
87
|
+
require_relative "./lib/modules/check_attribute_params"
|
88
|
+
require_relative "./lib/modules/config"
|
89
|
+
require_relative "./lib/modules/object_serializer"
|
90
|
+
require_relative "./lib/modules/plan_point"
|
84
91
|
require_relative "./lib/validations/check_batch_opt_key"
|
85
92
|
require_relative "./lib/validations/check_batch_opt_loader"
|
86
93
|
require_relative "./lib/validations/check_opt_batch"
|
@@ -136,97 +143,6 @@ class Serega
|
|
136
143
|
config.batch.default_key = opts[:default_key] if opts.key?(:default_key)
|
137
144
|
end
|
138
145
|
|
139
|
-
#
|
140
|
-
# Batch loader config
|
141
|
-
#
|
142
|
-
class BatchConfig
|
143
|
-
attr_reader :opts
|
144
|
-
|
145
|
-
def initialize(opts)
|
146
|
-
@opts = opts
|
147
|
-
end
|
148
|
-
|
149
|
-
#
|
150
|
-
# Defines batch loader
|
151
|
-
#
|
152
|
-
# @param loader_name [Symbol] Batch loader name, that is used when defining attribute with batch loader.
|
153
|
-
# @param block [Proc] Block that can accept 3 parameters - keys, context, plan_point
|
154
|
-
# and returns hash where ids are keys and values are batch loaded objects/
|
155
|
-
#
|
156
|
-
# @return [void]
|
157
|
-
#
|
158
|
-
def define(loader_name, &block)
|
159
|
-
unless block
|
160
|
-
raise SeregaError, "Block must be given to #define method"
|
161
|
-
end
|
162
|
-
|
163
|
-
params = block.parameters
|
164
|
-
if params.count > 3 || !params.all? { |param| (param[0] == :req) || (param[0] == :opt) }
|
165
|
-
raise SeregaError, "Block can have maximum 3 regular parameters"
|
166
|
-
end
|
167
|
-
|
168
|
-
loaders[loader_name] = block
|
169
|
-
end
|
170
|
-
|
171
|
-
# Shows defined loaders
|
172
|
-
# @return [Hash] defined loaders
|
173
|
-
def loaders
|
174
|
-
opts[:loaders]
|
175
|
-
end
|
176
|
-
|
177
|
-
#
|
178
|
-
# Finds previously defined batch loader by name
|
179
|
-
#
|
180
|
-
# @param loader_name [Symbol]
|
181
|
-
#
|
182
|
-
# @return [Proc] batch loader block
|
183
|
-
def fetch_loader(loader_name)
|
184
|
-
loaders[loader_name] || (raise SeregaError, "Batch loader with name `#{loader_name.inspect}` was not defined. Define example: config.batch.define(:#{loader_name}) { |keys, ctx, points| ... }")
|
185
|
-
end
|
186
|
-
|
187
|
-
# Shows option to auto hide attributes with :batch specified
|
188
|
-
# @return [Boolean, nil] option value
|
189
|
-
def auto_hide
|
190
|
-
opts[:auto_hide]
|
191
|
-
end
|
192
|
-
|
193
|
-
# @param value [Boolean] New :auto_hide option value
|
194
|
-
# @return [Boolean] New option value
|
195
|
-
def auto_hide=(value)
|
196
|
-
raise SeregaError, "Must have boolean value, #{value.inspect} provided" if (value != true) && (value != false)
|
197
|
-
opts[:auto_hide] = value
|
198
|
-
end
|
199
|
-
|
200
|
-
# Shows default key for :batch option
|
201
|
-
# @return [Symbol, nil] default key for :batch option
|
202
|
-
def default_key
|
203
|
-
opts[:default_key]
|
204
|
-
end
|
205
|
-
|
206
|
-
# @param value [Symbol] New :default_key option value
|
207
|
-
# @return [Boolean] New option value
|
208
|
-
def default_key=(value)
|
209
|
-
raise SeregaError, "Must be a Symbol, #{value.inspect} provided" unless value.is_a?(Symbol)
|
210
|
-
opts[:default_key] = value
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
#
|
215
|
-
# Config class additional/patched instance methods
|
216
|
-
#
|
217
|
-
# @see Serega::SeregaConfig
|
218
|
-
#
|
219
|
-
module ConfigInstanceMethods
|
220
|
-
#
|
221
|
-
# Returns all batch loaders registered for current serializer
|
222
|
-
#
|
223
|
-
# @return [Serega::SeregaPlugins::Batch::BatchConfig] configuration for batch loaded attributes
|
224
|
-
#
|
225
|
-
def batch
|
226
|
-
@batch ||= BatchConfig.new(opts.fetch(:batch))
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
146
|
#
|
231
147
|
# Serega class additional/patched class methods
|
232
148
|
#
|
@@ -248,138 +164,6 @@ class Serega
|
|
248
164
|
end
|
249
165
|
end
|
250
166
|
|
251
|
-
#
|
252
|
-
# Serega::SeregaValidations::CheckAttributeParams additional/patched class methods
|
253
|
-
#
|
254
|
-
# @see Serega::SeregaValidations::CheckAttributeParams
|
255
|
-
#
|
256
|
-
module CheckAttributeParamsInstanceMethods
|
257
|
-
private
|
258
|
-
|
259
|
-
def check_opts
|
260
|
-
super
|
261
|
-
|
262
|
-
CheckOptBatch.call(opts, block, self.class.serializer_class)
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
#
|
267
|
-
# Serega::SeregaAttribute additional/patched class methods
|
268
|
-
#
|
269
|
-
# @see Serega::SeregaAttribute
|
270
|
-
#
|
271
|
-
module AttributeInstanceMethods
|
272
|
-
#
|
273
|
-
# @return [nil, Hash] :batch option
|
274
|
-
#
|
275
|
-
attr_reader :batch
|
276
|
-
|
277
|
-
private
|
278
|
-
|
279
|
-
def set_normalized_vars(normalizer)
|
280
|
-
super
|
281
|
-
@batch = normalizer.batch
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
#
|
286
|
-
# SeregaAttributeNormalizer additional/patched instance methods
|
287
|
-
#
|
288
|
-
# @see SeregaAttributeNormalizer::AttributeInstanceMethods
|
289
|
-
#
|
290
|
-
module AttributeNormalizerInstanceMethods
|
291
|
-
#
|
292
|
-
# Returns normalized attribute :batch option with prepared :key and
|
293
|
-
# :default options. Option :loader will be prepared at serialization
|
294
|
-
# time as loaders are usually defined after attributes.
|
295
|
-
#
|
296
|
-
# @return [Hash] attribute :batch normalized options
|
297
|
-
#
|
298
|
-
def batch
|
299
|
-
return @batch if instance_variable_defined?(:@batch)
|
300
|
-
|
301
|
-
@batch = prepare_batch
|
302
|
-
end
|
303
|
-
|
304
|
-
private
|
305
|
-
|
306
|
-
#
|
307
|
-
# Patch for original `prepare_hide` method
|
308
|
-
#
|
309
|
-
# Marks attribute hidden if auto_hide option was set and attribute has batch loader
|
310
|
-
#
|
311
|
-
def prepare_hide
|
312
|
-
res = super
|
313
|
-
return res unless res.nil?
|
314
|
-
|
315
|
-
if batch
|
316
|
-
self.class.serializer_class.config.batch.auto_hide || nil
|
317
|
-
end
|
318
|
-
end
|
319
|
-
|
320
|
-
def prepare_batch
|
321
|
-
batch = init_opts[:batch]
|
322
|
-
return unless batch
|
323
|
-
|
324
|
-
# take loader
|
325
|
-
loader = batch[:loader]
|
326
|
-
|
327
|
-
# take key
|
328
|
-
key = batch[:key] || self.class.serializer_class.config.batch.default_key
|
329
|
-
proc_key =
|
330
|
-
if key.is_a?(Symbol)
|
331
|
-
proc do |object|
|
332
|
-
handle_no_method_error { object.public_send(key) }
|
333
|
-
end
|
334
|
-
else
|
335
|
-
key
|
336
|
-
end
|
337
|
-
|
338
|
-
# take default value
|
339
|
-
default = batch.fetch(:default) { many ? FROZEN_EMPTY_ARRAY : nil }
|
340
|
-
|
341
|
-
{loader: loader, key: proc_key, default: default}
|
342
|
-
end
|
343
|
-
|
344
|
-
def handle_no_method_error
|
345
|
-
yield
|
346
|
-
rescue NoMethodError => error
|
347
|
-
raise error, "NoMethodError when serializing '#{name}' attribute in #{self.class.serializer_class}\n\n#{error.message}", error.backtrace
|
348
|
-
end
|
349
|
-
end
|
350
|
-
|
351
|
-
#
|
352
|
-
# Serega::SeregaPlanPoint additional/patched class methods
|
353
|
-
#
|
354
|
-
# @see SeregaAttribute
|
355
|
-
#
|
356
|
-
module PlanPointInstanceMethods
|
357
|
-
#
|
358
|
-
# Returns attribute :batch option with prepared loader
|
359
|
-
# @return [Hash] attribute :batch option
|
360
|
-
#
|
361
|
-
attr_reader :batch
|
362
|
-
|
363
|
-
private
|
364
|
-
|
365
|
-
def set_normalized_vars
|
366
|
-
super
|
367
|
-
@batch = prepare_batch
|
368
|
-
end
|
369
|
-
|
370
|
-
def prepare_batch
|
371
|
-
batch = attribute.batch
|
372
|
-
if batch
|
373
|
-
loader = batch[:loader]
|
374
|
-
if loader.is_a?(Symbol)
|
375
|
-
batch_config = attribute.class.serializer_class.config.batch
|
376
|
-
batch[:loader] = batch_config.fetch_loader(loader)
|
377
|
-
end
|
378
|
-
end
|
379
|
-
batch
|
380
|
-
end
|
381
|
-
end
|
382
|
-
|
383
167
|
#
|
384
168
|
# Serega additional/patched instance methods
|
385
169
|
#
|
@@ -398,28 +182,6 @@ class Serega
|
|
398
182
|
result
|
399
183
|
end
|
400
184
|
end
|
401
|
-
|
402
|
-
#
|
403
|
-
# SeregaObjectSerializer additional/patched class methods
|
404
|
-
#
|
405
|
-
# @see Serega::SeregaObjectSerializer
|
406
|
-
#
|
407
|
-
module SeregaObjectSerializerInstanceMethods
|
408
|
-
private
|
409
|
-
|
410
|
-
def attach_value(object, point, container)
|
411
|
-
batch = point.batch
|
412
|
-
return super unless batch
|
413
|
-
|
414
|
-
remember_key_for_batch_loading(batch, object, point, container)
|
415
|
-
end
|
416
|
-
|
417
|
-
def remember_key_for_batch_loading(batch, object, point, container)
|
418
|
-
key = batch[:key].call(object, context)
|
419
|
-
opts[:batch_loaders].get(point, self).remember(key, container)
|
420
|
-
container[point.name] = nil # Reserve attribute place in resulted hash. We will set correct value later
|
421
|
-
end
|
422
|
-
end
|
423
185
|
end
|
424
186
|
|
425
187
|
register_plugin(Batch.plugin_name, Batch)
|