rom 0.7.1 → 0.8.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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +5 -8
  4. data/CHANGELOG.md +28 -1
  5. data/CODE_OF_CONDUCT.md +13 -0
  6. data/Gemfile +2 -2
  7. data/lib/rom.rb +1 -1
  8. data/lib/rom/command.rb +7 -5
  9. data/lib/rom/command_registry.rb +1 -1
  10. data/lib/rom/commands.rb +0 -2
  11. data/lib/rom/commands/abstract.rb +55 -25
  12. data/lib/rom/commands/composite.rb +13 -1
  13. data/lib/rom/commands/delete.rb +0 -8
  14. data/lib/rom/commands/graph.rb +102 -0
  15. data/lib/rom/commands/graph/class_interface.rb +69 -0
  16. data/lib/rom/commands/lazy.rb +87 -0
  17. data/lib/rom/constants.rb +22 -0
  18. data/lib/rom/env.rb +48 -18
  19. data/lib/rom/gateway.rb +132 -0
  20. data/lib/rom/global.rb +19 -19
  21. data/lib/rom/header.rb +42 -16
  22. data/lib/rom/header/attribute.rb +37 -15
  23. data/lib/rom/lint/gateway.rb +94 -0
  24. data/lib/rom/lint/spec.rb +15 -3
  25. data/lib/rom/lint/test.rb +45 -14
  26. data/lib/rom/mapper.rb +23 -10
  27. data/lib/rom/mapper/attribute_dsl.rb +157 -18
  28. data/lib/rom/memory.rb +1 -1
  29. data/lib/rom/memory/commands.rb +10 -8
  30. data/lib/rom/memory/dataset.rb +22 -2
  31. data/lib/rom/memory/{repository.rb → gateway.rb} +10 -10
  32. data/lib/rom/pipeline.rb +2 -1
  33. data/lib/rom/processor/transproc.rb +105 -14
  34. data/lib/rom/relation.rb +4 -4
  35. data/lib/rom/relation/class_interface.rb +19 -13
  36. data/lib/rom/relation/graph.rb +22 -0
  37. data/lib/rom/relation/lazy.rb +5 -3
  38. data/lib/rom/repository.rb +9 -118
  39. data/lib/rom/setup.rb +21 -14
  40. data/lib/rom/setup/finalize.rb +19 -19
  41. data/lib/rom/setup_dsl/relation.rb +10 -1
  42. data/lib/rom/support/deprecations.rb +21 -3
  43. data/lib/rom/support/enumerable_dataset.rb +1 -1
  44. data/lib/rom/version.rb +1 -1
  45. data/rom.gemspec +2 -4
  46. data/spec/integration/commands/delete_spec.rb +6 -0
  47. data/spec/integration/commands/graph_spec.rb +235 -0
  48. data/spec/integration/mappers/combine_spec.rb +14 -5
  49. data/spec/integration/mappers/definition_dsl_spec.rb +6 -1
  50. data/spec/integration/mappers/exclude_spec.rb +28 -0
  51. data/spec/integration/mappers/fold_spec.rb +16 -0
  52. data/spec/integration/mappers/group_spec.rb +0 -22
  53. data/spec/integration/mappers/prefix_separator_spec.rb +54 -0
  54. data/spec/integration/mappers/prefix_spec.rb +50 -0
  55. data/spec/integration/mappers/reusing_mappers_spec.rb +21 -0
  56. data/spec/integration/mappers/step_spec.rb +120 -0
  57. data/spec/integration/mappers/unfold_spec.rb +93 -0
  58. data/spec/integration/mappers/ungroup_spec.rb +127 -0
  59. data/spec/integration/mappers/unwrap_spec.rb +2 -2
  60. data/spec/integration/multi_repo_spec.rb +11 -11
  61. data/spec/integration/repositories/setting_logger_spec.rb +2 -2
  62. data/spec/integration/setup_spec.rb +11 -1
  63. data/spec/shared/command_behavior.rb +18 -0
  64. data/spec/shared/materializable.rb +4 -2
  65. data/spec/shared/users_and_tasks.rb +3 -3
  66. data/spec/test/memory_repository_lint_test.rb +4 -4
  67. data/spec/unit/rom/commands/graph_spec.rb +198 -0
  68. data/spec/unit/rom/commands/lazy_spec.rb +88 -0
  69. data/spec/unit/rom/commands_spec.rb +2 -2
  70. data/spec/unit/rom/env_spec.rb +26 -0
  71. data/spec/unit/rom/gateway_spec.rb +90 -0
  72. data/spec/unit/rom/global_spec.rb +4 -3
  73. data/spec/unit/rom/mapper/dsl_spec.rb +42 -1
  74. data/spec/unit/rom/mapper_spec.rb +4 -1
  75. data/spec/unit/rom/memory/commands/create_spec.rb +21 -0
  76. data/spec/unit/rom/memory/commands/delete_spec.rb +21 -0
  77. data/spec/unit/rom/memory/commands/update_spec.rb +21 -0
  78. data/spec/unit/rom/memory/relation_spec.rb +42 -10
  79. data/spec/unit/rom/memory/repository_spec.rb +3 -3
  80. data/spec/unit/rom/processor/transproc_spec.rb +75 -0
  81. data/spec/unit/rom/relation/lazy/combine_spec.rb +33 -4
  82. data/spec/unit/rom/relation/lazy_spec.rb +9 -1
  83. data/spec/unit/rom/repository_spec.rb +4 -63
  84. data/spec/unit/rom/setup_spec.rb +19 -5
  85. metadata +28 -38
  86. data/.ruby-version +0 -1
  87. data/lib/rom/lint/repository.rb +0 -94
