rom-sql 0.8.0 → 0.9.0

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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +16 -12
  3. data/CHANGELOG.md +23 -0
  4. data/Gemfile +11 -3
  5. data/README.md +1 -7
  6. data/lib/rom/sql.rb +4 -7
  7. data/lib/rom/sql/association.rb +1 -1
  8. data/lib/rom/sql/association/one_to_many.rb +44 -1
  9. data/lib/rom/sql/association/one_to_one.rb +1 -38
  10. data/lib/rom/sql/commands.rb +0 -3
  11. data/lib/rom/sql/commands/error_wrapper.rb +1 -1
  12. data/lib/rom/sql/errors.rb +4 -1
  13. data/lib/rom/sql/extensions.rb +19 -0
  14. data/lib/rom/sql/{support → extensions}/active_support_notifications.rb +0 -0
  15. data/lib/rom/sql/extensions/postgres.rb +3 -0
  16. data/lib/rom/sql/{commands/postgres.rb → extensions/postgres/commands.rb} +38 -0
  17. data/lib/rom/sql/extensions/postgres/inferrer.rb +64 -0
  18. data/lib/rom/sql/extensions/postgres/types.rb +65 -0
  19. data/lib/rom/sql/{support → extensions}/rails_log_subscriber.rb +0 -0
  20. data/lib/rom/sql/gateway.rb +15 -4
  21. data/lib/rom/sql/relation.rb +6 -2
  22. data/lib/rom/sql/relation/reading.rb +18 -0
  23. data/lib/rom/sql/schema/dsl.rb +7 -4
  24. data/lib/rom/sql/schema/inferrer.rb +44 -31
  25. data/lib/rom/sql/types.rb +5 -1
  26. data/lib/rom/sql/version.rb +1 -1
  27. data/rom-sql.gemspec +14 -13
  28. data/spec/extensions/postgres/inferrer_spec.rb +40 -0
  29. data/spec/extensions/postgres/integration_spec.rb +38 -0
  30. data/spec/extensions/postgres/types_spec.rb +115 -0
  31. data/spec/integration/association/many_to_many_spec.rb +2 -1
  32. data/spec/integration/association/one_to_one_spec.rb +6 -4
  33. data/spec/integration/combine_spec.rb +1 -1
  34. data/spec/integration/commands/create_spec.rb +46 -21
  35. data/spec/integration/commands/delete_spec.rb +13 -38
  36. data/spec/integration/commands/update_spec.rb +19 -41
  37. data/spec/integration/commands/upsert_spec.rb +1 -1
  38. data/spec/integration/gateway_spec.rb +5 -9
  39. data/spec/integration/migration_spec.rb +6 -7
  40. data/spec/integration/read_spec.rb +30 -38
  41. data/spec/integration/schema_inference_spec.rb +211 -49
  42. data/spec/integration/setup_spec.rb +5 -5
  43. data/spec/integration/support/active_support_notifications_spec.rb +4 -3
  44. data/spec/integration/support/rails_log_subscriber_spec.rb +5 -4
  45. data/spec/shared/database_setup.rb +21 -6
  46. data/spec/spec_helper.rb +44 -35
  47. data/spec/unit/association/one_to_many_spec.rb +20 -0
  48. data/spec/unit/association/one_to_one_spec.rb +23 -2
  49. data/spec/unit/association_errors_spec.rb +1 -1
  50. data/spec/unit/gateway_spec.rb +9 -8
  51. data/spec/unit/logger_spec.rb +1 -1
  52. data/spec/unit/migration_tasks_spec.rb +3 -3
  53. data/spec/unit/migrator_spec.rb +3 -2
  54. data/spec/unit/plugin/assoc_macros/combined_associations_spec.rb +1 -1
  55. data/spec/unit/plugin/assoc_macros/many_to_many_spec.rb +1 -1
  56. data/spec/unit/plugin/assoc_macros/many_to_one_spec.rb +1 -1
  57. data/spec/unit/plugin/assoc_macros/one_to_many_spec.rb +1 -1
  58. data/spec/unit/relation/associations_spec.rb +27 -0
  59. data/spec/unit/relation/avg_spec.rb +11 -0
  60. data/spec/unit/relation/by_pk_spec.rb +15 -0
  61. data/spec/unit/relation/dataset_spec.rb +48 -0
  62. data/spec/unit/relation/distinct_spec.rb +14 -0
  63. data/spec/unit/relation/exclude_spec.rb +13 -0
  64. data/spec/unit/relation/fetch_spec.rb +21 -0
  65. data/spec/unit/relation/having_spec.rb +20 -0
  66. data/spec/unit/relation/inner_join_spec.rb +22 -0
  67. data/spec/unit/relation/inspect_spec.rb +11 -0
  68. data/spec/unit/relation/invert_spec.rb +12 -0
  69. data/spec/unit/relation/left_join_spec.rb +16 -0
  70. data/spec/unit/relation/map_spec.rb +16 -0
  71. data/spec/unit/relation/max_spec.rb +11 -0
  72. data/spec/unit/relation/min_spec.rb +11 -0
  73. data/spec/unit/relation/pluck_spec.rb +11 -0
  74. data/spec/unit/relation/prefix_spec.rb +27 -0
  75. data/spec/unit/relation/primary_key_spec.rb +27 -0
  76. data/spec/unit/relation/project_spec.rb +22 -0
  77. data/spec/unit/relation/qualified_columns_spec.rb +27 -0
  78. data/spec/unit/relation/rename_spec.rb +21 -0
  79. data/spec/unit/relation/sum_spec.rb +11 -0
  80. data/spec/unit/relation/union_spec.rb +19 -0
  81. data/spec/unit/relation/unique_predicate_spec.rb +18 -0
  82. data/spec/unit/schema_spec.rb +1 -1
  83. data/spec/unit/types_spec.rb +4 -21
  84. metadata +79 -11
  85. data/lib/rom/sql/commands_ext/postgres.rb +0 -45
  86. data/lib/rom/sql/types/pg.rb +0 -26
  87. data/spec/unit/relation_spec.rb +0 -272
