rom 0.9.0.beta1 → 0.9.0.rc1
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 +25 -0
- data/Gemfile +1 -1
- data/lib/rom/commands/abstract.rb +1 -1
- data/lib/rom/commands/graph.rb +0 -4
- data/lib/rom/commands/graph/class_interface.rb +4 -17
- data/lib/rom/commands/graph/input_evaluator.rb +58 -0
- data/lib/rom/commands/lazy.rb +6 -2
- data/lib/rom/environment.rb +27 -1
- data/lib/rom/gateway.rb +7 -1
- data/lib/rom/relation/class_interface.rb +13 -4
- data/lib/rom/setup.rb +15 -2
- data/lib/rom/setup/finalize.rb +29 -9
- data/lib/rom/support/configurable.rb +66 -0
- data/lib/rom/version.rb +1 -1
- data/spec/integration/commands/graph_spec.rb +0 -10
- data/spec/integration/relations/inheritance_spec.rb +39 -0
- data/spec/unit/rom/relation_spec.rb +57 -25
- data/spec/unit/rom/setup_spec.rb +96 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 68b700901edb358688ae8f41a8f474cab6dc1254
|
4
|
+
data.tar.gz: 97d2569ad4ad0b653e725b0598fe6edb0d6d70b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5627b18505dd2e30d7eca6b6514b84f6f81573cd99a44eb7fb67b15966e37fccc007df8b3d3016b8a65a4363321d10e056e5e93c255c0ef13704693592345c5c
|
7
|
+
data.tar.gz: 46dd954fd398b22e3a5a5af01215ff9f52ab51ee9b750de68d7a5c9510a4275f29fb9e04914d03cb52e026653cf3c0754fa88aad10fb4feebd8ae28d138ea122
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,30 @@
|
|
1
1
|
## v0.9.0 to-be-released
|
2
2
|
|
3
|
+
### Added
|
4
|
+
|
5
|
+
* Configuration API for gateways supporting following options:
|
6
|
+
- `infer_relations` either `true` or `false` - if disabled schema inference
|
7
|
+
won't be used to automatically set up relations for you
|
8
|
+
- `inferrable_relations` a list of allowed relations that should be inferred
|
9
|
+
- `not_inferrable_relations` a list of relations that should not be inferred
|
10
|
+
|
11
|
+
### Changed
|
12
|
+
|
13
|
+
* Global setup with auto-registration ported to the `:auto_registration` environment plugin (AMHOL)
|
14
|
+
* Multi-environment setup possible now via `ROM::Environment` object (AMHOL)
|
15
|
+
* All relations are now lazy with auto-currying enabled (solnic)
|
16
|
+
* Low-level query DSL provided by adapters is now public but using it directly in
|
17
|
+
application layer is discouraged (solnic)
|
18
|
+
* `ROM::Mapper` component extracted into standalone `rom-mapper` gem (solnic)
|
19
|
+
* Support libraries extracted to `rom-support` gem (solnic)
|
20
|
+
|
21
|
+
## Fixed
|
22
|
+
|
23
|
+
* `register_as` is now properly inferred for relations and their descendants (solnic)
|
24
|
+
* Adapter-specific interface is properly included in relation descendants (solnic)
|
25
|
+
* Combined commands (aka command graph) properly rejects keys from nested input
|
26
|
+
prior sending the input to individual commands (solnic)
|
27
|
+
|
3
28
|
[Compare v0.8.1...HEAD](https://github.com/rom-rb/rom/compare/v0.8.1...HEAD)
|
4
29
|
|
5
30
|
## v0.8.1 2015-07-12
|
data/Gemfile
CHANGED
@@ -77,7 +77,7 @@ module ROM
|
|
77
77
|
#
|
78
78
|
# @api public
|
79
79
|
def curry(*args)
|
80
|
-
if curry_args.empty? && args.first.is_a?(
|
80
|
+
if curry_args.empty? && args.first.is_a?(Graph::InputEvaluator)
|
81
81
|
Lazy.new(self, args.first)
|
82
82
|
else
|
83
83
|
self.class.build(relation, options.merge(curry_args: args))
|
data/lib/rom/commands/graph.rb
CHANGED
@@ -63,8 +63,6 @@ module ROM
|
|
63
63
|
end
|
64
64
|
rescue => err
|
65
65
|
raise CommandFailure.new(node, err)
|
66
|
-
rescue CommandFailure => err
|
67
|
-
raise err
|
68
66
|
end
|
69
67
|
|
70
68
|
if node.one? && !node.graph?
|
@@ -81,8 +79,6 @@ module ROM
|
|
81
79
|
end
|
82
80
|
rescue => err
|
83
81
|
raise CommandFailure.new(root, err)
|
84
|
-
rescue CommandFailure => err
|
85
|
-
raise err
|
86
82
|
end
|
87
83
|
end
|
88
84
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'rom/commands/graph/input_evaluator'
|
2
|
+
|
1
3
|
module ROM
|
2
4
|
module Commands
|
3
5
|
class Graph
|
@@ -31,25 +33,10 @@ module ROM
|
|
31
33
|
[spec, spec]
|
32
34
|
end
|
33
35
|
|
34
|
-
command = registry[relation][name]
|
35
36
|
|
37
|
+
command = registry[relation][name]
|
36
38
|
tuple_path = Array[*path] << key
|
37
|
-
|
38
|
-
input_proc = -> *args do
|
39
|
-
input, index = args
|
40
|
-
|
41
|
-
begin
|
42
|
-
if index
|
43
|
-
tuple_path[0..tuple_path.size-2]
|
44
|
-
.reduce(input) { |a,e| a.fetch(e) }
|
45
|
-
.at(index)[tuple_path.last]
|
46
|
-
else
|
47
|
-
tuple_path.reduce(input) { |a,e| a.fetch(e) }
|
48
|
-
end
|
49
|
-
rescue KeyError => err
|
50
|
-
raise CommandFailure.new(command, err)
|
51
|
-
end
|
52
|
-
end
|
39
|
+
input_proc = InputEvaluator.build(tuple_path, nodes)
|
53
40
|
|
54
41
|
command = command.with(input_proc)
|
55
42
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module ROM
|
2
|
+
module Commands
|
3
|
+
class Graph
|
4
|
+
class InputEvaluator
|
5
|
+
attr_reader :tuple_path
|
6
|
+
|
7
|
+
attr_reader :excluded_keys
|
8
|
+
|
9
|
+
attr_reader :exclude_proc
|
10
|
+
|
11
|
+
def self.build(tuple_path, nodes)
|
12
|
+
new(tuple_path, extract_excluded_keys(nodes))
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.extract_excluded_keys(nodes)
|
16
|
+
return unless nodes
|
17
|
+
|
18
|
+
nodes
|
19
|
+
.map { |item| item.is_a?(Array) && item.size > 1 ? item.first : item }
|
20
|
+
.compact
|
21
|
+
.map { |item| item.is_a?(Hash) ? item.keys.first : item }
|
22
|
+
.reject { |item| item.is_a?(Array) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.exclude_proc(excluded_keys)
|
26
|
+
-> input { input.reject { |k, _| excluded_keys.include?(k) } }
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize(tuple_path, excluded_keys)
|
30
|
+
@tuple_path = tuple_path
|
31
|
+
@excluded_keys = excluded_keys
|
32
|
+
@exclude_proc = self.class.exclude_proc(excluded_keys)
|
33
|
+
end
|
34
|
+
|
35
|
+
def call(*args)
|
36
|
+
input, index = args
|
37
|
+
|
38
|
+
begin
|
39
|
+
value =
|
40
|
+
if index
|
41
|
+
tuple_path[0..tuple_path.size-2]
|
42
|
+
.reduce(input) { |a,e| a.fetch(e) }
|
43
|
+
.at(index)[tuple_path.last]
|
44
|
+
else
|
45
|
+
tuple_path.reduce(input) { |a,e| a.fetch(e) }
|
46
|
+
end
|
47
|
+
|
48
|
+
if excluded_keys
|
49
|
+
value.is_a?(Array) ? value.map(&exclude_proc) : exclude_proc[value]
|
50
|
+
else
|
51
|
+
value
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/rom/commands/lazy.rb
CHANGED
@@ -31,11 +31,15 @@ module ROM
|
|
31
31
|
|
32
32
|
if size > 1 && last.is_a?(Array)
|
33
33
|
last.map.with_index do |item, index|
|
34
|
-
|
34
|
+
input = evaluator.call(first, index)
|
35
|
+
command.call(input, item)
|
35
36
|
end.reduce(:concat)
|
36
37
|
else
|
37
|
-
|
38
|
+
input = evaluator.call(first)
|
39
|
+
command.call(input, *args[1..size-1])
|
38
40
|
end
|
41
|
+
rescue => err
|
42
|
+
raise CommandFailure.new(command, err)
|
39
43
|
end
|
40
44
|
|
41
45
|
# Compose a lazy command with another one
|
data/lib/rom/environment.rb
CHANGED
@@ -113,6 +113,11 @@ module ROM
|
|
113
113
|
config = setup_config(*args)
|
114
114
|
@boot = Setup.new(setup_gateways(config), adapters.keys.first)
|
115
115
|
|
116
|
+
config.each do |name, config_args|
|
117
|
+
options = config_args.is_a?(Array) && config_args.last
|
118
|
+
load_config(@boot.config.gateways[name], options) if options.is_a?(Hash)
|
119
|
+
end
|
120
|
+
|
116
121
|
if block
|
117
122
|
@boot.instance_exec(&block)
|
118
123
|
@boot.finalize
|
@@ -172,7 +177,7 @@ module ROM
|
|
172
177
|
boot.mappers(*args, &block)
|
173
178
|
end
|
174
179
|
|
175
|
-
# Finalize the setup and store default global container under
|
180
|
+
# Finalize the setup and store default global container under
|
176
181
|
# ROM::Environmrnt#container
|
177
182
|
#
|
178
183
|
# @example
|
@@ -213,6 +218,15 @@ module ROM
|
|
213
218
|
boot.register_command(klass) if boot
|
214
219
|
end
|
215
220
|
|
221
|
+
# Return gateway config that was used to setup this environment's container
|
222
|
+
#
|
223
|
+
# @return [Configurable::Config]
|
224
|
+
#
|
225
|
+
# @api public
|
226
|
+
def config
|
227
|
+
boot.config
|
228
|
+
end
|
229
|
+
|
216
230
|
private
|
217
231
|
|
218
232
|
# Helper method to handle single- or multi-repo setup options
|
@@ -228,11 +242,23 @@ module ROM
|
|
228
242
|
def setup_gateways(config)
|
229
243
|
config.each_with_object({}) do |(name, spec), hash|
|
230
244
|
identifier, *args = Array(spec)
|
245
|
+
|
231
246
|
gateway = Gateway.setup(identifier, *(args.flatten))
|
232
247
|
hash[name] = gateway
|
233
248
|
|
234
249
|
gateways[gateway] = identifier unless identifier.is_a?(Gateway)
|
235
250
|
end
|
236
251
|
end
|
252
|
+
|
253
|
+
# @api private
|
254
|
+
def load_config(config, hash)
|
255
|
+
hash.each do |key, value|
|
256
|
+
if value.is_a?(Hash)
|
257
|
+
load_config(config[key], value)
|
258
|
+
else
|
259
|
+
config.send("#{key}=", value)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
237
263
|
end
|
238
264
|
end
|
data/lib/rom/gateway.rb
CHANGED
@@ -50,7 +50,13 @@ module ROM
|
|
50
50
|
See https://github.com/rom-rb/rom/blob/master/CHANGELOG.md
|
51
51
|
STRING
|
52
52
|
when Symbol
|
53
|
-
class_from_symbol(gateway_or_scheme)
|
53
|
+
klass = class_from_symbol(gateway_or_scheme)
|
54
|
+
|
55
|
+
if klass.instance_method(:initialize).arity == 0
|
56
|
+
klass.new
|
57
|
+
else
|
58
|
+
klass.new(*args)
|
59
|
+
end
|
54
60
|
else
|
55
61
|
if args.empty?
|
56
62
|
gateway_or_scheme
|
@@ -19,7 +19,9 @@ module ROM
|
|
19
19
|
klass.extend Deprecations
|
20
20
|
klass.defines :adapter
|
21
21
|
|
22
|
-
|
22
|
+
# Extend with functionality required by adapters *only* if this is a direct
|
23
|
+
# descendant of an adapter-specific relation subclass
|
24
|
+
return unless respond_to?(:adapter) && klass.superclass == ROM::Relation[adapter]
|
23
25
|
|
24
26
|
klass.class_eval do
|
25
27
|
use :registry_reader
|
@@ -31,7 +33,7 @@ module ROM
|
|
31
33
|
|
32
34
|
gateway :default
|
33
35
|
|
34
|
-
dataset
|
36
|
+
dataset default_name
|
35
37
|
|
36
38
|
# Relation's dataset name
|
37
39
|
#
|
@@ -44,19 +46,26 @@ module ROM
|
|
44
46
|
|
45
47
|
# Set or get name under which a relation will be registered
|
46
48
|
#
|
47
|
-
# This defaults to `dataset`
|
49
|
+
# This defaults to `dataset` or `default_name` for descendant relations
|
48
50
|
#
|
49
51
|
# @return [Symbol]
|
50
52
|
#
|
51
53
|
# @api public
|
52
54
|
def self.register_as(value = Undefined)
|
53
55
|
if value == Undefined
|
54
|
-
super()
|
56
|
+
super_val = super()
|
57
|
+
|
58
|
+
if superclass == ROM::Relation[adapter]
|
59
|
+
super_val || dataset
|
60
|
+
else
|
61
|
+
super_val == dataset ? default_name : super_val
|
62
|
+
end
|
55
63
|
else
|
56
64
|
super
|
57
65
|
end
|
58
66
|
end
|
59
67
|
|
68
|
+
# @api public
|
60
69
|
def self.exposed_relations(*args)
|
61
70
|
Deprecations.announce("#{self}.exposed_relations", 'this method has no effect anymore')
|
62
71
|
Set.new
|
data/lib/rom/setup.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'rom/support/configurable'
|
2
|
+
|
1
3
|
require 'rom/setup/finalize'
|
2
4
|
require 'rom/support/deprecations'
|
3
5
|
|
@@ -6,6 +8,8 @@ module ROM
|
|
6
8
|
#
|
7
9
|
# @api public
|
8
10
|
class Setup
|
11
|
+
include Configurable
|
12
|
+
|
9
13
|
extend Deprecations
|
10
14
|
include Equalizer.new(:gateways, :container)
|
11
15
|
|
@@ -57,15 +61,24 @@ module ROM
|
|
57
61
|
|
58
62
|
# Finalize the setup
|
59
63
|
#
|
60
|
-
# @return [Container] frozen container with access to gateways,
|
64
|
+
# @return [Container] frozen container with access to gateways,
|
61
65
|
# relations, mappers and commands
|
62
66
|
#
|
63
67
|
# @api public
|
64
68
|
def finalize
|
65
69
|
raise EnvAlreadyFinalizedError if container
|
70
|
+
|
71
|
+
# initialize default configs for all gateways
|
72
|
+
gateways.each_key do |key|
|
73
|
+
gateway_config = config.gateways[key]
|
74
|
+
|
75
|
+
gateway_config.infer_relations = true unless gateway_config.key?(:infer_relations)
|
76
|
+
end
|
77
|
+
|
66
78
|
finalize = Finalize.new(
|
67
|
-
gateways, relation_classes, mapper_classes, command_classes
|
79
|
+
gateways, relation_classes, mapper_classes, command_classes, config.freeze
|
68
80
|
)
|
81
|
+
|
69
82
|
@container = finalize.run!
|
70
83
|
end
|
71
84
|
|
data/lib/rom/setup/finalize.rb
CHANGED
@@ -17,16 +17,17 @@ module ROM
|
|
17
17
|
# @private
|
18
18
|
class Finalize
|
19
19
|
attr_reader :gateways, :repo_adapter, :datasets,
|
20
|
-
:relation_classes, :mapper_classes, :mappers, :command_classes
|
20
|
+
:relation_classes, :mapper_classes, :mappers, :command_classes, :config
|
21
21
|
|
22
22
|
# @api private
|
23
|
-
def initialize(gateways, relation_classes, mappers, command_classes)
|
23
|
+
def initialize(gateways, relation_classes, mappers, command_classes, config)
|
24
24
|
@gateways = gateways
|
25
25
|
@repo_adapter_map = ROM.gateways
|
26
26
|
@relation_classes = relation_classes
|
27
27
|
@mapper_classes = mappers.select { |mapper| mapper.is_a?(Class) }
|
28
28
|
@mappers = (mappers - @mapper_classes).reduce(:merge) || {}
|
29
29
|
@command_classes = command_classes
|
30
|
+
@config = config
|
30
31
|
initialize_datasets
|
31
32
|
end
|
32
33
|
|
@@ -47,7 +48,7 @@ module ROM
|
|
47
48
|
#
|
48
49
|
# @api private
|
49
50
|
def run!
|
50
|
-
|
51
|
+
infer_relations_relations
|
51
52
|
|
52
53
|
relations = load_relations
|
53
54
|
mappers = load_mappers
|
@@ -67,7 +68,7 @@ module ROM
|
|
67
68
|
# @api private
|
68
69
|
def initialize_datasets
|
69
70
|
@datasets = gateways.each_with_object({}) do |(key, gateway), h|
|
70
|
-
h[key] = gateway.schema
|
71
|
+
h[key] = gateway.schema if config.gateways[key][:infer_relations]
|
71
72
|
end
|
72
73
|
end
|
73
74
|
|
@@ -120,16 +121,35 @@ module ROM
|
|
120
121
|
# Relations explicitly defined are being skipped
|
121
122
|
#
|
122
123
|
# @api private
|
123
|
-
def
|
124
|
+
def infer_relations_relations
|
124
125
|
datasets.each do |gateway, schema|
|
125
126
|
schema.each do |name|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
127
|
+
if infer_relation?(gateway, name)
|
128
|
+
klass = Relation.build_class(name, adapter: adapter_for(gateway))
|
129
|
+
klass.gateway(gateway)
|
130
|
+
klass.dataset(name)
|
131
|
+
else
|
132
|
+
next
|
133
|
+
end
|
130
134
|
end
|
131
135
|
end
|
132
136
|
end
|
137
|
+
|
138
|
+
def infer_relation?(gateway, name)
|
139
|
+
inferrable_relations(gateway).include?(name) && relation_classes.none? { |klass|
|
140
|
+
klass.dataset == name
|
141
|
+
}
|
142
|
+
end
|
143
|
+
|
144
|
+
def inferrable_relations(gateway)
|
145
|
+
gateway_config = config.gateways[gateway]
|
146
|
+
schema = gateways[gateway].schema
|
147
|
+
|
148
|
+
allowed = gateway_config[:inferrable_relations] || schema
|
149
|
+
skipped = gateway_config[:not_inferrable_relations] || []
|
150
|
+
|
151
|
+
schema & allowed - skipped
|
152
|
+
end
|
133
153
|
end
|
134
154
|
end
|
135
155
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module ROM
|
2
|
+
# @api private
|
3
|
+
module Configurable
|
4
|
+
class Config
|
5
|
+
WRITER_REGEXP = /=$/.freeze
|
6
|
+
|
7
|
+
attr_reader :settings
|
8
|
+
|
9
|
+
# @api private
|
10
|
+
def initialize
|
11
|
+
@settings = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
# @api public
|
15
|
+
def [](name)
|
16
|
+
public_send(name)
|
17
|
+
end
|
18
|
+
|
19
|
+
# @api private
|
20
|
+
def key?(name)
|
21
|
+
settings.key?(name)
|
22
|
+
end
|
23
|
+
|
24
|
+
# @api private
|
25
|
+
def freeze
|
26
|
+
settings.each_value { |value| value.freeze }
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
# @api private
|
31
|
+
def respond_to_missing?(name, include_private = false)
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# @api private
|
38
|
+
def method_missing(meth, *args, &block)
|
39
|
+
return settings.fetch(meth, nil) if frozen?
|
40
|
+
|
41
|
+
name = meth.to_s
|
42
|
+
key = name.gsub(WRITER_REGEXP, '').to_sym
|
43
|
+
|
44
|
+
if writer?(name)
|
45
|
+
settings[key] = args.first
|
46
|
+
else
|
47
|
+
settings.fetch(key) { settings[key] = self.class.new }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# @api private
|
52
|
+
def writer?(name)
|
53
|
+
! WRITER_REGEXP.match(name).nil?
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def config
|
58
|
+
@config ||= Config.new
|
59
|
+
end
|
60
|
+
|
61
|
+
# @api public
|
62
|
+
def configure
|
63
|
+
yield(config)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/lib/rom/version.rb
CHANGED
@@ -12,15 +12,12 @@ describe 'Building up a command graph for nested input' do
|
|
12
12
|
|
13
13
|
setup.commands(:users) do
|
14
14
|
define(:create) do
|
15
|
-
input T(:accept_keys, [:name])
|
16
15
|
result :one
|
17
16
|
end
|
18
17
|
end
|
19
18
|
|
20
19
|
setup.commands(:books) do
|
21
20
|
define(:create) do
|
22
|
-
input T(:accept_keys, [:title, :user])
|
23
|
-
|
24
21
|
def execute(tuples, user)
|
25
22
|
super(tuples.map { |t| t.merge(user: user.fetch(:name)) })
|
26
23
|
end
|
@@ -29,8 +26,6 @@ describe 'Building up a command graph for nested input' do
|
|
29
26
|
|
30
27
|
setup.commands(:tags) do
|
31
28
|
define(:create) do
|
32
|
-
input T(:accept_keys, [:name, :task])
|
33
|
-
|
34
29
|
def execute(tuples, task)
|
35
30
|
super(tuples.map { |t| t.merge(task: task.fetch(:title)) })
|
36
31
|
end
|
@@ -41,7 +36,6 @@ describe 'Building up a command graph for nested input' do
|
|
41
36
|
it 'creates a command graph for nested input :one result as root' do
|
42
37
|
setup.commands(:tasks) do
|
43
38
|
define(:create) do
|
44
|
-
input T(:accept_keys, [:title, :user])
|
45
39
|
result :one
|
46
40
|
|
47
41
|
def execute(tuple, user)
|
@@ -102,8 +96,6 @@ describe 'Building up a command graph for nested input' do
|
|
102
96
|
it 'creates a command graph for nested input with :many results as root' do
|
103
97
|
setup.commands(:tasks) do
|
104
98
|
define(:create) do
|
105
|
-
input T(:accept_keys, [:title, :user])
|
106
|
-
|
107
99
|
def execute(tuples, user)
|
108
100
|
super(tuples.map { |t| t.merge(user: user.fetch(:name)) })
|
109
101
|
end
|
@@ -178,8 +170,6 @@ describe 'Building up a command graph for nested input' do
|
|
178
170
|
|
179
171
|
setup.commands(:tasks) do
|
180
172
|
define(:create) do
|
181
|
-
input T(:accept_keys, [:title, :user])
|
182
|
-
|
183
173
|
def execute(tuples, user)
|
184
174
|
super(tuples.map { |t| t.merge(user: user.fetch(:name)) })
|
185
175
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe 'Inheritance relation hierarchy' do
|
4
|
+
before do
|
5
|
+
ROM.setup(:memory)
|
6
|
+
|
7
|
+
module Test
|
8
|
+
class Users < ROM::Relation[:memory]
|
9
|
+
dataset :users
|
10
|
+
|
11
|
+
def by_email(email)
|
12
|
+
restrict(email: email)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class OtherUsers < Users
|
17
|
+
register_as :other_users
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
ROM.finalize
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'registers parent and descendant relations' do
|
25
|
+
rom = ROM.env
|
26
|
+
|
27
|
+
users = rom.relations.users
|
28
|
+
other_users = rom.relations.other_users
|
29
|
+
|
30
|
+
expect(users).to be_instance_of(Test::Users)
|
31
|
+
expect(other_users).to be_instance_of(Test::OtherUsers)
|
32
|
+
|
33
|
+
jane = { name: 'Jane', email: 'jane@doe.org' }
|
34
|
+
|
35
|
+
other_users.insert(jane)
|
36
|
+
|
37
|
+
expect(other_users.by_email('jane@doe.org').one).to eql(jane)
|
38
|
+
end
|
39
|
+
end
|
@@ -29,9 +29,51 @@ describe ROM::Relation do
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
describe
|
33
|
-
|
32
|
+
describe ".register_as" do
|
33
|
+
it "defaults to dataset with a generated class" do
|
34
|
+
rel = Class.new(ROM::Relation[:memory]) { dataset :users }
|
35
|
+
expect(rel.register_as).to eq(:users)
|
36
|
+
rel.register_as(:guests)
|
37
|
+
expect(rel.register_as).to eq(:guests)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "defaults to dataset with a defined class that has dataset inferred" do
|
41
|
+
class Test::Users < ROM::Relation[:memory]; end
|
42
|
+
expect(Test::Users.register_as).to eq(:test_users)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "defaults to dataset with a defined class that has dataset set manually" do
|
46
|
+
class Test::Users < ROM::Relation[:memory]
|
47
|
+
dataset :guests
|
48
|
+
end
|
49
|
+
expect(Test::Users.register_as).to eq(:guests)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "defaults to :name for descendant classes" do
|
53
|
+
class Test::SuperUsers < ROM::Relation[:memory]
|
54
|
+
dataset :users
|
55
|
+
end
|
56
|
+
|
57
|
+
class Test::DescendantUsers < Test::SuperUsers;end
|
58
|
+
|
59
|
+
expect(Test::DescendantUsers.register_as).to eq(:test_descendant_users)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "sets custom value for super and descendant classes" do
|
63
|
+
class Test::SuperUsers < ROM::Relation[:memory]
|
64
|
+
register_as :users
|
65
|
+
end
|
66
|
+
|
67
|
+
class Test::DescendantUsers < Test::SuperUsers
|
68
|
+
register_as :descendant_users
|
69
|
+
end
|
70
|
+
|
71
|
+
expect(Test::SuperUsers.register_as).to eq(:users)
|
72
|
+
expect(Test::DescendantUsers.register_as).to eq(:descendant_users)
|
73
|
+
end
|
74
|
+
end
|
34
75
|
|
76
|
+
describe '#name' do
|
35
77
|
context 'missing dataset' do
|
36
78
|
context 'with Relation inside module' do
|
37
79
|
before do
|
@@ -58,6 +100,19 @@ describe ROM::Relation do
|
|
58
100
|
expect(relation.name).to eq(:test_super_relation)
|
59
101
|
end
|
60
102
|
end
|
103
|
+
|
104
|
+
context 'with a descendant relation' do
|
105
|
+
before do
|
106
|
+
class Test::SuperRelation < ROM::Relation[:memory]; end
|
107
|
+
class Test::DescendantRelation < Test::SuperRelation; end
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'inherits :name from the super relation' do
|
111
|
+
relation = Test::DescendantRelation.new([])
|
112
|
+
|
113
|
+
expect(relation.name).to eql(:test_super_relation)
|
114
|
+
end
|
115
|
+
end
|
61
116
|
end
|
62
117
|
|
63
118
|
context 'manualy set dataset' do
|
@@ -93,29 +148,6 @@ describe ROM::Relation do
|
|
93
148
|
end
|
94
149
|
end
|
95
150
|
|
96
|
-
describe ".register_as" do
|
97
|
-
before { ROM.setup(:memory) }
|
98
|
-
|
99
|
-
it "defaults to dataset with a generated class" do
|
100
|
-
rel = Class.new(ROM::Relation[:memory]) { dataset :users }
|
101
|
-
expect(rel.register_as).to eq(:users)
|
102
|
-
rel.register_as(:guests)
|
103
|
-
expect(rel.register_as).to eq(:guests)
|
104
|
-
end
|
105
|
-
|
106
|
-
it "defaults to dataset with a defined class that has dataset inferred" do
|
107
|
-
class Test::Users < ROM::Relation[:memory]; end
|
108
|
-
expect(Test::Users.register_as).to eq(:test_users)
|
109
|
-
end
|
110
|
-
|
111
|
-
it "defaults to dataset with a defined class that has dataset set manually" do
|
112
|
-
class Test::Users < ROM::Relation[:memory]
|
113
|
-
dataset :guests
|
114
|
-
end
|
115
|
-
expect(Test::Users.register_as).to eq(:guests)
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
151
|
describe "#to_a" do
|
120
152
|
it "materializes relation to an array" do
|
121
153
|
expect(relation.to_a).to eql([jane, joe])
|
data/spec/unit/rom/setup_spec.rb
CHANGED
@@ -1,6 +1,46 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe ROM::Setup do
|
4
|
+
it 'is configurable' do
|
5
|
+
setup = ROM::Setup.new({})
|
6
|
+
|
7
|
+
setup.configure do |config|
|
8
|
+
config.sql.infer_relations = false
|
9
|
+
end
|
10
|
+
|
11
|
+
expect(setup.config.sql.infer_relations).to be(false)
|
12
|
+
expect(setup.config[:sql][:infer_relations]).to be(false)
|
13
|
+
|
14
|
+
expect(setup.config).to respond_to(:sql)
|
15
|
+
expect(setup.config).to respond_to(:other=)
|
16
|
+
|
17
|
+
setup.config.freeze
|
18
|
+
|
19
|
+
expect(setup.config.other).to be(nil)
|
20
|
+
expect(setup.config.key?(:other)).to be(false)
|
21
|
+
expect(setup.config.key?(:sql)).to be(true)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'is configurable via settings hash' do
|
25
|
+
setup = ROM.setup(:memory, 'something', infer_schema: false)
|
26
|
+
|
27
|
+
setup.finalize
|
28
|
+
|
29
|
+
expect(setup.config.gateways.default.infer_schema).to be(false)
|
30
|
+
|
31
|
+
setup = ROM.setup(:memory, infer_schema: false)
|
32
|
+
|
33
|
+
setup.finalize
|
34
|
+
|
35
|
+
expect(setup.config.gateways.default.infer_schema).to be(false)
|
36
|
+
|
37
|
+
setup = ROM.setup(default: [:memory, infer_schema: false])
|
38
|
+
|
39
|
+
setup.finalize
|
40
|
+
|
41
|
+
expect(setup.config.gateways.default.infer_schema).to be(false)
|
42
|
+
end
|
43
|
+
|
4
44
|
describe '#finalize' do
|
5
45
|
context 'with gateway that supports schema inferring' do
|
6
46
|
it 'builds relation from inferred schema' do
|
@@ -33,6 +73,62 @@ describe ROM::Setup do
|
|
33
73
|
expect(rom.relations.test_users).to be_instance_of(Test::Users)
|
34
74
|
end
|
35
75
|
|
76
|
+
it 'skips inferring when it is turned off for the adapter' do
|
77
|
+
setup = ROM.setup(:memory)
|
78
|
+
|
79
|
+
setup.configure { |config| config.gateways.default.infer_relations = false }
|
80
|
+
|
81
|
+
repo = setup.default
|
82
|
+
|
83
|
+
expect(repo).not_to receive(:schema)
|
84
|
+
|
85
|
+
setup.finalize
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'infers configured relations' do
|
89
|
+
setup = ROM.setup(:memory)
|
90
|
+
|
91
|
+
setup.configure do |config|
|
92
|
+
config.gateways.default.inferrable_relations = [:test_tasks]
|
93
|
+
end
|
94
|
+
|
95
|
+
repo = setup.default
|
96
|
+
dataset = double('dataset')
|
97
|
+
|
98
|
+
allow(repo).to receive(:schema).and_return([:test_tasks, :test_users])
|
99
|
+
|
100
|
+
expect(repo).to receive(:dataset).with(:test_tasks).and_return(dataset)
|
101
|
+
expect(repo).to_not receive(:dataset).with(:test_users)
|
102
|
+
|
103
|
+
rom = setup.finalize
|
104
|
+
|
105
|
+
expect(rom.relations.elements.key?(:test_users)).to be(false)
|
106
|
+
expect(rom.relations[:test_tasks]).to be_kind_of(ROM::Memory::Relation)
|
107
|
+
expect(rom.relations[:test_tasks].dataset).to be(dataset)
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'skip inferring blacklisted relations' do
|
111
|
+
setup = ROM.setup(:memory)
|
112
|
+
|
113
|
+
setup.configure do |config|
|
114
|
+
config.gateways.default.not_inferrable_relations = [:test_users]
|
115
|
+
end
|
116
|
+
|
117
|
+
repo = setup.default
|
118
|
+
dataset = double('dataset')
|
119
|
+
|
120
|
+
allow(repo).to receive(:schema).and_return([:test_tasks, :test_users])
|
121
|
+
|
122
|
+
expect(repo).to receive(:dataset).with(:test_tasks).and_return(dataset)
|
123
|
+
expect(repo).to_not receive(:dataset).with(:test_users)
|
124
|
+
|
125
|
+
rom = setup.finalize
|
126
|
+
|
127
|
+
expect(rom.relations.elements.key?(:test_users)).to be(false)
|
128
|
+
expect(rom.relations[:test_tasks]).to be_kind_of(ROM::Memory::Relation)
|
129
|
+
expect(rom.relations[:test_tasks].dataset).to be(dataset)
|
130
|
+
end
|
131
|
+
|
36
132
|
it 'can register multiple relations with same dataset' do
|
37
133
|
setup = ROM.setup(:memory)
|
38
134
|
|
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: 0.9.0.
|
4
|
+
version: 0.9.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Solnica
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-08-
|
11
|
+
date: 2015-08-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: transproc
|
@@ -147,6 +147,7 @@ files:
|
|
147
147
|
- lib/rom/commands/delete.rb
|
148
148
|
- lib/rom/commands/graph.rb
|
149
149
|
- lib/rom/commands/graph/class_interface.rb
|
150
|
+
- lib/rom/commands/graph/input_evaluator.rb
|
150
151
|
- lib/rom/commands/lazy.rb
|
151
152
|
- lib/rom/commands/result.rb
|
152
153
|
- lib/rom/commands/update.rb
|
@@ -192,6 +193,7 @@ files:
|
|
192
193
|
- lib/rom/setup_dsl/mapper_dsl.rb
|
193
194
|
- lib/rom/setup_dsl/relation.rb
|
194
195
|
- lib/rom/setup_dsl/setup.rb
|
196
|
+
- lib/rom/support/configurable.rb
|
195
197
|
- lib/rom/version.rb
|
196
198
|
- rakelib/benchmark.rake
|
197
199
|
- rakelib/mutant.rake
|
@@ -223,6 +225,7 @@ files:
|
|
223
225
|
- spec/integration/mappers/unwrap_spec.rb
|
224
226
|
- spec/integration/mappers/wrap_spec.rb
|
225
227
|
- spec/integration/multi_repo_spec.rb
|
228
|
+
- spec/integration/relations/inheritance_spec.rb
|
226
229
|
- spec/integration/relations/reading_spec.rb
|
227
230
|
- spec/integration/relations/registry_dsl_spec.rb
|
228
231
|
- spec/integration/repositories/extending_relations_spec.rb
|