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.
Files changed (186) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +58 -65
  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,160 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rom/support/configurable"
4
+
5
+ require "rom/core"
6
+ require "rom/settings"
7
+ require "rom/registries/root"
8
+
9
+ require_relative "dsl"
10
+ require_relative "registry"
11
+
12
+ module ROM
13
+ # Define a module for component definitions and runtime setup
14
+ #
15
+ # @return [Components::Provider]
16
+ #
17
+ # @api public
18
+ def self.Provider(*features, **options)
19
+ Components::Provider.new(features, **options)
20
+ end
21
+
22
+ # @api private
23
+ module Components
24
+ # @api private
25
+ class Provider < Module
26
+ attr_reader :provider
27
+
28
+ attr_reader :type
29
+
30
+ attr_reader :features
31
+
32
+ # @api private
33
+ module InstanceMethods
34
+ # @api public
35
+ def components
36
+ @components ||= Registry.new(provider: self)
37
+ end
38
+
39
+ # @api private
40
+ def registry(**options)
41
+ Registries::Root.new(
42
+ config: config,
43
+ components: components,
44
+ notifications: Notifications.event_bus(:configuration),
45
+ **options
46
+ )
47
+ end
48
+ end
49
+
50
+ # @api private
51
+ module ClassMethods
52
+ include InstanceMethods
53
+
54
+ # @api private
55
+ def inherited(klass)
56
+ super
57
+ klass.components.update(components, abstract: true)
58
+ end
59
+ end
60
+
61
+ # @api private
62
+ def initialize(features, type: nil)
63
+ super()
64
+ @provider = nil
65
+ @type = type
66
+ @features = features
67
+ end
68
+
69
+ # @api private
70
+ def define_configure_method(type, features)
71
+ yield Module.new {
72
+ define_method(:configure) do |*args, &block|
73
+ # Inherit global defaults
74
+ config.component.inherit!(**ROM.config[type], type: type)
75
+
76
+ # Inherit global defaults for individual features
77
+ features.each do |name|
78
+ config[name].inherit!(**ROM.config[name]) if ROM.config.key?(name)
79
+ end
80
+
81
+ super(*args, &block)
82
+ end
83
+ }
84
+ end
85
+
86
+ # @api private
87
+ def included(provider)
88
+ super
89
+ @provider = provider
90
+ provider.include(mod)
91
+ provider.include(Configurable)
92
+ import_settings
93
+ provider.include(InstanceMethods)
94
+ define_configure_method(type, features) { |mod|
95
+ provider.prepend(mod)
96
+ }
97
+ freeze
98
+ end
99
+
100
+ # @api private
101
+ def extended(provider)
102
+ super
103
+ @provider = provider
104
+ provider.extend(mod)
105
+ provider.extend(Configurable)
106
+ import_settings
107
+ provider.extend(ClassMethods)
108
+ define_configure_method(type, features) { |mod|
109
+ provider.singleton_class.prepend(mod)
110
+ }
111
+ freeze
112
+ end
113
+
114
+ # @api private
115
+ def mod
116
+ @mod ||=
117
+ Module.new.tap do |mod|
118
+ define_dsl_method(mod, :__dsl__)
119
+
120
+ features.each do |type|
121
+ if ROM.components.key?(type)
122
+ handler = ROM.components[type]
123
+
124
+ [handler.key, handler.namespace]
125
+ .select { |name|
126
+ DSL.instance_methods.include?(name)
127
+ }
128
+ .each { |name|
129
+ define_dsl_method(mod, name)
130
+ }
131
+ else
132
+ define_dsl_method(mod, type)
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ # @api private
139
+ def define_dsl_method(mod, name)
140
+ mod.define_method(name) { |*args, **opts, &block|
141
+ DSL.instance_method(name).bind(self).(*args, **opts, &block)
142
+ }
143
+ end
144
+
145
+ # @api private
146
+ def import_settings
147
+ # Import default settings for the provider
148
+ provider.setting(:component, import: ROM.settings[type])
149
+
150
+ # Import default settings for each feature that the provider supports
151
+ features.each do |name|
152
+ if ROM.settings.key?(name)
153
+ # Define the settings
154
+ provider.setting(name, import: ROM.settings[name])
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rom/constants"
4
+ require "rom/core"
5
+
6
+ module ROM
7
+ # @api private
8
+ module Components
9
+ # @api public
10
+ class Registry
11
+ include Enumerable
12
+
13
+ # @api private
14
+ attr_reader :provider
15
+
16
+ # @api private
17
+ attr_reader :handlers
18
+
19
+ DUPLICATE_ERRORS = {
20
+ gateways: GatewayAlreadyDefinedError,
21
+ datasets: DatasetAlreadyDefinedError,
22
+ schemas: SchemaAlreadyDefinedError,
23
+ relations: RelationAlreadyDefinedError,
24
+ associations: AssociationAlreadyDefinedError,
25
+ commands: CommandAlreadyDefinedError,
26
+ mappers: MapperAlreadyDefinedError
27
+ }.freeze
28
+
29
+ # @api private
30
+ def initialize(provider:, handlers: ROM.components)
31
+ @provider = provider
32
+ @handlers = handlers
33
+ end
34
+
35
+ # @api private
36
+ def store
37
+ @store ||= handlers.map { |handler| [handler.namespace, EMPTY_ARRAY.dup] }.to_h
38
+ end
39
+
40
+ # @api private
41
+ def each
42
+ store.each { |type, components|
43
+ components.each { |component| yield(type, component) }
44
+ }
45
+ end
46
+
47
+ # @api private
48
+ def to_a
49
+ flat_map { |_, components| components }
50
+ end
51
+
52
+ # @api private
53
+ def call(key, &fallback)
54
+ comp = detect { |_, component| component.key == key && !component.abstract? }&.last
55
+
56
+ if comp
57
+ comp.build
58
+ elsif fallback
59
+ fallback.()
60
+ else
61
+ raise KeyError, "+#{key}+ not found"
62
+ end
63
+ end
64
+
65
+ # @api private
66
+ def [](type)
67
+ store[type]
68
+ end
69
+
70
+ # @api private
71
+ def get(type, **opts)
72
+ public_send(type, **opts).first
73
+ end
74
+
75
+ # @api private
76
+ def add(type, item: nil, **options)
77
+ component = item || build(type, **options)
78
+
79
+ # if include?(type, component)
80
+ # other = get(type, key: component.key)
81
+
82
+ # raise(
83
+ # DUPLICATE_ERRORS[type],
84
+ # "#{provider}: +#{component.key}+ is already defined by #{other.provider}"
85
+ # )
86
+ # end
87
+
88
+ store[type] << component
89
+
90
+ update(component.local_components)
91
+
92
+ component
93
+ end
94
+
95
+ # @api private
96
+ def replace(type, item: nil, **options)
97
+ component = item || build(type, **options)
98
+ delete(type, item) if include?(type, component)
99
+ store[type] << component
100
+ component
101
+ end
102
+
103
+ # @api private
104
+ def delete(type, item)
105
+ self[type].delete(item)
106
+ self
107
+ end
108
+
109
+ # @api private
110
+ def update(other, **options)
111
+ other.each do |type, component|
112
+ add(
113
+ type,
114
+ item: component.with(provider: provider, config: component.config.join(options, :right))
115
+ )
116
+ end
117
+ self
118
+ end
119
+
120
+ # @api private
121
+ def build(type, **options)
122
+ handlers[type].build(**options, provider: provider)
123
+ end
124
+
125
+ # @api private
126
+ def include?(type, component)
127
+ !component.abstract? && keys(type).include?(component.key)
128
+ end
129
+
130
+ # @api private
131
+ def key?(key)
132
+ keys.include?(key)
133
+ end
134
+
135
+ # @api private
136
+ def keys(type = nil)
137
+ if type
138
+ self[type].map(&:key)
139
+ else
140
+ to_a.map(&:key)
141
+ end
142
+ end
143
+
144
+ CORE_COMPONENTS.each do |type|
145
+ define_method(type) do |**opts|
146
+ all = self[type]
147
+ return all if opts.empty?
148
+
149
+ all.select { |el| opts.all? { |key, value| el.public_send(key).eql?(value) } }
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "core"
4
+
5
+ module ROM
6
+ module Components
7
+ # @api public
8
+ class Relation < Core
9
+ # @!attribute [r] constant
10
+ # @return [.new] Relation instance builder (typically a class)
11
+ option :constant, type: Types.Interface(:new)
12
+
13
+ # @return [ROM::Relation]
14
+ #
15
+ # @api public
16
+ def build
17
+ constant.use(:changeset)
18
+ constant.use(:registry_reader, relations: registry.relation_ids)
19
+
20
+ # Define view methods if there are any registered view components for this relation
21
+ local_components.views(relation_id: id).each do |view|
22
+ view.define(constant)
23
+ end
24
+
25
+ apply_plugins
26
+
27
+ constant.new(inflector: inflector, registry: registry, **plugin_options)
28
+ end
29
+
30
+ # @api public
31
+ def adapter
32
+ config.adapter
33
+ end
34
+
35
+ # @api private
36
+ def local_components
37
+ constant.components
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rom/relation/name"
4
+
5
+ require_relative "core"
6
+
7
+ module ROM
8
+ module Components
9
+ # @api public
10
+ class Schema < Core
11
+ # @api private
12
+ option :name, type: Types.Instance(ROM::Relation::Name), default: -> {
13
+ ROM::Relation::Name[config.relation, config.dataset]
14
+ }
15
+
16
+ # @api public
17
+ def build
18
+ if view?
19
+ registry.schemas[config.relation].instance_eval(&block)
20
+ else
21
+ schema = config.constant.define(
22
+ name, **config, **config.options, inferrer: inferrer, registry: registry
23
+ )
24
+
25
+ if gateway?
26
+ schema.finalize_attributes!(gateway: gateway)
27
+ else
28
+ schema.finalize_attributes!
29
+ end
30
+
31
+ schema.finalize!
32
+ end
33
+ end
34
+
35
+ # @api private
36
+ def inferrer
37
+ config.inferrer.with(enabled: config.infer)
38
+ end
39
+
40
+ # @api private
41
+ def dataset
42
+ config.dataset
43
+ end
44
+
45
+ # @api private
46
+ def adapter
47
+ config.adapter
48
+ end
49
+
50
+ # @api private
51
+ def relation
52
+ config.relation
53
+ end
54
+
55
+ # @api private
56
+ def view?
57
+ config.view.equal?(true)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "core"
4
+
5
+ module ROM
6
+ module Components
7
+ # @api public
8
+ class View < Core
9
+ # @!attribute [r] relation_id
10
+ # @return [Symbol] Relation runtime identifier
11
+ # @api private
12
+ option :relation_id
13
+
14
+ # @!attribute [r] relation_block
15
+ # @return [Proc] Block used for view method definition
16
+ # @api private
17
+ option :relation_block
18
+
19
+ # @return [ROM::Relation]
20
+ #
21
+ # @api private
22
+ def build
23
+ registry.relations[relation_id].public_send(config.id)
24
+ end
25
+
26
+ # @return [Symbol]
27
+ #
28
+ # @api private
29
+ def define(constant)
30
+ _name = config.id
31
+ _relation_block = relation_block
32
+
33
+ if relation_block&.arity&.positive?
34
+ constant.class_eval do
35
+ auto_curry_guard do
36
+ define_method(_name, &_relation_block)
37
+
38
+ auto_curry(_name) do
39
+ schemas[_name].(self)
40
+ end
41
+ end
42
+ end
43
+ else
44
+ constant.class_eval do
45
+ define_method(_name) do
46
+ schemas[_name].(instance_eval(&_relation_block))
47
+ end
48
+ end
49
+ end
50
+
51
+ _name
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/container"
4
+
5
+ require_relative "initializer"
6
+ require_relative "types"
7
+
8
+ module ROM
9
+ # Registry of all known component handlers
10
+ #
11
+ # @api public
12
+ module Components
13
+ extend Dry::Container::Mixin
14
+ extend Enumerable
15
+
16
+ module_function
17
+
18
+ # @api private
19
+ class Handler
20
+ extend Initializer
21
+
22
+ option :key, type: Types.Instance(Symbol)
23
+
24
+ option :constant, type: Types.Interface(:new)
25
+
26
+ option :namespace, type: Types.Instance(Symbol), default: -> { Inflector.namespace(key) }
27
+
28
+ # @api private
29
+ def build(**options)
30
+ constant.new(**options)
31
+ end
32
+ end
33
+
34
+ # @see ROM.components
35
+ #
36
+ # @return [Components]
37
+ #
38
+ # @api public
39
+ def register(key, constant = nil, **options)
40
+ Handler.new(key: key, constant: constant, **options).tap do |handler|
41
+ super(handler.key, handler)
42
+ # TODO: unify handler access
43
+ super(handler.namespace, handler)
44
+ end
45
+ self
46
+ end
47
+
48
+ # Iterate over all registered component handlers
49
+ #
50
+ # @api public
51
+ def each
52
+ keys.each { |key| yield(resolve(key)) }
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ # TODO: move this to rom/compat
4
+ ROM::ConfigurationDSL = ROM::Components::DSL
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/core/constants"
4
+
5
+ # Constants and errors common in the whole library
6
+ module ROM
7
+ include Dry::Core::Constants
8
+
9
+ CORE_COMPONENTS = %i[
10
+ gateways
11
+ datasets
12
+ schemas
13
+ relations
14
+ views
15
+ associations
16
+ mappers
17
+ commands
18
+ ].freeze
19
+
20
+ AdapterLoadError = Class.new(StandardError)
21
+
22
+ # Exception raised when a component is configured with an adapter that's not loaded
23
+ class AdapterNotPresentError < StandardError
24
+ # @api private
25
+ def initialize(adapter, component)
26
+ super(
27
+ "Failed to find #{component} class for #{adapter} adapter. " \
28
+ "Make sure ROM setup was started and the adapter identifier is correct."
29
+ )
30
+ end
31
+ end
32
+
33
+ ConfigError = Class.new(StandardError) do
34
+ attr_reader :name, :component, :owner
35
+
36
+ # @api private
37
+ def initialize(name, component, reason = :inferrence)
38
+ @name = name
39
+ @component = component
40
+ @owner = component.owner
41
+
42
+ key = "#{component.type}.#{name}"
43
+
44
+ case reason
45
+ when :inferrence
46
+ super("Failed to infer +#{key}+ setting for #{component.provider}")
47
+ else
48
+ super("#{owner.name} #{key} setting is not valid")
49
+ end
50
+ end
51
+ end
52
+
53
+ EnvAlreadyFinalizedError = Class.new(StandardError)
54
+ GatewayAlreadyDefinedError = Class.new(StandardError)
55
+ DatasetAlreadyDefinedError = Class.new(StandardError)
56
+ SchemaAlreadyDefinedError = Class.new(StandardError)
57
+ RelationAlreadyDefinedError = Class.new(StandardError)
58
+ AssociationAlreadyDefinedError = Class.new(StandardError)
59
+ CommandAlreadyDefinedError = Class.new(StandardError)
60
+ MapperAlreadyDefinedError = Class.new(StandardError)
61
+ MapperMisconfiguredError = Class.new(StandardError)
62
+ NoRelationError = Class.new(StandardError)
63
+ InvalidRelationName = Class.new(StandardError)
64
+ CommandError = Class.new(StandardError)
65
+ KeyMissing = Class.new(ROM::CommandError)
66
+ TupleCountMismatchError = Class.new(CommandError)
67
+ UnknownPluginError = Class.new(StandardError)
68
+ UnsupportedRelationError = Class.new(StandardError)
69
+ MissingAdapterIdentifierError = Class.new(StandardError)
70
+ AttributeAlreadyDefinedError = Class.new(StandardError)
71
+
72
+ # Exception raised when a reserved keyword is used as a relation name
73
+ class InvalidRelationName < StandardError
74
+ # @api private
75
+ def initialize(relation)
76
+ super("Relation name: #{relation} is a protected word, please use another relation name")
77
+ end
78
+ end
79
+
80
+ # Exception raised when an element inside a component registry is not found
81
+ class ElementNotFoundError < KeyError
82
+ # @api private
83
+ def initialize(key, registry = nil)
84
+ msg =
85
+ if registry
86
+ "#{key.inspect} doesn't exist in #{registry.type} registry"
87
+ else
88
+ "#{key} doesn't exist in the registry"
89
+ end
90
+ super(msg)
91
+ end
92
+ end
93
+
94
+ GatewayMissingError = Class.new(ElementNotFoundError)
95
+
96
+ DatasetMissingError = Class.new(ElementNotFoundError)
97
+
98
+ SchemaMissingError = Class.new(ElementNotFoundError)
99
+
100
+ RelationMissingError = Class.new(ElementNotFoundError)
101
+
102
+ MapperMissingError = Class.new(ElementNotFoundError)
103
+
104
+ CommandNotFoundError = Class.new(ElementNotFoundError)
105
+
106
+ MissingSchemaClassError = Class.new(StandardError) do
107
+ # @api private
108
+ def initialize(klass)
109
+ super("#{klass.inspect} relation is missing schema_class")
110
+ end
111
+ end
112
+
113
+ MissingSchemaError = Class.new(StandardError) do
114
+ # @api private
115
+ def initialize(klass)
116
+ super("#{klass.inspect} relation is missing schema definition")
117
+ end
118
+ end
119
+
120
+ MISSING_ELEMENT_ERRORS = {
121
+ gateways: GatewayMissingError,
122
+ schemas: SchemaMissingError,
123
+ datasets: DatasetMissingError,
124
+ relations: RelationMissingError,
125
+ associations: RelationMissingError,
126
+ commands: CommandNotFoundError,
127
+ mappers: MapperMissingError
128
+ }.freeze
129
+
130
+ DuplicateConfigurationError = Class.new(StandardError)
131
+ DuplicateContainerError = Class.new(StandardError)
132
+
133
+ InvalidOptionValueError = Class.new(StandardError)
134
+ InvalidOptionKeyError = Class.new(StandardError)
135
+ end