rom-repository 1.4.0 → 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -6
  3. data/{LICENSE.txt → LICENSE} +1 -1
  4. data/README.md +18 -1
  5. data/lib/rom-repository.rb +1 -2
  6. data/lib/rom/repository.rb +9 -216
  7. data/lib/rom/repository/class_interface.rb +16 -33
  8. data/lib/rom/repository/relation_reader.rb +46 -0
  9. data/lib/rom/repository/root.rb +3 -59
  10. data/lib/rom/repository/version.rb +1 -1
  11. metadata +9 -98
  12. data/.gitignore +0 -3
  13. data/.rspec +0 -3
  14. data/.travis.yml +0 -27
  15. data/.yardopts +0 -2
  16. data/Gemfile +0 -38
  17. data/Rakefile +0 -19
  18. data/lib/rom/open_struct.rb +0 -35
  19. data/lib/rom/repository/changeset.rb +0 -155
  20. data/lib/rom/repository/changeset/associated.rb +0 -100
  21. data/lib/rom/repository/changeset/create.rb +0 -16
  22. data/lib/rom/repository/changeset/delete.rb +0 -17
  23. data/lib/rom/repository/changeset/pipe.rb +0 -97
  24. data/lib/rom/repository/changeset/restricted.rb +0 -28
  25. data/lib/rom/repository/changeset/stateful.rb +0 -282
  26. data/lib/rom/repository/changeset/update.rb +0 -82
  27. data/lib/rom/repository/command_compiler.rb +0 -257
  28. data/lib/rom/repository/command_proxy.rb +0 -26
  29. data/lib/rom/repository/header_builder.rb +0 -65
  30. data/lib/rom/repository/mapper_builder.rb +0 -23
  31. data/lib/rom/repository/relation_proxy.rb +0 -337
  32. data/lib/rom/repository/relation_proxy/combine.rb +0 -320
  33. data/lib/rom/repository/relation_proxy/wrap.rb +0 -78
  34. data/lib/rom/repository/struct_builder.rb +0 -83
  35. data/lib/rom/struct.rb +0 -113
  36. data/log/.gitkeep +0 -0
  37. data/rom-repository.gemspec +0 -23
  38. data/spec/integration/changeset_spec.rb +0 -193
  39. data/spec/integration/command_macros_spec.rb +0 -191
  40. data/spec/integration/command_spec.rb +0 -228
  41. data/spec/integration/multi_adapter_spec.rb +0 -73
  42. data/spec/integration/repository/aggregate_spec.rb +0 -58
  43. data/spec/integration/repository_spec.rb +0 -406
  44. data/spec/integration/root_repository_spec.rb +0 -106
  45. data/spec/integration/typed_structs_spec.rb +0 -64
  46. data/spec/shared/database.rb +0 -79
  47. data/spec/shared/mappers.rb +0 -35
  48. data/spec/shared/models.rb +0 -41
  49. data/spec/shared/plugins.rb +0 -66
  50. data/spec/shared/relations.rb +0 -115
  51. data/spec/shared/repo.rb +0 -86
  52. data/spec/shared/seeds.rb +0 -30
  53. data/spec/shared/structs.rb +0 -140
  54. data/spec/spec_helper.rb +0 -83
  55. data/spec/support/mapper_registry.rb +0 -9
  56. data/spec/support/mutant.rb +0 -10
  57. data/spec/unit/changeset/associate_spec.rb +0 -120
  58. data/spec/unit/changeset/map_spec.rb +0 -111
  59. data/spec/unit/changeset_spec.rb +0 -186
  60. data/spec/unit/relation_proxy_spec.rb +0 -202
  61. data/spec/unit/repository/changeset_spec.rb +0 -197
  62. data/spec/unit/repository/inspect_spec.rb +0 -18
  63. data/spec/unit/repository/session_spec.rb +0 -251
  64. data/spec/unit/repository/transaction_spec.rb +0 -42
  65. data/spec/unit/session_spec.rb +0 -46
  66. data/spec/unit/struct_builder_spec.rb +0 -128
