arel_extensions 2.0.1 → 2.0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -4
  3. data/.travis.yml +59 -91
  4. data/Gemfile +14 -19
  5. data/README.md +17 -12
  6. data/Rakefile +38 -27
  7. data/appveyor.yml +1 -1
  8. data/arel_extensions.gemspec +2 -2
  9. data/functions.html +3 -3
  10. data/gemfiles/rails4.gemfile +1 -1
  11. data/gemfiles/rails6.gemfile +30 -0
  12. data/gemspec_v2/arel_extensions-v2.gemspec +28 -0
  13. data/generate_gems.sh +14 -0
  14. data/init/mssql.sql +4 -4
  15. data/init/mysql.sql +38 -38
  16. data/init/postgresql.sql +21 -21
  17. data/lib/arel_extensions.rb +63 -19
  18. data/lib/arel_extensions/attributes.rb +0 -1
  19. data/lib/arel_extensions/boolean_functions.rb +38 -13
  20. data/lib/arel_extensions/common_sql_functions.rb +5 -4
  21. data/lib/arel_extensions/comparators.rb +4 -2
  22. data/lib/arel_extensions/insert_manager.rb +15 -13
  23. data/lib/arel_extensions/math.rb +3 -3
  24. data/lib/arel_extensions/math_functions.rb +10 -5
  25. data/lib/arel_extensions/nodes.rb +1 -1
  26. data/lib/arel_extensions/nodes/abs.rb +0 -0
  27. data/lib/arel_extensions/nodes/aggregate_function.rb +14 -0
  28. data/lib/arel_extensions/nodes/case.rb +8 -4
  29. data/lib/arel_extensions/nodes/ceil.rb +0 -0
  30. data/lib/arel_extensions/nodes/coalesce.rb +2 -2
  31. data/lib/arel_extensions/nodes/collate.rb +1 -1
  32. data/lib/arel_extensions/nodes/concat.rb +6 -13
  33. data/lib/arel_extensions/nodes/date_diff.rb +3 -5
  34. data/lib/arel_extensions/nodes/duration.rb +0 -2
  35. data/lib/arel_extensions/nodes/find_in_set.rb +0 -0
  36. data/lib/arel_extensions/nodes/floor.rb +0 -0
  37. data/lib/arel_extensions/nodes/format.rb +8 -8
  38. data/lib/arel_extensions/nodes/formatted_number.rb +23 -23
  39. data/lib/arel_extensions/nodes/function.rb +2 -0
  40. data/lib/arel_extensions/nodes/is_null.rb +0 -0
  41. data/lib/arel_extensions/nodes/json.rb +43 -30
  42. data/lib/arel_extensions/nodes/length.rb +0 -0
  43. data/lib/arel_extensions/nodes/locate.rb +0 -0
  44. data/lib/arel_extensions/nodes/matches.rb +4 -4
  45. data/lib/arel_extensions/nodes/power.rb +6 -5
  46. data/lib/arel_extensions/nodes/rand.rb +0 -0
  47. data/lib/arel_extensions/nodes/repeat.rb +2 -2
  48. data/lib/arel_extensions/nodes/replace.rb +24 -6
  49. data/lib/arel_extensions/nodes/round.rb +5 -5
  50. data/lib/arel_extensions/nodes/soundex.rb +16 -15
  51. data/lib/arel_extensions/nodes/std.rb +19 -21
  52. data/lib/arel_extensions/nodes/substring.rb +8 -15
  53. data/lib/arel_extensions/nodes/sum.rb +7 -0
  54. data/lib/arel_extensions/nodes/trim.rb +3 -3
  55. data/lib/arel_extensions/nodes/union.rb +2 -3
  56. data/lib/arel_extensions/nodes/union_all.rb +0 -1
  57. data/lib/arel_extensions/nodes/wday.rb +0 -0
  58. data/lib/arel_extensions/null_functions.rb +2 -2
  59. data/lib/arel_extensions/predications.rb +35 -33
  60. data/lib/arel_extensions/set_functions.rb +2 -2
  61. data/lib/arel_extensions/string_functions.rb +34 -12
  62. data/lib/arel_extensions/tasks.rb +5 -5
  63. data/lib/arel_extensions/version.rb +1 -1
  64. data/lib/arel_extensions/visitors.rb +1 -1
  65. data/lib/arel_extensions/visitors/ibm_db.rb +1 -1
  66. data/lib/arel_extensions/visitors/mssql.rb +14 -13
  67. data/lib/arel_extensions/visitors/mysql.rb +89 -39
  68. data/lib/arel_extensions/visitors/oracle.rb +15 -15
  69. data/lib/arel_extensions/visitors/oracle12.rb +1 -1
  70. data/lib/arel_extensions/visitors/postgresql.rb +78 -32
  71. data/lib/arel_extensions/visitors/sqlite.rb +61 -53
  72. data/lib/arel_extensions/visitors/to_sql.rb +93 -73
  73. data/test/arelx_test_helper.rb +28 -0
  74. data/test/real_db_test.rb +1 -1
  75. data/test/support/fake_record.rb +1 -1
  76. data/test/test_comparators.rb +9 -8
  77. data/test/visitors/test_bulk_insert_oracle.rb +8 -7
  78. data/test/visitors/test_bulk_insert_sqlite.rb +9 -8
  79. data/test/visitors/test_bulk_insert_to_sql.rb +8 -10
  80. data/test/visitors/test_oracle.rb +41 -40
  81. data/test/visitors/test_to_sql.rb +367 -193
  82. data/test/with_ar/all_agnostic_test.rb +68 -35
  83. data/test/with_ar/insert_agnostic_test.rb +3 -2
  84. data/test/with_ar/test_bulk_sqlite.rb +6 -5
  85. data/test/with_ar/test_math_sqlite.rb +4 -4
  86. data/test/with_ar/test_string_mysql.rb +4 -6
  87. data/test/with_ar/test_string_sqlite.rb +3 -7
  88. data/version_v1.rb +3 -0
  89. data/version_v2.rb +3 -0
  90. metadata +14 -7
  91. data/test/helper.rb +0 -18
