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
@@ -24,7 +24,7 @@ RSpec.describe 'Commands / Delete' do
24
24
  describe '#transaction' do
25
25
  it 'deletes in normal way if no error raised' do
26
26
  expect {
27
- delete_user.transaction do
27
+ users.transaction do
28
28
  delete_user.by_name('Jade').call
29
29
  end
30
30
  }.to change { users.count }.by(-1)
@@ -32,9 +32,9 @@ RSpec.describe 'Commands / Delete' do
32
32
 
33
33
  it 'deletes nothing if error was raised' do
34
34
  expect {
35
- delete_user.transaction do
35
+ users.transaction do |t|
36
36
  delete_user.by_name('Jade').call
37
- raise ROM::SQL::Rollback
37
+ t.rollback!
38
38
  end
39
39
  }.to_not change { users.count }
40
40
  end
@@ -42,9 +42,9 @@ RSpec.describe 'Commands / Delete' do
42
42
 
43
43
  describe '#call' do
44
44
  it 'deletes all tuples in a restricted relation' do
45
- result = user_commands.try { delete_user.by_name('Jade').call }
45
+ result = delete_user.by_name('Jade').call
46
46
 
47
- expect(result.value).to eql(id: 3, name: 'Jade')
47
+ expect(result).to eql(id: 3, name: 'Jade')
48
48
  end
49
49
 
50
50
  it 're-raises database error' do
@@ -55,7 +55,7 @@ RSpec.describe 'Commands / Delete' do
55
55
  )
56
56
 
57
57
  expect {
58
- user_commands.try { command.call }
58
+ command.call
59
59
  }.to raise_error(ROM::SQL::DatabaseError, /totally wrong/)
60
60
  end
61
61
  end
@@ -41,17 +41,17 @@ RSpec.describe 'Commands / Update', seeds: false do
41
41
 
42
42
  context '#transaction' do
43
43
  it 'update record if there was no errors' do
44
- result = update_user.transaction do
44
+ result = users.transaction do
45
45
  update_user.by_id(piotr[:id]).call(peter)
46
46
  end
47
47
 
48
- expect(result.value).to eq([{ id: 1, name: 'Peter' }])
48
+ expect(result).to eq([{ id: 1, name: 'Peter' }])
49
49
  end
50
50
 
51
51
  it 'updates nothing if error was raised' do
52
- update_user.transaction do
52
+ users.transaction do |t|
53
53
  update_user.by_id(piotr[:id]).call(peter)
54
- raise ROM::SQL::Rollback
54
+ t.rollback!
55
55
  end
56
56
 
57
57
  expect(users.first[:name]).to eql('Piotr')
@@ -60,11 +60,9 @@ RSpec.describe 'Commands / Update', seeds: false do
60
60
 
61
61
  describe '#call' do
62
62
  it 'updates relation tuples' do
63
- result = user_commands.try do
64
- update_user.by_id(piotr[:id]).call(peter)
65
- end
63
+ result = update_user.by_id(piotr[:id]).call(peter)
66
64
 
67
- expect(result.value.to_a).to match_array([{ id: 1, name: 'Peter' }])
65
+ expect(result.to_a).to match_array([{ id: 1, name: 'Peter' }])
68
66
  end
69
67
 
70
68
  it 're-raises database errors' do |example|
@@ -53,8 +53,8 @@ RSpec.describe 'Plugins / :associates / with many-to-many', :sqlite, seeds: fals
53
53
  end
54
54
 
55
55
  it 'associates a child with many parents' do
56
- add_tags = create_tag.with([{ name: 'red' }, { name: 'blue' }])
57
- add_task = create_task.with(user_id: jane[:id], title: "Jade's task")
56
+ add_tags = create_tag.curry([{ name: 'red' }, { name: 'blue' }])
57
+ add_task = create_task.curry(user_id: jane[:id], title: "Jade's task")
58
58
 
59
59
  command = add_tags >> add_task
60
60
 
@@ -68,8 +68,8 @@ RSpec.describe 'Plugins / :associates', seeds: false do
68
68
 
69
69
  shared_context 'automatic FK setting' do
70
70
  it 'sets foreign key prior execution for many tuples' do
71
- create_user = users[:create].with(name: 'Jade')
72
- create_task = tasks[:create_many].with([{ title: 'Task one' }, { title: 'Task two' }])
71
+ create_user = users[:create].curry(name: 'Jade')
72
+ create_task = tasks[:create_many].curry([{ title: 'Task one' }, { title: 'Task two' }])
73
73
 
