rom 0.7.1 → 0.8.0

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