serega 0.42.0 → 0.50.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 +124 -1207
- data/VERSION +1 -1
- data/lib/serega/attribute.rb +186 -131
- data/lib/serega/attribute_normalizer.rb +164 -345
- data/lib/serega/attribute_normalizers/batch.rb +45 -0
- data/lib/serega/attribute_normalizers/block.rb +81 -0
- data/lib/serega/attribute_normalizers/delegate.rb +34 -0
- data/lib/serega/attribute_normalizers/hash_access.rb +37 -0
- data/lib/serega/attribute_normalizers/preloads.rb +46 -0
- data/lib/serega/attribute_value_resolvers/batch.rb +5 -54
- data/lib/serega/attribute_value_resolvers/const.rb +2 -24
- data/lib/serega/attribute_value_resolvers/delegate.rb +17 -28
- data/lib/serega/attribute_value_resolvers/hash_access.rb +34 -52
- data/lib/serega/attribute_value_resolvers/keyword.rb +10 -25
- data/lib/serega/attribute_values.rb +46 -0
- data/lib/serega/batch_loader.rb +37 -0
- data/lib/serega/conditions.rb +56 -0
- data/lib/serega/config.rb +105 -144
- data/lib/serega/engine/pulls.rb +64 -0
- data/lib/serega/engine/run.rb +106 -0
- data/lib/serega/errors.rb +36 -8
- data/lib/serega/formatter.rb +98 -0
- data/lib/serega/plan/cache.rb +96 -0
- data/lib/serega/plan/per_ractor_cache.rb +23 -0
- data/lib/serega/plan.rb +101 -128
- data/lib/serega/plan_point.rb +44 -151
- data/lib/serega/plugins/activerecord_preloads/activerecord_preloads.rb +13 -80
- data/lib/serega/plugins/activerecord_preloads/lib/preloader.rb +8 -75
- data/lib/serega/plugins/context_metadata/context_metadata.rb +40 -123
- data/lib/serega/plugins/metadata/check_params.rb +80 -0
- data/lib/serega/plugins/metadata/meta_attribute.rb +40 -79
- data/lib/serega/plugins/metadata/metadata.rb +40 -168
- data/lib/serega/plugins/root/root.rb +91 -235
- data/lib/serega/plugins.rb +16 -49
- data/lib/serega/presenter.rb +61 -19
- data/lib/serega/result_builder.rb +68 -0
- data/lib/serega/result_code.rb +203 -0
- data/lib/serega/shareable.rb +52 -0
- data/lib/serega/source_group.rb +187 -0
- data/lib/serega/utils/collection_detector.rb +19 -13
- data/lib/serega/utils/deep_merge.rb +26 -0
- data/lib/serega/utils/enum_deep_dup.rb +10 -16
- data/lib/serega/utils/enum_deep_freeze.rb +8 -14
- data/lib/serega/utils/method_signature.rb +6 -15
- data/lib/serega/utils/parse_string_modifiers.rb +63 -0
- data/lib/serega/utils/ractor_local.rb +36 -0
- data/lib/serega/utils/serialized_attribute_error.rb +60 -20
- data/lib/serega/utils/to_hash.rb +5 -26
- data/lib/serega/validations/attribute/check_block.rb +3 -15
- data/lib/serega/validations/attribute/check_name.rb +4 -15
- data/lib/serega/validations/attribute/check_opt_base_serializer.rb +3 -15
- data/lib/serega/validations/attribute/check_opt_batch.rb +26 -56
- data/lib/serega/validations/attribute/check_opt_condition.rb +55 -0
- data/lib/serega/validations/attribute/check_opt_delegate.rb +10 -63
- data/lib/serega/validations/attribute/check_opt_format.rb +36 -0
- data/lib/serega/validations/attribute/check_opt_hash_access.rb +11 -59
- data/lib/serega/validations/attribute/check_opt_hide.rb +3 -14
- data/lib/serega/validations/attribute/check_opt_many.rb +18 -20
- data/lib/serega/validations/attribute/check_opt_method.rb +3 -25
- data/lib/serega/validations/attribute/check_opt_preload.rb +3 -26
- data/lib/serega/validations/attribute/check_opt_serializer.rb +4 -18
- data/lib/serega/validations/attribute/check_opt_value.rb +3 -21
- data/lib/serega/validations/check_attribute_params.rb +92 -71
- data/lib/serega/validations/check_batch_loader_params.rb +43 -62
- data/lib/serega/validations/check_formatter.rb +80 -0
- data/lib/serega/validations/check_serialize_keywords.rb +23 -0
- data/lib/serega/validations/initiate/check_modifiers.rb +14 -20
- data/lib/serega/validations/utils/check_allowed_keys.rb +3 -13
- data/lib/serega/validations/utils/check_hash_access_value.rb +44 -0
- data/lib/serega/validations/utils/check_opt_is_bool.rb +3 -13
- data/lib/serega/validations/utils/check_opt_is_hash.rb +3 -13
- data/lib/serega/validations/utils/check_opt_is_string_or_symbol.rb +3 -13
- data/lib/serega/version.rb +1 -4
- data/lib/serega.rb +459 -388
- data/sig/serega/plugins.rbs +49 -0
- data/sig/serega.rbs +142 -0
- metadata +42 -38
- data/lib/serega/data_builder.rb +0 -54
- data/lib/serega/engine/level.rb +0 -59
- data/lib/serega/engine/level_queue.rb +0 -56
- data/lib/serega/engine/loader.rb +0 -70
- data/lib/serega/helpers/serializer_class_helper.rb +0 -19
- data/lib/serega/object_serializer.rb +0 -125
- data/lib/serega/plugins/camel_case/camel_case.rb +0 -213
- data/lib/serega/plugins/depth_limit/depth_limit.rb +0 -206
- data/lib/serega/plugins/explicit_many_option/explicit_many_option.rb +0 -69
- data/lib/serega/plugins/explicit_many_option/validations/check_opt_many.rb +0 -38
- data/lib/serega/plugins/formatters/formatters.rb +0 -322
- data/lib/serega/plugins/if/if.rb +0 -287
- data/lib/serega/plugins/if/validations/check_opt_if.rb +0 -72
- data/lib/serega/plugins/if/validations/check_opt_if_value.rb +0 -77
- data/lib/serega/plugins/if/validations/check_opt_unless.rb +0 -72
- data/lib/serega/plugins/if/validations/check_opt_unless_value.rb +0 -77
- data/lib/serega/plugins/metadata/validations/check_block.rb +0 -47
- data/lib/serega/plugins/metadata/validations/check_opt_const.rb +0 -39
- data/lib/serega/plugins/metadata/validations/check_opt_hide_empty.rb +0 -35
- data/lib/serega/plugins/metadata/validations/check_opt_hide_nil.rb +0 -35
- data/lib/serega/plugins/metadata/validations/check_opt_value.rb +0 -61
- data/lib/serega/plugins/metadata/validations/check_opts.rb +0 -59
- data/lib/serega/plugins/metadata/validations/check_path.rb +0 -50
- data/lib/serega/plugins/string_modifiers/parse_string_modifiers.rb +0 -111
- data/lib/serega/plugins/string_modifiers/string_modifiers.rb +0 -63
- data/lib/serega/utils/symbol_name.rb +0 -39
- data/lib/serega/validations/attribute/check_opt_const.rb +0 -40
- data/lib/serega/validations/check_initiate_params.rb +0 -57
- data/lib/serega/validations/check_serialize_params.rb +0 -54
data/lib/serega/plan_point.rb
CHANGED
|
@@ -4,162 +4,55 @@ class Serega
|
|
|
4
4
|
#
|
|
5
5
|
# Combines attribute and nested attributes
|
|
6
6
|
#
|
|
7
|
-
#
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
#
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
#
|
|
33
|
-
# @param plan [SeregaPlan] Current plan this point belongs to
|
|
34
|
-
# @param attribute [SeregaAttribute] Attribute to construct plan point
|
|
35
|
-
# @param modifiers Serialization parameters
|
|
36
|
-
# @option modifiers [Hash] :only The only attributes to serialize
|
|
37
|
-
# @option modifiers [Hash] :except Attributes to hide
|
|
38
|
-
# @option modifiers [Hash] :with Hidden attributes to serialize additionally
|
|
39
|
-
#
|
|
40
|
-
# @return [SeregaPlanPoint] New plan point
|
|
41
|
-
#
|
|
42
|
-
def initialize(plan, attribute, modifiers = nil)
|
|
43
|
-
@plan = plan
|
|
44
|
-
@attribute = attribute
|
|
45
|
-
@modifiers = modifiers
|
|
46
|
-
set_normalized_vars
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# Attribute `value`
|
|
50
|
-
# @see SeregaAttribute::AttributeInstanceMethods#value
|
|
51
|
-
def value(obj, ctx, batches: nil)
|
|
52
|
-
attribute.value(obj, ctx, batches: batches)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Attribute `name`
|
|
56
|
-
# @see SeregaAttribute::AttributeInstanceMethods#value
|
|
57
|
-
def name
|
|
58
|
-
attribute.name
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# Attribute `many` option
|
|
62
|
-
# @see SeregaAttribute::AttributeInstanceMethods#many
|
|
63
|
-
def many
|
|
64
|
-
attribute.many
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# Attribute `serializer` option
|
|
68
|
-
# @see SeregaAttribute::AttributeInstanceMethods#serializer
|
|
69
|
-
def serializer
|
|
70
|
-
attribute.serializer
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# Attribute `batch_loaders`
|
|
74
|
-
# @see SeregaAttribute::AttributeInstanceMethods#batch_loaders
|
|
75
|
-
def batch_loaders
|
|
76
|
-
attribute.batch_loaders
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
# Attribute `preloads`
|
|
80
|
-
# @see SeregaAttribute::AttributeInstanceMethods#preloads
|
|
81
|
-
def preloads
|
|
82
|
-
attribute.preloads
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
# Runs this point's declared preloads over the given objects using the
|
|
86
|
-
# serializer's registered preload handler.
|
|
87
|
-
#
|
|
88
|
-
# Presenters are unwrapped first, as preload handlers work with the
|
|
89
|
-
# serialized objects themselves.
|
|
90
|
-
#
|
|
91
|
-
# @param objects [Array] objects serialized at this point's level
|
|
92
|
-
# @return [void]
|
|
93
|
-
def run_preloads(objects)
|
|
94
|
-
return unless preloads
|
|
95
|
-
|
|
96
|
-
serializer_class = self.class.serializer_class
|
|
97
|
-
objects = objects.map(&:__getobj__) if serializer_class.presenter
|
|
98
|
-
|
|
99
|
-
handler = serializer_class.preload_with
|
|
100
|
-
unless handler
|
|
101
|
-
raise SeregaError, "The :preload option requires a preload handler. Register one with `preload_with` (the :activerecord_preloads plugin does this for you)."
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
handler.call(objects, preloads)
|
|
105
|
-
rescue => error
|
|
106
|
-
SeregaUtils::SerializedAttributeError.call(error, self)
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
# Loads the batch loaders this point's value needs, each once for the whole
|
|
110
|
-
# level, and returns them keyed by loader name for #value to read from.
|
|
111
|
-
#
|
|
112
|
-
# @param level [SeregaEngine::Level] level whose objects are loaded for
|
|
113
|
-
# @return [Hash, nil] loaded data per loader name, or nil when none are needed
|
|
114
|
-
def load_batches(level)
|
|
115
|
-
names = batch_loaders
|
|
116
|
-
return if names.empty?
|
|
117
|
-
|
|
118
|
-
loaders = self.class.serializer_class.batch_loaders
|
|
119
|
-
names.each_with_object({}) do |name, batches|
|
|
120
|
-
batches[name] = level.fetch(loaders[name])
|
|
121
|
-
end
|
|
122
|
-
rescue => error
|
|
123
|
-
SeregaUtils::SerializedAttributeError.call(error, self)
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
#
|
|
127
|
-
# @return [Class<SeregaObjectSerializer>] object serializer class for child plan
|
|
128
|
-
#
|
|
129
|
-
def child_object_serializer
|
|
130
|
-
serializer::SeregaObjectSerializer
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
# Builds the object serializer that serializes this point's relation, or nil
|
|
134
|
-
# when the point has no child plan (a plain attribute). The point owns the
|
|
135
|
-
# static config (child plan, serializer class, `many`); the caller injects the
|
|
136
|
-
# runtime `context` and `opts`.
|
|
137
|
-
#
|
|
138
|
-
# @param context [Hash] serialization context
|
|
139
|
-
# @param opts [Hash] extra object-serializer options (e.g. the level queue)
|
|
140
|
-
# @return [SeregaObjectSerializer, nil] serializer for the child level
|
|
141
|
-
def child_serializer(context:, **opts)
|
|
142
|
-
return unless child_plan
|
|
143
|
-
|
|
144
|
-
child_object_serializer.new(context: context, plan: child_plan, many: many, **opts)
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
private
|
|
7
|
+
class SeregaPlanPoint # :nodoc:
|
|
8
|
+
# Link to current plan this point belongs to
|
|
9
|
+
attr_reader :plan
|
|
10
|
+
|
|
11
|
+
# Shows current attribute
|
|
12
|
+
attr_reader :attribute
|
|
13
|
+
|
|
14
|
+
# Attribute `name`
|
|
15
|
+
attr_reader :name
|
|
16
|
+
|
|
17
|
+
# Shows child plan if exists
|
|
18
|
+
attr_reader :child_plan
|
|
19
|
+
|
|
20
|
+
# Whether the relation values of a class are collections, for a point
|
|
21
|
+
# with a child plan
|
|
22
|
+
attr_reader :collection_classes
|
|
23
|
+
|
|
24
|
+
# Initializes plan point
|
|
25
|
+
def initialize(plan, attribute, modifiers = nil)
|
|
26
|
+
@plan = plan
|
|
27
|
+
@attribute = attribute
|
|
28
|
+
@name = attribute.name
|
|
29
|
+
@child_plan = serializer ? SeregaPlan.new(serializer, self, modifiers || FROZEN_EMPTY_HASH) : nil
|
|
30
|
+
@collection_classes = @child_plan ? {}.compare_by_identity : nil
|
|
31
|
+
end
|
|
148
32
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
33
|
+
# Attribute `many` option
|
|
34
|
+
def many
|
|
35
|
+
attribute.many
|
|
36
|
+
end
|
|
152
37
|
|
|
153
|
-
|
|
154
|
-
|
|
38
|
+
# Attribute `serializer` option
|
|
39
|
+
def serializer
|
|
40
|
+
attribute.serializer
|
|
41
|
+
end
|
|
155
42
|
|
|
156
|
-
|
|
43
|
+
# Attribute `batch_loaders`
|
|
44
|
+
def batch_loaders
|
|
45
|
+
attribute.batch_loaders
|
|
46
|
+
end
|
|
157
47
|
|
|
158
|
-
|
|
159
|
-
|
|
48
|
+
# Attribute `preloads`
|
|
49
|
+
def preloads
|
|
50
|
+
attribute.preloads
|
|
160
51
|
end
|
|
161
52
|
|
|
162
|
-
|
|
163
|
-
|
|
53
|
+
# Attribute `conditional?`
|
|
54
|
+
def conditional?
|
|
55
|
+
attribute.conditional?
|
|
56
|
+
end
|
|
164
57
|
end
|
|
165
58
|
end
|
|
@@ -2,97 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
class Serega
|
|
4
4
|
module SeregaPlugins
|
|
5
|
+
# `plugin :activerecord_preloads` loads every `:preload` of the serialized
|
|
6
|
+
# fields once, with `ActiveRecord::Associations::Preloader`
|
|
5
7
|
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# @example
|
|
14
|
-
# class AppSerializer < Serega
|
|
15
|
-
# config.auto_preload = true
|
|
16
|
-
# plugin :activerecord_preloads
|
|
17
|
-
# end
|
|
18
|
-
#
|
|
19
|
-
# class AlbumSerializer < AppSerializer
|
|
20
|
-
# # no preloads
|
|
21
|
-
# attribute :title
|
|
22
|
-
#
|
|
23
|
-
# # preloads :downloads, as manually specified
|
|
24
|
-
# attribute :downloads_count, preload: :downloads, value: proc { |album| album.downloads.count }
|
|
25
|
-
# end
|
|
26
|
-
#
|
|
27
|
-
# class UserSerializer < AppSerializer
|
|
28
|
-
# # no preloads
|
|
29
|
-
# attribute :username
|
|
30
|
-
#
|
|
31
|
-
# # preloads :user_stats, as auto_preload is enabled for :delegate attributes
|
|
32
|
-
# attribute :comments_count, delegate: { to: :user_stats }
|
|
33
|
-
#
|
|
34
|
-
# # preloads :albums, as auto_preload is enabled for :serializer attributes
|
|
35
|
-
# attribute :albums, serializer: AlbumSerializer
|
|
36
|
-
# end
|
|
37
|
-
#
|
|
38
|
-
# UserSerializer.to_h(users)
|
|
39
|
-
# # 1 query to load :user_stats for all users
|
|
40
|
-
# # + 1 query to load :albums for all users
|
|
41
|
-
# # + 1 query to load :downloads for all albums
|
|
42
|
-
# # = 3 queries total, regardless of how many users/albums are serialized
|
|
8
|
+
# ```ruby
|
|
9
|
+
# class AppSerializer < Serega
|
|
10
|
+
# plugin :activerecord_preloads
|
|
11
|
+
# config.auto_preload = true
|
|
12
|
+
# end
|
|
13
|
+
# ```
|
|
43
14
|
#
|
|
15
|
+
# See [ActiveRecord preloads](https://github.com/andreyruby/serega/blob/master/docs/preloads.md#activerecord).
|
|
44
16
|
module ActiverecordPreloads
|
|
45
|
-
#
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def self.plugin_name
|
|
50
|
-
:activerecord_preloads
|
|
51
|
-
end
|
|
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
|
-
# @private
|
|
61
|
-
def self.before_load_plugin(serializer_class, **opts)
|
|
62
|
-
opts.each_key do |key|
|
|
63
|
-
raise SeregaError, "Plugin #{plugin_name.inspect} does not accept the #{key.inspect} option. No options are allowed"
|
|
17
|
+
# Adds the plugin to the serializer
|
|
18
|
+
def self.apply(serializer_class, **opts) # :nodoc:
|
|
19
|
+
unless opts.empty?
|
|
20
|
+
raise SeregaError, "Plugin :activerecord_preloads does not accept the #{opts.keys.first.inspect} option. No options are allowed"
|
|
64
21
|
end
|
|
65
|
-
end
|
|
66
22
|
|
|
67
|
-
#
|
|
68
|
-
# Applies plugin code to specific serializer
|
|
69
|
-
#
|
|
70
|
-
# @param serializer_class [Class<Serega>] Current serializer class
|
|
71
|
-
# @param _opts [Hash] Plugin options
|
|
72
|
-
#
|
|
73
|
-
# @return [void]
|
|
74
|
-
#
|
|
75
|
-
# @private
|
|
76
|
-
def self.load_plugin(serializer_class, **_opts)
|
|
77
23
|
require_relative "lib/preloader"
|
|
78
|
-
end
|
|
79
24
|
|
|
80
|
-
#
|
|
81
|
-
# Registers the ActiveRecord preload handler
|
|
82
|
-
#
|
|
83
|
-
# @param serializer_class [Class<Serega>] Current serializer class
|
|
84
|
-
# @param _opts [Hash] Plugin options
|
|
85
|
-
#
|
|
86
|
-
# @return [void]
|
|
87
|
-
#
|
|
88
|
-
# @private
|
|
89
|
-
def self.after_load_plugin(serializer_class, **_opts)
|
|
90
25
|
serializer_class.preload_with do |objects, preloads|
|
|
91
26
|
Preloader.preload(objects, preloads)
|
|
92
27
|
end
|
|
93
28
|
end
|
|
94
29
|
end
|
|
95
|
-
|
|
96
|
-
register_plugin(ActiverecordPreloads.plugin_name, ActiverecordPreloads)
|
|
97
30
|
end
|
|
98
31
|
end
|
|
@@ -4,16 +4,9 @@ class Serega
|
|
|
4
4
|
module SeregaPlugins
|
|
5
5
|
module ActiverecordPreloads
|
|
6
6
|
# Handles preloads for different types of initial records
|
|
7
|
-
#
|
|
8
|
-
class Preloader
|
|
7
|
+
class Preloader # :nodoc:
|
|
9
8
|
class << self
|
|
10
9
|
# Preloads associations to records
|
|
11
|
-
#
|
|
12
|
-
# @param object [Object] record(s)
|
|
13
|
-
# @param preloads [Hash] associations names
|
|
14
|
-
#
|
|
15
|
-
# @return [Object] provided object with preloaded associations
|
|
16
|
-
#
|
|
17
10
|
def preload(object, preloads)
|
|
18
11
|
return object if object.nil? || (object.is_a?(Array) && object.empty?)
|
|
19
12
|
|
|
@@ -23,9 +16,7 @@ class Serega
|
|
|
23
16
|
preload_handler.preload(object, preloads)
|
|
24
17
|
end
|
|
25
18
|
|
|
26
|
-
# Returns handlers which will try to check if
|
|
27
|
-
#
|
|
28
|
-
# @return [Array] Registered preload adapters for different types of initial records
|
|
19
|
+
# Returns handlers which will try to check if the object to serialize fits for preloading using this handler
|
|
29
20
|
def handlers
|
|
30
21
|
@handlers ||= [
|
|
31
22
|
ActiverecordRelation,
|
|
@@ -38,47 +29,22 @@ class Serega
|
|
|
38
29
|
end
|
|
39
30
|
|
|
40
31
|
# Associations loader for prepared records
|
|
41
|
-
#
|
|
42
|
-
class Loader
|
|
43
|
-
# :nocov: We can check only one version of activerecord
|
|
44
|
-
|
|
32
|
+
class Loader # :nodoc:
|
|
45
33
|
# Preloads associations to records
|
|
46
|
-
#
|
|
47
|
-
# @param records [Array<ActiveRecord::Base>] records
|
|
48
|
-
# @param associations [Hash] associations names
|
|
49
|
-
#
|
|
50
|
-
# @return [void]
|
|
51
|
-
#
|
|
52
34
|
def self.call(records, associations)
|
|
53
|
-
|
|
54
|
-
ActiveRecord::Associations::Preloader.new(records: records, associations: associations).call
|
|
55
|
-
else
|
|
56
|
-
ActiveRecord::Associations::Preloader.new.preload(records, associations)
|
|
57
|
-
end
|
|
35
|
+
ActiveRecord::Associations::Preloader.new(records: records, associations: associations).call
|
|
58
36
|
end
|
|
59
|
-
# :nocov:
|
|
60
37
|
end
|
|
61
38
|
|
|
62
39
|
# Preloader adapter for ActiveRecord object
|
|
63
|
-
#
|
|
64
|
-
class ActiverecordObject
|
|
40
|
+
class ActiverecordObject # :nodoc:
|
|
65
41
|
class << self
|
|
66
|
-
#
|
|
67
42
|
# Checks object is kind of ActiveRecord::Base
|
|
68
|
-
#
|
|
69
|
-
# @param object [Object] object
|
|
70
|
-
#
|
|
71
|
-
# @return [Boolean] whether object is kind of ActiveRecord::Base
|
|
72
43
|
def fit?(object)
|
|
73
44
|
object.is_a?(ActiveRecord::Base)
|
|
74
45
|
end
|
|
75
46
|
|
|
76
|
-
#
|
|
77
47
|
# Preloads associations to ActiveRecord::Base record
|
|
78
|
-
#
|
|
79
|
-
# @param record [ActiveRecord::Base] record
|
|
80
|
-
#
|
|
81
|
-
# @return [Object] provided record with preloaded associations
|
|
82
48
|
def preload(record, preloads)
|
|
83
49
|
Loader.call([record], preloads)
|
|
84
50
|
record
|
|
@@ -87,25 +53,14 @@ class Serega
|
|
|
87
53
|
end
|
|
88
54
|
|
|
89
55
|
# Preloader adapter for ActiveRecord::Relation
|
|
90
|
-
#
|
|
91
|
-
class ActiverecordRelation
|
|
56
|
+
class ActiverecordRelation # :nodoc:
|
|
92
57
|
class << self
|
|
93
|
-
#
|
|
94
58
|
# Checks object is kind of ActiveRecord::Relation
|
|
95
|
-
#
|
|
96
|
-
# @param object [Object] object to check
|
|
97
|
-
#
|
|
98
|
-
# @return [Boolean] whether object is kind of ActiveRecord::Relation
|
|
99
59
|
def fit?(object)
|
|
100
60
|
object.is_a?(ActiveRecord::Relation)
|
|
101
61
|
end
|
|
102
62
|
|
|
103
|
-
#
|
|
104
63
|
# Preloads associations to ActiveRecord::Relation
|
|
105
|
-
#
|
|
106
|
-
# @param scope [ActiveRecord::Relation] scope
|
|
107
|
-
#
|
|
108
|
-
# @return [ActiveRecord::Relation] provided scope with preloaded associations
|
|
109
64
|
def preload(scope, preloads)
|
|
110
65
|
scope.load
|
|
111
66
|
Loader.call(scope.to_a, preloads)
|
|
@@ -115,27 +70,16 @@ class Serega
|
|
|
115
70
|
end
|
|
116
71
|
|
|
117
72
|
# Preloader adapter for Array of ActiveRecord objects
|
|
118
|
-
#
|
|
119
|
-
class ActiverecordArray
|
|
73
|
+
class ActiverecordArray # :nodoc:
|
|
120
74
|
class << self
|
|
121
|
-
#
|
|
122
75
|
# Checks object is an array of ActiveRecord::Base objects
|
|
123
|
-
#
|
|
124
|
-
# @param object [Object] object
|
|
125
|
-
#
|
|
126
|
-
# @return [Boolean] whether object is an array with ActiveRecord objects (and all objects have same class)
|
|
127
76
|
def fit?(object)
|
|
128
77
|
object.is_a?(Array) &&
|
|
129
78
|
ActiverecordObject.fit?(object.first) &&
|
|
130
79
|
same_kind?(object)
|
|
131
80
|
end
|
|
132
81
|
|
|
133
|
-
#
|
|
134
82
|
# Preloads associations to array with ActiveRecord::Base objects
|
|
135
|
-
#
|
|
136
|
-
# @param records [Array<ActiveRecord::Base>] ActiveRecord records
|
|
137
|
-
#
|
|
138
|
-
# @return [Array<ActiveRecord::Base>] provided records with preloaded associations
|
|
139
83
|
def preload(records, preloads)
|
|
140
84
|
Loader.call(records, preloads)
|
|
141
85
|
records
|
|
@@ -151,26 +95,15 @@ class Serega
|
|
|
151
95
|
end
|
|
152
96
|
|
|
153
97
|
# Preloader adapter for Enumerator with ActiveRecord objects
|
|
154
|
-
#
|
|
155
|
-
class ActiverecordEnumerator
|
|
98
|
+
class ActiverecordEnumerator # :nodoc:
|
|
156
99
|
class << self
|
|
157
|
-
#
|
|
158
100
|
# Checks object is an Enumerator with each value is a ActiveRecord::Base object
|
|
159
|
-
#
|
|
160
|
-
# @param object [Object] object
|
|
161
|
-
#
|
|
162
|
-
# @return [Boolean] whether object is an Enumerator with each value is a ActiveRecord::Base object
|
|
163
101
|
def fit?(object)
|
|
164
102
|
object.is_a?(Enumerator) &&
|
|
165
103
|
ActiverecordArray.fit?(object.to_a)
|
|
166
104
|
end
|
|
167
105
|
|
|
168
|
-
#
|
|
169
106
|
# Preloads associations to Enumerator with ActiveRecord::Base objects
|
|
170
|
-
#
|
|
171
|
-
# @param enum [Enumerator<ActiveRecord::Base>] enum
|
|
172
|
-
#
|
|
173
|
-
# @return [Enumerator<ActiveRecord::Base>] provided enumerator with preloaded associations
|
|
174
107
|
def preload(enum, preloads)
|
|
175
108
|
ActiverecordArray.preload(enum.to_a, preloads)
|
|
176
109
|
enum
|