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