rom 0.9.1 → 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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