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.
- checksums.yaml +4 -4
- data/.travis.yml +16 -12
- data/CHANGELOG.md +23 -0
- data/Gemfile +11 -3
- data/README.md +1 -7
- data/lib/rom/sql.rb +4 -7
- data/lib/rom/sql/association.rb +1 -1
- data/lib/rom/sql/association/one_to_many.rb +44 -1
- data/lib/rom/sql/association/one_to_one.rb +1 -38
- data/lib/rom/sql/commands.rb +0 -3
- data/lib/rom/sql/commands/error_wrapper.rb +1 -1
- data/lib/rom/sql/errors.rb +4 -1
- data/lib/rom/sql/extensions.rb +19 -0
- data/lib/rom/sql/{support → extensions}/active_support_notifications.rb +0 -0
- data/lib/rom/sql/extensions/postgres.rb +3 -0
- data/lib/rom/sql/{commands/postgres.rb → extensions/postgres/commands.rb} +38 -0
- data/lib/rom/sql/extensions/postgres/inferrer.rb +64 -0
- data/lib/rom/sql/extensions/postgres/types.rb +65 -0
- data/lib/rom/sql/{support → extensions}/rails_log_subscriber.rb +0 -0
- data/lib/rom/sql/gateway.rb +15 -4
- data/lib/rom/sql/relation.rb +6 -2
- data/lib/rom/sql/relation/reading.rb +18 -0
- data/lib/rom/sql/schema/dsl.rb +7 -4
- data/lib/rom/sql/schema/inferrer.rb +44 -31
- data/lib/rom/sql/types.rb +5 -1
- data/lib/rom/sql/version.rb +1 -1
- data/rom-sql.gemspec +14 -13
- data/spec/extensions/postgres/inferrer_spec.rb +40 -0
- data/spec/extensions/postgres/integration_spec.rb +38 -0
- data/spec/extensions/postgres/types_spec.rb +115 -0
- data/spec/integration/association/many_to_many_spec.rb +2 -1
- data/spec/integration/association/one_to_one_spec.rb +6 -4
- data/spec/integration/combine_spec.rb +1 -1
- data/spec/integration/commands/create_spec.rb +46 -21
- data/spec/integration/commands/delete_spec.rb +13 -38
- data/spec/integration/commands/update_spec.rb +19 -41
- data/spec/integration/commands/upsert_spec.rb +1 -1
- data/spec/integration/gateway_spec.rb +5 -9
- data/spec/integration/migration_spec.rb +6 -7
- data/spec/integration/read_spec.rb +30 -38
- data/spec/integration/schema_inference_spec.rb +211 -49
- data/spec/integration/setup_spec.rb +5 -5
- data/spec/integration/support/active_support_notifications_spec.rb +4 -3
- data/spec/integration/support/rails_log_subscriber_spec.rb +5 -4
- data/spec/shared/database_setup.rb +21 -6
- data/spec/spec_helper.rb +44 -35
- data/spec/unit/association/one_to_many_spec.rb +20 -0
- data/spec/unit/association/one_to_one_spec.rb +23 -2
- data/spec/unit/association_errors_spec.rb +1 -1
- data/spec/unit/gateway_spec.rb +9 -8
- data/spec/unit/logger_spec.rb +1 -1
- data/spec/unit/migration_tasks_spec.rb +3 -3
- data/spec/unit/migrator_spec.rb +3 -2
- data/spec/unit/plugin/assoc_macros/combined_associations_spec.rb +1 -1
- data/spec/unit/plugin/assoc_macros/many_to_many_spec.rb +1 -1
- data/spec/unit/plugin/assoc_macros/many_to_one_spec.rb +1 -1
- data/spec/unit/plugin/assoc_macros/one_to_many_spec.rb +1 -1
- data/spec/unit/relation/associations_spec.rb +27 -0
- data/spec/unit/relation/avg_spec.rb +11 -0
- data/spec/unit/relation/by_pk_spec.rb +15 -0
- data/spec/unit/relation/dataset_spec.rb +48 -0
- data/spec/unit/relation/distinct_spec.rb +14 -0
- data/spec/unit/relation/exclude_spec.rb +13 -0
- data/spec/unit/relation/fetch_spec.rb +21 -0
- data/spec/unit/relation/having_spec.rb +20 -0
- data/spec/unit/relation/inner_join_spec.rb +22 -0
- data/spec/unit/relation/inspect_spec.rb +11 -0
- data/spec/unit/relation/invert_spec.rb +12 -0
- data/spec/unit/relation/left_join_spec.rb +16 -0
- data/spec/unit/relation/map_spec.rb +16 -0
- data/spec/unit/relation/max_spec.rb +11 -0
- data/spec/unit/relation/min_spec.rb +11 -0
- data/spec/unit/relation/pluck_spec.rb +11 -0
- data/spec/unit/relation/prefix_spec.rb +27 -0
- data/spec/unit/relation/primary_key_spec.rb +27 -0
- data/spec/unit/relation/project_spec.rb +22 -0
- data/spec/unit/relation/qualified_columns_spec.rb +27 -0
- data/spec/unit/relation/rename_spec.rb +21 -0
- data/spec/unit/relation/sum_spec.rb +11 -0
- data/spec/unit/relation/union_spec.rb +19 -0
- data/spec/unit/relation/unique_predicate_spec.rb +18 -0
- data/spec/unit/schema_spec.rb +1 -1
- data/spec/unit/types_spec.rb +4 -21
- metadata +79 -11
- data/lib/rom/sql/commands_ext/postgres.rb +0 -45
- data/lib/rom/sql/types/pg.rb +0 -26
- data/spec/unit/relation_spec.rb +0 -272
data/lib/rom/sql/types/pg.rb
DELETED
@@ -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
|
data/spec/unit/relation_spec.rb
DELETED
@@ -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
|