rom 0.9.1 → 1.0.0.beta1

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 (143) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +30 -12
  3. data/.travis.yml +1 -1
  4. data/CHANGELOG.md +24 -0
  5. data/Gemfile +7 -3
  6. data/README.md +24 -11
  7. data/lib/rom.rb +9 -26
  8. data/lib/rom/command.rb +113 -75
  9. data/lib/rom/commands/class_interface.rb +115 -0
  10. data/lib/rom/commands/graph.rb +17 -23
  11. data/lib/rom/commands/graph/builder.rb +176 -0
  12. data/lib/rom/commands/graph/class_interface.rb +8 -2
  13. data/lib/rom/commands/graph/input_evaluator.rb +13 -9
  14. data/lib/rom/commands/lazy.rb +23 -17
  15. data/lib/rom/commands/lazy/create.rb +23 -0
  16. data/lib/rom/commands/lazy/delete.rb +27 -0
  17. data/lib/rom/commands/lazy/update.rb +34 -0
  18. data/lib/rom/commands/result.rb +14 -0
  19. data/lib/rom/commands/update.rb +0 -4
  20. data/lib/rom/configuration.rb +86 -0
  21. data/lib/rom/{setup_dsl/setup.rb → configuration_dsl.rb} +9 -7
  22. data/lib/rom/configuration_dsl/command.rb +43 -0
  23. data/lib/rom/{setup_dsl → configuration_dsl}/command_dsl.rb +5 -4
  24. data/lib/rom/configuration_dsl/mapper.rb +37 -0
  25. data/lib/rom/{setup_dsl → configuration_dsl}/mapper_dsl.rb +11 -5
  26. data/lib/rom/configuration_dsl/relation.rb +26 -0
  27. data/lib/rom/configuration_plugin.rb +17 -0
  28. data/lib/rom/constants.rb +5 -12
  29. data/lib/rom/container.rb +11 -8
  30. data/lib/rom/create_container.rb +61 -0
  31. data/lib/rom/environment.rb +27 -241
  32. data/lib/rom/gateway.rb +18 -2
  33. data/lib/rom/global.rb +24 -0
  34. data/lib/rom/global/plugin_dsl.rb +2 -0
  35. data/lib/rom/lint/spec.rb +0 -12
  36. data/lib/rom/lint/test.rb +0 -31
  37. data/lib/rom/memory/commands.rb +2 -2
  38. data/lib/rom/memory/gateway.rb +2 -0
  39. data/lib/rom/pipeline.rb +1 -1
  40. data/lib/rom/plugin_base.rb +1 -1
  41. data/lib/rom/plugin_registry.rb +12 -10
  42. data/lib/rom/plugins/configuration/configuration_dsl.rb +16 -0
  43. data/lib/rom/plugins/relation/key_inference.rb +31 -0
  44. data/lib/rom/plugins/relation/view.rb +90 -0
  45. data/lib/rom/plugins/relation/view/dsl.rb +32 -0
  46. data/lib/rom/relation.rb +1 -11
  47. data/lib/rom/relation/class_interface.rb +37 -50
  48. data/lib/rom/setup.rb +13 -104
  49. data/lib/rom/setup/auto_registration.rb +55 -0
  50. data/lib/rom/setup/finalize.rb +113 -127
  51. data/lib/rom/setup/finalize/commands.rb +67 -0
  52. data/lib/rom/setup/finalize/mappers.rb +36 -0
  53. data/lib/rom/setup/finalize/relations.rb +53 -0
  54. data/lib/rom/support/configurable.rb +21 -7
  55. data/lib/rom/version.rb +1 -1
  56. data/rakelib/mutant.rake +4 -1
  57. data/rom.gemspec +3 -4
  58. data/spec/fixtures/app/commands/create_user.rb +2 -0
  59. data/spec/fixtures/app/mappers/user_list.rb +2 -0
  60. data/spec/fixtures/app/relations/users.rb +2 -0
  61. data/spec/fixtures/lib/persistence/commands/create_user.rb +6 -0
  62. data/spec/fixtures/lib/persistence/mappers/user_list.rb +6 -0
  63. data/spec/fixtures/lib/persistence/relations/users.rb +6 -0
  64. data/spec/{unit/rom → integration}/command_registry_spec.rb +8 -9
  65. data/spec/integration/commands/create_spec.rb +17 -13
  66. data/spec/integration/commands/delete_spec.rb +12 -11
  67. data/spec/integration/commands/error_handling_spec.rb +5 -4
  68. data/spec/integration/commands/graph_builder_spec.rb +213 -0
  69. data/spec/integration/commands/graph_spec.rb +112 -49
  70. data/spec/integration/commands/update_spec.rb +14 -11
  71. data/spec/integration/commands_spec.rb +60 -0
  72. data/spec/integration/mappers/combine_spec.rb +7 -6
  73. data/spec/integration/mappers/deep_embedded_spec.rb +5 -6
  74. data/spec/integration/mappers/definition_dsl_spec.rb +19 -18
  75. data/spec/integration/mappers/embedded_spec.rb +11 -12
  76. data/spec/integration/mappers/exclude_spec.rb +5 -6
  77. data/spec/integration/mappers/fold_spec.rb +8 -7
  78. data/spec/integration/mappers/group_spec.rb +16 -15
  79. data/spec/integration/mappers/overwrite_attributes_value_spec.rb +5 -5
  80. data/spec/integration/mappers/prefix_separator_spec.rb +5 -7
  81. data/spec/integration/mappers/prefix_spec.rb +5 -7
  82. data/spec/integration/mappers/prefixing_attributes_spec.rb +7 -7
  83. data/spec/integration/mappers/registering_custom_mappers_spec.rb +4 -5
  84. data/spec/integration/mappers/renaming_attributes_spec.rb +18 -18
  85. data/spec/integration/mappers/step_spec.rb +11 -12
  86. data/spec/integration/mappers/symbolizing_attributes_spec.rb +11 -8
  87. data/spec/integration/mappers/unfold_spec.rb +9 -10
  88. data/spec/integration/mappers/ungroup_spec.rb +10 -11
  89. data/spec/integration/mappers/unwrap_spec.rb +10 -15
  90. data/spec/integration/mappers/wrap_spec.rb +16 -15
  91. data/spec/{unit/rom → integration}/memory/commands/create_spec.rb +7 -5
  92. data/spec/{unit/rom → integration}/memory/commands/delete_spec.rb +7 -5
  93. data/spec/{unit/rom → integration}/memory/commands/update_spec.rb +7 -5
  94. data/spec/integration/multi_env_spec.rb +16 -124
  95. data/spec/integration/multi_repo_spec.rb +9 -9
  96. data/spec/integration/relations/default_dataset_spec.rb +15 -0
  97. data/spec/integration/relations/inheritance_spec.rb +5 -7
  98. data/spec/integration/relations/reading_spec.rb +32 -65
  99. data/spec/integration/relations/registry_dsl_spec.rb +5 -4
  100. data/spec/integration/repositories/extending_relations_spec.rb +6 -7
  101. data/spec/integration/repositories/setting_logger_spec.rb +5 -7
  102. data/spec/integration/setup_spec.rb +49 -61
  103. data/spec/shared/command_graph.rb +50 -0
  104. data/spec/shared/container.rb +9 -0
  105. data/spec/shared/gateway_only.rb +6 -0
  106. data/spec/shared/no_container.rb +16 -0
  107. data/spec/shared/one_behavior.rb +4 -4
  108. data/spec/shared/users_and_tasks.rb +5 -17
  109. data/spec/spec_helper.rb +5 -3
  110. data/spec/test/memory_repository_lint_test.rb +1 -1
  111. data/spec/unit/rom/auto_registration_spec.rb +54 -0
  112. data/spec/unit/rom/commands/graph_spec.rb +18 -44
  113. data/spec/unit/rom/commands/lazy_spec.rb +246 -35
  114. data/spec/unit/rom/commands/result_spec.rb +56 -0
  115. data/spec/unit/rom/commands_spec.rb +9 -73
  116. data/spec/unit/rom/configurable_spec.rb +49 -0
  117. data/spec/unit/rom/configuration_spec.rb +61 -0
  118. data/spec/unit/rom/container_spec.rb +39 -33
  119. data/spec/unit/rom/create_container_spec.rb +151 -0
  120. data/spec/unit/rom/environment_spec.rb +123 -0
  121. data/spec/unit/rom/gateway_spec.rb +58 -2
  122. data/spec/unit/rom/global_spec.rb +10 -7
  123. data/spec/unit/rom/plugin_spec.rb +44 -25
  124. data/spec/unit/rom/plugins/relation/key_inference_spec.rb +27 -0
  125. data/spec/unit/rom/plugins/relation/view_spec.rb +47 -0
  126. data/spec/unit/rom/relation/composite_spec.rb +20 -20
  127. data/spec/unit/rom/relation/curried_spec.rb +10 -11
  128. data/spec/unit/rom/relation/graph_spec.rb +27 -27
  129. data/spec/unit/rom/relation/lazy/combine_spec.rb +26 -20
  130. data/spec/unit/rom/relation/lazy_spec.rb +38 -38
  131. data/spec/unit/rom/relation/loaded_spec.rb +2 -3
  132. data/spec/unit/rom/relation_spec.rb +39 -2
  133. metadata +58 -66
  134. data/lib/rom/commands/abstract.rb +0 -184
  135. data/lib/rom/environment_plugin.rb +0 -17
  136. data/lib/rom/environment_plugins/auto_registration.rb +0 -38
  137. data/lib/rom/repository.rb +0 -16
  138. data/lib/rom/setup_dsl/command.rb +0 -36
  139. data/lib/rom/setup_dsl/mapper.rb +0 -32
  140. data/lib/rom/setup_dsl/relation.rb +0 -30
  141. data/spec/integration/inline_setup_spec.rb +0 -65
  142. data/spec/unit/rom/repository_spec.rb +0 -12
  143. data/spec/unit/rom/setup_spec.rb +0 -253
