Skip to content

Commit 2bfbb10

Browse files
committed
Refactor optimized relation reader
1 parent 520bc19 commit 2bfbb10

File tree

10 files changed

+76
-68
lines changed

10 files changed

+76
-68
lines changed

core/lib/rom/cache.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def inspect
4646

4747
# @api private
4848
def initialize
49-
@objects = Concurrent::Map.new
49+
@objects = ::Concurrent::Map.new
5050
@namespaced = {}
5151
end
5252

core/lib/rom/container.rb

+10
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,16 @@ def self.new(gateways, relations, mappers, commands)
110110
end
111111
end
112112

113+
# @api private
114+
attr_reader :cache
115+
116+
# @api private
117+
def initialize
118+
super
119+
120+
@cache = Cache.new
121+
end
122+
113123
# Return registered gateways
114124
#
115125
# @return [Hash<Symbol=>Gateway>]

core/lib/rom/plugins/relation/registry_reader.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ class RegistryReader < ::Module
1414
EMPTY_REGISTRY = RelationRegistry.build(EMPTY_HASH).freeze
1515

1616
# @api private
17-
def initialize(klass:, relation_readers_module:)
17+
def initialize(readers:)
1818
super()
19-
klass.include relation_readers_module
19+
include readers
2020
end
2121

2222
# @api private

core/lib/rom/setup/finalize/finalize_relations.rb

+8-10
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,12 @@ class Finalize
99
class FinalizeRelations
1010
attr_reader :notifications
1111

