rom-sql 1.0.0.beta2 → 1.0.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/CHANGELOG.md +4 -0
  4. data/circle.yml +1 -1
  5. data/lib/rom/plugins/relation/sql/auto_combine.rb +1 -1
  6. data/lib/rom/sql/association.rb +5 -1
  7. data/lib/rom/sql/association/many_to_many.rb +8 -4
  8. data/lib/rom/sql/association/many_to_one.rb +2 -3
  9. data/lib/rom/sql/association/one_to_many.rb +2 -3
  10. data/lib/rom/sql/commands/create.rb +8 -1
  11. data/lib/rom/sql/commands/update.rb +7 -0
  12. data/lib/rom/sql/extensions.rb +8 -0
  13. data/lib/rom/sql/extensions/active_support_notifications.rb +7 -18
  14. data/lib/rom/sql/extensions/mysql.rb +1 -0
  15. data/lib/rom/sql/extensions/mysql/inferrer.rb +10 -0
  16. data/lib/rom/sql/extensions/postgres/commands.rb +1 -1
  17. data/lib/rom/sql/extensions/postgres/inferrer.rb +4 -0
  18. data/lib/rom/sql/extensions/postgres/types.rb +20 -22
  19. data/lib/rom/sql/extensions/sqlite.rb +1 -0
  20. data/lib/rom/sql/extensions/sqlite/inferrer.rb +10 -0
  21. data/lib/rom/sql/function.rb +6 -2
  22. data/lib/rom/sql/order_dsl.rb +1 -1
  23. data/lib/rom/sql/plugin/associates.rb +28 -5
  24. data/lib/rom/sql/relation.rb +18 -0
  25. data/lib/rom/sql/relation/reading.rb +2 -2
  26. data/lib/rom/sql/relation/sequel_api.rb +119 -0
  27. data/lib/rom/sql/schema/inferrer.rb +26 -2
  28. data/lib/rom/sql/tasks/migration_tasks.rake +1 -1
  29. data/lib/rom/sql/type.rb +13 -2
  30. data/lib/rom/sql/types.rb +5 -3
  31. data/lib/rom/sql/version.rb +1 -1
  32. data/spec/extensions/postgres/types_spec.rb +29 -0
  33. data/spec/integration/association/many_to_many_spec.rb +8 -0
  34. data/spec/integration/association/many_to_one_spec.rb +11 -0
  35. data/spec/integration/association/one_to_many_spec.rb +9 -0
  36. data/spec/integration/schema/inferrer/mysql_spec.rb +36 -0
  37. data/spec/integration/schema/inferrer/postgres_spec.rb +118 -0
  38. data/spec/integration/schema/inferrer/sqlite_spec.rb +36 -0
  39. data/spec/integration/{schema_inference_spec.rb → schema/inferrer_spec.rb} +44 -15
  40. data/spec/integration/sequel_api_spec.rb +31 -0
  41. data/spec/support/helpers.rb +4 -0
  42. data/spec/unit/function_spec.rb +35 -0
  43. data/spec/unit/order_dsl_spec.rb +35 -0
  44. data/spec/unit/relation/assoc_spec.rb +38 -0
  45. data/spec/unit/relation/inner_join_spec.rb +15 -0
  46. data/spec/unit/types_spec.rb +53 -1
  47. metadata +23 -6
  48. data/spec/extensions/postgres/inferrer_spec.rb +0 -59
@@ -0,0 +1,36 @@
1
+ RSpec.describe 'ROM::SQL::Schema::SqliteInferrer', :sqlite do
2
+ include_context 'database setup'
3
+
4
+ before do
5
+ conn.drop_table?(:test_inferrence)
6
+
7
+ conn.create_table :test_inferrence do
8
+ tinyint :tiny
9
+ int8 :big
10
+ end
11
+ end
12
+
13
+ after do
14
+ conn.drop_table?(:test_inferrence)
15
+ end
16
+
17
+ let(:dataset) { :test_inferrence }
18
+
19
+ let(:schema) { container.relations[dataset].schema }
20
+
21
+ before do
22
+ dataset = self.dataset
23
+ conf.relation(dataset) do
24
+ schema(dataset, infer: true)
25
+ end
26
+ end
27
+
28
+ it 'can infer attributes for dataset' do
29
+ source = container.relations[:test_inferrence].name
30
+
31
+ expect(schema.to_h).to eql(
32
+ tiny: ROM::SQL::Types::Int.optional.meta(name: :tiny, source: source),
33
+ big: ROM::SQL::Types::Int.optional.meta(name: :big, source: source),
34
+ )
35
+ end
36
+ end
@@ -57,7 +57,6 @@ RSpec.describe 'Schema inference for common datatypes' do
57
57
  Time :time
