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