rom 5.4.1 → 6.0.0.alpha1
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/CHANGELOG.md +58 -65
- data/LICENSE +1 -1
- data/README.md +7 -6
- data/lib/rom/array_dataset.rb +46 -0
- data/lib/rom/associations/abstract.rb +217 -0
- data/lib/rom/associations/definitions/abstract.rb +150 -0
- data/lib/rom/associations/definitions/many_to_many.rb +29 -0
- data/lib/rom/associations/definitions/many_to_one.rb +14 -0
- data/lib/rom/associations/definitions/one_to_many.rb +14 -0
- data/lib/rom/associations/definitions/one_to_one.rb +14 -0
- data/lib/rom/associations/definitions/one_to_one_through.rb +14 -0
- data/lib/rom/associations/definitions.rb +7 -0
- data/lib/rom/associations/many_to_many.rb +128 -0
- data/lib/rom/associations/many_to_one.rb +65 -0
- data/lib/rom/associations/one_to_many.rb +65 -0
- data/lib/rom/associations/one_to_one.rb +13 -0
- data/lib/rom/associations/one_to_one_through.rb +13 -0
- data/lib/rom/associations/through_identifier.rb +41 -0
- data/lib/rom/attribute.rb +425 -0
- data/lib/rom/auto_curry.rb +70 -0
- data/lib/rom/cache.rb +87 -0
- data/lib/rom/changeset/associated.rb +110 -0
- data/lib/rom/changeset/create.rb +18 -0
- data/lib/rom/changeset/delete.rb +15 -0
- data/lib/rom/changeset/extensions/relation.rb +26 -0
- data/lib/rom/changeset/pipe.rb +81 -0
- data/lib/rom/changeset/pipe_registry.rb +27 -0
- data/lib/rom/changeset/stateful.rb +285 -0
- data/lib/rom/changeset/update.rb +81 -0
- data/lib/rom/changeset.rb +185 -0
- data/lib/rom/command.rb +351 -0
- data/lib/rom/command_compiler.rb +201 -0
- data/lib/rom/command_proxy.rb +36 -0
- data/lib/rom/commands/class_interface.rb +236 -0
- data/lib/rom/commands/composite.rb +55 -0
- data/lib/rom/commands/create.rb +15 -0
- data/lib/rom/commands/delete.rb +16 -0
- data/lib/rom/commands/graph/class_interface.rb +64 -0
- data/lib/rom/commands/graph/input_evaluator.rb +94 -0
- data/lib/rom/commands/graph.rb +88 -0
- data/lib/rom/commands/lazy/create.rb +35 -0
- data/lib/rom/commands/lazy/delete.rb +39 -0
- data/lib/rom/commands/lazy/update.rb +46 -0
- data/lib/rom/commands/lazy.rb +106 -0
- data/lib/rom/commands/update.rb +16 -0
- data/lib/rom/commands.rb +5 -0
- data/lib/rom/compat/auto_registration.rb +115 -0
- data/lib/rom/compat/auto_registration_strategies/base.rb +29 -0
- data/lib/rom/compat/auto_registration_strategies/custom_namespace.rb +84 -0
- data/lib/rom/compat/auto_registration_strategies/no_namespace.rb +33 -0
- data/lib/rom/compat/auto_registration_strategies/with_namespace.rb +29 -0
- data/lib/rom/compat/command.rb +74 -0
- data/lib/rom/compat/components/dsl/schema.rb +130 -0
- data/lib/rom/compat/components.rb +91 -0
- data/lib/rom/compat/global.rb +17 -0
- data/lib/rom/compat/mapper.rb +22 -0
- data/lib/rom/compat/registries.rb +47 -0
- data/lib/rom/compat/relation.rb +40 -0
- data/lib/rom/compat/schema/dsl.rb +260 -0
- data/lib/rom/compat/setting_proxy.rb +44 -0
- data/lib/rom/compat/setup.rb +151 -0
- data/lib/rom/compat/transformer.rb +49 -0
- data/lib/rom/compat.rb +22 -0
- data/lib/rom/components/association.rb +26 -0
- data/lib/rom/components/command.rb +24 -0
- data/lib/rom/components/core.rb +148 -0
- data/lib/rom/components/dataset.rb +60 -0
- data/lib/rom/components/dsl/association.rb +47 -0
- data/lib/rom/components/dsl/command.rb +60 -0
- data/lib/rom/components/dsl/core.rb +126 -0
- data/lib/rom/components/dsl/dataset.rb +33 -0
- data/lib/rom/components/dsl/gateway.rb +14 -0
- data/lib/rom/components/dsl/mapper.rb +70 -0
- data/lib/rom/components/dsl/relation.rb +49 -0
- data/lib/rom/components/dsl/schema.rb +150 -0
- data/lib/rom/components/dsl/view.rb +82 -0
- data/lib/rom/components/dsl.rb +255 -0
- data/lib/rom/components/gateway.rb +50 -0
- data/lib/rom/components/mapper.rb +29 -0
- data/lib/rom/components/provider.rb +160 -0
- data/lib/rom/components/registry.rb +154 -0
- data/lib/rom/components/relation.rb +41 -0
- data/lib/rom/components/schema.rb +61 -0
- data/lib/rom/components/view.rb +55 -0
- data/lib/rom/components.rb +55 -0
- data/lib/rom/configuration_dsl.rb +4 -0
- data/lib/rom/constants.rb +135 -0
- data/lib/rom/container.rb +182 -0
- data/lib/rom/core.rb +125 -0
- data/lib/rom/data_proxy.rb +97 -0
- data/lib/rom/enumerable_dataset.rb +70 -0
- data/lib/rom/gateway.rb +232 -0
- data/lib/rom/global.rb +56 -0
- data/lib/rom/header/attribute.rb +190 -0
- data/lib/rom/header.rb +198 -0
- data/lib/rom/inferrer.rb +55 -0
- data/lib/rom/initializer.rb +80 -0
- data/lib/rom/lint/enumerable_dataset.rb +56 -0
- data/lib/rom/lint/gateway.rb +120 -0
- data/lib/rom/lint/linter.rb +79 -0
- data/lib/rom/lint/spec.rb +22 -0
- data/lib/rom/lint/test.rb +98 -0
- data/lib/rom/loader.rb +161 -0
- data/lib/rom/mapper/attribute_dsl.rb +480 -0
- data/lib/rom/mapper/dsl.rb +107 -0
- data/lib/rom/mapper/model_dsl.rb +61 -0
- data/lib/rom/mapper.rb +99 -0
- data/lib/rom/mapper_compiler.rb +84 -0
- data/lib/rom/memory/associations/many_to_many.rb +12 -0
- data/lib/rom/memory/associations/many_to_one.rb +12 -0
- data/lib/rom/memory/associations/one_to_many.rb +12 -0
- data/lib/rom/memory/associations/one_to_one.rb +12 -0
- data/lib/rom/memory/associations.rb +6 -0
- data/lib/rom/memory/commands.rb +60 -0
- data/lib/rom/memory/dataset.rb +127 -0
- data/lib/rom/memory/gateway.rb +66 -0
- data/lib/rom/memory/mapper_compiler.rb +10 -0
- data/lib/rom/memory/relation.rb +91 -0
- data/lib/rom/memory/schema.rb +32 -0
- data/lib/rom/memory/storage.rb +61 -0
- data/lib/rom/memory/types.rb +11 -0
- data/lib/rom/memory.rb +7 -0
- data/lib/rom/model_builder.rb +103 -0
- data/lib/rom/open_struct.rb +112 -0
- data/lib/rom/pipeline.rb +111 -0
- data/lib/rom/plugin.rb +130 -0
- data/lib/rom/plugins/class_methods.rb +37 -0
- data/lib/rom/plugins/command/schema.rb +45 -0
- data/lib/rom/plugins/command/timestamps.rb +149 -0
- data/lib/rom/plugins/dsl.rb +53 -0
- data/lib/rom/plugins/relation/changeset.rb +97 -0
- data/lib/rom/plugins/relation/instrumentation.rb +66 -0
- data/lib/rom/plugins/relation/registry_reader.rb +36 -0
- data/lib/rom/plugins/schema/timestamps.rb +59 -0
- data/lib/rom/plugins.rb +100 -0
- data/lib/rom/processor/composer.rb +37 -0
- data/lib/rom/processor/transformer.rb +415 -0
- data/lib/rom/processor.rb +30 -0
- data/lib/rom/registries/associations.rb +26 -0
- data/lib/rom/registries/commands.rb +11 -0
- data/lib/rom/registries/container.rb +12 -0
- data/lib/rom/registries/datasets.rb +21 -0
- data/lib/rom/registries/gateways.rb +8 -0
- data/lib/rom/registries/mappers.rb +21 -0
- data/lib/rom/registries/nestable.rb +32 -0
- data/lib/rom/registries/relations.rb +8 -0
- data/lib/rom/registries/root.rb +203 -0
- data/lib/rom/registries/schemas.rb +44 -0
- data/lib/rom/registries/views.rb +11 -0
- data/lib/rom/relation/class_interface.rb +61 -0
- data/lib/rom/relation/combined.rb +160 -0
- data/lib/rom/relation/commands.rb +65 -0
- data/lib/rom/relation/composite.rb +53 -0
- data/lib/rom/relation/curried.rb +129 -0
- data/lib/rom/relation/graph.rb +107 -0
- data/lib/rom/relation/loaded.rb +136 -0
- data/lib/rom/relation/materializable.rb +62 -0
- data/lib/rom/relation/name.rb +122 -0
- data/lib/rom/relation/wrap.rb +64 -0
- data/lib/rom/relation.rb +625 -0
- data/lib/rom/repository/class_interface.rb +162 -0
- data/lib/rom/repository/relation_reader.rb +48 -0
- data/lib/rom/repository/root.rb +75 -0
- data/lib/rom/repository/session.rb +60 -0
- data/lib/rom/repository.rb +179 -0
- data/lib/rom/schema/associations_dsl.rb +222 -0
- data/lib/rom/schema/inferrer.rb +106 -0
- data/lib/rom/schema.rb +471 -0
- data/lib/rom/settings.rb +141 -0
- data/lib/rom/setup.rb +297 -0
- data/lib/rom/struct.rb +99 -0
- data/lib/rom/struct_compiler.rb +114 -0
- data/lib/rom/support/configurable.rb +213 -0
- data/lib/rom/support/inflector.rb +31 -0
- data/lib/rom/support/memoizable.rb +61 -0
- data/lib/rom/support/notifications.rb +238 -0
- data/lib/rom/transaction.rb +26 -0
- data/lib/rom/transformer.rb +46 -0
- data/lib/rom/types.rb +74 -0
- data/lib/rom/version.rb +1 -1
- data/lib/rom-changeset.rb +4 -0
- data/lib/rom-core.rb +3 -0
- data/lib/rom-repository.rb +4 -0
- data/lib/rom.rb +3 -3
- metadata +302 -23
@@ -0,0 +1,415 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/transformer/all"
|
4
|
+
|
5
|
+
require "rom/processor"
|
6
|
+
require "rom/processor/composer"
|
7
|
+
|
8
|
+
module ROM
|
9
|
+
class Processor
|
10
|
+
# Data mapping transformer builder using dry-transformer
|
11
|
+
#
|
12
|
+
# This builds a transformer object that is used to map a whole relation
|
13
|
+
#
|
14
|
+
# @see https://github.com/dry-rb/dry-transformer
|
15
|
+
#
|
16
|
+
# @private
|
17
|
+
class Transformer < Processor
|
18
|
+
include Composer
|
19
|
+
|
20
|
+
module Functions
|
21
|
+
extend Dry::Transformer::Registry
|
22
|
+
|
23
|
+
import Dry::Transformer::Coercions
|
24
|
+
import Dry::Transformer::ArrayTransformations
|
25
|
+
import Dry::Transformer::HashTransformations
|
26
|
+
import Dry::Transformer::ClassTransformations
|
27
|
+
import Dry::Transformer::ProcTransformations
|
28
|
+
|
29
|
+
INVALID_INJECT_UNION_VALUE = "%s attribute: block is required for :from with union value."
|
30
|
+
|
31
|
+
def self.get(arr, idx)
|
32
|
+
arr[idx]
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.filter_empty(arr)
|
36
|
+
arr.reject { |row| row.values.all?(&:nil?) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.inject_union_value(tuple, name, keys, coercer)
|
40
|
+
raise ROM::MapperMisconfiguredError, INVALID_INJECT_UNION_VALUE % [name] unless coercer
|
41
|
+
|
42
|
+
values = tuple.values_at(*keys)
|
43
|
+
result = coercer.call(*values)
|
44
|
+
|
45
|
+
tuple.merge(name => result)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Mapper] mapper that this processor belongs to
|
50
|
+
#
|
51
|
+
# @api private
|
52
|
+
attr_reader :mapper
|
53
|
+
|
54
|
+
# @return [Header] header from a mapper
|
55
|
+
#
|
56
|
+
# @api private
|
57
|
+
attr_reader :header
|
58
|
+
|
59
|
+
# @return [Class] model class from a mapper
|
60
|
+
#
|
61
|
+
# @api private
|
62
|
+
attr_reader :model
|
63
|
+
|
64
|
+
# @return [Hash] header's attribute mapping
|
65
|
+
#
|
66
|
+
# @api private
|
67
|
+
attr_reader :mapping
|
68
|
+
|
69
|
+
# @return [Proc] row-processing proc
|
70
|
+
#
|
71
|
+
# @api private
|
72
|
+
attr_reader :row_proc
|
73
|
+
|
74
|
+
# Build a transformer object from the header
|
75
|
+
#
|
76
|
+
# @param [ROM::Header] header
|
77
|
+
#
|
78
|
+
# @return [Dry::Transformer::Pipe]
|
79
|
+
#
|
80
|
+
# @api private
|
81
|
+
def self.build(mapper, header)
|
82
|
+
new(mapper, header).call
|
83
|
+
end
|
84
|
+
|
85
|
+
# @api private
|
86
|
+
def initialize(mapper, header)
|
87
|
+
@mapper = mapper
|
88
|
+
@header = header
|
89
|
+
@model = header.model
|
90
|
+
@mapping = header.mapping
|
91
|
+
initialize_row_proc
|
92
|
+
end
|
93
|
+
|
94
|
+
# Coerce mapper header to a transformer object
|
95
|
+
#
|
96
|
+
# @return [Dry::Transformer::Pipe]
|
97
|
+
#
|
98
|
+
# @api private
|
99
|
+
def call
|
100
|
+
compose(t(:identity)) do |ops|
|
101
|
+
combined = header.combined
|
102
|
+
ops << t(:combine, combined.map(&method(:combined_args))) if combined.any?
|
103
|
+
ops << header.preprocessed.map { |attr| visit(attr, true) }
|
104
|
+
ops << t(:map_array, row_proc) if row_proc
|
105
|
+
ops << header.postprocessed.map { |attr| visit(attr, true) }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
# Visit an attribute from the header
|
112
|
+
#
|
113
|
+
# This forwards to a specialized visitor based on the attribute type
|
114
|
+
#
|
115
|
+
# @param [Header::Attribute] attribute
|
116
|
+
# @param [Array] args Allows to send `preprocess: true`
|
117
|
+
#
|
118
|
+
# @api private
|
119
|
+
def visit(attribute, *args)
|
120
|
+
type = attribute.class.name.split("::").last.downcase
|
121
|
+
send("visit_#{type}", attribute, *args)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Visit plain attribute
|
125
|
+
#
|
126
|
+
# It will call block transformation if it's used
|
127
|
+
#
|
128
|
+
# If it's a typed attribute a coercion transformation is added
|
129
|
+
#
|
130
|
+
# @param [Header::Attribute] attribute
|
131
|
+
#
|
132
|
+
# @api private
|
133
|
+
def visit_attribute(attribute)
|
134
|
+
coercer = attribute.meta[:coercer]
|
135
|
+
if attribute.union?
|
136
|
+
compose do |ops|
|
137
|
+
ops << t(:inject_union_value, attribute.name, attribute.key, coercer)
|
138
|
+
ops << t(:reject_keys, attribute.key) unless header.copy_keys
|
139
|
+
end
|
140
|
+
elsif coercer
|
141
|
+
t(:map_value, attribute.name, t(:bind, mapper, coercer))
|
142
|
+
elsif attribute.typed?
|
143
|
+
t(:map_value, attribute.name, t(:"to_#{attribute.type}"))
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Visit hash attribute
|
148
|
+
#
|
149
|
+
# @param [Header::Attribute::Hash] attribute
|
150
|
+
#
|
151
|
+
# @api private
|
152
|
+
def visit_hash(attribute)
|
153
|
+
with_row_proc(attribute) do |row_proc|
|
154
|
+
t(:map_value, attribute.name, row_proc)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Visit combined attribute
|
159
|
+
#
|
160
|
+
# @api private
|
161
|
+
def visit_combined(attribute)
|
162
|
+
op = with_row_proc(attribute) do |row_proc|
|
163
|
+
array_proc =
|
164
|
+
if attribute.type == :hash
|
165
|
+
t(:map_array, row_proc) >> t(:get, 0)
|
166
|
+
else
|
167
|
+
t(:map_array, row_proc)
|
168
|
+
end
|
169
|
+
|
170
|
+
t(:map_value, attribute.name, array_proc)
|
171
|
+
end
|
172
|
+
|
173
|
+
if op
|
174
|
+
op
|
175
|
+
elsif attribute.type == :hash
|
176
|
+
t(:map_value, attribute.name, t(:get, 0))
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# Visit array attribute
|
181
|
+
#
|
182
|
+
# @param [Header::Attribute::Array] attribute
|
183
|
+
#
|
184
|
+
# @api private
|
185
|
+
def visit_array(attribute)
|
186
|
+
with_row_proc(attribute) do |row_proc|
|
187
|
+
t(:map_value, attribute.name, t(:map_array, row_proc))
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# Visit wrapped hash attribute
|
192
|
+
#
|
193
|
+
# :nest transformation is added to handle wrapping
|
194
|
+
#
|
195
|
+
# @param [Header::Attribute::Wrap] attribute
|
196
|
+
#
|
197
|
+
# @api private
|
198
|
+
def visit_wrap(attribute)
|
199
|
+
name = attribute.name
|
200
|
+
keys = attribute.tuple_keys
|
201
|
+
|
202
|
+
compose do |ops|
|
203
|
+
ops << t(:nest, name, keys)
|
204
|
+
ops << visit_hash(attribute)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Visit unwrap attribute
|
209
|
+
#
|
210
|
+
# :unwrap transformation is added to handle unwrapping
|
211
|
+
#
|
212
|
+
# @param [Header::Attributes::Unwrap] attribute
|
213
|
+
#
|
214
|
+
# @api private
|
215
|
+
def visit_unwrap(attribute)
|
216
|
+
name = attribute.name
|
217
|
+
keys = attribute.pop_keys
|
218
|
+
|
219
|
+
compose do |ops|
|
220
|
+
ops << visit_hash(attribute)
|
221
|
+
ops << t(:unwrap, name, keys)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# Visit group hash attribute
|
226
|
+
#
|
227
|
+
# :group transformation is added to handle grouping during preprocessing.
|
228
|
+
# Otherwise we simply use array visitor for the attribute.
|
229
|
+
#
|
230
|
+
# @param [Header::Attribute::Group] attribute
|
231
|
+
# @param [Boolean] preprocess true if we are building a relation preprocessing
|
232
|
+
# function that is applied to the whole relation
|
233
|
+
#
|
234
|
+
# @api private
|
235
|
+
def visit_group(attribute, preprocess = false)
|
236
|
+
if preprocess
|
237
|
+
name = attribute.name
|
238
|
+
header = attribute.header
|
239
|
+
keys = attribute.tuple_keys
|
240
|
+
|
241
|
+
others = header.preprocessed
|
242
|
+
|
243
|
+
compose do |ops|
|
244
|
+
ops << t(:group, name, keys)
|
245
|
+
ops << t(:map_array, t(:map_value, name, t(:filter_empty)))
|
246
|
+
ops << others.map { |attr|
|
247
|
+
t(:map_array, t(:map_value, name, visit(attr, true)))
|
248
|
+
}
|
249
|
+
end
|
250
|
+
else
|
251
|
+
visit_array(attribute)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
# Visit ungroup attribute
|
256
|
+
#
|
257
|
+
# :ungroup transforation is added to handle ungrouping during preprocessing.
|
258
|
+
# Otherwise we simply use array visitor for the attribute.
|
259
|
+
#
|
260
|
+
# @param [Header::Attribute::Ungroup] attribute
|
261
|
+
# @param [Boolean] preprocess true if we are building a relation preprocessing
|
262
|
+
# function that is applied to the whole relation
|
263
|
+
#
|
264
|
+
# @api private
|
265
|
+
def visit_ungroup(attribute, preprocess = false)
|
266
|
+
if preprocess
|
267
|
+
name = attribute.name
|
268
|
+
header = attribute.header
|
269
|
+
keys = attribute.pop_keys
|
270
|
+
|
271
|
+
others = header.postprocessed
|
272
|
+
|
273
|
+
compose do |ops|
|
274
|
+
ops << others.map { |attr|
|
275
|
+
t(:map_array, t(:map_value, name, visit(attr, true)))
|
276
|
+
}
|
277
|
+
ops << t(:ungroup, name, keys)
|
278
|
+
end
|
279
|
+
else
|
280
|
+
visit_array(attribute)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
# Visit fold hash attribute
|
285
|
+
#
|
286
|
+
# :fold transformation is added to handle folding during preprocessing.
|
287
|
+
#
|
288
|
+
# @param [Header::Attribute::Fold] attribute
|
289
|
+
# @param [Boolean] preprocess true if we are building a relation preprocessing
|
290
|
+
# function that is applied to the whole relation
|
291
|
+
#
|
292
|
+
# @api private
|
293
|
+
def visit_fold(attribute, preprocess = false)
|
294
|
+
if preprocess
|
295
|
+
name = attribute.name
|
296
|
+
keys = attribute.tuple_keys
|
297
|
+
|
298
|
+
compose do |ops|
|
299
|
+
ops << t(:group, name, keys)
|
300
|
+
ops << t(:map_array, t(:map_value, name, t(:filter_empty)))
|
301
|
+
ops << t(:map_array, t(:fold, name, keys.first))
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
# Visit unfold hash attribute
|
307
|
+
#
|
308
|
+
# :unfold transformation is added to handle unfolding during preprocessing.
|
309
|
+
#
|
310
|
+
# @param [Header::Attribute::Unfold] attribute
|
311
|
+
# @param [Boolean] preprocess true if we are building a relation preprocessing
|
312
|
+
# function that is applied to the whole relation
|
313
|
+
#
|
314
|
+
# @api private
|
315
|
+
def visit_unfold(attribute, preprocess = false)
|
316
|
+
return unless preprocess
|
317
|
+
|
318
|
+
name = attribute.name
|
319
|
+
header = attribute.header
|
320
|
+
keys = attribute.pop_keys
|
321
|
+
key = keys.first
|
322
|
+
|
323
|
+
others = header.postprocessed
|
324
|
+
|
325
|
+
compose do |ops|
|
326
|
+
ops << others.map { |attr|
|
327
|
+
t(:map_array, t(:map_value, name, visit(attr, true)))
|
328
|
+
}
|
329
|
+
ops << t(:map_array, t(:map_value, name, t(:insert_key, key)))
|
330
|
+
ops << t(:map_array, t(:reject_keys, [key] - [name]))
|
331
|
+
ops << t(:ungroup, name, [key])
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
# Visit excluded attribute
|
336
|
+
#
|
337
|
+
# @param [Header::Attribute::Exclude] attribute
|
338
|
+
#
|
339
|
+
# @api private
|
340
|
+
def visit_exclude(attribute)
|
341
|
+
t(:reject_keys, [attribute.name])
|
342
|
+
end
|
343
|
+
|
344
|
+
# @api private
|
345
|
+
def combined_args(attribute)
|
346
|
+
other = attribute.header.combined
|
347
|
+
|
348
|
+
if other.any?
|
349
|
+
children = other.map(&method(:combined_args))
|
350
|
+
[attribute.name, attribute.meta[:keys], children]
|
351
|
+
else
|
352
|
+
[attribute.name, attribute.meta[:keys]]
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
# Build row_proc
|
357
|
+
#
|
358
|
+
# This dry-transformer function is applied to each row in a dataset
|
359
|
+
#
|
360
|
+
# @api private
|
361
|
+
def initialize_row_proc
|
362
|
+
@row_proc = compose { |ops|
|
363
|
+
alias_handler = header.copy_keys ? :copy_keys : :rename_keys
|
364
|
+
process_header_keys(ops)
|
365
|
+
|
366
|
+
ops << t(alias_handler, mapping) if header.aliased?
|
367
|
+
ops << header.map { |attr| visit(attr) }
|
368
|
+
ops << t(:constructor_inject, model) if model
|
369
|
+
}
|
370
|
+
end
|
371
|
+
|
372
|
+
# Process row_proc header keys
|
373
|
+
#
|
374
|
+
# @api private
|
375
|
+
def process_header_keys(ops)
|
376
|
+
if header.reject_keys
|
377
|
+
all_keys = header.tuple_keys + header.non_primitives.map(&:key)
|
378
|
+
ops << t(:accept_keys, all_keys)
|
379
|
+
end
|
380
|
+
ops
|
381
|
+
end
|
382
|
+
|
383
|
+
# Yield row proc for a given attribute if any
|
384
|
+
#
|
385
|
+
# @param [Header::Attribute] attribute
|
386
|
+
#
|
387
|
+
# @api private
|
388
|
+
def with_row_proc(attribute)
|
389
|
+
row_proc = row_proc_from(attribute)
|
390
|
+
yield(row_proc) if row_proc
|
391
|
+
end
|
392
|
+
|
393
|
+
# Build a row_proc from a given attribute
|
394
|
+
#
|
395
|
+
# This is used by embedded attribute visitors
|
396
|
+
#
|
397
|
+
# @api private
|
398
|
+
def row_proc_from(attribute)
|
399
|
+
new(mapper, attribute.header).row_proc
|
400
|
+
end
|
401
|
+
|
402
|
+
# Return a new instance of the processor
|
403
|
+
#
|
404
|
+
# @api private
|
405
|
+
def new(*args)
|
406
|
+
self.class.new(*args)
|
407
|
+
end
|
408
|
+
|
409
|
+
# @api private
|
410
|
+
def t(*args)
|
411
|
+
Functions[*args]
|
412
|
+
end
|
413
|
+
end
|
414
|
+
end
|
415
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rom/mapper"
|
4
|
+
|
5
|
+
module ROM
|
6
|
+
# Abstract processor class
|
7
|
+
#
|
8
|
+
# Every ROM processor should inherit from this class
|
9
|
+
#
|
10
|
+
# @api public
|
11
|
+
class Processor
|
12
|
+
# Hook used to auto-register a processor class
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
def self.inherited(processor)
|
16
|
+
Mapper.register_processor(processor)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Required interface to be implemented by descendants
|
20
|
+
#
|
21
|
+
# @return [Processor]
|
22
|
+
#
|
23
|
+
# @abstract
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
def self.build
|
27
|
+
raise NotImplementedError, "+build+ must be implemented"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
module Registries
|
5
|
+
# @api public
|
6
|
+
class Associations < Root
|
7
|
+
# @api public
|
8
|
+
def fetch(key, &block)
|
9
|
+
super(key) {
|
10
|
+
components.key?(key) ? super(key, &block) : fetch_aliased_association(key)
|
11
|
+
}
|
12
|
+
end
|
13
|
+
alias_method :[], :fetch
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
# @api private
|
18
|
+
def fetch_aliased_association(key)
|
19
|
+
components
|
20
|
+
.associations(namespace: namespace)
|
21
|
+
.detect { |assoc| key == "#{namespace}.#{assoc.config.name}" }
|
22
|
+
.then { |assoc| fetch(assoc.config.as) if assoc }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "nestable"
|
4
|
+
|
5
|
+
module ROM
|
6
|
+
module Registries
|
7
|
+
# @api public
|
8
|
+
class Datasets < Root
|
9
|
+
prepend Nestable
|
10
|
+
|
11
|
+
# @api private
|
12
|
+
def define_component(**options)
|
13
|
+
return super unless provider_type == :relation
|
14
|
+
|
15
|
+
comp = components.get(:datasets, relation_id: config.component.id, abstract: false)
|
16
|
+
|
17
|
+
comp || super(**options, id: config.component.dataset, relation_id: config.component.id)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "nestable"
|
4
|
+
|
5
|
+
module ROM
|
6
|
+
module Registries
|
7
|
+
class Mappers < Root
|
8
|
+
prepend Nestable
|
9
|
+
|
10
|
+
# @api private
|
11
|
+
def import(mappers)
|
12
|
+
container.namespace(namespace) do |namespace|
|
13
|
+
mappers.each do |name, mapper|
|
14
|
+
namespace.register(name, mapper)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
self
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
module Registries
|
5
|
+
module Nestable
|
6
|
+
# @api public
|
7
|
+
def fetch(key, &block)
|
8
|
+
if relation_namespace?(key)
|
9
|
+
super(namespace, &block)
|
10
|
+
elsif relation_scope_key?(key)
|
11
|
+
scoped(key)
|
12
|
+
else
|
13
|
+
super(key, &block)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
alias_method :[], :fetch
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# @api private
|
21
|
+
def relation_namespace?(key)
|
22
|
+
# TODO: stop nesting canonical mappers under relation's id ie `mappers.users.users`
|
23
|
+
path.last == key && !mappers?
|
24
|
+
end
|
25
|
+
|
26
|
+
# @api private
|
27
|
+
def relation_scope_key?(key)
|
28
|
+
!key?(key) && relation_ids.include?(key)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|