12-
module BuildRelationReaders
13-
def self.build(relations)
14-
Module.new do
15-
relations.each do |name|
16-
define_method(name) do
17-
__registry__[name]
18-
end
19-
end
12+
class RegistryReaders < ::Module
13+
def initialize(relations)
14+
super()
15+
16+
relations.each do |name|
17+
define_method(name) { __registry__[name] }
2018
end
2119
end
2220
end
@@ -44,7 +42,7 @@ def initialize(gateways, relation_classes, notifications:, mappers: nil, plugins
4442
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
4543
def run!
4644
relation_registry = RelationRegistry.new do |registry, relations|
47-
relation_readers_module = BuildRelationReaders.build(relation_names)
45+
registry_readers = RegistryReaders.new(relation_names)
4846
@relation_classes.each do |klass|
4947
unless klass.adapter
5048
raise MissingAdapterIdentifierError,
@@ -58,7 +56,7 @@ def run!
5856
"Relation with name #{key.inspect} registered more than once"
5957
end
6058

61-
klass.use(:registry_reader, klass: klass, relation_readers_module: relation_readers_module)
59+
klass.use(:registry_reader, readers: registry_readers)
6260

6361
notifications.trigger(
6462
'configuration.relations.class.ready',

repository/lib/rom/repository.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,9 @@ class Repository
8080

8181
# @!method self.relation_reader
8282
# Get or set relation reader module
83-
# @return [RelationReader]
83+
# @return [Module]
8484
defines :relation_reader
85+
relation_reader RelationReader
8586

8687
struct_namespace ROM::Struct
8788

repository/lib/rom/repository/class_interface.rb

+5-3
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,11 @@ def [](name)
5959
def new(container = nil, **options)
6060
container ||= options.fetch(:container)
6161

62-
unless relation_reader
63-
relation_reader(RelationReader.new(self, container.relations.elements.keys))
64-
include(relation_reader)
62+
unless self < relation_reader
63+
include relation_reader.new(
64+
relations: container.relations.elements.keys,
65+
cache: container.cache
66+
)
6567
end
6668

6769
super(**options, container: container)

repository/lib/rom/repository/relation_reader.rb

+46-47
Original file line numberDiff line numberDiff line change
@@ -4,72 +4,71 @@ module ROM
44
class Repository
55
# @api private
66
class RelationReader < ::Module
7-
extend ::Dry::Core::ClassAttributes
8-
9-
# @api private
10-
attr_reader :klass
11-
12-
# @api private
13-
attr_reader :relations
14-
15-
defines :relation_readers
16-
17-
defines :mutex
18-
mutex(Mutex.new)
19-
20-
defines :relation_cache
21-
relation_cache(Concurrent::Hash.new)
22-
237
module InstanceMethods
248
# @api private
25-
def set_relation(name) # rubocop:disable Naming/AccessorMethodName
9+
def prepare_relation(name, **)
2610
container
2711
.relations[name]
28-
.with(auto_struct: auto_struct, struct_namespace: struct_namespace)
12+
.with(
13+
auto_struct: auto_struct,
14+
struct_namespace: struct_namespace
15+
)
2916
end
3017

31-
def relation_reader(name, relation_cache)
32-
key = [name, auto_struct, struct_namespace]
33-
relation_cache[key] ||= set_relation(name)
18+
# @api private
19+
def relation_reader(name, relation_cache, **kwargs)
20+
relation_cache.fetch_or_store(relation_cache_key(name, **kwargs)) do
21+
prepare_relation(name, **kwargs)
22+
end
3423
end
35-
end
3624

37-
# @api private
38-
def mutex
39-
ROM::Repository::RelationReader.mutex
25+
# @api private
26+
def relation_cache_key(name, **)
27+
:"#{name}[auto_struct=#{auto_struct} struct_namespace=#{struct_namespace}]"
28+
end
4029
end
4130

4231
# @api private
43-
def initialize(klass, relations)
44-
super()
45-
@relations = relations
46-
mutex.synchronize do
47-
unless self.class.relation_readers
48-
self.class.relation_readers(
49-
build_relation_readers(relations, self.class.relation_cache)
50-
)
32+
class Readers < ::Module
33+
# @api private
34+
attr_reader :cache
35+
36+
def initialize(relations)
37+
super()
38+
39+
include InstanceMethods
40+
41+
define_readers(relations)
42+
end
43+
44+
# @api private
45+
def define_readers(relations)
46+
cache = Cache.new
47+
relations.each do |name|
48+
define_readers_for_relation(name, cache)
49+
end
50+
end
51+
52+
# @api private
53+
def define_readers_for_relation(name, cache)
54+
define_method(name) do |**kwargs|
55+
relation_reader(name, cache, **kwargs)
5156
end
5257
end
53-
klass.include self.class.relation_readers
5458
end
5559

5660
# @api private
57-
def included(klass)
58-
super
59-
klass.include(InstanceMethods)
60-
end
61+
def initialize(relations:, cache:)
62+
super()
6163

62-
private
64+
add_readers(relations, cache)
65+
end
6366

6467
# @api private
65-
def build_relation_readers(relations, relation_cache)
66-
Module.new do
67-
relations.each do |name|
68-
define_method(name) do
69-
relation_reader(name, relation_cache)
70-
end
71-
end
72-
end
68+
def add_readers(relations, cache)
69+
include cache.fetch_or_store(:relation_readers) {
70+
Readers.new(relations)
71+
}
7372
end
7473
end
7574
end

repository/lib/rom/repository/root.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def self.inherited(klass)
5858
# @see Repository#initialize
5959
def initialize(*, **)
6060
super
61-
@root = set_relation(self.class.root)
61+
@root = prepare_relation(self.class.root)
6262
end
6363
end
6464
end

repository/spec/integration/plugin_spec.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def self.apply(target, **)
1212
target.prepend(self)
1313
end
1414

15-
def set_relation(*)
15+
def prepare_relation(*)
1616
super.where { `1 = 0` }
1717
end
1818
end

repository/spec/spec_helper.rb

-2
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,6 @@ def self.remove_constants
5858

5959
config.after do
6060
Test.remove_constants
61-
ROM::Repository::RelationReader.relation_readers(nil)
62-
ROM::Repository::RelationReader.relation_cache(Concurrent::Hash.new)
6361
end
6462

6563
Dir[SPEC_ROOT.join('support/*.rb').to_s].each do |f|

0 commit comments

Comments
 (0)