rom-sql 2.0.0.beta1 → 2.0.0.beta2

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2 -1
  3. data/lib/rom/plugins/relation/sql/auto_restrictions.rb +19 -6
  4. data/lib/rom/sql/attribute.rb +9 -0
  5. data/lib/rom/sql/commands/create.rb +0 -2
  6. data/lib/rom/sql/commands/delete.rb +0 -2
  7. data/lib/rom/sql/commands/update.rb +0 -2
  8. data/lib/rom/sql/extensions/postgres/attributes_inferrer.rb +1 -1
  9. data/lib/rom/sql/index.rb +16 -0
  10. data/lib/rom/sql/migration/inline_runner.rb +12 -4
  11. data/lib/rom/sql/migration/schema_diff.rb +23 -3
  12. data/lib/rom/sql/plugin/associates.rb +3 -3
  13. data/lib/rom/sql/plugin/timestamps.rb +2 -2
  14. data/lib/rom/sql/relation.rb +7 -0
  15. data/lib/rom/sql/relation/reading.rb +1 -1
  16. data/lib/rom/sql/schema.rb +2 -1
  17. data/lib/rom/sql/schema/dsl.rb +26 -0
  18. data/lib/rom/sql/schema/index_dsl.rb +50 -0
  19. data/lib/rom/sql/schema/inferrer.rb +11 -5
  20. data/lib/rom/sql/version.rb +1 -1
  21. data/spec/integration/auto_migrations/indexes_spec.rb +147 -3
  22. data/spec/integration/{graph_spec.rb → combine_with_spec.rb} +1 -1
  23. data/spec/integration/commands/create_spec.rb +37 -62
  24. data/spec/integration/commands/delete_spec.rb +6 -6
  25. data/spec/integration/commands/update_spec.rb +6 -8
  26. data/spec/integration/plugins/associates/many_to_many_spec.rb +2 -2
  27. data/spec/integration/plugins/associates_spec.rb +7 -7
  28. data/spec/integration/plugins/auto_restrictions_spec.rb +31 -0
  29. data/spec/integration/relation_schema_spec.rb +68 -0
  30. data/spec/integration/schema/inferrer_spec.rb +31 -6
  31. data/spec/support/helpers.rb +1 -1
  32. data/spec/unit/plugin/timestamp_spec.rb +2 -2
  33. data/spec/unit/types_spec.rb +1 -1
  34. metadata +6 -5
  35. data/lib/rom/sql/commands/transaction.rb +0 -33
@@ -1,5 +1,5 @@
1
1
  module ROM
2
2
  module SQL
3
- VERSION = '2.0.0.beta1'.freeze
3
+ VERSION = '2.0.0.beta2'.freeze
4
4
  end
5
5
  end
@@ -6,6 +6,7 @@ RSpec.describe ROM::SQL::Gateway, :postgres, :helpers do
6
6
  end
7
7
 
8
8
  let(:table_name) { :users }
9
+ let(:relation_name) { ROM::Relation::Name.new(table_name) }
9
10
 
10
11
  subject(:gateway) { container.gateways[:default] }
11
12
 
@@ -18,6 +19,14 @@ RSpec.describe ROM::SQL::Gateway, :postgres, :helpers do
18
19
 
19
20
  let(:attributes) { migrated_schema.to_a }
20
21
 
22
+ def indexdef(index)
23
+ gateway.connection[<<-SQL, index].first[:indexdef]
24
+ select indexdef
25
+ from pg_indexes
26
+ where indexname = ?
27
+ SQL
28
+ end
29
+
21
30
  describe 'create table' do
22
31
  describe 'one-column indexes' do
23
32
  before do
@@ -25,6 +34,10 @@ RSpec.describe ROM::SQL::Gateway, :postgres, :helpers do
25
34
  schema do
26
35
  attribute :id, ROM::SQL::Types::Serial
27
36
  attribute :name, ROM::SQL::Types::String.meta(index: true)
37
+
38
+ indexes do
39
+ index :name, name: :unique_name, unique: true
40
+ end
28
41
  end
