rom-sql 3.6.5 → 3.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -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 +5 -2
- 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 +9 -15
@@ -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
|