rom 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +81 -0
  3. data/.travis.yml +2 -1
  4. data/CHANGELOG.md +41 -0
  5. data/Gemfile +12 -8
  6. data/Guardfile +17 -11
  7. data/README.md +7 -7
  8. data/Rakefile +29 -0
  9. data/lib/rom.rb +9 -66
  10. data/lib/rom/adapter.rb +45 -12
  11. data/lib/rom/adapter/memory.rb +0 -4
  12. data/lib/rom/adapter/memory/commands.rb +0 -10
  13. data/lib/rom/adapter/memory/dataset.rb +18 -6
  14. data/lib/rom/adapter/memory/storage.rb +0 -3
  15. data/lib/rom/command_registry.rb +24 -43
  16. data/lib/rom/commands.rb +5 -6
  17. data/lib/rom/commands/create.rb +5 -5
  18. data/lib/rom/commands/delete.rb +8 -6
  19. data/lib/rom/commands/result.rb +82 -0
  20. data/lib/rom/commands/update.rb +5 -4
  21. data/lib/rom/commands/with_options.rb +1 -4
  22. data/lib/rom/config.rb +70 -0
  23. data/lib/rom/env.rb +11 -3
  24. data/lib/rom/global.rb +107 -0
  25. data/lib/rom/header.rb +122 -89
  26. data/lib/rom/header/attribute.rb +148 -0
  27. data/lib/rom/mapper.rb +46 -67
  28. data/lib/rom/mapper_builder.rb +20 -73
  29. data/lib/rom/mapper_builder/mapper_dsl.rb +114 -0
  30. data/lib/rom/mapper_builder/model_dsl.rb +29 -0
  31. data/lib/rom/mapper_registry.rb +21 -0
  32. data/lib/rom/model_builder.rb +11 -17
  33. data/lib/rom/processor.rb +28 -0
  34. data/lib/rom/processor/transproc.rb +105 -0
  35. data/lib/rom/reader.rb +81 -21
  36. data/lib/rom/reader_builder.rb +14 -4
  37. data/lib/rom/relation.rb +19 -5
  38. data/lib/rom/relation_builder.rb +20 -6
  39. data/lib/rom/repository.rb +0 -2
  40. data/lib/rom/setup.rb +156 -0
  41. data/lib/rom/{boot → setup}/base_relation_dsl.rb +4 -8
  42. data/lib/rom/setup/command_dsl.rb +46 -0
  43. data/lib/rom/setup/finalize.rb +125 -0
  44. data/lib/rom/setup/mapper_dsl.rb +19 -0
  45. data/lib/rom/{boot → setup}/relation_dsl.rb +1 -4
  46. data/lib/rom/setup/schema_dsl.rb +33 -0
  47. data/lib/rom/support/registry.rb +10 -6
  48. data/lib/rom/version.rb +1 -1
  49. data/rom.gemspec +3 -1
  50. data/spec/integration/adapters/extending_relations_spec.rb +0 -2
  51. data/spec/integration/commands/create_spec.rb +2 -9
  52. data/spec/integration/commands/delete_spec.rb +4 -5
  53. data/spec/integration/commands/error_handling_spec.rb +4 -3
  54. data/spec/integration/commands/update_spec.rb +3 -8
  55. data/spec/integration/mappers/deep_embedded_spec.rb +52 -0
  56. data/spec/integration/mappers/definition_dsl_spec.rb +0 -118
  57. data/spec/integration/mappers/embedded_spec.rb +82 -0
  58. data/spec/integration/mappers/group_spec.rb +170 -0
  59. data/spec/integration/mappers/prefixing_attributes_spec.rb +2 -2
  60. data/spec/integration/mappers/renaming_attributes_spec.rb +8 -6
  61. data/spec/integration/mappers/symbolizing_attributes_spec.rb +80 -0
  62. data/spec/integration/mappers/wrap_spec.rb +162 -0
  63. data/spec/integration/multi_repo_spec.rb +64 -0
  64. data/spec/integration/relations/reading_spec.rb +12 -8
  65. data/spec/integration/relations/registry_dsl_spec.rb +1 -3
  66. data/spec/integration/schema_spec.rb +10 -0
  67. data/spec/integration/setup_spec.rb +57 -6
  68. data/spec/spec_helper.rb +2 -1
  69. data/spec/unit/config_spec.rb +60 -0
  70. data/spec/unit/rom/adapter/memory/dataset_spec.rb +52 -0
  71. data/spec/unit/rom/adapter_spec.rb +31 -11
  72. data/spec/unit/rom/header_spec.rb +60 -16
  73. data/spec/unit/rom/mapper_builder_spec.rb +311 -0
  74. data/spec/unit/rom/mapper_registry_spec.rb +25 -0
  75. data/spec/unit/rom/mapper_spec.rb +4 -5
  76. data/spec/unit/rom/model_builder_spec.rb +15 -13
  77. data/spec/unit/rom/processor/transproc_spec.rb +331 -0
  78. data/spec/unit/rom/reader_spec.rb +73 -0
  79. data/spec/unit/rom/registry_spec.rb +38 -0
  80. data/spec/unit/rom/relation_spec.rb +0 -1
  81. data/spec/unit/rom/setup_spec.rb +55 -0
  82. data/spec/unit/rom_spec.rb +14 -0
  83. metadata +62 -22
  84. data/Gemfile.devtools +0 -71
  85. data/lib/rom/boot.rb +0 -197
  86. data/lib/rom/boot/command_dsl.rb +0 -48
  87. data/lib/rom/boot/dsl.rb +0 -37
  88. data/lib/rom/boot/mapper_dsl.rb +0 -23
  89. data/lib/rom/boot/schema_dsl.rb +0 -27
  90. data/lib/rom/ra.rb +0 -172
  91. data/lib/rom/ra/operation/group.rb +0 -47
  92. data/lib/rom/ra/operation/join.rb +0 -39
  93. data/lib/rom/ra/operation/wrap.rb +0 -45
  94. data/lib/rom/transformer.rb +0 -77
  95. data/spec/integration/ra/group_spec.rb +0 -46
  96. data/spec/integration/ra/join_spec.rb +0 -50
  97. data/spec/integration/ra/wrap_spec.rb +0 -37
  98. data/spec/unit/rom/ra/operation/group_spec.rb +0 -55
  99. data/spec/unit/rom/ra/operation/wrap_spec.rb +0 -29
  100. data/spec/unit/rom/transformer_spec.rb +0 -41
@@ -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