data/lib/rom/constants.rb CHANGED
@@ -15,23 +15,16 @@ module ROM
15
15
  RelationAlreadyDefinedError = Class.new(StandardError)
16
16
  NoRelationError = Class.new(StandardError)
17
17
  CommandError = Class.new(StandardError)
18
+ KeyMissing = Class.new(ROM::CommandError)
18
19
  TupleCountMismatchError = Class.new(CommandError)
19
20
  MapperMissingError = Class.new(StandardError)
20
21
  UnknownPluginError = Class.new(StandardError)
21
22
  UnsupportedRelationError = Class.new(StandardError)
23
+ MissingAdapterIdentifierError = Class.new(StandardError)
24
+
25
+ DuplicateConfigurationError = Class.new(StandardError)
26
+ DuplicateContainerError = Class.new(StandardError)
22
27
 
23
28
  InvalidOptionValueError = Class.new(StandardError)
24
29
  InvalidOptionKeyError = Class.new(StandardError)
25
-
26
- class CommandFailure < StandardError
27
- attr_reader :command
28
- attr_reader :original_error
29
-
30
- def initialize(command, err)
31
- super("command: #{command.inspect}; original message: #{err.message}")
32
- @command = command
33
- @original_error = err
34
- set_backtrace(err.backtrace)
35
- end
36
- end
37
30
  end