29
42
  end
30
43
  end
@@ -43,6 +56,13 @@ RSpec.describe ROM::SQL::Gateway, :postgres, :helpers do
43
56
  [:definition, [String, {}]],
44
57
  source: :users]],
45
58
  ])
59
+
60
+ expect(migrated_schema.indexes.first).
61
+ to eql(ROM::SQL::Index.new(
62
+ [define_attribute(:name, :String, source: relation_name)],
63
+ name: :unique_name,
64
+ unique: true
65
+ ))
46
66
  end
47
67
  end
48
68
  end
@@ -51,23 +71,54 @@ RSpec.describe ROM::SQL::Gateway, :postgres, :helpers do
51
71
  describe 'one-column indexes' do
52
72
  context 'adding' do
53
73
  before do
74
+ end
75
+
76
+ it 'adds indexed column' do
77
+ conn.create_table :users do
78
+ primary_key :id
79
+ end
80
+
54
81
  conf.relation(:users) do
55
82
  schema do
56
83
  attribute :id, ROM::SQL::Types::Serial
57
84
  attribute :name, ROM::SQL::Types::String.meta(index: true)
58
85
  end
59
86
  end
87
+
88
+ gateway.auto_migrate!(conf)
89
+
90
+ name_index = migrated_schema.indexes.first
91
+
92
+ expect(migrated_schema.attributes[1].name).to eql(:name)
93
+ expect(migrated_schema.indexes.size).to eql(1)
94
+ expect(name_index.name).to eql(:users_name_index)
95
+ expect(name_index.attributes.map(&:name)).to eql(%i(name))
60
96
  end
61
97
 
62
- it 'adds indexed column' do
98
+ it 'supports custom names' do
63
99
  conn.create_table :users do
64
100
  primary_key :id
65
101
  end
66
102
 
103
+ conf.relation(:users) do
104
+ schema do
105
+ attribute :id, ROM::SQL::Types::Serial
106
+ attribute :name, ROM::SQL::Types::String
107
+
108
+ indexes do
109
+ index :name, name: :custom_idx
110
+ end
111
+ end
112
+ end
113
+
67
114
  gateway.auto_migrate!(conf)
68
115
 
116
+ name_index = migrated_schema.indexes.first
117
+
69
118
  expect(migrated_schema.attributes[1].name).to eql(:name)
70
- expect(migrated_schema.indexes.map { |idx| idx.attributes.map(&:name) }).to eql([%i(name)])
119
+ expect(migrated_schema.indexes.size).to eql(1)
120
+ expect(name_index.name).to eql(:custom_idx)
121
+ expect(name_index.attributes.map(&:name)).to eql(%i(name))
71
122
  end
72
123
 
73
124
  it 'adds index to existing column' do
@@ -76,9 +127,98 @@ RSpec.describe ROM::SQL::Gateway, :postgres, :helpers do
76
127
  column :name, String
77
128
  end
78
129
 
130
+ conf.relation(:users) do
131
+ schema do
132
+ attribute :id, ROM::SQL::Types::Serial
133
+ attribute :name, ROM::SQL::Types::String
134
+
135
+ indexes do
136
+ index :name
137
+ end
138
+ end
139
+ end
140
+
141
+ gateway.auto_migrate!(conf)
142
+
143
+ name_index = migrated_schema.indexes.first
144
+
145
+ expect(name_index.name).to eql(:users_name_index)
146
+ expect(name_index.attributes.map(&:name)).to eql(%i(name))
147
+ expect(name_index).not_to be_unique
148
+ end
149
+
150
+ it 'supports unique indexes' do
151
+ conn.create_table :users do
152
+ primary_key :id
153
+ column :name, String
154
+ end
155
+
156
+ conf.relation(:users) do
157
+ schema do
158
+ attribute :id, ROM::SQL::Types::Serial
159
+ attribute :name, ROM::SQL::Types::String
160
+
161
+ indexes do
162
+ index :name, unique: true
163
+ end
164
+ end
165
+ end
166
+
79
167
  gateway.auto_migrate!(conf)