74
74
  command = create_user >> create_task
75
75
 
@@ -82,8 +82,8 @@ RSpec.describe 'Plugins / :associates', seeds: false do
82
82
  end
83
83
 
84
84
  it 'sets foreign key prior execution for one tuple' do
85
- create_user = users[:create].with(name: 'Jade')
86
- create_task = tasks[:create_one].with(title: 'Task one')
85
+ create_user = users[:create].curry(name: 'Jade')
86
+ create_task = tasks[:create_one].curry(title: 'Task one')
87
87
 
88
88
  command = create_user >> create_task
89
89
 
@@ -161,9 +161,9 @@ RSpec.describe 'Plugins / :associates', seeds: false do
161
161
  end
162
162
 
163
163
  it 'sets FKs for the join table' do
164
- create_user = users[:create].with(name: 'Jade')
165
- create_task = tasks[:create].with(title: "Jade's task")
166
- create_tags = tags[:create].with([{ name: 'red' }, { name: 'blue' }])
164
+ create_user = users[:create].curry(name: 'Jade')
165
+ create_task = tasks[:create].curry(title: "Jade's task")
166
+ create_tags = tags[:create].curry([{ name: 'red' }, { name: 'blue' }])
167
167
 
168
168
  command = create_user >> create_task >> create_tags
169
169
 
@@ -31,6 +31,10 @@ RSpec.describe 'Plugins / :auto_restrictions', seeds: true do
31
31
  attribute :id, ROM::SQL::Types::Serial
32
32
  attribute :user_id, ROM::SQL::Types::Int
33
33
  attribute :title, ROM::SQL::Types::String.meta(index: true)
34
+
35
+ indexes do
36
+ index :user_id, :title
37
+ end
34
38
  end
35
39
 
36
40
  use :auto_restrictions
@@ -38,6 +42,33 @@ RSpec.describe 'Plugins / :auto_restrictions', seeds: true do
38
42
  end
39
43
 
40
44
  include_context 'auto-generated restriction view'
45
+
46
+ it 'generates restrictrions by a composite index' do
47
+ expect(tasks.by_user_id_and_title(1, "Jane's task").first).to eql(id: 2, user_id: 1, title: "Jane's task")
48
+ end
49
+ end
50
+
51
+ if metadata[:postgres]
52
+ # An auto-generated restriction should include the prediate from the index definition
53
+ # but it seems to be too much from my POV, better leave it to the user
54
+ # Note that this can be enabled later
55
+ it 'skips partial indexes' do
56
+ conf.relation(:tasks) do
57
+ schema do
58
+ attribute :id, ROM::SQL::Types::Serial
59
+ attribute :user_id, ROM::SQL::Types::Int
60
+ attribute :title, ROM::SQL::Types::String
61
+
62
+ indexes do
63
+ index :title, predicate: 'title is not null'
64
+ end
65
+ end
66
+
67
+ use :auto_restrictions
68
+ end
69
+
70
+ expect(tasks).not_to respond_to(:by_title)
71
+ end
41
72
  end
42
73
  end
43
74
  end
@@ -199,5 +199,73 @@ RSpec.describe 'Inferring schema from database' do
199
199
  expect(tag_associations[:published_posts].definition).to eql(assoc)
200
200
  end
201
201
  end
202
+
203
+ context 'defining indexes', :helpers do |ctx|
204
+ it 'allows defining indexes' do
205
+ class Test::Tags < ROM::Relation[:sql]
206
+ schema(:tags) do
207
+ attribute :id, Types::Serial
208
+ attribute :name, Types::String
209
+ attribute :created_at, Types::Time
210
+ attribute :updated_at, Types::Time
211
+
212
+ indexes do
213
+ index :name
214
+ index :created_at, :name
215
+ index :updated_at, name: :recently_idx
216
+ index :created_at, name: :unique_date, unique: true
217
+ end
218
+ end
219
+ end
220
+
221
+ conf.register_relation(Test::Tags)
222
+ schema = container.relations[:tags].schema
223
+
224
+ expect(schema.indexes.to_a).
225
+ to contain_exactly(
226
+ ROM::SQL::Index.new([define_attribute(:name, :String, source: schema.name)]),
227
+ ROM::SQL::Index.new(
228
+ [define_attribute(:created_at, :Time, source: schema.name),
229
+ define_attribute(:name, :String, source: schema.name)]
230
+ ),
231
+ ROM::SQL::Index.new(
232
+ [define_attribute(:updated_at, :Time, source: schema.name)],
233
+ name: :recently_idx
234
+ ),
235
+ ROM::SQL::Index.new(
236
+ [define_attribute(:created_at, :Time, source: schema.name)],
237
+ name: :unique_date,
238
+ unique: true
239
+ )
240
+ )
241
+ end
242
+
243
+ if metadata[:postgres]
244
+ it 'can provide index type' do
245
+ class Test::Tags < ROM::Relation[:sql]
246
+ schema(:tags) do
247
+ attribute :id, Types::Serial
248
+ attribute :name, Types::String
249
+
250
+ indexes do
251
+ index :name, type: :gist
252
+ end
253
+ end
254
+ end
255
+
256
+ conf.register_relation(Test::Tags)
257
+ schema = container.relations[:tags].schema
258
+ index = schema.indexes.first
259
+
260
+ expect(index).to eql(
261
+ ROM::SQL::Index.new(
262
+ [define_attribute(:name, :String, source: schema.name)],
263
+ type: :gist)
264
+ )
265
+
266
+ expect(index.type).to eql(:gist)
267
+ end
268
+ end
269
+ end
202
270
  end