58
58
  Date :date
59
59
  DateTime :datetime, null: false
60
- BigDecimal :bigdec
61
60
 
62
61
  if ctx.sqlite?(example)
63
62
  add_constraint(:test_constraint) { char_length(text) > 3 }
@@ -83,7 +82,50 @@ RSpec.describe 'Schema inference for common datatypes' do
83
82
  date: ROM::SQL::Types::Date.optional.meta(name: :date, source: source),
84
83
  datetime: ROM::SQL::Types::Time.meta(name: :datetime, source: source),
85
84
  data: ROM::SQL::Types::Blob.optional.meta(name: :data, source: source),
86
- bigdec: ROM::SQL::Types::Decimal.optional.meta(name: :bigdec, source: source)
85
+ )
86
+ end
87
+ end
88
+
89
+ context 'numeric datatypes' do
90
+ before do |example|
91
+ ctx = self
92
+ conn.drop_table?(:test_numeric)
93
+
94
+ conn.create_table :test_numeric do
95
+ primary_key :id
96
+ decimal :dec, null: false
97
+ decimal :dec_prec, size: 12, null: false
98
+ numeric :num, size: [5, 2], null: false
99
+ smallint :small
100
+ integer :int
101
+ bigint :big
102
+ float :floating
103
+ double :double_p
104
+ end
105
+ end
106
+
107
+ let(:dataset) { :test_numeric }
108
+ let(:source) { ROM::Relation::Name[dataset] }
109
+
110
+ let(:decimal) { ROM::SQL::Types::Decimal.meta(source: source) }
111
+
112
+ it 'infers attributes with precision' do |example|
113
+ if mysql?(example)
114
+ default_precision = decimal.meta(name: :dec, precision: 10, scale: 0)
115
+ else
116
+ default_precision = decimal.meta(name: :dec)
117
+ end
118
+
119
+ expect(schema.to_h).to eql(
120
+ id: ROM::SQL::Types::Serial.meta(name: :id, source: source),
121
+ dec: default_precision,
122
+ dec_prec: decimal.meta(name: :dec_prec, precision: 12, scale: 0),
123
+ num: decimal.meta(name: :num, precision: 5, scale: 2),
124
+ small: ROM::SQL::Types::Int.optional.meta(name: :small, source: source),
125
+ int: ROM::SQL::Types::Int.optional.meta(name: :int, source: source),
126
+ big: ROM::SQL::Types::Int.optional.meta(name: :big, source: source),
127
+ floating: ROM::SQL::Types::Float.optional.meta(name: :floating, source: source),
128
+ double_p: ROM::SQL::Types::Float.optional.meta(name: :double_p, source: source),
87
129
  )
88
130
  end
89
131
  end
@@ -238,17 +280,4 @@ RSpec.describe 'Schema inference for common datatypes' do
238
280
  end
239
281
  end
240
282
  end
241
-
242
- with_adapters(:postgres) do
243
- context 'with a table without columns' do
244
- before do
245
- conn.create_table(:dummy) unless conn.table_exists?(:dummy)
246
- conf.relation(:dummy) { schema(infer: true) }
247
- end
248
-
249
- it 'does not fail with a weird error when a relation does not have attributes' do
250
- expect(container.relations[:dummy].schema).to be_empty
251
- end
252
- end
253
- end
254
283
  end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Using legacy sequel api', :sqlite do
4
+ include_context 'database setup'
5
+
6
+ let(:users) { relations[:users] }
7
+
8
+ before do
9
+ conf.relation(:users) do
10
+ include ROM::SQL::Relation::SequelAPI
11
+ end
12
+
13
+ users.insert(name: 'Jane')
14
+ end
15
+
16
+ describe '#select' do
17
+ it 'selects columns' do
18
+ expect(users.select(:users__id, :users__name).first).to eql(id: 1, name: 'Jane')
19
+ end
20
+
21
+ it 'supports legacy blocks' do
22
+ expect(users.select { count(id).as(:count) }.group(:id).first).to eql(count: 1)
23
+ end
24
+ end
25
+
26
+ describe '#where' do
27
+ it 'restricts relation' do
28
+ expect(users.where(name: 'Jane').first).to eql(id: 1, name: 'Jane')
29
+ end
30
+ end
31
+ end
@@ -14,4 +14,8 @@ module Helpers
14
14
  type_class: ROM::SQL::Type
