rom 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +81 -0
- data/.travis.yml +2 -1
- data/CHANGELOG.md +41 -0
- data/Gemfile +12 -8
- data/Guardfile +17 -11
- data/README.md +7 -7
- data/Rakefile +29 -0
- data/lib/rom.rb +9 -66
- data/lib/rom/adapter.rb +45 -12
- data/lib/rom/adapter/memory.rb +0 -4
- data/lib/rom/adapter/memory/commands.rb +0 -10
- data/lib/rom/adapter/memory/dataset.rb +18 -6
- data/lib/rom/adapter/memory/storage.rb +0 -3
- data/lib/rom/command_registry.rb +24 -43
- data/lib/rom/commands.rb +5 -6
- data/lib/rom/commands/create.rb +5 -5
- data/lib/rom/commands/delete.rb +8 -6
- data/lib/rom/commands/result.rb +82 -0
- data/lib/rom/commands/update.rb +5 -4
- data/lib/rom/commands/with_options.rb +1 -4
- data/lib/rom/config.rb +70 -0
- data/lib/rom/env.rb +11 -3
- data/lib/rom/global.rb +107 -0
- data/lib/rom/header.rb +122 -89
- data/lib/rom/header/attribute.rb +148 -0
- data/lib/rom/mapper.rb +46 -67
- data/lib/rom/mapper_builder.rb +20 -73
- data/lib/rom/mapper_builder/mapper_dsl.rb +114 -0
- data/lib/rom/mapper_builder/model_dsl.rb +29 -0
- data/lib/rom/mapper_registry.rb +21 -0
- data/lib/rom/model_builder.rb +11 -17
- data/lib/rom/processor.rb +28 -0
- data/lib/rom/processor/transproc.rb +105 -0
- data/lib/rom/reader.rb +81 -21
- data/lib/rom/reader_builder.rb +14 -4
- data/lib/rom/relation.rb +19 -5
- data/lib/rom/relation_builder.rb +20 -6
- data/lib/rom/repository.rb +0 -2
- data/lib/rom/setup.rb +156 -0
- data/lib/rom/{boot → setup}/base_relation_dsl.rb +4 -8
- data/lib/rom/setup/command_dsl.rb +46 -0
- data/lib/rom/setup/finalize.rb +125 -0
- data/lib/rom/setup/mapper_dsl.rb +19 -0
- data/lib/rom/{boot → setup}/relation_dsl.rb +1 -4
- data/lib/rom/setup/schema_dsl.rb +33 -0
- data/lib/rom/support/registry.rb +10 -6
- data/lib/rom/version.rb +1 -1
- data/rom.gemspec +3 -1
- data/spec/integration/adapters/extending_relations_spec.rb +0 -2
- data/spec/integration/commands/create_spec.rb +2 -9
- data/spec/integration/commands/delete_spec.rb +4 -5
- data/spec/integration/commands/error_handling_spec.rb +4 -3
- data/spec/integration/commands/update_spec.rb +3 -8
- data/spec/integration/mappers/deep_embedded_spec.rb +52 -0
- data/spec/integration/mappers/definition_dsl_spec.rb +0 -118
- data/spec/integration/mappers/embedded_spec.rb +82 -0
- data/spec/integration/mappers/group_spec.rb +170 -0
- data/spec/integration/mappers/prefixing_attributes_spec.rb +2 -2
- data/spec/integration/mappers/renaming_attributes_spec.rb +8 -6
- data/spec/integration/mappers/symbolizing_attributes_spec.rb +80 -0
- data/spec/integration/mappers/wrap_spec.rb +162 -0
- data/spec/integration/multi_repo_spec.rb +64 -0
- data/spec/integration/relations/reading_spec.rb +12 -8
- data/spec/integration/relations/registry_dsl_spec.rb +1 -3
- data/spec/integration/schema_spec.rb +10 -0
- data/spec/integration/setup_spec.rb +57 -6
- data/spec/spec_helper.rb +2 -1
- data/spec/unit/config_spec.rb +60 -0
- data/spec/unit/rom/adapter/memory/dataset_spec.rb +52 -0
- data/spec/unit/rom/adapter_spec.rb +31 -11
- data/spec/unit/rom/header_spec.rb +60 -16
- data/spec/unit/rom/mapper_builder_spec.rb +311 -0
- data/spec/unit/rom/mapper_registry_spec.rb +25 -0
- data/spec/unit/rom/mapper_spec.rb +4 -5
- data/spec/unit/rom/model_builder_spec.rb +15 -13
- data/spec/unit/rom/processor/transproc_spec.rb +331 -0
- data/spec/unit/rom/reader_spec.rb +73 -0
- data/spec/unit/rom/registry_spec.rb +38 -0
- data/spec/unit/rom/relation_spec.rb +0 -1
- data/spec/unit/rom/setup_spec.rb +55 -0
- data/spec/unit/rom_spec.rb +14 -0
- metadata +62 -22
- data/Gemfile.devtools +0 -71
- data/lib/rom/boot.rb +0 -197
- data/lib/rom/boot/command_dsl.rb +0 -48
- data/lib/rom/boot/dsl.rb +0 -37
- data/lib/rom/boot/mapper_dsl.rb +0 -23
- data/lib/rom/boot/schema_dsl.rb +0 -27
- data/lib/rom/ra.rb +0 -172
- data/lib/rom/ra/operation/group.rb +0 -47
- data/lib/rom/ra/operation/join.rb +0 -39
- data/lib/rom/ra/operation/wrap.rb +0 -45
- data/lib/rom/transformer.rb +0 -77
- data/spec/integration/ra/group_spec.rb +0 -46
- data/spec/integration/ra/join_spec.rb +0 -50
- data/spec/integration/ra/wrap_spec.rb +0 -37
- data/spec/unit/rom/ra/operation/group_spec.rb +0 -55
- data/spec/unit/rom/ra/operation/wrap_spec.rb +0 -29
- data/spec/unit/rom/transformer_spec.rb +0 -41
data/lib/rom/transformer.rb
DELETED
@@ -1,77 +0,0 @@
|
|
1
|
-
module ROM
|
2
|
-
|
3
|
-
class Transformer
|
4
|
-
attr_reader :operations
|
5
|
-
|
6
|
-
class Operation
|
7
|
-
attr_reader :attribute, :key, :names
|
8
|
-
|
9
|
-
def initialize(attribute)
|
10
|
-
@attribute = attribute
|
11
|
-
@key = attribute.key
|
12
|
-
@names = attribute.header.map(&:key)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
class Wrap < Operation
|
17
|
-
def call(tuples)
|
18
|
-
keys = nil
|
19
|
-
|
20
|
-
tuples.map { |tuple|
|
21
|
-
keys ||= tuple.keys - names
|
22
|
-
|
23
|
-
root = Hash[keys.zip(tuple.values_at(*keys))]
|
24
|
-
child = Hash[names.zip(tuple.values_at(*names))]
|
25
|
-
|
26
|
-
root.merge(key => child)
|
27
|
-
}
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
class Group < Operation
|
32
|
-
def call(tuples)
|
33
|
-
keys = nil
|
34
|
-
|
35
|
-
tuples.
|
36
|
-
group_by { |tuple|
|
37
|
-
keys ||= tuple.keys - names
|
38
|
-
Hash[keys.zip(tuple.values_at(*keys))]
|
39
|
-
}.map { |root, children|
|
40
|
-
root.merge(
|
41
|
-
key => children.map { |child| Hash[names.zip(child.values_at(*names))] }
|
42
|
-
)
|
43
|
-
}
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def self.build(header)
|
48
|
-
operations = header.map do |attribute|
|
49
|
-
type = attribute.type
|
50
|
-
|
51
|
-
if type == Hash
|
52
|
-
Wrap.new(attribute)
|
53
|
-
elsif type == Array
|
54
|
-
Group.new(attribute)
|
55
|
-
end
|
56
|
-
end.compact
|
57
|
-
|
58
|
-
sorted_ops =
|
59
|
-
operations.select { |op| Group === op } +
|
60
|
-
operations.select { |op| Wrap === op }
|
61
|
-
|
62
|
-
new(sorted_ops.flatten)
|
63
|
-
end
|
64
|
-
|
65
|
-
def initialize(operations)
|
66
|
-
@operations = operations
|
67
|
-
end
|
68
|
-
|
69
|
-
def call(input)
|
70
|
-
output = input
|
71
|
-
operations.each { |op| output = op.call(output) }
|
72
|
-
output
|
73
|
-
end
|
74
|
-
|
75
|
-
end
|
76
|
-
|
77
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe 'Group operation' do
|
4
|
-
include_context 'users and tasks'
|
5
|
-
|
6
|
-
specify 'defining a grouped relation' do
|
7
|
-
setup.relation(:users) do
|
8
|
-
include ROM::RA
|
9
|
-
|
10
|
-
def with_tasks
|
11
|
-
group(join(tasks), tasks: [:title, :priority])
|
12
|
-
end
|
13
|
-
|
14
|
-
def by_name(name)
|
15
|
-
restrict(name: name)
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|
19
|
-
|
20
|
-
users = rom.relations.users
|
21
|
-
|
22
|
-
expect(users.with_tasks.to_a).to eql(
|
23
|
-
[
|
24
|
-
{
|
25
|
-
name: "Joe", email: "joe@doe.org", tasks: [
|
26
|
-
{ title: "be nice", priority: 1 },
|
27
|
-
{ title: "sleep well", priority: 2 }
|
28
|
-
]
|
29
|
-
},
|
30
|
-
{ name: "Jane", email: "jane@doe.org", tasks: [{ title: "be cool", priority: 2 }] }
|
31
|
-
]
|
32
|
-
)
|
33
|
-
|
34
|
-
expect(users.with_tasks.by_name("Jane").to_a).to eql(
|
35
|
-
[
|
36
|
-
{ name: "Jane", email: "jane@doe.org", tasks: [{ title: "be cool", priority: 2 }] }
|
37
|
-
]
|
38
|
-
)
|
39
|
-
|
40
|
-
expect(users.by_name("Jane").with_tasks.to_a).to eql(
|
41
|
-
[
|
42
|
-
{ name: "Jane", email: "jane@doe.org", tasks: [{ title: "be cool", priority: 2 }] }
|
43
|
-
]
|
44
|
-
)
|
45
|
-
end
|
46
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe 'Join operation' do
|
4
|
-
include_context 'users and tasks'
|
5
|
-
|
6
|
-
specify 'defining a joined one-to-many relation' do
|
7
|
-
setup.relation(:users) do
|
8
|
-
include ROM::RA
|
9
|
-
|
10
|
-
def with_tasks
|
11
|
-
join(tasks)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
setup.relation(:tasks)
|
16
|
-
|
17
|
-
users = rom.relations.users
|
18
|
-
|
19
|
-
expect(users.with_tasks.to_a).to eql(
|
20
|
-
[
|
21
|
-
{ name: 'Joe', email: 'joe@doe.org', title: 'be nice', priority: 1 },
|
22
|
-
{ name: 'Joe', email: 'joe@doe.org', title: 'sleep well', priority: 2 },
|
23
|
-
{ name: 'Jane', email: 'jane@doe.org', title: 'be cool', priority: 2 }
|
24
|
-
]
|
25
|
-
)
|
26
|
-
end
|
27
|
-
|
28
|
-
specify 'defining a joined many-to-one relation' do
|
29
|
-
setup.relation(:users)
|
30
|
-
|
31
|
-
setup.relation(:tasks) do
|
32
|
-
include ROM::RA
|
33
|
-
|
34
|
-
def with_user
|
35
|
-
join(users)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
tasks = rom.relations.tasks
|
40
|
-
|
41
|
-
expect(tasks.with_user.to_a).to eql(
|
42
|
-
[
|
43
|
-
{ title: 'be nice', priority: 1, name: 'Joe', email: 'joe@doe.org' },
|
44
|
-
{ title: 'sleep well', priority: 2, name: 'Joe', email: 'joe@doe.org' },
|
45
|
-
{ title: 'be cool', priority: 2, name: 'Jane', email: 'jane@doe.org' }
|
46
|
-
]
|
47
|
-
)
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe 'Wrap operation' do
|
4
|
-
include_context 'users and tasks'
|
5
|
-
|
6
|
-
specify 'defining a wrapped relation' do
|
7
|
-
setup.relation(:users) do
|
8
|
-
include ROM::RA
|
9
|
-
|
10
|
-
def with_task
|
11
|
-
wrap(join(tasks), task: [:title, :priority])
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
users = rom.relations.users
|
16
|
-
|
17
|
-
expect(users.with_task.to_a).to eql(
|
18
|
-
[
|
19
|
-
{
|
20
|
-
name: "Joe",
|
21
|
-
email: "joe@doe.org",
|
22
|
-
task: { title: "be nice", priority: 1 }
|
23
|
-
},
|
24
|
-
{
|
25
|
-
name: "Joe",
|
26
|
-
email: "joe@doe.org",
|
27
|
-
task: { title: "sleep well", priority: 2 }
|
28
|
-
},
|
29
|
-
{
|
30
|
-
name: "Jane",
|
31
|
-
email: "jane@doe.org",
|
32
|
-
task: { title: "be cool", priority: 2 }
|
33
|
-
}
|
34
|
-
]
|
35
|
-
)
|
36
|
-
end
|
37
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe 'Group operation' do
|
4
|
-
subject(:group) { relation.group(options) }
|
5
|
-
|
6
|
-
let(:relation) do
|
7
|
-
ROM::Relation.new(dataset, header).extend(ROM::RA)
|
8
|
-
end
|
9
|
-
|
10
|
-
let(:header) do
|
11
|
-
[:name, :email, :street, :zipcode, :city]
|
12
|
-
end
|
13
|
-
|
14
|
-
let(:options) do
|
15
|
-
{ addresses: [:street, :zipcode, :city] }
|
16
|
-
end
|
17
|
-
|
18
|
-
context 'when group values are present' do
|
19
|
-
let(:dataset) do
|
20
|
-
[{ name: 'Jane',
|
21
|
-
email: 'jane@doe.org',
|
22
|
-
street: 'Street 1',
|
23
|
-
zipcode: '1234',
|
24
|
-
city: 'Cracow' }]
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'groups given attributes under specified key' do
|
28
|
-
expect(group.to_a).to eql(
|
29
|
-
[{ name: 'Jane',
|
30
|
-
email: 'jane@doe.org',
|
31
|
-
addresses: [{ street: 'Street 1', zipcode: '1234', city: 'Cracow' }] }]
|
32
|
-
)
|
33
|
-
end
|
34
|
-
|
35
|
-
it 'exposes the header' do
|
36
|
-
expect(group.header).to eql([:name, :email, :addresses])
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
context 'when group values are not present' do
|
41
|
-
let(:dataset) do
|
42
|
-
[{ name: 'Jane',
|
43
|
-
email: 'jane@doe.org',
|
44
|
-
street: nil,
|
45
|
-
zipcode: nil,
|
46
|
-
city: nil }]
|
47
|
-
end
|
48
|
-
|
49
|
-
it 'sets empty array for grouped attributes' do
|
50
|
-
expect(group.to_a).to eql(
|
51
|
-
[{ name: 'Jane', email: 'jane@doe.org', addresses: [] }]
|
52
|
-
)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe 'Wrap operation' do
|
4
|
-
subject(:wrap) { relation.wrap(address: [:street, :zipcode, :city]) }
|
5
|
-
|
6
|
-
let(:relation) do
|
7
|
-
ROM::Relation.new([{ name: 'Jane',
|
8
|
-
email: 'jane@doe.org',
|
9
|
-
street: 'Street 1',
|
10
|
-
zipcode: '1234',
|
11
|
-
city: 'Cracow' }], header).extend(ROM::RA)
|
12
|
-
end
|
13
|
-
|
14
|
-
let(:header) do
|
15
|
-
[:name, :email, :street, :zipcode, :city]
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'wraps given attributes under specified key' do
|
19
|
-
expect(wrap.to_a).to eql(
|
20
|
-
[{ name: 'Jane',
|
21
|
-
email: 'jane@doe.org',
|
22
|
-
address: { street: 'Street 1', zipcode: '1234', city: 'Cracow' } }]
|
23
|
-
)
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'exposes the header' do
|
27
|
-
expect(wrap.header).to eql([:name, :email, :address])
|
28
|
-
end
|
29
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe ROM::Transformer do
|
4
|
-
subject(:transformer) { ROM::Transformer.build(header) }
|
5
|
-
|
6
|
-
let(:header) do
|
7
|
-
ROM::Header.coerce([
|
8
|
-
[:name],
|
9
|
-
[:address, type: Hash, header: [[:street], [:zipcode]]],
|
10
|
-
[:tasks, type: Array, header: [[:title], [:priority]]]
|
11
|
-
])
|
12
|
-
end
|
13
|
-
|
14
|
-
let(:relation) do
|
15
|
-
[{ name: 'Jane',
|
16
|
-
street: 'Street 1',
|
17
|
-
zipcode: '123',
|
18
|
-
title: 'Sing a song',
|
19
|
-
priority: 'high' },
|
20
|
-
{ name: 'Jane',
|
21
|
-
street: 'Street 1',
|
22
|
-
zipcode: '123',
|
23
|
-
title: 'Relax',
|
24
|
-
priority: 'very-high' }]
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'transforms a tuple' do
|
28
|
-
expect(transformer.call(relation)).to eql([
|
29
|
-
name: 'Jane',
|
30
|
-
address: { street: 'Street 1', zipcode: '123' },
|
31
|
-
tasks: [
|
32
|
-
{ title: 'Sing a song', priority: 'high' },
|
33
|
-
{ title: 'Relax', priority: 'very-high' }
|
34
|
-
]
|
35
|
-
])
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'skip transforming if tuple is empty' do
|
39
|
-
expect(transformer.call([])).to eql([])
|
40
|
-
end
|
41
|
-
end
|