203
271
  end
@@ -12,6 +12,10 @@ RSpec.describe 'Schema inference for common datatypes', seeds: false do
12
12
  Time.mktime(time.year, time.month, time.day, time.hour, time.min, time.sec, usec)
13
13
  end
14
14
 
15
+ def index_by_name(indexes, name)
16
+ indexes.find { |idx| idx.name == name }
17
+ end
18
+
15
19
  with_adapters do |adapter|
16
20
  describe 'inferring attributes' do
17
21
  before do
@@ -335,7 +339,10 @@ RSpec.describe 'Schema inference for common datatypes', seeds: false do
335
339
  end
336
340
 
337
341
  describe 'inferring indices', oracle: false do
338
- before do |ex|
342
+ let(:dataset) { :test_inferrence }
343
+ let(:source) { ROM::Relation::Name[dataset] }
344
+
345
+ it 'infers types with indices' do
339
346
  conn.create_table :test_inferrence do
340
347
  primary_key :id
341
348
  Integer :foo
@@ -348,17 +355,35 @@ RSpec.describe 'Schema inference for common datatypes', seeds: false do
348
355
  index :baz, name: :baz2_idx
349
356
 
350
357
  index %i(bar baz), name: :composite_idx
358
+ index %i(foo bar), name: :unique_idx, unique: true
351
359
  end
352
360
 
353
361
  conf.relation(:test_inferrence) { schema(infer: true) }
362
+
363
+ expect(schema.indexes.map(&:name)).
364
+ to match_array(%i(foo_idx bar_idx baz1_idx baz2_idx composite_idx unique_idx))
365
+
366
+ unique_idx = index_by_name(schema.indexes, :unique_idx)
367
+
368
+ expect(unique_idx).to be_unique
354
369
  end
355
370
 
356
- let(:dataset) { :test_inferrence }
357
- let(:source) { ROM::Relation::Name[dataset] }
371
+ if metadata[:postgres]
372
+ it 'infers cutsom index types' do
373
+ pending 'Sequel not returning index type'
374
+ conn.create_table :test_inferrence do
375
+ primary_key :id
376
+ Integer :foo
377
+ index :foo, name: :foo_idx, type: :gist
378
+ end
358
379
 
359
- it 'infers types with indices' do
360
- expect(schema.indexes.map(&:name)).
361
- to match_array(%i(foo_idx bar_idx baz1_idx baz2_idx composite_idx))
380
+ conf.relation(:test_inferrence) { schema(infer: true) }
381
+
382
+ index = schema.indexes.first
383
+
384
+ expect(index.name).to eql(:foo_idx)
385
+ expect(index.type).to eql(:gist)
386
+ end
362
387
  end
363
388
  end
364
389
  end
@@ -12,7 +12,7 @@ module Helpers
12
12
  )
13
13
  end
14
14
 
15
- def define_type(name, id, **opts)
15
+ def define_attribute(name, id, **opts)
16
16
  ROM::SQL::Attribute.new(ROM::Types.const_get(id).meta(name: name, **opts))
17
17
  end
18
18
 
@@ -97,8 +97,8 @@ RSpec.describe 'Plugin / Timestamp' do
97
97
  end
98
98
 
99
99
  it "works with chained commands" do
100
- create_user = container.commands[:users].create.with(name: "John Doe")
101
- create_note = container.commands[:notes].create_with_user.with(text: "new note")
100
+ create_user = container.commands[:users].create.curry(name: "John Doe")
101
+ create_note = container.commands[:notes].create_with_user.curry(text: "new note")
102
102
 