@@ -68,7 +68,7 @@ module ArelExtensions
68
68
  if i != 0
69
69
  collector << Arel::Visitors::MySQL::COMMA
70
70
  end
71
- collector = visit v, collector
71
+ collector = visit v, collector
72
72
  end
73
73
  collector << ')'
74
74
  when Hash
@@ -1,6 +1,6 @@
1
1
  module ArelExtensions
2
2
  module Visitors
3
- Arel::Visitors::PostgreSQL.class_eval do
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.orders.blank?
90
- collector << ' ORDER BY '
91
- o.orders.each_with_index do |order,i|
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 = visit order, 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
- if o.right && o.right != 'NULL'
99
- collector = visit o.right, collector
100
- else
101
- collector = visit Arel::Nodes.build_quoted(','), collector
102
- end
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,6 +303,22 @@ 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
323
  collector = visit o.expr, collector
282
324
  collector << ' IS NULL'
@@ -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
- 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
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 = visit v, collector
487
+ collector = visit v, collector
442
488
  end
443
489
  collector << '])'
444
490
  when Hash
@@ -1,6 +1,6 @@
1
1
  module ArelExtensions
2
2
  module Visitors
3
- Arel::Visitors::SQLite.class_eval do
3
+ class Arel::Visitors::SQLite
4
4
  Arel::Visitors::SQLite::DATE_MAPPING = {'d' => '%d', 'm' => '%m', 'w' => '%W', 'y' => '%Y', 'wd' => '%w', 'M' => '%M', 'h' => '%H', 'mn' => '%M', 's' => '%S'}
