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
data/spec/unit/rom/setup_spec.rb
CHANGED
@@ -101,8 +101,8 @@ describe ROM::Setup do
|
|
101
101
|
expect(env.relations).to eql(ROM::RelationRegistry.new)
|
102
102
|
end
|
103
103
|
|
104
|
-
it 'builds empty
|
105
|
-
expect(env.
|
104
|
+
it 'builds empty mappers' do
|
105
|
+
expect(env.mappers).to eql(ROM::Registry.new)
|
106
106
|
end
|
107
107
|
|
108
108
|
it 'builds empty commands' do
|
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.6.0.
|
4
|
+
version: 0.6.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-03-
|
11
|
+
date: 2015-03-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: transproc
|
@@ -17,6 +17,9 @@ dependencies:
|
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0.1'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.1.2
|
20
23
|
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -24,6 +27,9 @@ dependencies:
|
|
24
27
|
- - "~>"
|
25
28
|
- !ruby/object:Gem::Version
|
26
29
|
version: '0.1'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.1.2
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
34
|
name: equalizer
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -152,8 +158,8 @@ files:
|
|
152
158
|
- lib/rom/model_builder.rb
|
153
159
|
- lib/rom/processor.rb
|
154
160
|
- lib/rom/processor/transproc.rb
|
155
|
-
- lib/rom/reader.rb
|
156
161
|
- lib/rom/relation.rb
|
162
|
+
- lib/rom/relation/class_interface.rb
|
157
163
|
- lib/rom/relation/composite.rb
|
158
164
|
- lib/rom/relation/curried.rb
|
159
165
|
- lib/rom/relation/lazy.rb
|
@@ -220,7 +226,6 @@ files:
|
|
220
226
|
- spec/unit/rom/memory/storage_spec.rb
|
221
227
|
- spec/unit/rom/model_builder_spec.rb
|
222
228
|
- spec/unit/rom/processor/transproc_spec.rb
|
223
|
-
- spec/unit/rom/reader_spec.rb
|
224
229
|
- spec/unit/rom/registry_spec.rb
|
225
230
|
- spec/unit/rom/relation/composite_spec.rb
|
226
231
|
- spec/unit/rom/relation/lazy_spec.rb
|
data/lib/rom/reader.rb
DELETED
@@ -1,174 +0,0 @@
|
|
1
|
-
module ROM
|
2
|
-
# Exposes mapped tuples via enumerable interface
|
3
|
-
#
|
4
|
-
# See example for each method
|
5
|
-
#
|
6
|
-
# @api public
|
7
|
-
class Reader
|
8
|
-
include Enumerable
|
9
|
-
include Equalizer.new(:path, :relation, :mapper)
|
10
|
-
|
11
|
-
# Map relation to an array using a mapper
|
12
|
-
#
|
13
|
-
# @return [Array]
|
14
|
-
#
|
15
|
-
# @api public
|
16
|
-
alias_method :to_ary, :to_a
|
17
|
-
|
18
|
-
# @return [String] access path used to read a relation
|
19
|
-
#
|
20
|
-
# @api private
|
21
|
-
attr_reader :path
|
22
|
-
|
23
|
-
# @return [Relation] relation used by the reader
|
24
|
-
#
|
25
|
-
# @api private
|
26
|
-
attr_reader :relation
|
27
|
-
|
28
|
-
# @return [MapperRegistry] registry of mappers used by the reader
|
29
|
-
#
|
30
|
-
# @api private
|
31
|
-
attr_reader :mappers
|
32
|
-
|
33
|
-
# @return [Mapper] mapper to read the relation
|
34
|
-
#
|
35
|
-
# @api private
|
36
|
-
attr_reader :mapper
|
37
|
-
|
38
|
-
# Builds a reader instance for the provided relation
|
39
|
-
#
|
40
|
-
# @param [Symbol] name of the root relation
|
41
|
-
# @param [Relation] relation that the reader will use
|
42
|
-
# @param [MapperRegistry] mappers registry of mappers
|
43
|
-
# @param [Array<Symbol>] method_names a list of method names exposed by the relation
|
44
|
-
#
|
45
|
-
# @return [Reader]
|
46
|
-
#
|
47
|
-
# @api private
|
48
|
-
def self.build(name, relation, mappers, method_names = [])
|
49
|
-
klass = build_class(relation, method_names)
|
50
|
-
klass.new(name, relation, mappers)
|
51
|
-
end
|
52
|
-
|
53
|
-
# Build a reader subclass for the relation
|
54
|
-
#
|
55
|
-
# This method defines public methods on the class narrowing down data access
|
56
|
-
# only to the methods exposed by a given relation
|
57
|
-
#
|
58
|
-
# @param [Relation] relation that the reader will use
|
59
|
-
# @param [Array<Symbol>] method_names a list of method names exposed by the relation
|
60
|
-
#
|
61
|
-
# @return [Class]
|
62
|
-
#
|
63
|
-
# @api private
|
64
|
-
def self.build_class(relation, method_names)
|
65
|
-
klass_name = "#{Reader.name}[#{Inflector.camelize(relation.name)}]"
|
66
|
-
|
67
|
-
ClassBuilder.new(name: klass_name, parent: Reader).call do |klass|
|
68
|
-
method_names.each do |method_name|
|
69
|
-
klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
70
|
-
def #{method_name}(*args, &block)
|
71
|
-
new_relation = relation.send(#{method_name.inspect}, *args, &block)
|
72
|
-
self.class.new(
|
73
|
-
new_path(#{method_name.to_s.inspect}), new_relation, mappers
|
74
|
-
)
|
75
|
-
end
|
76
|
-
RUBY
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
# @api private
|
82
|
-
def initialize(path, relation, mappers, mapper = nil)
|
83
|
-
@path = path.to_s
|
84
|
-
@relation = relation
|
85
|
-
@mappers = mappers
|
86
|
-
@mapper = mapper || mappers.by_path(@path)
|
87
|
-
end
|
88
|
-
|
89
|
-
# @api private
|
90
|
-
def header
|
91
|
-
mapper.header
|
92
|
-
end
|
93
|
-
|
94
|
-
# Yields tuples mapped to objects
|
95
|
-
#
|
96
|
-
# @example
|
97
|
-
#
|
98
|
-
# # accessing root relation
|
99
|
-
# rom.read(:users).each { |user| # ... }
|
100
|
-
#
|
101
|
-
# # accessing virtual relations
|
102
|
-
# rom.read(:users).adults.recent.active.each { |user| # ... }
|
103
|
-
#
|
104
|
-
# @api public
|
105
|
-
def each
|
106
|
-
mapper.call(relation).each { |tuple| yield(tuple) }
|
107
|
-
end
|
108
|
-
|
109
|
-
# Returns a single tuple from the relation if there is one.
|
110
|
-
#
|
111
|
-
# @raise [ROM::TupleCountMismatchError] if the relation contains more than
|
112
|
-
# one tuple
|
113
|
-
#
|
114
|
-
# @api public
|
115
|
-
def one
|
116
|
-
if relation.count > 1
|
117
|
-
raise(
|
118
|
-
TupleCountMismatchError,
|
119
|
-
'The relation consists of more than one tuple'
|
120
|
-
)
|
121
|
-
else
|
122
|
-
mapper.call(relation).first
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
# Like [one], but additionally raises an error if the relation is empty.
|
127
|
-
#
|
128
|
-
# @raise [ROM::TupleCountMismatchError] if the relation does not contain
|
129
|
-
# exactly one tuple
|
130
|
-
#
|
131
|
-
# @api public
|
132
|
-
def one!
|
133
|
-
one || raise(
|
134
|
-
TupleCountMismatchError,
|
135
|
-
'The relation does not contain any tuples'
|
136
|
-
)
|
137
|
-
end
|
138
|
-
|
139
|
-
# Map tuples using a specific mapper if name is provided
|
140
|
-
#
|
141
|
-
# Defaults to Enumerable#map behavior
|
142
|
-
#
|
143
|
-
# @example
|
144
|
-
#
|
145
|
-
# rom.read(:users).map(:my_mapper_name)
|
146
|
-
# rom.read(:users).map { |user| ... }
|
147
|
-
#
|
148
|
-
# @return [Array,Reader]
|
149
|
-
#
|
150
|
-
# @api public
|
151
|
-
def map(*args)
|
152
|
-
if args.any?
|
153
|
-
mappers[args[0]].call(relation)
|
154
|
-
else
|
155
|
-
super
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
private
|
160
|
-
|
161
|
-
# @api private
|
162
|
-
def method_missing(name, *)
|
163
|
-
raise(
|
164
|
-
NoRelationError,
|
165
|
-
"undefined relation #{name.inspect} within #{path.inspect}"
|
166
|
-
)
|
167
|
-
end
|
168
|
-
|
169
|
-
# @api private
|
170
|
-
def new_path(name)
|
171
|
-
path.dup << ".#{name}"
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|
@@ -1,146 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe ROM::Reader do
|
4
|
-
subject(:reader) { ROM::Reader.new(name, relation, mappers) }
|
5
|
-
|
6
|
-
let(:name) { :users }
|
7
|
-
let(:relation) { [jane, joe] }
|
8
|
-
let(:jane) { { name: 'Jane' } }
|
9
|
-
let(:joe) { { name: 'Joe' } }
|
10
|
-
let(:mappers) { ROM::MapperRegistry.new(users: mapper) }
|
11
|
-
let(:mapper) { double('mapper', header: []) }
|
12
|
-
|
13
|
-
describe '.build' do
|
14
|
-
subject(:reader) do
|
15
|
-
ROM::Reader.build(name, relation, mappers, [:all])
|
16
|
-
end
|
17
|
-
|
18
|
-
before do
|
19
|
-
relation.instance_exec do
|
20
|
-
def name
|
21
|
-
'users'
|
22
|
-
end
|
23
|
-
|
24
|
-
def all(*_args)
|
25
|
-
find_all
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'sets reader class name' do
|
31
|
-
expect(reader.class.name).to eql("ROM::Reader[Users]")
|
32
|
-
end
|
33
|
-
|
34
|
-
it 'defines methods from relation' do
|
35
|
-
block = proc {}
|
36
|
-
|
37
|
-
user_id = 1
|
38
|
-
|
39
|
-
expect(relation).to receive(:all)
|
40
|
-
.with(user_id, &block)
|
41
|
-
.and_return([joe])
|
42
|
-
|
43
|
-
expect(mapper).to receive(:call)
|
44
|
-
.with([joe])
|
45
|
-
.and_return([joe])
|
46
|
-
|
47
|
-
result = reader.all(user_id, &block)
|
48
|
-
|
49
|
-
expect(result.path).to eql('users.all')
|
50
|
-
expect(result.to_a).to eql([joe])
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'raises error when relation does not respond to the method' do
|
54
|
-
expect { reader.not_here }
|
55
|
-
.to raise_error(ROM::NoRelationError, /not_here/)
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'raises error when relation does not respond to the method with args' do
|
59
|
-
expect { reader.find_by_id(1) }
|
60
|
-
.to raise_error(ROM::NoRelationError, /find_by_id/)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
describe '#initialize' do
|
65
|
-
it 'raises error when mapper cannot be found' do
|
66
|
-
expect { ROM::Reader.new(:not_here, relation, mappers) }
|
67
|
-
.to raise_error(ROM::MapperMissingError, /not_here/)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
describe '#each' do
|
72
|
-
it 'yields mapped tuples from relations' do
|
73
|
-
expect(mapper).to receive(:call)
|
74
|
-
.with(relation)
|
75
|
-
.and_return(relation)
|
76
|
-
|
77
|
-
result = []
|
78
|
-
reader.each { |user| result << user }
|
79
|
-
expect(result).to eql([jane, joe])
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
shared_examples_for 'one and one!' do |method|
|
84
|
-
context 'with a single tuple' do
|
85
|
-
let(:relation) { [jane] }
|
86
|
-
|
87
|
-
it 'returns a single tuple' do
|
88
|
-
expect(mapper).to receive(:call)
|
89
|
-
.with(relation)
|
90
|
-
.and_return(relation)
|
91
|
-
|
92
|
-
expect(reader.public_send(method)).to eql(jane)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
context 'with more than one tuple' do
|
97
|
-
it 'raises an error' do
|
98
|
-
expect { reader.public_send(method) }
|
99
|
-
.to raise_error(ROM::TupleCountMismatchError)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
describe '#one' do
|
105
|
-
it_should_behave_like 'one and one!', :one
|
106
|
-
|
107
|
-
context 'without any tuple' do
|
108
|
-
let(:relation) { [] }
|
109
|
-
|
110
|
-
it 'returns nil' do
|
111
|
-
expect(mapper).to receive(:call)
|
112
|
-
.with(relation)
|
113
|
-
.and_return(relation)
|
114
|
-
|
115
|
-
expect(reader.one).to be_nil
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
describe '#one!' do
|
121
|
-
it_should_behave_like 'one and one!', :one!
|
122
|
-
|
123
|
-
context 'without any tuple' do
|
124
|
-
let(:relation) { [] }
|
125
|
-
|
126
|
-
it 'raises an error' do
|
127
|
-
expect(mapper).to receive(:call)
|
128
|
-
.with(relation)
|
129
|
-
.and_return(relation)
|
130
|
-
|
131
|
-
expect { reader.one! }.to raise_error(ROM::TupleCountMismatchError)
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
describe '#to_ary' do
|
137
|
-
it 'casts relation to an array with loaded objects' do
|
138
|
-
expect(mapper).to receive(:call)
|
139
|
-
.with(relation)
|
140
|
-
.and_return(relation)
|
141
|
-
|
142
|
-
result = reader.to_ary
|
143
|
-
expect(result).to eql(relation)
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|