rom-core 4.0.0.beta2 → 4.0.0.beta3
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/CHANGELOG.md +2 -1
- data/lib/rom/attribute.rb +427 -0
- data/lib/rom/auto_curry.rb +1 -1
- data/lib/rom/command.rb +9 -0
- data/lib/rom/command_proxy.rb +10 -2
- data/lib/rom/constants.rb +8 -0
- data/lib/rom/core.rb +0 -2
- data/lib/rom/gateway.rb +0 -11
- data/lib/rom/plugins/command/schema.rb +2 -4
- data/lib/rom/relation/class_interface.rb +13 -2
- data/lib/rom/relation/combined.rb +10 -4
- data/lib/rom/relation/commands.rb +28 -8
- data/lib/rom/relation/composite.rb +1 -3
- data/lib/rom/relation/curried.rb +10 -14
- data/lib/rom/relation/graph.rb +8 -0
- data/lib/rom/relation/materializable.rb +0 -7
- data/lib/rom/relation/name.rb +2 -2
- data/lib/rom/relation/wrap.rb +8 -27
- data/lib/rom/relation.rb +78 -15
- data/lib/rom/schema/dsl.rb +4 -2
- data/lib/rom/schema/inferrer.rb +4 -1
- data/lib/rom/schema.rb +13 -12
- data/lib/rom/setup/finalize/finalize_mappers.rb +5 -4
- data/lib/rom/setup/finalize/finalize_relations.rb +7 -10
- data/lib/rom/support/notifications.rb +92 -0
- data/lib/rom/version.rb +1 -1
- metadata +10 -5
- data/lib/rom/plugins/configuration/configuration_dsl.rb +0 -21
- data/lib/rom/schema/attribute.rb +0 -419
data/lib/rom/relation/curried.rb
CHANGED
@@ -20,7 +20,7 @@ module ROM
|
|
20
20
|
param :relation
|
21
21
|
|
22
22
|
option :view, type: Types::Strict::Symbol
|
23
|
-
option :arity, type: Types::Strict::Int
|
23
|
+
option :arity, type: Types::Strict::Int
|
24
24
|
option :curry_args, default: -> { EMPTY_ARRAY }
|
25
25
|
|
26
26
|
# Load relation if args match the arity
|
@@ -29,22 +29,18 @@ module ROM
|
|
29
29
|
#
|
30
30
|
# @api public
|
31
31
|
def call(*args)
|
32
|
-
|
33
|
-
all_args = curry_args + args
|
32
|
+
all_args = curry_args + args
|
34
33
|
|
35
|
-
|
36
|
-
|
37
|
-
|
34
|
+
if all_args.empty?
|
35
|
+
raise ArgumentError, "curried #{relation.class}##{view} relation was called without any arguments"
|
36
|
+
end
|
38
37
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
else
|
44
|
-
__new__(relation, curry_args: all_args)
|
45
|
-
end
|
38
|
+
if args.empty?
|
39
|
+
self
|
40
|
+
elsif arity == all_args.size
|
41
|
+
Loaded.new(relation.__send__(view, *all_args))
|
46
42
|
else
|
47
|
-
|
43
|
+
__new__(relation, curry_args: all_args)
|
48
44
|
end
|
49
45
|
end
|
50
46
|
alias_method :[], :call
|
data/lib/rom/relation/graph.rb
CHANGED
@@ -6,6 +6,7 @@ require 'rom/relation/loaded'
|
|
6
6
|
require 'rom/relation/composite'
|
7
7
|
require 'rom/relation/materializable'
|
8
8
|
require 'rom/pipeline'
|
9
|
+
require 'rom/support/memoizable'
|
9
10
|
|
10
11
|
module ROM
|
11
12
|
class Relation
|
@@ -15,6 +16,8 @@ module ROM
|
|
15
16
|
class Graph
|
16
17
|
extend Initializer
|
17
18
|
|
19
|
+
include Memoizable
|
20
|
+
|
18
21
|
param :root
|
19
22
|
|
20
23
|
param :nodes
|
@@ -70,6 +73,11 @@ module ROM
|
|
70
73
|
mappers[to_ast]
|
71
74
|
end
|
72
75
|
|
76
|
+
# @api private
|
77
|
+
memoize def to_ast
|
78
|
+
[:relation, [name.relation, attr_ast + nodes.map(&:to_ast), meta_ast]]
|
79
|
+
end
|
80
|
+
|
73
81
|
private
|
74
82
|
|
75
83
|
# @api private
|
data/lib/rom/relation/name.rb
CHANGED
@@ -71,7 +71,7 @@ module ROM
|
|
71
71
|
|
72
72
|
# @api private
|
73
73
|
def aliased?
|
74
|
-
|
74
|
+
aliaz && aliaz != relation
|
75
75
|
end
|
76
76
|
|
77
77
|
# Return relation name
|
@@ -80,7 +80,7 @@ module ROM
|
|
80
80
|
#
|
81
81
|
# @api private
|
82
82
|
def to_s
|
83
|
-
if
|
83
|
+
if aliased?
|
84
84
|
"#{relation} on #{dataset} as #{aliaz}"
|
85
85
|
elsif relation == dataset
|
86
86
|
relation.to_s
|
data/lib/rom/relation/wrap.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'rom/relation/graph'
|
2
|
+
require 'rom/relation/combined'
|
2
3
|
|
3
4
|
module ROM
|
4
5
|
class Relation
|
@@ -6,18 +7,6 @@ module ROM
|
|
6
7
|
#
|
7
8
|
# @api public
|
8
9
|
class Wrap < Graph
|
9
|
-
extend Initializer
|
10
|
-
|
11
|
-
include Materializable
|
12
|
-
include Pipeline
|
13
|
-
include Pipeline::Proxy
|
14
|
-
|
15
|
-
param :root
|
16
|
-
param :nodes
|
17
|
-
|
18
|
-
alias_method :left, :root
|
19
|
-
alias_method :right, :nodes
|
20
|
-
|
21
10
|
# @api public
|
22
11
|
def wrap(*args)
|
23
12
|
self.class.new(root, nodes + root.wrap(*args).nodes)
|
@@ -39,21 +28,6 @@ module ROM
|
|
39
28
|
raise NotImplementedError
|
40
29
|
end
|
41
30
|
|
42
|
-
# @api private
|
43
|
-
def to_ast
|
44
|
-
@__ast__ ||= [:relation, [name.relation, attr_ast + nodes_ast, meta_ast]]
|
45
|
-
end
|
46
|
-
|
47
|
-
# @api private
|
48
|
-
def attr_ast
|
49
|
-
root.attr_ast
|
50
|
-
end
|
51
|
-
|
52
|
-
# @api private
|
53
|
-
def nodes_ast
|
54
|
-
nodes.map(&:to_ast)
|
55
|
-
end
|
56
|
-
|
57
31
|
# Return if this is a wrap relation
|
58
32
|
#
|
59
33
|
# @return [true]
|
@@ -62,6 +36,13 @@ module ROM
|
|
62
36
|
def wrap?
|
63
37
|
true
|
64
38
|
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# @api private
|
43
|
+
def decorate?(other)
|
44
|
+
super || other.is_a?(Combined)
|
45
|
+
end
|
65
46
|
end
|
66
47
|
end
|
67
48
|
end
|
data/lib/rom/relation.rb
CHANGED
@@ -14,6 +14,7 @@ require 'rom/command_registry'
|
|
14
14
|
|
15
15
|
require 'rom/relation/loaded'
|
16
16
|
require 'rom/relation/curried'
|
17
|
+
require 'rom/relation/commands'
|
17
18
|
require 'rom/relation/composite'
|
18
19
|
require 'rom/relation/combined'
|
19
20
|
require 'rom/relation/wrap'
|
@@ -55,9 +56,69 @@ module ROM
|
|
55
56
|
|
56
57
|
extend Dry::Core::ClassAttributes
|
57
58
|
|
58
|
-
defines :adapter, :
|
59
|
+
defines :adapter, :schema_opts, :schema_class,
|
59
60
|
:schema_attr_class, :schema_inferrer, :schema_dsl,
|
60
|
-
:wrap_class
|
61
|
+
:wrap_class
|
62
|
+
|
63
|
+
# @!method self.gateway
|
64
|
+
# Manage the gateway
|
65
|
+
#
|
66
|
+
# @overload gateway
|
67
|
+
# Return the gateway key that the relation is associated with
|
68
|
+
# @return [Symbol]
|
69
|
+
#
|
70
|
+
# @overload gateway(gateway_key)
|
71
|
+
# Link the relation to a gateway. Change this setting if the
|
72
|
+
# relation is defined on a non-default gateway
|
73
|
+
#
|
74
|
+
# @example
|
75
|
+
# class Users < ROM::Relation[:sql]
|
76
|
+
# gateway :custom
|
77
|
+
# end
|
78
|
+
#
|
79
|
+
# @param [Symbol] gateway_key
|
80
|
+
defines :gateway
|
81
|
+
|
82
|
+
# @!method self.auto_map
|
83
|
+
# Whether or not a relation and its compositions should be auto-mapped
|
84
|
+
#
|
85
|
+
# @overload auto_map
|
86
|
+
# Return auto_map setting value
|
87
|
+
# @return [Boolean]
|
88
|
+
#
|
89
|
+
# @overload auto_map(value)
|
90
|
+
# Set auto_map value
|
91
|
+
defines :auto_map
|
92
|
+
|
93
|
+
# @!method self.auto_struct
|
94
|
+
# Whether or not tuples should be auto-mapped to structs
|
95
|
+
#
|
96
|
+
# @overload auto_struct
|
97
|
+
# Return auto_struct setting value
|
98
|
+
# @return [Boolean]
|
99
|
+
#
|
100
|
+
# @overload auto_struct(value)
|
101
|
+
# Set auto_struct value
|
102
|
+
defines :auto_struct
|
103
|
+
|
104
|
+
# @!method self.struct_namespace
|
105
|
+
# Get or set a namespace for auto-generated struct classes.
|
106
|
+
# By default, new struct classes are created within ROM::Struct
|
107
|
+
#
|
108
|
+
# @example using custom namespace
|
109
|
+
# class Users < ROM::Relation[:sql]
|
110
|
+
# struct_namespace Entities
|
111
|
+
# end
|
112
|
+
#
|
113
|
+
# users.by_pk(1).one! # => #<Entities::User id=1 name="Jane Doe">
|
114
|
+
#
|
115
|
+
# @overload struct_namespace
|
116
|
+
# @return [Module] Default struct namespace
|
117
|
+
#
|
118
|
+
# @overload struct_namespace(namespace)
|
119
|
+
# @param [Module] namespace
|
120
|
+
#
|
121
|
+
defines :struct_namespace
|
61
122
|
|
62
123
|
gateway :default
|
63
124
|
|
@@ -67,7 +128,7 @@ module ROM
|
|
67
128
|
|
68
129
|
schema_opts EMPTY_HASH
|
69
130
|
schema_dsl Schema::DSL
|
70
|
-
schema_attr_class
|
131
|
+
schema_attr_class Attribute
|
71
132
|
schema_class Schema
|
72
133
|
schema_inferrer Schema::DEFAULT_INFERRER
|
73
134
|
|
@@ -109,12 +170,12 @@ module ROM
|
|
109
170
|
# @!attribute [r] auto_map
|
110
171
|
# @return [TrueClass,FalseClass] Whether or not a relation and its compositions should be auto-mapped
|
111
172
|
# @api private
|
112
|
-
option :auto_map,
|
173
|
+
option :auto_map, default: -> { self.class.auto_map }
|
113
174
|
|
114
175
|
# @!attribute [r] auto_struct
|
115
176
|
# @return [TrueClass,FalseClass] Whether or not tuples should be auto-mapped to structs
|
116
177
|
# @api private
|
117
|
-
option :auto_struct,
|
178
|
+
option :auto_struct, default: -> { self.class.auto_struct }
|
118
179
|
|
119
180
|
# @!attribute [r] struct_namespace
|
120
181
|
# @return [Module] Custom struct namespace
|
@@ -146,7 +207,7 @@ module ROM
|
|
146
207
|
# tasks_with_users[:title, :tasks]
|
147
208
|
# # => #<ROM::SQL::Attribute[String] primary_key=false name=:title source=ROM::Relation::Name(tasks)>
|
148
209
|
#
|
149
|
-
# @return [
|
210
|
+
# @return [Attribute]
|
150
211
|
#
|
151
212
|
# @api public
|
152
213
|
def [](name)
|
@@ -176,7 +237,7 @@ module ROM
|
|
176
237
|
#
|
177
238
|
# @overload combine(*associations)
|
178
239
|
# Composes relations using configured associations
|
179
|
-
|
240
|
+
#
|
180
241
|
# @example
|
181
242
|
# users.combine(:tasks, :posts)
|
182
243
|
# @param *associations [Array<Symbol>] A list of association names
|
@@ -334,17 +395,19 @@ module ROM
|
|
334
395
|
#
|
335
396
|
# @api public
|
336
397
|
def new(dataset, new_opts = EMPTY_HASH)
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
398
|
+
opts =
|
399
|
+
if new_opts.empty?
|
400
|
+
options
|
401
|
+
elsif new_opts.key?(:schema)
|
402
|
+
options.merge(new_opts).reject { |k, _| k == :input_schema || k == :output_schema }
|
403
|
+
else
|
404
|
+
options.merge(new_opts)
|
405
|
+
end
|
344
406
|
|
345
407
|
self.class.new(dataset, opts)
|
346
408
|
end
|
347
409
|
|
410
|
+
undef_method :with
|
348
411
|
# Returns a new instance with the same dataset but new options
|
349
412
|
#
|
350
413
|
# @example
|
@@ -417,7 +480,7 @@ module ROM
|
|
417
480
|
# Map tuples to the provided custom model class
|
418
481
|
#
|
419
482
|
# @example
|
420
|
-
# users.
|
483
|
+
# users.map_with(MyUserModel)
|
421
484
|
#
|
422
485
|
# @param [Class>] model Your custom model class
|
423
486
|
#
|
data/lib/rom/schema/dsl.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'dry/equalizer'
|
2
2
|
|
3
3
|
require 'rom/types'
|
4
|
-
require 'rom/
|
4
|
+
require 'rom/attribute'
|
5
5
|
require 'rom/schema/associations_dsl'
|
6
6
|
|
7
7
|
module ROM
|
@@ -45,7 +45,7 @@ module ROM
|
|
45
45
|
# @api public
|
46
46
|
def attribute(name, type, options = EMPTY_HASH)
|
47
47
|
if attributes.key?(name)
|
48
|
-
::Kernel.raise ::ROM::
|
48
|
+
::Kernel.raise ::ROM::AttributeAlreadyDefinedError,
|
49
49
|
"Attribute #{ name.inspect } already defined"
|
50
50
|
end
|
51
51
|
|
@@ -93,6 +93,8 @@ module ROM
|
|
93
93
|
def build_type(name, type, options = EMPTY_HASH)
|
94
94
|
if options[:read]
|
95
95
|
type.meta(name: name, source: relation, read: options[:read])
|
96
|
+
elsif type.optional? && !type.meta[:read] && type.right.meta[:read]
|
97
|
+
type.meta(name: name, source: relation, read: type.right.meta[:read].optional)
|
96
98
|
else
|
97
99
|
type.meta(name: name, source: relation)
|
98
100
|
end
|
data/lib/rom/schema/inferrer.rb
CHANGED
@@ -11,7 +11,10 @@ module ROM
|
|
11
11
|
|
12
12
|
MissingAttributesError = Class.new(StandardError) do
|
13
13
|
def initialize(name, attributes)
|
14
|
-
super(
|
14
|
+
super(
|
15
|
+
"Following attributes in #{Relation::Name[name].relation.inspect} schema cannot "\
|
16
|
+
"be inferred and have to be defined explicitly: #{attributes.map(&:inspect).join(', ')}"
|
17
|
+
)
|
15
18
|
end
|
16
19
|
end
|
17
20
|
|
data/lib/rom/schema.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'dry/equalizer'
|
2
2
|
|
3
|
-
require 'rom/
|
3
|
+
require 'rom/constants'
|
4
|
+
require 'rom/attribute'
|
4
5
|
require 'rom/schema/dsl'
|
5
6
|
require 'rom/schema/inferrer'
|
6
7
|
require 'rom/association_set'
|
@@ -39,8 +40,10 @@ module ROM
|
|
39
40
|
registry = event[:registry]
|
40
41
|
|
41
42
|
registry.each do |_, relation|
|
42
|
-
relation.schema.
|
43
|
-
|
43
|
+
unless relation.schema.frozen?
|
44
|
+
relation.schema.finalize_associations!(relations: registry)
|
45
|
+
relation.schema.finalize!
|
46
|
+
end
|
44
47
|
end
|
45
48
|
end
|
46
49
|
|
@@ -58,8 +61,6 @@ module ROM
|
|
58
61
|
|
59
62
|
DEFAULT_INFERRER = Inferrer.new(enabled: false).freeze
|
60
63
|
|
61
|
-
AttributeAlreadyDefinedError = Class.new(StandardError)
|
62
|
-
|
63
64
|
extend Initializer
|
64
65
|
|
65
66
|
include Dry::Equalizer(:name, :attributes, :associations)
|
@@ -101,7 +102,7 @@ module ROM
|
|
101
102
|
# Define a relation schema from plain rom types
|
102
103
|
#
|
103
104
|
# Resulting schema will decorate plain rom types with adapter-specific types
|
104
|
-
# By default `
|
105
|
+
# By default `Attribute` will be used
|
105
106
|
#
|
106
107
|
# @param [Relation::Name, Symbol] name The schema name, typically ROM::Relation::Name
|
107
108
|
#
|
@@ -147,7 +148,7 @@ module ROM
|
|
147
148
|
|
148
149
|
# Iterate over schema's attributes
|
149
150
|
#
|
150
|
-
# @yield [
|
151
|
+
# @yield [Attribute]
|
151
152
|
#
|
152
153
|
# @api public
|
153
154
|
def each(&block)
|
@@ -197,7 +198,7 @@ module ROM
|
|
197
198
|
|
198
199
|
# Project a schema to include only specified attributes
|
199
200
|
#
|
200
|
-
# @param [*Array<Symbol,
|
201
|
+
# @param [*Array<Symbol, Attribute>] names Attribute names
|
201
202
|
#
|
202
203
|
# @return [Schema]
|
203
204
|
#
|
@@ -260,7 +261,7 @@ module ROM
|
|
260
261
|
|
261
262
|
# Return FK attribute for a given relation name
|
262
263
|
#
|
263
|
-
# @return [
|
264
|
+
# @return [Attribute]
|
264
265
|
#
|
265
266
|
# @api public
|
266
267
|
def foreign_key(relation)
|
@@ -269,7 +270,7 @@ module ROM
|
|
269
270
|
|
270
271
|
# Return primary key attributes
|
271
272
|
#
|
272
|
-
# @return [Array<
|
273
|
+
# @return [Array<Attribute>]
|
273
274
|
#
|
274
275
|
# @api public
|
275
276
|
def primary_key
|
@@ -292,7 +293,7 @@ module ROM
|
|
292
293
|
#
|
293
294
|
# This returns a new schema instance
|
294
295
|
#
|
295
|
-
# @param [*Array<
|
296
|
+
# @param [*Array<Attribute>]
|
296
297
|
#
|
297
298
|
# @return [Schema]
|
298
299
|
#
|
@@ -303,7 +304,7 @@ module ROM
|
|
303
304
|
|
304
305
|
# Return a new schema with uniq attributes
|
305
306
|
#
|
306
|
-
# @param [*Array<
|
307
|
+
# @param [*Array<Attribute>]
|
307
308
|
#
|
308
309
|
# @return [Schema]
|
309
310
|
#
|
@@ -36,13 +36,14 @@ module ROM
|
|
36
36
|
private
|
37
37
|
|
38
38
|
def check_duplicate_registered_mappers
|
39
|
-
|
40
|
-
|
39
|
+
mapper_relation_register = mapper_classes.map {|mapper_class| [mapper_class.relation, mapper_class.register_as].compact }
|
40
|
+
return if mapper_relation_register.uniq.count == mapper_classes.count
|
41
|
+
mapper_relation_register.select { |relation_register_as| mapper_relation_register.count(relation_register_as) > 1 }
|
41
42
|
.uniq
|
42
43
|
.each do |duplicated_mappers|
|
43
44
|
raise MapperAlreadyDefinedError,
|
44
|
-
"Mapper with `register_as #{duplicated_mappers.inspect}` registered more " \
|
45
|
-
"than once"
|
45
|
+
"Mapper with `register_as #{duplicated_mappers.last.inspect}` registered more " \
|
46
|
+
"than once for relation #{duplicated_mappers.first.inspect}"
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
@@ -71,19 +71,17 @@ module ROM
|
|
71
71
|
# where klass' gateway points to non-existant repo
|
72
72
|
gateway = @gateways.fetch(klass.gateway)
|
73
73
|
|
74
|
-
|
75
|
-
plugins = schema_plugins
|
74
|
+
plugins = schema_plugins
|
76
75
|
|
77
|
-
|
78
|
-
|
79
|
-
end
|
80
|
-
|
81
|
-
klass.set_schema!(resolved_schema)
|
76
|
+
schema = klass.schema_proc.call do
|
77
|
+
plugins.each { |plugin| app_plugin(plugin) }
|
82
78
|
end
|
83
79
|
|
80
|
+
klass.set_schema!(schema) if klass.schema.nil?
|
81
|
+
|
84
82
|
notifications.trigger(
|
85
83
|
'configuration.relations.schema.allocated',
|
86
|
-
schema:
|
84
|
+
schema: schema, gateway: gateway, registry: registry
|
87
85
|
)
|
88
86
|
|
89
87
|
relation_plugins.each do |plugin|
|
@@ -92,10 +90,9 @@ module ROM
|
|
92
90
|
|
93
91
|
notifications.trigger(
|
94
92
|
'configuration.relations.schema.set',
|
95
|
-
schema:
|
93
|
+
schema: schema, relation: klass, adapter: klass.adapter
|
96
94
|
)
|
97
95
|
|
98
|
-
schema = klass.schema
|
99
96
|
rel_key = schema.name.to_sym
|
100
97
|
dataset = gateway.dataset(schema.name.dataset).instance_exec(klass, &klass.dataset)
|
101
98
|
|
@@ -3,16 +3,61 @@ require 'dry/equalizer'
|
|
3
3
|
require 'rom/constants'
|
4
4
|
|
5
5
|
module ROM
|
6
|
+
# Notification subsystem
|
7
|
+
#
|
8
|
+
# This is an abstract event bus that implements a simple pub/sub protocol.
|
9
|
+
# The Notifications module is used in the setup process to decouple
|
10
|
+
# different modules from each other.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# class Setup
|
14
|
+
# extend ROM::Notifications
|
15
|
+
#
|
16
|
+
# register_event('setup.before_setup')
|
17
|
+
# register_event('setup.after_setup')
|
18
|
+
#
|
19
|
+
# def initialize
|
20
|
+
# @bus = Notifications.event_bus(:setup)
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# def setup
|
24
|
+
# @bus.trigger('setup.before_setup', at: Time.now)
|
25
|
+
# # ...
|
26
|
+
# @bus.trigger('setup.after_setup', at: Time.now)
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# class Plugin
|
31
|
+
# extend ROM::Notifications::Listener
|
32
|
+
#
|
33
|
+
# subscribe('setup.after_setup') do |event|
|
34
|
+
# puts "Loaded at #{event.at.iso8601}"
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
#
|
6
38
|
module Notifications
|
7
39
|
LISTENERS_HASH = Hash.new { |h, k| h[k] = [] }
|
8
40
|
|
9
41
|
module Publisher
|
42
|
+
# Subscribe to events.
|
43
|
+
# If the query parameter is provided, filters events by payload.
|
44
|
+
#
|
45
|
+
# @param [String] event_id The event key
|
46
|
+
# @param [Hash] query An optional event filter
|
47
|
+
# @yield [block] The callback
|
48
|
+
# @return [Object] self
|
49
|
+
#
|
10
50
|
# @api public
|
11
51
|
def subscribe(event_id, query = EMPTY_HASH, &block)
|
12
52
|
listeners[event_id] << [block, query]
|
13
53
|
self
|
14
54
|
end
|
15
55
|
|
56
|
+
# Trigger an event
|
57
|
+
#
|
58
|
+
# @param [String] event_id The event key
|
59
|
+
# @param [Hash] payload An optional payload
|
60
|
+
#
|
16
61
|
# @api public
|
17
62
|
def trigger(event_id, payload = EMPTY_HASH)
|
18
63
|
event = events[event_id]
|
@@ -23,20 +68,40 @@ module ROM
|
|
23
68
|
end
|
24
69
|
end
|
25
70
|
|
71
|
+
# Event object
|
72
|
+
#
|
73
|
+
# @api public
|
26
74
|
class Event
|
27
75
|
include Dry::Equalizer(:id, :payload)
|
28
76
|
|
77
|
+
# @attr_reader [String] id Event ID
|
29
78
|
attr_reader :id
|
30
79
|
|
80
|
+
# @api public
|
31
81
|
def initialize(id, payload = EMPTY_HASH)
|
32
82
|
@id = id
|
33
83
|
@payload = payload
|
34
84
|
end
|
35
85
|
|
86
|
+
# Get data from the payload
|
87
|
+
#
|
88
|
+
# @param [String,Symbol] name
|
89
|
+
#
|
90
|
+
# @api public
|
36
91
|
def [](name)
|
37
92
|
@payload.fetch(name)
|
38
93
|
end
|
39
94
|
|
95
|
+
# Get or set a payload
|
96
|
+
#
|
97
|
+
# @overload
|
98
|
+
# @return [Hash] payload
|
99
|
+
#
|
100
|
+
# @overload payload(data)
|
101
|
+
# @param [Hash] data A new payload
|
102
|
+
# @return [Event] A copy of the event with the provided payload
|
103
|
+
#
|
104
|
+
# @api public
|
40
105
|
def payload(data = nil)
|
41
106
|
if data
|
42
107
|
self.class.new(id, @payload.merge(data))
|
@@ -45,10 +110,17 @@ module ROM
|
|
45
110
|
end
|
46
111
|
end
|
47
112
|
|
113
|
+
# Trigger the event
|
114
|
+
#
|
115
|
+
# @param [#call] listener
|
116
|
+
# @param [Hash] query
|
117
|
+
#
|
118
|
+
# @api private
|
48
119
|
def trigger(listener, query = EMPTY_HASH)
|
49
120
|
listener.(self) if trigger?(query)
|
50
121
|
end
|
51
122
|
|
123
|
+
# @api private
|
52
124
|
def trigger?(query)
|
53
125
|
query.empty? || query.all? { |key, value| @payload[key] == value }
|
54
126
|
end
|
@@ -56,6 +128,11 @@ module ROM
|
|
56
128
|
|
57
129
|
extend Publisher
|
58
130
|
|
131
|
+
# Register an event
|
132
|
+
#
|
133
|
+
# @param [String] id A unique event key
|
134
|
+
# @param [Hash] info
|
135
|
+
#
|
59
136
|
# @api public
|
60
137
|
def register_event(id, info = EMPTY_HASH)
|
61
138
|
Notifications.events[id] = Event.new(id, info)
|
@@ -71,6 +148,11 @@ module ROM
|
|
71
148
|
@__listeners__ ||= LISTENERS_HASH.dup
|
72
149
|
end
|
73
150
|
|
151
|
+
# Build an event bus
|
152
|
+
#
|
153
|
+
# @param [Symbol] id Bus key
|
154
|
+
# @return [Notifications::EventBus] A new bus
|
155
|
+
#
|
74
156
|
# @api public
|
75
157
|
def self.event_bus(id)
|
76
158
|
EventBus.new(id, events: events.dup, listeners: listeners.dup)
|
@@ -78,12 +160,22 @@ module ROM
|
|
78
160
|
|
79
161
|
# @api public
|
80
162
|
module Listener
|
163
|
+
# Subscribe to events
|
164
|
+
#
|
165
|
+
# @param [String] event_id The event key
|
166
|
+
# @param [Hash] query An optional event filter
|
167
|
+
# @return [Object] self
|
168
|
+
#
|
81
169
|
# @api public
|
82
170
|
def subscribe(event_id, query = EMPTY_HASH, &block)
|
83
171
|
Notifications.listeners[event_id] << [block, query]
|
84
172
|
end
|
85
173
|
end
|
86
174
|
|
175
|
+
# Event bus
|
176
|
+
#
|
177
|
+
# An event bus stores listeners (callbacks) and events
|
178
|
+
#
|
87
179
|
# @api public
|
88
180
|
class EventBus
|
89
181
|
include Publisher
|
data/lib/rom/version.rb
CHANGED