arel_extensions 1.2.23 → 2.0.0.rc3

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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -7
  3. data/.travis.yml +91 -61
  4. data/Gemfile +20 -15
  5. data/README.md +12 -17
  6. data/Rakefile +29 -40
  7. data/appveyor.yml +1 -1
  8. data/arel_extensions.gemspec +3 -3
  9. data/functions.html +3 -3
  10. data/gemfiles/rails3.gemfile +9 -9
  11. data/gemfiles/rails4.gemfile +13 -13
  12. data/gemfiles/rails5_0.gemfile +13 -13
  13. data/gemfiles/rails5_1_4.gemfile +13 -13
  14. data/gemfiles/rails5_2.gemfile +13 -13
  15. data/init/mssql.sql +4 -4
  16. data/init/mysql.sql +38 -38
  17. data/init/postgresql.sql +21 -21
  18. data/lib/arel_extensions.rb +19 -69
  19. data/lib/arel_extensions/attributes.rb +1 -0
  20. data/lib/arel_extensions/boolean_functions.rb +14 -55
  21. data/lib/arel_extensions/common_sql_functions.rb +8 -7
  22. data/lib/arel_extensions/comparators.rb +15 -14
  23. data/lib/arel_extensions/date_duration.rb +5 -4
  24. data/lib/arel_extensions/insert_manager.rb +16 -17
  25. data/lib/arel_extensions/math.rb +12 -11
  26. data/lib/arel_extensions/math_functions.rb +22 -29
  27. data/lib/arel_extensions/nodes.rb +1 -1
  28. data/lib/arel_extensions/nodes/abs.rb +1 -0
  29. data/lib/arel_extensions/nodes/blank.rb +1 -0
  30. data/lib/arel_extensions/nodes/case.rb +8 -11
  31. data/lib/arel_extensions/nodes/cast.rb +2 -4
  32. data/lib/arel_extensions/nodes/ceil.rb +1 -1
  33. data/lib/arel_extensions/nodes/change_case.rb +0 -0
  34. data/lib/arel_extensions/nodes/coalesce.rb +3 -2
  35. data/lib/arel_extensions/nodes/collate.rb +2 -1
  36. data/lib/arel_extensions/nodes/concat.rb +16 -7
  37. data/lib/arel_extensions/nodes/date_diff.rb +13 -10
  38. data/lib/arel_extensions/nodes/duration.rb +3 -0
  39. data/lib/arel_extensions/nodes/find_in_set.rb +1 -0
  40. data/lib/arel_extensions/nodes/floor.rb +1 -1
  41. data/lib/arel_extensions/nodes/format.rb +8 -34
  42. data/lib/arel_extensions/nodes/formatted_number.rb +23 -22
  43. data/lib/arel_extensions/nodes/function.rb +16 -25
  44. data/lib/arel_extensions/nodes/json.rb +36 -43
  45. data/lib/arel_extensions/nodes/length.rb +1 -0
  46. data/lib/arel_extensions/nodes/levenshtein_distance.rb +0 -0
  47. data/lib/arel_extensions/nodes/locate.rb +1 -0
  48. data/lib/arel_extensions/nodes/log10.rb +2 -1
  49. data/lib/arel_extensions/nodes/matches.rb +6 -4
  50. data/lib/arel_extensions/nodes/md5.rb +1 -0
  51. data/lib/arel_extensions/nodes/power.rb +5 -5
  52. data/lib/arel_extensions/nodes/rand.rb +1 -0
  53. data/lib/arel_extensions/nodes/repeat.rb +4 -2
  54. data/lib/arel_extensions/nodes/replace.rb +6 -22
  55. data/lib/arel_extensions/nodes/round.rb +6 -5
  56. data/lib/arel_extensions/nodes/soundex.rb +15 -15
  57. data/lib/arel_extensions/nodes/std.rb +21 -18
  58. data/lib/arel_extensions/nodes/substring.rb +16 -8
  59. data/lib/arel_extensions/nodes/then.rb +0 -0
  60. data/lib/arel_extensions/nodes/trim.rb +5 -3
  61. data/lib/arel_extensions/nodes/union.rb +5 -2
  62. data/lib/arel_extensions/nodes/union_all.rb +3 -0
  63. data/lib/arel_extensions/nodes/wday.rb +4 -0
  64. data/lib/arel_extensions/null_functions.rb +7 -5
  65. data/lib/arel_extensions/predications.rb +34 -35
  66. data/lib/arel_extensions/railtie.rb +5 -5
  67. data/lib/arel_extensions/set_functions.rb +4 -2
  68. data/lib/arel_extensions/string_functions.rb +22 -43
  69. data/lib/arel_extensions/tasks.rb +5 -5
  70. data/lib/arel_extensions/version.rb +1 -1
  71. data/lib/arel_extensions/visitors.rb +60 -68
  72. data/lib/arel_extensions/visitors/ibm_db.rb +12 -5
  73. data/lib/arel_extensions/visitors/mssql.rb +57 -63
  74. data/lib/arel_extensions/visitors/mysql.rb +98 -149
  75. data/lib/arel_extensions/visitors/oracle.rb +68 -71
  76. data/lib/arel_extensions/visitors/oracle12.rb +15 -2
  77. data/lib/arel_extensions/visitors/postgresql.rb +63 -116
  78. data/lib/arel_extensions/visitors/sqlite.rb +70 -83
  79. data/lib/arel_extensions/visitors/to_sql.rb +109 -141
  80. data/test/database.yml +0 -2
  81. data/test/helper.rb +18 -0
  82. data/test/real_db_test.rb +43 -28
  83. data/test/support/fake_record.rb +2 -2
  84. data/test/test_comparators.rb +12 -9
  85. data/test/visitors/test_bulk_insert_oracle.rb +8 -8
  86. data/test/visitors/test_bulk_insert_sqlite.rb +10 -9
  87. data/test/visitors/test_bulk_insert_to_sql.rb +10 -8
  88. data/test/visitors/test_oracle.rb +42 -42
  89. data/test/visitors/test_to_sql.rb +196 -361
  90. data/test/with_ar/all_agnostic_test.rb +160 -195
  91. data/test/with_ar/insert_agnostic_test.rb +4 -3
  92. data/test/with_ar/test_bulk_sqlite.rb +9 -6
  93. data/test/with_ar/test_math_sqlite.rb +12 -8
  94. data/test/with_ar/test_string_mysql.rb +11 -5
  95. data/test/with_ar/test_string_sqlite.rb +12 -4
  96. metadata +11 -22
  97. data/.github/workflows/ruby.yml +0 -102
  98. data/gemfiles/rails6.gemfile +0 -30
  99. data/gemfiles/rails6_1.gemfile +0 -30
  100. data/gemspecs/arel_extensions-v1.gemspec +0 -28
  101. data/gemspecs/arel_extensions-v2.gemspec +0 -28
  102. data/generate_gems.sh +0 -15
  103. data/lib/arel_extensions/nodes/aggregate_function.rb +0 -13
  104. data/lib/arel_extensions/nodes/sum.rb +0 -7
  105. data/lib/arel_extensions/visitors/convert_format.rb +0 -37
  106. data/test/arelx_test_helper.rb +0 -26
  107. data/version_v1.rb +0 -3
  108. data/version_v2.rb +0 -3