5
5
  Arel::Visitors::SQLite::DATE_FORMAT_DIRECTIVES = { # ISO C / POSIX
6
6
  '%Y' => '%Y', '%C' => '', '%y' => '%y', '%m' => '%m', '%B' => '%M', '%b' => '%b', '%^b' => '%b', # year, month
@@ -193,18 +193,28 @@ module ArelExtensions
193
193
  collector
194
194
  end
195
195
 
196
- # CASE WHEN ROUND(3.42,1) > round(3.42) THEN round(3.42) ELSE round(3.42)-1 END
197
- # OR CAST(3.14 AS INTEGER)
196
+ # CAST(
197
+ # CASE
198
+ # WHEN 3.42 >= 0 THEN CAST(3.42 AS INT)
199
+ # WHEN CAST(3.42 AS INT) = 3.42 THEN CAST(3.42 AS INT)
200
+ # ELSE CAST((3.42 - 1.0) AS INT)
201
+ # END
202
+ # AS FLOAT
203
+ # )
198
204
  def visit_ArelExtensions_Nodes_Floor o, collector
199
- collector << "CASE WHEN ROUND("
205
+ collector << "CAST(CASE WHEN "
200
206
  collector = visit o.left, collector
201
- collector << ", 1) > ROUND("
207
+ collector << " >= 0 THEN CAST("
202
208
  collector = visit o.left, collector
203
- collector << ") THEN ROUND("
209
+ collector << " AS INT) WHEN CAST("
204
210
  collector = visit o.left, collector
205
- collector << ") ELSE ROUND("
211
+ collector << " AS INT) = "
206
212
  collector = visit o.left, collector
207
- collector << ") - 1 END"
213
+ collector << " THEN CAST("
214
+ collector = visit o.left, collector
215
+ collector << " AS INT) ELSE CAST(("
216
+ collector = visit o.left, collector
217
+ collector << " - 1.0) AS INT) END AS FLOAT)"
208
218
  collector
209
219
  end
210
220
 
@@ -225,9 +235,8 @@ module ArelExtensions
225
235
  def visit_ArelExtensions_InsertManager_BulkValues o, collector
226
236
  o.left.each_with_index do |row, idx|
227
237
  collector << 'SELECT '
228
- v = Arel::Nodes::Values.new(row, o.cols)
229
- len = v.expressions.length - 1
230
- v.expressions.zip(v.columns).each_with_index { |(value, attr), i|
238
+ len = row.length - 1
239
+ row.zip(o.cols).each_with_index { |(value, attr), i|
231
240
  case value
232
241
  when Arel::Nodes::SqlLiteral, Arel::Nodes::BindParam
233
242
  collector = visit value.as(attr.name), collector
@@ -249,19 +258,24 @@ module ArelExtensions
249
258
  o.left.each_with_index do |row, idx|
250
259
  collector << 'SELECT '
251
260
  len = row.length - 1
252
- row.each_with_index { |value, i|
253
- attr = o.cols[i]
254
- case value
255
- when Arel::Nodes::SqlLiteral, Arel::Nodes::BindParam
256
- collector = visit value.as(attr.name), collector
257
- else
258
- collector << (attr && attr.able_to_type_cast? ? quote(attr.type_cast_for_database(value)) : quote(value).to_s)
259
- if idx == 0
260
- collector << " AS "
261
- collector << quote(attr.name)
261
+ row.zip(o.cols).each_with_index { |(value, attr), i|
262
+ case value
263
+ when Arel::Nodes::SqlLiteral, Arel::Nodes::BindParam
264
+ collector = visit value.as(attr.name), collector
265
+ when Integer
266
+ collector << value.to_s
267
+ if idx == 0
268
+ collector << " AS "
269
+ collector << quote(attr.name)
270
+ end
271
+ else
272
+ collector << (attr && attr.able_to_type_cast? ? quote(attr.type_cast_for_database(value)) : quote(value).to_s)
273
+ if idx == 0
274
+ collector << " AS "
275
+ collector << quote(attr.name)
276
+ end
262
277
  end
263
- end
264
- collector << Arel::Visitors::SQLite::COMMA unless i == len
278
+ collector << Arel::Visitors::SQLite::COMMA unless i == len
265
279
  }
266
280
  collector << ' UNION ALL ' unless idx == o.left.length - 1
267
281
  end
@@ -270,32 +284,36 @@ module ArelExtensions
270
284
  end
271
285
 
272
286
  def visit_ArelExtensions_Nodes_Union o, collector
273
- if o.left.is_a?(Arel::SelectManager)
274
- collector = visit o.left.ast, collector
275
- else
276
- collector = visit o.left, collector
277
- end
287
+ collector =
288
+ if o.left.is_a?(Arel::SelectManager)
289
+ visit o.left.ast, collector
290
+ else
291
+ visit o.left, collector
292
+ end
278
293
  collector << " UNION "
279
- if o.right.is_a?(Arel::SelectManager)
280
- collector = visit o.right.ast, collector
281
- else
282
- collector = visit o.right, collector
283
- end
294
+ collector =
295
+ if o.right.is_a?(Arel::SelectManager)
296
+ visit o.right.ast, collector
297
+ else
298
+ visit o.right, collector
299
+ end
284
300
  collector
285
301
  end
286
302
 
287
303
  def visit_ArelExtensions_Nodes_UnionAll o, collector
288
- if o.left.is_a?(Arel::SelectManager)
289
- collector = visit o.left.ast, collector
290
- else
291
- collector = visit o.left, collector
292
- end
304
+ collector =
305
+ if o.left.is_a?(Arel::SelectManager)
306
+ visit o.left.ast, collector
307
+ else
308
+ visit o.left, collector
309
+ end
293
310
  collector << " UNION ALL "
294
- if o.right.is_a?(Arel::SelectManager)
295
- collector = visit o.right.ast, collector
296
- else
297
- collector = visit o.right, collector
298
- end
311
+ collector =
312
+ if o.right.is_a?(Arel::SelectManager)
313
+ visit o.right.ast, collector
314
+ else
315
+ visit o.right, collector
316
+ end
299
317
  collector
300
318
  end
301
319
 
@@ -346,16 +364,6 @@ module ArelExtensions
346
364
  collector
347
365
  end
348
366
 
349
-
350
- alias_method :old_visit_Arel_Nodes_SelectStatement, :visit_Arel_Nodes_SelectStatement
351
- def visit_Arel_Nodes_SelectStatement o, collector
352
- if !collector.value.blank? && o.limit.blank?
353
- o = o.dup
354
- o.orders = []
355
- end
356
- old_visit_Arel_Nodes_SelectStatement(o,collector)
357
- end
358
-
359
367
  alias_method :old_visit_Arel_Nodes_As, :visit_Arel_Nodes_As
360
368
  def visit_Arel_Nodes_As o, collector
361
369
  if o.left.is_a?(Arel::Nodes::Binary)
@@ -1,7 +1,7 @@
1
1
  module ArelExtensions
2
2
  module Visitors
3
- Arel::Visitors::ToSql.class_eval do
4
- Arel::Visitors::ToSql::COMMA = ", "
3
+ class Arel::Visitors::ToSql
4
+ Arel::Visitors::ToSql::COMMA = ', ' unless defined?(Arel::Visitors::ToSql::COMMA)
5
5
 
6
6
  # Math Functions
7
7
  def visit_ArelExtensions_Nodes_Abs o, collector
@@ -53,14 +53,14 @@ module ArelExtensions
53
53
  collector << ")"
54
54
  collector
55
55
  end
56
-
56
+
57
57
  def visit_ArelExtensions_Nodes_Log10 o, collector
58
58
  collector << "LOG10("
59
59
  collector = visit o.left, collector
60
60
  collector << ")"
61
61
  collector
62
62
  end
63
-
63
+
64
64
  def visit_ArelExtensions_Nodes_Power o, collector
65
65
  collector << "POW("
66
66
  o.expressions.each_with_index { |arg, i|
@@ -71,6 +71,13 @@ module ArelExtensions
71
71
  collector
72
72
  end
73
73
 
74
+ def visit_ArelExtensions_Nodes_Sum o, collector
75
+ collector << "SUM("
76
+ collector = visit o.expr, collector
77
+ collector << ")"
78
+ collector
79
+ end
80
+
74
81
  # String functions
75
82
  def visit_ArelExtensions_Nodes_Concat o, collector
76
83
  collector << "CONCAT("
@@ -85,9 +92,9 @@ module ArelExtensions
85
92
  def visit_ArelExtensions_Nodes_GroupConcat o, collector
86
93
  collector << "GROUP_CONCAT("
87
94
  collector = visit o.left, collector
88
- if o.right && o.right != 'NULL'
95
+ if o.separator && o.separator != 'NULL'
89
96
  collector << Arel::Visitors::ToSql::COMMA
90
- collector = visit o.right, collector
97
+ collector = visit o.separator, collector
91
98
  end
92
99
  collector << ")"
93
100
  collector
@@ -128,14 +135,26 @@ module ArelExtensions
128
135
 
129
136
  def visit_ArelExtensions_Nodes_Replace o, collector
130
137
  collector << "REPLACE("
131
- o.expressions.each_with_index { |arg, i|
132
- collector << Arel::Visitors::ToSql::COMMA unless i == 0
133
- collector = visit arg, collector
134
- }
138
+ visit o.left, collector
139
+ collector << Arel::Visitors::ToSql::COMMA
140
+ visit o.pattern, collector
141
+ collector << Arel::Visitors::ToSql::COMMA
142
+ visit o.substitute, collector
143
+ collector << ")"
144
+ collector
145
+ end
146
+
147
+ def visit_ArelExtensions_Nodes_RegexpReplace o, collector
148
+ collector << "REGEXP_REPLACE("
149
+ visit o.left, collector
150
+ collector << Arel::Visitors::ToSql::COMMA
151
+ visit Arel::Nodes.build_quoted(o.pattern.to_s), collector
152
+ collector << Arel::Visitors::ToSql::COMMA
153
+ visit o.substitute, collector
135
154
  collector << ")"
136
155
  collector
137
156
  end
138
-
157
+
139
158
  def visit_ArelExtensions_Nodes_Repeat o, collector
140
159
  collector << "REPEAT("
141
160
  o.expressions.each_with_index { |arg, i|
@@ -270,12 +289,12 @@ module ArelExtensions
270
289
  as_attr = Arel::Nodes::SqlLiteral.new('int')
271
290
  when :decimal, :float, :number
272
291
  as_attr = Arel::Nodes::SqlLiteral.new('float')
273
- when :datetime
292
+ when :datetime
274
293
  as_attr = Arel::Nodes::SqlLiteral.new('datetime')
275
294
  when :time
276
295
  as_attr = Arel::Nodes::SqlLiteral.new('time')
277
- when :binary
278
- as_attr = Arel::Nodes::SqlLiteral.new('binary')
296
+ when :binary
297
+ as_attr = Arel::Nodes::SqlLiteral.new('binary')
279
298
  else
280
299
  as_attr = Arel::Nodes::SqlLiteral.new(o.as_attr.to_s)
281
300
  end
@@ -306,7 +325,7 @@ module ArelExtensions
306
325
  collector << ")"
307
326
  collector
308
327
  end
309
-
328
+
310
329
  def visit_ArelExtensions_Nodes_DateSub o, collector
311
330
  collector << "DATE_SUB("
312
331
  collector = visit o.left, collector
@@ -385,7 +404,7 @@ module ArelExtensions
385
404
  collector = visit o.left, collector
386
405
  collector << ") THEN "
387
406
  collector = visit o.right, collector
388
- if o.expressions[2]
407
+ if o.expressions[2]
389
408
  collector << " ELSE "
390
409
  collector = visit o.expressions[2], collector
391
410
  end
@@ -409,16 +428,15 @@ module ArelExtensions
409
428
  row_nb = o.left.length
410
429
  o.left.each_with_index do |row, idx|
411
430
  collector << '('
412
- v = Arel::Nodes::Values.new(row, o.cols)
413
- len = v.expressions.length - 1
414
- v.expressions.zip(v.columns).each_with_index { |(value, attr), i|
415
- case value
416
- when Arel::Nodes::SqlLiteral, Arel::Nodes::BindParam
417
- collector = visit value, collector
418
- else
419
- collector << quote(value, attr && column_for(attr)).to_s
420
- end
421
- collector << Arel::Visitors::ToSql::COMMA unless i == len
431
+ len = row.length - 1
432
+ row.zip(o.cols).each_with_index { |(value, attr), i|
433
+ case value
434
+ when Arel::Nodes::SqlLiteral, Arel::Nodes::BindParam
435
+ collector = visit value, collector
436
+ else
437
+ collector << quote(value, attr && column_for(attr)).to_s
438
+ end
439
+ collector << Arel::Visitors::ToSql::COMMA unless i == len
422
440
  }
423
441
  collector << (idx == row_nb-1 ? ')' : '), ')
424
442
  end
@@ -431,15 +449,16 @@ module ArelExtensions
431
449
  o.left.each_with_index do |row, idx|
432
450
  collector << '('
433
451
  len = row.length - 1
434
- row.each_with_index { |value, i|
435
- attr = o.cols[i]
436
- case value
437
- when Arel::Nodes::SqlLiteral, Arel::Nodes::BindParam
438
- collector = visit value, collector
439
- else
440
- collector << (attr && attr.able_to_type_cast? ? quote(attr.type_cast_for_database(value)) : quote(value).to_s)
441
- end
442
- collector << Arel::Visitors::ToSql::COMMA unless i == len
452
+ row.zip(o.cols).each_with_index { |(value, attr), i|
453
+ case value
454
+ when Arel::Nodes::SqlLiteral, Arel::Nodes::BindParam
455
+ collector = visit value, collector
456
+ when Integer
457
+ collector << value.to_s
458
+ else
459
+ collector << (attr && attr.able_to_type_cast? ? quote(attr.type_cast_for_database(value)) : quote(value).to_s)
460
+ end
461
+ collector << Arel::Visitors::ToSql::COMMA unless i == len
443
462
  }
444
463
  collector << (idx == row_nb-1 ? ')' : '), ')
445
464
  end
@@ -453,7 +472,7 @@ module ArelExtensions
453
472
  collector = visit o.right, collector
454
473
  collector
455
474
  end
456
-
475
+
457
476
  def visit_ArelExtensions_Nodes_UnionAll o, collector
458
477
  collector = visit o.left, collector
459
478
  collector << " UNION ALL "
@@ -490,25 +509,25 @@ module ArelExtensions
490
509
  visit Arel::Nodes.build_quoted(o.expr), collector
491
510
  end
492
511
 
493
- def visit_ArelExtensions_Nodes_FormattedNumber o, collector
512
+ def visit_ArelExtensions_Nodes_FormattedNumber o, collector
494
513
  visit o.left, collector
495
514
  end
496
-
497
- remove_method(:visit_Arel_Nodes_LessThan) rescue nil
515
+
516
+ remove_method(:visit_Arel_Nodes_LessThan) rescue nil
498
517
  def visit_Arel_Nodes_LessThan o, collector
499
518
  collector = visit o.left, collector
500
519
  collector << " < "
501
520
  visit o.right, collector
502
521
  end
503
-
504
- def visit_ArelExtensions_Nodes_Std o, collector
522
+
523
+ def visit_ArelExtensions_Nodes_Std o, collector
505
524
  collector << "STD("
506
525
  visit o.left, collector
507
526
  collector << ")"
508
527
  collector
509
528
  end
510
-
511
- def visit_ArelExtensions_Nodes_Variance o, collector
529
+
530
+ def visit_ArelExtensions_Nodes_Variance o, collector
512
531
  collector << "VARIANCE("
513
532
  visit o.left, collector
514
533
  collector << ")"
@@ -524,11 +543,13 @@ module ArelExtensions
524
543
  collector
525
544
  end
526
545
 
546
+ # Boolean logic.
547
+
527
548
  alias_method :old_visit_Arel_Nodes_And, :visit_Arel_Nodes_And
528
549
  def visit_Arel_Nodes_And o, collector
529
550
  case o.children.length
530
551
  when 0
531
- collector << '1=1' # but this should not happen
552
+ collector << '1 = 1' # but this should not happen
532
553
  when 1
533
554
  collector = visit o.children[0], collector
534
555
  else
@@ -544,10 +565,11 @@ module ArelExtensions
544
565
  collector
545
566
  end
546
567
 
547
- def visit_ArelExtensions_Nodes_Or o, collector
568
+ alias_method :old_visit_Arel_Nodes_Or, :visit_Arel_Nodes_Or
569
+ def visit_Arel_Nodes_Or o, collector
548
570
  case o.children.length
549
571
  when 0
550
- collector << '0=1' # but this should not happen
572
+ collector << '1 = 0' # but this should not happen
551
573
  when 1
552
574
  collector = visit o.children[0], collector
553
575
  else
@@ -563,14 +585,24 @@ module ArelExtensions
563
585
  collector
564
586
  end
565
587
 
566
- alias_method :old_visit_Arel_Nodes_Or, :visit_Arel_Nodes_Or
567
- def visit_Arel_Nodes_Or o, collector
568
- collector << '('
569
- collector = visit o.left, collector
570
- collector << ') OR ('
571
- collector = visit o.right, collector
572
- collector << ')'
573
- collector
588
+ def json_value(o,v)
589
+ case o.type_of_node(v)
590
+ when :string
591
+ Arel.when(v.is_null).then(Arel::Nodes.build_quoted("null")).else(Arel::Nodes.build_quoted('"') + v.replace('\\','\\\\').replace('"','\"') + '"')
592
+ when :date
593
+ s = v.format('%Y-%m-%d')
594
+ Arel.when(s.is_null).then(Arel::Nodes.build_quoted("null")).else(Arel::Nodes.build_quoted('"') + s + '"')
595
+ when :datetime
596
+ s = v.format('%Y-%m-%dT%H:%M:%S')
597
+ Arel.when(s.is_null).then(Arel::Nodes.build_quoted("null")).else(Arel::Nodes.build_quoted('"') + s + '"')
598
+ when :time
599
+ s = v.format('%H:%M:%S')
600
+ Arel.when(s.is_null).then(Arel::Nodes.build_quoted("null")).else(Arel::Nodes.build_quoted('"') + s + '"')
601
+ when :nil
602
+ Arel::Nodes.build_quoted("null")
603
+ else
604
+ ArelExtensions::Nodes::Cast.new([v, :string]).coalesce("null")
605
+ end
574
606
  end
575
607
 
576
608
  def visit_ArelExtensions_Nodes_Json o,collector
@@ -581,11 +613,7 @@ module ArelExtensions
581
613
  if i != 0
582
614
  res += ', '
583
615
  end
584
- if (v.is_a?(Arel::Attributes::Attribute) && o.type_of_attribute(v) == :string) || (v.return_type == :string)
585
- res = res + '"' + v + '"'
586
- else
587
- res += v
588
- end
616
+ res += json_value(o,v)
589
617
  end
590
618
  res += ']'
591
619
  collector = visit res, collector
@@ -595,12 +623,8 @@ module ArelExtensions
595
623
  if i != 0
596
624
  res += ', '
597
625
  end
598
- res += Arel::Nodes.build_quoted('"')+k + '": '
599
- if (v.is_a?(Arel::Attributes::Attribute) && o.type_of_attribute(v) == :string) || (v.respond_to?(:return_type) && v.return_type == :string)
600
- res = res + '"' + v + '"'
601
- else
602
- res += v
603
- end
626
+ res += Arel::Nodes.build_quoted('"') + ArelExtensions::Nodes::Cast.new([k, :string]).coalesce("").replace('\\','\\\\').replace('"','\"') + '": '
627
+ res += json_value(o,v)
604
628
  end
605
629
  res += '}'
606
630
  collector = visit res, collector
@@ -612,7 +636,7 @@ module ArelExtensions
612
636
 
613
637
  def visit_ArelExtensions_Nodes_JsonGroup o, collector
614
638
  if o.as_array
615
- res = Arel::Nodes.build_quoted('[') + (o.orders ? o.dict.group_concat(', ',o.orders) : o.dict.group_concat(', ')) + ']'
639
+ res = Arel::Nodes.build_quoted('[') + (o.orders ? o.dict.group_concat(', ', order: Array(o.orders)) : o.dict.group_concat(', ')).coalesce('') + ']'
616
640
  collector = visit res, collector
617
641
  else
618
642
  res = Arel::Nodes.build_quoted('{')
@@ -621,13 +645,9 @@ module ArelExtensions
621
645
  if i != 0
622
646
  res = res + ', '
623
647
  end
624
- kv = Arel::Nodes.build_quoted('"')+k + '": '
625
- if (v.is_a?(Arel::Attributes::Attribute) && o.type_of_attribute(v) == :string) || (v.respond_to?(:return_type) && v.return_type == :string)
626
- kv = kv + '"' + v + '"'
627
- else
628
- kv += v
629
- end
630
- res = res + kv.group_concat(', ',orders)
648
+ kv = Arel::Nodes.build_quoted('"') + ArelExtensions::Nodes::Cast.new([k, :string]).coalesce("").replace('\\','\\\\').replace('"','\"') + '": '
649
+ kv += json_value(o,v)
650
+ res = res + kv.group_concat(', ', order: Array(orders)).coalesce('')
631
651
  end
632
652
  res = res + '}'
633
653
  collector = visit res, collector