rom-repository 1.4.0 → 2.0.0.beta1

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 (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