serega 0.20.0 → 0.21.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 +3 -0
- data/VERSION +1 -1
- data/lib/serega/object_serializer.rb +1 -0
- data/lib/serega/plugins/activerecord_preloads/activerecord_preloads.rb +17 -10
- data/lib/serega/plugins/batch/batch.rb +5 -0
- data/lib/serega/plugins/batch/lib/plugins_extensions/if.rb +31 -0
- data/lib/serega/plugins/if/if.rb +19 -2
- data/lib/serega/plugins/preloads/preloads.rb +4 -0
- data/lib/serega/plugins/string_modifiers/parse_string_modifiers.rb +43 -30
- data/lib/serega.rb +12 -4
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ea0f19662815497e76a3ace9b247e90268f7c44a3cf917b97a186887043fc7b
|
4
|
+
data.tar.gz: fb13ebbaa26603c0eda053e78634aaecf1a8d040c73b5824892b03c2b0d2a70d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a5847251f29dfd44a7da2cd9b5a99411aa430323d1d57e7706e176cc234f96ff7575298c5909c753aa4f3a2895d41a48c3c6a5b67a95e0bdac935f38c5c6f15d
|
7
|
+
data.tar.gz: 4fdf12f075816ea3ba155ace47b6f5e6c7b3b0bcd000179e43e4edf356e63b19360de227b6112b4fe98e310975da4afebc3d5c86476deadc749c4197330ddfd0
|
data/README.md
CHANGED
@@ -549,6 +549,9 @@ UserSerializer.to_h(user)
|
|
549
549
|
# => preloads {users_stats: {}, albums: { downloads: {} }}
|
550
550
|
```
|
551
551
|
|
552
|
+
For testing purposes preloading can be done manually with
|
553
|
+
`#preload_association_to(obj)` instance method
|
554
|
+
|
552
555
|
### Plugin :batch
|
553
556
|
|
554
557
|
Helps to omit N+1.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.21.0
|
@@ -90,6 +90,22 @@ class Serega
|
|
90
90
|
# Overrides Serega class instance methods
|
91
91
|
#
|
92
92
|
module InstanceMethods
|
93
|
+
#
|
94
|
+
# Preloads associations to object
|
95
|
+
#
|
96
|
+
# @param object [Object] Any object
|
97
|
+
# @return provided object
|
98
|
+
#
|
99
|
+
def preload_associations_to(object)
|
100
|
+
return object if object.nil? || (object.is_a?(Array) && object.empty?)
|
101
|
+
|
102
|
+
preloads = preloads() # `preloads()` method comes from :preloads plugin
|
103
|
+
return object if preloads.empty?
|
104
|
+
|
105
|
+
Preloader.preload(object, preloads)
|
106
|
+
object
|
107
|
+
end
|
108
|
+
|
93
109
|
private
|
94
110
|
|
95
111
|
#
|
@@ -97,18 +113,9 @@ class Serega
|
|
97
113
|
# Preloads associations to object before serialization
|
98
114
|
#
|
99
115
|
def serialize(object, _opts)
|
100
|
-
|
116
|
+
preload_associations_to(object)
|
101
117
|
super
|
102
118
|
end
|
103
|
-
|
104
|
-
def add_preloads(obj)
|
105
|
-
return obj if obj.nil? || (obj.is_a?(Array) && obj.empty?)
|
106
|
-
|
107
|
-
preloads = preloads() # `preloads()` method comes from :preloads plugin
|
108
|
-
return obj if preloads.empty?
|
109
|
-
|
110
|
-
Preloader.preload(obj, preloads)
|
111
|
-
end
|
112
119
|
end
|
113
120
|
end
|
114
121
|
|
@@ -105,6 +105,11 @@ class Serega
|
|
105
105
|
serializer_class::SeregaAttribute.include(PluginsExtensions::Formatters::SeregaAttributeInstanceMethods)
|
106
106
|
end
|
107
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
|
+
|
108
113
|
if serializer_class.plugin_used?(:preloads)
|
109
114
|
require_relative "lib/plugins_extensions/preloads"
|
110
115
|
serializer_class::SeregaAttributeNormalizer.include(PluginsExtensions::Preloads::AttributeNormalizerInstanceMethods)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Serega
|
4
|
+
module SeregaPlugins
|
5
|
+
module Batch
|
6
|
+
#
|
7
|
+
# Extensions (mini-plugins) that are enabled when :batch plugin used with other plugins
|
8
|
+
#
|
9
|
+
module PluginsExtensions
|
10
|
+
#
|
11
|
+
# Extension that is used when :if plugin is loaded
|
12
|
+
#
|
13
|
+
module If
|
14
|
+
#
|
15
|
+
# SeregaObjectSerializer additional/patched class methods
|
16
|
+
#
|
17
|
+
# @see Serega::SeregaObjectSerializer
|
18
|
+
#
|
19
|
+
module ObjectSerializerInstanceMethods123
|
20
|
+
private
|
21
|
+
|
22
|
+
# Removes key added by `batch` plugin at the start of serialization to preserve attributes ordering
|
23
|
+
def attach_final_value(value, point, container)
|
24
|
+
container.delete(point.name) if super == SeregaPlugins::If::KEY_SKIPPED
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/serega/plugins/if/if.rb
CHANGED
@@ -42,11 +42,27 @@ class Serega
|
|
42
42
|
# end
|
43
43
|
#
|
44
44
|
module If
|
45
|
+
# This value must be returned to identify that serialization key was skipped
|
46
|
+
KEY_SKIPPED = :_key_skipped_with_serega_if_plugin
|
47
|
+
|
45
48
|
# @return [Symbol] Plugin name
|
46
49
|
def self.plugin_name
|
47
50
|
:if
|
48
51
|
end
|
49
52
|
|
53
|
+
# Checks requirements to load plugin
|
54
|
+
#
|
55
|
+
# @param serializer_class [Class<Serega>] Current serializer class
|
56
|
+
# @param opts [Hash] plugin options
|
57
|
+
#
|
58
|
+
# @return [void]
|
59
|
+
#
|
60
|
+
def self.before_load_plugin(serializer_class, **opts)
|
61
|
+
if serializer_class.plugin_used?(:batch)
|
62
|
+
raise SeregaError, "Plugin #{plugin_name.inspect} must be loaded before the :batch plugin"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
50
66
|
#
|
51
67
|
# Applies plugin code to specific serializer
|
52
68
|
#
|
@@ -194,12 +210,13 @@ class Serega
|
|
194
210
|
private
|
195
211
|
|
196
212
|
def serialize_point(object, point, _container)
|
197
|
-
return unless point.satisfy_if_conditions?(object, context)
|
213
|
+
return KEY_SKIPPED unless point.satisfy_if_conditions?(object, context)
|
198
214
|
super
|
199
215
|
end
|
200
216
|
|
201
217
|
def attach_final_value(value, point, _container)
|
202
|
-
return unless point.satisfy_if_value_conditions?(value, context)
|
218
|
+
return KEY_SKIPPED unless point.satisfy_if_value_conditions?(value, context)
|
219
|
+
|
203
220
|
super
|
204
221
|
end
|
205
222
|
end
|
@@ -88,6 +88,10 @@ class Serega
|
|
88
88
|
" - :auto_preload_attributes_with_serializer [Boolean] - Automatically adds `preload: <attribute_name>` option to attributes with :serializer option specified\n" \
|
89
89
|
" - :auto_hide_attributes_with_preload [Boolean] - Automatically adds `hide: true` option to attributes with :preload option (specified manually or added automatically)"
|
90
90
|
end
|
91
|
+
|
92
|
+
if serializer_class.plugin_used?(:batch)
|
93
|
+
raise SeregaError, "Plugin #{plugin_name.inspect} must be loaded before the :batch plugin"
|
94
|
+
end
|
91
95
|
end
|
92
96
|
|
93
97
|
#
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "stringio"
|
4
|
-
|
5
3
|
class Serega
|
6
4
|
module SeregaPlugins
|
7
5
|
#
|
@@ -25,6 +23,14 @@ class Serega
|
|
25
23
|
# Modifiers parser
|
26
24
|
#
|
27
25
|
class ParseStringModifiers
|
26
|
+
COMMA = ","
|
27
|
+
COMMA_CODEPOINT = COMMA.ord
|
28
|
+
LPAREN = "("
|
29
|
+
LPAREN_CODEPOINT = LPAREN.ord
|
30
|
+
RPAREN = ")"
|
31
|
+
RPAREN_CODEPOINT = RPAREN.ord
|
32
|
+
private_constant :COMMA, :LPAREN, :RPAREN, :COMMA_CODEPOINT, :LPAREN_CODEPOINT, :RPAREN_CODEPOINT
|
33
|
+
|
28
34
|
class << self
|
29
35
|
#
|
30
36
|
# Parses string modifiers
|
@@ -40,45 +46,52 @@ class Serega
|
|
40
46
|
# parse("user,comments") => { user: {}, comments: {} }
|
41
47
|
# parse("user(comments(text))") => { user: { comments: { text: {} } } }
|
42
48
|
def parse(fields)
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
path_stack = nil
|
47
|
-
fields = StringIO.new(fields)
|
49
|
+
result = {}
|
50
|
+
attribute_storage = result
|
51
|
+
path_stack = (fields.include?(LPAREN) || fields.include?(RPAREN)) ? [] : nil
|
48
52
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
when
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
53
|
+
start_index = 0
|
54
|
+
end_index = 0
|
55
|
+
fields.each_codepoint do |codepoint|
|
56
|
+
case codepoint
|
57
|
+
when COMMA_CODEPOINT
|
58
|
+
attribute = extract_attribute(fields, start_index, end_index)
|
59
|
+
add_attribute(attribute_storage, attribute, FROZEN_EMPTY_HASH) if attribute
|
60
|
+
start_index = end_index + 1
|
61
|
+
when LPAREN_CODEPOINT
|
62
|
+
attribute = extract_attribute(fields, start_index, end_index)
|
63
|
+
if attribute
|
64
|
+
attribute_storage = add_attribute(attribute_storage, attribute, {})
|
65
|
+
path_stack.push(attribute)
|
66
|
+
end
|
67
|
+
start_index = end_index + 1
|
68
|
+
when RPAREN_CODEPOINT
|
69
|
+
attribute = extract_attribute(fields, start_index, end_index)
|
70
|
+
add_attribute(attribute_storage, attribute, FROZEN_EMPTY_HASH) if attribute
|
71
|
+
path_stack.pop
|
72
|
+
attribute_storage = dig?(result, path_stack)
|
73
|
+
start_index = end_index + 1
|
61
74
|
end
|
75
|
+
|
76
|
+
end_index += 1
|
62
77
|
end
|
63
78
|
|
64
|
-
|
79
|
+
attribute = extract_attribute(fields, start_index, end_index)
|
80
|
+
add_attribute(attribute_storage, attribute, FROZEN_EMPTY_HASH) if attribute
|
65
81
|
|
66
|
-
|
82
|
+
result
|
67
83
|
end
|
68
84
|
|
69
85
|
private
|
70
86
|
|
71
|
-
def
|
87
|
+
def extract_attribute(fields, start_index, end_index)
|
88
|
+
attribute = fields[start_index, end_index - start_index]
|
72
89
|
attribute.strip!
|
73
|
-
|
74
|
-
|
75
|
-
name = attribute.to_sym
|
76
|
-
attribute.clear
|
77
|
-
|
78
|
-
current_attrs = dig?(res, path_stack)
|
79
|
-
current_attrs[name] = nested_attributes
|
90
|
+
attribute.empty? ? nil : attribute.to_sym
|
91
|
+
end
|
80
92
|
|
81
|
-
|
93
|
+
def add_attribute(storage, attribute, nested_attributes = FROZEN_EMPTY_HASH)
|
94
|
+
storage[attribute] = nested_attributes
|
82
95
|
end
|
83
96
|
|
84
97
|
def dig?(hash, path)
|
data/lib/serega.rb
CHANGED
@@ -167,6 +167,7 @@ class Serega
|
|
167
167
|
modifiers_opts = FROZEN_EMPTY_HASH
|
168
168
|
serialize_opts = nil
|
169
169
|
else
|
170
|
+
opts.transform_keys!(&:to_sym)
|
170
171
|
serialize_opts = opts.except(*initiate_keys)
|
171
172
|
modifiers_opts = opts.slice(*initiate_keys)
|
172
173
|
end
|
@@ -296,7 +297,14 @@ class Serega
|
|
296
297
|
# @option opts [Boolean] :validate Validates provided modifiers (Default is true)
|
297
298
|
#
|
298
299
|
def initialize(opts = nil)
|
299
|
-
@opts =
|
300
|
+
@opts =
|
301
|
+
if opts.nil? || opts.empty?
|
302
|
+
FROZEN_EMPTY_HASH
|
303
|
+
else
|
304
|
+
opts.transform_keys!(&:to_sym)
|
305
|
+
parse_modifiers(opts)
|
306
|
+
end
|
307
|
+
|
300
308
|
self.class::CheckInitiateParams.new(@opts).validate if opts&.fetch(:check_initiate_params) { config.check_initiate_params }
|
301
309
|
|
302
310
|
@plan = self.class::SeregaPlan.call(@opts)
|
@@ -320,10 +328,10 @@ class Serega
|
|
320
328
|
# @return [Hash] Serialization result
|
321
329
|
#
|
322
330
|
def call(object, opts = nil)
|
323
|
-
|
324
|
-
opts
|
325
|
-
opts[:context] ||= {}
|
331
|
+
opts = opts ? opts.transform_keys!(&:to_sym) : {}
|
332
|
+
self.class::CheckSerializeParams.new(opts).validate unless opts.empty?
|
326
333
|
|
334
|
+
opts[:context] ||= {}
|
327
335
|
serialize(object, opts)
|
328
336
|
end
|
329
337
|
|
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.21.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrey Glushkov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-11-18 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |
|
14
14
|
JSON Serializer
|
@@ -54,6 +54,7 @@ files:
|
|
54
54
|
- lib/serega/plugins/batch/lib/modules/plan_point.rb
|
55
55
|
- lib/serega/plugins/batch/lib/plugins_extensions/activerecord_preloads.rb
|
56
56
|
- lib/serega/plugins/batch/lib/plugins_extensions/formatters.rb
|
57
|
+
- lib/serega/plugins/batch/lib/plugins_extensions/if.rb
|
57
58
|
- lib/serega/plugins/batch/lib/plugins_extensions/preloads.rb
|
58
59
|
- lib/serega/plugins/batch/lib/validations/check_batch_opt_id_method.rb
|
59
60
|
- lib/serega/plugins/batch/lib/validations/check_batch_opt_loader.rb
|
@@ -140,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
140
141
|
- !ruby/object:Gem::Version
|
141
142
|
version: '0'
|
142
143
|
requirements: []
|
143
|
-
rubygems_version: 3.5.
|
144
|
+
rubygems_version: 3.5.6
|
144
145
|
signing_key:
|
145
146
|
specification_version: 4
|
146
147
|
summary: JSON Serializer
|