15
15
  )
16
16
  end
17
+
18
+ def define_type(name, id, **opts)
19
+ ROM::SQL::Type.new(ROM::Types.const_get(id).meta(name: name, **opts))
20
+ end
17
21
  end
@@ -0,0 +1,35 @@
1
+ require 'rom/sql/function'
2
+
3
+ RSpec.describe ROM::SQL::Function, :postgres do
4
+ subject(:func) { ROM::SQL::Function.new(type) }
5
+
6
+ include_context 'database setup'
7
+
8
+ let(:ds) { container.gateways[:default][:users] }
9
+ let(:type) { ROM::SQL::Types::Int }
10
+
11
+ describe '#sql_literal' do
12
+ context 'without alias' do
13
+ specify do
14
+ expect(func.count(:id).sql_literal(ds)).to eql(%(COUNT("id")))
15
+ end
16
+ end
17
+
18
+ context 'with alias' do
19
+ specify do
20
+ expect(func.count(:id).as(:count).sql_literal(ds)).to eql(%(COUNT("id") AS "count"))
21
+ end
22
+ end
23
+ end
24
+
25
+ describe '#method_missing' do
26
+ it 'responds to anything when not set' do
27
+ expect(func.count(:id)).to be_instance_of(func.class)
28
+ end
29
+
30
+ it 'raises error when is set already' do
31
+ expect { func.count(:id).upper.sql_literal(ds) }.
32
+ to raise_error(NoMethodError, /upper/)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ROM::SQL::OrderDSL, :postgres, helpers: true do
4
+ include_context 'database setup'
5
+
6
+ subject(:dsl) do
7
+ ROM::SQL::OrderDSL.new(schema)
8
+ end
9
+
10
+ let(:schema) do
11
+ define_schema(:users, id: ROM::SQL::Types::Serial, name: ROM::SQL::Types::String)
12
+ end
13
+
14
+ let(:ds) do
15
+ conn[:users]
16
+ end
17
+
18
+ describe '#call' do
19
+ it 'returns an array with ordered expressions' do
20
+ expect(dsl.call { id }.first.sql_literal(conn[:users])).to eql('"id"')
21
+ end
22
+ end
23
+
24
+ describe '#method_missing' do
25
+ it 'responds to methods matching attribute names' do
26
+ expect(dsl.id.name).to be(:id)
27
+ expect(dsl.name.name).to be(:name)
28
+ end
29
+
30
+ it 'delegates to sequel virtual row' do
31
+ expect(dsl.call { nullif(id.qualified, `''`).desc }.first.sql_literal(conn[:users])).
32
+ to eql(%(NULLIF("users"."id", '') DESC))
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ROM::SQL::Relation, :sqlite do
4
+ include_context 'users and tasks'
5
+
6
+ let(:users) { relations[:users] }
7
+ let(:tasks) { relations[:tasks] }
8
+
9
+ before do
10
+ conf.relation(:users) do
11
+ schema(infer: true) do
12
+ associations do
13
+ has_many :tasks
14
+ end
15
+ end
16
+ end
17
+
18
+ conf.relation(:tasks) do
19
+ schema(infer: true) do
20
+ associations do
21
+ belongs_to :users, as: :user
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ with_adapters(:sqlite) do
28
+ it 'returns child tuples for a relation' do
29
+ expect(users.assoc(:tasks).where(name: 'Jane').to_a).
30
+ to eql([{ id: 2, user_id: 1, title: "Jane's task" }])
31
+ end
32
+
33
+ it 'returns parent tuples for a relation' do
34
+ expect(tasks.assoc(:user).where(title: "Jane's task").to_a).
35
+ to eql([{ id: 1, task_id: 2, name: 'Jane' }])
36
+ end
37
+ end
38
+ end
@@ -21,6 +21,21 @@ RSpec.describe ROM::Relation, '#inner_join' do
21
21
  ])
22
22
  end
23
23
 
24
+ it 'allows specifying table_aliases' do
25
+ relation.insert id: 3, name: 'Jade'
26
+
27
+ result = relation.
28
+ inner_join(:tasks, {user_id: :id}, table_alias: :t1).
29
+ select(:name, tasks[:title])
30
+
31
+ expect(result.schema.map(&:name)).to eql(%i[name title])
32
+
33
+ expect(result.to_a).to eql([
34
+ { name: 'Jane', title: "Jane's task" },
35
+ { name: 'Joe', title: "Joe's task" }
36
+ ])
37
+ end
38
+
24
39
  context 'with associations' do
25
40
  before do
