rom 0.6.2 → 0.7.0
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/.rspec +1 -0
- data/.rubocop.yml +9 -0
- data/CHANGELOG.md +34 -0
- data/CONTRIBUTING.md +1 -0
- data/Gemfile +1 -1
- data/README.md +12 -7
- data/lib/rom.rb +8 -0
- data/lib/rom/command.rb +19 -0
- data/lib/rom/commands/abstract.rb +6 -1
- data/lib/rom/commands/composite.rb +1 -52
- data/lib/rom/commands/update.rb +4 -1
- data/lib/rom/constants.rb +1 -0
- data/lib/rom/env.rb +3 -25
- data/lib/rom/global.rb +23 -0
- data/lib/rom/global/plugin_dsl.rb +47 -0
- data/lib/rom/header.rb +19 -8
- data/lib/rom/header/attribute.rb +14 -2
- data/lib/rom/lint/enumerable_dataset.rb +3 -1
- data/lib/rom/lint/repository.rb +5 -5
- data/lib/rom/mapper.rb +2 -1
- data/lib/rom/mapper/attribute_dsl.rb +86 -13
- data/lib/rom/mapper/dsl.rb +20 -1
- data/lib/rom/memory/commands.rb +3 -1
- data/lib/rom/memory/dataset.rb +1 -1
- data/lib/rom/memory/relation.rb +1 -1
- data/lib/rom/pipeline.rb +91 -0
- data/lib/rom/plugin.rb +31 -0
- data/lib/rom/plugin_registry.rb +134 -0
- data/lib/rom/plugins/relation/registry_reader.rb +30 -0
- data/lib/rom/processor/transproc.rb +78 -3
- data/lib/rom/relation/class_interface.rb +14 -2
- data/lib/rom/relation/composite.rb +9 -97
- data/lib/rom/relation/graph.rb +76 -0
- data/lib/rom/relation/lazy.rb +15 -63
- data/lib/rom/relation/materializable.rb +66 -0
- data/lib/rom/setup/finalize.rb +16 -5
- data/lib/rom/setup_dsl/mapper_dsl.rb +10 -2
- data/lib/rom/setup_dsl/setup.rb +1 -1
- data/lib/rom/support/array_dataset.rb +7 -4
- data/lib/rom/support/data_proxy.rb +7 -7
- data/lib/rom/support/deprecations.rb +17 -0
- data/lib/rom/support/enumerable_dataset.rb +10 -3
- data/lib/rom/support/inflector.rb +1 -1
- data/lib/rom/version.rb +1 -1
- data/rom.gemspec +1 -1
- data/spec/integration/commands/create_spec.rb +3 -3
- data/spec/integration/commands/update_spec.rb +24 -4
- data/spec/integration/mappers/combine_spec.rb +107 -0
- data/spec/integration/mappers/registering_custom_mappers_spec.rb +29 -0
- data/spec/integration/mappers/reusing_mappers_spec.rb +22 -0
- data/spec/integration/mappers/unwrap_spec.rb +98 -0
- data/spec/integration/multi_repo_spec.rb +2 -2
- data/spec/integration/repositories/extending_relations_spec.rb +9 -0
- data/spec/integration/setup_spec.rb +2 -2
- data/spec/shared/enumerable_dataset.rb +4 -1
- data/spec/shared/materializable.rb +34 -0
- data/spec/shared/proxy.rb +0 -0
- data/spec/spec_helper.rb +6 -2
- data/spec/support/mutant.rb +9 -6
- data/spec/unit/rom/commands_spec.rb +3 -3
- data/spec/unit/rom/header_spec.rb +2 -2
- data/spec/unit/rom/mapper/dsl_spec.rb +102 -1
- data/spec/unit/rom/memory/dataset_spec.rb +10 -33
- data/spec/unit/rom/memory/relation_spec.rb +63 -0
- data/spec/unit/rom/memory/storage_spec.rb +2 -2
- data/spec/unit/rom/plugin_spec.rb +121 -0
- data/spec/unit/rom/processor/transproc_spec.rb +47 -6
- data/spec/unit/rom/relation/composite_spec.rb +3 -1
- data/spec/unit/rom/relation/graph_spec.rb +78 -0
- data/spec/unit/rom/relation/lazy/combine_spec.rb +130 -0
- data/spec/unit/rom/relation/lazy_spec.rb +3 -1
- data/spec/unit/rom/relation/loaded_spec.rb +3 -1
- data/spec/unit/rom/setup_spec.rb +8 -8
- data/spec/unit/rom/support/array_dataset_spec.rb +3 -1
- data/spec/unit/rom/support/class_builder_spec.rb +2 -2
- metadata +24 -7
- data/lib/rom/relation/registry_reader.rb +0 -23
File without changes
|
data/spec/spec_helper.rb
CHANGED
@@ -19,8 +19,12 @@ end
|
|
19
19
|
|
20
20
|
root = Pathname(__FILE__).dirname
|
21
21
|
|
22
|
-
Dir[root.join('support/*.rb').to_s].each
|
23
|
-
|
22
|
+
Dir[root.join('support/*.rb').to_s].each do |f|
|
23
|
+
require f
|
24
|
+
end
|
25
|
+
Dir[root.join('shared/*.rb').to_s].each do |f|
|
26
|
+
require f
|
27
|
+
end
|
24
28
|
|
25
29
|
# Namespace holding all objects created during specs
|
26
30
|
module Test
|
data/spec/support/mutant.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
module Mutant
|
2
|
-
class
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
end
|
2
|
+
class Selector
|
3
|
+
# Expression based test selector
|
4
|
+
class Expression < self
|
5
|
+
def call(subject)
|
6
|
+
integration.all_tests
|
7
|
+
end
|
8
|
+
end # Expression
|
9
|
+
end # Selector
|
10
|
+
end # Mutant
|
@@ -15,11 +15,11 @@ describe 'Commands' do
|
|
15
15
|
|
16
16
|
describe '.build_class' do
|
17
17
|
it 'creates a command class constant' do
|
18
|
-
klass = ROM::Command.build_class(:create, :users, adapter: :memory)
|
18
|
+
klass = ROM::Command.build_class(:create, :users, adapter: :memory) {
|
19
19
|
def super?
|
20
20
|
true
|
21
21
|
end
|
22
|
-
|
22
|
+
}
|
23
23
|
|
24
24
|
expect(klass.name).to eql('ROM::Memory::Commands::Create[Users]')
|
25
25
|
expect(klass.register_as).to eql(:create)
|
@@ -135,7 +135,7 @@ describe 'Commands' do
|
|
135
135
|
}.build(users)
|
136
136
|
|
137
137
|
create_task = Class.new(ROM::Commands::Create) {
|
138
|
-
def execute(
|
138
|
+
def execute(task_input, user_tuple)
|
139
139
|
relation.insert(task_input.merge(user_id: user_tuple[:user_id]))
|
140
140
|
end
|
141
141
|
}.build(tasks)
|
@@ -33,7 +33,7 @@ describe ROM::Header do
|
|
33
33
|
|
34
34
|
expect(tasks.type).to be(:array)
|
35
35
|
expect(tasks.header.model).to be(model)
|
36
|
-
expect(tasks.header).to eql(ROM::Header.coerce([[:title]], model))
|
36
|
+
expect(tasks.header).to eql(ROM::Header.coerce([[:title]], model: model))
|
37
37
|
|
38
38
|
expect(input.first[1])
|
39
39
|
.to eql(header: [[:title]], type: :array, model: model)
|
@@ -55,7 +55,7 @@ describe ROM::Header do
|
|
55
55
|
|
56
56
|
expect(tasks.type).to be(:hash)
|
57
57
|
expect(tasks.header.model).to be(model)
|
58
|
-
expect(tasks.header).to eql(ROM::Header.coerce([[:title]], model))
|
58
|
+
expect(tasks.header).to eql(ROM::Header.coerce([[:title]], model: model))
|
59
59
|
|
60
60
|
expect(input.first[1])
|
61
61
|
.to eql(header: [[:title]], type: :hash, model: model)
|
@@ -3,7 +3,9 @@ require 'spec_helper'
|
|
3
3
|
describe ROM::Mapper do
|
4
4
|
subject(:mapper) do
|
5
5
|
klass = Class.new(parent)
|
6
|
-
options.each
|
6
|
+
options.each do |k, v|
|
7
|
+
klass.send(k, v)
|
8
|
+
end
|
7
9
|
klass
|
8
10
|
end
|
9
11
|
|
@@ -69,6 +71,18 @@ describe ROM::Mapper do
|
|
69
71
|
end
|
70
72
|
end
|
71
73
|
|
74
|
+
describe 'reject_keys' do
|
75
|
+
let(:attributes) { [[:name, type: :string]] }
|
76
|
+
let(:options) { { reject_keys: true } }
|
77
|
+
|
78
|
+
it 'sets rejected_keys for the header' do
|
79
|
+
mapper.reject_keys true
|
80
|
+
mapper.attribute :name, type: :string
|
81
|
+
|
82
|
+
expect(header).to eql(expected_header)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
72
86
|
describe 'overriding inherited attributes' do
|
73
87
|
context 'when name matches' do
|
74
88
|
let(:attributes) { [[:name, type: :string]] }
|
@@ -322,4 +336,91 @@ describe ROM::Mapper do
|
|
322
336
|
end
|
323
337
|
end
|
324
338
|
end
|
339
|
+
|
340
|
+
context 'reusing mappers' do
|
341
|
+
describe '#group' do
|
342
|
+
let(:task_mapper) do
|
343
|
+
Class.new(ROM::Mapper) { attribute :title }
|
344
|
+
end
|
345
|
+
|
346
|
+
let(:attributes) do
|
347
|
+
[
|
348
|
+
[:name],
|
349
|
+
[:tasks, type: :array, group: true, header: task_mapper.header]
|
350
|
+
]
|
351
|
+
end
|
352
|
+
|
353
|
+
it 'uses other mapper header' do
|
354
|
+
mapper.attribute :name
|
355
|
+
mapper.group :tasks, mapper: task_mapper
|
356
|
+
|
357
|
+
expect(header).to eql(expected_header)
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
describe '#wrap' do
|
362
|
+
let(:task_mapper) do
|
363
|
+
Class.new(ROM::Mapper) { attribute :title }
|
364
|
+
end
|
365
|
+
|
366
|
+
let(:attributes) do
|
367
|
+
[
|
368
|
+
[:name],
|
369
|
+
[:task, type: :hash, wrap: true, header: task_mapper.header]
|
370
|
+
]
|
371
|
+
end
|
372
|
+
|
373
|
+
it 'uses other mapper header' do
|
374
|
+
mapper.attribute :name
|
375
|
+
mapper.wrap :task, mapper: task_mapper
|
376
|
+
|
377
|
+
expect(header).to eql(expected_header)
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
describe '#embedded' do
|
382
|
+
let(:task_mapper) do
|
383
|
+
Class.new(ROM::Mapper) { attribute :title }
|
384
|
+
end
|
385
|
+
|
386
|
+
let(:attributes) do
|
387
|
+
[
|
388
|
+
[:name],
|
389
|
+
[:task, type: :array, header: task_mapper.header]
|
390
|
+
]
|
391
|
+
end
|
392
|
+
|
393
|
+
it 'uses other mapper header' do
|
394
|
+
mapper.attribute :name
|
395
|
+
mapper.embedded :task, mapper: task_mapper, type: :hash
|
396
|
+
|
397
|
+
expect(header).to eql(expected_header)
|
398
|
+
end
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
describe '#combine' do
|
403
|
+
let(:attributes) do
|
404
|
+
[
|
405
|
+
[:title],
|
406
|
+
[:tasks, combine: true, type: :array, header: [[:title]]]
|
407
|
+
]
|
408
|
+
end
|
409
|
+
|
410
|
+
it 'adds combine attributes' do
|
411
|
+
mapper.attribute :title
|
412
|
+
|
413
|
+
mapper.combine :tasks, on: { title: :title } do
|
414
|
+
attribute :title
|
415
|
+
end
|
416
|
+
|
417
|
+
expect(header).to eql(expected_header)
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
describe '#method_missing' do
|
422
|
+
it 'responds to DSL methods' do
|
423
|
+
expect(mapper).to respond_to(:attribute)
|
424
|
+
end
|
425
|
+
end
|
325
426
|
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'rom/lint/spec'
|
3
|
+
|
3
4
|
require 'rom/memory/dataset'
|
4
5
|
|
5
6
|
describe ROM::Memory::Dataset do
|
6
|
-
subject(:dataset) {
|
7
|
+
subject(:dataset) { ROM::Memory::Dataset.new(data) }
|
7
8
|
|
8
9
|
let(:data) do
|
9
10
|
[
|
@@ -15,40 +16,16 @@ describe ROM::Memory::Dataset do
|
|
15
16
|
|
16
17
|
it_behaves_like "a rom enumerable dataset"
|
17
18
|
|
18
|
-
describe '
|
19
|
-
it '
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
{ name: 'Joe', age: 12 }
|
24
|
-
])
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
describe '#restrict' do
|
29
|
-
it 'restricts data using criteria hash' do
|
30
|
-
expect(dataset.restrict(age: 10)).to match_array([
|
31
|
-
{ name: 'Jane', email: 'jane@doe.org', age: 10 }
|
32
|
-
])
|
19
|
+
describe 'subclassing' do
|
20
|
+
it 'supports options' do
|
21
|
+
descendant = Class.new(ROM::Memory::Dataset) do
|
22
|
+
option :path, reader: true
|
23
|
+
end
|
33
24
|
|
34
|
-
|
35
|
-
end
|
36
|
-
|
37
|
-
it 'restricts data using block' do
|
38
|
-
expect(dataset.restrict { |tuple| tuple[:age] > 10 }).to match_array([
|
39
|
-
{ name: 'Jade', email: 'jade@doe.org', age: 11 },
|
40
|
-
{ name: 'Joe', email: 'joe@doe.org', age: 12 }
|
41
|
-
])
|
42
|
-
end
|
43
|
-
end
|
25
|
+
dataset = descendant.new([1, 2, 3], path: '/data')
|
44
26
|
|
45
|
-
|
46
|
-
|
47
|
-
expect(dataset.order(:name)).to match_array([
|
48
|
-
{ name: 'Jade', email: 'jade@doe.org', age: 11 },
|
49
|
-
{ name: 'Jane', email: 'jane@doe.org', age: 10 },
|
50
|
-
{ name: 'Joe', email: 'joe@doe.org', age: 12 }
|
51
|
-
])
|
27
|
+
expect(dataset.to_a).to eql([1, 2, 3])
|
28
|
+
expect(dataset.path).to eql('/data')
|
52
29
|
end
|
53
30
|
end
|
54
31
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rom/lint/spec'
|
3
|
+
|
4
|
+
require 'rom/memory/dataset'
|
5
|
+
require 'rom/memory/relation'
|
6
|
+
|
7
|
+
describe ROM::Memory::Relation do
|
8
|
+
subject(:relation) { ROM::Memory::Relation.new(dataset) }
|
9
|
+
|
10
|
+
let(:dataset) do
|
11
|
+
ROM::Memory::Dataset.new([
|
12
|
+
{ name: 'Jane', email: 'jane@doe.org', age: 10 },
|
13
|
+
{ name: 'Jade', email: 'jade@doe.org', age: 11 },
|
14
|
+
{ name: 'Joe', email: 'joe@doe.org', age: 12 }
|
15
|
+
])
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#take' do
|
19
|
+
it 'takes given number of tuples' do
|
20
|
+
expect(relation.take(2)).to match_array([
|
21
|
+
{ name: 'Jane', email: 'jane@doe.org', age: 10 },
|
22
|
+
{ name: 'Jade', email: 'jade@doe.org', age: 11 }
|
23
|
+
])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#project' do
|
28
|
+
it 'projects tuples with the provided keys' do
|
29
|
+
expect(relation.project(:name, :age)).to match_array([
|
30
|
+
{ name: 'Jane', age: 10 },
|
31
|
+
{ name: 'Jade', age: 11 },
|
32
|
+
{ name: 'Joe', age: 12 }
|
33
|
+
])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#restrict' do
|
38
|
+
it 'restricts data using criteria hash' do
|
39
|
+
expect(relation.restrict(age: 10)).to match_array([
|
40
|
+
{ name: 'Jane', email: 'jane@doe.org', age: 10 }
|
41
|
+
])
|
42
|
+
|
43
|
+
expect(relation.restrict(age: 10.0)).to match_array([])
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'restricts data using block' do
|
47
|
+
expect(relation.restrict { |tuple| tuple[:age] > 10 }).to match_array([
|
48
|
+
{ name: 'Jade', email: 'jade@doe.org', age: 11 },
|
49
|
+
{ name: 'Joe', email: 'joe@doe.org', age: 12 }
|
50
|
+
])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#order' do
|
55
|
+
it 'sorts data using provided attribute names' do
|
56
|
+
expect(relation.order(:name).to_a).to eq([
|
57
|
+
{ name: 'Jade', email: 'jade@doe.org', age: 11 },
|
58
|
+
{ name: 'Jane', email: 'jane@doe.org', age: 10 },
|
59
|
+
{ name: 'Joe', email: 'joe@doe.org', age: 12 }
|
60
|
+
])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -33,13 +33,13 @@ describe ROM::Memory::Storage do
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def threaded_operations
|
36
|
-
threads.times.map
|
36
|
+
threads.times.map { |thread|
|
37
37
|
Thread.new do
|
38
38
|
operations.times do |operation|
|
39
39
|
yield thread, operation
|
40
40
|
end
|
41
41
|
end
|
42
|
-
|
42
|
+
}.each(&:join)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "ROM::PluginRegistry" do
|
4
|
+
subject(:env) { setup.finalize }
|
5
|
+
|
6
|
+
let(:setup) { ROM.setup(:memory) }
|
7
|
+
|
8
|
+
before do
|
9
|
+
Test::CommandPlugin = Module.new
|
10
|
+
Test::MapperPlugin = Module.new
|
11
|
+
Test::RelationPlugin = Module.new do
|
12
|
+
def self.included(mod)
|
13
|
+
mod.exposed_relations << :plugged_in
|
14
|
+
end
|
15
|
+
|
16
|
+
def plugged_in
|
17
|
+
"a relation"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
ROM.plugins do
|
22
|
+
register :publisher, Test::CommandPlugin, type: :command
|
23
|
+
register :pager, Test::RelationPlugin, type: :relation
|
24
|
+
register :translater, Test::MapperPlugin, type: :mapper
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
around do |example|
|
29
|
+
orig_plugins = ROM.plugin_registry
|
30
|
+
example.run
|
31
|
+
ROM.instance_variable_set('@plugin_registry', orig_plugins)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "includes relation plugins" do
|
35
|
+
setup.relation(:users) do
|
36
|
+
use :pager
|
37
|
+
end
|
38
|
+
|
39
|
+
expect(env.relation(:users).plugged_in).to eq "a relation"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "makes command plugins available" do
|
43
|
+
setup.relation(:users)
|
44
|
+
|
45
|
+
Class.new(ROM::Commands::Create[:memory]) do
|
46
|
+
relation :users
|
47
|
+
register_as :create
|
48
|
+
use :publisher
|
49
|
+
end
|
50
|
+
|
51
|
+
expect(env.command(:users).create).to be_kind_of Test::CommandPlugin
|
52
|
+
end
|
53
|
+
|
54
|
+
it "inclues plugins in mappers" do
|
55
|
+
setup.relation(:users)
|
56
|
+
|
57
|
+
Class.new(ROM::Mapper) do
|
58
|
+
relation :users
|
59
|
+
register_as :translator
|
60
|
+
use :translater
|
61
|
+
end
|
62
|
+
|
63
|
+
expect(env.mappers[:users][:translator]).to be_kind_of Test::MapperPlugin
|
64
|
+
end
|
65
|
+
|
66
|
+
it "restricts plugins to defined type" do
|
67
|
+
expect {
|
68
|
+
setup.relation(:users) do
|
69
|
+
use :publisher
|
70
|
+
end
|
71
|
+
}.to raise_error ROM::UnknownPluginError
|
72
|
+
end
|
73
|
+
|
74
|
+
it "allows definition of adapter restricted plugins" do
|
75
|
+
Test::LazyPlugin = Module.new do
|
76
|
+
def self.included(mod)
|
77
|
+
mod.exposed_relations << :lazy?
|
78
|
+
end
|
79
|
+
|
80
|
+
def lazy?
|
81
|
+
true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
ROM.plugins do
|
86
|
+
adapter :memory do
|
87
|
+
register :lazy, Test::LazyPlugin, type: :relation
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
setup.relation(:users) do
|
92
|
+
use :lazy, adapter: :memory
|
93
|
+
end
|
94
|
+
|
95
|
+
expect(env.relation(:users)).to be_lazy
|
96
|
+
end
|
97
|
+
|
98
|
+
it "respects adapter restrictions" do
|
99
|
+
Test::LazyPlugin = Module.new
|
100
|
+
Test::LazySQLPlugin = Module.new
|
101
|
+
|
102
|
+
ROM.plugins do
|
103
|
+
register :lazy, Test::LazyPlugin, type: :command
|
104
|
+
|
105
|
+
adapter :sql do
|
106
|
+
register :lazy, Test::LazySQLPlugin, type: :command
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
setup.relation(:users)
|
111
|
+
|
112
|
+
Class.new(ROM::Commands::Create[:memory]) do
|
113
|
+
relation :users
|
114
|
+
register_as :create
|
115
|
+
use :lazy, adapter: :memory
|
116
|
+
end
|
117
|
+
|
118
|
+
expect(env.command(:users).create).not_to be_kind_of Test::LazySQLPlugin
|
119
|
+
expect(env.command(:users).create).to be_kind_of Test::LazyPlugin
|
120
|
+
end
|
121
|
+
end
|