serega 0.21.0 → 0.30.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 +113 -229
- data/VERSION +1 -1
- data/lib/serega/attribute.rb +31 -3
- data/lib/serega/attribute_normalizer.rb +143 -42
- data/lib/serega/batch/attribute_loader.rb +70 -0
- data/lib/serega/batch/attribute_loaders.rb +59 -0
- data/lib/serega/batch/auto_resolver.rb +24 -0
- data/lib/serega/batch/auto_resolver_factory.rb +48 -0
- data/lib/serega/batch/loader.rb +67 -0
- data/lib/serega/config.rb +59 -1
- data/lib/serega/object_serializer.rb +11 -9
- data/lib/serega/plan.rb +16 -0
- data/lib/serega/plan_point.rb +31 -5
- data/lib/serega/plugins/activerecord_preloads/activerecord_preloads.rb +25 -13
- data/lib/serega/plugins/activerecord_preloads/lib/active_record_objects.rb +31 -0
- data/lib/serega/plugins/camel_case/camel_case.rb +1 -1
- data/lib/serega/plugins/formatters/formatters.rb +79 -22
- data/lib/serega/plugins/if/if.rb +41 -22
- data/lib/serega/plugins/if/validations/check_opt_if.rb +27 -6
- data/lib/serega/plugins/if/validations/check_opt_if_value.rb +27 -6
- data/lib/serega/plugins/if/validations/check_opt_unless.rb +27 -6
- data/lib/serega/plugins/if/validations/check_opt_unless_value.rb +27 -6
- data/lib/serega/plugins/metadata/meta_attribute.rb +9 -10
- data/lib/serega/plugins/metadata/validations/check_block.rb +2 -4
- data/lib/serega/plugins/metadata/validations/check_opt_value.rb +2 -3
- data/lib/serega/plugins/presenter/presenter.rb +1 -1
- data/lib/serega/utils/format_user_preloads.rb +58 -0
- data/lib/serega/utils/method_signature.rb +89 -0
- data/lib/serega/utils/preload_paths.rb +53 -0
- data/lib/serega/utils/preloads_constructor.rb +77 -0
- data/lib/serega/validations/attribute/check_block.rb +38 -6
- data/lib/serega/validations/attribute/check_opt_batch.rb +101 -0
- data/lib/serega/validations/attribute/check_opt_const.rb +1 -0
- data/lib/serega/validations/attribute/check_opt_delegate.rb +1 -0
- data/lib/serega/validations/attribute/check_opt_method.rb +1 -0
- data/lib/serega/{plugins/preloads/validations → validations/attribute}/check_opt_preload.rb +2 -2
- data/lib/serega/{plugins/preloads/validations → validations/attribute}/check_opt_preload_path.rb +3 -3
- data/lib/serega/validations/attribute/check_opt_value.rb +35 -9
- data/lib/serega/validations/check_attribute_params.rb +3 -2
- data/lib/serega/validations/check_batch_loader_params.rb +80 -0
- data/lib/serega/validations/initiate/check_modifiers.rb +1 -1
- data/lib/serega.rb +98 -7
- metadata +17 -37
- data/lib/serega/plugins/batch/batch.rb +0 -168
- data/lib/serega/plugins/batch/lib/batch_config.rb +0 -77
- data/lib/serega/plugins/batch/lib/loader.rb +0 -113
- data/lib/serega/plugins/batch/lib/loaders.rb +0 -45
- data/lib/serega/plugins/batch/lib/modules/attribute.rb +0 -26
- data/lib/serega/plugins/batch/lib/modules/attribute_normalizer.rb +0 -78
- data/lib/serega/plugins/batch/lib/modules/check_attribute_params.rb +0 -22
- data/lib/serega/plugins/batch/lib/modules/config.rb +0 -23
- data/lib/serega/plugins/batch/lib/modules/object_serializer.rb +0 -46
- data/lib/serega/plugins/batch/lib/modules/plan_point.rb +0 -22
- data/lib/serega/plugins/batch/lib/plugins_extensions/activerecord_preloads.rb +0 -43
- data/lib/serega/plugins/batch/lib/plugins_extensions/formatters.rb +0 -54
- data/lib/serega/plugins/batch/lib/plugins_extensions/if.rb +0 -31
- data/lib/serega/plugins/batch/lib/plugins_extensions/preloads.rb +0 -34
- data/lib/serega/plugins/batch/lib/validations/check_batch_opt_id_method.rb +0 -43
- data/lib/serega/plugins/batch/lib/validations/check_batch_opt_loader.rb +0 -59
- data/lib/serega/plugins/batch/lib/validations/check_opt_batch.rb +0 -62
- data/lib/serega/plugins/preloads/lib/format_user_preloads.rb +0 -60
- data/lib/serega/plugins/preloads/lib/modules/attribute.rb +0 -28
- data/lib/serega/plugins/preloads/lib/modules/attribute_normalizer.rb +0 -99
- data/lib/serega/plugins/preloads/lib/modules/check_attribute_params.rb +0 -22
- data/lib/serega/plugins/preloads/lib/modules/config.rb +0 -19
- data/lib/serega/plugins/preloads/lib/modules/plan_point.rb +0 -41
- data/lib/serega/plugins/preloads/lib/preload_paths.rb +0 -53
- data/lib/serega/plugins/preloads/lib/preloads_config.rb +0 -62
- data/lib/serega/plugins/preloads/lib/preloads_constructor.rb +0 -79
- data/lib/serega/plugins/preloads/preloads.rb +0 -162
- data/lib/serega/utils/params_count.rb +0 -50
- data/lib/serega/validations/utils/check_extra_keyword_arg.rb +0 -33
@@ -71,7 +71,7 @@ class Serega
|
|
71
71
|
|
72
72
|
def build_full_attribute_name(*names)
|
73
73
|
head, *nested = *names
|
74
|
-
result = head.to_s # names are symbols, we need not frozen string
|
74
|
+
result = +head.to_s # names are symbols, we need not frozen string
|
75
75
|
nested.each { |nested_name| result << "(" << nested_name.to_s }
|
76
76
|
nested.each { result << ")" }
|
77
77
|
result
|
data/lib/serega.rb
CHANGED
@@ -17,15 +17,22 @@ require_relative "serega/errors"
|
|
17
17
|
require_relative "serega/helpers/serializer_class_helper"
|
18
18
|
require_relative "serega/utils/enum_deep_dup"
|
19
19
|
require_relative "serega/utils/enum_deep_freeze"
|
20
|
-
require_relative "serega/utils/
|
20
|
+
require_relative "serega/utils/format_user_preloads"
|
21
|
+
require_relative "serega/utils/method_signature"
|
22
|
+
require_relative "serega/utils/preload_paths"
|
23
|
+
require_relative "serega/utils/preloads_constructor"
|
21
24
|
require_relative "serega/utils/symbol_name"
|
22
25
|
require_relative "serega/utils/to_hash"
|
23
26
|
require_relative "serega/json/adapter"
|
24
27
|
|
25
28
|
require_relative "serega/attribute"
|
26
29
|
require_relative "serega/attribute_normalizer"
|
30
|
+
require_relative "serega/batch/attribute_loader"
|
31
|
+
require_relative "serega/batch/attribute_loaders"
|
32
|
+
require_relative "serega/batch/auto_resolver"
|
33
|
+
require_relative "serega/batch/auto_resolver_factory"
|
34
|
+
require_relative "serega/batch/loader"
|
27
35
|
require_relative "serega/validations/utils/check_allowed_keys"
|
28
|
-
require_relative "serega/validations/utils/check_extra_keyword_arg"
|
29
36
|
require_relative "serega/validations/utils/check_opt_is_bool"
|
30
37
|
require_relative "serega/validations/utils/check_opt_is_hash"
|
31
38
|
require_relative "serega/validations/utils/check_opt_is_string_or_symbol"
|
@@ -34,13 +41,17 @@ require_relative "serega/validations/attribute/check_name"
|
|
34
41
|
require_relative "serega/validations/attribute/check_opt_const"
|
35
42
|
require_relative "serega/validations/attribute/check_opt_hide"
|
36
43
|
require_relative "serega/validations/attribute/check_opt_delegate"
|
44
|
+
require_relative "serega/validations/attribute/check_opt_batch"
|
37
45
|
require_relative "serega/validations/attribute/check_opt_many"
|
38
46
|
require_relative "serega/validations/attribute/check_opt_method"
|
47
|
+
require_relative "serega/validations/attribute/check_opt_preload"
|
48
|
+
require_relative "serega/validations/attribute/check_opt_preload_path"
|
39
49
|
require_relative "serega/validations/attribute/check_opt_serializer"
|
40
50
|
require_relative "serega/validations/attribute/check_opt_value"
|
41
51
|
require_relative "serega/validations/initiate/check_modifiers"
|
42
52
|
require_relative "serega/validations/check_attribute_params"
|
43
53
|
require_relative "serega/validations/check_initiate_params"
|
54
|
+
require_relative "serega/validations/check_batch_loader_params"
|
44
55
|
require_relative "serega/validations/check_serialize_params"
|
45
56
|
|
46
57
|
require_relative "serega/config"
|
@@ -67,6 +78,21 @@ class Serega
|
|
67
78
|
check_serialize_params_class.serializer_class = self
|
68
79
|
const_set(:CheckSerializeParams, check_serialize_params_class)
|
69
80
|
|
81
|
+
# Validates `Serializer.batch_loader` params
|
82
|
+
check_batch_loader_params_class = Class.new(SeregaValidations::CheckBatchLoaderParams)
|
83
|
+
check_batch_loader_params_class.serializer_class = self
|
84
|
+
const_set(:CheckBatchLoaderParams, check_batch_loader_params_class)
|
85
|
+
|
86
|
+
# Assigns `SeregaBatchLoader` constant to current class
|
87
|
+
batch_loader_class = Class.new(SeregaBatch::Loader)
|
88
|
+
batch_loader_class.serializer_class = self
|
89
|
+
const_set(:SeregaBatchLoader, batch_loader_class)
|
90
|
+
|
91
|
+
# Assigns `SeregaBatchAttributeLoader` constant to current class
|
92
|
+
batch_attribute_loader_class = Class.new(SeregaBatch::AttributeLoader)
|
93
|
+
batch_attribute_loader_class.serializer_class = self
|
94
|
+
const_set(:SeregaBatchAttributeLoader, batch_attribute_loader_class)
|
95
|
+
|
70
96
|
#
|
71
97
|
# Serializers class methods
|
72
98
|
#
|
@@ -128,6 +154,15 @@ class Serega
|
|
128
154
|
@attributes ||= {}
|
129
155
|
end
|
130
156
|
|
157
|
+
#
|
158
|
+
# Lists batch loaders
|
159
|
+
#
|
160
|
+
# @return [Hash] batch loaders list
|
161
|
+
#
|
162
|
+
def batch_loaders
|
163
|
+
@batch_loaders ||= {}
|
164
|
+
end
|
165
|
+
|
131
166
|
#
|
132
167
|
# Adds attribute
|
133
168
|
#
|
@@ -145,6 +180,41 @@ class Serega
|
|
145
180
|
attributes[attribute.name] = attribute
|
146
181
|
end
|
147
182
|
|
183
|
+
#
|
184
|
+
# Defines a batch loader
|
185
|
+
#
|
186
|
+
# @example
|
187
|
+
# batch_loader :tags, PostTagsLoader
|
188
|
+
#
|
189
|
+
# @example with block
|
190
|
+
# batch_loader(:tags) do |posts|
|
191
|
+
# Tags.where(post: posts).group(:post_id).pluck(:post_id, Arel.sql('ARRAY_AGG(tags.tag ORDER BY tag)')).to_h
|
192
|
+
# end
|
193
|
+
#
|
194
|
+
# attribute :tags, batch: :tags, value: { |post, batch:| batch[:tags][post.id] }
|
195
|
+
#
|
196
|
+
# @example with context
|
197
|
+
# batch_loader(:tags) do |posts, ctx:|
|
198
|
+
# next {} if ctx[:bot]
|
199
|
+
#
|
200
|
+
# Tags.where(post: posts).group(:post_id).pluck(:post_id, Arel.sql('ARRAY_AGG(tags.tag ORDER BY tag)')).to_h
|
201
|
+
# end
|
202
|
+
#
|
203
|
+
# attribute :tags, batch: :tags, value: { |post, batch:| batch[:tags][post.id] }
|
204
|
+
#
|
205
|
+
# @param name [Symbol] A batch loader name
|
206
|
+
# @param value [#call] Batch loader
|
207
|
+
# @param block [Proc] Batch loader
|
208
|
+
#
|
209
|
+
# @return [#call] Batch loader
|
210
|
+
#
|
211
|
+
def batch_loader(name, value = nil, &block)
|
212
|
+
raise SeregaError, "Batch loader must be defined with a callable value or block" if (value && block) || (!value && !block)
|
213
|
+
|
214
|
+
batch_loader = self::SeregaBatchLoader.new(name: name, block: value || block)
|
215
|
+
batch_loaders[batch_loader.name] = batch_loader
|
216
|
+
end
|
217
|
+
|
148
218
|
#
|
149
219
|
# Serializes provided object to Hash
|
150
220
|
#
|
@@ -232,7 +302,6 @@ class Serega
|
|
232
302
|
private
|
233
303
|
|
234
304
|
# Patched in:
|
235
|
-
# - plugin :batch (defines SeregaBatchLoaders, SeregaBatchLoader)
|
236
305
|
# - plugin :metadata (defines MetaAttribute and copies meta_attributes to subclasses)
|
237
306
|
# - plugin :presenter (defines Presenter)
|
238
307
|
def inherited(subclass)
|
@@ -257,6 +326,14 @@ class Serega
|
|
257
326
|
plan_point_class.serializer_class = subclass
|
258
327
|
subclass.const_set(:SeregaPlanPoint, plan_point_class)
|
259
328
|
|
329
|
+
batch_loader_class = Class.new(self::SeregaBatchLoader)
|
330
|
+
batch_loader_class.serializer_class = subclass
|
331
|
+
subclass.const_set(:SeregaBatchLoader, batch_loader_class)
|
332
|
+
|
333
|
+
batch_attribute_loader_class = Class.new(self::SeregaBatchAttributeLoader)
|
334
|
+
batch_attribute_loader_class.serializer_class = subclass
|
335
|
+
subclass.const_set(:SeregaBatchAttributeLoader, batch_attribute_loader_class)
|
336
|
+
|
260
337
|
object_serializer_class = Class.new(self::SeregaObjectSerializer)
|
261
338
|
object_serializer_class.serializer_class = subclass
|
262
339
|
subclass.const_set(:SeregaObjectSerializer, object_serializer_class)
|
@@ -273,12 +350,21 @@ class Serega
|
|
273
350
|
check_serialize_params_class.serializer_class = subclass
|
274
351
|
subclass.const_set(:CheckSerializeParams, check_serialize_params_class)
|
275
352
|
|
353
|
+
check_batch_loader_params_class = Class.new(self::CheckBatchLoaderParams)
|
354
|
+
check_batch_loader_params_class.serializer_class = self
|
355
|
+
subclass.const_set(:CheckBatchLoaderParams, check_batch_loader_params_class)
|
356
|
+
|
276
357
|
# Assign same attributes
|
277
358
|
attributes.each_value do |attr|
|
278
359
|
params = attr.initials
|
279
360
|
subclass.attribute(params[:name], **params[:opts], ¶ms[:block])
|
280
361
|
end
|
281
362
|
|
363
|
+
# Assign same batch loaders
|
364
|
+
batch_loaders.each_value do |loader|
|
365
|
+
subclass.batch_loader(loader.name, loader.block)
|
366
|
+
end
|
367
|
+
|
282
368
|
super
|
283
369
|
end
|
284
370
|
end
|
@@ -340,6 +426,11 @@ class Serega
|
|
340
426
|
call(object, opts)
|
341
427
|
end
|
342
428
|
|
429
|
+
# @return [Hash] merged preloads of all serialized attributes
|
430
|
+
def preloads
|
431
|
+
@preloads ||= SeregaUtils::PreloadsConstructor.call(plan)
|
432
|
+
end
|
433
|
+
|
343
434
|
#
|
344
435
|
# Serializes provided object to JSON string
|
345
436
|
#
|
@@ -397,14 +488,14 @@ class Serega
|
|
397
488
|
|
398
489
|
# Patched in:
|
399
490
|
# - plugin :activerecord_preloads (loads defined :preloads to object)
|
400
|
-
# - plugin :batch (runs serialization of collected batches)
|
401
491
|
# - plugin :root (wraps result `{ root => result }`)
|
402
492
|
# - plugin :context_metadata (adds context metadata to final result)
|
403
493
|
# - plugin :metadata (adds metadata to final result)
|
404
494
|
def serialize(object, opts)
|
405
|
-
|
406
|
-
|
407
|
-
|
495
|
+
batch_loaders = plan.has_batch_points ? SeregaBatch::AttributeLoaders.new : nil
|
496
|
+
result = self.class::SeregaObjectSerializer.new(**opts, batch_loaders: batch_loaders, plan: plan).serialize(object)
|
497
|
+
batch_loaders&.load_all(opts[:context])
|
498
|
+
result
|
408
499
|
end
|
409
500
|
end
|
410
501
|
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: serega
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.30.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrey Glushkov
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
11
|
dependencies: []
|
13
12
|
description: |
|
14
13
|
JSON Serializer
|
@@ -30,6 +29,11 @@ files:
|
|
30
29
|
- lib/serega.rb
|
31
30
|
- lib/serega/attribute.rb
|
32
31
|
- lib/serega/attribute_normalizer.rb
|
32
|
+
- lib/serega/batch/attribute_loader.rb
|
33
|
+
- lib/serega/batch/attribute_loaders.rb
|
34
|
+
- lib/serega/batch/auto_resolver.rb
|
35
|
+
- lib/serega/batch/auto_resolver_factory.rb
|
36
|
+
- lib/serega/batch/loader.rb
|
33
37
|
- lib/serega/config.rb
|
34
38
|
- lib/serega/errors.rb
|
35
39
|
- lib/serega/helpers/serializer_class_helper.rb
|
@@ -41,24 +45,8 @@ files:
|
|
41
45
|
- lib/serega/plan_point.rb
|
42
46
|
- lib/serega/plugins.rb
|
43
47
|
- lib/serega/plugins/activerecord_preloads/activerecord_preloads.rb
|
48
|
+
- lib/serega/plugins/activerecord_preloads/lib/active_record_objects.rb
|
44
49
|
- lib/serega/plugins/activerecord_preloads/lib/preloader.rb
|
45
|
-
- lib/serega/plugins/batch/batch.rb
|
46
|
-
- lib/serega/plugins/batch/lib/batch_config.rb
|
47
|
-
- lib/serega/plugins/batch/lib/loader.rb
|
48
|
-
- lib/serega/plugins/batch/lib/loaders.rb
|
49
|
-
- lib/serega/plugins/batch/lib/modules/attribute.rb
|
50
|
-
- lib/serega/plugins/batch/lib/modules/attribute_normalizer.rb
|
51
|
-
- lib/serega/plugins/batch/lib/modules/check_attribute_params.rb
|
52
|
-
- lib/serega/plugins/batch/lib/modules/config.rb
|
53
|
-
- lib/serega/plugins/batch/lib/modules/object_serializer.rb
|
54
|
-
- lib/serega/plugins/batch/lib/modules/plan_point.rb
|
55
|
-
- lib/serega/plugins/batch/lib/plugins_extensions/activerecord_preloads.rb
|
56
|
-
- lib/serega/plugins/batch/lib/plugins_extensions/formatters.rb
|
57
|
-
- lib/serega/plugins/batch/lib/plugins_extensions/if.rb
|
58
|
-
- lib/serega/plugins/batch/lib/plugins_extensions/preloads.rb
|
59
|
-
- lib/serega/plugins/batch/lib/validations/check_batch_opt_id_method.rb
|
60
|
-
- lib/serega/plugins/batch/lib/validations/check_batch_opt_loader.rb
|
61
|
-
- lib/serega/plugins/batch/lib/validations/check_opt_batch.rb
|
62
50
|
- lib/serega/plugins/camel_case/camel_case.rb
|
63
51
|
- lib/serega/plugins/context_metadata/context_metadata.rb
|
64
52
|
- lib/serega/plugins/depth_limit/depth_limit.rb
|
@@ -79,42 +67,36 @@ files:
|
|
79
67
|
- lib/serega/plugins/metadata/validations/check_opt_value.rb
|
80
68
|
- lib/serega/plugins/metadata/validations/check_opts.rb
|
81
69
|
- lib/serega/plugins/metadata/validations/check_path.rb
|
82
|
-
- lib/serega/plugins/preloads/lib/format_user_preloads.rb
|
83
|
-
- lib/serega/plugins/preloads/lib/modules/attribute.rb
|
84
|
-
- lib/serega/plugins/preloads/lib/modules/attribute_normalizer.rb
|
85
|
-
- lib/serega/plugins/preloads/lib/modules/check_attribute_params.rb
|
86
|
-
- lib/serega/plugins/preloads/lib/modules/config.rb
|
87
|
-
- lib/serega/plugins/preloads/lib/modules/plan_point.rb
|
88
|
-
- lib/serega/plugins/preloads/lib/preload_paths.rb
|
89
|
-
- lib/serega/plugins/preloads/lib/preloads_config.rb
|
90
|
-
- lib/serega/plugins/preloads/lib/preloads_constructor.rb
|
91
|
-
- lib/serega/plugins/preloads/preloads.rb
|
92
|
-
- lib/serega/plugins/preloads/validations/check_opt_preload.rb
|
93
|
-
- lib/serega/plugins/preloads/validations/check_opt_preload_path.rb
|
94
70
|
- lib/serega/plugins/presenter/presenter.rb
|
95
71
|
- lib/serega/plugins/root/root.rb
|
96
72
|
- lib/serega/plugins/string_modifiers/parse_string_modifiers.rb
|
97
73
|
- lib/serega/plugins/string_modifiers/string_modifiers.rb
|
98
74
|
- lib/serega/utils/enum_deep_dup.rb
|
99
75
|
- lib/serega/utils/enum_deep_freeze.rb
|
100
|
-
- lib/serega/utils/
|
76
|
+
- lib/serega/utils/format_user_preloads.rb
|
77
|
+
- lib/serega/utils/method_signature.rb
|
78
|
+
- lib/serega/utils/preload_paths.rb
|
79
|
+
- lib/serega/utils/preloads_constructor.rb
|
101
80
|
- lib/serega/utils/symbol_name.rb
|
102
81
|
- lib/serega/utils/to_hash.rb
|
103
82
|
- lib/serega/validations/attribute/check_block.rb
|
104
83
|
- lib/serega/validations/attribute/check_name.rb
|
84
|
+
- lib/serega/validations/attribute/check_opt_batch.rb
|
105
85
|
- lib/serega/validations/attribute/check_opt_const.rb
|
106
86
|
- lib/serega/validations/attribute/check_opt_delegate.rb
|
107
87
|
- lib/serega/validations/attribute/check_opt_hide.rb
|
108
88
|
- lib/serega/validations/attribute/check_opt_many.rb
|
109
89
|
- lib/serega/validations/attribute/check_opt_method.rb
|
90
|
+
- lib/serega/validations/attribute/check_opt_preload.rb
|
91
|
+
- lib/serega/validations/attribute/check_opt_preload_path.rb
|
110
92
|
- lib/serega/validations/attribute/check_opt_serializer.rb
|
111
93
|
- lib/serega/validations/attribute/check_opt_value.rb
|
112
94
|
- lib/serega/validations/check_attribute_params.rb
|
95
|
+
- lib/serega/validations/check_batch_loader_params.rb
|
113
96
|
- lib/serega/validations/check_initiate_params.rb
|
114
97
|
- lib/serega/validations/check_serialize_params.rb
|
115
98
|
- lib/serega/validations/initiate/check_modifiers.rb
|
116
99
|
- lib/serega/validations/utils/check_allowed_keys.rb
|
117
|
-
- lib/serega/validations/utils/check_extra_keyword_arg.rb
|
118
100
|
- lib/serega/validations/utils/check_opt_is_bool.rb
|
119
101
|
- lib/serega/validations/utils/check_opt_is_hash.rb
|
120
102
|
- lib/serega/validations/utils/check_opt_is_string_or_symbol.rb
|
@@ -126,7 +108,6 @@ metadata:
|
|
126
108
|
source_code_uri: https://github.com/aglushkov/serega
|
127
109
|
documentation_uri: https://www.rubydoc.info/gems/serega
|
128
110
|
changelog_uri: https://github.com/aglushkov/serega/blob/master/CHANGELOG.md
|
129
|
-
post_install_message:
|
130
111
|
rdoc_options: []
|
131
112
|
require_paths:
|
132
113
|
- lib
|
@@ -141,8 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
141
122
|
- !ruby/object:Gem::Version
|
142
123
|
version: '0'
|
143
124
|
requirements: []
|
144
|
-
rubygems_version: 3.
|
145
|
-
signing_key:
|
125
|
+
rubygems_version: 3.7.1
|
146
126
|
specification_version: 4
|
147
127
|
summary: JSON Serializer
|
148
128
|
test_files: []
|
@@ -1,168 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Serega
|
4
|
-
module SeregaPlugins
|
5
|
-
#
|
6
|
-
# Plugin `:batch`
|
7
|
-
#
|
8
|
-
# Must be used to omit N+1 when loading attributes values.
|
9
|
-
#
|
10
|
-
# @example Quick example
|
11
|
-
#
|
12
|
-
# class AppSerializer
|
13
|
-
# plugin :batch, id_method: :id
|
14
|
-
# end
|
15
|
-
#
|
16
|
-
# class UserSerializer < AppSerializer
|
17
|
-
# attribute :comments_count, batch: { loader: CommentsCountBatchLoader }, default: 0
|
18
|
-
# attribute :company, serializer: CompanySerializer, batch: { loader: UserCompanyBatchLoader }
|
19
|
-
# end
|
20
|
-
#
|
21
|
-
module Batch
|
22
|
-
# Returns plugin name
|
23
|
-
# @return [Symbol] Plugin name
|
24
|
-
def self.plugin_name
|
25
|
-
:batch
|
26
|
-
end
|
27
|
-
|
28
|
-
# Checks requirements to load plugin
|
29
|
-
#
|
30
|
-
# @param serializer_class [Class<Serega>] Current serializer class
|
31
|
-
# @param opts [Hash] plugin options
|
32
|
-
#
|
33
|
-
# @return [void]
|
34
|
-
#
|
35
|
-
def self.before_load_plugin(serializer_class, **opts)
|
36
|
-
allowed_keys = %i[auto_hide id_method]
|
37
|
-
opts.each_key do |key|
|
38
|
-
next if allowed_keys.include?(key)
|
39
|
-
|
40
|
-
raise SeregaError,
|
41
|
-
"Plugin #{plugin_name.inspect} does not accept the #{key.inspect} option. Allowed options:\n" \
|
42
|
-
" - :auto_hide [Boolean] - Marks attribute as hidden when it has :batch loader specified\n" \
|
43
|
-
" - :id_method [Symbol, #call] - Specified the default method to use to find object identifier"
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
#
|
48
|
-
# Applies plugin code to specific serializer
|
49
|
-
#
|
50
|
-
# @param serializer_class [Class<Serega>] Current serializer class
|
51
|
-
# @param _opts [Hash] Plugin options
|
52
|
-
#
|
53
|
-
# @return [void]
|
54
|
-
#
|
55
|
-
def self.load_plugin(serializer_class, **_opts)
|
56
|
-
require_relative "lib/batch_config"
|
57
|
-
require_relative "lib/loader"
|
58
|
-
require_relative "lib/loaders"
|
59
|
-
require_relative "lib/modules/attribute"
|
60
|
-
require_relative "lib/modules/attribute_normalizer"
|
61
|
-
require_relative "lib/modules/check_attribute_params"
|
62
|
-
require_relative "lib/modules/config"
|
63
|
-
require_relative "lib/modules/object_serializer"
|
64
|
-
require_relative "lib/modules/plan_point"
|
65
|
-
require_relative "lib/validations/check_batch_opt_id_method"
|
66
|
-
require_relative "lib/validations/check_batch_opt_loader"
|
67
|
-
require_relative "lib/validations/check_opt_batch"
|
68
|
-
|
69
|
-
serializer_class.extend(ClassMethods)
|
70
|
-
serializer_class.include(InstanceMethods)
|
71
|
-
serializer_class::CheckAttributeParams.include(CheckAttributeParamsInstanceMethods)
|
72
|
-
serializer_class::SeregaAttribute.include(AttributeInstanceMethods)
|
73
|
-
serializer_class::SeregaAttributeNormalizer.include(AttributeNormalizerInstanceMethods)
|
74
|
-
serializer_class::SeregaPlanPoint.include(PlanPointInstanceMethods)
|
75
|
-
serializer_class::SeregaObjectSerializer.include(SeregaObjectSerializerInstanceMethods)
|
76
|
-
end
|
77
|
-
|
78
|
-
#
|
79
|
-
# Runs callbacks after plugin was attached
|
80
|
-
#
|
81
|
-
# @param serializer_class [Class<Serega>] Current serializer class
|
82
|
-
# @param opts [Hash] Plugin options
|
83
|
-
#
|
84
|
-
# @return [void]
|
85
|
-
#
|
86
|
-
def self.after_load_plugin(serializer_class, **opts)
|
87
|
-
serializer_class::SeregaConfig.include(ConfigInstanceMethods)
|
88
|
-
|
89
|
-
batch_loaders_class = Class.new(SeregaBatchLoaders)
|
90
|
-
batch_loaders_class.serializer_class = serializer_class
|
91
|
-
serializer_class.const_set(:SeregaBatchLoaders, batch_loaders_class)
|
92
|
-
|
93
|
-
batch_loader_class = Class.new(SeregaBatchLoader)
|
94
|
-
batch_loader_class.serializer_class = serializer_class
|
95
|
-
serializer_class.const_set(:SeregaBatchLoader, batch_loader_class)
|
96
|
-
|
97
|
-
if serializer_class.plugin_used?(:activerecord_preloads)
|
98
|
-
require_relative "lib/plugins_extensions/activerecord_preloads"
|
99
|
-
serializer_class::SeregaBatchLoader.include(PluginsExtensions::ActiveRecordPreloads::BatchLoaderInstanceMethods)
|
100
|
-
end
|
101
|
-
|
102
|
-
if serializer_class.plugin_used?(:formatters)
|
103
|
-
require_relative "lib/plugins_extensions/formatters"
|
104
|
-
serializer_class::SeregaBatchLoader.include(PluginsExtensions::Formatters::BatchLoaderInstanceMethods)
|
105
|
-
serializer_class::SeregaAttribute.include(PluginsExtensions::Formatters::SeregaAttributeInstanceMethods)
|
106
|
-
end
|
107
|
-
|
108
|
-
if serializer_class.plugin_used?(:if)
|
109
|
-
require_relative "lib/plugins_extensions/if"
|
110
|
-
serializer_class::SeregaObjectSerializer.include(PluginsExtensions::If::ObjectSerializerInstanceMethods123)
|
111
|
-
end
|
112
|
-
|
113
|
-
if serializer_class.plugin_used?(:preloads)
|
114
|
-
require_relative "lib/plugins_extensions/preloads"
|
115
|
-
serializer_class::SeregaAttributeNormalizer.include(PluginsExtensions::Preloads::AttributeNormalizerInstanceMethods)
|
116
|
-
end
|
117
|
-
|
118
|
-
config = serializer_class.config
|
119
|
-
config.attribute_keys << :batch
|
120
|
-
config.opts[:batch] = {loaders: {}, id_method: nil, auto_hide: false}
|
121
|
-
config.batch.auto_hide = opts[:auto_hide] if opts.key?(:auto_hide)
|
122
|
-
config.batch.id_method = opts[:id_method] if opts.key?(:id_method)
|
123
|
-
end
|
124
|
-
|
125
|
-
#
|
126
|
-
# Serega class additional/patched class methods
|
127
|
-
#
|
128
|
-
# @see Serega::SeregaConfig
|
129
|
-
#
|
130
|
-
module ClassMethods
|
131
|
-
private
|
132
|
-
|
133
|
-
def inherited(subclass)
|
134
|
-
super
|
135
|
-
|
136
|
-
batch_loaders_class = Class.new(self::SeregaBatchLoaders)
|
137
|
-
batch_loaders_class.serializer_class = subclass
|
138
|
-
subclass.const_set(:SeregaBatchLoaders, batch_loaders_class)
|
139
|
-
|
140
|
-
batch_loader_class = Class.new(self::SeregaBatchLoader)
|
141
|
-
batch_loader_class.serializer_class = subclass
|
142
|
-
subclass.const_set(:SeregaBatchLoader, batch_loader_class)
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
#
|
147
|
-
# Serega additional/patched instance methods
|
148
|
-
#
|
149
|
-
# @see Serega::InstanceMethods
|
150
|
-
#
|
151
|
-
module InstanceMethods
|
152
|
-
private
|
153
|
-
|
154
|
-
#
|
155
|
-
# Loads batch loaded attributes after serialization
|
156
|
-
#
|
157
|
-
def serialize(object, opts)
|
158
|
-
batch_loaders = opts[:batch_loaders] = self.class::SeregaBatchLoaders.new
|
159
|
-
result = super
|
160
|
-
batch_loaders.load_all
|
161
|
-
result
|
162
|
-
end
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
register_plugin(Batch.plugin_name, Batch)
|
167
|
-
end
|
168
|
-
end
|
@@ -1,77 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Serega
|
4
|
-
module SeregaPlugins
|
5
|
-
module Batch
|
6
|
-
#
|
7
|
-
# Batch plugin config
|
8
|
-
#
|
9
|
-
class BatchConfig
|
10
|
-
attr_reader :opts
|
11
|
-
|
12
|
-
def initialize(opts)
|
13
|
-
@opts = opts
|
14
|
-
end
|
15
|
-
|
16
|
-
#
|
17
|
-
# Defines batch loader
|
18
|
-
#
|
19
|
-
# @param loader_name [Symbol] Batch loader name, that is used when defining attribute with batch loader.
|
20
|
-
# @param block [Proc] Block that can accept 3 parameters - ids, context, plan_point
|
21
|
-
# and returns hash with ids as keys and values are batch loaded objects
|
22
|
-
#
|
23
|
-
# @return [void]
|
24
|
-
#
|
25
|
-
def define(loader_name, callable = nil, &block)
|
26
|
-
if (!callable && !block) || (callable && block)
|
27
|
-
raise SeregaError, "Batch loader can be specified with one of arguments - callable value or &block"
|
28
|
-
end
|
29
|
-
|
30
|
-
callable ||= block
|
31
|
-
SeregaValidations::Utils::CheckExtraKeywordArg.call(callable, "batch loader `#{loader_name}`")
|
32
|
-
params_count = SeregaUtils::ParamsCount.call(callable, max_count: 3)
|
33
|
-
|
34
|
-
if params_count > 3
|
35
|
-
raise SeregaError, "Batch loader can have maximum 3 parameters (ids, context, plan)"
|
36
|
-
end
|
37
|
-
|
38
|
-
loaders[loader_name] = callable
|
39
|
-
end
|
40
|
-
|
41
|
-
# Shows defined loaders
|
42
|
-
# @return [Hash] defined loaders
|
43
|
-
def loaders
|
44
|
-
opts[:loaders]
|
45
|
-
end
|
46
|
-
|
47
|
-
# Shows option to auto hide attributes with :batch specified
|
48
|
-
# @return [Boolean, nil] option value
|
49
|
-
def auto_hide
|
50
|
-
opts[:auto_hide]
|
51
|
-
end
|
52
|
-
|
53
|
-
# @param value [Boolean] New :auto_hide option value
|
54
|
-
# @return [Boolean] New option value
|
55
|
-
def auto_hide=(value)
|
56
|
-
raise SeregaError, "Must have boolean value, #{value.inspect} provided" if (value != true) && (value != false)
|
57
|
-
opts[:auto_hide] = value
|
58
|
-
end
|
59
|
-
|
60
|
-
# Shows method name or callable object needed to get object identifier for batch load
|
61
|
-
# @return [Symbol, #call, nil] Default method name or callable object to get identifier
|
62
|
-
def id_method
|
63
|
-
opts[:id_method]
|
64
|
-
end
|
65
|
-
|
66
|
-
# Sets new identifier method name or callable value needed for batch loading
|
67
|
-
#
|
68
|
-
# @param value [Symbol, #call] New :id_method value
|
69
|
-
# @return [Boolean] New option value
|
70
|
-
def id_method=(value)
|
71
|
-
CheckBatchOptIdMethod.call(value)
|
72
|
-
opts[:id_method] = value
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
@@ -1,113 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Serega
|
4
|
-
module SeregaPlugins
|
5
|
-
module Batch
|
6
|
-
#
|
7
|
-
# Encapsulates point and according object_serializer
|
8
|
-
# so we can put batch loaded values to this serializer response
|
9
|
-
#
|
10
|
-
class SeregaBatchLoader
|
11
|
-
#
|
12
|
-
# Batch Loader instance methods
|
13
|
-
#
|
14
|
-
module InstanceMethods
|
15
|
-
# @return [Serega::SeregaPlanPoint]
|
16
|
-
attr_reader :point
|
17
|
-
|
18
|
-
# @return [Serega::SeregaObjectSerializer]
|
19
|
-
attr_reader :object_serializer
|
20
|
-
|
21
|
-
#
|
22
|
-
# Initializes new SeregaBatchLoader
|
23
|
-
#
|
24
|
-
# @param object_serializer [Serega::SeregaObjectSerializer]
|
25
|
-
# @param point [Serega::SeregaPlanPoint]
|
26
|
-
#
|
27
|
-
# @return [Serega::SeregaPlugins::Batch::SeregaBatchLoader]
|
28
|
-
#
|
29
|
-
def initialize(object_serializer, point)
|
30
|
-
@object_serializer = object_serializer
|
31
|
-
@point = point
|
32
|
-
end
|
33
|
-
|
34
|
-
#
|
35
|
-
# Remembers key and hash container where value for this key must be inserted
|
36
|
-
#
|
37
|
-
# @param key [Object] key that identifies batch loaded objects
|
38
|
-
# @param container [Hash] container where batch loaded objects must be attached
|
39
|
-
#
|
40
|
-
# @return [void]
|
41
|
-
#
|
42
|
-
def remember(key, container)
|
43
|
-
(keys[key] ||= []) << container
|
44
|
-
end
|
45
|
-
|
46
|
-
#
|
47
|
-
# Loads this batch and assigns values to remembered containers
|
48
|
-
#
|
49
|
-
# @return [void]
|
50
|
-
#
|
51
|
-
def load
|
52
|
-
keys_values = keys_values()
|
53
|
-
|
54
|
-
each_key do |key, container|
|
55
|
-
value = keys_values.fetch(key) { point.batch[:default] }
|
56
|
-
final_value = object_serializer.__send__(:final_value, value, point)
|
57
|
-
object_serializer.__send__(:attach_final_value, final_value, point, container)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
private
|
62
|
-
|
63
|
-
def keys
|
64
|
-
@keys ||= {}
|
65
|
-
end
|
66
|
-
|
67
|
-
def each_key
|
68
|
-
keys.each do |key, containers|
|
69
|
-
containers.each do |container|
|
70
|
-
yield(key, container)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
# Patched in:
|
76
|
-
# - plugin batch (extension :activerecord_preloads - preloads data to found values)
|
77
|
-
# - plugin batch (extension :formatters - formats values)
|
78
|
-
def keys_values
|
79
|
-
ids = keys.keys
|
80
|
-
|
81
|
-
keys_values = load_keys_values(ids)
|
82
|
-
validate(keys_values)
|
83
|
-
|
84
|
-
keys_values
|
85
|
-
end
|
86
|
-
|
87
|
-
def load_keys_values(ids)
|
88
|
-
point.batch[:loader].call(ids, object_serializer.context, point)
|
89
|
-
rescue => error
|
90
|
-
raise reraise_with_serialized_attribute_details(error, point)
|
91
|
-
end
|
92
|
-
|
93
|
-
def validate(keys_values)
|
94
|
-
return if keys_values.is_a?(Hash)
|
95
|
-
|
96
|
-
attribute_name = "#{point.class.serializer_class}.#{point.name}"
|
97
|
-
raise SeregaError, "Batch loader for `#{attribute_name}` must return Hash, but #{keys_values.inspect} was returned"
|
98
|
-
end
|
99
|
-
|
100
|
-
def reraise_with_serialized_attribute_details(error, point)
|
101
|
-
raise error.exception(<<~MESSAGE.strip)
|
102
|
-
#{error.message}
|
103
|
-
(when serializing '#{point.name}' attribute in #{self.class.serializer_class})
|
104
|
-
MESSAGE
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
include InstanceMethods
|
109
|
-
extend Serega::SeregaHelpers::SerializerClassHelper
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|