rom 0.6.0.beta3 → 0.6.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/.gitignore +1 -2
- data/CHANGELOG.md +2 -1
- data/Gemfile +1 -1
- data/lib/rom.rb +0 -2
- data/lib/rom/commands/abstract.rb +1 -1
- data/lib/rom/env.rb +9 -7
- data/lib/rom/memory/storage.rb +6 -1
- data/lib/rom/relation.rb +14 -134
- data/lib/rom/relation/class_interface.rb +180 -0
- data/lib/rom/relation/lazy.rb +1 -1
- data/lib/rom/relation/registry_reader.rb +1 -1
- data/lib/rom/setup/finalize.rb +1 -21
- data/lib/rom/version.rb +1 -1
- data/rakelib/benchmark.rake +3 -1
- data/rom.gemspec +2 -2
- data/spec/integration/mappers/deep_embedded_spec.rb +1 -1
- data/spec/integration/mappers/definition_dsl_spec.rb +8 -6
- data/spec/integration/mappers/embedded_spec.rb +2 -6
- data/spec/integration/mappers/group_spec.rb +4 -4
- data/spec/integration/mappers/prefixing_attributes_spec.rb +1 -1
- data/spec/integration/mappers/renaming_attributes_spec.rb +5 -3
- data/spec/integration/mappers/symbolizing_attributes_spec.rb +2 -2
- data/spec/integration/mappers/wrap_spec.rb +4 -4
- data/spec/integration/multi_repo_spec.rb +5 -1
- data/spec/integration/relations/reading_spec.rb +6 -14
- data/spec/integration/setup_spec.rb +3 -3
- data/spec/unit/rom/env_spec.rb +1 -1
- data/spec/unit/rom/relation/lazy_spec.rb +16 -4
- data/spec/unit/rom/setup_spec.rb +2 -2
- metadata +9 -4
- data/lib/rom/reader.rb +0 -174
- data/spec/unit/rom/reader_spec.rb +0 -146
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ea7e1a611937b1db33e9bb5f6495c116ff163bd
|
4
|
+
data.tar.gz: 98243b1e80fc05db0038fdeea7465a7b913990f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fde6f6d9efc44fe43c2bffefdfcf809e6f7d3991a4059185ac58909c3455c3e821dda71843503c3a4c31f36178eaff0454ef48c2d71c4ae1106beb30f95623c0
|
7
|
+
data.tar.gz: 1fa7191e19578e32cfc72c71db3eeebb7a28a7410dd98db8064af3f19f85bfa19e7397f22d46c86eaf42013943a91cc7f754f89fd2f62e96f6de12737fc7e7c9
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -20,8 +20,9 @@
|
|
20
20
|
|
21
21
|
### Changed
|
22
22
|
|
23
|
-
* [BREAKING] Command API was simplified - commands should be accessed directly in `.try` block (solnic)
|
24
23
|
* [BREAKING] Schema DSL was **removed** - attributes can be specified only in mapper DSL
|
24
|
+
* [BREAKING] Reader was **removed** in favor of relation interface with explicit mapping (solnic)
|
25
|
+
* [BREAKING] Command API was simplified - commands should be accessed directly in `.try` block (solnic)
|
25
26
|
and default repository can be changed when defining a relation (solnic)
|
26
27
|
* `.setup` interface requires either an adapter identifier or can accept a repository
|
27
28
|
instance (aflatter)
|
data/Gemfile
CHANGED
data/lib/rom.rb
CHANGED
@@ -13,7 +13,6 @@ require 'rom/support/class_builder'
|
|
13
13
|
# core parts
|
14
14
|
require 'rom/relation'
|
15
15
|
require 'rom/mapper'
|
16
|
-
require 'rom/reader'
|
17
16
|
require 'rom/command'
|
18
17
|
|
19
18
|
# default mapper processor using Transproc gem
|
@@ -33,5 +32,4 @@ module ROM
|
|
33
32
|
extend Global
|
34
33
|
|
35
34
|
RelationRegistry = Class.new(Registry)
|
36
|
-
ReaderRegistry = Class.new(Registry)
|
37
35
|
end
|
data/lib/rom/env.rb
CHANGED
@@ -88,15 +88,17 @@ module ROM
|
|
88
88
|
#
|
89
89
|
# @param [Symbol] name of the registered reader
|
90
90
|
#
|
91
|
+
# @deprecated
|
92
|
+
#
|
91
93
|
# @api public
|
92
94
|
def read(name, &block)
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
95
|
+
warn <<-MSG
|
96
|
+
#{self.class}#read is deprecated.
|
97
|
+
Please use `#{self.class}#relation(#{name.inspect})` instead.
|
98
|
+
For mapping append `.map_with(:your_mapper_name)`
|
99
|
+
[#{caller[0]}]
|
100
|
+
MSG
|
101
|
+
relation(name, &block)
|
100
102
|
end
|
101
103
|
|
102
104
|
# Returns commands registry for the given relation
|
data/lib/rom/memory/storage.rb
CHANGED
data/lib/rom/relation.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require '
|
2
|
-
|
1
|
+
require 'rom/relation/class_interface'
|
2
|
+
|
3
3
|
require 'rom/relation/lazy'
|
4
4
|
require 'rom/relation/curried'
|
5
5
|
|
@@ -19,147 +19,26 @@ module ROM
|
|
19
19
|
#
|
20
20
|
# @api public
|
21
21
|
class Relation
|
22
|
-
extend
|
22
|
+
extend ClassInterface
|
23
23
|
|
24
24
|
include Options
|
25
25
|
include Equalizer.new(:dataset)
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
repository :default
|
30
|
-
|
31
|
-
attr_reader :name, :dataset, :exposed_relations
|
32
|
-
|
33
|
-
# Register adapter relation subclasses during setup phase
|
34
|
-
#
|
35
|
-
# In adition those subclasses are extended with an interface for accessing
|
36
|
-
# relation registry and to define `register_as` setting
|
37
|
-
#
|
38
|
-
# @api private
|
39
|
-
def self.inherited(klass)
|
40
|
-
super
|
41
|
-
|
42
|
-
return if self == ROM::Relation
|
43
|
-
|
44
|
-
klass.class_eval do
|
45
|
-
include ROM::Relation::RegistryReader
|
46
|
-
|
47
|
-
dataset(default_name)
|
48
|
-
exposed_relations Set.new
|
49
|
-
|
50
|
-
def self.register_as(value = Undefined)
|
51
|
-
if value == Undefined
|
52
|
-
@register_as || dataset
|
53
|
-
else
|
54
|
-
super
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def self.method_added(name)
|
59
|
-
super
|
60
|
-
exposed_relations << name if public_instance_methods.include?(name)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
ROM.register_relation(klass)
|
65
|
-
end
|
66
|
-
|
67
|
-
# Return adapter-specific relation subclass
|
68
|
-
#
|
69
|
-
# @example
|
70
|
-
# ROM::Relation[:memory]
|
71
|
-
# # => ROM::Memory::Relation
|
27
|
+
# Dataset used by the relation
|
72
28
|
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
# @api public
|
76
|
-
def self.[](type)
|
77
|
-
ROM.adapters.fetch(type).const_get(:Relation)
|
78
|
-
end
|
79
|
-
|
80
|
-
# Dynamically define a method that will forward to the dataset and wrap
|
81
|
-
# response in the relation itself
|
82
|
-
#
|
83
|
-
# @example
|
84
|
-
# class SomeAdapterRelation < ROM::Relation
|
85
|
-
# forward :super_query
|
86
|
-
# end
|
87
|
-
#
|
88
|
-
# @api public
|
89
|
-
def self.forward(*methods)
|
90
|
-
methods.each do |method|
|
91
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
92
|
-
def #{method}(*args, &block)
|
93
|
-
__new__(dataset.__send__(:#{method}, *args, &block))
|
94
|
-
end
|
95
|
-
RUBY
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
# Return default relation name used for `register_as` setting
|
29
|
+
# This object is provided by the repository during the setup
|
100
30
|
#
|
101
|
-
# @return [
|
31
|
+
# @return [Object]
|
102
32
|
#
|
103
33
|
# @api private
|
104
|
-
|
105
|
-
return unless name
|
106
|
-
Inflector.underscore(name).gsub('/', '_').to_sym
|
107
|
-
end
|
108
|
-
|
109
|
-
# Build relation registry of specified descendant classes
|
110
|
-
#
|
111
|
-
# This is used by the setup
|
112
|
-
#
|
113
|
-
# @param [Hash] repositories
|
114
|
-
# @param [Array] descendants a list of relation descendants
|
115
|
-
#
|
116
|
-
# @return [Hash]
|
117
|
-
#
|
118
|
-
# @api private
|
119
|
-
def self.registry(repositories, descendants)
|
120
|
-
registry = {}
|
121
|
-
|
122
|
-
descendants.each do |klass|
|
123
|
-
# TODO: raise a meaningful error here and add spec covering the case
|
124
|
-
# where klass' repository points to non-existant repo
|
125
|
-
repository = repositories.fetch(klass.repository)
|
126
|
-
dataset = repository.dataset(klass.dataset)
|
127
|
-
|
128
|
-
relation = klass.new(dataset, __registry__: registry)
|
129
|
-
|
130
|
-
name = klass.register_as
|
131
|
-
|
132
|
-
if registry.key?(name)
|
133
|
-
raise RelationAlreadyDefinedError,
|
134
|
-
"Relation with `register_as #{name.inspect}` registered more " \
|
135
|
-
"than once"
|
136
|
-
end
|
137
|
-
|
138
|
-
registry[name] = relation
|
139
|
-
end
|
140
|
-
|
141
|
-
registry.each_value do |relation|
|
142
|
-
relation.class.finalize(registry, relation)
|
143
|
-
end
|
144
|
-
|
145
|
-
registry
|
146
|
-
end
|
34
|
+
attr_reader :dataset
|
147
35
|
|
148
36
|
# @api private
|
149
37
|
def initialize(dataset, options = {})
|
150
38
|
@dataset = dataset
|
151
|
-
@name = self.class.dataset
|
152
|
-
@exposed_relations = self.class.exposed_relations
|
153
39
|
super
|
154
40
|
end
|
155
41
|
|
156
|
-
# Hook to finalize a relation after its instance was created
|
157
|
-
#
|
158
|
-
# @api private
|
159
|
-
def self.finalize(_env, _relation)
|
160
|
-
# noop
|
161
|
-
end
|
162
|
-
|
163
42
|
# Yield dataset tuples
|
164
43
|
#
|
165
44
|
# @yield [Hash]
|
@@ -170,7 +49,7 @@ module ROM
|
|
170
49
|
dataset.each { |tuple| yield(tuple) }
|
171
50
|
end
|
172
51
|
|
173
|
-
# Materialize relation into an array
|
52
|
+
# Materialize a relation into an array
|
174
53
|
#
|
175
54
|
# @return [Array<Hash>]
|
176
55
|
#
|
@@ -179,11 +58,12 @@ module ROM
|
|
179
58
|
to_enum.to_a
|
180
59
|
end
|
181
60
|
|
182
|
-
#
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
61
|
+
# Turn relation into a lazy-loadable and composable relation
|
62
|
+
#
|
63
|
+
# @see Lazy
|
64
|
+
#
|
65
|
+
# @return [Lazy]
|
66
|
+
#
|
187
67
|
# @api public
|
188
68
|
def to_lazy(*args)
|
189
69
|
Lazy.new(self, *args)
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'rom/relation/registry_reader'
|
3
|
+
|
4
|
+
module ROM
|
5
|
+
class Relation
|
6
|
+
module ClassInterface
|
7
|
+
# Register adapter relation subclasses during setup phase
|
8
|
+
#
|
9
|
+
# In adition those subclasses are extended with an interface for accessing
|
10
|
+
# relation registry and to define `register_as` setting
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
def inherited(klass)
|
14
|
+
super
|
15
|
+
|
16
|
+
return if klass.superclass == ROM::Relation
|
17
|
+
|
18
|
+
klass.class_eval do
|
19
|
+
extend ClassMacros
|
20
|
+
include RegistryReader
|
21
|
+
|
22
|
+
defines :repository, :dataset, :register_as, :exposed_relations
|
23
|
+
|
24
|
+
repository :default
|
25
|
+
|
26
|
+
dataset(default_name)
|
27
|
+
exposed_relations Set.new
|
28
|
+
|
29
|
+
# Relation's dataset name
|
30
|
+
#
|
31
|
+
# In example a table name in an SQL database
|
32
|
+
#
|
33
|
+
# @return [Symbol]
|
34
|
+
#
|
35
|
+
# @api public
|
36
|
+
attr_reader :name
|
37
|
+
|
38
|
+
# A set with public method names that return "virtual" relations
|
39
|
+
#
|
40
|
+
# Only those methods are exposed directly on relations return by
|
41
|
+
# Env#relation interface
|
42
|
+
#
|
43
|
+
# @return [Set]
|
44
|
+
#
|
45
|
+
# @api private
|
46
|
+
attr_reader :exposed_relations
|
47
|
+
|
48
|
+
# Set or get name under which a relation will be registered
|
49
|
+
#
|
50
|
+
# This defaults to `dataset` name
|
51
|
+
#
|
52
|
+
# @return [Symbol]
|
53
|
+
#
|
54
|
+
# @api public
|
55
|
+
def self.register_as(value = Undefined)
|
56
|
+
if value == Undefined
|
57
|
+
super() || dataset
|
58
|
+
else
|
59
|
+
super
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Hook used to collect public method names
|
64
|
+
#
|
65
|
+
# @api private
|
66
|
+
def self.method_added(name)
|
67
|
+
super
|
68
|
+
exposed_relations << name if public_instance_methods.include?(name)
|
69
|
+
end
|
70
|
+
|
71
|
+
# @api private
|
72
|
+
def initialize(dataset, options = {})
|
73
|
+
@name = self.class.dataset
|
74
|
+
@exposed_relations = self.class.exposed_relations
|
75
|
+
super
|
76
|
+
end
|
77
|
+
|
78
|
+
# Return name of the source repository of this relation
|
79
|
+
#
|
80
|
+
# @return [Symbol]
|
81
|
+
#
|
82
|
+
# @api private
|
83
|
+
def repository
|
84
|
+
self.class.repository
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
ROM.register_relation(klass)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Return adapter-specific relation subclass
|
92
|
+
#
|
93
|
+
# @example
|
94
|
+
# ROM::Relation[:memory]
|
95
|
+
# # => ROM::Memory::Relation
|
96
|
+
#
|
97
|
+
# @return [Class]
|
98
|
+
#
|
99
|
+
# @api public
|
100
|
+
def [](type)
|
101
|
+
ROM.adapters.fetch(type).const_get(:Relation)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Dynamically define a method that will forward to the dataset and wrap
|
105
|
+
# response in the relation itself
|
106
|
+
#
|
107
|
+
# @example
|
108
|
+
# class SomeAdapterRelation < ROM::Relation
|
109
|
+
# forward :super_query
|
110
|
+
# end
|
111
|
+
#
|
112
|
+
# @api public
|
113
|
+
def forward(*methods)
|
114
|
+
methods.each do |method|
|
115
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
116
|
+
def #{method}(*args, &block)
|
117
|
+
__new__(dataset.__send__(:#{method}, *args, &block))
|
118
|
+
end
|
119
|
+
RUBY
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Return default relation name used for `register_as` setting
|
124
|
+
#
|
125
|
+
# @return [Symbol]
|
126
|
+
#
|
127
|
+
# @api private
|
128
|
+
def default_name
|
129
|
+
return unless name
|
130
|
+
Inflector.underscore(name).gsub('/', '_').to_sym
|
131
|
+
end
|
132
|
+
|
133
|
+
# Build relation registry of specified descendant classes
|
134
|
+
#
|
135
|
+
# This is used by the setup
|
136
|
+
#
|
137
|
+
# @param [Hash] repositories
|
138
|
+
# @param [Array] descendants a list of relation descendants
|
139
|
+
#
|
140
|
+
# @return [Hash]
|
141
|
+
#
|
142
|
+
# @api private
|
143
|
+
def registry(repositories, descendants)
|
144
|
+
registry = {}
|
145
|
+
|
146
|
+
descendants.each do |klass|
|
147
|
+
# TODO: raise a meaningful error here and add spec covering the case
|
148
|
+
# where klass' repository points to non-existant repo
|
149
|
+
repository = repositories.fetch(klass.repository)
|
150
|
+
dataset = repository.dataset(klass.dataset)
|
151
|
+
|
152
|
+
relation = klass.new(dataset, __registry__: registry)
|
153
|
+
|
154
|
+
name = klass.register_as
|
155
|
+
|
156
|
+
if registry.key?(name)
|
157
|
+
raise RelationAlreadyDefinedError,
|
158
|
+
"Relation with `register_as #{name.inspect}` registered more " \
|
159
|
+
"than once"
|
160
|
+
end
|
161
|
+
|
162
|
+
registry[name] = relation
|
163
|
+
end
|
164
|
+
|
165
|
+
registry.each_value do |relation|
|
166
|
+
relation.class.finalize(registry, relation)
|
167
|
+
end
|
168
|
+
|
169
|
+
registry
|
170
|
+
end
|
171
|
+
|
172
|
+
# Hook to finalize a relation after its instance was created
|
173
|
+
#
|
174
|
+
# @api private
|
175
|
+
def finalize(_env, _relation)
|
176
|
+
# noop
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|