data/lib/rom/container.rb CHANGED
@@ -1,22 +1,21 @@
1
1
  require 'rom/relation/loaded'
2
2
  require 'rom/commands/graph'
3
- require 'rom/support/deprecations'
3
+ require 'rom/commands/graph/builder'
4
+ require 'rom/support/publisher'
4
5
 
5
6
  module ROM
6
7
  # Exposes defined gateways, relations and mappers
7
8
  #
8
9
  # @api public
9
10
  class Container
10
- extend Deprecations
11
- include Equalizer.new(:gateways, :relations, :mappers, :commands)
11
+ include ROM::Support::Publisher
12
+ include Dry::Equalizer(:gateways, :relations, :mappers, :commands)
12
13
 
13
14
  # @return [Hash] configured gateways
14
15
  #
15
16
  # @api public
16
17
  attr_reader :gateways
17
18
 
18
- deprecate :repositories, :gateways
19
-
20
19
  # @return [RelationRegistry] relation registry
21
20
  #
22
21
  # @api private
@@ -38,7 +37,6 @@ module ROM
38
37
  @relations = relations
39
38
  @mappers = mappers
40
39
  @commands = commands
41
- freeze
42
40
  end
43
41
 
44
42
  # Get lazy relation identified by its name
@@ -77,7 +75,6 @@ module ROM
77
75
  relation
