rom 5.2.6 → 6.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (186) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +60 -21
  3. data/LICENSE +1 -1
  4. data/README.md +6 -6
  5. data/lib/rom/array_dataset.rb +46 -0
  6. data/lib/rom/associations/abstract.rb +217 -0
  7. data/lib/rom/associations/definitions/abstract.rb +150 -0
  8. data/lib/rom/associations/definitions/many_to_many.rb +29 -0
  9. data/lib/rom/associations/definitions/many_to_one.rb +14 -0
  10. data/lib/rom/associations/definitions/one_to_many.rb +14 -0
  11. data/lib/rom/associations/definitions/one_to_one.rb +14 -0
  12. data/lib/rom/associations/definitions/one_to_one_through.rb +14 -0
  13. data/lib/rom/associations/definitions.rb +7 -0
  14. data/lib/rom/associations/many_to_many.rb +128 -0
  15. data/lib/rom/associations/many_to_one.rb +65 -0
  16. data/lib/rom/associations/one_to_many.rb +65 -0
  17. data/lib/rom/associations/one_to_one.rb +13 -0
  18. data/lib/rom/associations/one_to_one_through.rb +13 -0
  19. data/lib/rom/associations/through_identifier.rb +41 -0
  20. data/lib/rom/attribute.rb +425 -0
  21. data/lib/rom/auto_curry.rb +70 -0
  22. data/lib/rom/cache.rb +87 -0
  23. data/lib/rom/changeset/associated.rb +110 -0
  24. data/lib/rom/changeset/create.rb +18 -0
  25. data/lib/rom/changeset/delete.rb +15 -0
  26. data/lib/rom/changeset/extensions/relation.rb +26 -0
  27. data/lib/rom/changeset/pipe.rb +81 -0
  28. data/lib/rom/changeset/pipe_registry.rb +27 -0
  29. data/lib/rom/changeset/stateful.rb +285 -0
  30. data/lib/rom/changeset/update.rb +81 -0
  31. data/lib/rom/changeset.rb +185 -0
  32. data/lib/rom/command.rb +351 -0
  33. data/lib/rom/command_compiler.rb +201 -0
  34. data/lib/rom/command_proxy.rb +36 -0
  35. data/lib/rom/commands/class_interface.rb +236 -0
  36. data/lib/rom/commands/composite.rb +55 -0
  37. data/lib/rom/commands/create.rb +15 -0
  38. data/lib/rom/commands/delete.rb +16 -0
  39. data/lib/rom/commands/graph/class_interface.rb +64 -0
  40. data/lib/rom/commands/graph/input_evaluator.rb +94 -0
  41. data/lib/rom/commands/graph.rb +88 -0
  42. data/lib/rom/commands/lazy/create.rb +35 -0
  43. data/lib/rom/commands/lazy/delete.rb +39 -0
  44. data/lib/rom/commands/lazy/update.rb +46 -0
  45. data/lib/rom/commands/lazy.rb +106 -0
  46. data/lib/rom/commands/update.rb +16 -0
  47. data/lib/rom/commands.rb +5 -0
  48. data/lib/rom/compat/auto_registration.rb +115 -0
  49. data/lib/rom/compat/auto_registration_strategies/base.rb +29 -0
  50. data/lib/rom/compat/auto_registration_strategies/custom_namespace.rb +84 -0
  51. data/lib/rom/compat/auto_registration_strategies/no_namespace.rb +33 -0
  52. data/lib/rom/compat/auto_registration_strategies/with_namespace.rb +29 -0
  53. data/lib/rom/compat/command.rb +74 -0
  54. data/lib/rom/compat/components/dsl/schema.rb +130 -0
  55. data/lib/rom/compat/components.rb +91 -0
  56. data/lib/rom/compat/global.rb +17 -0
  57. data/lib/rom/compat/mapper.rb +22 -0
  58. data/lib/rom/compat/registries.rb +47 -0
  59. data/lib/rom/compat/relation.rb +40 -0
  60. data/lib/rom/compat/schema/dsl.rb +260 -0
  61. data/lib/rom/compat/setting_proxy.rb +44 -0
  62. data/lib/rom/compat/setup.rb +151 -0
  63. data/lib/rom/compat/transformer.rb +49 -0
  64. data/lib/rom/compat.rb +22 -0
  65. data/lib/rom/components/association.rb +26 -0
  66. data/lib/rom/components/command.rb +24 -0
  67. data/lib/rom/components/core.rb +148 -0
  68. data/lib/rom/components/dataset.rb +60 -0
  69. data/lib/rom/components/dsl/association.rb +47 -0
  70. data/lib/rom/components/dsl/command.rb +60 -0
  71. data/lib/rom/components/dsl/core.rb +126 -0
  72. data/lib/rom/components/dsl/dataset.rb +33 -0
  73. data/lib/rom/components/dsl/gateway.rb +14 -0
  74. data/lib/rom/components/dsl/mapper.rb +70 -0
  75. data/lib/rom/components/dsl/relation.rb +49 -0
  76. data/lib/rom/components/dsl/schema.rb +150 -0
  77. data/lib/rom/components/dsl/view.rb +82 -0
  78. data/lib/rom/components/dsl.rb +255 -0
  79. data/lib/rom/components/gateway.rb +50 -0
  80. data/lib/rom/components/mapper.rb +29 -0
  81. data/lib/rom/components/provider.rb +160 -0
  82. data/lib/rom/components/registry.rb +154 -0
  83. data/lib/rom/components/relation.rb +41 -0
  84. data/lib/rom/components/schema.rb +61 -0
  85. data/lib/rom/components/view.rb +55 -0
  86. data/lib/rom/components.rb +55 -0
  87. data/lib/rom/configuration_dsl.rb +4 -0
  88. data/lib/rom/constants.rb +135 -0
  89. data/lib/rom/container.rb +182 -0
  90. data/lib/rom/core.rb +125 -0
  91. data/lib/rom/data_proxy.rb +97 -0
  92. data/lib/rom/enumerable_dataset.rb +70 -0
  93. data/lib/rom/gateway.rb +232 -0
  94. data/lib/rom/global.rb +56 -0
  95. data/lib/rom/header/attribute.rb +190 -0
  96. data/lib/rom/header.rb +198 -0
  97. data/lib/rom/inferrer.rb +55 -0
  98. data/lib/rom/initializer.rb +80 -0
  99. data/lib/rom/lint/enumerable_dataset.rb +56 -0
  100. data/lib/rom/lint/gateway.rb +120 -0
  101. data/lib/rom/lint/linter.rb +79 -0
  102. data/lib/rom/lint/spec.rb +22 -0
  103. data/lib/rom/lint/test.rb +98 -0
  104. data/lib/rom/loader.rb +161 -0
  105. data/lib/rom/mapper/attribute_dsl.rb +480 -0
  106. data/lib/rom/mapper/dsl.rb +107 -0
  107. data/lib/rom/mapper/model_dsl.rb +61 -0
  108. data/lib/rom/mapper.rb +99 -0
  109. data/lib/rom/mapper_compiler.rb +84 -0
  110. data/lib/rom/memory/associations/many_to_many.rb +12 -0
  111. data/lib/rom/memory/associations/many_to_one.rb +12 -0
  112. data/lib/rom/memory/associations/one_to_many.rb +12 -0
  113. data/lib/rom/memory/associations/one_to_one.rb +12 -0
  114. data/lib/rom/memory/associations.rb +6 -0
  115. data/lib/rom/memory/commands.rb +60 -0
  116. data/lib/rom/memory/dataset.rb +127 -0
  117. data/lib/rom/memory/gateway.rb +66 -0
  118. data/lib/rom/memory/mapper_compiler.rb +10 -0
  119. data/lib/rom/memory/relation.rb +91 -0
  120. data/lib/rom/memory/schema.rb +32 -0
  121. data/lib/rom/memory/storage.rb +61 -0
  122. data/lib/rom/memory/types.rb +11 -0
  123. data/lib/rom/memory.rb +7 -0
  124. data/lib/rom/model_builder.rb +103 -0
  125. data/lib/rom/open_struct.rb +112 -0
  126. data/lib/rom/pipeline.rb +111 -0
  127. data/lib/rom/plugin.rb +130 -0
  128. data/lib/rom/plugins/class_methods.rb +37 -0
  129. data/lib/rom/plugins/command/schema.rb +45 -0
  130. data/lib/rom/plugins/command/timestamps.rb +149 -0
  131. data/lib/rom/plugins/dsl.rb +53 -0
  132. data/lib/rom/plugins/relation/changeset.rb +97 -0
  133. data/lib/rom/plugins/relation/instrumentation.rb +66 -0
  134. data/lib/rom/plugins/relation/registry_reader.rb +36 -0
  135. data/lib/rom/plugins/schema/timestamps.rb +59 -0
  136. data/lib/rom/plugins.rb +100 -0
  137. data/lib/rom/processor/composer.rb +37 -0
  138. data/lib/rom/processor/transformer.rb +415 -0
  139. data/lib/rom/processor.rb +30 -0
  140. data/lib/rom/registries/associations.rb +26 -0
  141. data/lib/rom/registries/commands.rb +11 -0
  142. data/lib/rom/registries/container.rb +12 -0
  143. data/lib/rom/registries/datasets.rb +21 -0
  144. data/lib/rom/registries/gateways.rb +8 -0
  145. data/lib/rom/registries/mappers.rb +21 -0
  146. data/lib/rom/registries/nestable.rb +32 -0
  147. data/lib/rom/registries/relations.rb +8 -0
  148. data/lib/rom/registries/root.rb +203 -0
  149. data/lib/rom/registries/schemas.rb +44 -0
  150. data/lib/rom/registries/views.rb +11 -0
  151. data/lib/rom/relation/class_interface.rb +61 -0
  152. data/lib/rom/relation/combined.rb +160 -0
  153. data/lib/rom/relation/commands.rb +65 -0
  154. data/lib/rom/relation/composite.rb +53 -0
  155. data/lib/rom/relation/curried.rb +129 -0
  156. data/lib/rom/relation/graph.rb +107 -0
  157. data/lib/rom/relation/loaded.rb +136 -0
  158. data/lib/rom/relation/materializable.rb +62 -0
  159. data/lib/rom/relation/name.rb +122 -0
  160. data/lib/rom/relation/wrap.rb +64 -0
  161. data/lib/rom/relation.rb +625 -0
  162. data/lib/rom/repository/class_interface.rb +162 -0
  163. data/lib/rom/repository/relation_reader.rb +48 -0
  164. data/lib/rom/repository/root.rb +75 -0
  165. data/lib/rom/repository/session.rb +60 -0
  166. data/lib/rom/repository.rb +179 -0
  167. data/lib/rom/schema/associations_dsl.rb +222 -0
  168. data/lib/rom/schema/inferrer.rb +106 -0
  169. data/lib/rom/schema.rb +471 -0
  170. data/lib/rom/settings.rb +141 -0
  171. data/lib/rom/setup.rb +297 -0
  172. data/lib/rom/struct.rb +99 -0
  173. data/lib/rom/struct_compiler.rb +114 -0
  174. data/lib/rom/support/configurable.rb +213 -0
  175. data/lib/rom/support/inflector.rb +31 -0
  176. data/lib/rom/support/memoizable.rb +61 -0
  177. data/lib/rom/support/notifications.rb +238 -0
  178. data/lib/rom/transaction.rb +26 -0
  179. data/lib/rom/transformer.rb +46 -0
  180. data/lib/rom/types.rb +74 -0
  181. data/lib/rom/version.rb +1 -1
  182. data/lib/rom-changeset.rb +4 -0
  183. data/lib/rom-core.rb +3 -0
  184. data/lib/rom-repository.rb +4 -0
  185. data/lib/rom.rb +3 -3
  186. metadata +273 -36
@@ -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,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "nestable"
4
+
5
+ module ROM
6
+ module Registries
7
+ class Commands < Root
8
+ prepend Nestable
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/container"
4
+
5
+ module ROM
6
+ module Registries
7
+ # @api private
8
+ class Container
9
+ include Dry::Container::Mixin
10
+ end
11
+ end
12
+ 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,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ROM
4
+ module Registries
5
+ class Gateways < Root
6
+ end
7
+ end
8
+ 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
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ROM
4
+ module Registries
5
+ class Relations < Root
6
+ end
7
+ end
8
+ end