arel_extensions 1.1.8 → 1.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +2 -0
- data/Gemfile +1 -1
- data/gemfiles/rails3.gemfile +12 -12
- data/gemfiles/rails4.gemfile +17 -17
- data/gemfiles/rails5_0.gemfile +17 -17
- data/gemfiles/rails5_1_4.gemfile +17 -17
- data/gemfiles/rails5_2.gemfile +17 -17
- data/lib/arel_extensions/boolean_functions.rb +30 -11
- data/lib/arel_extensions/math.rb +111 -112
- data/lib/arel_extensions/math_functions.rb +50 -31
- data/lib/arel_extensions/nodes/function.rb +25 -26
- data/lib/arel_extensions/nodes/json.rb +81 -0
- data/lib/arel_extensions/predications.rb +95 -97
- data/lib/arel_extensions/version.rb +1 -1
- data/lib/arel_extensions/visitors/mssql.rb +121 -108
- data/lib/arel_extensions/visitors/mysql.rb +230 -148
- data/lib/arel_extensions/visitors/oracle.rb +242 -232
- data/lib/arel_extensions/visitors/oracle12.rb +39 -1
- data/lib/arel_extensions/visitors/postgresql.rb +216 -134
- data/lib/arel_extensions/visitors/sqlite.rb +200 -189
- data/lib/arel_extensions/visitors/to_sql.rb +239 -171
- data/lib/arel_extensions/visitors.rb +63 -33
- data/lib/arel_extensions.rb +1 -0
- data/test/visitors/test_oracle.rb +1 -1
- data/test/visitors/test_to_sql.rb +206 -195
- data/test/with_ar/all_agnostic_test.rb +278 -235
- metadata +3 -2
@@ -1,6 +1,6 @@
|
|
1
1
|
module ArelExtensions
|
2
2
|
module Visitors
|
3
|
-
|
3
|
+
Arel::Visitors::MySQL.class_eval do
|
4
4
|
Arel::Visitors::MySQL::DATE_MAPPING = {'d' => 'DAY', 'm' => 'MONTH', 'w' => 'WEEK', 'y' => 'YEAR', 'wd' => 'WEEKDAY', 'h' => 'HOUR', 'mn' => 'MINUTE', 's' => 'SECOND'}
|
5
5
|
Arel::Visitors::MySQL::DATE_FORMAT_DIRECTIVES = { # ISO C / POSIX
|
6
6
|
'%Y' => '%Y', '%C' => '', '%y' => '%y', '%m' => '%m', '%B' => '%M', '%b' => '%b', '%^b' => '%b', # year, month
|
@@ -10,18 +10,18 @@ module ArelExtensions
|
|
10
10
|
}
|
11
11
|
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
13
|
+
#Math functions
|
14
|
+
def visit_ArelExtensions_Nodes_Log10 o, collector
|
15
|
+
collector << "LOG10("
|
16
|
+
o.expressions.each_with_index { |arg, i|
|
17
|
+
collector << Arel::Visitors::ToSql::COMMA unless i == 0
|
18
|
+
collector = visit arg, collector
|
19
|
+
}
|
20
|
+
collector << ")"
|
21
|
+
collector
|
22
|
+
end
|
23
|
+
|
24
|
+
def visit_ArelExtensions_Nodes_Power o, collector
|
25
25
|
collector << "POW("
|
26
26
|
o.expressions.each_with_index { |arg, i|
|
27
27
|
collector << Arel::Visitors::ToSql::COMMA unless i == 0
|
@@ -29,11 +29,11 @@ module ArelExtensions
|
|
29
29
|
}
|
30
30
|
collector << ")"
|
31
31
|
collector
|
32
|
-
|
32
|
+
end
|
33
33
|
|
34
34
|
#String functions
|
35
35
|
def visit_ArelExtensions_Nodes_IMatches o, collector # insensitive on ASCII
|
36
|
-
|
36
|
+
collector << 'LOWER('
|
37
37
|
collector = visit o.left, collector
|
38
38
|
collector << ') LIKE LOWER('
|
39
39
|
collector = visit o.right, collector
|
@@ -45,8 +45,8 @@ module ArelExtensions
|
|
45
45
|
collector
|
46
46
|
end
|
47
47
|
end
|
48
|
-
|
49
|
-
def visit_ArelExtensions_Nodes_AiMatches o, collector
|
48
|
+
|
49
|
+
def visit_ArelExtensions_Nodes_AiMatches o, collector
|
50
50
|
collector = visit o.left.ai_collate, collector
|
51
51
|
collector << ' LIKE '
|
52
52
|
collector = visit o.right.ai_collate, collector
|
@@ -57,8 +57,8 @@ module ArelExtensions
|
|
57
57
|
collector
|
58
58
|
end
|
59
59
|
end
|
60
|
-
|
61
|
-
def visit_ArelExtensions_Nodes_AiIMatches o, collector
|
60
|
+
|
61
|
+
def visit_ArelExtensions_Nodes_AiIMatches o, collector
|
62
62
|
collector = visit o.left.ai_collate, collector
|
63
63
|
collector << ' LIKE '
|
64
64
|
collector = visit o.right.ai_collate, collector
|
@@ -70,17 +70,17 @@ module ArelExtensions
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
73
|
+
def visit_ArelExtensions_Nodes_SMatches o, collector
|
74
|
+
collector = visit o.left.collate, collector
|
75
|
+
collector << ' LIKE '
|
76
|
+
collector = visit o.right.collate, collector
|
77
|
+
if o.escape
|
78
|
+
collector << ' ESCAPE '
|
79
|
+
visit o.escape, collector
|
80
|
+
else
|
81
|
+
collector
|
82
|
+
end
|
83
|
+
end
|
84
84
|
|
85
85
|
def visit_ArelExtensions_Nodes_IDoesNotMatch o, collector
|
86
86
|
collector << 'LOWER('
|
@@ -96,29 +96,29 @@ module ArelExtensions
|
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
99
|
+
def visit_ArelExtensions_Nodes_Collate o, collector
|
100
|
+
case o.expressions.first
|
101
|
+
when Arel::Attributes::Attribute
|
102
|
+
charset = case o.option
|
103
|
+
when 'latin1','utf8'
|
104
|
+
o.option
|
105
|
+
else
|
106
|
+
Arel::Table.engine.connection.charset || 'utf8'
|
107
|
+
end
|
108
|
+
else
|
109
|
+
charset = (o.option == 'latin1') ? 'latin1' : 'utf8'
|
110
|
+
end
|
111
|
+
collector = visit o.expressions.first, collector
|
112
|
+
if o.ai
|
113
|
+
collector << " COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : 'utf8_unicode_ci' }"
|
114
|
+
#doesn't work in latin1
|
115
|
+
elsif o.ci
|
116
|
+
collector << " COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : 'utf8_unicode_ci' }"
|
117
|
+
else
|
118
|
+
collector << " COLLATE #{charset}_bin"
|
119
|
+
end
|
120
|
+
collector
|
121
|
+
end
|
122
122
|
|
123
123
|
def visit_ArelExtensions_Nodes_Concat o, collector
|
124
124
|
collector << "CONCAT("
|
@@ -180,7 +180,7 @@ module ArelExtensions
|
|
180
180
|
collector << ")"
|
181
181
|
collector
|
182
182
|
end
|
183
|
-
|
183
|
+
|
184
184
|
def visit_ArelExtensions_Nodes_Repeat o, collector
|
185
185
|
collector << "REPEAT("
|
186
186
|
o.expressions.each_with_index { |arg, i|
|
@@ -262,17 +262,17 @@ module ArelExtensions
|
|
262
262
|
collector << ")"
|
263
263
|
collector
|
264
264
|
end
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
265
|
+
|
266
|
+
def visit_ArelExtensions_Nodes_IsNotNull o, collector
|
267
|
+
collector << "NOT ISNULL("
|
268
|
+
collector = visit o.left, collector
|
269
|
+
if o.right
|
270
|
+
collector << Arel::Visitors::MySQL::COMMA
|
271
|
+
collector = visit o.right, collector
|
272
|
+
end
|
273
|
+
collector << ")"
|
274
|
+
collector
|
275
|
+
end
|
276
276
|
|
277
277
|
def visit_ArelExtensions_Nodes_Wday o, collector
|
278
278
|
collector << "(WEEKDAY("
|
@@ -281,96 +281,178 @@ module ArelExtensions
|
|
281
281
|
collector
|
282
282
|
end
|
283
283
|
|
284
|
-
|
284
|
+
def visit_ArelExtensions_Nodes_Cast o, collector
|
285
285
|
collector << "CAST("
|
286
286
|
collector = visit o.left, collector
|
287
287
|
collector << " AS "
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
288
|
+
case o.as_attr
|
289
|
+
when :string
|
290
|
+
as_attr = Arel::Nodes::SqlLiteral.new('char')
|
291
|
+
when :time
|
292
|
+
as_attr = Arel::Nodes::SqlLiteral.new('time')
|
293
|
+
when :number
|
294
|
+
as_attr = Arel::Nodes::SqlLiteral.new('int')
|
295
|
+
when :datetime
|
296
|
+
as_attr = Arel::Nodes::SqlLiteral.new('datetime')
|
297
|
+
when :binary
|
298
|
+
as_attr = Arel::Nodes::SqlLiteral.new('binary')
|
299
|
+
else
|
300
|
+
as_attr = Arel::Nodes::SqlLiteral.new(o.as_attr.to_s)
|
301
|
+
end
|
302
302
|
collector = visit as_attr, collector
|
303
303
|
collector << ")"
|
304
304
|
collector
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
305
|
+
end
|
306
|
+
|
307
|
+
alias_method :old_visit_Arel_Nodes_SelectStatement, :visit_Arel_Nodes_SelectStatement
|
308
|
+
def visit_Arel_Nodes_SelectStatement o, collector
|
309
|
+
if !(collector.value.blank? || (collector.value.is_a?(Array) && collector.value[0].blank?)) && o.limit.blank? && o.offset.blank?
|
310
|
+
o = o.dup
|
311
|
+
o.orders = []
|
312
|
+
end
|
313
|
+
old_visit_Arel_Nodes_SelectStatement(o,collector)
|
314
|
+
end
|
315
|
+
|
316
|
+
alias_method :old_visit_Arel_Nodes_As, :visit_Arel_Nodes_As
|
317
|
+
def visit_Arel_Nodes_As o, collector
|
318
|
+
if o.left.is_a?(Arel::Nodes::Binary)
|
319
|
+
collector << '('
|
320
|
+
collector = visit o.left, collector
|
321
|
+
collector << ')'
|
322
|
+
else
|
323
|
+
collector = visit o.left, collector
|
324
|
+
end
|
325
|
+
collector << " AS `"
|
326
|
+
collector = visit o.right, collector
|
327
|
+
collector << "`"
|
328
|
+
collector
|
329
|
+
end
|
330
|
+
|
331
|
+
def visit_ArelExtensions_Nodes_FormattedNumber o, collector
|
332
|
+
col = o.left.coalesce(0)
|
333
|
+
params = o.locale ? [o.precision,Arel::Nodes.build_quoted(o.locale)] : [o.precision]
|
334
|
+
sign = ArelExtensions::Nodes::Case.new.when(col<0).
|
335
|
+
then('-').
|
336
|
+
else(o.flags.include?('+') ? '+' : (o.flags.include?(' ') ? ' ' : ''))
|
337
|
+
sign_length = ArelExtensions::Nodes::Length.new([sign])
|
338
|
+
|
339
|
+
if o.scientific_notation
|
340
|
+
number = ArelExtensions::Nodes::Concat.new([
|
341
|
+
Arel::Nodes::NamedFunction.new('FORMAT',[
|
342
|
+
col.abs/Arel::Nodes.build_quoted(10).pow(col.abs.log10.floor)
|
343
|
+
]+params),
|
344
|
+
o.type,
|
345
|
+
Arel::Nodes::NamedFunction.new('FORMAT',[
|
346
|
+
col.abs.log10.floor,
|
347
|
+
0
|
348
|
+
])
|
349
|
+
])
|
350
|
+
else
|
351
|
+
number = Arel::Nodes::NamedFunction.new('FORMAT',[col.abs]+params)
|
352
|
+
end
|
353
|
+
|
354
|
+
repeated_char = (o.width == 0) ? Arel::Nodes.build_quoted('') : ArelExtensions::Nodes::Case.new().
|
355
|
+
when(Arel::Nodes.build_quoted(o.width).abs-(number.length+sign_length)>0).
|
356
|
+
then(Arel::Nodes.build_quoted(
|
357
|
+
o.flags.include?('-') ? ' ' : (o.flags.include?('0') ? '0' : ' ')
|
358
|
+
).repeat(Arel::Nodes.build_quoted(o.width).abs-(number.length+sign_length))
|
359
|
+
).
|
360
|
+
else('')
|
361
|
+
before = (!o.flags.include?('0'))&&(!o.flags.include?('-')) ? repeated_char : ''
|
362
|
+
middle = (o.flags.include?('0'))&&(!o.flags.include?('-')) ? repeated_char : ''
|
363
|
+
after = o.flags.include?('-') ? repeated_char : ''
|
364
|
+
full_number = ArelExtensions::Nodes::Concat.new([
|
365
|
+
before,
|
366
|
+
sign,
|
367
|
+
middle,
|
368
|
+
number,
|
369
|
+
after
|
370
|
+
])
|
371
|
+
collector = visit ArelExtensions::Nodes::Concat.new([Arel::Nodes.build_quoted(o.prefix),full_number,Arel::Nodes.build_quoted(o.suffix)]), collector
|
372
|
+
collector
|
373
|
+
end
|
374
|
+
|
375
|
+
def visit_ArelExtensions_Nodes_Std o, collector
|
376
|
+
collector << (o.unbiased_estimator ? "STDDEV_SAMP(" : "STDDEV_POP(")
|
377
|
+
visit o.left, collector
|
378
|
+
collector << ")"
|
379
|
+
collector
|
380
|
+
end
|
373
381
|
|
382
|
+
def visit_ArelExtensions_Nodes_Variance o, collector
|
383
|
+
collector << (o.unbiased_estimator ? "VAR_SAMP(" : "VAR_POP(")
|
384
|
+
visit o.left, collector
|
385
|
+
collector << ")"
|
386
|
+
collector
|
387
|
+
end
|
388
|
+
|
389
|
+
def visit_ArelExtensions_Nodes_Json o,collector
|
390
|
+
case o.hash
|
391
|
+
when Array
|
392
|
+
collector << 'JSON_ARRAY('
|
393
|
+
o.hash.each.with_index do |v,i|
|
394
|
+
if i != 0
|
395
|
+
collector << Arel::Visitors::MySQL::COMMA
|
396
|
+
end
|
397
|
+
collector = visit v, collector
|
398
|
+
end
|
399
|
+
collector << ')'
|
400
|
+
when Hash
|
401
|
+
collector << 'JSON_OBJECT('
|
402
|
+
o.hash.each.with_index do |(k,v),i|
|
403
|
+
if i != 0
|
404
|
+
collector << Arel::Visitors::MySQL::COMMA
|
405
|
+
end
|
406
|
+
collector = visit k, collector
|
407
|
+
collector << Arel::Visitors::MySQL::COMMA
|
408
|
+
collector = visit v, collector
|
409
|
+
end
|
410
|
+
collector << ')'
|
411
|
+
else
|
412
|
+
collector = visit o.hash, collector
|
413
|
+
end
|
414
|
+
collector
|
415
|
+
end
|
416
|
+
|
417
|
+
def visit_ArelExtensions_Nodes_JsonMerge o,collector
|
418
|
+
collector << 'JSON_MERGE_PATCH('
|
419
|
+
o.expressions.each.with_index do |v,i|
|
420
|
+
if i != 0
|
421
|
+
collector << Arel::Visitors::MySQL::COMMA
|
422
|
+
end
|
423
|
+
collector = visit v, collector
|
424
|
+
end
|
425
|
+
collector << ')'
|
426
|
+
collector
|
427
|
+
end
|
428
|
+
|
429
|
+
def visit_ArelExtensions_Nodes_JsonGet o,collector
|
430
|
+
collector << 'JSON_EXTRACT('
|
431
|
+
collector = visit o.hash, collector
|
432
|
+
collector << Arel::Visitors::MySQL::COMMA
|
433
|
+
if o.key.is_a?(Integer)
|
434
|
+
collector << "\"$[#{o.key}]\""
|
435
|
+
else
|
436
|
+
collector = visit Arel::Nodes.build_quoted('$.')+o.key, collector
|
437
|
+
end
|
438
|
+
collector << ')'
|
439
|
+
collector
|
440
|
+
end
|
441
|
+
|
442
|
+
def visit_ArelExtensions_Nodes_JsonSet o,collector
|
443
|
+
collector << 'JSON_SET('
|
444
|
+
collector = visit o.hash, collector
|
445
|
+
collector << Arel::Visitors::MySQL::COMMA
|
446
|
+
if o.key.is_a?(Integer)
|
447
|
+
collector << "\"$[#{o.key}]\""
|
448
|
+
else
|
449
|
+
collector = visit Arel::Nodes.build_quoted('$.')+o.key, collector
|
450
|
+
end
|
451
|
+
collector << Arel::Visitors::MySQL::COMMA
|
452
|
+
collector = visit o.value, collector
|
453
|
+
collector << ')'
|
454
|
+
collector
|
455
|
+
end
|
374
456
|
|
375
457
|
end
|
376
458
|
end
|