78
76
  end
79
77
  end
80
- deprecate :read, :relation, "For mapping append `.map_with(:your_mapper_name)`"
81
78
 
82
79
  # Returns commands registry for the given relation
83
80
  #
@@ -99,7 +96,7 @@ module ROM
99
96
  # @return [Command, Command::Graph]
100
97
  #
101
98
  # @api public
102
- def command(options)
99
+ def command(options = nil)
103
100
  case options
104
101
  when Symbol
105
102
  name = options
@@ -117,9 +114,15 @@ module ROM
117
114
  else
118
115
  graph
119
116
  end
117
+ when nil
118
+ Commands::Graph::Builder.new(self)
120
119
  else
121
120
  raise ArgumentError, "#{self.class}#command accepts a symbol or an array"
122
121
  end
123
122
  end
123
+
124
+ def disconnect
125
+ gateways.each_key(&:disconnect)
126
+ end
124
127
  end
125
128
  end
@@ -0,0 +1,61 @@
1
+ require 'rom/configuration'
2
+ require 'rom/environment'
3
+ require 'rom/setup'
4
+ require 'rom/setup/finalize'
5
+
6
+ module ROM
7
+ class CreateContainer
8
+ include ROM::Support::Publisher
9
+
10
+ attr_reader :container
11
+
12
+ def initialize(environment, setup)
13
+ @container = finalize(environment, setup)
14
+ end
15
+
16
+ private
17
+
18
+ def finalize(environment, setup)
19
+ environment.configure do |config|
20
+ environment.gateways.each_key do |key|
21
+ gateway_config = config.gateways[key]
22
+ gateway_config.infer_relations = true unless gateway_config.key?(:infer_relations)
23
+ end
24
+ end
25
+
26
+ finalize = Finalize.new(
27
+ gateways: environment.gateways,
28
+ gateway_map: environment.gateways_map,
29
+ relation_classes: setup.relation_classes,
30
+ command_classes: setup.command_classes,
31
+ mappers: setup.mapper_classes,
32
+ config: environment.config.dup.freeze
33
+ )
34
+
35
+ finalize.run!
36
+ end
37
+ end
38
+
39
+ class InlineCreateContainer < CreateContainer
40
+ def initialize(*args, &block)
41
+ case args.first
42
+ when Configuration
43
+ environment = args.first.environment
44
+ setup = args.first.setup
45
+ when Environment
46
+ environment = args.first
47
+ setup = args[1]
48
+ else
49
+ configuration = Configuration.new(*args, &block)
50
+ environment = configuration.environment
51
+ setup = configuration.setup
52
+ end
53
+
54
+ super(environment, setup)
55
+ end
56
+ end
57
+
58
+ def self.container(*args, &block)
59
+ InlineCreateContainer.new(*args, &block).container
60
+ end
61
+ end
@@ -1,272 +1,58 @@
1
- require 'rom/setup'
2
- require 'rom/repository'
1
+ require 'rom/support/configurable'
2
+ require 'rom/gateway'
3
3
 
4
4
  module ROM
5
- # Globally accessible public interface exposed via ROM module
5
+ # Core gateway configuration interface
6
6
  #
7
7
  # @api public
8
8
  class Environment
9
- # An internal gateway => identifier map used by the setup
10
- #
11
- # @return [Hash]
12
- #
13
- # @api private
14
- attr_reader :gateways
9
+ include Configurable
15
10
 
16
- # Setup object created during setup phase
17
- #
18
- # This gets set to nil after setup is finalized
19
- #
20
- # @return [Setup]
21
- #
22
- # @api private
23
- attr_reader :boot
11
+ attr_reader :gateways, :gateways_map
24
12
 
