arel_extensions 1.2.2 → 1.2.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rubocop.yml +7 -4
- data/.travis.yml +59 -91
- data/Gemfile +2 -2
- data/README.md +17 -12
- data/Rakefile +38 -27
- data/appveyor.yml +1 -1
- data/arel_extensions.gemspec +1 -1
- data/functions.html +3 -3
- data/gemfiles/rails4.gemfile +1 -1
- data/gemfiles/rails6.gemfile +30 -0
- data/gemspec_v2/arel_extensions-v2.gemspec +28 -0
- data/generate_gems.sh +14 -0
- data/init/mssql.sql +4 -4
- data/init/mysql.sql +38 -38
- data/init/postgresql.sql +21 -21
- data/lib/arel_extensions.rb +63 -19
- data/lib/arel_extensions/attributes.rb +0 -1
- data/lib/arel_extensions/boolean_functions.rb +38 -13
- data/lib/arel_extensions/common_sql_functions.rb +5 -4
- data/lib/arel_extensions/comparators.rb +4 -2
- data/lib/arel_extensions/insert_manager.rb +26 -24
- data/lib/arel_extensions/math.rb +3 -3
- data/lib/arel_extensions/math_functions.rb +10 -5
- data/lib/arel_extensions/nodes.rb +1 -1
- data/lib/arel_extensions/nodes/abs.rb +0 -0
- data/lib/arel_extensions/nodes/aggregate_function.rb +14 -0
- data/lib/arel_extensions/nodes/blank.rb +14 -11
- data/lib/arel_extensions/nodes/case.rb +8 -4
- data/lib/arel_extensions/nodes/ceil.rb +0 -0
- data/lib/arel_extensions/nodes/change_case.rb +2 -2
- data/lib/arel_extensions/nodes/coalesce.rb +2 -2
- data/lib/arel_extensions/nodes/collate.rb +12 -12
- data/lib/arel_extensions/nodes/concat.rb +6 -13
- data/lib/arel_extensions/nodes/date_diff.rb +3 -5
- data/lib/arel_extensions/nodes/duration.rb +0 -2
- data/lib/arel_extensions/nodes/find_in_set.rb +0 -0
- data/lib/arel_extensions/nodes/floor.rb +0 -0
- data/lib/arel_extensions/nodes/format.rb +8 -8
- data/lib/arel_extensions/nodes/formatted_number.rb +23 -23
- data/lib/arel_extensions/nodes/function.rb +10 -0
- data/lib/arel_extensions/nodes/is_null.rb +10 -8
- data/lib/arel_extensions/nodes/json.rb +28 -30
- data/lib/arel_extensions/nodes/length.rb +0 -0
- data/lib/arel_extensions/nodes/levenshtein_distance.rb +5 -5
- data/lib/arel_extensions/nodes/locate.rb +7 -7
- data/lib/arel_extensions/nodes/matches.rb +4 -4
- data/lib/arel_extensions/nodes/power.rb +6 -5
- data/lib/arel_extensions/nodes/rand.rb +0 -0
- data/lib/arel_extensions/nodes/repeat.rb +2 -2
- data/lib/arel_extensions/nodes/replace.rb +24 -6
- data/lib/arel_extensions/nodes/round.rb +5 -5
- data/lib/arel_extensions/nodes/soundex.rb +16 -15
- data/lib/arel_extensions/nodes/std.rb +19 -21
- data/lib/arel_extensions/nodes/substring.rb +8 -15
- data/lib/arel_extensions/nodes/sum.rb +7 -0
- data/lib/arel_extensions/nodes/trim.rb +3 -3
- data/lib/arel_extensions/nodes/union.rb +2 -3
- data/lib/arel_extensions/nodes/union_all.rb +1 -2
- data/lib/arel_extensions/nodes/wday.rb +0 -0
- data/lib/arel_extensions/null_functions.rb +2 -2
- data/lib/arel_extensions/predications.rb +35 -33
- data/lib/arel_extensions/set_functions.rb +16 -16
- data/lib/arel_extensions/string_functions.rb +34 -12
- data/lib/arel_extensions/tasks.rb +5 -5
- data/lib/arel_extensions/version.rb +1 -1
- data/lib/arel_extensions/visitors.rb +1 -1
- data/lib/arel_extensions/visitors/ibm_db.rb +1 -1
- data/lib/arel_extensions/visitors/mssql.rb +18 -17
- data/lib/arel_extensions/visitors/mysql.rb +92 -46
- data/lib/arel_extensions/visitors/oracle.rb +40 -28
- data/lib/arel_extensions/visitors/oracle12.rb +1 -1
- data/lib/arel_extensions/visitors/postgresql.rb +80 -34
- data/lib/arel_extensions/visitors/sqlite.rb +54 -46
- data/lib/arel_extensions/visitors/to_sql.rb +75 -62
- data/test/arelx_test_helper.rb +28 -0
- data/test/real_db_test.rb +1 -1
- data/test/support/fake_record.rb +4 -0
- data/test/test_comparators.rb +9 -8
- data/test/visitors/test_bulk_insert_oracle.rb +8 -7
- data/test/visitors/test_bulk_insert_sqlite.rb +9 -8
- data/test/visitors/test_bulk_insert_to_sql.rb +8 -10
- data/test/visitors/test_oracle.rb +41 -40
- data/test/visitors/test_to_sql.rb +367 -193
- data/test/with_ar/all_agnostic_test.rb +85 -39
- data/test/with_ar/insert_agnostic_test.rb +3 -2
- data/test/with_ar/test_bulk_sqlite.rb +6 -5
- data/test/with_ar/test_math_sqlite.rb +4 -4
- data/test/with_ar/test_string_mysql.rb +4 -6
- data/test/with_ar/test_string_sqlite.rb +3 -7
- data/version_v1.rb +3 -0
- data/version_v2.rb +3 -0
- metadata +13 -7
- data/test/helper.rb +0 -18
@@ -1,6 +1,6 @@
|
|
1
1
|
module ArelExtensions
|
2
2
|
module Visitors
|
3
|
-
Arel::Visitors::MySQL
|
3
|
+
class Arel::Visitors::MySQL
|
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
|
@@ -97,26 +97,28 @@ module ArelExtensions
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def visit_ArelExtensions_Nodes_Collate o, collector
|
100
|
-
|
101
|
-
|
102
|
-
|
100
|
+
charset =
|
101
|
+
case o.expressions.first
|
102
|
+
when Arel::Attributes::Attribute
|
103
|
+
case o.option
|
103
104
|
when 'latin1','utf8'
|
104
105
|
o.option
|
105
106
|
else
|
106
107
|
Arel::Table.engine.connection.charset || 'utf8'
|
107
108
|
end
|
108
|
-
|
109
|
-
|
110
|
-
|
109
|
+
else
|
110
|
+
(o.option == 'latin1') ? 'latin1' : 'utf8'
|
111
|
+
end
|
111
112
|
collector = visit o.expressions.first, collector
|
112
|
-
|
113
|
-
|
113
|
+
collector <<
|
114
|
+
if o.ai
|
115
|
+
" COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : 'utf8_unicode_ci' }"
|
114
116
|
#doesn't work in latin1
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
117
|
+
elsif o.ci
|
118
|
+
" COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : 'utf8_unicode_ci' }"
|
119
|
+
else
|
120
|
+
" COLLATE #{charset}_bin"
|
121
|
+
end
|
120
122
|
collector
|
121
123
|
end
|
122
124
|
|
@@ -139,16 +141,16 @@ module ArelExtensions
|
|
139
141
|
def visit_ArelExtensions_Nodes_GroupConcat o, collector
|
140
142
|
collector << "GROUP_CONCAT("
|
141
143
|
collector = visit o.left, collector
|
142
|
-
if !o.
|
144
|
+
if !o.order.blank?
|
143
145
|
collector << ' ORDER BY '
|
144
|
-
o.
|
146
|
+
o.order.each_with_index do |order,i|
|
145
147
|
collector << Arel::Visitors::ToSql::COMMA unless i == 0
|
146
148
|
collector = visit order, collector
|
147
149
|
end
|
148
150
|
end
|
149
|
-
if o.
|
151
|
+
if o.separator && o.separator != 'NULL'
|
150
152
|
collector << ' SEPARATOR '
|
151
|
-
collector = visit o.
|
153
|
+
collector = visit o.separator, collector
|
152
154
|
end
|
153
155
|
collector << ")"
|
154
156
|
collector
|
@@ -191,6 +193,13 @@ module ArelExtensions
|
|
191
193
|
collector
|
192
194
|
end
|
193
195
|
|
196
|
+
def visit_ArelExtensions_Nodes_RegexpReplace o, collector
|
197
|
+
if !regexp_replace_supported?
|
198
|
+
warn("Warning : ArelExtensions: REGEXP_REPLACE does not seem to be available in the current version of the DBMS, it might crash")
|
199
|
+
end
|
200
|
+
super(o,collector)
|
201
|
+
end
|
202
|
+
|
194
203
|
def visit_ArelExtensions_Nodes_Format o, collector
|
195
204
|
case o.col_type
|
196
205
|
when :date, :datetime
|
@@ -262,7 +271,7 @@ module ArelExtensions
|
|
262
271
|
else
|
263
272
|
if o.with_interval
|
264
273
|
case o.left
|
265
|
-
when
|
274
|
+
when 'd','m','y'
|
266
275
|
interval = 'DAY'
|
267
276
|
when 'h','mn','s'
|
268
277
|
interval = 'SECOND'
|
@@ -284,22 +293,14 @@ module ArelExtensions
|
|
284
293
|
|
285
294
|
def visit_ArelExtensions_Nodes_IsNull o, collector
|
286
295
|
collector << "ISNULL("
|
287
|
-
collector = visit o.
|
288
|
-
if o.right
|
289
|
-
collector << Arel::Visitors::MySQL::COMMA
|
290
|
-
collector = visit o.right, collector
|
291
|
-
end
|
296
|
+
collector = visit o.expr, collector
|
292
297
|
collector << ")"
|
293
298
|
collector
|
294
299
|
end
|
295
300
|
|
296
301
|
def visit_ArelExtensions_Nodes_IsNotNull o, collector
|
297
302
|
collector << "NOT ISNULL("
|
298
|
-
collector = visit o.
|
299
|
-
if o.right
|
300
|
-
collector << Arel::Visitors::MySQL::COMMA
|
301
|
-
collector = visit o.right, collector
|
302
|
-
end
|
303
|
+
collector = visit o.expr, collector
|
303
304
|
collector << ")"
|
304
305
|
collector
|
305
306
|
end
|
@@ -370,20 +371,21 @@ module ArelExtensions
|
|
370
371
|
else(o.flags.include?('+') ? '+' : (o.flags.include?(' ') ? ' ' : ''))
|
371
372
|
sign_length = ArelExtensions::Nodes::Length.new([sign])
|
372
373
|
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
374
|
+
number =
|
375
|
+
if o.scientific_notation
|
376
|
+
ArelExtensions::Nodes::Concat.new([
|
377
|
+
Arel::Nodes::NamedFunction.new('FORMAT',[
|
378
|
+
col.abs/Arel::Nodes.build_quoted(10).pow(col.abs.log10.floor)
|
379
|
+
]+params),
|
380
|
+
o.type,
|
381
|
+
Arel::Nodes::NamedFunction.new('FORMAT',[
|
382
|
+
col.abs.log10.floor,
|
383
|
+
0
|
384
|
+
])
|
382
385
|
])
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
end
|
386
|
+
else
|
387
|
+
Arel::Nodes::NamedFunction.new('FORMAT',[col.abs]+params)
|
388
|
+
end
|
387
389
|
|
388
390
|
repeated_char = (o.width == 0) ? Arel::Nodes.build_quoted('') : ArelExtensions::Nodes::Case.new().
|
389
391
|
when(Arel::Nodes.build_quoted(o.width).abs-(number.length+sign_length)>0).
|
@@ -406,10 +408,34 @@ module ArelExtensions
|
|
406
408
|
collector
|
407
409
|
end
|
408
410
|
|
411
|
+
def visit_Aggregate_For_AggregateFunction o, collector
|
412
|
+
if !window_supported?
|
413
|
+
warn("Warning : ArelExtensions: Window Functions are not available in the current version of the DBMS.")
|
414
|
+
return collector
|
415
|
+
end
|
416
|
+
|
417
|
+
if !o.order.empty? || !o.group.empty?
|
418
|
+
collector << " OVER ("
|
419
|
+
if !o.group.empty?
|
420
|
+
collector << " PARTITION BY ("
|
421
|
+
visit o.group, collector
|
422
|
+
collector << ")"
|
423
|
+
end
|
424
|
+
if !o.order.empty?
|
425
|
+
collector << " ORDER BY ("
|
426
|
+
visit o.order, collector
|
427
|
+
collector << ")"
|
428
|
+
end
|
429
|
+
collector << ")"
|
430
|
+
end
|
431
|
+
collector
|
432
|
+
end
|
433
|
+
|
409
434
|
def visit_ArelExtensions_Nodes_Std o, collector
|
410
435
|
collector << (o.unbiased_estimator ? "STDDEV_SAMP(" : "STDDEV_POP(")
|
411
436
|
visit o.left, collector
|
412
437
|
collector << ")"
|
438
|
+
visit_Aggregate_For_AggregateFunction o, collector
|
413
439
|
collector
|
414
440
|
end
|
415
441
|
|
@@ -417,15 +443,35 @@ module ArelExtensions
|
|
417
443
|
collector << (o.unbiased_estimator ? "VAR_SAMP(" : "VAR_POP(")
|
418
444
|
visit o.left, collector
|
419
445
|
collector << ")"
|
446
|
+
visit_Aggregate_For_AggregateFunction o, collector
|
420
447
|
collector
|
421
448
|
end
|
422
449
|
|
423
450
|
# JSON if implemented only after 10.2.3 in MariaDb and 5.7 in MySql
|
424
451
|
def json_supported?
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
452
|
+
version_supported?('10.2.3', '5.7.0')
|
453
|
+
end
|
454
|
+
|
455
|
+
def window_supported?
|
456
|
+
version_supported?('10.2.3', '8.0')
|
457
|
+
end
|
458
|
+
|
459
|
+
def regexp_replace_supported?
|
460
|
+
version_supported?('10.0.5', '8.0')
|
461
|
+
end
|
462
|
+
|
463
|
+
def version_supported?(mariadb_v = '10.2.3', mysql_v = '5.7.0')
|
464
|
+
conn = Arel::Table.engine.connection
|
465
|
+
conn.send(:mariadb?) && \
|
466
|
+
(conn.respond_to?(:get_database_version) && conn.send(:get_database_version) >= mariadb_v || \
|
467
|
+
conn.respond_to?(:version) && conn.send(:version) >= mariadb_v || \
|
468
|
+
conn.instance_variable_get(:"@version") && conn.instance_variable_get(:"@version") >= mariadb_v) || \
|
469
|
+
!conn.send(:mariadb?) && \
|
470
|
+
(conn.respond_to?(:get_database_version) && conn.send(:get_database_version) >= mysql_v || \
|
471
|
+
conn.respond_to?(:version) && conn.send(:version) >= mysql_v || \
|
472
|
+
conn.instance_variable_get(:"@version") && conn.instance_variable_get(:"@version") >= mysql_v)
|
473
|
+
# ideally we should parse the instance_variable @full_version because @version contains only the supposedly
|
474
|
+
# corresponding mysql version of the current mariadb version (which is not very helpful most of the time)
|
429
475
|
end
|
430
476
|
|
431
477
|
def visit_ArelExtensions_Nodes_Json o,collector
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#require 'oracle_visitor'
|
2
2
|
module ArelExtensions
|
3
3
|
module Visitors
|
4
|
-
Arel::Visitors::Oracle
|
4
|
+
class Arel::Visitors::Oracle
|
5
5
|
|
6
6
|
SPECIAL_CHARS = {"\t" => 'CHR(9)', "\n" => 'CHR(10)', "\r" => 'CHR(13)'}
|
7
7
|
Arel::Visitors::Oracle::DATE_MAPPING = {'d' => 'DAY', 'm' => 'MONTH', 'w' => 'IW', 'y' => 'YEAR', 'wd' => 'D', 'h' => 'HOUR', 'mn' => 'MINUTE', 's' => 'SECOND'}
|
@@ -131,14 +131,15 @@ module ArelExtensions
|
|
131
131
|
collector << "(LISTAGG("
|
132
132
|
collector = visit o.left, collector
|
133
133
|
collector << Arel::Visitors::Oracle::COMMA
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
134
|
+
collector =
|
135
|
+
if o.separator && o.separator != 'NULL'
|
136
|
+
visit o.separator, collector
|
137
|
+
else
|
138
|
+
visit Arel::Nodes.build_quoted(','), collector
|
139
|
+
end
|
139
140
|
collector << ") WITHIN GROUP (ORDER BY "
|
140
|
-
if !o.
|
141
|
-
o.
|
141
|
+
if !o.order.blank?
|
142
|
+
o.order.each_with_index do |order,i|
|
142
143
|
collector << Arel::Visitors::Oracle::COMMA unless i == 0
|
143
144
|
collector = visit order, collector
|
144
145
|
end
|
@@ -154,8 +155,8 @@ module ArelExtensions
|
|
154
155
|
o.expressions.each_with_index { |arg, i|
|
155
156
|
collector << Arel::Visitors::Oracle::COMMA unless i == 0
|
156
157
|
if i > 0 && o.left_node_type == :text
|
157
|
-
if arg == ''
|
158
|
-
collector <<
|
158
|
+
if arg == '' || (arg.is_a?(Arel::Nodes::Quoted) && (arg.expr == ''))
|
159
|
+
collector << "NULL"
|
159
160
|
else
|
160
161
|
collector << 'TO_CLOB('
|
161
162
|
collector = visit arg, collector
|
@@ -257,9 +258,15 @@ module ArelExtensions
|
|
257
258
|
collector << ")"
|
258
259
|
return collector
|
259
260
|
when :time
|
260
|
-
|
261
|
-
|
262
|
-
|
261
|
+
if (o.left.respond_to?(:return_type) && o.left.return_type == :string) || o.left.is_a?(Arel::Nodes::Quoted)
|
262
|
+
collector << "TO_DATE("
|
263
|
+
collector = visit o.left, collector
|
264
|
+
collector << ",'HH24:MI:SS')"
|
265
|
+
else
|
266
|
+
collector << "TO_DATE(TO_CHAR("
|
267
|
+
collector = visit o.left, collector
|
268
|
+
collector << ",'HH24:MI:SS'),'HH24:MI:SS')"
|
269
|
+
end
|
263
270
|
return collector
|
264
271
|
when :number, :decimal
|
265
272
|
collector << "TO_NUMBER("
|
@@ -269,9 +276,15 @@ module ArelExtensions
|
|
269
276
|
when :datetime
|
270
277
|
as_attr = Arel::Nodes::SqlLiteral.new('timestamp')
|
271
278
|
when :date
|
272
|
-
|
273
|
-
|
274
|
-
|
279
|
+
if (o.left.respond_to?(:return_type) && o.left.return_type == :string) || o.left.is_a?(Arel::Nodes::Quoted)
|
280
|
+
collector << "TO_DATE("
|
281
|
+
collector = visit o.left, collector
|
282
|
+
collector << ",'YYYY-MM-DD')"
|
283
|
+
else
|
284
|
+
collector << "TO_DATE(TO_CHAR("
|
285
|
+
collector = visit o.left, collector
|
286
|
+
collector << ",'YYYY-MM-DD'),'YYYY-MM-DD')"
|
287
|
+
end
|
275
288
|
return collector
|
276
289
|
when :binary
|
277
290
|
as_attr = Arel::Nodes::SqlLiteral.new('binary')
|
@@ -294,13 +307,13 @@ module ArelExtensions
|
|
294
307
|
end
|
295
308
|
|
296
309
|
def visit_ArelExtensions_Nodes_IsNull o, collector
|
297
|
-
collector = visit o.
|
310
|
+
collector = visit o.expr, collector
|
298
311
|
collector << ' IS NULL'
|
299
312
|
collector
|
300
313
|
end
|
301
314
|
|
302
315
|
def visit_ArelExtensions_Nodes_IsNotNull o, collector
|
303
|
-
collector = visit o.
|
316
|
+
collector = visit o.expr, collector
|
304
317
|
collector << ' IS NOT NULL'
|
305
318
|
collector
|
306
319
|
end
|
@@ -407,11 +420,11 @@ module ArelExtensions
|
|
407
420
|
end
|
408
421
|
|
409
422
|
def visit_ArelExtensions_Nodes_Blank o, collector
|
410
|
-
visit o.
|
423
|
+
visit o.expr.trim.length.coalesce(0).eq(0), collector
|
411
424
|
end
|
412
425
|
|
413
426
|
def visit_ArelExtensions_Nodes_NotBlank o, collector
|
414
|
-
visit o.
|
427
|
+
visit o.expr.trim.length.coalesce(0).gt(0), collector
|
415
428
|
end
|
416
429
|
|
417
430
|
def visit_ArelExtensions_Nodes_DateAdd o, collector
|
@@ -454,14 +467,12 @@ module ArelExtensions
|
|
454
467
|
o.left.each_with_index do |row, idx| # values
|
455
468
|
collector << " UNION ALL " if idx != 0
|
456
469
|
collector << "(SELECT "
|
457
|
-
|
458
|
-
|
459
|
-
v.expressions.each_with_index { |value, i|
|
470
|
+
len = row.length - 1
|
471
|
+
row.zip(o.cols).each_with_index { |(value, attr), i|
|
460
472
|
case value
|
461
473
|
when Arel::Nodes::SqlLiteral, Arel::Nodes::BindParam
|
462
474
|
collector = visit value, collector
|
463
475
|
else
|
464
|
-
attr = v.columns[i]
|
465
476
|
collector << quote(value, attr && column_for(attr)).to_s
|
466
477
|
end
|
467
478
|
collector << Arel::Visitors::Oracle::COMMA unless i == len
|
@@ -477,12 +488,13 @@ module ArelExtensions
|
|
477
488
|
o.left.each_with_index do |row, idx|
|
478
489
|
collector << " UNION ALL " if idx != 0
|
479
490
|
collector << "(SELECT "
|
480
|
-
|
481
|
-
|
482
|
-
v.expressions.zip(v.columns).each_with_index { |(value, attr), i|
|
491
|
+
len = row.length - 1
|
492
|
+
row.zip(o.cols).each_with_index { |(value, attr), i|
|
483
493
|
case value
|
484
494
|
when Arel::Nodes::SqlLiteral, Arel::Nodes::BindParam
|
485
495
|
collector = visit value, collector
|
496
|
+
when Integer
|
497
|
+
collector << value.to_s
|
486
498
|
else
|
487
499
|
collector << (attr && attr.able_to_type_cast? ? quote(attr.type_cast_for_database(value)) : quote(value).to_s)
|
488
500
|
end
|
@@ -571,7 +583,7 @@ module ArelExtensions
|
|
571
583
|
else
|
572
584
|
collector = visit o.left, collector
|
573
585
|
end
|
574
|
-
quote = o.right.to_s =~ /[
|
586
|
+
quote = o.right.to_s =~ /(\A["].*["]\z)|\A[a-zA-Z_]*\z/ ? '' : '"'
|
575
587
|
collector << " AS #{quote}"
|
576
588
|
collector = visit o.right, collector
|
577
589
|
collector << "#{quote}"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module ArelExtensions
|
2
2
|
module Visitors
|
3
|
-
Arel::Visitors::PostgreSQL
|
3
|
+
class Arel::Visitors::PostgreSQL
|
4
4
|
Arel::Visitors::PostgreSQL::DATE_MAPPING = {'d' => 'DAY', 'm' => 'MONTH', 'w' => 'WEEK', 'y' => 'YEAR', 'wd' => 'DOW', 'h' => 'HOUR', 'mn' => 'MINUTE', 's' => 'SECOND'}
|
5
5
|
Arel::Visitors::PostgreSQL::DATE_FORMAT_DIRECTIVES = {
|
6
6
|
'%Y' => 'IYYY', '%C' => 'CC', '%y' => 'YY', '%m' => 'MM', '%B' => 'Month', '%^B' => 'MONTH', '%b' => 'Mon', '%^b' => 'MON',
|
@@ -83,23 +83,49 @@ module ArelExtensions
|
|
83
83
|
collector
|
84
84
|
end
|
85
85
|
|
86
|
+
def visit_Aggregate_For_AggregateFunction o, collector
|
87
|
+
if !o.order.blank? || !o.group.blank?
|
88
|
+
collector << " OVER ("
|
89
|
+
if !o.group.blank?
|
90
|
+
collector << " PARTITION BY "
|
91
|
+
o.group.each_with_index do |group, i|
|
92
|
+
collector << Arel::Visitors::PostgreSQL::COMMA unless i == 0
|
93
|
+
visit group, collector
|
94
|
+
end
|
95
|
+
end
|
96
|
+
if !o.order.blank?
|
97
|
+
collector << " ORDER BY "
|
98
|
+
o.order.each_with_index do |order, i|
|
99
|
+
collector << Arel::Visitors::PostgreSQL::COMMA unless i == 0
|
100
|
+
visit order, collector
|
101
|
+
end
|
102
|
+
end
|
103
|
+
collector << ")"
|
104
|
+
end
|
105
|
+
collector
|
106
|
+
end
|
107
|
+
|
86
108
|
def visit_ArelExtensions_Nodes_GroupConcat o, collector
|
87
109
|
collector << "array_to_string(array_agg("
|
88
110
|
collector = visit o.left, collector
|
89
|
-
if !o.
|
90
|
-
collector <<
|
91
|
-
o.
|
111
|
+
if o.order && !o.order.blank?
|
112
|
+
collector << " ORDER BY"
|
113
|
+
o.order.each_with_index do |order, i|
|
92
114
|
collector << Arel::Visitors::PostgreSQL::COMMA unless i == 0
|
93
|
-
collector
|
115
|
+
collector << " "
|
116
|
+
visit order, collector
|
94
117
|
end
|
95
118
|
end
|
96
119
|
collector << ")"
|
120
|
+
o.order = nil
|
121
|
+
visit_Aggregate_For_AggregateFunction o, collector
|
97
122
|
collector << Arel::Visitors::PostgreSQL::COMMA
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
123
|
+
collector =
|
124
|
+
if o.separator && o.separator != 'NULL'
|
125
|
+
visit o.separator, collector
|
126
|
+
else
|
127
|
+
visit Arel::Nodes.build_quoted(','), collector
|
128
|
+
end
|
103
129
|
collector << ")"
|
104
130
|
collector
|
105
131
|
end
|
@@ -277,14 +303,30 @@ module ArelExtensions
|
|
277
303
|
collector
|
278
304
|
end
|
279
305
|
|
306
|
+
def visit_ArelExtensions_Nodes_RegexpReplace o, collector
|
307
|
+
collector << "REGEXP_REPLACE("
|
308
|
+
visit o.left, collector
|
309
|
+
collector << Arel::Visitors::ToSql::COMMA
|
310
|
+
tab = o.pattern.inspect+ 'g' # Make it always global
|
311
|
+
pattern = tab.split('/')[1..-2].join('/')
|
312
|
+
flags = tab.split('/')[-1]
|
313
|
+
visit Arel::Nodes.build_quoted(pattern), collector
|
314
|
+
collector << Arel::Visitors::ToSql::COMMA
|
315
|
+
visit o.substitute, collector
|
316
|
+
collector << Arel::Visitors::ToSql::COMMA
|
317
|
+
visit Arel::Nodes.build_quoted(flags+"g"), collector
|
318
|
+
collector << ")"
|
319
|
+
collector
|
320
|
+
end
|
321
|
+
|
280
322
|
def visit_ArelExtensions_Nodes_IsNull o, collector
|
281
|
-
collector = visit o.
|
323
|
+
collector = visit o.expr, collector
|
282
324
|
collector << ' IS NULL'
|
283
325
|
collector
|
284
326
|
end
|
285
327
|
|
286
328
|
def visit_ArelExtensions_Nodes_IsNotNull o, collector
|
287
|
-
collector = visit o.
|
329
|
+
collector = visit o.expr, collector
|
288
330
|
collector << ' IS NOT NULL'
|
289
331
|
collector
|
290
332
|
end
|
@@ -293,6 +335,7 @@ module ArelExtensions
|
|
293
335
|
collector << "sum("
|
294
336
|
collector = visit o.expr, collector
|
295
337
|
collector << ")"
|
338
|
+
visit_Aggregate_For_AggregateFunction o, collector
|
296
339
|
collector
|
297
340
|
end
|
298
341
|
|
@@ -345,27 +388,28 @@ module ArelExtensions
|
|
345
388
|
else(o.flags.include?('+') ? '+' : (o.flags.include?(' ') ? ' ' : ''))
|
346
389
|
sign_length = ArelExtensions::Nodes::Length.new([sign])
|
347
390
|
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
391
|
+
number =
|
392
|
+
if o.scientific_notation
|
393
|
+
ArelExtensions::Nodes::Concat.new([
|
394
|
+
Arel::Nodes::NamedFunction.new('TRIM',[
|
395
|
+
Arel::Nodes::NamedFunction.new('TO_CHAR',[
|
396
|
+
col.abs/Arel::Nodes.build_quoted(10).pow(col.abs.log10.floor),
|
397
|
+
Arel::Nodes.build_quoted('FM'+nines_before+'"'+comma+'"V'+nines_after)
|
398
|
+
])]),
|
399
|
+
o.type,
|
400
|
+
Arel::Nodes::NamedFunction.new('TRIM',[
|
401
|
+
Arel::Nodes::NamedFunction.new('TO_CHAR',[
|
402
|
+
col.abs.log10.floor,
|
403
|
+
Arel::Nodes.build_quoted('FM'+nines_before)
|
404
|
+
])])
|
405
|
+
])
|
406
|
+
else
|
407
|
+
Arel::Nodes::NamedFunction.new('TRIM',[
|
408
|
+
Arel::Nodes::NamedFunction.new('TO_CHAR',[
|
409
|
+
Arel::Nodes.build_quoted(col.abs),
|
410
|
+
Arel::Nodes.build_quoted('FM'+nines_before+'"'+comma+'"V'+nines_after)
|
411
|
+
])])
|
412
|
+
end
|
369
413
|
|
370
414
|
repeated_char = (o.width == 0) ? Arel::Nodes.build_quoted('') : ArelExtensions::Nodes::Case.new().
|
371
415
|
when(Arel::Nodes.build_quoted(o.width).abs-(number.length+sign_length)>0).
|
@@ -420,6 +464,7 @@ module ArelExtensions
|
|
420
464
|
collector << (o.unbiased_estimator ? "STDDEV_SAMP(" : "STDDEV_POP(")
|
421
465
|
visit o.left, collector
|
422
466
|
collector << ")"
|
467
|
+
visit_Aggregate_For_AggregateFunction o, collector
|
423
468
|
collector
|
424
469
|
end
|
425
470
|
|
@@ -427,6 +472,7 @@ module ArelExtensions
|
|
427
472
|
collector << (o.unbiased_estimator ? "VAR_SAMP(" : "VAR_POP(")
|
428
473
|
visit o.left, collector
|
429
474
|
collector << ")"
|
475
|
+
visit_Aggregate_For_AggregateFunction o, collector
|
430
476
|
collector
|
431
477
|
end
|
432
478
|
|
@@ -438,7 +484,7 @@ module ArelExtensions
|
|
438
484
|
if i != 0
|
439
485
|
collector << Arel::Visitors::MySQL::COMMA
|
440
486
|
end
|
441
|
-
collector
|
487
|
+
collector = visit v, collector
|
442
488
|
end
|
443
489
|
collector << '])'
|
444
490
|
when Hash
|