rom 0.5.0 → 0.6.0.beta1
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/.rubocop.yml +19 -15
- data/.rubocop_todo.yml +28 -0
- data/.travis.yml +8 -1
- data/CHANGELOG.md +40 -0
- data/Gemfile +10 -2
- data/Guardfile +12 -10
- data/README.md +42 -43
- data/Rakefile +13 -23
- data/lib/rom.rb +19 -27
- data/lib/rom/command.rb +118 -0
- data/lib/rom/command_registry.rb +13 -27
- data/lib/rom/commands.rb +1 -59
- data/lib/rom/commands/abstract.rb +147 -0
- data/lib/rom/commands/composite.rb +47 -0
- data/lib/rom/commands/create.rb +2 -17
- data/lib/rom/commands/delete.rb +5 -25
- data/lib/rom/commands/result.rb +5 -5
- data/lib/rom/commands/update.rb +3 -27
- data/lib/rom/constants.rb +19 -0
- data/lib/rom/env.rb +85 -35
- data/lib/rom/global.rb +173 -42
- data/lib/rom/header.rb +5 -5
- data/lib/rom/header/attribute.rb +2 -2
- data/lib/rom/lint/enumerable_dataset.rb +52 -0
- data/lib/rom/lint/linter.rb +64 -0
- data/lib/rom/lint/repository.rb +78 -0
- data/lib/rom/lint/spec.rb +20 -0
- data/lib/rom/lint/test.rb +98 -0
- data/lib/rom/mapper.rb +32 -5
- data/lib/rom/mapper/attribute_dsl.rb +240 -0
- data/lib/rom/mapper/dsl.rb +100 -0
- data/lib/rom/mapper/model_dsl.rb +55 -0
- data/lib/rom/mapper_registry.rb +8 -1
- data/lib/rom/memory.rb +4 -0
- data/lib/rom/memory/commands.rb +46 -0
- data/lib/rom/memory/dataset.rb +72 -0
- data/lib/rom/memory/relation.rb +44 -0
- data/lib/rom/memory/repository.rb +62 -0
- data/lib/rom/memory/storage.rb +57 -0
- data/lib/rom/model_builder.rb +44 -5
- data/lib/rom/processor.rb +1 -1
- data/lib/rom/processor/transproc.rb +109 -16
- data/lib/rom/reader.rb +91 -39
- data/lib/rom/relation.rb +165 -26
- data/lib/rom/relation/composite.rb +132 -0
- data/lib/rom/relation/curried.rb +48 -0
- data/lib/rom/relation/lazy.rb +173 -0
- data/lib/rom/relation/loaded.rb +75 -0
- data/lib/rom/relation/registry_reader.rb +23 -0
- data/lib/rom/repository.rb +93 -34
- data/lib/rom/setup.rb +54 -98
- data/lib/rom/setup/finalize.rb +85 -76
- data/lib/rom/setup_dsl/command.rb +36 -0
- data/lib/rom/setup_dsl/command_dsl.rb +34 -0
- data/lib/rom/setup_dsl/mapper.rb +32 -0
- data/lib/rom/setup_dsl/mapper_dsl.rb +30 -0
- data/lib/rom/setup_dsl/relation.rb +21 -0
- data/lib/rom/setup_dsl/setup.rb +75 -0
- data/lib/rom/support/array_dataset.rb +38 -0
- data/lib/rom/support/class_builder.rb +44 -0
- data/lib/rom/support/class_macros.rb +56 -0
- data/lib/rom/support/data_proxy.rb +102 -0
- data/lib/rom/support/enumerable_dataset.rb +58 -0
- data/lib/rom/support/inflector.rb +73 -0
- data/lib/rom/support/options.rb +188 -0
- data/lib/rom/support/registry.rb +4 -8
- data/lib/rom/version.rb +1 -1
- data/rakelib/benchmark.rake +13 -0
- data/rakelib/mutant.rake +16 -0
- data/rakelib/rubocop.rake +18 -0
- data/rom.gemspec +4 -7
- data/spec/integration/commands/create_spec.rb +32 -24
- data/spec/integration/commands/delete_spec.rb +15 -7
- data/spec/integration/commands/update_spec.rb +13 -11
- data/spec/integration/mappers/deep_embedded_spec.rb +4 -11
- data/spec/integration/mappers/definition_dsl_spec.rb +31 -44
- data/spec/integration/mappers/embedded_spec.rb +9 -24
- data/spec/integration/mappers/group_spec.rb +22 -30
- data/spec/integration/mappers/prefixing_attributes_spec.rb +18 -23
- data/spec/integration/mappers/renaming_attributes_spec.rb +23 -38
- data/spec/integration/mappers/symbolizing_attributes_spec.rb +18 -24
- data/spec/integration/mappers/wrap_spec.rb +22 -30
- data/spec/integration/multi_repo_spec.rb +15 -37
- data/spec/integration/relations/reading_spec.rb +82 -14
- data/spec/integration/repositories/extending_relations_spec.rb +50 -0
- data/spec/integration/{adapters → repositories}/setting_logger_spec.rb +6 -5
- data/spec/integration/setup_spec.rb +59 -62
- data/spec/shared/enumerable_dataset.rb +49 -0
- data/spec/shared/one_behavior.rb +26 -0
- data/spec/shared/users_and_tasks.rb +11 -23
- data/spec/spec_helper.rb +16 -7
- data/spec/support/constant_leak_finder.rb +14 -0
- data/spec/test/memory_repository_lint_test.rb +27 -0
- data/spec/unit/rom/command_registry_spec.rb +44 -0
- data/spec/unit/rom/commands/result_spec.rb +14 -0
- data/spec/unit/rom/commands_spec.rb +174 -0
- data/spec/unit/rom/env_spec.rb +40 -7
- data/spec/unit/rom/global_spec.rb +14 -0
- data/spec/unit/rom/{mapper_builder_spec.rb → mapper/dsl_spec.rb} +52 -38
- data/spec/unit/rom/mapper_spec.rb +51 -10
- data/spec/unit/rom/{adapter/memory → memory}/dataset_spec.rb +6 -4
- data/spec/unit/rom/memory/repository_spec.rb +12 -0
- data/spec/unit/rom/memory/storage_spec.rb +45 -0
- data/spec/unit/rom/model_builder_spec.rb +4 -3
- data/spec/unit/rom/processor/transproc_spec.rb +1 -0
- data/spec/unit/rom/reader_spec.rb +97 -24
- data/spec/unit/rom/relation/composite_spec.rb +65 -0
- data/spec/unit/rom/relation/lazy_spec.rb +145 -0
- data/spec/unit/rom/relation/loaded_spec.rb +28 -0
- data/spec/unit/rom/relation_spec.rb +111 -6
- data/spec/unit/rom/repository_spec.rb +59 -9
- data/spec/unit/rom/setup_spec.rb +99 -11
- data/spec/unit/rom/support/array_dataset_spec.rb +59 -0
- data/spec/unit/rom/support/class_builder_spec.rb +42 -0
- data/spec/unit/rom/support/enumerable_dataset_spec.rb +17 -0
- data/spec/unit/rom/support/inflector_spec.rb +89 -0
- data/spec/unit/rom/support/options_spec.rb +119 -0
- metadata +74 -112
- data/lib/rom/adapter.rb +0 -191
- data/lib/rom/adapter/memory.rb +0 -32
- data/lib/rom/adapter/memory/commands.rb +0 -31
- data/lib/rom/adapter/memory/dataset.rb +0 -67
- data/lib/rom/adapter/memory/storage.rb +0 -26
- data/lib/rom/commands/with_options.rb +0 -18
- data/lib/rom/config.rb +0 -70
- data/lib/rom/mapper_builder.rb +0 -52
- data/lib/rom/mapper_builder/mapper_dsl.rb +0 -114
- data/lib/rom/mapper_builder/model_dsl.rb +0 -29
- data/lib/rom/reader_builder.rb +0 -48
- data/lib/rom/relation_builder.rb +0 -62
- data/lib/rom/setup/base_relation_dsl.rb +0 -46
- data/lib/rom/setup/command_dsl.rb +0 -46
- data/lib/rom/setup/mapper_dsl.rb +0 -19
- data/lib/rom/setup/relation_dsl.rb +0 -20
- data/lib/rom/setup/schema_dsl.rb +0 -33
- data/spec/integration/adapters/extending_relations_spec.rb +0 -41
- data/spec/integration/commands/try_spec.rb +0 -27
- data/spec/integration/schema_spec.rb +0 -77
- data/spec/unit/config_spec.rb +0 -60
- data/spec/unit/rom/adapter_spec.rb +0 -79
- data/spec/unit/rom_spec.rb +0 -14
@@ -1,20 +1,23 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'rom/memory/dataset'
|
2
3
|
|
3
4
|
require 'ostruct'
|
4
5
|
|
5
6
|
describe ROM::Mapper do
|
6
|
-
subject(:mapper)
|
7
|
-
ROM::Mapper.build(ROM::Header.coerce(relation.header.zip, user_model))
|
8
|
-
end
|
7
|
+
subject(:mapper) { mapper_class.build }
|
9
8
|
|
10
|
-
let(:
|
11
|
-
|
9
|
+
let(:mapper_class) do
|
10
|
+
user_model = self.user_model
|
11
|
+
|
12
|
+
Class.new(ROM::Mapper) do
|
13
|
+
attribute :id
|
14
|
+
attribute :name
|
15
|
+
model user_model
|
16
|
+
end
|
12
17
|
end
|
13
18
|
|
14
|
-
let(:
|
15
|
-
|
16
|
-
[{ id: 1, name: 'Jane' }, { id: 2, name: 'Joe' }], [:id, :name]
|
17
|
-
)
|
19
|
+
let(:relation) do
|
20
|
+
[{ id: 1, name: 'Jane' }, { id: 2, name: 'Joe' }]
|
18
21
|
end
|
19
22
|
|
20
23
|
let(:user_model) do
|
@@ -24,11 +27,49 @@ describe ROM::Mapper do
|
|
24
27
|
let(:jane) { user_model.new(id: 1, name: 'Jane') }
|
25
28
|
let(:joe) { user_model.new(id: 2, name: 'Joe') }
|
26
29
|
|
30
|
+
describe '.registry' do
|
31
|
+
it 'builds mapper class registry for base and virtual relations' do
|
32
|
+
users = Class.new(ROM::Mapper) { relation(:users) }
|
33
|
+
active = Class.new(users) { relation(:active) }
|
34
|
+
admins = Class.new(users) { relation(:admins) }
|
35
|
+
custom = Class.new(users) { register_as(:custom) }
|
36
|
+
|
37
|
+
registry = ROM::Mapper.registry([users, active, admins, custom])
|
38
|
+
|
39
|
+
expect(registry).to eql(
|
40
|
+
users: {
|
41
|
+
users: users.build,
|
42
|
+
active: active.build,
|
43
|
+
admins: admins.build,
|
44
|
+
custom: custom.build
|
45
|
+
}
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '.relation' do
|
51
|
+
it 'inherits from parent' do
|
52
|
+
base = Class.new(ROM::Mapper) { relation(:users) }
|
53
|
+
virt = Class.new(base)
|
54
|
+
|
55
|
+
expect(virt.relation).to be(:users)
|
56
|
+
expect(virt.base_relation).to be(:users)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'allows overriding' do
|
60
|
+
base = Class.new(ROM::Mapper) { relation(:users) }
|
61
|
+
virt = Class.new(base) { relation(:active) }
|
62
|
+
|
63
|
+
expect(virt.relation).to be(:active)
|
64
|
+
expect(virt.base_relation).to be(:users)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
27
68
|
describe "#each" do
|
28
69
|
it "yields all mapped objects" do
|
29
70
|
result = []
|
30
71
|
|
31
|
-
mapper.
|
72
|
+
mapper.call(relation).each do |tuple|
|
32
73
|
result << tuple
|
33
74
|
end
|
34
75
|
|
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'rom/lint/spec'
|
3
|
+
require 'rom/memory/dataset'
|
2
4
|
|
3
|
-
describe ROM::
|
4
|
-
subject(:dataset)
|
5
|
-
ROM::Adapter::Memory::Dataset.new(data, [:name, :email, :age])
|
6
|
-
end
|
5
|
+
describe ROM::Memory::Dataset do
|
6
|
+
subject(:dataset) { described_class.new(data) }
|
7
7
|
|
8
8
|
let(:data) do
|
9
9
|
[
|
@@ -13,6 +13,8 @@ describe ROM::Adapter::Memory::Dataset do
|
|
13
13
|
]
|
14
14
|
end
|
15
15
|
|
16
|
+
it_behaves_like "a rom enumerable dataset"
|
17
|
+
|
16
18
|
describe '#project' do
|
17
19
|
it 'projects tuples with the provided keys' do
|
18
20
|
expect(dataset.project(:name, :age)).to match_array([
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rom/lint/spec'
|
3
|
+
require 'rom/memory'
|
4
|
+
|
5
|
+
describe ROM::Memory::Repository do
|
6
|
+
let(:repository) { ROM::Memory::Repository }
|
7
|
+
let(:uri) { nil }
|
8
|
+
|
9
|
+
it_behaves_like "a rom repository" do
|
10
|
+
let(:identifier) { :memory }
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rom/memory/storage'
|
3
|
+
|
4
|
+
describe ROM::Memory::Storage do
|
5
|
+
describe 'thread safe' do
|
6
|
+
let(:threads) { 4 }
|
7
|
+
let(:operations) { 5000 }
|
8
|
+
|
9
|
+
describe 'data' do
|
10
|
+
it 'create datasets properly' do
|
11
|
+
storage = ROM::Memory::Storage.new
|
12
|
+
|
13
|
+
threaded_operations do |thread, operation|
|
14
|
+
key = "#{thread}:#{operation}"
|
15
|
+
storage.create_dataset(key)
|
16
|
+
end
|
17
|
+
|
18
|
+
expect(storage.size).to eql(threads * operations)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'dataset' do
|
23
|
+
it 'inserts data in proper order' do
|
24
|
+
storage = ROM::Memory::Storage.new
|
25
|
+
dataset = storage.create_dataset(:ary)
|
26
|
+
|
27
|
+
threaded_operations do
|
28
|
+
dataset << :data
|
29
|
+
end
|
30
|
+
|
31
|
+
expect(dataset.size).to eql(threads * operations)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def threaded_operations
|
36
|
+
threads.times.map do |thread|
|
37
|
+
Thread.new do
|
38
|
+
operations.times do |operation|
|
39
|
+
yield thread, operation
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end.each(&:join)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -28,16 +28,17 @@ describe ROM::ModelBuilder do
|
|
28
28
|
builder.call([:name, :email])
|
29
29
|
|
30
30
|
expect(Object.const_defined?(:User)).to be(true)
|
31
|
+
Object.send(:remove_const, :User)
|
31
32
|
end
|
32
33
|
|
33
34
|
it 'defines a constant within a namespace for the model' do
|
34
|
-
module MyApp; module Entities; end; end
|
35
|
+
module Test::MyApp; module Entities; end; end
|
35
36
|
|
36
|
-
builder = ROM::ModelBuilder::PORO.new(name: 'MyApp::Entities::User')
|
37
|
+
builder = ROM::ModelBuilder::PORO.new(name: 'Test::MyApp::Entities::User')
|
37
38
|
|
38
39
|
builder.call([:name, :email])
|
39
40
|
|
40
|
-
expect(MyApp::Entities.const_defined?(:User)).to be(true)
|
41
|
+
expect(Test::MyApp::Entities.const_defined?(:User)).to be(true)
|
41
42
|
expect(Object.const_defined?(:User)).to be(false)
|
42
43
|
end
|
43
44
|
end
|
@@ -10,27 +10,10 @@ describe ROM::Reader do
|
|
10
10
|
let(:mappers) { ROM::MapperRegistry.new(users: mapper) }
|
11
11
|
let(:mapper) { double('mapper', header: []) }
|
12
12
|
|
13
|
-
describe '#initialize' do
|
14
|
-
it 'raises error when mapper cannot be found' do
|
15
|
-
expect { ROM::Reader.new(:not_here, relation, mappers) }
|
16
|
-
.to raise_error(ROM::Reader::MapperMissingError, /not_here/)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
describe '#each' do
|
21
|
-
it 'yields mapped tuples from relations' do
|
22
|
-
expect(mapper).to receive(:process)
|
23
|
-
.with(relation)
|
24
|
-
.and_yield(jane).and_yield(joe)
|
25
|
-
|
26
|
-
result = []
|
27
|
-
reader.each { |user| result << user }
|
28
|
-
expect(result).to eql([jane, joe])
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
13
|
describe '.build' do
|
33
|
-
subject(:reader)
|
14
|
+
subject(:reader) do
|
15
|
+
ROM::Reader.build(name, relation, mappers, [:all])
|
16
|
+
end
|
34
17
|
|
35
18
|
before do
|
36
19
|
relation.instance_exec do
|
@@ -51,15 +34,17 @@ describe ROM::Reader do
|
|
51
34
|
it 'defines methods from relation' do
|
52
35
|
block = proc {}
|
53
36
|
|
37
|
+
user_id = 1
|
38
|
+
|
54
39
|
expect(relation).to receive(:all)
|
55
|
-
.with(
|
40
|
+
.with(user_id, &block)
|
56
41
|
.and_return([joe])
|
57
42
|
|
58
|
-
expect(mapper).to receive(:
|
43
|
+
expect(mapper).to receive(:call)
|
59
44
|
.with([joe])
|
60
|
-
.
|
45
|
+
.and_return([joe])
|
61
46
|
|
62
|
-
result = reader.all(
|
47
|
+
result = reader.all(user_id, &block)
|
63
48
|
|
64
49
|
expect(result.path).to eql('users.all')
|
65
50
|
expect(result.to_a).to eql([joe])
|
@@ -69,5 +54,93 @@ describe ROM::Reader do
|
|
69
54
|
expect { reader.not_here }
|
70
55
|
.to raise_error(ROM::NoRelationError, /not_here/)
|
71
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
|
72
145
|
end
|
73
146
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ROM::Relation::Composite do
|
4
|
+
include_context 'users and tasks'
|
5
|
+
|
6
|
+
let(:users) { rom.relation(:users) }
|
7
|
+
|
8
|
+
let(:name_list) { proc { |r| r.map { |t| t[:name] } } }
|
9
|
+
let(:upcaser) { proc { |r| r.map(&:upcase) } }
|
10
|
+
|
11
|
+
before do
|
12
|
+
setup.relation(:users) do
|
13
|
+
def by_name(name)
|
14
|
+
restrict(name: name)
|
15
|
+
end
|
16
|
+
|
17
|
+
def sorted(other)
|
18
|
+
other.sort_by { |t| t[:name] }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#call' do
|
24
|
+
it 'sends a relation through mappers' do
|
25
|
+
relation = users >> name_list >> upcaser
|
26
|
+
loaded = relation.call
|
27
|
+
|
28
|
+
expect(loaded.source).to eql(users.relation)
|
29
|
+
expect(loaded).to match_array(%w(JANE JOE))
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'sends a relation through another relation' do
|
33
|
+
relation = users >> users.sorted
|
34
|
+
loaded = relation.call
|
35
|
+
|
36
|
+
expect(loaded.source).to eql(users.relation)
|
37
|
+
expect(loaded).to match_array([
|
38
|
+
{ name: 'Jane', email: 'jane@doe.org' },
|
39
|
+
{ name: 'Joe', email: 'joe@doe.org' }
|
40
|
+
])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#each' do
|
45
|
+
let(:relation) { users >> name_list >> upcaser }
|
46
|
+
|
47
|
+
it 'calls and iterates' do
|
48
|
+
result = []
|
49
|
+
relation.each { |object| result << object }
|
50
|
+
expect(result).to match_array(%w(JANE JOE))
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'returns enumerator if block is not provided' do
|
54
|
+
expect(relation.each.to_a).to match_array(%w(JANE JOE))
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#first' do
|
59
|
+
let(:relation) { users >> name_list >> upcaser }
|
60
|
+
|
61
|
+
it 'calls and returns the first object' do
|
62
|
+
expect(relation.first).to eql('JOE')
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ROM::Relation::Lazy do
|
4
|
+
include_context 'users and tasks'
|
5
|
+
|
6
|
+
let(:users) { rom.relations.users.to_lazy }
|
7
|
+
let(:tasks) { rom.relations.tasks.to_lazy }
|
8
|
+
|
9
|
+
before do
|
10
|
+
setup.relation(:users) do
|
11
|
+
def repository
|
12
|
+
:default
|
13
|
+
end
|
14
|
+
|
15
|
+
def by_name(name)
|
16
|
+
restrict(name: name)
|
17
|
+
end
|
18
|
+
|
19
|
+
def by_email(email)
|
20
|
+
restrict(name: email)
|
21
|
+
end
|
22
|
+
|
23
|
+
def by_name_and_email(name, email)
|
24
|
+
by_name(name).by_email(email)
|
25
|
+
end
|
26
|
+
|
27
|
+
def by_name_and_email_sorted(name, email, order_by)
|
28
|
+
by_name_and_email(name, email).order(order_by)
|
29
|
+
end
|
30
|
+
|
31
|
+
def all(*args)
|
32
|
+
if args.any?
|
33
|
+
restrict(*args)
|
34
|
+
else
|
35
|
+
self
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
setup.relation(:tasks) do
|
41
|
+
def for_users(users)
|
42
|
+
names = users.map { |u| u[:name] }
|
43
|
+
restrict { |t| names.include?(t[:name]) }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it_behaves_like 'a relation that returns one tuple' do
|
49
|
+
let(:relation) { users }
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#method_missing' do
|
53
|
+
it 'forwards to relation and auto-curries' do
|
54
|
+
relation = users.by_name_and_email_sorted('Jane')
|
55
|
+
|
56
|
+
expect(relation.name).to eql(:by_name_and_email_sorted)
|
57
|
+
expect(relation.curry_args).to eql(['Jane'])
|
58
|
+
|
59
|
+
relation = relation['jane@doe.org']
|
60
|
+
|
61
|
+
expect(relation.name).to eql(:by_name_and_email_sorted)
|
62
|
+
expect(relation.curry_args).to eql(['Jane', 'jane@doe.org'])
|
63
|
+
|
64
|
+
expect(relation[:email]).to match_array(
|
65
|
+
rom.relations.users.by_name_and_email_sorted('Jane', 'jane@doe.org', :email)
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'forwards to relation and does not auto-curry when it is not needed' do
|
70
|
+
relation = users.by_name('Jane')
|
71
|
+
|
72
|
+
expect(relation).to_not be_curried
|
73
|
+
expect(relation).to match_array(rom.relations.users.by_name('Jane'))
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'forwards to relation and return lazy when arity is unknown' do
|
77
|
+
relation = users.all(name: 'Jane')
|
78
|
+
expect(relation).to_not be_curried
|
79
|
+
expect(relation).to match_array(rom.relations.users.by_name('Jane').to_a)
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'returns original response if it is not a relation' do
|
83
|
+
expect(users.repository).to be(:default)
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'raises NoMethodError when relation does not respond to a method' do
|
87
|
+
expect { users.not_here }.to raise_error(NoMethodError, /not_here/)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe '#call' do
|
92
|
+
it 'auto-curries' do
|
93
|
+
relation = users.by_name
|
94
|
+
|
95
|
+
expect(relation.name).to eql(:by_name)
|
96
|
+
expect(relation['Jane'].to_a).to eql(rom.relations.users.by_name('Jane').to_a)
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'returns relation' do
|
100
|
+
expect(users.call.to_a).to eql(rom.relations.users.to_a)
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'does not allow currying on already curried relation' do
|
104
|
+
expect { users.by_name.by_email }.to raise_error(NoMethodError, /by_email/)
|
105
|
+
end
|
106
|
+
|
107
|
+
describe 'using mappers' do
|
108
|
+
subject(:users) { rom.relations.users.to_lazy(mappers: mappers) }
|
109
|
+
|
110
|
+
let(:name_list) { proc { |r| r.map { |t| t[:name] } } }
|
111
|
+
let(:upcaser) { proc { |r| r.map(&:upcase) } }
|
112
|
+
let(:mappers) { { name_list: name_list, upcaser: upcaser } }
|
113
|
+
|
114
|
+
it 'sends relation through mappers' do
|
115
|
+
relation = users.map_with(:name_list, :upcaser).by_name('Jane')
|
116
|
+
|
117
|
+
expect(relation.call.to_a).to eql(['JANE'])
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe '#>>' do
|
123
|
+
it 'composes two relations' do
|
124
|
+
other = users.by_name('Jane') >> tasks.for_users
|
125
|
+
|
126
|
+
expect(other).to match_array([
|
127
|
+
{ name: 'Jane', title: 'be cool', priority: 2 }
|
128
|
+
])
|
129
|
+
end
|
130
|
+
|
131
|
+
it_behaves_like 'a relation that returns one tuple' do
|
132
|
+
let(:relation) { rom.relation(:users) >> proc { |r| r } }
|
133
|
+
|
134
|
+
describe 'using a mapper' do
|
135
|
+
it 'returns one mapped tuple' do
|
136
|
+
mapper = proc { |r| r.map { |t| t[:name].upcase } }
|
137
|
+
relation = users.by_name('Jane') >> mapper
|
138
|
+
|
139
|
+
expect(relation.one).to eql('JANE')
|
140
|
+
expect(relation.one!).to eql('JANE')
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|