@@ -17,9 +17,13 @@ describe 'Mapper definition DSL' do
17
17
  end
18
18
 
19
19
  setup.relation(:users) do
20
- def addresses(_users_)
20
+ def addresses(_users)
21
21
  [{ city: 'NYC', user: 'Jane' }, { city: 'Boston', user: 'Joe' }]
22
22
  end
23
+
24
+ def books(_users)
25
+ [{ title: 'Book One', user: 'Jane' }, { title: 'Book Two', user: 'Joe' }]
26
+ end
23
27
  end
24
28
 
25
29
  setup.mappers do
@@ -53,6 +57,8 @@ describe 'Mapper definition DSL' do
53
57
 
54
58
  attribute :city
55
59
  end
60
+
61
+ combine :book, on: { name: :user }, type: :hash
56
62
  end
57
63
  end
58
64
  end
@@ -70,7 +76,8 @@ describe 'Mapper definition DSL' do
70
76
  Test::Task.new(title: 'sleep well', meta: { user: 'Joe', priority: 2 },
71
77
  tags: [])
72
78
  ],
73
- address: Test::Address.new(city: 'Boston')
79
+ address: Test::Address.new(city: 'Boston'),
80
+ book: { title: 'Book Two', user: 'Joe' }
74
81
  )
75
82
  }
76
83
 
@@ -85,20 +92,22 @@ describe 'Mapper definition DSL' do
85
92
  tags: [Test::Tag.new(name: 'blue')]
86
93
  )
87
94
  ],
88
- address: Test::Address.new(city: 'NYC')
95
+ address: Test::Address.new(city: 'NYC'),
96
+ book: { title: 'Book One', user: 'Jane' }
89
97
  )
90
98
  }
91
99
 
92
100
  it 'works' do
93
101
  rom
94
102
 
95
- Test::User.send(:include, Equalizer.new(:name, :email, :tasks, :address))
103
+ Test::User.send(:include, Equalizer.new(:name, :email, :tasks, :address, :book))
96
104
  Test::Task.send(:include, Equalizer.new(:title, :meta))
97
105
  Test::Address.send(:include, Equalizer.new(:city))
98
106
 
99
107
  result = users.combine(
100
108
  tasks.for_users.combine(tasks.tags),
101
- users.addresses
109
+ users.addresses,
110
+ users.books
102
111
  ).as(:entity)
103
112
 
104
113
  expect(result).to match_array([joe, jane])
@@ -84,7 +84,12 @@ describe 'Mapper definition DSL' do
84
84
  end
85
85
 
86
86
  it 'inherits the attributes from the parent by default' do
87
- expect(header.keys).to eql([:email])
87
+ expect(header.keys).to eql([:name, :email])
88
+ end
89
+
90
+ it 'excludes an inherited attribute when requested' do
91
+ name = header.attributes[:name]
92
+ expect(name).to be_kind_of ROM::Header::Exclude
88
93
  end
