rom-sql 3.6.4 → 3.7.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/CHANGELOG.md +17 -0
- data/README.md +1 -2
- data/lib/rom/plugins/relation/sql/auto_restrictions.rb +4 -1
- data/lib/rom/plugins/relation/sql/instrumentation.rb +6 -2
- data/lib/rom/plugins/relation/sql/postgres/explain.rb +1 -1
- data/lib/rom/plugins/relation/sql/postgres/full_text_search.rb +31 -12
- data/lib/rom/plugins/relation/sql/postgres/streaming.rb +6 -6
- data/lib/rom/sql/associations/many_to_many.rb +6 -3
- data/lib/rom/sql/associations/many_to_one.rb +3 -0
- data/lib/rom/sql/attribute.rb +22 -8
- data/lib/rom/sql/attribute_aliasing.rb +7 -6
- data/lib/rom/sql/commands/create.rb +4 -3
- data/lib/rom/sql/commands/update.rb +4 -3
- data/lib/rom/sql/dsl.rb +3 -1
- data/lib/rom/sql/extensions/active_support_notifications.rb +1 -1
- data/lib/rom/sql/extensions/postgres/type_builder.rb +7 -7
- data/lib/rom/sql/extensions/postgres/type_serializer.rb +2 -2
- data/lib/rom/sql/extensions/postgres/types/geometric.rb +12 -12
- data/lib/rom/sql/extensions/postgres/types/json.rb +9 -3
- data/lib/rom/sql/extensions/postgres/types/ltree.rb +106 -36
- data/lib/rom/sql/extensions/postgres/types/range.rb +18 -18
- data/lib/rom/sql/extensions/rails_log_subscriber.rb +4 -4
- data/lib/rom/sql/function.rb +37 -18
- data/lib/rom/sql/gateway.rb +8 -7
- data/lib/rom/sql/group_dsl.rb +7 -2
- data/lib/rom/sql/migration/inline_runner.rb +8 -2
- data/lib/rom/sql/migration/migrator.rb +5 -5
- data/lib/rom/sql/migration/recorder.rb +10 -4
- data/lib/rom/sql/migration/runner.rb +5 -4
- data/lib/rom/sql/migration/schema_diff.rb +15 -10
- data/lib/rom/sql/migration/writer.rb +8 -8
- data/lib/rom/sql/migration.rb +5 -5
- data/lib/rom/sql/order_dsl.rb +6 -2
- data/lib/rom/sql/plugin/associates.rb +21 -7
- data/lib/rom/sql/plugin/pagination.rb +2 -2
- data/lib/rom/sql/projection_dsl.rb +1 -1
- data/lib/rom/sql/relation/reading.rb +83 -71
- data/lib/rom/sql/relation/writing.rb +19 -13
- data/lib/rom/sql/relation.rb +74 -28
- data/lib/rom/sql/restriction_dsl.rb +6 -2
- data/lib/rom/sql/schema/attributes_inferrer.rb +2 -2
- data/lib/rom/sql/schema/dsl.rb +2 -2
- data/lib/rom/sql/schema/index_dsl.rb +5 -6
- data/lib/rom/sql/schema/inferrer.rb +23 -19
- data/lib/rom/sql/schema/type_builder.rb +19 -3
- data/lib/rom/sql/schema.rb +10 -10
- data/lib/rom/sql/tasks/migration_tasks.rake +4 -5
- data/lib/rom/sql/transaction.rb +1 -0
- data/lib/rom/sql/type_dsl.rb +7 -3
- data/lib/rom/sql/type_extensions.rb +4 -4
- data/lib/rom/sql/type_serializer.rb +2 -2
- data/lib/rom/sql/types.rb +2 -2
- data/lib/rom/sql/version.rb +1 -1
- data/lib/rom/types/values.rb +2 -4
- metadata +10 -19
@@ -6,14 +6,14 @@ module ROM
|
|
6
6
|
module SQL
|
7
7
|
module Postgres
|
8
8
|
# @api public
|
9
|
+
#
|
10
|
+
# rubocop:disable Metrics/ModuleLength
|
9
11
|
module Types
|
10
12
|
# @see https://www.postgresql.org/docs/current/static/ltree.html
|
11
13
|
|
12
14
|
LTree = Type('ltree') do
|
13
15
|
SQL::Types.define(ROM::Types::Values::TreePath) do
|
14
|
-
input
|
15
|
-
label_path.to_s
|
16
|
-
end
|
16
|
+
input(&:to_s)
|
17
17
|
|
18
18
|
output do |label_path|
|
19
19
|
ROM::Types::Values::TreePath.new(label_path.to_s) if label_path
|
@@ -41,8 +41,12 @@ module ROM
|
|
41
41
|
# # Translates to the ? operator
|
42
42
|
# #
|
43
43
|
# # @example
|
44
|
-
# # people.select(:name).where {
|
45
|
-
# #
|
44
|
+
# # people.select(:name).where {
|
45
|
+
# # ltree_tags.match_any(['Bottom', 'Bottom.Cities.*'])
|
46
|
+
# # }
|
47
|
+
# # people.select(:name).where {
|
48
|
+
# # ltree_tags.match_any('Bottom,Bottom.Cities.*')
|
49
|
+
# # }
|
46
50
|
# #
|
47
51
|
# # @param [Array,String] value
|
48
52
|
# #
|
@@ -69,7 +73,9 @@ module ROM
|
|
69
73
|
# #
|
70
74
|
# # @example
|
71
75
|
# # people.select(:name).where { ltree_tags.contain_descendant(['Bottom.Cities']) }
|
72
|
-
# # people.select(:name).where {
|
76
|
+
# # people.select(:name).where {
|
77
|
+
# # ltree_tags.contain_descendant('Bottom.Cities, Bottom.Parks')
|
78
|
+
# # }
|
73
79
|
# #
|
74
80
|
# # @param [Array<String>, String] value
|
75
81
|
# #
|
@@ -96,7 +102,9 @@ module ROM
|
|
96
102
|
# #
|
97
103
|
# # @example
|
98
104
|
# # people.select(:name).where { ltree_tags.contain_ascendant(['Bottom.Cities']) }
|
99
|
-
# # people.select(:name).where {
|
105
|
+
# # people.select(:name).where {
|
106
|
+
# # ltree_tags.contain_ascendant('Bottom.Cities, Bottom.Parks')
|
107
|
+
# # }
|
100
108
|
# #
|
101
109
|
# # @param [Array<String>, String] value
|
102
110
|
# #
|
@@ -122,8 +130,12 @@ module ROM
|
|
122
130
|
# # Translates to ||
|
123
131
|
# #
|
124
132
|
# # @example
|
125
|
-
# # people.select {
|
126
|
-
# #
|
133
|
+
# # people.select {
|
134
|
+
# # (ltree_tags + ROM::Types::Values::TreePath.new('Moscu')).as(:ltree_tags)
|
135
|
+
# # }.where { name.is('Jade Doe') }
|
136
|
+
# # people.select {
|
137
|
+
# # (ltree_tags + 'Moscu').as(:ltree_tags)
|
138
|
+
# # }.where { name.is('Jade Doe') }
|
127
139
|
# #
|
128
140
|
# # @param [LTree, String] keys
|
129
141
|
# #
|
@@ -149,7 +161,9 @@ module ROM
|
|
149
161
|
# # Translates to @>
|
150
162
|
# #
|
151
163
|
# # @example
|
152
|
-
# # people.select(:name).where {
|
164
|
+
# # people.select(:name).where {
|
165
|
+
# # parents_tags.contain_ancestor('Top.Building.EmpireState.381')
|
166
|
+
# # }
|
153
167
|
# #
|
154
168
|
# # @param [String] value
|
155
169
|
# #
|
@@ -162,7 +176,9 @@ module ROM
|
|
162
176
|
# # Translates to <@
|
163
177
|
# #
|
164
178
|
# # @example
|
165
|
-
# # people.select(:name).where {
|
179
|
+
# # people.select(:name).where {
|
180
|
+
# # parents_tags.contain_descendant('Top.Building.EmpireState.381')
|
181
|
+
# # }
|
166
182
|
# #
|
167
183
|
# # @param [String] value
|
168
184
|
# #
|
@@ -175,7 +191,9 @@ module ROM
|
|
175
191
|
# # Translates to ?@>
|
176
192
|
# #
|
177
193
|
# # @example
|
178
|
-
# # people.select(:name).where {
|
194
|
+
# # people.select(:name).where {
|
195
|
+
# # parents_tags.find_ancestor('Left.Parks').not(nil)
|
196
|
+
# # }
|
179
197
|
# #
|
180
198
|
# # @param [String] value
|
181
199
|
# #
|
@@ -188,7 +206,9 @@ module ROM
|
|
188
206
|
# # Translates to ?<@
|
189
207
|
# #
|
190
208
|
# # @example
|
191
|
-
# # people.select(:name).where {
|
209
|
+
# # people.select(:name).where {
|
210
|
+
# # parents_tags.find_descendant('Left.Parks').not(nil)
|
211
|
+
# # }
|
192
212
|
# #
|
193
213
|
# # @param [String] value
|
194
214
|
# #
|
@@ -201,7 +221,9 @@ module ROM
|
|
201
221
|
# # Translates to ?~
|
202
222
|
# #
|
203
223
|
# # @example
|
204
|
-
# # people.select(:name).where {
|
224
|
+
# # people.select(:name).where {
|
225
|
+
# # parents_tags.match_any_lquery('Right.*').not(nil)
|
226
|
+
# # }
|
205
227
|
# #
|
206
228
|
# # @param [String] value
|
207
229
|
# #
|
@@ -214,7 +236,9 @@ module ROM
|
|
214
236
|
# # Translates to ?@
|
215
237
|
# #
|
216
238
|
# # @example
|
217
|
-
# # people.select(:name).where {
|
239
|
+
# # people.select(:name).where {
|
240
|
+
# # parents_tags.match_any_ltextquery('EmpireState').not(nil)
|
241
|
+
# # }
|
218
242
|
# #
|
219
243
|
# # @param [String] value
|
220
244
|
# #
|
@@ -234,12 +258,16 @@ module ROM
|
|
234
258
|
MATCH_ANY_LTEXTQUERY = ['(', ' ?@ ', ')'].freeze
|
235
259
|
|
236
260
|
def match(_type, expr, query)
|
237
|
-
Attribute[SQL::Types::Bool].meta(
|
261
|
+
Attribute[SQL::Types::Bool].meta(
|
262
|
+
sql_expr: ::Sequel::SQL::BooleanExpression.new(:~, expr, query)
|
263
|
+
)
|
238
264
|
end
|
239
265
|
|
240
266
|
def match_any(_type, expr, query)
|
241
267
|
array = build_array_query(query)
|
242
|
-
Attribute[SQL::Types::Bool].meta(
|
268
|
+
Attribute[SQL::Types::Bool].meta(
|
269
|
+
sql_expr: custom_operator_expr(MATCH_ANY, expr, array)
|
270
|
+
)
|
243
271
|
end
|
244
272
|
|
245
273
|
private
|
@@ -262,31 +290,57 @@ module ROM
|
|
262
290
|
include LTreeMethods
|
263
291
|
|
264
292
|
def contain_any_ltextquery(_type, expr, query)
|
265
|
-
Attribute[SQL::Types::Bool].meta(
|
293
|
+
Attribute[SQL::Types::Bool].meta(
|
294
|
+
sql_expr: custom_operator_expr(
|
295
|
+
LTreeMethods::MATCH_LTEXTQUERY, expr, query
|
296
|
+
)
|
297
|
+
)
|
266
298
|
end
|
267
299
|
|
268
300
|
def contain_ancestor(_type, expr, query)
|
269
|
-
Attribute[SQL::Types::Bool].meta(
|
301
|
+
Attribute[SQL::Types::Bool].meta(
|
302
|
+
sql_expr: custom_operator_expr(
|
303
|
+
LTreeMethods::ASCENDANT, expr, query
|
304
|
+
)
|
305
|
+
)
|
270
306
|
end
|
271
307
|
|
272
308
|
def contain_descendant(_type, expr, query)
|
273
|
-
Attribute[SQL::Types::Bool].meta(
|
309
|
+
Attribute[SQL::Types::Bool].meta(
|
310
|
+
sql_expr: custom_operator_expr(
|
311
|
+
LTreeMethods::DESCENDANT, expr, query
|
312
|
+
)
|
313
|
+
)
|
274
314
|
end
|
275
315
|
|
276
316
|
def find_ancestor(_type, expr, query)
|
277
|
-
Attribute[LTree].meta(
|
317
|
+
Attribute[LTree].meta(
|
318
|
+
sql_expr: custom_operator_expr(
|
319
|
+
LTreeMethods::FIND_ASCENDANT, expr, query
|
320
|
+
)
|
321
|
+
)
|
278
322
|
end
|
279
323
|
|
280
324
|
def find_descendant(_type, expr, query)
|
281
|
-
Attribute[LTree].meta(
|
325
|
+
Attribute[LTree].meta(
|
326
|
+
sql_expr: custom_operator_expr(
|
327
|
+
LTreeMethods::FIND_DESCENDANT, expr, query
|
328
|
+
)
|
329
|
+
)
|
282
330
|
end
|
283
331
|
|
284
332
|
def match_any_lquery(_type, expr, query)
|
285
|
-
Attribute[LTree].meta(
|
333
|
+
Attribute[LTree].meta(
|
334
|
+
sql_expr: custom_operator_expr(
|
335
|
+
LTreeMethods::MATCH_ANY_LQUERY, expr, query
|
336
|
+
)
|
337
|
+
)
|
286
338
|
end
|
287
339
|
|
288
340
|
def match_any_ltextquery(_type, expr, query)
|
289
|
-
Attribute[LTree].meta(sql_expr: custom_operator_expr(
|
341
|
+
Attribute[LTree].meta(sql_expr: custom_operator_expr(
|
342
|
+
LTreeMethods::MATCH_ANY_LTEXTQUERY, expr, query
|
343
|
+
))
|
290
344
|
end
|
291
345
|
end
|
292
346
|
|
@@ -294,38 +348,54 @@ module ROM
|
|
294
348
|
include LTreeMethods
|
295
349
|
|
296
350
|
def match_ltextquery(_type, expr, query)
|
297
|
-
Attribute[SQL::Types::Bool].meta(sql_expr: custom_operator_expr(
|
351
|
+
Attribute[SQL::Types::Bool].meta(sql_expr: custom_operator_expr(
|
352
|
+
LTreeMethods::MATCH_LTEXTQUERY, expr, query
|
353
|
+
))
|
298
354
|
end
|
299
355
|
|
300
356
|
def contain_descendant(_type, expr, query)
|
301
357
|
array = build_array_query(query, 'ltree')
|
302
|
-
Attribute[SQL::Types::Bool].meta(sql_expr: custom_operator_expr(
|
358
|
+
Attribute[SQL::Types::Bool].meta(sql_expr: custom_operator_expr(
|
359
|
+
LTreeMethods::DESCENDANT, expr, array
|
360
|
+
))
|
303
361
|
end
|
304
362
|
|
305
363
|
def descendant(_type, expr, query)
|
306
|
-
Attribute[SQL::Types::Bool].meta(sql_expr: custom_operator_expr(
|
364
|
+
Attribute[SQL::Types::Bool].meta(sql_expr: custom_operator_expr(
|
365
|
+
LTreeMethods::DESCENDANT, expr, query
|
366
|
+
))
|
307
367
|
end
|
308
368
|
|
309
369
|
def contain_ascendant(_type, expr, query)
|
310
370
|
array = build_array_query(query, 'ltree')
|
311
|
-
Attribute[SQL::Types::Bool].meta(sql_expr: custom_operator_expr(
|
371
|
+
Attribute[SQL::Types::Bool].meta(sql_expr: custom_operator_expr(
|
372
|
+
LTreeMethods::ASCENDANT, expr, array
|
373
|
+
))
|
312
374
|
end
|
313
375
|
|
314
376
|
def ascendant(_type, expr, query)
|
315
|
-
Attribute[SQL::Types::Bool].meta(sql_expr: custom_operator_expr(
|
377
|
+
Attribute[SQL::Types::Bool].meta(sql_expr: custom_operator_expr(
|
378
|
+
LTreeMethods::ASCENDANT, expr, query
|
379
|
+
))
|
316
380
|
end
|
317
381
|
|
318
382
|
def +(_type, expr, other)
|
319
|
-
other_value =
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
383
|
+
other_value =
|
384
|
+
case other
|
385
|
+
when ::ROM::Types::Values::TreePath
|
386
|
+
other
|
387
|
+
else
|
388
|
+
::ROM::Types::Values::TreePath.new(other)
|
389
|
+
end
|
390
|
+
Attribute[LTree].meta(
|
391
|
+
sql_expr: ::Sequel::SQL::StringExpression.new(
|
392
|
+
:'||', expr, other_value.to_s
|
393
|
+
)
|
394
|
+
)
|
326
395
|
end
|
327
396
|
end
|
328
397
|
end
|
329
398
|
end
|
399
|
+
# rubocop:enable Metrics/ModuleLength
|
330
400
|
end
|
331
401
|
end
|
@@ -9,19 +9,16 @@ module ROM
|
|
9
9
|
module Postgres
|
10
10
|
module Values
|
11
11
|
Range = ::Struct.new(:lower, :upper, :bounds) do
|
12
|
-
PAREN_LEFT = '('.freeze
|
13
|
-
PAREN_RIGHT = ')'.freeze
|
14
|
-
|
15
12
|
def initialize(lower, upper, bounds = :'[)')
|
16
13
|
super
|
17
14
|
end
|
18
15
|
|
19
16
|
def exclude_begin?
|
20
|
-
bounds[0] ==
|
17
|
+
bounds[0] == '('
|
21
18
|
end
|
22
19
|
|
23
20
|
def exclude_end?
|
24
|
-
bounds[1] ==
|
21
|
+
bounds[1] == ')'
|
25
22
|
end
|
26
23
|
end
|
27
24
|
end
|
@@ -38,10 +35,10 @@ module ROM
|
|
38
35
|
int8range: Sequel::Postgres::PGRange::Parser.new(
|
39
36
|
'int8range', SQL::Types::Coercible::Integer
|
40
37
|
),
|
41
|
-
numrange:
|
38
|
+
numrange: Sequel::Postgres::PGRange::Parser.new(
|
42
39
|
'numrange', SQL::Types::Coercible::Integer
|
43
40
|
),
|
44
|
-
tsrange:
|
41
|
+
tsrange: Sequel::Postgres::PGRange::Parser.new(
|
45
42
|
'tsrange', ::Time.method(:parse)
|
46
43
|
),
|
47
44
|
tstzrange: Sequel::Postgres::PGRange::Parser.new(
|
@@ -56,20 +53,21 @@ module ROM
|
|
56
53
|
def self.range_read_type(name)
|
57
54
|
SQL::Types.Constructor(Values::Range) do |value|
|
58
55
|
pg_range =
|
59
|
-
if value.is_a?(Sequel::Postgres::PGRange)
|
56
|
+
if value.is_a?(::Sequel::Postgres::PGRange)
|
60
57
|
value
|
61
|
-
elsif value && value.respond_to?(:to_s)
|
58
|
+
elsif value && value.respond_to?(:to_s) # rubocop:disable Style/SafeNavigation
|
62
59
|
@range_parsers[name].(value.to_s)
|
63
|
-
else
|
60
|
+
else # rubocop:disable Lint/DuplicateBranch
|
64
61
|
value
|
65
62
|
end
|
66
63
|
|
67
64
|
Values::Range.new(
|
68
65
|
pg_range.begin,
|
69
66
|
pg_range.end,
|
70
|
-
[
|
71
|
-
|
72
|
-
|
67
|
+
[
|
68
|
+
pg_range.exclude_begin? ? :'(' : :'[',
|
69
|
+
pg_range.exclude_end? ? :')' : :']'
|
70
|
+
].join.to_sym
|
73
71
|
)
|
74
72
|
end
|
75
73
|
end
|
@@ -78,11 +76,13 @@ module ROM
|
|
78
76
|
def self.range(name, read_type)
|
79
77
|
Type(name) do
|
80
78
|
type = SQL::Types.Nominal(Values::Range).constructor do |range|
|
81
|
-
format(
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
79
|
+
format(
|
80
|
+
'%<begin>s%<lower>s,%<upper>s%<end>s',
|
81
|
+
begin: range.exclude_begin? ? :'(' : :'[',
|
82
|
+
lower: range.lower,
|
83
|
+
upper: range.upper,
|
84
|
+
end: range.exclude_end? ? :')' : :']'
|
85
|
+
)
|
86
86
|
end
|
87
87
|
|
88
88
|
type.meta(read: read_type)
|
@@ -7,15 +7,15 @@ module ROM
|
|
7
7
|
class RailsLogSubscriber < ActiveSupport::LogSubscriber
|
8
8
|
as_version =
|
9
9
|
begin
|
10
|
-
require
|
10
|
+
require 'active_support/gem_version'
|
11
11
|
ActiveSupport.gem_version
|
12
12
|
rescue LoadError
|
13
13
|
nil
|
14
14
|
end
|
15
15
|
|
16
16
|
COLOR_OPTION =
|
17
|
-
if as_version && as_version >= Gem::Version.new(
|
18
|
-
{color: true}
|
17
|
+
if as_version && as_version >= ::Gem::Version.new('7.2')
|
18
|
+
{ color: true }
|
19
19
|
else
|
20
20
|
true
|
21
21
|
end
|
@@ -25,7 +25,7 @@ module ROM
|
|
25
25
|
|
26
26
|
payload = event.payload
|
27
27
|
|
28
|
-
name = format('
|
28
|
+
name = format('%<name>s (%<duration>.1fms)', name: payload[:name], duration: event.duration)
|
29
29
|
sql = payload[:sql].squeeze(' ')
|
30
30
|
binds = payload[:binds].to_a.inspect if payload[:binds]
|
31
31
|
|
data/lib/rom/sql/function.rb
CHANGED
@@ -19,10 +19,10 @@ module ROM
|
|
19
19
|
when :start then 'UNBOUNDED PRECEDING'
|
20
20
|
when :end then 'UNBOUNDED FOLLOWING'
|
21
21
|
else
|
22
|
-
if value
|
23
|
-
"#{
|
22
|
+
if value.positive?
|
23
|
+
"#{value} FOLLOWING"
|
24
24
|
else
|
25
|
-
"#{
|
25
|
+
"#{value.abs} PRECEDING"
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
@@ -34,13 +34,14 @@ module ROM
|
|
34
34
|
WINDOW_FRAMES = Hash.new do |cache, frame|
|
35
35
|
type = frame.key?(:rows) ? 'ROWS' : 'RANGE'
|
36
36
|
bounds = frame[:rows] || frame[:range]
|
37
|
-
cache[frame] =
|
37
|
+
cache[frame] =
|
38
|
+
"#{type} BETWEEN #{frame_limit(bounds[0])} AND #{frame_limit(bounds[1])}"
|
38
39
|
end
|
39
40
|
|
40
41
|
WINDOW_FRAMES[nil] = nil
|
41
|
-
WINDOW_FRAMES[:all] = WINDOW_FRAMES[rows: [
|
42
|
-
WINDOW_FRAMES[:rows] = WINDOW_FRAMES[rows: [
|
43
|
-
WINDOW_FRAMES[range: :current] = WINDOW_FRAMES[range: [
|
42
|
+
WINDOW_FRAMES[:all] = WINDOW_FRAMES[rows: %i[start end]]
|
43
|
+
WINDOW_FRAMES[:rows] = WINDOW_FRAMES[rows: %i[start current]]
|
44
|
+
WINDOW_FRAMES[{ range: :current }] = WINDOW_FRAMES[range: %i[current current]]
|
44
45
|
|
45
46
|
# Return a new attribute with an alias
|
46
47
|
#
|
@@ -88,10 +89,10 @@ module ROM
|
|
88
89
|
end
|
89
90
|
|
90
91
|
# @api private
|
91
|
-
def new(&
|
92
|
+
def new(&)
|
92
93
|
case func
|
93
94
|
when ::Sequel::SQL::Function
|
94
|
-
meta(func: ::Sequel::SQL::Function.new!(func.name, func.args.map(&
|
95
|
+
meta(func: ::Sequel::SQL::Function.new!(func.name, func.args.map(&), func.opts))
|
95
96
|
else
|
96
97
|
meta(func: func)
|
97
98
|
end
|
@@ -125,7 +126,15 @@ module ROM
|
|
125
126
|
#
|
126
127
|
# @example
|
127
128
|
# users.select { [id, integer::row_number().over(partition: name, order: id).as(:row_no)] }
|
128
|
-
# users.select {
|
129
|
+
# users.select {
|
130
|
+
# [
|
131
|
+
# id,
|
132
|
+
# integer::row_number().over(
|
133
|
+
# partition: [first_name, last_name],
|
134
|
+
# order: id
|
135
|
+
# ).as(:row_no)
|
136
|
+
# ]
|
137
|
+
# }
|
129
138
|
#
|
130
139
|
# @example frame variants
|
131
140
|
# # ROWS BETWEEN 3 PRECEDING AND CURRENT ROW
|
@@ -167,7 +176,8 @@ module ROM
|
|
167
176
|
# users.select { bool::cast(json_data.get_text('activated')).as(:activated) }
|
168
177
|
#
|
169
178
|
# @param [ROM::SQL::Attribute] expr Expression to be cast
|
170
|
-
# @param [String] db_type
|
179
|
+
# @param [String] db_type
|
180
|
+
# Target database type (usually can be inferred from the target data type)
|
171
181
|
#
|
172
182
|
# @return [ROM::SQL::Attribute]
|
173
183
|
#
|
@@ -211,10 +221,10 @@ module ROM
|
|
211
221
|
# @return [SQL::Function]
|
212
222
|
#
|
213
223
|
# @api public
|
214
|
-
def filter(condition = Undefined, &
|
215
|
-
if
|
216
|
-
conditions = schema.restriction(&
|
217
|
-
conditions
|
224
|
+
def filter(condition = Undefined, &)
|
225
|
+
if block_given?
|
226
|
+
conditions = schema.restriction(&)
|
227
|
+
conditions &= condition unless condition.equal?(Undefined)
|
218
228
|
else
|
219
229
|
conditions = condition
|
220
230
|
end
|
@@ -236,9 +246,9 @@ module ROM
|
|
236
246
|
# @return [SQL::Function]
|
237
247
|
#
|
238
248
|
# @api public
|
239
|
-
def within_group(*args, &
|
240
|
-
if
|
241
|
-
group = args + ::ROM::SQL::OrderDSL.new(schema).(&
|
249
|
+
def within_group(*args, &)
|
250
|
+
if block_given?
|
251
|
+
group = args + ::ROM::SQL::OrderDSL.new(schema).(&)
|
242
252
|
else
|
243
253
|
group = args
|
244
254
|
end
|
@@ -258,6 +268,15 @@ module ROM
|
|
258
268
|
meta[:func]
|
259
269
|
end
|
260
270
|
|
271
|
+
# @api private
|
272
|
+
def respond_to_missing?(meth, _include_private = false)
|
273
|
+
if func
|
274
|
+
func.respond_to?(meth) || super
|
275
|
+
else
|
276
|
+
true
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
261
280
|
# @api private
|
262
281
|
def method_missing(meth, *args)
|
263
282
|
if func
|
data/lib/rom/sql/gateway.rb
CHANGED
@@ -75,13 +75,14 @@ module ROM
|
|
75
75
|
#
|
76
76
|
# @return [SQL::Gateway]
|
77
77
|
#
|
78
|
-
# @see https://github.com/jeremyevans/sequel/blob/master/doc/opening_databases.rdoc
|
78
|
+
# @see https://github.com/jeremyevans/sequel/blob/master/doc/opening_databases.rdoc
|
79
|
+
# Sequel connection docs
|
79
80
|
#
|
80
81
|
# @api public
|
81
82
|
def initialize(uri, options = EMPTY_HASH)
|
82
83
|
@connection = connect(uri, options)
|
83
84
|
load_extensions(Array(options[:extensions]))
|
84
|
-
Notifications.trigger(
|
85
|
+
Notifications.trigger('configuration.gateway.connected', connection: @connection)
|
85
86
|
|
86
87
|
@options = options
|
87
88
|
|
@@ -152,15 +153,15 @@ module ROM
|
|
152
153
|
# Create a table using the configured connection
|
153
154
|
#
|
154
155
|
# @api public
|
155
|
-
def create_table(
|
156
|
-
connection.create_table(
|
156
|
+
def create_table(...)
|
157
|
+
connection.create_table(...)
|
157
158
|
end
|
158
159
|
|
159
160
|
# Drops a table
|
160
161
|
#
|
161
162
|
# @api public
|
162
|
-
def drop_table(
|
163
|
-
connection.drop_table(
|
163
|
+
def drop_table(...)
|
164
|
+
connection.drop_table(...)
|
164
165
|
end
|
165
166
|
|
166
167
|
# Returns a list of datasets inferred from table names
|
@@ -249,5 +250,5 @@ module ROM
|
|
249
250
|
end
|
250
251
|
end
|
251
252
|
|
252
|
-
Configuration.register_event(
|
253
|
+
Configuration.register_event('configuration.gateway.connected')
|
253
254
|
end
|
data/lib/rom/sql/group_dsl.rb
CHANGED
@@ -9,11 +9,16 @@ module ROM
|
|
9
9
|
private
|
10
10
|
|
11
11
|
# @api private
|
12
|
-
def
|
12
|
+
def respond_to_missing?(_meth, _include_private = false)
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
# @api private
|
17
|
+
def method_missing(meth, ...)
|
13
18
|
if schema.key?(meth)
|
14
19
|
schema[meth].canonical
|
15
20
|
else
|
16
|
-
::Sequel::VIRTUAL_ROW.__send__(meth.to_s,
|
21
|
+
::Sequel::VIRTUAL_ROW.__send__(meth.to_s, ...)
|
17
22
|
end
|
18
23
|
end
|
19
24
|
end
|
@@ -13,8 +13,14 @@ module ROM
|
|
13
13
|
yield(connection)
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
16
|
+
private
|
17
|
+
|
18
|
+
def method_missing(m, ...)
|
19
|
+
connection.public_send(m, ...)
|
20
|
+
end
|
21
|
+
|
22
|
+
def respond_to_missing?(meth, include_private = false)
|
23
|
+
connection.respond_to?(meth, include_private)
|
18
24
|
end
|
19
25
|
end
|
20
26
|
end
|
@@ -16,8 +16,8 @@ module ROM
|
|
16
16
|
class Migrator
|
17
17
|
extend Initializer
|
18
18
|
|
19
|
-
DEFAULT_PATH = 'db/migrate'
|
20
|
-
VERSION_FORMAT = '%Y%m%d%H%M%S'
|
19
|
+
DEFAULT_PATH = 'db/migrate'
|
20
|
+
VERSION_FORMAT = '%Y%m%d%H%M%S'
|
21
21
|
DEFAULT_INFERRER = Schema::Inferrer.new.suppress_errors.freeze
|
22
22
|
|
23
23
|
param :connection
|
@@ -37,14 +37,14 @@ module ROM
|
|
37
37
|
end
|
38
38
|
|
39
39
|
# @api private
|
40
|
-
def migration(&
|
41
|
-
Sequel.migration(&
|
40
|
+
def migration(&)
|
41
|
+
Sequel.migration(&)
|
42
42
|
end
|
43
43
|
|
44
44
|
# @api private
|
45
45
|
def create_file(name, version = generate_version, **options)
|
46
46
|
sequence = options[:sequence] ? '%03d' % options[:sequence] : nil
|
47
|
-
filename = "#{
|
47
|
+
filename = "#{version}#{sequence}_#{name}.rb"
|
48
48
|
content = options[:content] || migration_file_content
|
49
49
|
path = options[:path] || self.path
|
50
50
|
dirname = Pathname(path)
|
@@ -7,14 +7,20 @@ module ROM
|
|
7
7
|
class Recorder
|
8
8
|
attr_reader :operations
|
9
9
|
|
10
|
-
def initialize(&
|
10
|
+
def initialize(&)
|
11
11
|
@operations = []
|
12
12
|
|
13
|
-
instance_exec(&
|
13
|
+
instance_exec(&) if block_given?
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
16
|
+
private
|
17
|
+
|
18
|
+
def respond_to_missing?(_m, _include_private = false)
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
def method_missing(m, *args, &)
|
23
|
+
nested = block_given? ? Recorder.new(&).operations : EMPTY_ARRAY
|
18
24
|
@operations << [m, args, nested]
|
19
25
|
end
|
20
26
|
end
|