@@ -1,26 +0,0 @@
1
- require 'dry-types'
2
- require 'sequel'
3
-
4
- module ROM
5
- module SQL
6
- module Types
7
- module PG
8
- Sequel.extension(:pg_json)
9
-
10
- Array = Dry::Types::Definition
11
- .new(Sequel::Postgres::JSONArray)
12
- .constructor(Sequel.method(:pg_json))
13
-
14
- Hash = Dry::Types::Definition
15
- .new(Sequel::Postgres::JSONHash)
16
- .constructor(Sequel.method(:pg_json))
17
-
18
- JSON = Array | Hash
19
-
20
- Bytea = Dry::Types::Definition
21
- .new(Sequel::SQL::Blob)
22
- .constructor(Sequel::SQL::Blob.method(:new))
23
- end
24
- end
25
- end
26
- end
@@ -1,272 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ROM::Relation do
4
- include_context 'users and tasks'
5
-
6
- let(:users) { container.relations.users }
7
- let(:tasks) { container.relations.tasks }
8
-
9
- context 'with schema', adapter: :sqlite do
10
- let(:uri) { SQLITE_DB_URI }
11
-
12
- before do
13
- conf.relation(:users) do
14
- schema do
15
- attribute :id, ROM::SQL::Types::Serial
16
- attribute :name, ROM::SQL::Types::String
17
- end
18
-
19
- def sorted
20
- order(:id)
21
- end
22
- end
23
-
24
- conf.relation(:tasks)
25
- end
26
-
27
- describe '#dataset' do
28
- it 'uses schema to infer default dataset' do
29
- expect(container.relations[:users].dataset).to eql(
30
- container.gateways[:default].dataset(:users).select(:id, :name).order(:users__id)
31
- )
32
- end
33
- end
34
- end
35
-
36
- with_adapters do
37
- context 'without schema' do
38
- before do
39
- conf.relation(:users) do
40
- def sorted
41
- order(:id)
42
- end
43
- end
44
-
45
- conf.relation(:tasks)
46
- end
47
-
48
- describe '#associations' do
49
- it 'returns an empty association set' do
50
- expect(users.associations.elements).to be_empty
51
- end
52
- end
53
-
54
- describe '#dataset' do
55
- it 'selects all qualified columns and sorts by pk' do
56
- expect(users.dataset).to eql(
57
- users.select(*users.columns).order(:users__id).dataset
58
- )
59
- end
60
- end
61
-
62
- describe '#primary_key' do
63
- it 'returns :id by default' do
64
- expect(users.primary_key).to be(:id)
65
- end
66
-
67
- it 'returns configured primary key from the schema' do
68
- conf.relation(:other_users) do
69
- schema(:users) do
70
- attribute :name, ROM::SQL::Types::String.meta(primary_key: true)
71
- end
72
- end
73
-
74
- expect(container.relations[:other_users].primary_key).to be(:name)
75
- end
76
- end
77
-
78
- describe '#sum' do
79
- it 'returns a sum' do
80
- expect(users.sum(:id)).to eql(3)
81
- end
82
- end
83
-
84
- describe '#min' do
85
- it 'returns a min' do
86
- expect(users.min(:id)).to eql(1)
87
- end
88
- end
89
-
90
- describe '#max' do
91
- it 'delegates to dataset and return value' do
92
- expect(users.max(:id)).to eql(2)
93
- end
94
- end
95
-
96
- describe '#avg' do
97
- it 'delegates to dataset and return value' do
98
- expect(users.avg(:id)).to eql(1.5)
99
- end
100
- end
101
-
102
- describe '#distinct' do
103
- it 'delegates to dataset and returns a new relation' do
104
- expect(users.dataset).to receive(:distinct).with(:name).and_call_original
105
- expect(users.distinct(:name)).to_not eq(users)
106
- end
107
- end
108
-
109
- describe '#exclude' do
110
- it 'delegates to dataset and returns a new relation' do
111
- expect(users.dataset)
112
- .to receive(:exclude).with(name: 'Jane').and_call_original
113
- expect(users.exclude(name: 'Jane')).to_not eq(users)
114
- end
115
- end
116
-
117
- describe '#invert' do
118
- it 'delegates to dataset and returns a new relation' do
119
- expect(users.dataset).to receive(:invert).and_call_original
120
- expect(users.invert).to_not eq(users)
121
- end
122
- end
123
-
124
- describe '#map' do
125
- it 'yields tuples' do
126
- result = users.map { |tuple| tuple[:name] }
127
- expect(result).to eql(%w(Jane Joe))
128
- end
129
-
130
- it 'plucks value' do
131
- expect(users.map(:name)).to eql(%w(Jane Joe))
132
- end
133
- end
134
-
135
- describe '#inner_join' do
136
- it 'joins relations using inner join' do
137
- result = users.inner_join(:tasks, user_id: :id).select(:name, :title)
138
-
139
- expect(result.to_a).to eql([
140
- { name: 'Jane', title: "Jane's task" },
141
- { name: 'Joe', title: "Joe's task" }
142
- ])
143
- end
144
-
145
- it 'raises error when column names are ambiguous' do
146
- expect {
147
- users.inner_join(:tasks, user_id: :id).to_a
148
- }.to raise_error(Sequel::DatabaseError, /is ambiguous/)
149
- end
150
- end
151
-
152
- describe '#left_join' do
153
- it 'joins relations using left outer join' do
154
- result = users.left_join(:tasks, user_id: :id).select(:name, :title)
155
-
156
- expect(result.to_a).to match_array([
157
- { name: 'Joe', title: "Joe's task" },
158
- { name: 'Jane', title: "Jane's task" }
159
- ])
160
- end
161
- end
162
-
163
- describe '#project' do
164
- it 'projects the dataset using new column names' do
165
- projected = users.sorted.project(:name)
166
-
167
- expect(projected.header).to match_array([:name])
168
- expect(projected.first).to eql(name: 'Jane')
169
- end
170
- end
171
-
172
- describe '#rename' do
173
- it 'projects the dataset using new column names' do
174
- renamed = users.sorted.rename(id: :user_id, name: :user_name)
175
-
176
- expect(renamed.first).to eql(user_id: 1, user_name: 'Jane')
177
- end
178
- end
179
-
180
- describe '#prefix' do
181
- it 'projects the dataset using new column names' do
182
- prefixed = users.sorted.prefix(:user)
183
-
184
- expect(prefixed.first).to eql(user_id: 1, user_name: 'Jane')
185
- end
186
-
187
- it 'uses singularized table name as the default prefix' do
188
- prefixed = users.sorted.prefix
189
-
190
- expect(prefixed.first).to eql(user_id: 1, user_name: 'Jane')
191
- end
192
- end
193
-
194
- describe '#qualified_columns' do
195
- it 'returns qualified column names' do
196
- columns = users.sorted.prefix(:user).qualified_columns
197
-
198
- expect(columns).to eql([:users__id___user_id, :users__name___user_name])
199
- end
200
-
201
- it 'returns projected qualified column names' do
202
- columns = users.sorted.project(:id).prefix(:user).qualified_columns
203
-
204
- expect(columns).to eql([:users__id___user_id])
205
- end
206
- end
207
-
208
- describe '#inspect' do
209
- it 'includes dataset' do
210
- expect(users.inspect).to include('dataset')
211
- end
212
- end
213
-
214
- describe '#unique?' do
215
- before { tasks.delete }
216
-
217
- it 'returns true when there is only one tuple matching criteria' do
218
- expect(tasks.unique?(title: 'Task One')).to be(true)
219
- end
220
-
221
- it 'returns true when there are more than one tuple matching criteria' do
222
- tasks.insert(title: 'Task One')
223
- expect(tasks.unique?(title: 'Task One')).to be(false)
224
- end
225
- end
226
-
227
- describe '#union' do
228
- let(:relation1) { users.where(id: 1).select(:id, :name) }
229
- let(:relation2) { users.where(id: 2).select(:id, :name) }
230
-
231
- it 'unions two relations and returns a new relation' do
232
- result = relation1.union(relation2)
233
-
234
- expect(result.to_a).to match_array([
235
- { id: 1, name: 'Jane' },
236
- { id: 2, name: 'Joe' }
237
- ])
238
- end
239
- end
240
-
241
- describe '#pluck' do
242
- it 'returns a list of values from a specific column' do
243
- expect(users.pluck(:id)).to eql([1, 2])
244
- end
245
- end
246
-
247
- describe '#by_pk' do
248
- it 'restricts a relation by its PK' do
249
- expect(users.by_pk(1).to_a).to eql([id: 1, name: 'Jane'])
250
- end
251
-
252
- it 'is available as a view' do
253
- expect(users.by_pk).to be_curried
254
- end
255
- end
256
-
257
- describe '#fetch' do
258
- it 'returns a single tuple identified by the pk' do
259
- expect(users.fetch(1)).to eql(id: 1, name: 'Jane')
260
- end
261
-
262
- it 'raises when tuple was not found' do
263
- expect { users.fetch(535315412) }.to raise_error(ROM::TupleCountMismatchError)
264
- end
265
-
266
- it 'raises when more tuples were returned' do
267
- expect { users.fetch([1, 2]) }.to raise_error(ROM::TupleCountMismatchError)
268
- end
269
- end
270
- end
271
- end
272
- end