89
94
 
90
95
  it 'builds a new model' do
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+ require 'rom/memory'
3
+
4
+ describe 'Mapper definition DSL' do
5
+ let(:setup) { ROM.setup(:memory) }
6
+ let(:rom) { ROM.finalize.env }
7
+
8
+ before do
9
+ setup.relation(:users)
10
+
11
+ users = setup.default.dataset(:users)
12
+
13
+ users.insert(name: 'Joe', email: 'joe@doe.com')
14
+ users.insert(name: 'Jane', email: 'jane@doe.com')
15
+ end
16
+
17
+ describe 'exclude' do
18
+ let(:mapped_users) { rom.relation(:users).as(:users).to_a }
19
+
20
+ it 'removes the attribute' do
21
+ setup.mappers do
22
+ define(:users) { exclude :email }
23
+ end
24
+
25
+ expect(mapped_users).to eql [{ name: 'Joe' }, { name: 'Jane' }]
26
+ end
27
+ end
28
+ end
@@ -50,5 +50,21 @@ describe 'Mapper definition DSL' do
50
50
  { name: 'Jane', email: 'jane@doe.org', priorities: [2] }
51
51
  ]
52
52
  end
53
+
54
+ it 'accepts the block syntax' do
55
+ setup.mappers do
56
+ define(:users) do
57
+ fold :priorities do
58
+ attribute :priority
59
+ attribute :title
60
+ end
61
+ end
62
+ end
63
+
64
+ expect(actual).to eql [
65
+ { name: 'Joe', email: 'joe@doe.org', priorities: [1, 2] },
66
+ { name: 'Jane', email: 'jane@doe.org', priorities: [2] }
67
+ ]
68
+ end
53
69
  end
54
70
  end
@@ -158,27 +158,5 @@ describe 'Mapper definition DSL' do
158
158
  ])
159
159
  )
160
160
  end
161
-
162
- it 'allows defining grouped attributes with the same name as their keys' do
163
- setup.mappers do
164
- define(:with_tasks, parent: :users) do
165
-
166
- attribute :name
167
- attribute :email
168
-
169
- group title: [:title, :priority]
170
- end
171
- end
172
-
173
- rom = setup.finalize
174
-
175
- jane = rom.relation(:users).with_tasks.map_with(:with_tasks).to_a.last
176
-
177
- expect(jane).to eql(
178
- name: 'Jane',
179
- email: 'jane@doe.org',
180
- title: [{ title: 'be cool', priority: 2 }]
181
- )
182
- end
183
161
  end
184
162
  end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+ require 'rom/memory'
3
+
4
+ describe 'Mapper definition DSL' do
5
+ let(:setup) { ROM.setup(:memory) }
6
+ let(:rom) { ROM.finalize.env }
7
+
8
+ before do
9
+ setup.relation(:users)
10
+
11
+ users = setup.default.dataset(:users)
12
+ users.insert(
13
+ user_id: 1,
14
+ user_name: 'Joe',
15
+ user_email: 'joe@doe.com',
16
+ 'user.skype' => 'joe',
17
+ :'user.phone' => '1234567890'
18
+ )
19
+ end
20
+
21
+ describe 'prefix' do
22
+ subject(:mapped_users) { rom.relation(:users).as(:users).to_a }
23
+
24
+ it 'applies new separator to the attributes following it' do
25
+ setup.mappers do
26
+ define(:users) do
27
+
28
+ prefix :user
29
+ attribute :id
30
+ attribute :name
31
+ wrap :contacts do
32
+ attribute :email
33
+
34
+ prefix_separator '.'
35
+ attribute 'skype'
36
+ attribute :phone
37
+ end
38
+ end
39
+ end
40
+
41
+ expect(mapped_users).to eql [
42
+ {
43
+ id: 1,
44
+ name: 'Joe',
45
+ contacts: {
46
+ email: 'joe@doe.com',
47
+ 'skype' => 'joe',
48
+ phone: '1234567890'
49
+ }
50
+ }
51
+ ]
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+ require 'rom/memory'
3
+
4
+ describe 'Mapper definition DSL' do
5
+ let(:setup) { ROM.setup(:memory) }
6
+ let(:rom) { ROM.finalize.env }
7
+
8
+ before do
9
+ setup.relation(:users)
10
+
11
+ users = setup.default.dataset(:users)
12
+ users.insert(
13
+ user_id: 1,
14
+ user_name: 'Joe',
15
+ user_email: 'joe@doe.com',
16
+ contact_skype: 'joe',
17
+ contact_phone: '1234567890'
18
+ )
19
+ end
20
+
21
+ describe 'prefix' do
22
+ subject(:mapped_users) { rom.relation(:users).as(:users).to_a }
23
+
24
+ it 'applies new prefix to the attributes following it' do
25
+ setup.mappers do
26
+ define(:users) do
27
+
28
+ prefix :user
29
+ attribute :id
30
+ attribute :name
31
+ wrap :contacts do
32
+ attribute :email
33
+
34
+ prefix :contact
35
+ attribute :skype
36
+ attribute :phone
37
+ end
38
+ end
39
+ end
40
+
41
+ expect(mapped_users).to eql [
42
+ {
43
+ id: 1,
44
+ name: 'Joe',
45
+ contacts: { email: 'joe@doe.com', skype: 'joe', phone: '1234567890' }
46
+ }
47
+ ]
48
+ end
49
+ end
50
+ end
@@ -19,4 +19,25 @@ describe 'Reusing mappers' do
19
19
  { name: 'Jane', tasks: [{ title: 'One' }, { title: 'Two' }] }
