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.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +163 -13
  3. data/VERSION +1 -1
  4. data/lib/serega/attribute.rb +9 -4
  5. data/lib/serega/attribute_normalizer.rb +4 -13
  6. data/lib/serega/object_serializer.rb +11 -0
  7. data/lib/serega/plan.rb +20 -25
  8. data/lib/serega/plan_point.rb +13 -16
  9. data/lib/serega/plugins/batch/lib/loader.rb +25 -7
  10. data/lib/serega/plugins/batch/lib/modules/attribute_normalizer.rb +1 -9
  11. data/lib/serega/plugins/explicit_many_option/explicit_many_option.rb +69 -0
  12. data/lib/serega/plugins/explicit_many_option/validations/check_opt_many.rb +35 -0
  13. data/lib/serega/plugins/metadata/metadata.rb +5 -0
  14. data/lib/serega/plugins/openapi/lib/modules/config.rb +23 -0
  15. data/lib/serega/plugins/openapi/lib/openapi_config.rb +101 -0
  16. data/lib/serega/plugins/openapi/openapi.rb +245 -0
  17. data/lib/serega/plugins/preloads/lib/modules/attribute.rb +28 -0
  18. data/lib/serega/plugins/preloads/lib/modules/attribute_normalizer.rb +99 -0
  19. data/lib/serega/plugins/preloads/lib/modules/check_attribute_params.rb +22 -0
  20. data/lib/serega/plugins/preloads/lib/modules/config.rb +19 -0
  21. data/lib/serega/plugins/preloads/lib/modules/plan_point.rb +41 -0
  22. data/lib/serega/plugins/preloads/lib/preload_paths.rb +46 -0
  23. data/lib/serega/plugins/preloads/lib/preloads_config.rb +62 -0
  24. data/lib/serega/plugins/preloads/lib/preloads_constructor.rb +20 -7
  25. data/lib/serega/plugins/preloads/preloads.rb +12 -210
  26. data/lib/serega/plugins/preloads/validations/check_opt_preload_path.rb +54 -15
  27. metadata +18 -7
  28. 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
- child_preloads = dig?(preloads, point.preloads_path)
39
- append_many(child_preloads, child_plan)
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 dig?(hash, path)
54
- return hash if !path || path.empty?
54
+ def each_child_preloads(preloads, preloads_path)
55
+ return yield(preloads) if preloads_path.nil?
55
56
 
56
- path.each do |point|
57
- hash = hash[point]
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
- hash
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 unless opts.key?(:preload_path)
21
+ return if exactly_nil?(opts, :preload_path) # allow to provide nil anyway
22
22
 
23
- value = opts[:preload_path]
24
- raise SeregaError, "Invalid option :preload_path => #{value.inspect}. Can be provided only when :preload option provided" unless opts[:preload]
25
- raise SeregaError, "Invalid option :preload_path => #{value.inspect}. Can be provided only when :serializer option provided" unless opts[:serializer]
23
+ path = opts[:preload_path]
24
+ check_usage_with_other_options(path, opts)
25
+ return unless opts[:serializer]
26
26
 
27
- path = Array(value).map!(&:to_sym)
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 paths(preloads, path = [], result = [])
36
- preloads.each do |key, nested_preloads|
37
- path << key
38
- result << path.dup
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
- paths(nested_preloads, path, result)
41
- path.pop
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
- result
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.11.2
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-04-30 00:00:00.000000000 Z
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/main_preload_path.rb
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.7
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