103
103
  time = DateTime.now
104
104
  command = create_user >> create_note
@@ -12,7 +12,7 @@ RSpec.describe ROM::SQL::Types, :postgres do
12
12
  end
13
13
 
14
14
  describe '#sql_literal', helpers: true do
15
- subject(:base) { define_type(:age, :Int, source: ROM::Relation::Name.new(:users)) }
15
+ subject(:base) { define_attribute(:age, :Int, source: ROM::Relation::Name.new(:users)) }
16
16
 
17
17
  include_context 'database setup'
18
18
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rom-sql
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.beta1
4
+ version: 2.0.0.beta2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-30 00:00:00.000000000 Z
11
+ date: 2017-07-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel
@@ -158,7 +158,6 @@ files:
158
158
  - lib/rom/sql/commands/create.rb
159
159
  - lib/rom/sql/commands/delete.rb
160
160
  - lib/rom/sql/commands/error_wrapper.rb
161
- - lib/rom/sql/commands/transaction.rb
162
161
  - lib/rom/sql/commands/update.rb
163
162
  - lib/rom/sql/dsl.rb
164
163
  - lib/rom/sql/error.rb
@@ -199,6 +198,8 @@ files:
199
198
  - lib/rom/sql/schema.rb
200
199
  - lib/rom/sql/schema/associations_dsl.rb
201
200
  - lib/rom/sql/schema/attributes_inferrer.rb
201
+ - lib/rom/sql/schema/dsl.rb
202
+ - lib/rom/sql/schema/index_dsl.rb
202
203
  - lib/rom/sql/schema/inferrer.rb
203
204
  - lib/rom/sql/spec/support.rb
204
205
  - lib/rom/sql/tasks/migration_tasks.rake
@@ -231,12 +232,12 @@ files:
231
232
  - spec/integration/auto_migrations/indexes_spec.rb
232
233
  - spec/integration/auto_migrations/managing_columns_spec.rb
233
234
  - spec/integration/auto_migrations/postgres/column_types_spec.rb
235
+ - spec/integration/combine_with_spec.rb
234
236
  - spec/integration/commands/create_spec.rb
235
237
  - spec/integration/commands/delete_spec.rb
236
238
  - spec/integration/commands/update_spec.rb
237
239
  - spec/integration/commands/upsert_spec.rb
238
240
  - spec/integration/gateway_spec.rb
239
- - spec/integration/graph_spec.rb
240
241
  - spec/integration/migration_spec.rb
241
242
  - spec/integration/plugins/associates/many_to_many_spec.rb
242
243
  - spec/integration/plugins/associates_spec.rb
@@ -368,12 +369,12 @@ test_files:
368
369
  - spec/integration/auto_migrations/indexes_spec.rb
369
370
  - spec/integration/auto_migrations/managing_columns_spec.rb
370
371
  - spec/integration/auto_migrations/postgres/column_types_spec.rb
372
+ - spec/integration/combine_with_spec.rb
371
373
  - spec/integration/commands/create_spec.rb
372
374
  - spec/integration/commands/delete_spec.rb
373
375
  - spec/integration/commands/update_spec.rb
374
376
  - spec/integration/commands/upsert_spec.rb
375
377
  - spec/integration/gateway_spec.rb
376
- - spec/integration/graph_spec.rb
377
378
  - spec/integration/migration_spec.rb
378
379
  - spec/integration/plugins/associates/many_to_many_spec.rb
379
380
  - spec/integration/plugins/associates_spec.rb
@@ -1,33 +0,0 @@
1
- require 'rom/commands/result'
2
-
3
- module ROM
4
- module SQL
5
- module Commands
6
- # Adds transaction interface to commands
7
- #
8
- # @api private
9
- module Transaction
10
- ROM::SQL::Rollback = Class.new(Sequel::Rollback)
11
-
12
- # Start a transaction
13
- #
14
- # @param [Hash] options The options hash supported by Sequel
15
- #
16
- # @return [ROM::Commands::Result::Success,ROM::Commands::Result::Failure]
17
- #
18
- # @api public
19
- def transaction(options = {}, &block)
20
- result = relation.dataset.db.transaction(options, &block)
21
-
22
- if result
23
- ROM::Commands::Result::Success.new(result)
24
- else
25
- ROM::Commands::Result::Failure.new(result)
26
- end
27
- rescue ROM::CommandError => e
28
- ROM::Commands::Result::Failure.new(e)
29
- end
30
- end
31
- end
32
- end
33
- end