rom-sql 0.6.0.beta1 → 0.6.0.rc1
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 +6 -0
- data/README.md +2 -2
- data/lib/rom/sql/relation.rb +4 -377
- data/lib/rom/sql/relation/reading.rb +329 -0
- data/lib/rom/sql/relation/writing.rb +62 -0
- data/lib/rom/sql/version.rb +1 -1
- data/rom-sql.gemspec +1 -1
- data/spec/integration/commands/update_spec.rb +2 -2
- data/spec/unit/combined_associations_spec.rb +6 -1
- data/spec/unit/plugin/pagination_spec.rb +1 -1
- data/spec/unit/relation_spec.rb +2 -3
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7e48205c56b7409f2b14e32a3a7ca37191d73d26
|
4
|
+
data.tar.gz: 87551dc3a1bfae2fcfd3f48c337f07a76f292073
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f8fca06faa321e6dc58094d25a549d4e6d7f2f38e587fc12de8db1fe2d4f993ccf7cbe5e1d717439c14598aa2b19c85ed1b7e183022d3d48678909f4fdd4cce8
|
7
|
+
data.tar.gz: 01aea56b1a452e7f468de29aa7c7fe67e9f96c0ab65f256665c8ba1e149f85f24dd6f1aa660e97d8d819caff5a35f1de34a4737eed90dee8a150a641a13daced
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -15,9 +15,9 @@
|
|
15
15
|
|
16
16
|
RDBMS support for [Ruby Object Mapper](https://github.com/rom-rb/rom).
|
17
17
|
|
18
|
-
|
18
|
+
Resources:
|
19
19
|
|
20
|
-
|
20
|
+
- [Guides](http://rom-rb.org/guides/adapters/sql/)
|
21
21
|
|
22
22
|
## Installation
|
23
23
|
|
data/lib/rom/sql/relation.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'rom/sql/header'
|
2
2
|
|
3
3
|
require 'rom/sql/relation/class_methods'
|
4
|
+
require 'rom/sql/relation/reading'
|
5
|
+
require 'rom/sql/relation/writing'
|
4
6
|
require 'rom/sql/relation/inspection'
|
5
7
|
require 'rom/sql/relation/associations'
|
6
8
|
|
@@ -15,6 +17,8 @@ module ROM
|
|
15
17
|
|
16
18
|
include Inspection
|
17
19
|
include Associations
|
20
|
+
include Writing
|
21
|
+
include Reading
|
18
22
|
|
19
23
|
# @attr_reader [Header] header Internal lazy-initialized header
|
20
24
|
attr_reader :header
|
@@ -30,383 +34,6 @@ module ROM
|
|
30
34
|
@table = dataset.opts[:from].first
|
31
35
|
end
|
32
36
|
|
33
|
-
# Project a relation
|
34
|
-
#
|
35
|
-
# This method is intended to be used internally within a relation object
|
36
|
-
#
|
37
|
-
# @example
|
38
|
-
# rom.relation(:users) { |r| r.project(:id, :name) }
|
39
|
-
#
|
40
|
-
# @param [Symbol] names A list of symbol column names
|
41
|
-
#
|
42
|
-
# @return [Relation]
|
43
|
-
#
|
44
|
-
# @api public
|
45
|
-
def project(*names)
|
46
|
-
select(*header.project(*names))
|
47
|
-
end
|
48
|
-
|
49
|
-
# Rename columns in a relation
|
50
|
-
#
|
51
|
-
# This method is intended to be used internally within a relation object
|
52
|
-
#
|
53
|
-
# @example
|
54
|
-
# rom.relation(:users) { |r| r.rename(name: :user_name) }
|
55
|
-
#
|
56
|
-
# @param [Hash] options A name => new_name map
|
57
|
-
#
|
58
|
-
# @return [Relation]
|
59
|
-
#
|
60
|
-
# @api public
|
61
|
-
def rename(options)
|
62
|
-
select(*header.rename(options))
|
63
|
-
end
|
64
|
-
|
65
|
-
# Prefix all columns in a relation
|
66
|
-
#
|
67
|
-
# This method is intended to be used internally within a relation object
|
68
|
-
#
|
69
|
-
# @example
|
70
|
-
# rom.relation(:users) { |r| r.prefix(:user) }
|
71
|
-
#
|
72
|
-
# @param [Symbol] name The prefix
|
73
|
-
#
|
74
|
-
# @return [Relation]
|
75
|
-
#
|
76
|
-
# @api public
|
77
|
-
def prefix(name = Inflector.singularize(table))
|
78
|
-
rename(header.prefix(name).to_h)
|
79
|
-
end
|
80
|
-
|
81
|
-
# Qualifies all columns in a relation
|
82
|
-
#
|
83
|
-
# This method is intended to be used internally within a relation object
|
84
|
-
#
|
85
|
-
# @example
|
86
|
-
# rom.relation(:users) { |r| r.qualified }
|
87
|
-
#
|
88
|
-
# @return [Relation]
|
89
|
-
#
|
90
|
-
# @api public
|
91
|
-
def qualified
|
92
|
-
select(*qualified_columns)
|
93
|
-
end
|
94
|
-
|
95
|
-
# Return a list of qualified column names
|
96
|
-
#
|
97
|
-
# This method is intended to be used internally within a relation object
|
98
|
-
#
|
99
|
-
# @return [Relation]
|
100
|
-
#
|
101
|
-
# @api public
|
102
|
-
def qualified_columns
|
103
|
-
header.qualified.to_a
|
104
|
-
end
|
105
|
-
|
106
|
-
# Get first tuple from the relation
|
107
|
-
#
|
108
|
-
# @example
|
109
|
-
# users.first
|
110
|
-
#
|
111
|
-
# @return [Relation]
|
112
|
-
#
|
113
|
-
# @api public
|
114
|
-
def first
|
115
|
-
dataset.first
|
116
|
-
end
|
117
|
-
|
118
|
-
# Get last tuple from the relation
|
119
|
-
#
|
120
|
-
# @example
|
121
|
-
# users.last
|
122
|
-
#
|
123
|
-
# @return [Relation]
|
124
|
-
#
|
125
|
-
# @api public
|
126
|
-
def last
|
127
|
-
dataset.last
|
128
|
-
end
|
129
|
-
|
130
|
-
# Return relation count
|
131
|
-
#
|
132
|
-
# @example
|
133
|
-
# users.count # => 12
|
134
|
-
#
|
135
|
-
# @return [Relation]
|
136
|
-
#
|
137
|
-
# @api public
|
138
|
-
def count
|
139
|
-
dataset.count
|
140
|
-
end
|
141
|
-
|
142
|
-
# Select specific columns for select clause
|
143
|
-
#
|
144
|
-
# @example
|
145
|
-
# users.select(:id, :name)
|
146
|
-
#
|
147
|
-
# @return [Relation]
|
148
|
-
#
|
149
|
-
# @api public
|
150
|
-
def select(*args, &block)
|
151
|
-
__new__(dataset.__send__(__method__, *args, &block))
|
152
|
-
end
|
153
|
-
|
154
|
-
# Append specific columns to select clause
|
155
|
-
#
|
156
|
-
# @example
|
157
|
-
# users.select(:id, :name).select_append(:email)
|
158
|
-
#
|
159
|
-
# @return [Relation]
|
160
|
-
#
|
161
|
-
# @api public
|
162
|
-
def select_append(*args, &block)
|
163
|
-
__new__(dataset.__send__(__method__, *args, &block))
|
164
|
-
end
|
165
|
-
|
166
|
-
# Returns a copy of the relation with a SQL DISTINCT clause.
|
167
|
-
#
|
168
|
-
# @example
|
169
|
-
# users.distinct(:country)
|
170
|
-
#
|
171
|
-
# @return [Relation]
|
172
|
-
#
|
173
|
-
# @api public
|
174
|
-
def distinct(*args, &block)
|
175
|
-
__new__(dataset.__send__(__method__, *args, &block))
|
176
|
-
end
|
177
|
-
|
178
|
-
# Restrict a relation to match criteria
|
179
|
-
#
|
180
|
-
# @example
|
181
|
-
# users.where(name: 'Jane')
|
182
|
-
#
|
183
|
-
# @return [Relation]
|
184
|
-
#
|
185
|
-
# @api public
|
186
|
-
def where(*args, &block)
|
187
|
-
__new__(dataset.__send__(__method__, *args, &block))
|
188
|
-
end
|
189
|
-
|
190
|
-
# Restrict a relation to not match criteria
|
191
|
-
#
|
192
|
-
# @example
|
193
|
-
# users.exclude(name: 'Jane')
|
194
|
-
#
|
195
|
-
# @return [Relation]
|
196
|
-
#
|
197
|
-
# @api public
|
198
|
-
def exclude(*args, &block)
|
199
|
-
__new__(dataset.__send__(__method__, *args, &block))
|
200
|
-
end
|
201
|
-
|
202
|
-
# Inverts a request
|
203
|
-
#
|
204
|
-
# @example
|
205
|
-
# users.exclude(name: 'Jane').invert
|
206
|
-
#
|
207
|
-
# # this is the same as:
|
208
|
-
# users.where(name: 'Jane')
|
209
|
-
#
|
210
|
-
# @return [Relation]
|
211
|
-
#
|
212
|
-
# @api public
|
213
|
-
def invert(*args, &block)
|
214
|
-
__new__(dataset.__send__(__method__, *args, &block))
|
215
|
-
end
|
216
|
-
|
217
|
-
# Set order for the relation
|
218
|
-
#
|
219
|
-
# @example
|
220
|
-
# users.order(:name)
|
221
|
-
#
|
222
|
-
# @return [Relation]
|
223
|
-
#
|
224
|
-
# @api public
|
225
|
-
def order(*args, &block)
|
226
|
-
__new__(dataset.__send__(__method__, *args, &block))
|
227
|
-
end
|
228
|
-
|
229
|
-
# Reverse the order of the relation
|
230
|
-
#
|
231
|
-
# @example
|
232
|
-
# users.order(:name).reverse
|
233
|
-
#
|
234
|
-
# @return [Relation]
|
235
|
-
#
|
236
|
-
# @api public
|
237
|
-
def reverse(*args, &block)
|
238
|
-
__new__(dataset.__send__(__method__, *args, &block))
|
239
|
-
end
|
240
|
-
|
241
|
-
# Limit a relation to a specific number of tuples
|
242
|
-
#
|
243
|
-
# @example
|
244
|
-
# users.limit(1)
|
245
|
-
#
|
246
|
-
# @return [Relation]
|
247
|
-
#
|
248
|
-
# @api public
|
249
|
-
def limit(*args, &block)
|
250
|
-
__new__(dataset.__send__(__method__, *args, &block))
|
251
|
-
end
|
252
|
-
|
253
|
-
# Set offset for the relation
|
254
|
-
#
|
255
|
-
# @example
|
256
|
-
# users.limit(10).offset(2)
|
257
|
-
#
|
258
|
-
# @return [Relation]
|
259
|
-
#
|
260
|
-
# @api public
|
261
|
-
def offset(*args, &block)
|
262
|
-
__new__(dataset.__send__(__method__, *args, &block))
|
263
|
-
end
|
264
|
-
|
265
|
-
# Map tuples from the relation
|
266
|
-
#
|
267
|
-
# @example
|
268
|
-
# users.map { |user| ... }
|
269
|
-
#
|
270
|
-
# @api public
|
271
|
-
def map(&block)
|
272
|
-
to_enum.map(&block)
|
273
|
-
end
|
274
|
-
|
275
|
-
# Join other relation using inner join
|
276
|
-
#
|
277
|
-
# @param [Symbol] relation name
|
278
|
-
# @param [Hash] join keys
|
279
|
-
#
|
280
|
-
# @return [Relation]
|
281
|
-
#
|
282
|
-
# @api public
|
283
|
-
def inner_join(*args, &block)
|
284
|
-
__new__(dataset.__send__(__method__, *args, &block))
|
285
|
-
end
|
286
|
-
|
287
|
-
# Join other relation using left outer join
|
288
|
-
#
|
289
|
-
# @param [Symbol] relation name
|
290
|
-
# @param [Hash] join keys
|
291
|
-
#
|
292
|
-
# @return [Relation]
|
293
|
-
#
|
294
|
-
# @api public
|
295
|
-
def left_join(*args, &block)
|
296
|
-
__new__(dataset.__send__(__method__, *args, &block))
|
297
|
-
end
|
298
|
-
|
299
|
-
# Group by specific columns
|
300
|
-
#
|
301
|
-
# @example
|
302
|
-
# tasks.group(:user_id)
|
303
|
-
#
|
304
|
-
# @return [Relation]
|
305
|
-
#
|
306
|
-
# @api public
|
307
|
-
def group(*args, &block)
|
308
|
-
__new__(dataset.__send__(__method__, *args, &block))
|
309
|
-
end
|
310
|
-
|
311
|
-
# Group by specific columns and count by group
|
312
|
-
#
|
313
|
-
# @example
|
314
|
-
# tasks.group_and_count(:user_id)
|
315
|
-
# # => [{ user_id: 1, count: 2 }, { user_id: 2, count: 3 }]
|
316
|
-
#
|
317
|
-
# @return [Relation]
|
318
|
-
#
|
319
|
-
# @api public
|
320
|
-
def group_and_count(*args, &block)
|
321
|
-
__new__(dataset.__send__(__method__, *args, &block))
|
322
|
-
end
|
323
|
-
|
324
|
-
# Select and group by specific columns
|
325
|
-
#
|
326
|
-
# @example
|
327
|
-
# tasks.select_group(:user_id)
|
328
|
-
# # => [{ user_id: 1 }, { user_id: 2 }]
|
329
|
-
#
|
330
|
-
# @return [Relation]
|
331
|
-
#
|
332
|
-
# @api public
|
333
|
-
def select_group(*args, &block)
|
334
|
-
__new__(dataset.__send__(__method__, *args, &block))
|
335
|
-
end
|
336
|
-
|
337
|
-
# Insert tuple into relation
|
338
|
-
#
|
339
|
-
# @example
|
340
|
-
# users.insert(name: 'Jane')
|
341
|
-
#
|
342
|
-
# @param [Hash] tuple
|
343
|
-
#
|
344
|
-
# @return [Relation]
|
345
|
-
#
|
346
|
-
# @api public
|
347
|
-
def insert(*args, &block)
|
348
|
-
dataset.insert(*args, &block)
|
349
|
-
end
|
350
|
-
|
351
|
-
# Multi insert tuples into relation
|
352
|
-
#
|
353
|
-
# @example
|
354
|
-
# users.multi_insert([{name: 'Jane'}, {name: 'Jack'}])
|
355
|
-
#
|
356
|
-
# @param [Array] tuples
|
357
|
-
#
|
358
|
-
# @return [Relation]
|
359
|
-
#
|
360
|
-
# @api public
|
361
|
-
def multi_insert(*args, &block)
|
362
|
-
dataset.multi_insert(*args, &block)
|
363
|
-
end
|
364
|
-
|
365
|
-
# Update tuples in the relation
|
366
|
-
#
|
367
|
-
# @example
|
368
|
-
# users.update(name: 'Jane')
|
369
|
-
# users.where(name: 'Jane').update(name: 'Jane Doe')
|
370
|
-
#
|
371
|
-
# @return [Relation]
|
372
|
-
#
|
373
|
-
# @api public
|
374
|
-
def update(*args, &block)
|
375
|
-
dataset.update(*args, &block)
|
376
|
-
end
|
377
|
-
|
378
|
-
# Delete tuples from the relation
|
379
|
-
#
|
380
|
-
# @example
|
381
|
-
# users.delete # deletes all
|
382
|
-
# users.where(name: 'Jane').delete # delete tuples
|
383
|
-
# from restricted relation
|
384
|
-
#
|
385
|
-
# @return [Relation]
|
386
|
-
#
|
387
|
-
# @api public
|
388
|
-
def delete(*args, &block)
|
389
|
-
dataset.delete(*args, &block)
|
390
|
-
end
|
391
|
-
|
392
|
-
# Return if a restricted relation has 0 tuples
|
393
|
-
#
|
394
|
-
# @example
|
395
|
-
# users.unique?(email: 'jane@doe.org') # true
|
396
|
-
#
|
397
|
-
# users.insert(email: 'jane@doe.org')
|
398
|
-
#
|
399
|
-
# users.unique?(email: 'jane@doe.org') # false
|
400
|
-
#
|
401
|
-
# @param [Hash] criteria hash for the where clause
|
402
|
-
#
|
403
|
-
# @return [Relation]
|
404
|
-
#
|
405
|
-
# @api public
|
406
|
-
def unique?(criteria)
|
407
|
-
where(criteria).count.zero?
|
408
|
-
end
|
409
|
-
|
410
37
|
# Return a header for this relation
|
411
38
|
#
|
412
39
|
# @return [Header]
|
@@ -0,0 +1,329 @@
|
|
1
|
+
module ROM
|
2
|
+
module SQL
|
3
|
+
class Relation < ROM::Relation
|
4
|
+
module Reading
|
5
|
+
# Return relation count
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# users.count # => 12
|
9
|
+
#
|
10
|
+
# @return [Relation]
|
11
|
+
#
|
12
|
+
# @api public
|
13
|
+
def count
|
14
|
+
dataset.count
|
15
|
+
end
|
16
|
+
|
17
|
+
# Get first tuple from the relation
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# users.first
|
21
|
+
#
|
22
|
+
# @return [Relation]
|
23
|
+
#
|
24
|
+
# @api public
|
25
|
+
def first
|
26
|
+
dataset.first
|
27
|
+
end
|
28
|
+
|
29
|
+
# Get last tuple from the relation
|
30
|
+
#
|
31
|
+
# @example
|
32
|
+
# users.last
|
33
|
+
#
|
34
|
+
# @return [Relation]
|
35
|
+
#
|
36
|
+
# @api public
|
37
|
+
def last
|
38
|
+
dataset.last
|
39
|
+
end
|
40
|
+
|
41
|
+
# Prefix all columns in a relation
|
42
|
+
#
|
43
|
+
# This method is intended to be used internally within a relation object
|
44
|
+
#
|
45
|
+
# @example
|
46
|
+
# rom.relation(:users) { |r| r.prefix(:user) }
|
47
|
+
#
|
48
|
+
# @param [Symbol] name The prefix
|
49
|
+
#
|
50
|
+
# @return [Relation]
|
51
|
+
#
|
52
|
+
# @api public
|
53
|
+
def prefix(name = Inflector.singularize(table))
|
54
|
+
rename(header.prefix(name).to_h)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Qualifies all columns in a relation
|
58
|
+
#
|
59
|
+
# This method is intended to be used internally within a relation object
|
60
|
+
#
|
61
|
+
# @example
|
62
|
+
# rom.relation(:users) { |r| r.qualified }
|
63
|
+
#
|
64
|
+
# @return [Relation]
|
65
|
+
#
|
66
|
+
# @api public
|
67
|
+
def qualified
|
68
|
+
select(*qualified_columns)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Return a list of qualified column names
|
72
|
+
#
|
73
|
+
# This method is intended to be used internally within a relation object
|
74
|
+
#
|
75
|
+
# @return [Relation]
|
76
|
+
#
|
77
|
+
# @api public
|
78
|
+
def qualified_columns
|
79
|
+
header.qualified.to_a
|
80
|
+
end
|
81
|
+
|
82
|
+
# Return if a restricted relation has 0 tuples
|
83
|
+
#
|
84
|
+
# @example
|
85
|
+
# users.unique?(email: 'jane@doe.org') # true
|
86
|
+
#
|
87
|
+
# users.insert(email: 'jane@doe.org')
|
88
|
+
#
|
89
|
+
# users.unique?(email: 'jane@doe.org') # false
|
90
|
+
#
|
91
|
+
# @param [Hash] criteria hash for the where clause
|
92
|
+
#
|
93
|
+
# @return [Relation]
|
94
|
+
#
|
95
|
+
# @api public
|
96
|
+
def unique?(criteria)
|
97
|
+
where(criteria).count.zero?
|
98
|
+
end
|
99
|
+
|
100
|
+
# Map tuples from the relation
|
101
|
+
#
|
102
|
+
# @example
|
103
|
+
# users.map { |user| ... }
|
104
|
+
#
|
105
|
+
# @api public
|
106
|
+
def map(&block)
|
107
|
+
dataset.map(&block)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Project a relation
|
111
|
+
#
|
112
|
+
# This method is intended to be used internally within a relation object
|
113
|
+
#
|
114
|
+
# @example
|
115
|
+
# rom.relation(:users) { |r| r.project(:id, :name) }
|
116
|
+
#
|
117
|
+
# @param [Symbol] names A list of symbol column names
|
118
|
+
#
|
119
|
+
# @return [Relation]
|
120
|
+
#
|
121
|
+
# @api public
|
122
|
+
def project(*names)
|
123
|
+
select(*header.project(*names))
|
124
|
+
end
|
125
|
+
|
126
|
+
# Rename columns in a relation
|
127
|
+
#
|
128
|
+
# This method is intended to be used internally within a relation object
|
129
|
+
#
|
130
|
+
# @example
|
131
|
+
# rom.relation(:users) { |r| r.rename(name: :user_name) }
|
132
|
+
#
|
133
|
+
# @param [Hash] options A name => new_name map
|
134
|
+
#
|
135
|
+
# @return [Relation]
|
136
|
+
#
|
137
|
+
# @api public
|
138
|
+
def rename(options)
|
139
|
+
select(*header.rename(options))
|
140
|
+
end
|
141
|
+
|
142
|
+
# Select specific columns for select clause
|
143
|
+
#
|
144
|
+
# @example
|
145
|
+
# users.select(:id, :name)
|
146
|
+
#
|
147
|
+
# @return [Relation]
|
148
|
+
#
|
149
|
+
# @api public
|
150
|
+
def select(*args, &block)
|
151
|
+
__new__(dataset.__send__(__method__, *args, &block))
|
152
|
+
end
|
153
|
+
|
154
|
+
# Append specific columns to select clause
|
155
|
+
#
|
156
|
+
# @example
|
157
|
+
# users.select(:id, :name).select_append(:email)
|
158
|
+
#
|
159
|
+
# @return [Relation]
|
160
|
+
#
|
161
|
+
# @api public
|
162
|
+
def select_append(*args, &block)
|
163
|
+
__new__(dataset.__send__(__method__, *args, &block))
|
164
|
+
end
|
165
|
+
|
166
|
+
# Returns a copy of the relation with a SQL DISTINCT clause.
|
167
|
+
#
|
168
|
+
# @example
|
169
|
+
# users.distinct(:country)
|
170
|
+
#
|
171
|
+
# @return [Relation]
|
172
|
+
#
|
173
|
+
# @api public
|
174
|
+
def distinct(*args, &block)
|
175
|
+
__new__(dataset.__send__(__method__, *args, &block))
|
176
|
+
end
|
177
|
+
|
178
|
+
# Restrict a relation to match criteria
|
179
|
+
#
|
180
|
+
# @example
|
181
|
+
# users.where(name: 'Jane')
|
182
|
+
#
|
183
|
+
# @return [Relation]
|
184
|
+
#
|
185
|
+
# @api public
|
186
|
+
def where(*args, &block)
|
187
|
+
__new__(dataset.__send__(__method__, *args, &block))
|
188
|
+
end
|
189
|
+
|
190
|
+
# Restrict a relation to not match criteria
|
191
|
+
#
|
192
|
+
# @example
|
193
|
+
# users.exclude(name: 'Jane')
|
194
|
+
#
|
195
|
+
# @return [Relation]
|
196
|
+
#
|
197
|
+
# @api public
|
198
|
+
def exclude(*args, &block)
|
199
|
+
__new__(dataset.__send__(__method__, *args, &block))
|
200
|
+
end
|
201
|
+
|
202
|
+
# Inverts a request
|
203
|
+
#
|
204
|
+
# @example
|
205
|
+
# users.exclude(name: 'Jane').invert
|
206
|
+
#
|
207
|
+
# # this is the same as:
|
208
|
+
# users.where(name: 'Jane')
|
209
|
+
#
|
210
|
+
# @return [Relation]
|
211
|
+
#
|
212
|
+
# @api public
|
213
|
+
def invert(*args, &block)
|
214
|
+
__new__(dataset.__send__(__method__, *args, &block))
|
215
|
+
end
|
216
|
+
|
217
|
+
# Set order for the relation
|
218
|
+
#
|
219
|
+
# @example
|
220
|
+
# users.order(:name)
|
221
|
+
#
|
222
|
+
# @return [Relation]
|
223
|
+
#
|
224
|
+
# @api public
|
225
|
+
def order(*args, &block)
|
226
|
+
__new__(dataset.__send__(__method__, *args, &block))
|
227
|
+
end
|
228
|
+
|
229
|
+
# Reverse the order of the relation
|
230
|
+
#
|
231
|
+
# @example
|
232
|
+
# users.order(:name).reverse
|
233
|
+
#
|
234
|
+
# @return [Relation]
|
235
|
+
#
|
236
|
+
# @api public
|
237
|
+
def reverse(*args, &block)
|
238
|
+
__new__(dataset.__send__(__method__, *args, &block))
|
239
|
+
end
|
240
|
+
|
241
|
+
# Limit a relation to a specific number of tuples
|
242
|
+
#
|
243
|
+
# @example
|
244
|
+
# users.limit(1)
|
245
|
+
#
|
246
|
+
# @return [Relation]
|
247
|
+
#
|
248
|
+
# @api public
|
249
|
+
def limit(*args, &block)
|
250
|
+
__new__(dataset.__send__(__method__, *args, &block))
|
251
|
+
end
|
252
|
+
|
253
|
+
# Set offset for the relation
|
254
|
+
#
|
255
|
+
# @example
|
256
|
+
# users.limit(10).offset(2)
|
257
|
+
#
|
258
|
+
# @return [Relation]
|
259
|
+
#
|
260
|
+
# @api public
|
261
|
+
def offset(*args, &block)
|
262
|
+
__new__(dataset.__send__(__method__, *args, &block))
|
263
|
+
end
|
264
|
+
|
265
|
+
# Join other relation using inner join
|
266
|
+
#
|
267
|
+
# @param [Symbol] relation name
|
268
|
+
# @param [Hash] join keys
|
269
|
+
#
|
270
|
+
# @return [Relation]
|
271
|
+
#
|
272
|
+
# @api public
|
273
|
+
def inner_join(*args, &block)
|
274
|
+
__new__(dataset.__send__(__method__, *args, &block))
|
275
|
+
end
|
276
|
+
|
277
|
+
# Join other relation using left outer join
|
278
|
+
#
|
279
|
+
# @param [Symbol] relation name
|
280
|
+
# @param [Hash] join keys
|
281
|
+
#
|
282
|
+
# @return [Relation]
|
283
|
+
#
|
284
|
+
# @api public
|
285
|
+
def left_join(*args, &block)
|
286
|
+
__new__(dataset.__send__(__method__, *args, &block))
|
287
|
+
end
|
288
|
+
|
289
|
+
# Group by specific columns
|
290
|
+
#
|
291
|
+
# @example
|
292
|
+
# tasks.group(:user_id)
|
293
|
+
#
|
294
|
+
# @return [Relation]
|
295
|
+
#
|
296
|
+
# @api public
|
297
|
+
def group(*args, &block)
|
298
|
+
__new__(dataset.__send__(__method__, *args, &block))
|
299
|
+
end
|
300
|
+
|
301
|
+
# Group by specific columns and count by group
|
302
|
+
#
|
303
|
+
# @example
|
304
|
+
# tasks.group_and_count(:user_id)
|
305
|
+
# # => [{ user_id: 1, count: 2 }, { user_id: 2, count: 3 }]
|
306
|
+
#
|
307
|
+
# @return [Relation]
|
308
|
+
#
|
309
|
+
# @api public
|
310
|
+
def group_and_count(*args, &block)
|
311
|
+
__new__(dataset.__send__(__method__, *args, &block))
|
312
|
+
end
|
313
|
+
|
314
|
+
# Select and group by specific columns
|
315
|
+
#
|
316
|
+
# @example
|
317
|
+
# tasks.select_group(:user_id)
|
318
|
+
# # => [{ user_id: 1 }, { user_id: 2 }]
|
319
|
+
#
|
320
|
+
# @return [Relation]
|
321
|
+
#
|
322
|
+
# @api public
|
323
|
+
def select_group(*args, &block)
|
324
|
+
__new__(dataset.__send__(__method__, *args, &block))
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module ROM
|
2
|
+
module SQL
|
3
|
+
class Relation < ROM::Relation
|
4
|
+
module Writing
|
5
|
+
# Insert tuple into relation
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# users.insert(name: 'Jane')
|
9
|
+
#
|
10
|
+
# @param [Hash] tuple
|
11
|
+
#
|
12
|
+
# @return [Relation]
|
13
|
+
#
|
14
|
+
# @api public
|
15
|
+
def insert(*args, &block)
|
16
|
+
dataset.insert(*args, &block)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Multi insert tuples into relation
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# users.multi_insert([{name: 'Jane'}, {name: 'Jack'}])
|
23
|
+
#
|
24
|
+
# @param [Array] tuples
|
25
|
+
#
|
26
|
+
# @return [Relation]
|
27
|
+
#
|
28
|
+
# @api public
|
29
|
+
def multi_insert(*args, &block)
|
30
|
+
dataset.multi_insert(*args, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Update tuples in the relation
|
34
|
+
#
|
35
|
+
# @example
|
36
|
+
# users.update(name: 'Jane')
|
37
|
+
# users.where(name: 'Jane').update(name: 'Jane Doe')
|
38
|
+
#
|
39
|
+
# @return [Relation]
|
40
|
+
#
|
41
|
+
# @api public
|
42
|
+
def update(*args, &block)
|
43
|
+
dataset.update(*args, &block)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Delete tuples from the relation
|
47
|
+
#
|
48
|
+
# @example
|
49
|
+
# users.delete # deletes all
|
50
|
+
# users.where(name: 'Jane').delete # delete tuples
|
51
|
+
# from restricted relation
|
52
|
+
#
|
53
|
+
# @return [Relation]
|
54
|
+
#
|
55
|
+
# @api public
|
56
|
+
def delete(*args, &block)
|
57
|
+
dataset.delete(*args, &block)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/rom/sql/version.rb
CHANGED
data/rom-sql.gemspec
CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_runtime_dependency "sequel", "~> 4.18"
|
22
22
|
spec.add_runtime_dependency "equalizer", "~> 0.0", ">= 0.0.9"
|
23
|
-
spec.add_runtime_dependency "rom", "~> 0.9.0.
|
23
|
+
spec.add_runtime_dependency "rom", "~> 0.9.0.rc1"
|
24
24
|
|
25
25
|
spec.add_development_dependency "bundler"
|
26
26
|
spec.add_development_dependency "rake", "~> 10.0"
|
@@ -7,7 +7,7 @@ describe 'Commands / Update' do
|
|
7
7
|
subject(:users) { rom.command(:users) }
|
8
8
|
|
9
9
|
let(:relation) { rom.relations.users }
|
10
|
-
let(:piotr) { relation.by_name('Piotr').
|
10
|
+
let(:piotr) { relation.by_name('Piotr').one }
|
11
11
|
let(:peter) { { name: 'Peter' } }
|
12
12
|
|
13
13
|
before do
|
@@ -51,7 +51,7 @@ describe 'Commands / Update' do
|
|
51
51
|
raise ROM::SQL::Rollback
|
52
52
|
end
|
53
53
|
|
54
|
-
expect(relation.
|
54
|
+
expect(relation.one[:name]).to eql('Piotr')
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
@@ -9,6 +9,7 @@ describe 'Defining multiple associations' do
|
|
9
9
|
|
10
10
|
it 'extends relation with association methods' do
|
11
11
|
setup.relation(:users)
|
12
|
+
|
12
13
|
setup.relation(:tags)
|
13
14
|
|
14
15
|
setup.relation(:tasks) do
|
@@ -31,6 +32,10 @@ describe 'Defining multiple associations' do
|
|
31
32
|
where(tags__name: name)
|
32
33
|
end
|
33
34
|
|
35
|
+
def by_title(title)
|
36
|
+
where(tasks__title: title)
|
37
|
+
end
|
38
|
+
|
34
39
|
def with_tags
|
35
40
|
association_left_join(:tags, select: [:name])
|
36
41
|
end
|
@@ -65,7 +70,7 @@ describe 'Defining multiple associations' do
|
|
65
70
|
{ id: 2, title: 'Go to sleep', name: 'Piotr' }
|
66
71
|
])
|
67
72
|
|
68
|
-
expect(tasks.
|
73
|
+
expect(tasks.by_title('Go to sleep').to_a).to eql(
|
69
74
|
[{ id: 2, user_id: 1, title: 'Go to sleep' }]
|
70
75
|
)
|
71
76
|
end
|
@@ -24,7 +24,7 @@ describe 'Plugin / Pagination' do
|
|
24
24
|
|
25
25
|
it 'preserves existing modifiers' do
|
26
26
|
expect(
|
27
|
-
rom.relation(:users)
|
27
|
+
rom.relation(:users).send(:where, name: 'User 2').page(1).to_a.size
|
28
28
|
).to be(1)
|
29
29
|
end
|
30
30
|
end
|
data/spec/unit/relation_spec.rb
CHANGED
@@ -38,9 +38,8 @@ describe ROM::Relation do
|
|
38
38
|
|
39
39
|
describe '#map' do
|
40
40
|
it 'yields tuples' do
|
41
|
-
result = []
|
42
|
-
|
43
|
-
expect(result).to eql([{ id: 1, name: 'Piotr' }])
|
41
|
+
result = users.map { |tuple| tuple[:name] }
|
42
|
+
expect(result).to eql(%w(Piotr))
|
44
43
|
end
|
45
44
|
end
|
46
45
|
|
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: 0.6.0.
|
4
|
+
version: 0.6.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Solnica
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-08-
|
11
|
+
date: 2015-08-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sequel
|
@@ -50,14 +50,14 @@ dependencies:
|
|
50
50
|
requirements:
|
51
51
|
- - "~>"
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: 0.9.0.
|
53
|
+
version: 0.9.0.rc1
|
54
54
|
type: :runtime
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
58
|
- - "~>"
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: 0.9.0.
|
60
|
+
version: 0.9.0.rc1
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
62
|
name: bundler
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -128,6 +128,8 @@ files:
|
|
128
128
|
- lib/rom/sql/relation/associations.rb
|
129
129
|
- lib/rom/sql/relation/class_methods.rb
|
130
130
|
- lib/rom/sql/relation/inspection.rb
|
131
|
+
- lib/rom/sql/relation/reading.rb
|
132
|
+
- lib/rom/sql/relation/writing.rb
|
131
133
|
- lib/rom/sql/spec/support.rb
|
132
134
|
- lib/rom/sql/support/active_support_notifications.rb
|
133
135
|
- lib/rom/sql/support/rails_log_subscriber.rb
|