rom 2.0.2 → 3.0.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +4 -7
- data/.yardopts +2 -0
- data/CHANGELOG.md +35 -1
- data/Gemfile +17 -2
- data/Rakefile +7 -2
- data/lib/rom/array_dataset.rb +44 -0
- data/lib/rom/association_set.rb +11 -5
- data/lib/rom/auto_curry.rb +55 -0
- data/lib/rom/command.rb +331 -47
- data/lib/rom/command_registry.rb +7 -18
- data/lib/rom/commands/class_interface.rb +120 -6
- data/lib/rom/commands/composite.rb +0 -1
- data/lib/rom/commands/graph.rb +7 -15
- data/lib/rom/commands/lazy/update.rb +1 -1
- data/lib/rom/configuration.rb +2 -0
- data/lib/rom/configuration_dsl/command.rb +6 -8
- data/lib/rom/configuration_dsl/mapper.rb +2 -3
- data/lib/rom/configuration_dsl/mapper_dsl.rb +0 -1
- data/lib/rom/configuration_dsl/relation.rb +4 -4
- data/lib/rom/configuration_dsl.rb +0 -4
- data/lib/rom/constants.rb +7 -1
- data/lib/rom/container.rb +11 -17
- data/lib/rom/create_container.rb +0 -2
- data/lib/rom/data_proxy.rb +94 -0
- data/lib/rom/enumerable_dataset.rb +68 -0
- data/lib/rom/gateway.rb +74 -32
- data/lib/rom/global/plugin_dsl.rb +0 -2
- data/lib/rom/global.rb +0 -2
- data/lib/rom/initializer.rb +26 -0
- data/lib/rom/lint/gateway.rb +17 -0
- data/lib/rom/mapper_registry.rb +1 -1
- data/lib/rom/memory/commands.rb +0 -2
- data/lib/rom/memory/dataset.rb +1 -2
- data/lib/rom/memory/relation.rb +14 -1
- data/lib/rom/memory/schema.rb +13 -0
- data/lib/rom/plugin_registry.rb +1 -1
- data/lib/rom/plugins/command/schema.rb +2 -2
- data/lib/rom/plugins/configuration/configuration_dsl.rb +6 -2
- data/lib/rom/plugins/relation/key_inference.rb +4 -2
- data/lib/rom/plugins/relation/registry_reader.rb +5 -1
- data/lib/rom/registry.rb +50 -0
- data/lib/rom/relation/class_interface.rb +142 -30
- data/lib/rom/relation/curried.rb +15 -15
- data/lib/rom/relation/view_dsl.rb +31 -0
- data/lib/rom/relation.rb +101 -41
- data/lib/rom/schema/attribute.rb +367 -0
- data/lib/rom/schema/dsl.rb +14 -10
- data/lib/rom/schema.rb +337 -19
- data/lib/rom/setup/auto_registration.rb +20 -17
- data/lib/rom/setup/auto_registration_strategies/base.rb +8 -3
- data/lib/rom/setup/auto_registration_strategies/custom_namespace.rb +4 -3
- data/lib/rom/setup/auto_registration_strategies/no_namespace.rb +5 -4
- data/lib/rom/setup/auto_registration_strategies/with_namespace.rb +3 -3
- data/lib/rom/setup/finalize/finalize_commands.rb +1 -1
- data/lib/rom/setup/finalize/finalize_mappers.rb +1 -1
- data/lib/rom/setup/finalize/finalize_relations.rb +4 -2
- data/lib/rom/setup/finalize.rb +1 -1
- data/lib/rom/transaction.rb +24 -0
- data/lib/rom/types.rb +9 -1
- data/lib/rom/version.rb +1 -1
- data/lib/rom.rb +4 -8
- data/rom.gemspec +5 -4
- data/spec/integration/command_registry_spec.rb +1 -14
- data/spec/integration/commands/create_spec.rb +5 -25
- data/spec/integration/commands/delete_spec.rb +1 -1
- data/spec/integration/commands/error_handling_spec.rb +1 -1
- data/spec/integration/commands/graph_spec.rb +20 -14
- data/spec/integration/commands/update_spec.rb +4 -27
- data/spec/integration/commands_spec.rb +1 -1
- data/spec/integration/{repositories → gateways}/extending_relations_spec.rb +1 -1
- data/spec/integration/{repositories → gateways}/setting_logger_spec.rb +2 -2
- data/spec/integration/mappers/combine_spec.rb +1 -1
- data/spec/integration/mappers/deep_embedded_spec.rb +1 -1
- data/spec/integration/mappers/definition_dsl_spec.rb +1 -1
- data/spec/integration/mappers/embedded_spec.rb +1 -1
- data/spec/integration/mappers/exclude_spec.rb +1 -1
- data/spec/integration/mappers/fold_spec.rb +1 -1
- data/spec/integration/mappers/group_spec.rb +1 -1
- data/spec/integration/mappers/overwrite_attributes_value_spec.rb +1 -1
- data/spec/integration/mappers/prefix_separator_spec.rb +1 -1
- data/spec/integration/mappers/prefix_spec.rb +1 -1
- data/spec/integration/mappers/prefixing_attributes_spec.rb +1 -1
- data/spec/integration/mappers/registering_custom_mappers_spec.rb +1 -1
- data/spec/integration/mappers/renaming_attributes_spec.rb +1 -1
- data/spec/integration/mappers/reusing_mappers_spec.rb +1 -1
- data/spec/integration/mappers/step_spec.rb +1 -1
- data/spec/integration/mappers/symbolizing_attributes_spec.rb +1 -1
- data/spec/integration/mappers/unfold_spec.rb +1 -1
- data/spec/integration/mappers/ungroup_spec.rb +2 -2
- data/spec/integration/mappers/unwrap_spec.rb +2 -2
- data/spec/integration/mappers/wrap_spec.rb +1 -1
- data/spec/integration/memory/commands/create_spec.rb +1 -1
- data/spec/integration/memory/commands/delete_spec.rb +1 -1
- data/spec/integration/memory/commands/update_spec.rb +1 -1
- data/spec/integration/multi_env_spec.rb +1 -1
- data/spec/integration/multi_repo_spec.rb +1 -1
- data/spec/integration/relations/default_dataset_spec.rb +1 -1
- data/spec/integration/relations/reading_spec.rb +1 -1
- data/spec/integration/relations/registry_dsl_spec.rb +1 -1
- data/spec/integration/setup_spec.rb +10 -4
- data/spec/shared/command_graph.rb +8 -4
- data/spec/shared/enumerable_dataset.rb +1 -1
- data/spec/spec_helper.rb +7 -9
- data/spec/support/schema.rb +14 -0
- data/spec/unit/rom/array_dataset_spec.rb +59 -0
- data/spec/unit/rom/association_set_spec.rb +4 -0
- data/spec/unit/rom/auto_curry_spec.rb +63 -0
- data/spec/unit/rom/commands/graph_spec.rb +12 -11
- data/spec/unit/rom/commands/lazy_spec.rb +8 -5
- data/spec/unit/rom/commands/pre_and_post_processors_spec.rb +336 -0
- data/spec/unit/rom/commands/result_spec.rb +1 -1
- data/spec/unit/rom/commands_spec.rb +26 -3
- data/spec/unit/rom/configuration_spec.rb +1 -1
- data/spec/unit/rom/container_spec.rb +15 -5
- data/spec/unit/rom/create_container_spec.rb +1 -1
- data/spec/unit/rom/enumerable_dataset_spec.rb +15 -0
- data/spec/unit/rom/gateway_spec.rb +1 -1
- data/spec/unit/rom/mapper_registry_spec.rb +1 -1
- data/spec/unit/rom/memory/commands_spec.rb +1 -1
- data/spec/unit/rom/memory/dataset_spec.rb +1 -1
- data/spec/unit/rom/memory/{repository_spec.rb → gateway_spec.rb} +1 -1
- data/spec/unit/rom/memory/inheritance_spec.rb +32 -0
- data/spec/unit/rom/memory/relation_spec.rb +15 -3
- data/spec/unit/rom/memory/storage_spec.rb +1 -1
- data/spec/unit/rom/plugin_spec.rb +1 -1
- data/spec/unit/rom/plugins/command/schema_spec.rb +5 -5
- data/spec/unit/rom/plugins/relation/key_inference_spec.rb +1 -1
- data/spec/unit/rom/registry_spec.rb +86 -0
- data/spec/unit/rom/relation/attribute_reader_spec.rb +17 -0
- data/spec/unit/rom/relation/call_spec.rb +51 -0
- data/spec/unit/rom/relation/composite_spec.rb +1 -1
- data/spec/unit/rom/relation/graph_spec.rb +1 -1
- data/spec/unit/rom/relation/lazy/combine_spec.rb +1 -1
- data/spec/unit/rom/relation/lazy_spec.rb +1 -1
- data/spec/unit/rom/relation/loaded_spec.rb +1 -1
- data/spec/unit/rom/relation/schema_spec.rb +50 -6
- data/spec/unit/rom/relation/view_spec.rb +122 -0
- data/spec/unit/rom/relation_spec.rb +20 -5
- data/spec/unit/rom/schema/accessing_attributes_spec.rb +52 -0
- data/spec/unit/rom/schema/append_spec.rb +17 -0
- data/spec/unit/rom/schema/exclude_spec.rb +15 -0
- data/spec/unit/rom/schema/finalize_spec.rb +59 -0
- data/spec/unit/rom/schema/key_predicate_spec.rb +15 -0
- data/spec/unit/rom/schema/merge_spec.rb +17 -0
- data/spec/unit/rom/schema/prefix_spec.rb +16 -0
- data/spec/unit/rom/schema/project_spec.rb +15 -0
- data/spec/unit/rom/schema/rename_spec.rb +22 -0
- data/spec/unit/rom/schema/type_spec.rb +49 -0
- data/spec/unit/rom/schema/uniq_spec.rb +21 -0
- data/spec/unit/rom/schema/wrap_spec.rb +17 -0
- data/spec/unit/rom/schema_spec.rb +2 -2
- metadata +79 -17
- data/lib/rom/plugins/relation/view/dsl.rb +0 -32
- data/lib/rom/plugins/relation/view.rb +0 -95
- data/spec/unit/rom/plugins/relation/view_spec.rb +0 -51
data/lib/rom/command.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'dry/core/deprecations'
|
2
|
+
require 'dry/core/class_attributes'
|
3
|
+
|
4
|
+
require 'rom/types'
|
5
|
+
require 'rom/initializer'
|
3
6
|
require 'rom/pipeline'
|
4
7
|
|
5
8
|
require 'rom/commands/class_interface'
|
@@ -18,58 +21,213 @@ module ROM
|
|
18
21
|
#
|
19
22
|
# @abstract
|
20
23
|
#
|
21
|
-
# @
|
24
|
+
# @api public
|
22
25
|
class Command
|
23
|
-
|
24
|
-
|
26
|
+
extend Initializer
|
25
27
|
include Dry::Equalizer(:relation, :options)
|
26
28
|
include Commands
|
27
29
|
include Pipeline::Operator
|
28
30
|
|
29
|
-
extend
|
31
|
+
extend Dry::Core::ClassAttributes
|
30
32
|
extend ClassInterface
|
31
33
|
|
32
|
-
|
34
|
+
# @!method self.adapter
|
35
|
+
# Get or set adapter identifier
|
36
|
+
#
|
37
|
+
# @overload adapter
|
38
|
+
# Get adapter identifier
|
39
|
+
#
|
40
|
+
# @example
|
41
|
+
# ROM::Memory::Commands::Create.adapter
|
42
|
+
# # => :memory
|
43
|
+
#
|
44
|
+
# @return [Symbol]
|
45
|
+
#
|
46
|
+
# @overload adapter(identifier)
|
47
|
+
# Set adapter identifier. This must always match actual adapter identifier
|
48
|
+
# that was used to register an adapter.
|
49
|
+
#
|
50
|
+
# @example
|
51
|
+
# module MyAdapter
|
52
|
+
# class CreateCommand < ROM::Commands::Memory::Create
|
53
|
+
# adapter :my_adapter
|
54
|
+
# end
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# @api public
|
58
|
+
defines :adapter
|
33
59
|
|
34
|
-
|
60
|
+
# @!method self.relation
|
61
|
+
# Get or set relation identifier
|
62
|
+
#
|
63
|
+
# @overload relation
|
64
|
+
# Get relation identifier
|
65
|
+
#
|
66
|
+
# @example
|
67
|
+
# module CreateUser < ROM::Commands::Create[:memory]
|
68
|
+
# relation :users
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# CreateUser.relation
|
72
|
+
# # => :users
|
73
|
+
#
|
74
|
+
# @return [Symbol]
|
75
|
+
#
|
76
|
+
# @overload relation(identifier)
|
77
|
+
# Set relation identifier.
|
78
|
+
#
|
79
|
+
# @example
|
80
|
+
# module CreateUser < ROM::Commands::Create[:memory]
|
81
|
+
# relation :users
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
# @api public
|
85
|
+
defines :relation
|
35
86
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
87
|
+
# @!method self.relation
|
88
|
+
# Get or set result type
|
89
|
+
#
|
90
|
+
# @overload result
|
91
|
+
# Get result type
|
92
|
+
#
|
93
|
+
# @example
|
94
|
+
# module CreateUser < ROM::Commands::Create[:memory]
|
95
|
+
# result :one
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
# CreateUser.result
|
99
|
+
# # => :one
|
100
|
+
#
|
101
|
+
# @return [Symbol]
|
102
|
+
#
|
103
|
+
# @overload relation(identifier)
|
104
|
+
# Set result type
|
105
|
+
#
|
106
|
+
# @example
|
107
|
+
# module CreateUser < ROM::Commands::Create[:memory]
|
108
|
+
# result :one
|
109
|
+
# end
|
110
|
+
#
|
111
|
+
# @api public
|
112
|
+
defines :result
|
42
113
|
|
43
|
-
|
44
|
-
|
45
|
-
|
114
|
+
# @!method self.relation
|
115
|
+
# Get or set input processing function. This is typically set during setup
|
116
|
+
# to relation's input_schema
|
117
|
+
#
|
118
|
+
# @overload input
|
119
|
+
# Get input processing function
|
120
|
+
#
|
121
|
+
# @example
|
122
|
+
# module CreateUser < ROM::Commands::Create[:memory]
|
123
|
+
# input -> tuple { .. }
|
124
|
+
# end
|
125
|
+
#
|
126
|
+
# CreateUser.input
|
127
|
+
# # Your custom function
|
128
|
+
#
|
129
|
+
# @return [Proc,#call]
|
130
|
+
#
|
131
|
+
# @overload input(identifier)
|
132
|
+
# Set input processing function
|
133
|
+
#
|
134
|
+
# @example
|
135
|
+
# module CreateUser < ROM::Commands::Create[:memory]
|
136
|
+
# input -> tuple { .. }
|
137
|
+
# end
|
138
|
+
#
|
139
|
+
# @api public
|
140
|
+
defines :input
|
46
141
|
|
47
|
-
#
|
142
|
+
# @!method self.register_as
|
143
|
+
# Get or set identifier that should be used to register a command in a container
|
144
|
+
#
|
145
|
+
# @overload register_as
|
146
|
+
# Get registration identifier
|
147
|
+
#
|
148
|
+
# @example
|
149
|
+
# module CreateUser < ROM::Commands::Create[:memory]
|
150
|
+
# register_as :create_user
|
151
|
+
# end
|
152
|
+
#
|
153
|
+
# CreateUser.register_as
|
154
|
+
# # => :create_user
|
155
|
+
#
|
156
|
+
# @return [Symbol]
|
157
|
+
#
|
158
|
+
# @overload register_as(identifier)
|
159
|
+
# Set registration identifier
|
160
|
+
#
|
161
|
+
# @example
|
162
|
+
# module CreateUser < ROM::Commands::Create[:memory]
|
163
|
+
# register_as :create_user
|
164
|
+
# end
|
48
165
|
#
|
49
166
|
# @api public
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
167
|
+
defines :register_as
|
168
|
+
|
169
|
+
# @!method self.restrictable
|
170
|
+
# @overload restrictable
|
171
|
+
# Check if a command class is restrictable
|
172
|
+
#
|
173
|
+
# @example
|
174
|
+
# module UpdateUser < ROM::Commands::Update[:memory]
|
175
|
+
# restrictable true
|
176
|
+
# end
|
177
|
+
#
|
178
|
+
# CreateUser.restrictable
|
179
|
+
# # => true
|
180
|
+
#
|
181
|
+
# @return [FalseClass, TrueClass]
|
182
|
+
#
|
183
|
+
# @overload restrictable(value)
|
184
|
+
# Set if a command is restrictable
|
185
|
+
#
|
186
|
+
# @example
|
187
|
+
# module UpdateUser < ROM::Commands::Update[:memory]
|
188
|
+
# restrictable true
|
189
|
+
# end
|
190
|
+
#
|
191
|
+
# @api public
|
192
|
+
defines :restrictable
|
63
193
|
|
64
|
-
#
|
65
|
-
|
194
|
+
# @!attribute [r] relation
|
195
|
+
# @return [Relation] Command's relation
|
196
|
+
param :relation
|
66
197
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
198
|
+
CommandType = Types::Strict::Symbol.enum(:create, :update, :delete)
|
199
|
+
Result = Types::Strict::Symbol.enum(:one, :many)
|
200
|
+
|
201
|
+
# @!attribute [r] type
|
202
|
+
# @return [Symbol] The command type, one of :create, :update or :delete
|
203
|
+
option :type, type: CommandType, optional: true
|
204
|
+
|
205
|
+
# @!attribute [r] source
|
206
|
+
# @return [Relation] The source relation
|
207
|
+
option :source, reader: true, optional: true, default: -> c { c.relation }
|
208
|
+
|
209
|
+
# @!attribute [r] type
|
210
|
+
# @return [Symbol] Result type, either :one or :many
|
211
|
+
option :result, reader: true, type: Result
|
212
|
+
|
213
|
+
# @!attribute [r] input
|
214
|
+
# @return [Proc, #call] Tuple processing function, typically uses Relation#input_schema
|
215
|
+
option :input, reader: true
|
216
|
+
|
217
|
+
# @!attribute [r] curry_args
|
218
|
+
# @return [Array] Curried args
|
219
|
+
option :curry_args, reader: true, default: -> _ { EMPTY_ARRAY }
|
220
|
+
|
221
|
+
# @!attribute [r] before
|
222
|
+
# @return [Array<Hash>] An array with before hooks configuration
|
223
|
+
option :before, Types::Coercible::Array, reader: true, as: :before_hooks, default: proc { EMPTY_ARRAY }
|
224
|
+
|
225
|
+
# @!attribute [r] before
|
226
|
+
# @return [Array<Hash>] An array with after hooks configuration
|
227
|
+
option :after, Types::Coercible::Array, reader: true, as: :after_hooks, default: proc { EMPTY_ARRAY }
|
228
|
+
|
229
|
+
input Hash
|
230
|
+
result :many
|
73
231
|
|
74
232
|
# Return name of this command's relation
|
75
233
|
#
|
@@ -105,9 +263,35 @@ module ROM
|
|
105
263
|
|
106
264
|
# Call the command and return one or many tuples
|
107
265
|
#
|
266
|
+
# This method will apply before/after hooks automatically
|
267
|
+
#
|
108
268
|
# @api public
|
109
269
|
def call(*args, &block)
|
110
|
-
tuples =
|
270
|
+
tuples =
|
271
|
+
if hooks?
|
272
|
+
prepared =
|
273
|
+
if curried?
|
274
|
+
apply_hooks(before_hooks, *(curry_args + args))
|
275
|
+
else
|
276
|
+
apply_hooks(before_hooks, *args)
|
277
|
+
end
|
278
|
+
|
279
|
+
result = prepared ? execute(prepared, &block) : execute(&block)
|
280
|
+
|
281
|
+
if curried?
|
282
|
+
if args.size > 0
|
283
|
+
apply_hooks(after_hooks, result, *args)
|
284
|
+
elsif curry_args.size > 1
|
285
|
+
apply_hooks(after_hooks, result, curry_args[1])
|
286
|
+
else
|
287
|
+
apply_hooks(after_hooks, result)
|
288
|
+
end
|
289
|
+
else
|
290
|
+
apply_hooks(after_hooks, result, *args[1..args.size-1])
|
291
|
+
end
|
292
|
+
else
|
293
|
+
execute(*(curry_args + args), &block)
|
294
|
+
end
|
111
295
|
|
112
296
|
if one?
|
113
297
|
tuples.first
|
@@ -119,9 +303,10 @@ module ROM
|
|
119
303
|
|
120
304
|
# Curry this command with provided args
|
121
305
|
#
|
122
|
-
# Curried command can be called without args
|
306
|
+
# Curried command can be called without args. If argument is a graph input processor,
|
307
|
+
# lazy command will be returned, which is used for handling nested input hashes.
|
123
308
|
#
|
124
|
-
# @return [Command]
|
309
|
+
# @return [Command, Lazy]
|
125
310
|
#
|
126
311
|
# @api public
|
127
312
|
def curry(*args)
|
@@ -133,41 +318,140 @@ module ROM
|
|
133
318
|
end
|
134
319
|
alias_method :with, :curry
|
135
320
|
|
321
|
+
# Compose this command with other commands
|
322
|
+
#
|
323
|
+
# Composed commands can handle nested input
|
324
|
+
#
|
325
|
+
# @return [Command::Graph]
|
326
|
+
#
|
136
327
|
# @api public
|
137
328
|
def combine(*others)
|
138
329
|
Graph.new(self, others)
|
139
330
|
end
|
140
331
|
|
332
|
+
# Check if this command is curried
|
333
|
+
#
|
334
|
+
# @return [TrueClass, FalseClass]
|
335
|
+
#
|
336
|
+
# @api public
|
337
|
+
def curried?
|
338
|
+
curry_args.size > 0
|
339
|
+
end
|
340
|
+
|
341
|
+
# Return a new command with new options
|
342
|
+
#
|
343
|
+
# @param [Hash] new_opts A hash with new options
|
344
|
+
#
|
345
|
+
# @return [Command]
|
346
|
+
#
|
347
|
+
# @api public
|
348
|
+
def with_opts(new_opts)
|
349
|
+
self.class.new(relation, options.merge(new_opts))
|
350
|
+
end
|
351
|
+
|
352
|
+
# Return a new command with appended before hooks
|
353
|
+
#
|
354
|
+
# @param [Array<Hash>] hooks A list of before hooks configurations
|
355
|
+
#
|
356
|
+
# @return [Command]
|
357
|
+
#
|
358
|
+
# @api public
|
359
|
+
def before(*hooks)
|
360
|
+
self.class.new(relation, options.merge(before: before_hooks + hooks))
|
361
|
+
end
|
362
|
+
|
363
|
+
# Return a new command with appended after hooks
|
364
|
+
#
|
365
|
+
# @param [Array<Hash>] hooks A list of after hooks configurations
|
366
|
+
#
|
367
|
+
# @return [Command]
|
368
|
+
#
|
369
|
+
# @api public
|
370
|
+
def after(*hooks)
|
371
|
+
self.class.new(relation, options.merge(after: after_hooks + hooks))
|
372
|
+
end
|
373
|
+
|
374
|
+
# Return a new command with other source relation
|
375
|
+
#
|
376
|
+
# This can be used to restrict command with a specific relation
|
377
|
+
#
|
378
|
+
# @return [Command]
|
379
|
+
#
|
380
|
+
# @api public
|
381
|
+
def new(new_relation)
|
382
|
+
self.class.build(new_relation, options.merge(source: relation))
|
383
|
+
end
|
384
|
+
|
385
|
+
# Check if this command has any hooks
|
386
|
+
#
|
387
|
+
# @api private
|
388
|
+
def hooks?
|
389
|
+
before_hooks.size > 0 || after_hooks.size > 0
|
390
|
+
end
|
391
|
+
|
392
|
+
# Check if this command is lazy
|
393
|
+
#
|
394
|
+
# @return [false]
|
395
|
+
#
|
141
396
|
# @api private
|
142
397
|
def lazy?
|
143
398
|
false
|
144
399
|
end
|
145
400
|
|
401
|
+
# Check if this command is a graph
|
402
|
+
#
|
403
|
+
# @return [false]
|
404
|
+
#
|
146
405
|
# @api private
|
147
406
|
def graph?
|
148
407
|
false
|
149
408
|
end
|
150
409
|
|
410
|
+
# Check if this command returns a single tuple
|
411
|
+
#
|
412
|
+
# @return [TrueClass,FalseClass]
|
413
|
+
#
|
151
414
|
# @api private
|
152
415
|
def one?
|
153
416
|
result.equal?(:one)
|
154
417
|
end
|
155
418
|
|
419
|
+
# Check if this command returns many tuples
|
420
|
+
#
|
421
|
+
# @return [TrueClass,FalseClass]
|
422
|
+
#
|
156
423
|
# @api private
|
157
424
|
def many?
|
158
425
|
result.equal?(:many)
|
159
426
|
end
|
160
427
|
|
161
|
-
# @api private
|
162
|
-
def new(new_relation)
|
163
|
-
self.class.build(new_relation, options.merge(source: relation))
|
164
|
-
end
|
165
|
-
|
166
428
|
private
|
167
429
|
|
430
|
+
# Hook called by Pipeline to get composite class for commands
|
431
|
+
#
|
432
|
+
# @return [Class]
|
433
|
+
#
|
168
434
|
# @api private
|
169
435
|
def composite_class
|
170
436
|
Command::Composite
|
171
437
|
end
|
438
|
+
|
439
|
+
# Apply provided hooks
|
440
|
+
#
|
441
|
+
# Used by #call
|
442
|
+
#
|
443
|
+
# @return [Array<Hash>]
|
444
|
+
#
|
445
|
+
# @api private
|
446
|
+
def apply_hooks(hooks, tuples, *args)
|
447
|
+
hooks.reduce(tuples) do |a, e|
|
448
|
+
if e.is_a?(Hash)
|
449
|
+
hook_meth, hook_args = e.to_a.flatten(1)
|
450
|
+
__send__(hook_meth, a, *args, **hook_args)
|
451
|
+
else
|
452
|
+
__send__(e, a, *args)
|
453
|
+
end
|
454
|
+
end
|
455
|
+
end
|
172
456
|
end
|
173
457
|
end
|
data/lib/rom/command_registry.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'rom/types'
|
1
2
|
require 'rom/commands/result'
|
2
3
|
|
3
4
|
module ROM
|
@@ -5,40 +6,28 @@ module ROM
|
|
5
6
|
#
|
6
7
|
# @api public
|
7
8
|
class CommandRegistry
|
9
|
+
extend Initializer
|
8
10
|
include Commands
|
9
|
-
include Options
|
10
11
|
|
11
12
|
CommandNotFoundError = Class.new(KeyError)
|
13
|
+
RegistryType = Types.Definition(Registry) | Types.Constructor(Registry) { |r| Registry.new(r, self.class.name) }
|
12
14
|
|
13
15
|
# Name of the relation from which commands are under
|
14
16
|
#
|
15
17
|
# @return [String]
|
16
18
|
#
|
17
19
|
# @api private
|
18
|
-
|
20
|
+
param :relation_name
|
19
21
|
|
20
22
|
# Internal command registry
|
21
23
|
#
|
22
24
|
# @return [Registry]
|
23
25
|
#
|
24
26
|
# @api private
|
25
|
-
|
27
|
+
param :registry, type: RegistryType
|
26
28
|
|
27
|
-
option :mappers, reader: true
|
28
|
-
option :mapper, reader: true
|
29
|
-
|
30
|
-
# @api private
|
31
|
-
def initialize(relation_name, elements, options = EMPTY_HASH)
|
32
|
-
super
|
33
|
-
|
34
|
-
@relation_name = relation_name
|
35
|
-
@registry =
|
36
|
-
if elements.is_a?(Registry)
|
37
|
-
elements
|
38
|
-
else
|
39
|
-
Registry.new(elements, self.class.name)
|
40
|
-
end
|
41
|
-
end
|
29
|
+
option :mappers, reader: true, optional: true
|
30
|
+
option :mapper, reader: true, optional: true
|
42
31
|
|
43
32
|
# Try to execute a command in a block
|
44
33
|
#
|
@@ -1,4 +1,5 @@
|
|
1
|
-
require '
|
1
|
+
require 'dry/core/class_builder'
|
2
|
+
require 'dry/core/inflector'
|
2
3
|
|
3
4
|
module ROM
|
4
5
|
# Base command class with factory class-level interface and setup-related logic
|
@@ -6,6 +7,15 @@ module ROM
|
|
6
7
|
# @private
|
7
8
|
class Command
|
8
9
|
module ClassInterface
|
10
|
+
# This hook sets up default class state
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
def inherited(klass)
|
14
|
+
super
|
15
|
+
klass.instance_variable_set(:'@before', before ? before.dup : [])
|
16
|
+
klass.instance_variable_set(:'@after', before ? after.dup : [])
|
17
|
+
end
|
18
|
+
|
9
19
|
# Return adapter specific sub-class based on the adapter identifier
|
10
20
|
#
|
11
21
|
# This is a syntax sugar to make things consistent
|
@@ -20,7 +30,7 @@ module ROM
|
|
20
30
|
#
|
21
31
|
# @api public
|
22
32
|
def [](adapter)
|
23
|
-
adapter_namespace(adapter).const_get(Inflector.demodulize(name))
|
33
|
+
adapter_namespace(adapter).const_get(Dry::Core::Inflector.demodulize(name))
|
24
34
|
end
|
25
35
|
|
26
36
|
# Return namespaces that contains command subclasses of a specific adapter
|
@@ -65,8 +75,8 @@ module ROM
|
|
65
75
|
#
|
66
76
|
# @api public
|
67
77
|
def create_class(name, type, &block)
|
68
|
-
klass = ClassBuilder
|
69
|
-
.new(name: "#{Inflector.classify(type)}[:#{name}]", parent: type)
|
78
|
+
klass = Dry::Core::ClassBuilder
|
79
|
+
.new(name: "#{Dry::Core::Inflector.classify(type)}[:#{name}]", parent: type)
|
70
80
|
.call
|
71
81
|
|
72
82
|
if block
|
@@ -105,6 +115,110 @@ module ROM
|
|
105
115
|
include(relation_methods_mod(relation.class))
|
106
116
|
end
|
107
117
|
|
118
|
+
# Set before-execute hooks
|
119
|
+
#
|
120
|
+
# @overload before(hook)
|
121
|
+
# Set an before hook as a method name
|
122
|
+
#
|
123
|
+
# @example
|
124
|
+
# class CreateUser < ROM::Commands::Create[:sql]
|
125
|
+
# relation :users
|
126
|
+
# register_as :create
|
127
|
+
#
|
128
|
+
# before :my_hook
|
129
|
+
#
|
130
|
+
# def my_hook(tuple, *)
|
131
|
+
# puts "hook called#
|
132
|
+
# end
|
133
|
+
# end
|
134
|
+
#
|
135
|
+
# @overload before(hook_opts)
|
136
|
+
# Set an before hook as a method name with arguments
|
137
|
+
#
|
138
|
+
# @example
|
139
|
+
# class CreateUser < ROM::Commands::Create[:sql]
|
140
|
+
# relation :users
|
141
|
+
# register_as :create
|
142
|
+
#
|
143
|
+
# before my_hook: { arg1: 1, arg1: 2 }
|
144
|
+
#
|
145
|
+
# def my_hook(tuple, arg1:, arg2:)
|
146
|
+
# puts "hook called with args: #{arg1} and #{arg2}"
|
147
|
+
# end
|
148
|
+
# end
|
149
|
+
#
|
150
|
+
# @param [Hash<Symbol=>Hash>] hook Options with method name and pre-set args
|
151
|
+
#
|
152
|
+
# @return [Array<Hash, Symbol>] A list of all configured before hooks
|
153
|
+
#
|
154
|
+
# @api public
|
155
|
+
def before(*hooks)
|
156
|
+
if hooks.size > 0
|
157
|
+
set_hooks(:before, hooks)
|
158
|
+
else
|
159
|
+
@before
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# Set after-execute hooks
|
164
|
+
#
|
165
|
+
# @overload after(hook)
|
166
|
+
# Set an after hook as a method name
|
167
|
+
#
|
168
|
+
# @example
|
169
|
+
# class CreateUser < ROM::Commands::Create[:sql]
|
170
|
+
# relation :users
|
171
|
+
# register_as :create
|
172
|
+
#
|
173
|
+
# after :my_hook
|
174
|
+
#
|
175
|
+
# def my_hook(tuple, *)
|
176
|
+
# puts "hook called#
|
177
|
+
# end
|
178
|
+
# end
|
179
|
+
#
|
180
|
+
# @overload after(hook_opts)
|
181
|
+
# Set an after hook as a method name with arguments
|
182
|
+
#
|
183
|
+
# @example
|
184
|
+
# class CreateUser < ROM::Commands::Create[:sql]
|
185
|
+
# relation :users
|
186
|
+
# register_as :create
|
187
|
+
#
|
188
|
+
# after my_hook: { arg1: 1, arg1: 2 }
|
189
|
+
#
|
190
|
+
# def my_hook(tuple, arg1:, arg2:)
|
191
|
+
# puts "hook called with args: #{arg1} and #{arg2}"
|
192
|
+
# end
|
193
|
+
# end
|
194
|
+
#
|
195
|
+
# @param [Hash<Symbol=>Hash>] hook Options with method name and pre-set args
|
196
|
+
#
|
197
|
+
# @return [Array<Hash, Symbol>] A list of all configured after hooks
|
198
|
+
#
|
199
|
+
# @api public
|
200
|
+
def after(*hooks)
|
201
|
+
if hooks.size > 0
|
202
|
+
set_hooks(:after, hooks)
|
203
|
+
else
|
204
|
+
@after
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Set new or more hooks
|
209
|
+
#
|
210
|
+
# @api private
|
211
|
+
def set_hooks(type, hooks)
|
212
|
+
ivar = :"@#{type}"
|
213
|
+
value = instance_variable_get(ivar)
|
214
|
+
|
215
|
+
if value.empty?
|
216
|
+
instance_variable_set(ivar, hooks)
|
217
|
+
else
|
218
|
+
value.concat(hooks)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
108
222
|
# Return default name of the command class based on its name
|
109
223
|
#
|
110
224
|
# During setup phase this is used by defalut as `register_as` option
|
@@ -113,7 +227,7 @@ module ROM
|
|
113
227
|
#
|
114
228
|
# @api private
|
115
229
|
def default_name
|
116
|
-
Inflector.underscore(Inflector.demodulize(name)).to_sym
|
230
|
+
Dry::Core::Inflector.underscore(Dry::Core::Inflector.demodulize(name)).to_sym
|
117
231
|
end
|
118
232
|
|
119
233
|
# Return default options based on class macros
|
@@ -122,7 +236,7 @@ module ROM
|
|
122
236
|
#
|
123
237
|
# @api private
|
124
238
|
def options
|
125
|
-
{ input: input,
|
239
|
+
{ input: input, result: result, before: before, after: after }
|
126
240
|
end
|
127
241
|
|
128
242
|
# @api private
|