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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2 -1
- data/lib/rom/plugins/relation/sql/auto_restrictions.rb +19 -6
- data/lib/rom/sql/attribute.rb +9 -0
- data/lib/rom/sql/commands/create.rb +0 -2
- data/lib/rom/sql/commands/delete.rb +0 -2
- data/lib/rom/sql/commands/update.rb +0 -2
- data/lib/rom/sql/extensions/postgres/attributes_inferrer.rb +1 -1
- data/lib/rom/sql/index.rb +16 -0
- data/lib/rom/sql/migration/inline_runner.rb +12 -4
- data/lib/rom/sql/migration/schema_diff.rb +23 -3
- data/lib/rom/sql/plugin/associates.rb +3 -3
- data/lib/rom/sql/plugin/timestamps.rb +2 -2
- data/lib/rom/sql/relation.rb +7 -0
- data/lib/rom/sql/relation/reading.rb +1 -1
- data/lib/rom/sql/schema.rb +2 -1
- data/lib/rom/sql/schema/dsl.rb +26 -0
- data/lib/rom/sql/schema/index_dsl.rb +50 -0
- data/lib/rom/sql/schema/inferrer.rb +11 -5
- data/lib/rom/sql/version.rb +1 -1
- data/spec/integration/auto_migrations/indexes_spec.rb +147 -3
- data/spec/integration/{graph_spec.rb → combine_with_spec.rb} +1 -1
- data/spec/integration/commands/create_spec.rb +37 -62
- data/spec/integration/commands/delete_spec.rb +6 -6
- data/spec/integration/commands/update_spec.rb +6 -8
- data/spec/integration/plugins/associates/many_to_many_spec.rb +2 -2
- data/spec/integration/plugins/associates_spec.rb +7 -7
- data/spec/integration/plugins/auto_restrictions_spec.rb +31 -0
- data/spec/integration/relation_schema_spec.rb +68 -0
- data/spec/integration/schema/inferrer_spec.rb +31 -6
- data/spec/support/helpers.rb +1 -1
- data/spec/unit/plugin/timestamp_spec.rb +2 -2
- data/spec/unit/types_spec.rb +1 -1
- metadata +6 -5
- 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
|
-
|
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
|
-
|
35
|
+
users.transaction do |t|
|
36
36
|
delete_user.by_name('Jade').call
|
37
|
-
|
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 =
|
45
|
+
result = delete_user.by_name('Jade').call
|
46
46
|
|
47
|
-
expect(result
|
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
|
-
|
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 =
|
44
|
+
result = users.transaction do
|
45
45
|
update_user.by_id(piotr[:id]).call(peter)
|
46
46
|
end
|
47
47
|
|
48
|
-
expect(result
|
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
|
-
|
52
|
+
users.transaction do |t|
|
53
53
|
update_user.by_id(piotr[:id]).call(peter)
|
54
|
-
|
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 =
|
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.
|
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.
|
57
|
-
add_task = create_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].
|
72
|
-
create_task = tasks[:create_many].
|
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].
|
86
|
-
create_task = tasks[:create_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].
|
165
|
-
create_task = tasks[:create].
|
166
|
-
create_tags = tags[:create].
|
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
|
-
|
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
|
-
|
357
|
-
|
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
|
-
|
360
|
-
|
361
|
-
|
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
|
data/spec/support/helpers.rb
CHANGED
@@ -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.
|
101
|
-
create_note = container.commands[:notes].create_with_user.
|
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
|
data/spec/unit/types_spec.rb
CHANGED
@@ -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) {
|
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.
|
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-
|
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
|