25
- # Return ROM container configured by the setup
26
- #
27
- # @return [Container]
28
- #
29
13
  # @api public
30
- attr_reader :container
31
- alias_method :env, :container
32
-
33
- # @api private
34
- def initialize
14
+ def initialize(*args)
35
15
  @gateways = {}
36
- end
37
-
38
- # @api private
39
- def adapters
40
- ROM.adapters
41
- end
16
+ @gateways_map = {}
42
17
 
43
- # @api private
44
- def plugin_registry
45
- ROM.plugin_registry
18
+ configure_gateways(*args) unless args.empty?
46
19
  end
47
20
 
48
- # Apply a plugin to the environment
49
- #
50
- # @param [Mixed] The plugin identifier, usually a Symbol
51
- # @param [Hash] Plugin options
52
- #
53
- # @api public
54
- def use(plugin, options = {})
55
- plugin_registry.environment.fetch(plugin).apply_to(self, options)
56
- end
57
-
58
- # Starts the setup process for relations, mappers and commands.
59
- #
60
- # @overload setup(type, *args)
61
- # Sets up a single-gateway environment given a gateway type provided
62
- # under the ROM umbrella. For custom gateways, create an instance and
63
- # pass it directly.
64
- #
65
- # @param [Symbol] type
66
- # @param [Array] *args
67
- #
68
- # @overload setup(gateway)
69
- # @param [Gateway] gateway
70
- #
71
- # @overload setup(gateways)
72
- # Sets up multiple gateways.
73
- #
74
- # @param [Hash{Symbol=>Symbol,Array}] gateways
75
- #
76
- # @return [Setup] boot object
77
- #
78
- # @example
79
- # # Use the in-memory adapter shipped with ROM as the default gateway.
80
- # rom = ROM::Environment.new
81
- # env = rom.setup(:memory, 'memory://test')
82
- # # Use `rom-sql` with an in-memory sqlite database as default gateway.
83
- # rom.setup(:sql, 'sqlite::memory')
84
- # # Registers a `default` and a `warehouse` gateway.
85
- # env = rom.setup(
86
- # default: [:sql, 'sqlite::memory'],
87
- # warehouse: [:sql, 'postgres://localhost/warehouse']
88
- # )
89
- #
90
- # @example A full environment
91
- #
92
- # rom = ROM::Environment.new
93
- # rom.setup(:memory, 'memory://test')
94
- #
95
- # rom.relation(:users) do
96
- # # ...
97
- # end
98
- #
99
- # rom.mappers do
100
- # define(:users) do
101
- # # ...
102
- # end
103
- # end
104
- #
105
- # rom.commands(:users) do
106
- # define(:create) do
107
- # # ...
108
- # end
109
- # end
110
- #
111
- # rom.finalize # builds the container
112
- # rom.container # returns the container registry
113
- #
114
- # @api public
115
- def setup(*args, &block)
116
- config = setup_config(*args)
117
- configured_gateways = setup_gateways(config)
118
-
119
- default_adapter = gateways.fetch(
120
- configured_gateways[:default], adapters.keys.first
121
- )
21
+ private
122
22
 
123
- @boot = Setup.new(configured_gateways,
124
- gateway_map: gateways,
125
- default_adapter: default_adapter
126
- )
23
+ def configure_gateways(*args)
24
+ normalized_gateway_args = normalize_gateway_args(*args)
25
+ normalized_gateways = normalize_gateways(normalized_gateway_args)
127
26
 
128
- config.each do |name, config_args|
129
- options = config_args.is_a?(Array) && config_args.last
130
- load_config(@boot.config.gateways[name], options) if options.is_a?(Hash)
131
- end
27
+ @gateways, @gateways_map = normalized_gateways.values_at(:gateways, :map)
132
28
 
133
- if block
134
- use :auto_registration unless auto_registration?
135
- @boot.instance_exec(&block)
136
- finalize.container
137
- else
138
- @boot
29
+ normalized_gateway_args.each_with_object(config) do |(name, gateway_config), config|
30
+ options = gateway_config.is_a?(Array) && gateway_config.last
31
+ load_config(config.gateways[name], options) if options.is_a?(Hash)
139
32
  end
