rom 3.0.3 → 3.1.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/CHANGELOG.md +12 -0
- data/Gemfile +1 -3
- data/lib/rom.rb +2 -0
- data/lib/rom/configuration.rb +1 -1
- data/lib/rom/configuration_dsl.rb +33 -0
- data/lib/rom/create_container.rb +1 -0
- data/lib/rom/plugin.rb +3 -0
- data/lib/rom/plugin_base.rb +9 -0
- data/lib/rom/plugins/relation/instrumentation.rb +43 -0
- data/lib/rom/relation/graph.rb +8 -3
- data/lib/rom/relation/loaded.rb +9 -0
- data/lib/rom/setup.rb +10 -0
- data/lib/rom/setup/finalize.rb +4 -2
- data/lib/rom/setup/finalize/finalize_relations.rb +14 -2
- data/lib/rom/support/configurable.rb +8 -3
- data/lib/rom/version.rb +1 -1
- data/spec/integration/setup_spec.rb +24 -0
- data/spec/unit/rom/plugins/relation/instrumentation_spec.rb +40 -0
- data/spec/unit/rom/relation/graph_spec.rb +13 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60084563a6e8cbda433df877fa5ceeaf6e342551
|
4
|
+
data.tar.gz: 9cf468362a1adbc5b64e10d4459af3c1b05d31d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd60b6cc80d21d168fe472b4f6b52cd854e7afb368c930ae652ecb0306e9c3946d9d64d9dee7e7cdfa9e9fd66593ec8820f8ea49117cac1317c7e099f8a72a26
|
7
|
+
data.tar.gz: 5db668afb63edb340bd298314eede1a5cf33f6703e5777a5f9654e62eaba8789717147f322cabbdb7d911407ec66159f18d64191a03b1ccdd9d30e5fc1dd0206
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
# v3.0.4 2017-03-01
|
2
|
+
|
3
|
+
## Added
|
4
|
+
|
5
|
+
* New configuration DSL for configuring plugins (solnic)
|
6
|
+
* Instrumentation plugin for relations (solnic)
|
7
|
+
* New `ROM::Relation::Loaded#empty?` method (solnic)
|
8
|
+
* New `ROM::Relation::Graph#with_nodes` which returns a new graph with new nodes (solnic)
|
9
|
+
* New `ROM::Schema#empty` which returns an empty schema (solnic)
|
10
|
+
|
11
|
+
[Compare v3.0.3...v3.0.4](https://github.com/rom-rb/rom/compare/v3.0.3...v3.0.4)
|
12
|
+
|
1
13
|
# v3.0.3 2017-02-24
|
2
14
|
|
3
15
|
## Fixed
|
data/Gemfile
CHANGED
@@ -2,9 +2,6 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
|
-
gem 'rom-mapper', git: 'https://github.com/rom-rb/rom-mapper.git', branch: 'master'
|
6
|
-
gem 'transproc', git: 'https://github.com/solnic/transproc.git', branch: 'master'
|
7
|
-
|
8
5
|
group :console do
|
9
6
|
gem 'pry'
|
10
7
|
gem 'pg', platforms: [:mri]
|
@@ -47,6 +44,7 @@ group :benchmarks do
|
|
47
44
|
gem 'activerecord', '~> 5.0'
|
48
45
|
gem 'benchmark-ips', '~> 2.2.0'
|
49
46
|
gem 'rom-repository', git: 'https://github.com/rom-rb/rom-repository.git', branch: 'master'
|
47
|
+
gem 'hotch', platform: :mri
|
50
48
|
end
|
51
49
|
|
52
50
|
group :tools do
|
data/lib/rom.rb
CHANGED
@@ -30,6 +30,7 @@ require 'rom/create_container'
|
|
30
30
|
# register core plugins
|
31
31
|
require 'rom/plugins/configuration/configuration_dsl'
|
32
32
|
require 'rom/plugins/relation/registry_reader'
|
33
|
+
require 'rom/plugins/relation/instrumentation'
|
33
34
|
require 'rom/plugins/command/schema'
|
34
35
|
|
35
36
|
module ROM
|
@@ -38,6 +39,7 @@ module ROM
|
|
38
39
|
plugins do
|
39
40
|
register :macros, ROM::ConfigurationPlugins::ConfigurationDSL, type: :configuration
|
40
41
|
register :registry_reader, ROM::Plugins::Relation::RegistryReader, type: :relation
|
42
|
+
register :instrumentation, ROM::Plugins::Relation::Instrumentation, type: :relation
|
41
43
|
register :schema, ROM::Plugins::Command::Schema, type: :command
|
42
44
|
end
|
43
45
|
end
|
data/lib/rom/configuration.rb
CHANGED
@@ -13,7 +13,7 @@ module ROM
|
|
13
13
|
|
14
14
|
attr_reader :environment, :setup
|
15
15
|
|
16
|
-
def_delegators :@setup, :register_relation, :register_command, :register_mapper,
|
16
|
+
def_delegators :@setup, :register_relation, :register_command, :register_mapper, :register_plugin,
|
17
17
|
:relation_classes, :command_classes, :mapper_classes,
|
18
18
|
:auto_registration
|
19
19
|
|
@@ -70,5 +70,38 @@ module ROM
|
|
70
70
|
def commands(name, &block)
|
71
71
|
register_command(*CommandDSL.new(name, default_adapter, &block).command_classes)
|
72
72
|
end
|
73
|
+
|
74
|
+
# Configures a plugin for a specific adapter to be enabled for all relations
|
75
|
+
#
|
76
|
+
# @example
|
77
|
+
# config = ROM::Configuration.new(:sql, 'sqlite::memory')
|
78
|
+
#
|
79
|
+
# config.plugin(:sql, relations: :instrumentation) do |p|
|
80
|
+
# p.notifications = MyNotificationsBackend
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# config.plugin(:sql, relations: :pagination)
|
84
|
+
#
|
85
|
+
# @param [Symbol] adapter The adapter identifier
|
86
|
+
# @param [Hash<Symbol=>Symbol>] spec Component identifier => plugin identifier
|
87
|
+
#
|
88
|
+
# @return [Plugin]
|
89
|
+
#
|
90
|
+
# @api public
|
91
|
+
def plugin(adapter, spec, &block)
|
92
|
+
type, name = spec.flatten(1)
|
93
|
+
plugin = plugin_registry.send(type).adapter(adapter).fetch(name) { plugin_registry.send(type).fetch(name) }
|
94
|
+
|
95
|
+
if block
|
96
|
+
register_plugin(plugin.configure(&block))
|
97
|
+
else
|
98
|
+
register_plugin(plugin)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# @api private
|
103
|
+
def plugin_registry
|
104
|
+
ROM.plugin_registry
|
105
|
+
end
|
73
106
|
end
|
74
107
|
end
|
data/lib/rom/create_container.rb
CHANGED
data/lib/rom/plugin.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
require 'rom/plugin_base'
|
2
|
+
require 'rom/support/configurable'
|
2
3
|
|
3
4
|
module ROM
|
4
5
|
# Plugin is a simple object used to store plugin configurations
|
5
6
|
#
|
6
7
|
# @private
|
7
8
|
class Plugin < PluginBase
|
9
|
+
include Configurable
|
10
|
+
|
8
11
|
# Apply this plugin to the provided class
|
9
12
|
#
|
10
13
|
# @param [Class] klass
|
data/lib/rom/plugin_base.rb
CHANGED
@@ -13,10 +13,19 @@ module ROM
|
|
13
13
|
# @api private
|
14
14
|
attr_reader :options
|
15
15
|
|
16
|
+
# @api private
|
17
|
+
attr_reader :type
|
18
|
+
|
16
19
|
# @api private
|
17
20
|
def initialize(mod, options)
|
18
21
|
@mod = mod
|
19
22
|
@options = options
|
23
|
+
@type = options.fetch(:type)
|
24
|
+
end
|
25
|
+
|
26
|
+
# @api private
|
27
|
+
def relation?
|
28
|
+
type == :relation
|
20
29
|
end
|
21
30
|
|
22
31
|
# Apply this plugin to the provided class
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module ROM
|
2
|
+
module Plugins
|
3
|
+
module Relation
|
4
|
+
# Experimental plugin for configuring relations with an external
|
5
|
+
# instrumentation system like dry-monitor or ActiveSupport::Notifications
|
6
|
+
#
|
7
|
+
# @api public
|
8
|
+
module Instrumentation
|
9
|
+
# This hooks sets up a relation class with injectible notifications object
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
def self.included(klass)
|
13
|
+
super
|
14
|
+
klass.option :notifications, reader: true
|
15
|
+
klass.extend(ClassInterface)
|
16
|
+
klass.instrument(:to_a)
|
17
|
+
end
|
18
|
+
|
19
|
+
module ClassInterface
|
20
|
+
def instrument(*methods)
|
21
|
+
methods.each do |meth|
|
22
|
+
define_method(meth) do
|
23
|
+
instrument { super() }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# @api public
|
30
|
+
def instrument(&block)
|
31
|
+
notifications.instrument(self.class.adapter, { name: name.relation }.merge(notification_payload(self)), &block)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
# @api private
|
37
|
+
def notification_payload(relation)
|
38
|
+
EMPTY_HASH
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/rom/relation/graph.rb
CHANGED
@@ -61,6 +61,11 @@ module ROM
|
|
61
61
|
@nodes = nodes
|
62
62
|
end
|
63
63
|
|
64
|
+
# @api public
|
65
|
+
def with_nodes(nodes)
|
66
|
+
self.class.new(root, nodes)
|
67
|
+
end
|
68
|
+
|
64
69
|
# Return if this is a graph relation
|
65
70
|
#
|
66
71
|
# @return [true]
|
@@ -90,10 +95,10 @@ module ROM
|
|
90
95
|
left = root.call(*args)
|
91
96
|
|
92
97
|
right =
|
93
|
-
if left.
|
94
|
-
nodes.map { |node|
|
98
|
+
if left.empty?
|
99
|
+
nodes.map { |node| Loaded.new(node, EMPTY_ARRAY) }
|
95
100
|
else
|
96
|
-
nodes.map { |node|
|
101
|
+
nodes.map { |node| node.call(left) }
|
97
102
|
end
|
98
103
|
|
99
104
|
Loaded.new(self, [left, right])
|
data/lib/rom/relation/loaded.rb
CHANGED
@@ -107,6 +107,15 @@ module ROM
|
|
107
107
|
pluck(source.primary_key)
|
108
108
|
end
|
109
109
|
|
110
|
+
# Return if loaded relation is empty
|
111
|
+
#
|
112
|
+
# @return [TrueClass,FalseClass]
|
113
|
+
#
|
114
|
+
# @api public
|
115
|
+
def empty?
|
116
|
+
collection.empty?
|
117
|
+
end
|
118
|
+
|
110
119
|
# Return a loaded relation with a new collection
|
111
120
|
#
|
112
121
|
# @api public
|
data/lib/rom/setup.rb
CHANGED
@@ -17,11 +17,16 @@ module ROM
|
|
17
17
|
# @api private
|
18
18
|
attr_reader :command_classes
|
19
19
|
|
20
|
+
|
21
|
+
# @api private
|
22
|
+
attr_reader :plugins
|
23
|
+
|
20
24
|
# @api private
|
21
25
|
def initialize
|
22
26
|
@relation_classes = []
|
23
27
|
@command_classes = []
|
24
28
|
@mapper_classes = []
|
29
|
+
@plugins = []
|
25
30
|
end
|
26
31
|
|
27
32
|
# Relation sub-classes are being registered with this method during setup
|
@@ -45,6 +50,11 @@ module ROM
|
|
45
50
|
klasses.reduce(@command_classes, :<<)
|
46
51
|
end
|
47
52
|
|
53
|
+
# @api private
|
54
|
+
def register_plugin(plugin)
|
55
|
+
plugins << plugin
|
56
|
+
end
|
57
|
+
|
48
58
|
def auto_registration(directory, options = {})
|
49
59
|
auto_registration = AutoRegistration.new(directory, options)
|
50
60
|
auto_registration.relations.map { |r| register_relation(r) }
|
data/lib/rom/setup/finalize.rb
CHANGED
@@ -21,7 +21,7 @@ module ROM
|
|
21
21
|
# @private
|
22
22
|
class Finalize
|
23
23
|
attr_reader :gateways, :repo_adapter, :datasets, :gateway_map,
|
24
|
-
:relation_classes, :mapper_classes, :mapper_objects, :command_classes, :config
|
24
|
+
:relation_classes, :mapper_classes, :mapper_objects, :command_classes, :plugins, :config
|
25
25
|
|
26
26
|
# @api private
|
27
27
|
def initialize(options)
|
@@ -37,6 +37,8 @@ module ROM
|
|
37
37
|
|
38
38
|
@config = options.fetch(:config)
|
39
39
|
|
40
|
+
@plugins = options.fetch(:plugins)
|
41
|
+
|
40
42
|
initialize_datasets
|
41
43
|
end
|
42
44
|
|
@@ -90,7 +92,7 @@ module ROM
|
|
90
92
|
#
|
91
93
|
# @api private
|
92
94
|
def load_relations
|
93
|
-
FinalizeRelations.new(gateways, relation_classes).run!
|
95
|
+
FinalizeRelations.new(gateways, relation_classes, plugins.select(&:relation?)).run!
|
94
96
|
end
|
95
97
|
|
96
98
|
# @api private
|
@@ -11,9 +11,10 @@ module ROM
|
|
11
11
|
# @param [Array] relation_classes a list of relation descendants
|
12
12
|
#
|
13
13
|
# @api private
|
14
|
-
def initialize(gateways, relation_classes)
|
14
|
+
def initialize(gateways, relation_classes, plugins = EMPTY_ARRAY)
|
15
15
|
@gateways = gateways
|
16
16
|
@relation_classes = relation_classes
|
17
|
+
@plugins = plugins
|
17
18
|
end
|
18
19
|
|
19
20
|
# @return [Hash]
|
@@ -53,9 +54,20 @@ module ROM
|
|
53
54
|
klass.schema(infer: true) unless klass.schema
|
54
55
|
schema = klass.schema.finalize!(gateway: gateway, relations: registry)
|
55
56
|
|
57
|
+
@plugins.each do |plugin|
|
58
|
+
plugin.apply_to(klass)
|
59
|
+
end
|
60
|
+
|
56
61
|
dataset = gateway.dataset(klass.dataset).instance_exec(klass, &ds_proc)
|
57
62
|
|
58
|
-
|
63
|
+
options = { __registry__: registry, schema: schema.with(relations: registry), **plugin_options }
|
64
|
+
|
65
|
+
klass.new(dataset, options)
|
66
|
+
end
|
67
|
+
|
68
|
+
# @api private
|
69
|
+
def plugin_options
|
70
|
+
@plugins.map(&:config).map(&:to_hash).reduce(:merge) || EMPTY_HASH
|
59
71
|
end
|
60
72
|
end
|
61
73
|
end
|
@@ -21,6 +21,10 @@ module ROM
|
|
21
21
|
settings.key?(name)
|
22
22
|
end
|
23
23
|
|
24
|
+
def to_hash
|
25
|
+
settings
|
26
|
+
end
|
27
|
+
|
24
28
|
# @api private
|
25
29
|
def freeze
|
26
30
|
settings.each_value(&:freeze)
|
@@ -31,13 +35,13 @@ module ROM
|
|
31
35
|
def respond_to_missing?(_name, _include_private = false)
|
32
36
|
true
|
33
37
|
end
|
34
|
-
|
38
|
+
|
35
39
|
def dup
|
36
40
|
self.class.new(dup_settings(settings))
|
37
41
|
end
|
38
|
-
|
42
|
+
|
39
43
|
private
|
40
|
-
|
44
|
+
|
41
45
|
def dup_settings(settings)
|
42
46
|
settings.each_with_object({}) do |(key, value), new_settings|
|
43
47
|
if value.is_a?(self.class)
|
@@ -75,6 +79,7 @@ module ROM
|
|
75
79
|
# @api public
|
76
80
|
def configure
|
77
81
|
yield(config)
|
82
|
+
self
|
78
83
|
end
|
79
84
|
end
|
80
85
|
end
|
data/lib/rom/version.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'rom/plugins/relation/key_inference'
|
2
3
|
require 'dry-struct'
|
3
4
|
|
4
5
|
RSpec.describe 'Configuring ROM' do
|
@@ -163,4 +164,27 @@ RSpec.describe 'Configuring ROM' do
|
|
163
164
|
ROM.container(:memory) { |c| c.register_relation(Test::UserRelation) }
|
164
165
|
end
|
165
166
|
end
|
167
|
+
|
168
|
+
describe 'configuring plugins for all relations' do
|
169
|
+
it 'allows setting instrumentation for relations' do
|
170
|
+
Test::Notifications = double(:notifications)
|
171
|
+
|
172
|
+
configuration = ROM::Configuration.new(:memory)
|
173
|
+
|
174
|
+
configuration.plugin(:memory, relations: :instrumentation) do |p|
|
175
|
+
p.notifications = Test::Notifications
|
176
|
+
end
|
177
|
+
|
178
|
+
configuration.plugin(:memory, relations: :key_inference)
|
179
|
+
|
180
|
+
configuration.relation(:users)
|
181
|
+
|
182
|
+
container = ROM.container(configuration)
|
183
|
+
|
184
|
+
users = container.relations[:users]
|
185
|
+
|
186
|
+
expect(users.notifications).to be(Test::Notifications)
|
187
|
+
expect(users).to respond_to(:foreign_key)
|
188
|
+
end
|
189
|
+
end
|
166
190
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rom'
|
2
|
+
require 'rom/memory'
|
3
|
+
|
4
|
+
RSpec.describe ROM::Plugins::Relation::Instrumentation do
|
5
|
+
subject(:relation) do
|
6
|
+
relation_class.new(dataset, notifications: notifications)
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:dataset) do
|
10
|
+
double(:dataset)
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:relation_class) do
|
14
|
+
Class.new(ROM::Memory::Relation) do
|
15
|
+
schema(:users) do
|
16
|
+
attribute :name, ROM::Types::String
|
17
|
+
end
|
18
|
+
|
19
|
+
use :instrumentation
|
20
|
+
|
21
|
+
instrument def all
|
22
|
+
self
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
let(:notifications) { spy(:notifications) }
|
28
|
+
|
29
|
+
it 'uses notifications API when materializing a relation' do
|
30
|
+
relation.to_a
|
31
|
+
|
32
|
+
expect(notifications).to have_received(:instrument).with(:memory, name: :users)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'instruments custom methods' do
|
36
|
+
relation.all
|
37
|
+
|
38
|
+
expect(notifications).to have_received(:instrument).with(:memory, name: :users)
|
39
|
+
end
|
40
|
+
end
|
@@ -17,6 +17,10 @@ RSpec.describe ROM::Relation::Graph do
|
|
17
17
|
def for_users(_users)
|
18
18
|
self
|
19
19
|
end
|
20
|
+
|
21
|
+
def by_title(title)
|
22
|
+
restrict(title: title)
|
23
|
+
end
|
20
24
|
end.new(tasks_dataset)
|
21
25
|
end
|
22
26
|
|
@@ -64,6 +68,15 @@ RSpec.describe ROM::Relation::Graph do
|
|
64
68
|
end
|
65
69
|
end
|
66
70
|
|
71
|
+
describe '#with_nodes' do
|
72
|
+
it 'returns a new graph with new nodes' do
|
73
|
+
new_tasks = tasks_relation.by_title('foo')
|
74
|
+
new_graph = graph.with_nodes([new_tasks])
|
75
|
+
|
76
|
+
expect(new_graph.nodes[0]).to be(new_tasks)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
67
80
|
describe '#call' do
|
68
81
|
it 'materializes relations' do
|
69
82
|
expect(graph.call).to match_array([
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rom
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0
|
4
|
+
version: 3.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Solnica
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-03-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -219,6 +219,7 @@ files:
|
|
219
219
|
- lib/rom/plugin_registry.rb
|
220
220
|
- lib/rom/plugins/command/schema.rb
|
221
221
|
- lib/rom/plugins/configuration/configuration_dsl.rb
|
222
|
+
- lib/rom/plugins/relation/instrumentation.rb
|
222
223
|
- lib/rom/plugins/relation/key_inference.rb
|
223
224
|
- lib/rom/plugins/relation/registry_reader.rb
|
224
225
|
- lib/rom/registry.rb
|
@@ -349,6 +350,7 @@ files:
|
|
349
350
|
- spec/unit/rom/memory/storage_spec.rb
|
350
351
|
- spec/unit/rom/plugin_spec.rb
|
351
352
|
- spec/unit/rom/plugins/command/schema_spec.rb
|
353
|
+
- spec/unit/rom/plugins/relation/instrumentation_spec.rb
|
352
354
|
- spec/unit/rom/plugins/relation/key_inference_spec.rb
|
353
355
|
- spec/unit/rom/registry_spec.rb
|
354
356
|
- spec/unit/rom/relation/attribute_reader_spec.rb
|