rom-sql 0.6.0.beta1 → 0.6.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|