@@ -1,191 +0,0 @@
1
- RSpec.describe ROM::Repository, '.command' do
2
- include_context 'database'
3
- include_context 'relations'
4
-
5
- it 'allows configuring a create command' do
6
- repo = Class.new(ROM::Repository[:users]) do
7
- commands :create
8
- end.new(rom)
9
-
10
- user = repo.create(name: 'Jane')
11
-
12
- expect(user.id).to_not be(nil)
13
- expect(user.name).to eql('Jane')
14
- end
15
-
16
- it 'allows configuring an update and delete commands' do
17
- repo = Class.new(ROM::Repository[:users]) do
18
- commands :create, update: :by_pk, delete: :by_pk
19
- end.new(rom)
20
-
21
- user = repo.create(name: 'Jane')
22
-
23
- repo.update(user.id, name: 'Jane Doe')
24
-
25
- user = repo.users.by_pk(user.id).one
26
-
27
- expect(user.name).to eql('Jane Doe')
28
-
29
- repo.delete(user.id)
30
-
31
- expect(repo.users.by_pk(user.id).one).to be(nil)
32
- end
33
-
34
- it 'configures an update command with custom restriction' do
35
- repo = Class.new(ROM::Repository[:users]) do
36
- commands update: :by_name
37
- end.new(rom)
38
-
39
- repo.relations.users.insert(name: 'Jade')
40
-
41
- user = repo.update('Jade', name: 'Jade Doe')
42
- expect(user.name).to eql('Jade Doe')
43
-
44
- expect(repo.update('Oops', name: 'Jade')).to be(nil)
45
- end
46
-
47
- it 'allows to configure update command without create one' do
48
- repo = Class.new(ROM::Repository[:users]) do
49
- commands update: :by_pk
50
- end.new(rom)
51
-
52
- user = repo.command(create: :users)[name: 'Jane']
53
-
54
- repo.update(user.id, name: 'Jane Doe')
55
-
56
- updated_user = repo.users.by_pk(user.id).one
57
-
58
- expect(updated_user.name).to eql('Jane Doe')
59
- end
60
-
61
- it 'allows to configure :delete command without args' do
62
- repo = Class.new(ROM::Repository[:users]) do
63
- commands :delete
64
- end.new(rom)
65
-
66
- repo.users.insert(name: 'Jane')
67
- repo.users.insert(name: 'John')
68
-
69
- repo.delete
70
-
71
- expect(repo.users.count).to be_zero
72
- end
73
-
74
- it 'allows defining a single command with multiple views' do
75
- repo = Class.new(ROM::Repository[:users]) do
76
- commands :create, update: [:by_pk, :by_name]
77
- end.new(rom)
78
-
79
- user = repo.create(name: 'Jane')
80
-
81
- repo.update_by_pk(user.id, name: 'Jane Doe')
82
- user = repo.users.by_pk(user.id).one
83
- expect(user.name).to eql('Jane Doe')
84
-
85
- repo.update_by_name(user.name, name: 'Jane')
86
- user = repo.users.by_pk(user.id).one
87
- expect(user.name).to eql('Jane')
88
- end
89
-
90
- it 'uses a mapper built from AST by default' do
91
- repo = Class.new(ROM::Repository[:users]) do
92
- commands :create
93
- end.new(rom)
94
-
95
- user = repo.create(name: 'Jane')
96
-
97
- expect(user).to be_kind_of Dry::Struct
98
-
99
- struct_definition = [:users, [:header, [
100
- [:attribute, repo.users.schema[:id]],
101
- [:attribute, repo.users.schema[:name]]]]]
102
-
103
- expect(user).to be_an_instance_of ROM::Repository::StructBuilder.cache[struct_definition.hash]
104
- end
105
-
106
- describe 'using plugins' do
107
- include_context 'plugins'
108
-
109
- before do
110
- conn.alter_table :users do
111
- add_column :created_at, :timestamp, null: false
112
- add_column :updated_at, :timestamp, null: false
113
- end
114
- end
115
-
116
- it 'allows to use plugins in generated commands' do
117
- repo = Class.new(ROM::Repository[:users]) do
118
- commands :create, update: :by_pk, use: :timestamps
119
- end.new(rom)
120
-
121
- user = repo.create(name: 'Jane')
122
- expect(user.created_at).to be_within(1).of Time.now
123
- expect(user.created_at).to eql(user.updated_at)
124
-
125
- repo.update(user.id, **user, name: 'Jane Doe')
126
- updated_user = repo.users.by_pk(user.id).one
127
- expect(updated_user.created_at).to eql(user.created_at)
128
- expect(updated_user.updated_at).to be > updated_user.created_at
129
- end
130
-
131
- it 'allows to use several plugins' do
132
- repo = Class.new(ROM::Repository[:users]) do
133
- commands :create, use: %i(upcase_name timestamps)
134
- end.new(rom)
135
-
136
- user = repo.create(name: 'Jane')
137
- expect(user.created_at).to be_within(1).of Time.now
138
- expect(user.name).to eql('JANE')
139
- end
140
- end
141
-
142
- describe 'using custom mappers' do
143
- before do
144
- configuration.mappers do
145
- register :users,
146
- name_list: -> users { users.map { |u| u[:name] } },
147
- id_list: -> users { users.map { |u| u[:id] } }
148
- end
149
- end
150
-
151
- it 'allows to use named mapper in commands' do
152
- repo = Class.new(ROM::Repository[:users]).new(rom)
153
-
154
- name = repo.command(create: :users, mapper: :name_list).call(name: 'Jane')
155
-
156
- expect(name).to eql('Jane')
157
- end
158
-
159
- it 'caches command pipeline using mapper option' do
160
- repo = Class.new(ROM::Repository[:users]).new(rom)
161
-
162
- c1 = repo.command(create: :users, mapper: :name_list)
163
- c2 = repo.command(create: :users, mapper: :name_list)
164
- c3 = repo.command(create: :users, mapper: :id_list)
165
-
166
- name = c1.call(name: 'Jane')
167
- id = c3.call(name: 'John')
168
-
169
- expect(c1).to be c2
170
- expect(c3).not_to be c1
171
-
172
- expect(name).to eql('Jane')
173
- expect(id).to eql(2)
174
- end
175
-
176
- it 'allows to set a mapper with a class-level macro' do
177
- repo = Class.new(ROM::Repository[:users]) do
178
- commands :create, update: :by_pk, delete: :by_pk, mapper: :name_list
179
- end.new(rom)
180
-
181
- name = repo.create(name: 'Jane')
182
- expect(name).to eql('Jane')
183
-
184
- updated_name = repo.update(1, name: 'Jane Doe')
185
- expect(updated_name).to eql('Jane Doe')
186
-
187
- deleted_name = repo.delete(1)
188
- expect(deleted_name).to eql('Jane Doe')
189
- end
190
- end
191
- end
@@ -1,228 +0,0 @@
1
- RSpec.describe ROM::Repository, '#command' do
2
- include_context 'database'
3
- include_context 'relations'
4
- include_context 'repo'
5
-
6
- context 'accessing custom command from the registry' do
7
- before do
8
- configuration.commands(:users) do
9
- define(:upsert, type: ROM::SQL::Commands::Create)
10
- define(:create)
11
- end
12
-
13
- configuration.commands(:tasks) do
14
- define(:create)
15
- end
16
- end
17
-
18
- it 'returns registered command' do
19
- expect(repo.command(:users).upsert).to be(rom.command(:users).upsert)
20
- expect(repo.command(:users)[:upsert]).to be(rom.command(:users).upsert)
21
- end
22
-
23
- it 'exposes command builder DSL' do
24
- command = repo.command.create(user: :users) { |user| user.create(:tasks) }
25
-
26
- expect(command).to be_instance_of(ROM::Command::Graph)
27
- end
28
- end
29
-
30
- context ':create' do
31
- it 'builds Create command for a relation' do
32
- create_user = repo.command(create: :users)
33
-
34
- user = create_user.call(name: 'Jane Doe')
35
-
36
- expect(user.id).to_not be(nil)
37
- expect(user.name).to eql('Jane Doe')
38
- end
39
-
40
- it 'uses input_schema for command input' do
41
- create_user = repo.command(create: :users)
42
- expect(create_user.input).to eql(repo.users.input_schema)
43
- end
44
-
45
- it 'caches commands' do
46
- create_user = -> { repo.command(create: :users) }
47
-
48
- expect(create_user.()).to be(create_user.())
49
- end
50
-
51
- it 'builds Create command for a relation graph with one-to-one' do
52
- create_user = repo.command(
53
- :create,
54
- repo.users.combine_children(one: repo.tasks)
55
- )
56
-
57
- user = create_user.call(name: 'Jane Doe', task: { title: 'Task one' })
58
-
59
- expect(user.id).to_not be(nil)
60
- expect(user.name).to eql('Jane Doe')
61
- expect(user.task.title).to eql('Task one')
62
- end
63
-
64
- it 'builds Create command for a deeply nested relation graph' do
65
- create_user = repo.command(
66
- :create,
67
- repo.users.combine_children(one: repo.tasks.combine_children(many: repo.tags))
68
- )
69
-
70
- user = create_user.call(
71
- name: 'Jane Doe', task: { title: 'Task one', tags: [{ name: 'red' }] }
72
- )
73
-
74
- expect(user.id).to_not be(nil)
75
- expect(user.name).to eql('Jane Doe')
76
- expect(user.task.title).to eql('Task one')
77
- expect(user.task.tags).to be_instance_of(Array)
78
- expect(user.task.tags.first.name).to eql('red')
79
- end
80
-
81
- it 'builds Create command for a relation graph with one-to-many' do
82
- create_user = repo.command(
83
- :create,
84
- repo.users.combine_children(many: repo.tasks)
85
- )
86
-
87
- user = create_user.call(name: 'Jane Doe', tasks: [{ title: 'Task one' }])
88
-
89
- expect(user.id).to_not be(nil)
90
- expect(user.name).to eql('Jane Doe')
91
- expect(user.tasks).to be_instance_of(Array)
92
- expect(user.tasks.first.title).to eql('Task one')
93
- end
94
-
95
- it 'builds Create command for a relation graph with one-to-many with aliased association' do
96
- create_user = repo.command(:create, repo.users.combine(:aliased_posts))
97
-
98
- user = create_user.call(name: 'Jane Doe', aliased_posts: [{ title: 'Post one' }, { title: 'Post two' }])
99
-
100
- expect(user.id).to_not be(nil)
101
- expect(user.name).to eql('Jane Doe')
102
- expect(user.aliased_posts.size).to be(2)
103
- end
104
-
105
- it 'builds Create command for a deeply nested graph with one-to-many' do
106
- create_user = repo.command(
107
- :create,
108
- repo.aggregate(many: repo.tasks.combine_children(many: repo.tags))
109
- )
110
-
111
- user = create_user.call(
112
- name: 'Jane',
113
- tasks: [{ title: 'Task', tags: [{ name: 'red' }]}]
114
- )
115
-
116
- expect(user.id).to_not be(nil)
117
- expect(user.name).to eql('Jane')
118
- expect(user.tasks).to be_instance_of(Array)
119
- expect(user.tasks.first.title).to eql('Task')
120
- expect(user.tasks.first.tags).to be_instance_of(Array)
121
- expect(user.tasks.first.tags.first.name).to eql('red')
122
- end
123
-
124
- it 'builds Create command for a deeply nested graph with many-to-one & one-to-many' do
125
- create_user = repo.command(
126
- :create,
127
- repo.aggregate(one: repo.tasks.combine_children(many: repo.tags))
128
- )
129
-
130
- user = create_user.call(
131
- name: 'Jane', task: { title: 'Task', tags: [{ name: 'red' }, { name: 'blue' }] }
132
- )
133
-
134
- expect(user.id).to_not be(nil)
135
- expect(user.name).to eql('Jane')
136
- expect(user.task.title).to eql('Task')
137
- expect(user.task.tags).to be_instance_of(Array)
138
- expect(user.task.tags.size).to be(2)
139
- expect(user.task.tags[0].name).to eql('red')
140
- expect(user.task.tags[1].name).to eql('blue')
141
- end
142
-
143
- it 'builds Create command for a deeply nested graph with many-to-one' do
144
- create_user = repo.command(
145
- :create,
146
- repo.aggregate(one: repo.tasks.combine_children(one: repo.tags))
147
- )
148
-
149
- user = create_user.call(
150
- name: 'Jane', task: { title: 'Task', tag: { name: 'red' } }
151
- )
152
-
153
- expect(user.id).to_not be(nil)
154
- expect(user.name).to eql('Jane')
155
- expect(user.task.id).to_not be(nil)
156
- expect(user.task.title).to eql('Task')
157
- expect(user.task.tag.id).to_not be(nil)
158
- expect(user.task.tag.name).to eql('red')
159
- end
160
-
161
- it 'builds Create command for a nested graph with many-to-many' do
162
- user = repo.command(:create, repo.users).(name: 'Jane')
163
-
164
- create_post = repo.command(
165
- :create, repo.posts.combine_children(many: { labels: repo.labels })
166
- )
167
-
168
- post = create_post.call(
169
- author_id: user.id, title: 'Jane post', labels: [{ name: 'red' }]
170
- )
171
-
172
- expect(post.labels.size).to be(1)
173
- end
174
-
175
- context 'relation with a custom dataset name' do
176
- it 'allows configuring a create command' do
177
- create_comment = comments_repo.command(create: :comments)
178
-
179
- comment = create_comment.(author: 'gerybabooma', body: 'DIS GUY MUST BE A ALIEN OR SUTIN')
180
-
181
- expect(comment.message_id).to eql(1)
182
- expect(comment.author).to eql('gerybabooma')
183
- expect(comment.body).to eql('DIS GUY MUST BE A ALIEN OR SUTIN')
184
- end
185
-
186
- it 'allows configuring a create command with aliased one-to-many' do
187
- pending 'custom association names in the input are not yet support'
188
-
189
- create_comment = comments_repo.command(:create, comments_repo.comments.combine(:emotions))
190
-
191
- comment = create_comment.(author: 'Jane',
192
- body: 'Hello Joe',
193
- emotions: [{ author: 'Joe' }])
194
-
195
- expect(comment.message_id).to eql(1)
196
- expect(comment.author).to eql('Jane')
197
- expect(comment.body).to eql('Hello Joe')
198
- expect(comment.emotions.size).to eql(1)
199
- expect(comment.emotions[0].author).to eql('Joe')
200
- end
201
- end
202
- end
203
-
204
- context ':update' do
205
- it 'builds Update command for a relation' do
206
- repo.users.insert(id: 3, name: 'Jane')
207
-
208
- update_user = repo.command(:update, repo.users)
209
-
210
- user = update_user.by_pk(3).call(name: 'Jane Doe')
211
-
212
- expect(user.id).to be(3)
213
- expect(user.name).to eql('Jane Doe')
214
- end
215
- end
216
-
217
- context ':delete' do
218
- it 'builds Delete command for a relation' do
219
- repo.users.insert(id: 3, name: 'Jane')
220
-
221
- delete_user = repo.command(:delete, repo.users)
222
-
223
- delete_user.by_pk(3).call
224
-
225
- expect(repo.users.by_pk(3).one).to be(nil)
226
- end
227
- end
228
- end
@@ -1,73 +0,0 @@
1
- # coding: utf-8
2
- RSpec.describe 'Repository with multi-adapters configuration' do
3
- let(:configuration) {
4
- ROM::Configuration.new(default: [:sql, DB_URI], memory: [:memory])
5
- }
6
-
7
- let(:sql_conn) { configuration.gateways[:default].connection }
8
-
9
- let(:rom) { ROM.container(configuration) }
10
-
11
- let(:users) { rom.relation(:sql_users) }
12
- let(:tasks) { rom.relation(:memory_tasks) }
13
-
14
- let(:repo) { Test::Repository.new(rom) }
15
-
16
- before do
17
- [:tags, :tasks, :posts, :books, :users, :posts_labels, :labels,
18
- :reactions, :messages].each { |table| sql_conn.drop_table?(table) }
19
-
20
- sql_conn.create_table :users do
21
- primary_key :id
22
- column :name, String
23
- end
24
-
25
- module Test
26
- class Users < ROM::Relation[:sql]
27
- schema(:users, as: :sql_users, infer: true)
28
- end
29
-
30
- class Tasks < ROM::Relation[:memory]
31
- schema(:tasks, as: :memory_tasks) do
32
- attribute :user_id, ROM::Types::Int
33
- attribute :title, ROM::Types::String
34
- end
35
-
36
- gateway :memory
37
-
38
- use :key_inference
39
-
40
- view(:base, [:user_id, :title]) do
41
- self
42
- end
43
-
44
- def for_users(users)
45
- restrict(user_id: users.pluck(:id))
46
- end
47
- end
48
-
49
- class Repository < ROM::Repository[:sql_users]
50
- relations :memory_tasks
51
-
52
- def users_with_tasks(id)
53
- aggregate(many: { tasks: memory_tasks }).where(id: id)
54
- end
55
- end
56
- end
57
-
58
- configuration.register_relation(Test::Users)
59
- configuration.register_relation(Test::Tasks)
60
-
61
- user_id = configuration.gateways[:default].dataset(:users).insert(name: 'Jane')
62
- configuration.gateways[:memory].dataset(:tasks).insert(user_id: user_id, title: 'Jane Task')
63
- end
64
-
65
- specify 'ᕕ⁞ ᵒ̌ 〜 ᵒ̌ ⁞ᕗ' do
66
- user = repo.users_with_tasks(users.last[:id]).first
67
-
68
- expect(user.name).to eql('Jane')
69
-
70
- expect(user.tasks[0].user_id).to eql(user.id)
71
- expect(user.tasks[0].title).to eql('Jane Task')
72
- end
73
- end