rom 0.6.0.beta3 → 0.6.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|