serega 0.11.2 → 0.14.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 +163 -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/lib/loader.rb +25 -7
- data/lib/serega/plugins/batch/lib/modules/attribute_normalizer.rb +1 -9
- data/lib/serega/plugins/explicit_many_option/explicit_many_option.rb +69 -0
- data/lib/serega/plugins/explicit_many_option/validations/check_opt_many.rb +35 -0
- data/lib/serega/plugins/metadata/metadata.rb +5 -0
- data/lib/serega/plugins/openapi/lib/modules/config.rb +23 -0
- data/lib/serega/plugins/openapi/lib/openapi_config.rb +101 -0
- data/lib/serega/plugins/openapi/openapi.rb +245 -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 +18 -7
- data/lib/serega/plugins/preloads/lib/main_preload_path.rb +0 -53
@@ -35,8 +35,9 @@ class Serega
|
|
35
35
|
append_current(preloads, current_preloads)
|
36
36
|
next unless child_plan
|
37
37
|
|
38
|
-
|
39
|
-
|
38
|
+
each_child_preloads(preloads, point.preloads_path) do |child_preloads|
|
39
|
+
append_many(child_preloads, child_plan)
|
40
|
+
end
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|
@@ -50,14 +51,26 @@ class Serega
|
|
50
51
|
end
|
51
52
|
end
|
52
53
|
|
53
|
-
def
|
54
|
-
return
|
54
|
+
def each_child_preloads(preloads, preloads_path)
|
55
|
+
return yield(preloads) if preloads_path.nil?
|
55
56
|
|
56
|
-
|
57
|
-
|
57
|
+
if preloads_path[0].is_a?(Array)
|
58
|
+
preloads_path.each do |path|
|
59
|
+
yield dig_fetch(preloads, path)
|
60
|
+
end
|
61
|
+
else
|
62
|
+
yield dig_fetch(preloads, preloads_path)
|
58
63
|
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def dig_fetch(preloads, preloads_path)
|
67
|
+
return preloads if !preloads_path || preloads_path.empty?
|
59
68
|
|
60
|
-
|
69
|
+
preloads_path.each do |path|
|
70
|
+
preloads = preloads.fetch(path)
|
71
|
+
end
|
72
|
+
|
73
|
+
preloads
|
61
74
|
end
|
62
75
|
end
|
63
76
|
end
|
@@ -79,6 +79,18 @@ class Serega
|
|
79
79
|
# @return [void]
|
80
80
|
#
|
81
81
|
def self.load_plugin(serializer_class, **_opts)
|
82
|
+
require_relative "./lib/format_user_preloads"
|
83
|
+
require_relative "./lib/modules/attribute"
|
84
|
+
require_relative "./lib/modules/attribute_normalizer"
|
85
|
+
require_relative "./lib/modules/check_attribute_params"
|
86
|
+
require_relative "./lib/modules/config"
|
87
|
+
require_relative "./lib/modules/plan_point"
|
88
|
+
require_relative "./lib/preload_paths"
|
89
|
+
require_relative "./lib/preloads_config"
|
90
|
+
require_relative "./lib/preloads_constructor"
|
91
|
+
require_relative "./validations/check_opt_preload"
|
92
|
+
require_relative "./validations/check_opt_preload_path"
|
93
|
+
|
82
94
|
serializer_class.include(InstanceMethods)
|
83
95
|
serializer_class::SeregaAttribute.include(AttributeInstanceMethods)
|
84
96
|
serializer_class::SeregaAttributeNormalizer.include(AttributeNormalizerInstanceMethods)
|
@@ -86,12 +98,6 @@ class Serega
|
|
86
98
|
serializer_class::SeregaPlanPoint.include(PlanPointInstanceMethods)
|
87
99
|
|
88
100
|
serializer_class::CheckAttributeParams.include(CheckAttributeParamsInstanceMethods)
|
89
|
-
|
90
|
-
require_relative "./lib/format_user_preloads"
|
91
|
-
require_relative "./lib/main_preload_path"
|
92
|
-
require_relative "./lib/preloads_constructor"
|
93
|
-
require_relative "./validations/check_opt_preload"
|
94
|
-
require_relative "./validations/check_opt_preload_path"
|
95
101
|
end
|
96
102
|
|
97
103
|
#
|
@@ -125,210 +131,6 @@ class Serega
|
|
125
131
|
@preloads ||= PreloadsConstructor.call(plan)
|
126
132
|
end
|
127
133
|
end
|
128
|
-
|
129
|
-
#
|
130
|
-
# Config for `preloads` plugin
|
131
|
-
#
|
132
|
-
class PreloadsConfig
|
133
|
-
# @return [Hash] preloads plugin options
|
134
|
-
attr_reader :opts
|
135
|
-
|
136
|
-
#
|
137
|
-
# Initializes context_metadata config object
|
138
|
-
#
|
139
|
-
# @param opts [Hash] options
|
140
|
-
#
|
141
|
-
# @return [Serega::SeregaPlugins::Metadata::MetadataConfig]
|
142
|
-
#
|
143
|
-
def initialize(opts)
|
144
|
-
@opts = opts
|
145
|
-
end
|
146
|
-
|
147
|
-
# @!method auto_preload_attributes_with_delegate
|
148
|
-
# @return [Boolean, nil] option value
|
149
|
-
#
|
150
|
-
# @!method auto_preload_attributes_with_delegate=(value)
|
151
|
-
# @param value [Boolean] New option value
|
152
|
-
# @return [Boolean] New option value
|
153
|
-
#
|
154
|
-
# @!method auto_preload_attributes_with_serializer
|
155
|
-
# @return [Boolean, nil] option value
|
156
|
-
#
|
157
|
-
# @!method auto_preload_attributes_with_serializer=(value)
|
158
|
-
# @param value [Boolean] New option value
|
159
|
-
# @return [Boolean] New option value
|
160
|
-
#
|
161
|
-
# @!method auto_hide_attributes_with_preload
|
162
|
-
# @return [Boolean, nil] option value
|
163
|
-
#
|
164
|
-
# @!method auto_hide_attributes_with_preload=(value)
|
165
|
-
# @param value [Boolean] New option value
|
166
|
-
# @return [Boolean] New option value
|
167
|
-
#
|
168
|
-
%i[
|
169
|
-
auto_preload_attributes_with_delegate
|
170
|
-
auto_preload_attributes_with_serializer
|
171
|
-
auto_hide_attributes_with_preload
|
172
|
-
].each do |method_name|
|
173
|
-
define_method(method_name) do
|
174
|
-
opts.fetch(method_name)
|
175
|
-
end
|
176
|
-
|
177
|
-
define_method("#{method_name}=") do |value|
|
178
|
-
raise SeregaError, "Must have boolean value, #{value.inspect} provided" if (value != true) && (value != false)
|
179
|
-
opts[method_name] = value
|
180
|
-
end
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
#
|
185
|
-
# Config class additional/patched instance methods
|
186
|
-
#
|
187
|
-
# @see Serega::SeregaConfig
|
188
|
-
#
|
189
|
-
module ConfigInstanceMethods
|
190
|
-
# @return [Serega::SeregaPlugins::Preloads::PreloadsConfig] `preloads` plugin config
|
191
|
-
def preloads
|
192
|
-
@preloads ||= PreloadsConfig.new(opts.fetch(:preloads))
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
#
|
197
|
-
# Serega::SeregaAttribute additional/patched instance methods
|
198
|
-
#
|
199
|
-
# @see Serega::SeregaAttribute::AttributeInstanceMethods
|
200
|
-
#
|
201
|
-
module AttributeInstanceMethods
|
202
|
-
# @return [Hash, nil] normalized preloads of current attribute
|
203
|
-
attr_reader :preloads
|
204
|
-
|
205
|
-
# @return [Array] normalized preloads_path of current attribute
|
206
|
-
attr_reader :preloads_path
|
207
|
-
|
208
|
-
private
|
209
|
-
|
210
|
-
def set_normalized_vars(normalizer)
|
211
|
-
super
|
212
|
-
@preloads = normalizer.preloads
|
213
|
-
@preloads_path = normalizer.preloads_path
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
#
|
218
|
-
# SeregaAttributeNormalizer additional/patched instance methods
|
219
|
-
#
|
220
|
-
# @see SeregaAttributeNormalizer::AttributeInstanceMethods
|
221
|
-
#
|
222
|
-
module AttributeNormalizerInstanceMethods
|
223
|
-
# @return [Hash,nil] normalized attribute preloads
|
224
|
-
def preloads
|
225
|
-
return @preloads if instance_variable_defined?(:@preloads)
|
226
|
-
|
227
|
-
@preloads = prepare_preloads
|
228
|
-
end
|
229
|
-
|
230
|
-
# @return [Array, nil] normalized attribute preloads path
|
231
|
-
def preloads_path
|
232
|
-
return @preloads_path if instance_variable_defined?(:@preloads_path)
|
233
|
-
|
234
|
-
@preloads_path = prepare_preloads_path
|
235
|
-
end
|
236
|
-
|
237
|
-
private
|
238
|
-
|
239
|
-
#
|
240
|
-
# Patched in:
|
241
|
-
# - plugin :batch (extension :preloads - skips auto preloads when batch option provided)
|
242
|
-
#
|
243
|
-
def prepare_preloads
|
244
|
-
opts = init_opts
|
245
|
-
preloads_provided = opts.key?(:preload)
|
246
|
-
preloads =
|
247
|
-
if preloads_provided
|
248
|
-
opts[:preload]
|
249
|
-
elsif opts.key?(:serializer) && self.class.serializer_class.config.preloads.auto_preload_attributes_with_serializer
|
250
|
-
key
|
251
|
-
elsif opts.key?(:delegate) && self.class.serializer_class.config.preloads.auto_preload_attributes_with_delegate
|
252
|
-
opts[:delegate].fetch(:to)
|
253
|
-
end
|
254
|
-
|
255
|
-
# Nil and empty hash differs as we can preload nested results to
|
256
|
-
# empty hash, but we will skip nested preloading if nil or false provided
|
257
|
-
return if preloads_provided && !preloads
|
258
|
-
|
259
|
-
FormatUserPreloads.call(preloads)
|
260
|
-
end
|
261
|
-
|
262
|
-
def prepare_preloads_path
|
263
|
-
opts = init_opts
|
264
|
-
path = Array(opts[:preload_path]).map!(&:to_sym).freeze
|
265
|
-
path = MainPreloadPath.call(preloads) if path.empty?
|
266
|
-
path
|
267
|
-
end
|
268
|
-
|
269
|
-
#
|
270
|
-
# Patch for original `prepare_hide` method
|
271
|
-
#
|
272
|
-
# Marks attribute hidden if auto_hide_attribute_with_preloads option was set and attribute has preloads
|
273
|
-
#
|
274
|
-
def prepare_hide
|
275
|
-
res = super
|
276
|
-
return res unless res.nil?
|
277
|
-
|
278
|
-
if preloads && !preloads.empty?
|
279
|
-
self.class.serializer_class.config.preloads.auto_hide_attributes_with_preload || nil
|
280
|
-
end
|
281
|
-
end
|
282
|
-
end
|
283
|
-
|
284
|
-
#
|
285
|
-
# Serega::SeregaPlanPoint additional/patched instance methods
|
286
|
-
#
|
287
|
-
# @see Serega::SeregaPlanPoint::InstanceMethods
|
288
|
-
#
|
289
|
-
module PlanPointInstanceMethods
|
290
|
-
#
|
291
|
-
# @return [Hash] preloads for nested attributes
|
292
|
-
#
|
293
|
-
attr_reader :preloads
|
294
|
-
|
295
|
-
#
|
296
|
-
# @return [Array<Symbol>] preloads path for current attribute
|
297
|
-
#
|
298
|
-
attr_reader :preloads_path
|
299
|
-
|
300
|
-
private
|
301
|
-
|
302
|
-
def set_normalized_vars
|
303
|
-
super
|
304
|
-
|
305
|
-
@preloads = prepare_preloads
|
306
|
-
@preloads_path = prepare_preloads_path
|
307
|
-
end
|
308
|
-
|
309
|
-
def prepare_preloads
|
310
|
-
PreloadsConstructor.call(child_plan)
|
311
|
-
end
|
312
|
-
|
313
|
-
def prepare_preloads_path
|
314
|
-
attribute.preloads_path
|
315
|
-
end
|
316
|
-
end
|
317
|
-
|
318
|
-
#
|
319
|
-
# Serega::SeregaValidations::CheckAttributeParams additional/patched class methods
|
320
|
-
#
|
321
|
-
# @see Serega::SeregaValidations::CheckAttributeParams
|
322
|
-
#
|
323
|
-
module CheckAttributeParamsInstanceMethods
|
324
|
-
private
|
325
|
-
|
326
|
-
def check_opts
|
327
|
-
super
|
328
|
-
CheckOptPreload.call(opts)
|
329
|
-
CheckOptPreloadPath.call(opts)
|
330
|
-
end
|
331
|
-
end
|
332
134
|
end
|
333
135
|
|
334
136
|
register_plugin(Preloads.plugin_name, Preloads)
|
@@ -18,30 +18,69 @@ class Serega
|
|
18
18
|
# @return [void]
|
19
19
|
#
|
20
20
|
def call(opts)
|
21
|
-
return
|
21
|
+
return if exactly_nil?(opts, :preload_path) # allow to provide nil anyway
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
path = opts[:preload_path]
|
24
|
+
check_usage_with_other_options(path, opts)
|
25
|
+
return unless opts[:serializer]
|
26
26
|
|
27
|
-
path
|
28
|
-
preloads = FormatUserPreloads.call(opts[:preload])
|
29
|
-
allowed_paths = paths(preloads)
|
30
|
-
raise SeregaError, "Invalid option :preload_path => #{value.inspect}. Can be one of #{allowed_paths.inspect[1..-2]}" unless allowed_paths.include?(path)
|
27
|
+
check_allowed(path, opts)
|
31
28
|
end
|
32
29
|
|
33
30
|
private
|
34
31
|
|
35
|
-
def
|
36
|
-
|
37
|
-
|
38
|
-
|
32
|
+
def exactly_nil?(opts, opt_name)
|
33
|
+
opts.fetch(opt_name, false).nil?
|
34
|
+
end
|
35
|
+
|
36
|
+
def check_allowed(path, opts)
|
37
|
+
allowed_paths = PreloadPaths.call(opts[:preload])
|
38
|
+
check_required_when_many_allowed(path, allowed_paths)
|
39
|
+
check_in_allowed(path, allowed_paths)
|
40
|
+
end
|
41
|
+
|
42
|
+
def check_usage_with_other_options(path, opts)
|
43
|
+
return unless path
|
44
|
+
|
45
|
+
preload = opts[:preload]
|
46
|
+
raise SeregaError, "Invalid option preload_path: #{path.inspect}. Can be provided only when :preload option provided" unless preload
|
39
47
|
|
40
|
-
|
41
|
-
|
48
|
+
serializer = opts[:serializer]
|
49
|
+
raise SeregaError, "Invalid option preload_path: #{path.inspect}. Can be provided only when :serializer option provided" unless serializer
|
50
|
+
end
|
51
|
+
|
52
|
+
def check_required_when_many_allowed(path, allowed)
|
53
|
+
return if path || (allowed.size < 2)
|
54
|
+
|
55
|
+
raise SeregaError, "Option :preload_path must be provided. Possible values: #{allowed.inspect[1..-2]}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def check_in_allowed(path, allowed)
|
59
|
+
return if !path && allowed.size <= 1
|
60
|
+
|
61
|
+
if multiple_preload_paths_provided?(path)
|
62
|
+
check_many(path, allowed)
|
63
|
+
else
|
64
|
+
check_one(path, allowed)
|
42
65
|
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def check_one(path, allowed)
|
69
|
+
formatted_path = Array(path).map(&:to_sym)
|
70
|
+
return if allowed.include?(formatted_path)
|
71
|
+
|
72
|
+
raise SeregaError,
|
73
|
+
"Invalid preload_path (#{path.inspect}). " \
|
74
|
+
"Can be one of #{allowed.inspect[1..-2]}"
|
75
|
+
end
|
76
|
+
|
77
|
+
def check_many(paths, allowed)
|
78
|
+
paths.each { |path| check_one(path, allowed) }
|
79
|
+
end
|
43
80
|
|
44
|
-
|
81
|
+
# Check value is Array in Array
|
82
|
+
def multiple_preload_paths_provided?(value)
|
83
|
+
value.is_a?(Array) && value[0].is_a?(Array)
|
45
84
|
end
|
46
85
|
end
|
47
86
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: serega
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrey Glushkov
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-07-24 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |
|
14
14
|
JSON Serializer
|
@@ -59,6 +59,8 @@ files:
|
|
59
59
|
- lib/serega/plugins/batch/lib/validations/check_batch_opt_loader.rb
|
60
60
|
- lib/serega/plugins/batch/lib/validations/check_opt_batch.rb
|
61
61
|
- lib/serega/plugins/context_metadata/context_metadata.rb
|
62
|
+
- lib/serega/plugins/explicit_many_option/explicit_many_option.rb
|
63
|
+
- lib/serega/plugins/explicit_many_option/validations/check_opt_many.rb
|
62
64
|
- lib/serega/plugins/formatters/formatters.rb
|
63
65
|
- lib/serega/plugins/if/if.rb
|
64
66
|
- lib/serega/plugins/if/validations/check_opt_if.rb
|
@@ -72,8 +74,17 @@ files:
|
|
72
74
|
- lib/serega/plugins/metadata/validations/check_opt_hide_nil.rb
|
73
75
|
- lib/serega/plugins/metadata/validations/check_opts.rb
|
74
76
|
- lib/serega/plugins/metadata/validations/check_path.rb
|
77
|
+
- lib/serega/plugins/openapi/lib/modules/config.rb
|
78
|
+
- lib/serega/plugins/openapi/lib/openapi_config.rb
|
79
|
+
- lib/serega/plugins/openapi/openapi.rb
|
75
80
|
- lib/serega/plugins/preloads/lib/format_user_preloads.rb
|
76
|
-
- lib/serega/plugins/preloads/lib/
|
81
|
+
- lib/serega/plugins/preloads/lib/modules/attribute.rb
|
82
|
+
- lib/serega/plugins/preloads/lib/modules/attribute_normalizer.rb
|
83
|
+
- lib/serega/plugins/preloads/lib/modules/check_attribute_params.rb
|
84
|
+
- lib/serega/plugins/preloads/lib/modules/config.rb
|
85
|
+
- lib/serega/plugins/preloads/lib/modules/plan_point.rb
|
86
|
+
- lib/serega/plugins/preloads/lib/preload_paths.rb
|
87
|
+
- lib/serega/plugins/preloads/lib/preloads_config.rb
|
77
88
|
- lib/serega/plugins/preloads/lib/preloads_constructor.rb
|
78
89
|
- lib/serega/plugins/preloads/preloads.rb
|
79
90
|
- lib/serega/plugins/preloads/validations/check_opt_preload.rb
|
@@ -111,7 +122,7 @@ metadata:
|
|
111
122
|
source_code_uri: https://github.com/aglushkov/serega
|
112
123
|
documentation_uri: https://www.rubydoc.info/gems/serega
|
113
124
|
changelog_uri: https://github.com/aglushkov/serega/blob/master/CHANGELOG.md
|
114
|
-
post_install_message:
|
125
|
+
post_install_message:
|
115
126
|
rdoc_options: []
|
116
127
|
require_paths:
|
117
128
|
- lib
|
@@ -126,8 +137,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
126
137
|
- !ruby/object:Gem::Version
|
127
138
|
version: '0'
|
128
139
|
requirements: []
|
129
|
-
rubygems_version: 3.4.
|
130
|
-
signing_key:
|
140
|
+
rubygems_version: 3.4.6
|
141
|
+
signing_key:
|
131
142
|
specification_version: 4
|
132
143
|
summary: JSON Serializer
|
133
144
|
test_files: []
|
@@ -1,53 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Serega
|
4
|
-
module SeregaPlugins
|
5
|
-
module Preloads
|
6
|
-
#
|
7
|
-
# Class that constructs main preloads path.
|
8
|
-
#
|
9
|
-
# When we have nested preloads we will use this path to dig to `main` element and
|
10
|
-
# assign nested preloads to it.
|
11
|
-
#
|
12
|
-
# By default its a path to latest provided preload
|
13
|
-
#
|
14
|
-
# @example
|
15
|
-
# MainPreloadPath.(a: { b: { c: {} }, d: {} }) # => [:a, :d]
|
16
|
-
#
|
17
|
-
class MainPreloadPath
|
18
|
-
class << self
|
19
|
-
# Finds default preload path
|
20
|
-
#
|
21
|
-
# @param preloads [Hash] Formatted user provided preloads hash
|
22
|
-
#
|
23
|
-
# @return [Array<Symbol>] Preloads path to `main` element
|
24
|
-
def call(preloads)
|
25
|
-
return FROZEN_EMPTY_ARRAY if !preloads || preloads.empty?
|
26
|
-
|
27
|
-
main_path(preloads).freeze
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
# Generates path (Array) to the last included resource.
|
33
|
-
# We need to know this path to include nested associations.
|
34
|
-
#
|
35
|
-
# main_path(a: { b: { c: {} }, d: {} }) # => [:a, :d]
|
36
|
-
#
|
37
|
-
def main_path(hash, path = [])
|
38
|
-
current_level = path.size
|
39
|
-
|
40
|
-
hash.each do |key, data|
|
41
|
-
path.pop(path.size - current_level)
|
42
|
-
path << key
|
43
|
-
|
44
|
-
main_path(data, path)
|
45
|
-
end
|
46
|
-
|
47
|
-
path
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|