26
41
  conf.relation(:users) do
@@ -1,6 +1,6 @@
1
1
  require 'rom/sql/types'
2
2
 
3
- RSpec.describe 'ROM::SQL::Types', :postgres do
3
+ RSpec.describe ROM::SQL::Types, :postgres do
4
4
  describe 'ROM::SQL::Types::Serial' do
5
5
  it 'accepts ints > 0' do
6
6
  expect(ROM::SQL::Types::Serial[1]).to be(1)
@@ -20,4 +20,56 @@ RSpec.describe 'ROM::SQL::Types', :postgres do
20
20
  expect(output).to eql('sutin')
21
21
  end
22
22
  end
23
+
24
+ describe '#sql_literal', helpers: true do
25
+ subject(:base) { define_type(:age, :Int, source: ROM::Relation::Name.new(:users)) }
26
+
27
+ include_context 'database setup'
28
+
29
+ let(:ds) { container.gateways[:default][:users] }
30
+ let(:sql_literal) { type.sql_literal(ds) }
31
+
32
+ context 'when qualified' do
33
+ subject(:type) { base.qualified }
34
+
35
+ specify do
36
+ expect(sql_literal).to eql(%("users"."age"))
37
+ end
38
+ end
39
+
40
+ context 'when aliased' do
41
+ subject(:type) { base.as(:user_age) }
42
+
43
+ specify do
44
+ expect(sql_literal).to eql(%("age" AS "user_age"))
45
+ end
46
+ end
47
+
48
+ context 'when qualified and aliased' do
49
+ subject(:type) { base.qualified.as(:user_age) }
50
+
51
+ specify do
52
+ expect(sql_literal).to eql(%("users"."age" AS "user_age"))
53
+ end
54
+ end
55
+
56
+ context 'when aliased and qualified' do
57
+ subject(:type) { base.as(:user_age).qualified }
58
+
59
+ specify do
60
+ expect(sql_literal).to eql(%("users"."age" AS "user_age"))
61
+ end
62
+ end
63
+
64
+ context 'when qualified with a function expr' do
65
+ subject(:type) { base.meta(sql_expr: func).qualified }
66
+
67
+ let(:func) { Sequel::SQL::Function.new(:count, :age) }
68
+
69
+ specify do
70
+ expect { sql_literal }.
71
+ to raise_error(ROM::SQL::Type::QualifyError, "can't qualify :age (#{func.inspect})")
72
+ end
73
+ end
74
+ end
23
75
  end
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: 1.0.0.beta2
4
+ version: 1.0.0.beta3
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-01-12 00:00:00.000000000 Z
11
+ date: 2017-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel
@@ -153,11 +153,15 @@ files:
153
153
  - lib/rom/sql/errors.rb
154
154
  - lib/rom/sql/extensions.rb
155
155
  - lib/rom/sql/extensions/active_support_notifications.rb
156
+ - lib/rom/sql/extensions/mysql.rb
157
+ - lib/rom/sql/extensions/mysql/inferrer.rb
156
158
  - lib/rom/sql/extensions/postgres.rb
157
159
  - lib/rom/sql/extensions/postgres/commands.rb
158
160
  - lib/rom/sql/extensions/postgres/inferrer.rb
159
161
  - lib/rom/sql/extensions/postgres/types.rb
160
162
  - lib/rom/sql/extensions/rails_log_subscriber.rb
163
+ - lib/rom/sql/extensions/sqlite.rb
164
+ - lib/rom/sql/extensions/sqlite/inferrer.rb
161
165
  - lib/rom/sql/function.rb
162
166
  - lib/rom/sql/gateway.rb
163
167
  - lib/rom/sql/migration.rb
@@ -172,6 +176,7 @@ files:
172
176
  - lib/rom/sql/rake_task.rb
173
177
  - lib/rom/sql/relation.rb
174
178
  - lib/rom/sql/relation/reading.rb
179
+ - lib/rom/sql/relation/sequel_api.rb
175
180
  - lib/rom/sql/relation/writing.rb
176
181
  - lib/rom/sql/restriction_dsl.rb
177
182
  - lib/rom/sql/schema.rb
@@ -186,7 +191,6 @@ files:
186
191
  - lib/rom/sql/version.rb
187
192
  - log/.gitkeep
188
193
  - rom-sql.gemspec
189
- - spec/extensions/postgres/inferrer_spec.rb
190
194
  - spec/extensions/postgres/integration_spec.rb
191
195
  - spec/extensions/postgres/types_spec.rb
192
196
  - spec/fixtures/migrations/20150403090603_create_carrots.rb