80
168
 
81
- expect(migrated_schema.indexes.map { |idx| idx.attributes.map(&:name) }).to eql([%i(name)])
169
+ name_index = migrated_schema.indexes.first
170
+
171
+ expect(name_index.name).to eql(:users_name_index)
172
+ expect(name_index.attributes.map(&:name)).to eql(%i(name))
173
+ expect(name_index).to be_unique
174
+ end
175
+
176
+ if metadata[:postgres]
177
+ it 'uses index method' do
178
+ conn.create_table :users do
179
+ primary_key :id
180
+ column :props, :jsonb, null: false
181
+ end
182
+
183
+ conf.relation(:users) do
184
+ schema do
185
+ attribute :id, ROM::SQL::Types::Serial
186
+ attribute :props, ROM::SQL::Types::PG::JSONB
187
+
188
+ indexes do
189
+ index :props, type: :gin
190
+ end
191
+ end
192
+ end
193
+
194
+ gateway.auto_migrate!(conf)
195
+
196
+ expect(indexdef('users_props_index')).
197
+ to eql('CREATE INDEX users_props_index ON users USING gin (props)')
198
+ end
199
+
200
+ it 'supports partial indexes' do
201
+ conn.create_table :users do
202
+ primary_key :id
203
+ column :name, String
204
+ end
205
+
206
+ conf.relation(:users) do
207
+ schema do
208
+ attribute :id, ROM::SQL::Types::Serial
209
+ attribute :name, ROM::SQL::Types::String
210
+
211
+ indexes do
212
+ index :name, name: :long_names_only, predicate: 'length(name) > 10'
213
+ end
214
+ end
215
+ end
216
+
217
+ gateway.auto_migrate!(conf)
218
+
219
+ expect(indexdef('long_names_only')).
220
+ to eql('CREATE INDEX long_names_only ON users USING btree (name) WHERE (length(name) > 10)')
221
+ end
82
222
  end
83
223
  end
84
224
 
@@ -88,19 +228,23 @@ RSpec.describe ROM::SQL::Gateway, :postgres, :helpers do
88
228
  schema do
89
229
  attribute :id, ROM::SQL::Types::Serial
90
230
  attribute :name, ROM::SQL::Types::String
231
+ attribute :email, ROM::SQL::Types::String
91
232
  end
92
233
  end
93
234
 
94
235
  conn.create_table :users do
95
236
  primary_key :id
96
237
  column :name, String
238
+ column :email, String
97
239
 
98
240
  index :name
241
+ index :email, name: :email_idx
99
242
  end
100
243
  end
101
244
 
102
245
  it 'removes index' do
103
246
  gateway.auto_migrate!(conf)
247
+
104
248
  expect(migrated_schema.indexes).to be_empty
105
249
  end
106
250
  end
@@ -34,7 +34,7 @@ RSpec.describe 'Eager loading' do
34
34
  tasks = container.relations[:tasks]
35
35
  tags = container.relations[:tags]
36
36
 
37
- relation = users.graph(tasks.for_users.graph(tags.for_tasks))
37
+ relation = users.combine_with(tasks.for_users.combine_with(tags.for_tasks))
38
38
 
39
39
  # TODO: figure out a way to assert correct number of issued queries
40
40
  expect(relation.call).to be_instance_of(ROM::Relation::Loaded)
@@ -46,37 +46,37 @@ RSpec.describe 'Commands / Create', :postgres, seeds: false do
46
46
  with_adapters do
47
47
  describe '#transaction' do
48
48
  it 'creates record if nothing was raised' do