140
33
  end
141
34
 
142
- # Check if auto-registration is enabled for this environment
143
- #
144
- # @api private
145
- def auto_registration?
146
- false
147
- end
148
-
149
- # Global relation setup DSL
150
- #
151
- # @example
152
- # rom = ROM::Environment.new
153
- # rom.setup(:memory)
154
- #
155
- # rom.relation(:users) do
156
- # def by_name(name)
157
- # restrict(name: name)
158
- # end
159
- # end
160
- #
161
- # @api public
162
- def relation(*args, &block)
163
- boot.relation(*args, &block)
164
- end
165
-
166
- # Global commands setup DSL
167
- #
168
- # @example
169
- # rom = ROM::Environment.new
170
- # rom.setup(:memory)
171
- #
172
- # rom.commands(:users) do
173
- # define(:create) do
174
- # # ..
175
- # end
176
- # end
177
- #
178
- # @api public
179
- def commands(*args, &block)
180
- boot.commands(*args, &block)
181
- end
182
-
183
- # Global mapper setup DSL
184
- #
185
- # @example
186
- # rom = ROM::Environment.new
187
- # rom.setup(:memory)
188
- #
189
- # rom.mappers do
190
- # define(:uses) do
191
- # # ..
192
- # end
193
- # end
194
- #
195
- # @api public
196
- def mappers(*args, &block)
197
- boot.mappers(*args, &block)
198
- end
199
-
200
- # Finalize the setup and store default global container under
201
- # ROM::Environmrnt#container
202
- #
203
- # @example
204
- # rom = ROM::Environment.new
205
- # rom.setup(:memory)
206
- # rom.finalize # => rom
207
- # rom.boot # => nil
208
- # rom.container # => the container
209
- #
210
- # @return [ROM]
211
- #
212
- # @api public
213
- def finalize
214
- @container = boot.finalize
215
- self
216
- ensure
217
- @boot = nil
218
- end
219
-
220
- # Relation subclass registration during setup phase
221
- #
222
- # @api private
223
- def register_relation(klass)
224
- boot.register_relation(klass) if boot
225
- end
226
-
227
- # Mapper subclass registration during setup phase
228
- #
229
- # @api private
230
- def register_mapper(klass)
231
- boot.register_mapper(klass) if boot
232
- end
233
-
234
- # Command subclass registration during setup phase
235
- #
236
- # @api private
237
- def register_command(klass)
238
- boot.register_command(klass) if boot
239
- end
240
-
241
- # Return gateway config that was used to setup this environment's container
242
- #
243
- # @return [Configurable::Config]
244
- #
245
- # @api public
246
- def config
247
- boot.config
248
- end
249
35
 
250
- private
251
-
252
- # Helper method to handle single- or multi-repo setup options
253
- #
254
36
  # @api private
255
- def setup_config(*args)
256
- args.first.is_a?(Hash) ? args.first : { default: args }
37
+ def normalize_gateway_args(*args)
38
+ args.first.is_a?(Hash) ? args.first : {default: args}
257
39
  end
258
40
 
259
41
  # Build gateways using the setup interface
260
42
  #
261
43
  # @api private
262
- def setup_gateways(config)
263
- config.each_with_object({}) do |(name, spec), hash|
44
+ def normalize_gateways(gateways_config)
45
+ gateways_config.each_with_object({map: {}, gateways: {}}) do |(name, spec), hash|
264
46
  identifier, *args = Array(spec)
265
47
 
266
- gateway = Gateway.setup(identifier, *(args.flatten))
267
- hash[name] = gateway
48
+ if identifier.is_a?(Gateway)
49
+ gateway = identifier
50
+ else
51
+ gateway = Gateway.setup(identifier, *(args.flatten))
52
+ hash[:map][gateway] = identifier
53
+ end
268
54
 
269
- gateways[gateway] = identifier unless identifier.is_a?(Gateway)
55
+ hash[:gateways][name] = gateway
270
56
  end
271
57
  end
272
58