@@ -214,11 +218,15 @@ files:
214
218
  - spec/integration/plugins/auto_wrap_spec.rb
215
219
  - spec/integration/relation_schema_spec.rb
216
220
  - spec/integration/schema/call_spec.rb
221
+ - spec/integration/schema/inferrer/mysql_spec.rb
222
+ - spec/integration/schema/inferrer/postgres_spec.rb
223
+ - spec/integration/schema/inferrer/sqlite_spec.rb
224
+ - spec/integration/schema/inferrer_spec.rb
217
225
  - spec/integration/schema/prefix_spec.rb
218
226
  - spec/integration/schema/qualified_spec.rb
219
227
  - spec/integration/schema/rename_spec.rb
220
228
  - spec/integration/schema/view_spec.rb
221
- - spec/integration/schema_inference_spec.rb
229
+ - spec/integration/sequel_api_spec.rb
222
230
  - spec/integration/setup_spec.rb
223
231
  - spec/integration/support/active_support_notifications_spec.rb
224
232
  - spec/integration/support/rails_log_subscriber_spec.rb
@@ -234,12 +242,15 @@ files:
234
242
  - spec/unit/association/one_to_many_spec.rb
235
243
  - spec/unit/association/one_to_one_spec.rb
236
244
  - spec/unit/association/one_to_one_through_spec.rb
245
+ - spec/unit/function_spec.rb
237
246
  - spec/unit/gateway_spec.rb
238
247
  - spec/unit/logger_spec.rb
239
248
  - spec/unit/migration_tasks_spec.rb
240
249
  - spec/unit/migrator_spec.rb
250
+ - spec/unit/order_dsl_spec.rb
241
251
  - spec/unit/plugin/pagination_spec.rb
242
252
  - spec/unit/projection_dsl_spec.rb
253
+ - spec/unit/relation/assoc_spec.rb
243
254
  - spec/unit/relation/associations_spec.rb
244
255
  - spec/unit/relation/avg_spec.rb
245
256
  - spec/unit/relation/by_pk_spec.rb
@@ -298,7 +309,6 @@ signing_key:
298
309
  specification_version: 4
299
310
  summary: SQL databases support for ROM
300
311
  test_files:
301
- - spec/extensions/postgres/inferrer_spec.rb
302
312
  - spec/extensions/postgres/integration_spec.rb
303
313
  - spec/extensions/postgres/types_spec.rb
304
314
  - spec/fixtures/migrations/20150403090603_create_carrots.rb
@@ -326,11 +336,15 @@ test_files:
326
336
  - spec/integration/plugins/auto_wrap_spec.rb
327
337
  - spec/integration/relation_schema_spec.rb
328
338
  - spec/integration/schema/call_spec.rb
339
+ - spec/integration/schema/inferrer/mysql_spec.rb
340
+ - spec/integration/schema/inferrer/postgres_spec.rb
341
+ - spec/integration/schema/inferrer/sqlite_spec.rb
342
+ - spec/integration/schema/inferrer_spec.rb
329
343
  - spec/integration/schema/prefix_spec.rb
330
344
  - spec/integration/schema/qualified_spec.rb
331
345
  - spec/integration/schema/rename_spec.rb
332
346
  - spec/integration/schema/view_spec.rb
333
- - spec/integration/schema_inference_spec.rb
347
+ - spec/integration/sequel_api_spec.rb
334
348
  - spec/integration/setup_spec.rb
335
349
  - spec/integration/support/active_support_notifications_spec.rb
336
350
  - spec/integration/support/rails_log_subscriber_spec.rb
@@ -346,12 +360,15 @@ test_files:
346
360
  - spec/unit/association/one_to_many_spec.rb
347
361
  - spec/unit/association/one_to_one_spec.rb
348
362
  - spec/unit/association/one_to_one_through_spec.rb
363
+ - spec/unit/function_spec.rb
349
364
  - spec/unit/gateway_spec.rb
350
365
  - spec/unit/logger_spec.rb
351
366
  - spec/unit/migration_tasks_spec.rb
352
367
  - spec/unit/migrator_spec.rb
368
+ - spec/unit/order_dsl_spec.rb
353
369
  - spec/unit/plugin/pagination_spec.rb
354
370
  - spec/unit/projection_dsl_spec.rb
371
+ - spec/unit/relation/assoc_spec.rb
355
372
  - spec/unit/relation/associations_spec.rb
356
373
  - spec/unit/relation/avg_spec.rb
357
374
  - spec/unit/relation/by_pk_spec.rb