49
- result = create_user.transaction {
49
+ result = users.transaction {
50
50
  create_user.call(name: 'Jane')
51
51
  }
52
52
 
53
- expect(result.value).to eql(id: 1, name: 'Jane')
53
+ expect(result).to eql(id: 1, name: 'Jane')
54
54
  end
55
55
 
56
56
  it 'creates multiple records if nothing was raised' do
57
- result = create_user.transaction {
57
+ result = users.transaction {
58
58
  create_users.call([{ name: 'Jane' }, { name: 'Jack' }])
59
59
  }
60
60
 
61
- expect(result.value).to match_array([
61
+ expect(result).to match_array([
62
62
  { id: 1, name: 'Jane' }, { id: 2, name: 'Jack' }
63
63
  ])
64
64
  end
65
65
 
66
66
  it 'allows for nested transactions' do
67
- result = create_user.transaction {
68
- create_user.transaction {
67
+ result = users.transaction {
68
+ users.transaction {
69
69
  create_user.call(name: 'Jane')
70
70
  }
71
71
  }
72
72
 
73
- expect(result.value).to eql(id: 1, name: 'Jane')
73
+ expect(result).to eql(id: 1, name: 'Jane')
74
74
  end
75
75
 
76
76
  it 'creates nothing if command error was raised' do
77
77
  expect {
78
78
  begin
79
- create_user.transaction {
79
+ users.transaction {
80
80
  create_user.call(name: 'Jane')
81
81
  create_user.call(name: nil)
82
82
  }
@@ -87,19 +87,13 @@ RSpec.describe 'Commands / Create', :postgres, seeds: false do
87
87
 
88
88
  it 'creates nothing if rollback was raised' do
89
89
  expect {
90
- passed = false
91
-
92
- result = create_user.transaction {
90
+ result = users.transaction { |t|
93
91
  create_user.call(name: 'Jane')
94
92
  create_user.call(name: 'John')
95
- raise ROM::SQL::Rollback
96
- } >-> _value {
97
- passed = true
93
+ t.rollback!
98
94
  }
99
95
 
100
- expect(result.value).to be(nil)
101
- expect(result.error).to be(nil)
102
- expect(passed).to be(false)
96
+ expect(result).to be(nil)
103
97
  }.to_not change { container.relations.users.count }
104
98
  end
105
99
 
@@ -108,10 +102,9 @@ RSpec.describe 'Commands / Create', :postgres, seeds: false do
108
102
  begin
109
103
  passed = false
110
104
 
111
- create_user.transaction {
105
+ users.transaction {
112
106
  create_user.call(name: 'Jane')
113
107
  create_user.call(name: 'Jane')
114
- } >-> _value {
115
108
  passed = true
116
109
  }
117
110
  rescue => error
@@ -124,9 +117,10 @@ RSpec.describe 'Commands / Create', :postgres, seeds: false do
124
117
  it 'creates nothing if anything was raised in any nested transaction' do
125
118
  expect {
126
119
  expect {
127
- create_user.transaction {
120
+ users.transaction {
128
121
  create_user.call(name: 'John')
129
- create_user.transaction {
122
+
123
+ users.transaction {
130
124
  create_user.call(name: 'Jane')
131
125
  raise Exception
132
126
  }
@@ -158,24 +152,22 @@ RSpec.describe 'Commands / Create', :postgres, seeds: false do
158
152
  end
159
153
 
160
154
  it 'returns a single tuple when result is set to :one' do
161
- result = user_commands.try { create_user.call(name: 'Jane') }
155
+ result = create_user.call(name: 'Jane')
162
156
 
163
- expect(result.value).to eql(id: 1, name: 'Jane')
157
+ expect(result).to eql(id: 1, name: 'Jane')
164
158
  end
165
159
 
166
160
  it 'returns tuples when result is set to :many' do
167
- result = user_commands.try do
168
- create_users.call([{ name: 'Jane' }, { name: 'Jack' }])
169
- end
161
+ result = create_users.call([{ name: 'Jane' }, { name: 'Jack' }])
170
162
 
171
- expect(result.value.to_a).to match_array([
163
+ expect(result.to_a).to match_array([
172
164
  { id: 1, name: 'Jane' }, { id: 2, name: 'Jack' }
173
165
  ])
174
166
  end
175
167
 
176
168
  it 're-raises not-null constraint violation error' do
177
169
  expect {
178
- user_commands.try { create_user.call(name: nil) }
170
+ create_user.call(name: nil)
179
171
  }.to raise_error(ROM::SQL::NotNullConstraintError)
180
172
  end
181
173
 
@@ -198,34 +190,27 @@ RSpec.describe 'Commands / Create', :postgres, seeds: false do
198
190
  it 're-raises not-null constraint violation error with nil boolean' do
199
191
  puppies = commands[:puppies]
200
192
 
201
- expect {
202
- puppies.try { puppies.create.call(name: 'Charlie', cute: nil) }
203
- }.to raise_error(ROM::SQL::NotNullConstraintError)
193
+ expect { puppies.create.call(name: 'Charlie', cute: nil) }.
194
+ to raise_error(ROM::SQL::NotNullConstraintError)
204
195
  end
205
196
  end
206
197
  end
207
198
 
208
- it 're-raises uniqueness constraint violation error' do
199
+ it 'raises uniqueness constraint violation error' do
209
200
  expect {
210
- user_commands.try {
211
- create_user.call(name: 'Jane')
212
- } >-> user {
213
- user_commands.try { create_user.call(name: user[:name]) }
214
- }
201
+ user = create_user.call(name: 'Jane')
202
+ create_user.call(name: user[:name])
215
203
  }.to raise_error(ROM::SQL::UniqueConstraintError)
216
204
  end
217
205
 
218
206
  it 're-raises fk constraint violation error' do |ex|
219
- expect {
220
- task_commands.try {
221
- create_task.call(user_id: 918_273_645)
222
- }
223
- }.to raise_error(ROM::SQL::ForeignKeyConstraintError)
207
+ expect { create_task.call(user_id: 918_273_645) }.
208
+ to raise_error(ROM::SQL::ForeignKeyConstraintError)
224
209
  end
225
210
 
226
211
  it 're-raises database errors' do
227
212
  expect {
228
- user_commands.try { create_user.call(name: nil) }
213
+ create_user.call(name: nil)
229
214
  }.to raise_error(ROM::SQL::NotNullConstraintError)
230
215
  end
231
216
 
@@ -233,9 +218,8 @@ RSpec.describe 'Commands / Create', :postgres, seeds: false do
233
218
  context 'with a single record' do
234
219
  it 'materializes the result' do
235
220
  result = create_user.execute(name: 'Jane')
236
- expect(result).to eq([
237
- { id: 1, name: 'Jane' }
238
- ])
221
+
222
+ expect(result).to eq([{ id: 1, name: 'Jane' }])
239
223
  end
240
224
  end
241
225
 
@@ -245,10 +229,8 @@ RSpec.describe 'Commands / Create', :postgres, seeds: false do
245
229
  { name: 'Jane' },
246
230
  { name: 'John' }
247
231
  ])
248
- expect(result).to eq([
249
- { id: 1, name: 'Jane' },
250
- { id: 2, name: 'John' }
251
- ])
232
+
233
+ expect(result).to eql([{ id: 1, name: 'Jane' }, { id: 2, name: 'John' }])
252
234
  end
253
235
  end
254
236
 
@@ -288,20 +270,13 @@ RSpec.describe 'Commands / Create', :postgres, seeds: false do
288
270
  end
289
271
 
290
272
  describe '#call' do
291
- it 're-raises check constraint violation error' do
292
- expect {
293
- user_commands.try {
294
- create_user.call(name: 'J')
295
- }
296
- }.to raise_error(ROM::SQL::CheckConstraintError, /name/)
273
+ it 'raises check constraint violation error' do
274
+ expect { create_user.call(name: 'J') }.
275
+ to raise_error(ROM::SQL::CheckConstraintError, /name/)
297
276
  end
298
277
 
299
- it 're-raises constraint violation error' do
300
- expect {
301
- user_commands.try {
302
- create_task.call(title: '')
303
- }
304
- }.to raise_error(ROM::SQL::ConstraintError, /title/)
278
+ it 'raises constraint violation error' do
279
+ expect { create_task.call(title: '') }.to raise_error(ROM::SQL::ConstraintError, /title/)
305
280
  end
306
281
  end
307
282