20
20
  ])
21
21
  end
22
+
23
+ it 'allows using another mapper in an embbedded hash' do
24
+ class Test::PriorityMapper < ROM::Mapper
25
+ attribute :value, type: :integer
26
+ attribute :desc
27
+ end
28
+
29
+ class Test::TaskMapper < ROM::Mapper
30
+ attribute :title
31
+ embedded :priority, type: :hash, mapper: Test::PriorityMapper
32
+ end
33
+
34
+ mapper = Test::TaskMapper.build
35
+ relation = [{ title: 'Task One', priority: { value: '1' } }, { title: 'Task Two', priority: { value: '2' } }]
36
+ result = mapper.call(relation)
37
+
38
+ expect(result).to eql([
39
+ { title: 'Task One', priority: { value: 1 } },
40
+ { title: 'Task Two', priority: { value: 2 } }
41
+ ])
42
+ end
22
43
  end
@@ -0,0 +1,120 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Mapper definition DSL' do
4
+ let(:setup) { ROM.setup(:memory) }
5
+ let(:rom) { ROM.finalize.env }
6
+
7
+ before do
8
+ setup.relation(:lists)
9
+
10
+ setup.default.dataset(:lists).insert(
11
+ list_id: 1,
12
+ list_tasks: [
13
+ { user: 'Jacob', task_id: 1, task_title: 'be nice' },
14
+ { user: 'Jacob', task_id: 2, task_title: 'sleep well' }
15
+ ]
16
+ )
17
+ end
18
+
19
+ describe 'step' do
20
+ let(:mapped) { rom.relation(:lists).as(:lists).to_a }
21
+
22
+ it 'applies transformations one by one' do
23
+ setup.mappers do
24
+ define(:lists) do
25
+ step do
26
+ prefix 'list'
27
+ attribute :id
28
+ unfold :tasks
29
+ end
30
+
31
+ step do
32
+ unwrap :tasks do
33
+ attribute :task_id
34
+ attribute :name, from: :user
35
+ attribute :task_title
36
+ end
37
+ end
38
+
39
+ step do
40
+ group :tasks do
41
+ prefix 'task'
42
+ attribute :id
43
+ attribute :title
44
+ end
45
+ end
46
+
47
+ step do
48
+ wrap :user do
49
+ attribute :name
50
+ attribute :tasks
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ expect(mapped).to eql [
57
+ {
58
+ id: 1,
59
+ user: {
60
+ name: 'Jacob',
61
+ tasks: [
62
+ { id: 1, title: 'be nice' },
63
+ { id: 2, title: 'sleep well' }
64
+ ]
65
+ }
66
+ }
67
+ ]
68
+ end
69
+
70
+ it 'applies settings from root' do
71
+ setup.mappers do
72
+ define(:lists) do
73
+
74
+ prefix 'list'
75
+
76
+ step do
77
+ attribute :id
78
+ attribute :tasks
79
+ end
80
+ end
81
+ end
82
+
83
+ expect(mapped).to eql [
84
+ {
85
+ id: 1,
86
+ tasks: [
87
+ { user: 'Jacob', task_id: 1, task_title: 'be nice' },
88
+ { user: 'Jacob', task_id: 2, task_title: 'sleep well' }
89
+ ]
90
+ }
91
+ ]
92
+ end
93
+
94
+ it 'cannot precede attributes' do
95
+ setup.mappers do
96
+ define(:lists) do
97
+ step do
98
+ unfold :tasks, from: :list_tasks
99
+ end
100
+ attribute :id, from: :list_id
101
+ end
102
+ end
103
+
104
+ expect { rom }.to raise_error ROM::MapperMisconfiguredError
105
+ end
106
+
107
+ it 'cannot succeed attributes' do
108
+ setup.mappers do
109
+ define(:lists) do
110
+ attribute :id, from: :list_id
111
+ step do
112
+ unfold :tasks, from: :list_tasks
113
+ end
114
+ end
115
+ end
116
+
117
+ expect { rom }.to raise_error ROM::MapperMisconfiguredError
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,93 @@
1
+ require 'spec_helper'
2
+ require 'rom/memory'
3
+
4
+ describe 'Mapper definition DSL' do
5
+ let(:setup) { ROM.setup(:memory) }
6
+ let(:rom) { ROM.finalize.env }
7
+
8
+ before do
9
+ setup.relation(:users)
10
+
11
+ users = setup.default.dataset(:users)
12
+
13
+ users.insert(name: 'Joe', roles: ['admin', 'user', 'user', nil])
14
+ users.insert(name: 'Jane', roles: 'user')
15
+ users.insert(name: 'John')
16
+ end
17
+
18
+ describe 'unfold' do
19
+ let(:mapped_users) { rom.relation(:users).as(:users).to_a }
20
+
21
+ it 'splits the attribute' do
22
+ setup.mappers do
23
+ define(:users) { unfold :roles }
24
+ end
25
+
26
+ expect(mapped_users).to eql [
27
+ { name: 'Joe', roles: 'admin' },
28
+ { name: 'Joe', roles: 'user' },
29
+ { name: 'Joe', roles: 'user' },
30
+ { name: 'Joe', roles: nil },
31
+ { name: 'Jane', roles: 'user' },
32
+ { name: 'John' }
33
+ ]
34
+ end
35
+
36
+ it 'renames unfolded attribute when necessary' do
37
+ setup.mappers do
38
+ define(:users) { unfold :role, from: :roles }
39
+ end
40
+
41
+ expect(mapped_users).to eql [
42
+ { name: 'Joe', role: 'admin' },
43
+ { name: 'Joe', role: 'user' },
44
+ { name: 'Joe', role: 'user' },
45
+ { name: 'Joe', role: nil },
46
+ { name: 'Jane', role: 'user' },
47
+ { name: 'John' }
48
+ ]
49
+ end
50
+
51
+ it 'rewrites the existing attribute' do
52
+ setup.mappers do
53
+ define(:users) { unfold :name, from: :roles }
54
+ end
55
+
56
+ expect(mapped_users).to eql [
57
+ { name: 'admin' },
58
+ { name: 'user' },
59
+ { name: 'user' },
60
+ { name: nil },
61
+ { name: 'user' },
62
+ {}
63
+ ]
64
+ end
65
+
66
+ it 'ignores the absent attribute' do
67
+ setup.mappers do
68
+ define(:users) { unfold :foo, from: :absent }
69
+ end
70
+
71
+ expect(mapped_users).to eql [
72
+ { name: 'Joe', roles: ['admin', 'user', 'user', nil] },
73
+ { name: 'Jane', roles: 'user' },
74
+ { name: 'John' }
75
+ ]
76
+ end
77
+
78
+ it 'accepts block' do
79
+ setup.mappers do
80
+ define(:users) { unfold(:role, from: :roles) {} }
81
+ end
82
+
83
+ expect(mapped_users).to eql [
84
+ { name: 'Joe', role: 'admin' },
85
+ { name: 'Joe', role: 'user' },
86
+ { name: 'Joe', role: 'user' },
87
+ { name: 'Joe', role: nil },
88
+ { name: 'Jane', role: 'user' },
89
+ { name: 'John' }
90
+ ]
91
+ end
92
+ end
93
+ end