@@ -1,21 +1,22 @@
1
- # require 'oracle_visitor'
1
+ #require 'oracle_visitor'
2
2
  module ArelExtensions
3
3
  module Visitors
4
- class Arel::Visitors::Oracle
4
+ Arel::Visitors::Oracle.class_eval do
5
+
5
6
  SPECIAL_CHARS = {"\t" => 'CHR(9)', "\n" => 'CHR(10)', "\r" => 'CHR(13)'}
6
- DATE_MAPPING = {'d' => 'DAY', 'm' => 'MONTH', 'w' => 'IW', 'y' => 'YEAR', 'wd' => 'D', 'h' => 'HOUR', 'mn' => 'MINUTE', 's' => 'SECOND'}
7
- DATE_FORMAT_DIRECTIVES = {
7
+ Arel::Visitors::Oracle::DATE_MAPPING = {'d' => 'DAY', 'm' => 'MONTH', 'w' => 'IW', 'y' => 'YEAR', 'wd' => 'D', 'h' => 'HOUR', 'mn' => 'MINUTE', 's' => 'SECOND'}
8
+ Arel::Visitors::Oracle::DATE_FORMAT_DIRECTIVES = {
8
9
  '%Y' => 'IYYY', '%C' => 'CC', '%y' => 'YY', '%m' => 'MM', '%B' => 'Month', '%^B' => 'MONTH', '%b' => 'Mon', '%^b' => 'MON',
9
10
  '%d' => 'DD', '%e' => 'FMDD', '%j' => 'DDD', '%w' => '', '%A' => 'Day', # day, weekday
10
11
  '%H' => 'HH24', '%k' => '', '%I' => 'HH', '%l' => '', '%P' => 'am', '%p' => 'AM', # hours
11
12
  '%M' => 'MI', '%S' => 'SS', '%L' => 'MS', '%N' => 'US', '%z' => 'tz' # seconds, subseconds
12
13
  }
13
- NUMBER_COMMA_MAPPING = { 'en_US' => '.,', 'fr_FR' => ',', 'sv_SE' => ', ' }
14
+ Arel::Visitors::Oracle::NUMBER_COMMA_MAPPING = { 'en_US' => '.,', 'fr_FR' => ',', 'sv_SE' => ', ' }
14
15
 
15
16
  def visit_ArelExtensions_Nodes_Log10 o, collector
16
17
  collector << "LOG("
17
18
  o.expressions.each_with_index { |arg, i|
18
- collector << Arel::Visitors::ToSql::COMMA if i != 0
19
+ collector << Arel::Visitors::ToSql::COMMA unless i == 0
19
20
  collector = visit arg, collector
20
21
  }
21
22
  collector << ",10)"
@@ -25,7 +26,7 @@ module ArelExtensions
25
26
  def visit_ArelExtensions_Nodes_Power o, collector
26
27
  collector << "POWER("
27
28
  o.expressions.each_with_index { |arg, i|
28
- collector << Arel::Visitors::ToSql::COMMA if i != 0
29
+ collector << Arel::Visitors::ToSql::COMMA unless i == 0
29
30
  collector = visit arg, collector
30
31
  }
31
32
  collector << ")"
@@ -92,6 +93,7 @@ module ArelExtensions
92
93
  end
93
94
  end
94
95
 
96
+
95
97
  def visit_ArelExtensions_Nodes_IDoesNotMatch o, collector
96
98
  collector << 'LOWER('
97
99
  collector = visit o.left, collector
@@ -110,35 +112,34 @@ module ArelExtensions
110
112
  if o.ai
111
113
  collector << "NLSSORT("
112
114
  collector = visit o.expressions.first, collector
113
- collector << COMMA
115
+ collector << Arel::Visitors::Oracle::COMMA
114
116
  collector << "'NLS_SORT = BINARY_AI NLS_COMP = LINGUISTIC'"
115
117
  collector << ")"
116
118
  elsif o.ci
117
119
  collector << "NLSSORT("
118
120
  collector = visit o.expressions.first, collector
119
- collector << COMMA
121
+ collector << Arel::Visitors::Oracle::COMMA
120
122
  collector << "'NLS_SORT = BINARY_CI NLS_COMP = LINGUISTIC'"
121
123
  collector << ")"
122
124
  else
123
125
  collector = visit o.expressions.first, collector
124
126
  end
125
- collector
127
+ collector
126
128
  end
127
129
 
128
130
  def visit_ArelExtensions_Nodes_GroupConcat o, collector
129
131
  collector << "(LISTAGG("
130
132
  collector = visit o.left, collector
131
- collector << COMMA
132
- collector =
133
- if o.separator && o.separator != 'NULL'
134
- visit o.separator, collector
135
- else
136
- visit Arel::Nodes.build_quoted(','), collector
137
- end
133
+ collector << Arel::Visitors::Oracle::COMMA
134
+ if o.right && o.right != 'NULL'
135
+ collector = visit o.right, collector
136
+ else
137
+ collector = visit Arel::Nodes.build_quoted(','), collector
138
+ end
138
139
  collector << ") WITHIN GROUP (ORDER BY "
139
- if !o.order.blank?
140
- o.order.each_with_index do |order,i|
141
- collector << COMMA if i != 0
140
+ if !o.orders.blank?
141
+ o.orders.each_with_index do |order,i|
142
+ collector << Arel::Visitors::Oracle::COMMA unless i == 0
142
143
  collector = visit order, collector
143
144
  end
144
145
  else
@@ -151,9 +152,9 @@ module ArelExtensions
151
152
  def visit_ArelExtensions_Nodes_Coalesce o, collector
152
153
  collector << "COALESCE("
153
154
  o.expressions.each_with_index { |arg, i|
154
- collector << COMMA if i != 0
155
+ collector << Arel::Visitors::Oracle::COMMA unless i == 0
155
156
  if i > 0 && o.left_node_type == :text
156
- if arg == '' || (arg.is_a?(Arel::Nodes::Quoted) && (arg.expr == ''))
157
+ if arg == '' || (arg.is_a?(Arel::Nodes::Quoted) && (arg.expr == ''))
157
158
  collector << "NULL"
158
159
  else
159
160
  collector << 'TO_CLOB('
@@ -194,7 +195,7 @@ module ArelExtensions
194
195
  collector << 'TO_DATE(' if lc
195
196
  collector = visit o.left, collector
196
197
  collector << ')' if lc
197
- collector << COMMA
198
+ collector << Arel::Visitors::Oracle::COMMA
198
199
  collector << "'DDD') = "
199
200
  collector << 'TO_DATE(' if lc
200
201
  collector = visit o.left, collector
@@ -220,8 +221,8 @@ module ArelExtensions
220
221
  when 'wd', 'w'
221
222
  collector << "TO_CHAR("
222
223
  collector = visit o.right, collector
223
- collector << COMMA
224
- collector = visit Arel::Nodes.build_quoted(DATE_MAPPING[o.left]), collector
224
+ collector << Arel::Visitors::Oracle::COMMA
225
+ collector = visit Arel::Nodes.build_quoted(Arel::Visitors::Oracle::DATE_MAPPING[o.left]), collector
225
226
  else
226
227
  right = case o.left
227
228
  when 'd','m','y'
@@ -231,7 +232,7 @@ module ArelExtensions
231
232
  interval = 'SECOND'
232
233
  o.right.cast(:datetime)
233
234
  when /i\z/
234
- interval = DATE_MAPPING[o.left[0..-2]]
235
+ interval = Arel::Visitors::Oracle::DATE_MAPPING[o.left[0..-2]]
235
236
  collector << '('
236
237
  collector = visit o.right, collector
237
238
  collector << ") * (INTERVAL '1' #{interval})"
@@ -240,7 +241,7 @@ module ArelExtensions
240
241
  interval = nil
241
242
  o.right
242
243
  end
243
- collector << "EXTRACT(#{DATE_MAPPING[o.left]} FROM "
244
+ collector << "EXTRACT(#{Arel::Visitors::Oracle::DATE_MAPPING[o.left]} FROM "
244
245
  collector = visit right, collector
245
246
  end
246
247
  collector << ")"
@@ -255,16 +256,6 @@ module ArelExtensions
255
256
  collector = visit o.left, collector
256
257
  collector << ")"
257
258
  return collector
258
- when :text
259
- collector << "TO_CLOB("
260
- collector = visit o.left, collector
261
- collector << ")"
262
- return collector
263
- when :ntext
264
- collector << "TO_NCLOB("
265
- collector = visit o.left, collector
266
- collector << ")"
267
- return collector
268
259
  when :time
269
260
  if (o.left.respond_to?(:return_type) && o.left.return_type == :string) || o.left.is_a?(Arel::Nodes::Quoted)
270
261
  collector << "TO_DATE("
@@ -330,7 +321,7 @@ module ArelExtensions
330
321
  collector << "DBMS_RANDOM.VALUE("
331
322
  if o.left && o.right
332
323
  collector = visit o.left, collector
333
- collector << COMMA
324
+ collector << Arel::Visitors::Oracle::COMMA
334
325
  collector = visit o.right, collector
335
326
  end
336
327
  collector << ")"
@@ -340,7 +331,7 @@ module ArelExtensions
340
331
  def visit_Arel_Nodes_Regexp o, collector
341
332
  collector << " REGEXP_LIKE("
342
333
  collector = visit o.left, collector
343
- collector << COMMA
334
+ collector << Arel::Visitors::Oracle::COMMA
344
335
  collector = visit o.right, collector
345
336
  collector << ')'
346
337
  collector
@@ -349,7 +340,7 @@ module ArelExtensions
349
340
  def visit_Arel_Nodes_NotRegexp o, collector
350
341
  collector << " NOT REGEXP_LIKE("
351
342
  collector = visit o.left, collector
352
- collector << COMMA
343
+ collector << Arel::Visitors::Oracle::COMMA
353
344
  collector = visit o.right, collector
354
345
  collector << ')'
355
346
  collector
@@ -358,7 +349,7 @@ module ArelExtensions
358
349
  def visit_ArelExtensions_Nodes_Locate o, collector
359
350
  collector << "INSTR("
360
351
  o.expressions.each_with_index { |arg, i|
361
- collector << COMMA if i != 0
352
+ collector << Arel::Visitors::Oracle::COMMA unless i == 0
362
353
  collector = visit arg, collector
363
354
  }
364
355
  collector << ")"
@@ -368,7 +359,7 @@ module ArelExtensions
368
359
  def visit_ArelExtensions_Nodes_Substring o, collector
369
360
  collector << "SUBSTR("
370
361
  o.expressions.each_with_index { |arg, i|
371
- collector << COMMA if i != 0
362
+ collector << Arel::Visitors::Oracle::COMMA unless i == 0
372
363
  collector = visit arg, collector
373
364
  }
374
365
  collector << ")"
@@ -387,11 +378,11 @@ module ArelExtensions
387
378
  if o.type_of_attribute(o.left) == :text
388
379
  collector << 'dbms_lob.SUBSTR('
389
380
  collector = visit o.left, collector
390
- collector << COMMA
381
+ collector << Arel::Visitors::Oracle::COMMA
391
382
  collector << 'COALESCE(dbms_lob.GETLENGTH('
392
383
  collector = visit o.left, collector
393
384
  collector << "), 0)"
394
- collector << COMMA
385
+ collector << Arel::Visitors::Oracle::COMMA
395
386
  collector << '1)'
396
387
  else
397
388
  collector = visit o.left, collector
@@ -438,25 +429,28 @@ module ArelExtensions
438
429
  def visit_ArelExtensions_Nodes_DateAdd o, collector
439
430
  collector << '('
440
431
  collector = visit o.left, collector
441
- collector << ' + ' # (o.right.value >= 0 ? ' + ' : ' - ')
432
+ collector << ' + '# (o.right.value >= 0 ? ' + ' : ' - ')
442
433
  collector = visit o.oracle_value(o.right), collector
443
434
  collector << ')'
444
435
  collector
445
436
  end
446
437
 
447
438
  def visit_ArelExtensions_Nodes_Format o, collector
448
- fmt = ArelExtensions::Visitors::strftime_to_format(o.iso_format, DATE_FORMAT_DIRECTIVES)
449
439
  collector << "TO_CHAR("
450
440
  collector = visit o.left, collector
451
- collector << COMMA
452
- collector = visit Arel::Nodes.build_quoted(fmt), collector
441
+ collector << Arel::Visitors::Oracle::COMMA
442
+
443
+ f = o.iso_format.gsub(/\ (\w+)/, ' "\1"')
444
+ Arel::Visitors::Oracle::DATE_FORMAT_DIRECTIVES.each { |d, r| f.gsub!(d, r) }
445
+ collector = visit Arel::Nodes.build_quoted(f), collector
446
+
453
447
  collector << ")"
454
448
  collector
455
449
  end
456
450
 
457
451
  def visit_ArelExtensions_Nodes_Repeat o, collector
458
452
  collector << "LPAD("
459
- collector = visit o.expressions[0], collector # can't put empty string, otherwise it wouldn't work
453
+ collector = visit o.expressions[0], collector #can't put empty string, otherwise it wouldn't work
460
454
  collector << Arel::Visitors::ToSql::COMMA
461
455
  collector = visit o.expressions[1], collector
462
456
  collector << Arel::Visitors::ToSql::COMMA
@@ -465,24 +459,26 @@ module ArelExtensions
465
459
  collector
466
460
  end
467
461
 
468
- # add primary_key if not present, avoid zip
462
+ # add primary_key if not present, avoid zip
469
463
  if Arel::VERSION.to_i < 7
470
464
  def visit_ArelExtensions_InsertManager_BulkValues o, collector
471
465
  collector << "("
472
466
  o.left.each_with_index do |row, idx| # values
473
467
  collector << " UNION ALL " if idx != 0
474
- collector << "(SELECT "
475
- len = row.length - 1
476
- row.zip(o.cols).each_with_index { |(value, attr), i|
477
- case value
478
- when Arel::Nodes::SqlLiteral, Arel::Nodes::BindParam
479
- collector = visit value, collector
480
- else
481
- collector << quote(value, attr && column_for(attr)).to_s
482
- end
483
- collector << COMMA unless i == len
484
- }
485
- collector << ' FROM DUAL)'
468
+ collector << "(SELECT "
469
+ v = Arel::Nodes::Values.new(row, o.cols)
470
+ len = v.expressions.length - 1
471
+ v.expressions.each_with_index { |value, i|
472
+ case value
473
+ when Arel::Nodes::SqlLiteral, Arel::Nodes::BindParam
474
+ collector = visit value, collector
475
+ else
476
+ attr = v.columns[i]
477
+ collector << quote(value, attr && column_for(attr)).to_s
478
+ end
479
+ collector << Arel::Visitors::Oracle::COMMA unless i == len
480
+ }
481
+ collector << ' FROM DUAL)'
486
482
  end
487
483
  collector << ")"
488
484
  collector
@@ -494,16 +490,15 @@ module ArelExtensions
494
490
  collector << " UNION ALL " if idx != 0
495
491
  collector << "(SELECT "
496
492
  len = row.length - 1
497
- row.zip(o.cols).each_with_index { |(value, attr), i|
493
+ row.each_with_index { |value, i|
494
+ attr = o.cols[i]
498
495
  case value
499
496
  when Arel::Nodes::SqlLiteral, Arel::Nodes::BindParam
500
497
  collector = visit value, collector
501
- when Integer
502
- collector << value.to_s
503
498
  else
504
499
  collector << (attr && attr.able_to_type_cast? ? quote(attr.type_cast_for_database(value)) : quote(value).to_s)
505
500
  end
506
- collector << COMMA unless i == len
501
+ collector << Arel::Visitors::Oracle::COMMA unless i == len
507
502
  }
508
503
  collector << ' FROM DUAL)'
509
504
  end
@@ -562,7 +557,7 @@ module ArelExtensions
562
557
  end
563
558
 
564
559
 
565
- alias_method(:old_visit_Arel_Nodes_SelectStatement, :visit_Arel_Nodes_SelectStatement) rescue nil
560
+ alias_method :old_visit_Arel_Nodes_SelectStatement, :visit_Arel_Nodes_SelectStatement
566
561
  def visit_Arel_Nodes_SelectStatement o, collector
567
562
  if !(collector.value.blank? || (collector.value.is_a?(Array) && collector.value[0].blank?)) && o.limit.blank? && o.offset.blank?
568
563
  o = o.dup
@@ -571,7 +566,7 @@ module ArelExtensions
571
566
  old_visit_Arel_Nodes_SelectStatement(o,collector)
572
567
  end
573
568
 
574
- alias_method(:old_visit_Arel_Nodes_TableAlias, :visit_Arel_Nodes_TableAlias) rescue nil
569
+ alias_method :old_visit_Arel_Nodes_TableAlias, :visit_Arel_Nodes_TableAlias
575
570
  def visit_Arel_Nodes_TableAlias o, collector
576
571
  if o.name.length > 30
577
572
  o = Arel::Table.new(o.table_name).alias(Base64.urlsafe_encode64(Digest::MD5.new.digest(o.name)).tr('=', '').tr('-', '_'))
@@ -579,7 +574,7 @@ module ArelExtensions
579
574
  old_visit_Arel_Nodes_TableAlias(o,collector)
580
575
  end
581
576
 
582
- alias_method(:old_visit_Arel_Nodes_As, :visit_Arel_Nodes_As) rescue nil
577
+ alias_method :old_visit_Arel_Nodes_As, :visit_Arel_Nodes_As
583
578
  def visit_Arel_Nodes_As o, collector
584
579
  if o.left.is_a?(Arel::Nodes::Binary)
585
580
  collector << '('
@@ -599,7 +594,7 @@ module ArelExtensions
599
594
  visit_Arel_Nodes_As o, collector
600
595
  end
601
596
 
602
- alias_method(:old_visit_Arel_Attributes_Attribute, :visit_Arel_Attributes_Attribute) rescue nil
597
+ alias_method :old_visit_Arel_Attributes_Attribute, :visit_Arel_Attributes_Attribute
603
598
  def visit_Arel_Attributes_Attribute o, collector
604
599
  join_name = o.relation.table_alias || o.relation.name
605
600
  if join_name.length > 30
@@ -608,9 +603,10 @@ module ArelExtensions
608
603
  collector << "#{quote_table_name join_name}.#{quote_column_name o.name}"
609
604
  end
610
605
 
606
+
611
607
  def visit_ArelExtensions_Nodes_FormattedNumber o, collector
612
608
  col = o.left.coalesce(0)
613
- comma = NUMBER_COMMA_MAPPING[o.locale] || '.,'
609
+ comma = Arel::Visitors::Oracle::NUMBER_COMMA_MAPPING[o.locale] || '.,'
614
610
  comma_in_format = o.precision == 0 ? '' : 'D'
615
611
  nines_after = (1..o.precision-1).map{'9'}.join('')+'0'
616
612
  if comma.length == 1
@@ -687,6 +683,7 @@ module ArelExtensions
687
683
  collector << ')'
688
684
  collector
689
685
  end
686
+
690
687
  end
691
688
  end
692
689
  end
@@ -1,7 +1,19 @@
1
1
  module ArelExtensions
2
2
  module Visitors
3
+
3
4
  Arel::Visitors.send(:remove_const,'Oracle12') if Arel::Visitors.const_defined?('Oracle12')
4
5
  Arel::Visitors.const_set('Oracle12',Class.new(Arel::Visitors::Oracle)).class_eval do
6
+ def visit_Arel_Nodes_SelectStatement(o, collector)
7
+ # Oracle does not allow LIMIT clause with select for update
8
+ if o.limit && o.lock
9
+ raise ArgumentError, <<-MSG
10
+ 'Combination of limit and lock is not supported.
11
+ because generated SQL statements
12
+ `SELECT FOR UPDATE and FETCH FIRST n ROWS` generates ORA-02014.`
13
+ MSG
14
+ end
15
+ super
16
+ end
5
17
 
6
18
  def visit_Arel_Nodes_SelectOptions(o, collector)
7
19
  collector = maybe_visit o.offset, collector
@@ -56,7 +68,7 @@ module ArelExtensions
56
68
  if i != 0
57
69
  collector << Arel::Visitors::MySQL::COMMA
58
70
  end
59
- collector = visit v, collector
71
+ collector = visit v, collector
60
72
  end
61
73
  collector << ')'
62
74
  when Hash
@@ -72,7 +84,7 @@ module ArelExtensions
72
84
  collector << 'FORMAT JSON'
73
85
  end
74
86
  collector << ')'
75
- when String, Numeric, TrueClass, FalseClass
87
+ when String,Numeric,TrueClass,FalseClass
76
88
  collector = visit Arel::Nodes.build_quoted("#{o.dict}"), collector
77
89
  collector << ' FORMAT JSON'
78
90
  when NilClass
@@ -85,6 +97,7 @@ module ArelExtensions
85
97
  end
86
98
  collector
87
99
  end
100
+
88
101
  end
89
102
  end
90
103
  end
@@ -1,29 +1,20 @@
1
1
  module ArelExtensions
2
2
  module Visitors
3
- class Arel::Visitors::PostgreSQL
4
- DATE_MAPPING = {
5
- 'd' => 'DAY', 'm' => 'MONTH', 'w' => 'WEEK', 'y' => 'YEAR', 'wd' => 'DOW',
6
- 'h' => 'HOUR', 'mn' => 'MINUTE', 's' => 'SECOND'
7
- }.freeze
8
-
9
- DATE_FORMAT_DIRECTIVES = {
10
- '%Y' => 'IYYY', '%C' => 'CC', '%y' => 'YY',
11
- '%m' => 'MM', '%B' => 'Month', '%^B' => 'MONTH', '%b' => 'Mon', '%^b' => 'MON',
3
+ Arel::Visitors::PostgreSQL.class_eval do
4
+ Arel::Visitors::PostgreSQL::DATE_MAPPING = {'d' => 'DAY', 'm' => 'MONTH', 'w' => 'WEEK', 'y' => 'YEAR', 'wd' => 'DOW', 'h' => 'HOUR', 'mn' => 'MINUTE', 's' => 'SECOND'}
5
+ Arel::Visitors::PostgreSQL::DATE_FORMAT_DIRECTIVES = {
6
+ '%Y' => 'IYYY', '%C' => 'CC', '%y' => 'YY', '%m' => 'MM', '%B' => 'Month', '%^B' => 'MONTH', '%b' => 'Mon', '%^b' => 'MON',
12
7
  '%d' => 'DD', '%e' => 'FMDD', '%j' => 'DDD', '%w' => '', '%A' => 'Day', # day, weekday
13
8
  '%H' => 'HH24', '%k' => '', '%I' => 'HH', '%l' => '', '%P' => 'am', '%p' => 'AM', # hours
14
- '%M' => 'MI', '%S' => 'SS', '%L' => 'MS', '%N' => 'US', '%z' => 'tz', # seconds, subseconds
15
- '%%' => '%',
16
- }.freeze
17
-
18
- NUMBER_COMMA_MAPPING = {
19
- 'en_US' => '.,', 'fr_FR' => ',', 'sv_SE' => ', '
20
- }.freeze
9
+ '%M' => 'MI', '%S' => 'SS', '%L' => 'MS', '%N' => 'US', '%z' => 'tz' # seconds, subseconds
10
+ }
11
+ Arel::Visitors::PostgreSQL::NUMBER_COMMA_MAPPING = { 'en_US' => '.,', 'fr_FR' => ',', 'sv_SE' => ', ' }
21
12
 
22
13
  def visit_ArelExtensions_Nodes_Rand o, collector
23
14
  collector << "RANDOM("
24
- if (o.left != nil && o.right != nil)
15
+ if(o.left != nil && o.right != nil)
25
16
  collector = visit o.left, collector
26
- collector << COMMA
17
+ collector << Arel::Visitors::PostgreSQL::COMMA
27
18
  collector = isit o.right, collector
28
19
  end
29
20
  collector << ")"
@@ -33,7 +24,7 @@ module ArelExtensions
33
24
  def visit_ArelExtensions_Nodes_Power o, collector
34
25
  collector << "POWER("
35
26
  o.expressions.each_with_index { |arg, i|
36
- collector << Arel::Visitors::ToSql::COMMA if i != 0
27
+ collector << Arel::Visitors::ToSql::COMMA unless i == 0
37
28
  collector = visit arg, collector
38
29
  }
39
30
  collector << ")"
@@ -43,7 +34,7 @@ module ArelExtensions
43
34
  def visit_ArelExtensions_Nodes_Log10 o, collector
44
35
  collector << "LOG("
45
36
  o.expressions.each_with_index { |arg, i|
46
- collector << Arel::Visitors::ToSql::COMMA if i != 0
37
+ collector << Arel::Visitors::ToSql::COMMA unless i == 0
47
38
  collector = visit arg, collector
48
39
  }
49
40
  collector << ")"
@@ -77,7 +68,7 @@ module ArelExtensions
77
68
  collector
78
69
  end
79
70
 
80
- alias_method(:old_visit_Arel_Nodes_As, :visit_Arel_Nodes_As) rescue nil
71
+ alias_method :old_visit_Arel_Nodes_As, :visit_Arel_Nodes_As
81
72
  def visit_Arel_Nodes_As o, collector
82
73
  if o.left.is_a?(Arel::Nodes::Binary)
83
74
  collector << '('
@@ -92,49 +83,23 @@ module ArelExtensions
92
83
  collector
93
84
  end
94
85
 
95
- def visit_Aggregate_For_AggregateFunction o, collector
96
- if !o.order.blank? || !o.group.blank?
97
- collector << " OVER ("
98
- if !o.group.blank?
99
- collector << " PARTITION BY "
100
- o.group.each_with_index do |group, i|
101
- collector << COMMA if i != 0
102
- visit group, collector
103
- end
104
- end
105
- if !o.order.blank?
106
- collector << " ORDER BY "
107
- o.order.each_with_index do |order, i|
108
- collector << COMMA if i != 0
109
- visit order, collector
110
- end
111
- end
112
- collector << ")"
113
- end
114
- collector
115
- end
116
-
117
86
  def visit_ArelExtensions_Nodes_GroupConcat o, collector
118
87
  collector << "array_to_string(array_agg("
119
88
  collector = visit o.left, collector
120
- if o.order && !o.order.blank?
121
- collector << " ORDER BY"
122
- o.order.each_with_index do |order, i|
123
- collector << COMMA if i != 0
124
- collector << " "
125
- visit order, collector
89
+ if !o.orders.blank?
90
+ collector << ' ORDER BY '
91
+ o.orders.each_with_index do |order,i|
92
+ collector << Arel::Visitors::PostgreSQL::COMMA unless i == 0
93
+ collector = visit order, collector
126
94
  end
127
95
  end
128
96
  collector << ")"
129
- o.order = nil
130
- visit_Aggregate_For_AggregateFunction o, collector
131
- collector << COMMA
132
- collector =
133
- if o.separator && o.separator != 'NULL'
134
- visit o.separator, collector
135
- else
136
- visit Arel::Nodes.build_quoted(','), collector
137
- end
97
+ collector << Arel::Visitors::PostgreSQL::COMMA
98
+ if o.right && o.right != 'NULL'
99
+ collector = visit o.right, collector
100
+ else
101
+ collector = visit Arel::Nodes.build_quoted(','), collector
102
+ end
138
103
  collector << ")"
139
104
  collector
140
105
  end
@@ -167,11 +132,14 @@ module ArelExtensions
167
132
  end
168
133
 
169
134
  def visit_ArelExtensions_Nodes_Format o, collector
170
- fmt = ArelExtensions::Visitors::strftime_to_format(o.iso_format, DATE_FORMAT_DIRECTIVES)
171
135
  collector << "TO_CHAR("
172
136
  collector = visit o.left, collector
173
- collector << COMMA
174
- collector = visit Arel::Nodes.build_quoted(fmt), collector
137
+ collector << Arel::Visitors::PostgreSQL::COMMA
138
+
139
+ f = o.iso_format.dup
140
+ Arel::Visitors::PostgreSQL::DATE_FORMAT_DIRECTIVES.each { |d, r| f.gsub!(d, r) }
141
+ collector = visit Arel::Nodes.build_quoted(f), collector
142
+
175
143
  collector << ")"
176
144
  collector
177
145
  end
@@ -179,7 +147,7 @@ module ArelExtensions
179
147
  def visit_ArelExtensions_Nodes_Repeat o, collector
180
148
  collector << "REPEAT("
181
149
  o.expressions.each_with_index { |arg, i|
182
- collector << Arel::Visitors::ToSql::COMMA if i != 0
150
+ collector << Arel::Visitors::ToSql::COMMA unless i == 0
183
151
  collector = visit arg, collector
184
152
  }
185
153
  collector << ")"
@@ -237,7 +205,7 @@ module ArelExtensions
237
205
 
238
206
  def visit_ArelExtensions_Nodes_DateAdd o, collector
239
207
  collector = visit o.left, collector
240
- collector << ' + ' # (o.right.value >= 0 ? ' + ' : ' - ')
208
+ collector << ' + ' #(o.right.value >= 0 ? ' + ' : ' - ')
241
209
  collector = visit o.postgresql_value(o.right), collector
242
210
  collector
243
211
  end
@@ -251,7 +219,7 @@ module ArelExtensions
251
219
  end
252
220
  collector = visit o.right, collector
253
221
  collector << (o.right_node_type == :date ? '::date' : '::timestamp')
254
- collector << COMMA
222
+ collector << Arel::Visitors::PostgreSQL::COMMA
255
223
  collector = visit o.left, collector
256
224
  collector << (o.left_node_type == :date ? '::date' : '::timestamp')
257
225
  collector << ")"
@@ -279,11 +247,11 @@ module ArelExtensions
279
247
  collector << "("
280
248
  collector = visit o.right, collector
281
249
  collector << ")"
282
- collector << " * (INTERVAL '1' #{DATE_MAPPING[o.left[0..-2]]})"
250
+ collector << " * (INTERVAL '1' #{Arel::Visitors::PostgreSQL::DATE_MAPPING[o.left[0..-2]]})"
283
251
  return collector
284
252
  end
285
253
  end
286
- collector << "EXTRACT(#{DATE_MAPPING[o.left]} FROM "
254
+ collector << "EXTRACT(#{Arel::Visitors::PostgreSQL::DATE_MAPPING[o.left]} FROM "
287
255
  collector = visit o.right, collector
288
256
  collector << ")"
289
257
  collector << " * (INTERVAL '1' #{interval})" if interval && o.with_interval
@@ -302,29 +270,13 @@ module ArelExtensions
302
270
  def visit_ArelExtensions_Nodes_Substring o, collector
303
271
  collector << "SUBSTR("
304
272
  o.expressions.each_with_index { |arg, i|
305
- collector << COMMA if i != 0
273
+ collector << Arel::Visitors::PostgreSQL::COMMA unless i == 0
306
274
  collector = visit arg, collector
307
275
  }
308
276
  collector << ")"
309
277
  collector
310
278
  end
311
279
 
312
- def visit_ArelExtensions_Nodes_RegexpReplace o, collector
313
- collector << "REGEXP_REPLACE("
314
- visit o.left, collector
315
- collector << Arel::Visitors::ToSql::COMMA
316
- tab = o.pattern.inspect+ 'g' # Make it always global
317
- pattern = tab.split('/')[1..-2].join('/')
318
- flags = tab.split('/')[-1]
319
- visit Arel::Nodes.build_quoted(pattern), collector
320
- collector << Arel::Visitors::ToSql::COMMA
321
- visit o.substitute, collector
322
- collector << Arel::Visitors::ToSql::COMMA
323
- visit Arel::Nodes.build_quoted(flags+"g"), collector
324
- collector << ")"
325
- collector
326
- end
327
-
328
280
  def visit_ArelExtensions_Nodes_IsNull o, collector
329
281
  collector = visit o.expr, collector
330
282
  collector << ' IS NULL'
@@ -341,7 +293,6 @@ module ArelExtensions
341
293
  collector << "sum("
342
294
  collector = visit o.expr, collector
343
295
  collector << ")"
344
- visit_Aggregate_For_AggregateFunction o, collector
345
296
  collector
346
297
  end
347
298
 
@@ -356,8 +307,6 @@ module ArelExtensions
356
307
  as_attr = case o.as_attr
357
308
  when :string
358
309
  Arel::Nodes::SqlLiteral.new('varchar')
359
- when :text, :ntext
360
- Arel::Nodes::SqlLiteral.new('text')
361
310
  when :time
362
311
  Arel::Nodes::SqlLiteral.new('time')
363
312
  when :int
@@ -386,8 +335,8 @@ module ArelExtensions
386
335
 
387
336
  def visit_ArelExtensions_Nodes_FormattedNumber o, collector
388
337
  col = o.left.coalesce(0)
389
- comma = o.precision == 0 ? '' : (NUMBER_COMMA_MAPPING[o.locale][0] || '.')
390
- thousand_separator = NUMBER_COMMA_MAPPING[o.locale][1] || (NUMBER_COMMA_MAPPING[o.locale] ? '' : 'G')
338
+ comma = o.precision == 0 ? '' : (Arel::Visitors::PostgreSQL::NUMBER_COMMA_MAPPING[o.locale][0] || '.')
339
+ thousand_separator = Arel::Visitors::PostgreSQL::NUMBER_COMMA_MAPPING[o.locale][1] || (Arel::Visitors::PostgreSQL::NUMBER_COMMA_MAPPING[o.locale] ? '' : 'G')
391
340
  nines_after = (1..o.precision).map{'9'}.join('')
392
341
  nines_before = ("999#{thousand_separator}"*4+"990")
393
342
 
@@ -396,28 +345,27 @@ module ArelExtensions
396
345
  else(o.flags.include?('+') ? '+' : (o.flags.include?(' ') ? ' ' : ''))
397
346
  sign_length = ArelExtensions::Nodes::Length.new([sign])
398
347
 
399
- number =
400
- if o.scientific_notation
401
- ArelExtensions::Nodes::Concat.new([
402
- Arel::Nodes::NamedFunction.new('TRIM',[
403
- Arel::Nodes::NamedFunction.new('TO_CHAR',[
404
- col.abs/Arel::Nodes.build_quoted(10).pow(col.abs.log10.floor),
405
- Arel::Nodes.build_quoted('FM'+nines_before+'"'+comma+'"V'+nines_after)
406
- ])]),
407
- o.type,
408
- Arel::Nodes::NamedFunction.new('TRIM',[
409
- Arel::Nodes::NamedFunction.new('TO_CHAR',[
410
- col.abs.log10.floor,
411
- Arel::Nodes.build_quoted('FM'+nines_before)
412
- ])])
413
- ])
414
- else
415
- Arel::Nodes::NamedFunction.new('TRIM',[
416
- Arel::Nodes::NamedFunction.new('TO_CHAR',[
417
- Arel::Nodes.build_quoted(col.abs),
418
- Arel::Nodes.build_quoted('FM'+nines_before+'"'+comma+'"V'+nines_after)
419
- ])])
420
- end
348
+ if o.scientific_notation
349
+ number = ArelExtensions::Nodes::Concat.new([
350
+ Arel::Nodes::NamedFunction.new('TRIM',[
351
+ Arel::Nodes::NamedFunction.new('TO_CHAR',[
352
+ col.abs/Arel::Nodes.build_quoted(10).pow(col.abs.log10.floor),
353
+ Arel::Nodes.build_quoted('FM'+nines_before+'"'+comma+'"V'+nines_after)
354
+ ])]),
355
+ o.type,
356
+ Arel::Nodes::NamedFunction.new('TRIM',[
357
+ Arel::Nodes::NamedFunction.new('TO_CHAR',[
358
+ col.abs.log10.floor,
359
+ Arel::Nodes.build_quoted('FM'+nines_before)
360
+ ])])
361
+ ])
362
+ else
363
+ number = Arel::Nodes::NamedFunction.new('TRIM',[
364
+ Arel::Nodes::NamedFunction.new('TO_CHAR',[
365
+ Arel::Nodes.build_quoted(col.abs),
366
+ Arel::Nodes.build_quoted('FM'+nines_before+'"'+comma+'"V'+nines_after)
367
+ ])])
368
+ end
421
369
 
422
370
  repeated_char = (o.width == 0) ? Arel::Nodes.build_quoted('') : ArelExtensions::Nodes::Case.new().
423
371
  when(Arel::Nodes.build_quoted(o.width).abs-(number.length+sign_length)>0).
@@ -441,7 +389,7 @@ module ArelExtensions
441
389
  end
442
390
 
443
391
 
444
- alias_method(:old_visit_Arel_Nodes_SelectStatement, :visit_Arel_Nodes_SelectStatement) rescue nil
392
+ alias_method :old_visit_Arel_Nodes_SelectStatement, :visit_Arel_Nodes_SelectStatement
445
393
  def visit_Arel_Nodes_SelectStatement o, collector
446
394
 
447
395
  if !(collector.value.blank? || (collector.value.is_a?(Array) && collector.value[0].blank?)) && o.limit.blank? && o.offset.blank?
@@ -451,7 +399,7 @@ module ArelExtensions
451
399
  old_visit_Arel_Nodes_SelectStatement(o,collector)
452
400
  end
453
401
 
454
- alias_method(:old_visit_Arel_Nodes_TableAlias, :visit_Arel_Nodes_TableAlias) rescue nil
402
+ alias_method :old_visit_Arel_Nodes_TableAlias, :visit_Arel_Nodes_TableAlias
455
403
  def visit_Arel_Nodes_TableAlias o, collector
456
404
  if o.name.length > 63
457
405
  o = Arel::Table.new(o.table_name).alias(Arel.shorten(o.name))
@@ -459,7 +407,7 @@ module ArelExtensions
459
407
  old_visit_Arel_Nodes_TableAlias(o,collector)
460
408
  end
461
409
 
462
- alias_method(:old_visit_Arel_Attributes_Attribute, :visit_Arel_Attributes_Attribute) rescue nil
410
+ alias_method :old_visit_Arel_Attributes_Attribute, :visit_Arel_Attributes_Attribute
463
411
  def visit_Arel_Attributes_Attribute o, collector
464
412
  join_name = o.relation.table_alias || o.relation.name
465
413
  if join_name.length > 63
@@ -472,7 +420,6 @@ module ArelExtensions
472
420
  collector << (o.unbiased_estimator ? "STDDEV_SAMP(" : "STDDEV_POP(")
473
421
  visit o.left, collector
474
422
  collector << ")"
475
- visit_Aggregate_For_AggregateFunction o, collector
476
423
  collector
477
424
  end
478
425
 
@@ -480,7 +427,6 @@ module ArelExtensions
480
427
  collector << (o.unbiased_estimator ? "VAR_SAMP(" : "VAR_POP(")
481
428
  visit o.left, collector
482
429
  collector << ")"
483
- visit_Aggregate_For_AggregateFunction o, collector
484
430
  collector
485
431
  end
486
432
 
@@ -492,7 +438,7 @@ module ArelExtensions
492
438
  if i != 0
493
439
  collector << Arel::Visitors::MySQL::COMMA
494
440
  end
495
- collector = visit v, collector
441
+ collector = visit v, collector
496
442
  end
497
443
  collector << '])'
498
444
  when Hash
@@ -577,6 +523,7 @@ module ArelExtensions
577
523
  end
578
524
  collector
579
525
  end
526
+
580
527
  end
581
528
  end
582
529
  end