rom 5.4.2 → 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.
Files changed (186) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +58 -71
  3. data/LICENSE +1 -1
  4. data/README.md +7 -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 +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,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