arel_extensions 1.3.5 → 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 (122) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +2 -1
  3. data/.gitignore +6 -7
  4. data/.rubocop.yml +3 -67
  5. data/.travis/oracle/download.js +152 -0
  6. data/.travis/oracle/download.sh +30 -0
  7. data/.travis/oracle/download_ojdbc.js +116 -0
  8. data/.travis/oracle/install.sh +34 -0
  9. data/.travis/setup_accounts.sh +9 -0
  10. data/.travis/sqlite3/extension-functions.sh +6 -0
  11. data/.travis.yml +223 -0
  12. data/Gemfile +21 -16
  13. data/README.md +13 -125
  14. data/Rakefile +30 -41
  15. data/TODO +1 -0
  16. data/appveyor.yml +22 -51
  17. data/arel_extensions.gemspec +14 -14
  18. data/functions.html +3 -3
  19. data/gemfiles/rails3.gemfile +10 -10
  20. data/gemfiles/rails4.gemfile +14 -14
  21. data/gemfiles/rails5_0.gemfile +14 -14
  22. data/gemfiles/rails5_1_4.gemfile +14 -14
  23. data/gemfiles/rails5_2.gemfile +14 -16
  24. data/init/mssql.sql +4 -4
  25. data/init/mysql.sql +38 -38
  26. data/init/oracle.sql +0 -0
  27. data/init/postgresql.sql +21 -21
  28. data/init/sqlite.sql +0 -0
  29. data/lib/arel_extensions/attributes.rb +3 -4
  30. data/lib/arel_extensions/boolean_functions.rb +14 -53
  31. data/lib/arel_extensions/common_sql_functions.rb +17 -16
  32. data/lib/arel_extensions/comparators.rb +28 -27
  33. data/lib/arel_extensions/date_duration.rb +14 -13
  34. data/lib/arel_extensions/insert_manager.rb +15 -18
  35. data/lib/arel_extensions/math.rb +53 -55
  36. data/lib/arel_extensions/math_functions.rb +39 -46
  37. data/lib/arel_extensions/nodes/abs.rb +1 -0
  38. data/lib/arel_extensions/nodes/blank.rb +2 -1
  39. data/lib/arel_extensions/nodes/case.rb +16 -16
  40. data/lib/arel_extensions/nodes/cast.rb +8 -10
  41. data/lib/arel_extensions/nodes/ceil.rb +1 -1
  42. data/lib/arel_extensions/nodes/coalesce.rb +4 -3
  43. data/lib/arel_extensions/nodes/collate.rb +10 -9
  44. data/lib/arel_extensions/nodes/concat.rb +18 -9
  45. data/lib/arel_extensions/nodes/date_diff.rb +26 -42
  46. data/lib/arel_extensions/nodes/duration.rb +3 -0
  47. data/lib/arel_extensions/nodes/find_in_set.rb +1 -0
  48. data/lib/arel_extensions/nodes/floor.rb +1 -1
  49. data/lib/arel_extensions/nodes/format.rb +8 -35
  50. data/lib/arel_extensions/nodes/formatted_number.rb +23 -22
  51. data/lib/arel_extensions/nodes/function.rb +37 -42
  52. data/lib/arel_extensions/nodes/is_null.rb +0 -0
  53. data/lib/arel_extensions/nodes/json.rb +39 -48
  54. data/lib/arel_extensions/nodes/length.rb +0 -5
  55. data/lib/arel_extensions/nodes/levenshtein_distance.rb +1 -1
  56. data/lib/arel_extensions/nodes/locate.rb +2 -1
  57. data/lib/arel_extensions/nodes/log10.rb +2 -1
  58. data/lib/arel_extensions/nodes/matches.rb +7 -5
  59. data/lib/arel_extensions/nodes/md5.rb +1 -0
  60. data/lib/arel_extensions/nodes/power.rb +5 -5
  61. data/lib/arel_extensions/nodes/rand.rb +1 -0
  62. data/lib/arel_extensions/nodes/repeat.rb +5 -3
  63. data/lib/arel_extensions/nodes/replace.rb +8 -16
  64. data/lib/arel_extensions/nodes/round.rb +6 -5
  65. data/lib/arel_extensions/nodes/soundex.rb +15 -15
  66. data/lib/arel_extensions/nodes/std.rb +21 -18
  67. data/lib/arel_extensions/nodes/substring.rb +16 -8
  68. data/lib/arel_extensions/nodes/then.rb +1 -1
  69. data/lib/arel_extensions/nodes/trim.rb +6 -4
  70. data/lib/arel_extensions/nodes/union.rb +8 -5
  71. data/lib/arel_extensions/nodes/union_all.rb +7 -4
  72. data/lib/arel_extensions/nodes/wday.rb +4 -0
  73. data/lib/arel_extensions/nodes.rb +1 -1
  74. data/lib/arel_extensions/null_functions.rb +7 -5
  75. data/lib/arel_extensions/predications.rb +43 -44
  76. data/lib/arel_extensions/railtie.rb +5 -5
  77. data/lib/arel_extensions/set_functions.rb +7 -5
  78. data/lib/arel_extensions/string_functions.rb +29 -58
  79. data/lib/arel_extensions/tasks.rb +6 -6
  80. data/lib/arel_extensions/version.rb +1 -1
  81. data/lib/arel_extensions/visitors/ibm_db.rb +31 -24
  82. data/lib/arel_extensions/visitors/mssql.rb +181 -279
  83. data/lib/arel_extensions/visitors/mysql.rb +210 -280
  84. data/lib/arel_extensions/visitors/oracle.rb +180 -201
  85. data/lib/arel_extensions/visitors/oracle12.rb +31 -18
  86. data/lib/arel_extensions/visitors/postgresql.rb +173 -252
  87. data/lib/arel_extensions/visitors/sqlite.rb +126 -140
  88. data/lib/arel_extensions/visitors/to_sql.rb +237 -272
  89. data/lib/arel_extensions/visitors.rb +59 -75
  90. data/lib/arel_extensions.rb +31 -159
  91. data/test/database.yml +7 -15
  92. data/test/helper.rb +18 -0
  93. data/test/real_db_test.rb +116 -105
  94. data/test/support/fake_record.rb +3 -3
  95. data/test/test_comparators.rb +17 -14
  96. data/test/visitors/test_bulk_insert_oracle.rb +11 -11
  97. data/test/visitors/test_bulk_insert_sqlite.rb +13 -12
  98. data/test/visitors/test_bulk_insert_to_sql.rb +13 -11
  99. data/test/visitors/test_oracle.rb +55 -55
  100. data/test/visitors/test_to_sql.rb +226 -419
  101. data/test/with_ar/all_agnostic_test.rb +361 -578
  102. data/test/with_ar/insert_agnostic_test.rb +21 -27
  103. data/test/with_ar/test_bulk_sqlite.rb +16 -17
  104. data/test/with_ar/test_math_sqlite.rb +26 -26
  105. data/test/with_ar/test_string_mysql.rb +33 -31
  106. data/test/with_ar/test_string_sqlite.rb +34 -30
  107. metadata +22 -29
  108. data/.github/workflows/ruby.yml +0 -341
  109. data/gemfiles/rails6.gemfile +0 -30
  110. data/gemfiles/rails6_1.gemfile +0 -30
  111. data/gemfiles/rails7.gemfile +0 -23
  112. data/gemspecs/arel_extensions-v1.gemspec +0 -28
  113. data/gemspecs/arel_extensions-v2.gemspec +0 -28
  114. data/generate_gems.sh +0 -15
  115. data/lib/arel_extensions/aliases.rb +0 -14
  116. data/lib/arel_extensions/helpers.rb +0 -51
  117. data/lib/arel_extensions/nodes/aggregate_function.rb +0 -13
  118. data/lib/arel_extensions/nodes/sum.rb +0 -7
  119. data/lib/arel_extensions/visitors/convert_format.rb +0 -37
  120. data/test/arelx_test_helper.rb +0 -71
  121. data/version_v1.rb +0 -3
  122. data/version_v2.rb +0 -3
@@ -1,42 +1,38 @@
1
1
  module ArelExtensions
2
2
  module Visitors
3
- class Arel::Visitors::MySQL
4
- DATE_MAPPING = {
5
- 'd' => 'DAY', 'm' => 'MONTH', 'w' => 'WEEK', 'y' => 'YEAR', 'wd' => 'WEEKDAY',
6
- 'h' => 'HOUR', 'mn' => 'MINUTE', 's' => 'SECOND'
7
- }.freeze
8
-
9
- DATE_FORMAT_DIRECTIVES = { # ISO C / POSIX
3
+ Arel::Visitors::MySQL.class_eval do
4
+ Arel::Visitors::MySQL::COMMA = ", "
5
+ Arel::Visitors::MySQL::DATE_MAPPING = {'d' => 'DAY', 'm' => 'MONTH', 'w' => 'WEEK', 'y' => 'YEAR', 'wd' => 'WEEKDAY', 'h' => 'HOUR', 'mn' => 'MINUTE', 's' => 'SECOND'}
6
+ Arel::Visitors::MySQL::DATE_FORMAT_DIRECTIVES = { # ISO C / POSIX
10
7
  '%Y' => '%Y', '%C' => '', '%y' => '%y', '%m' => '%m', '%B' => '%M', '%b' => '%b', '%^b' => '%b', # year, month
11
- '%V' => '%v', '%G' => '%x', # ISO week number and year of week
12
- '%d' => '%d', '%e' => '%e', '%j' => '%j', '%w' => '%w', '%a' => '%a', '%A' => '%W', # day, weekday
8
+ '%d' => '%d', '%e' => '%e', '%j' => '%j', '%w' => '%w', '%A' => '%W', # day, weekday
13
9
  '%H' => '%H', '%k' => '%k', '%I' => '%I', '%l' => '%l', '%P' => '%p', '%p' => '%p', # hours
14
10
  '%M' => '%i', '%S' => '%S', '%L' => '', '%N' => '%f', '%z' => ''
15
- }.freeze
11
+ }
16
12
 
17
13
 
18
- # Math functions
14
+ #Math functions
19
15
  def visit_ArelExtensions_Nodes_Log10 o, collector
20
- collector << 'LOG10('
21
- o.expressions.each_with_index { |arg, i|
22
- collector << Arel::Visitors::ToSql::COMMA if i != 0
23
- collector = visit arg, collector
24
- }
25
- collector << ')'
26
- collector
16
+ collector << "LOG10("
17
+ o.expressions.each_with_index { |arg, i|
18
+ collector << Arel::Visitors::ToSql::COMMA unless i == 0
19
+ collector = visit arg, collector
20
+ }
21
+ collector << ")"
22
+ collector
27
23
  end
28
24
 
29
25
  def visit_ArelExtensions_Nodes_Power o, collector
30
- collector << 'POW('
26
+ collector << "POW("
31
27
  o.expressions.each_with_index { |arg, i|
32
- collector << Arel::Visitors::ToSql::COMMA if i != 0
28
+ collector << Arel::Visitors::ToSql::COMMA unless i == 0
33
29
  collector = visit arg, collector
34
30
  }
35
- collector << ')'
31
+ collector << ")"
36
32
  collector
37
33
  end
38
34
 
39
- # String functions
35
+ #String functions
40
36
  def visit_ArelExtensions_Nodes_IMatches o, collector # insensitive on ASCII
41
37
  collector << 'LOWER('
42
38
  collector = visit o.left, collector
@@ -45,9 +41,10 @@ module ArelExtensions
45
41
  collector << ')'
46
42
  if o.escape
47
43
  collector << ' ESCAPE '
48
- collector = visit o.escape, collector
44
+ visit o.escape, collector
45
+ else
46
+ collector
49
47
  end
50
- collector
51
48
  end
52
49
 
53
50
  def visit_ArelExtensions_Nodes_AiMatches o, collector
@@ -56,9 +53,10 @@ module ArelExtensions
56
53
  collector = visit o.right.ai_collate, collector
57
54
  if o.escape
58
55
  collector << ' ESCAPE '
59
- collector = visit o.escape, collector
56
+ visit o.escape, collector
57
+ else
58
+ collector
60
59
  end
61
- collector
62
60
  end
63
61
 
64
62
  def visit_ArelExtensions_Nodes_AiIMatches o, collector
@@ -67,20 +65,22 @@ module ArelExtensions
67
65
  collector = visit o.right.ai_collate, collector
68
66
  if o.escape
69
67
  collector << ' ESCAPE '
70
- collector = visit o.escape, collector
68
+ visit o.escape, collector
69
+ else
70
+ collector
71
71
  end
72
- collector
73
72
  end
74
73
 
75
74
  def visit_ArelExtensions_Nodes_SMatches o, collector
76
- collector = visit o.left.collate, collector
77
- collector << ' LIKE '
78
- collector = visit o.right.collate, collector
79
- if o.escape
80
- collector << ' ESCAPE '
81
- collector = visit o.escape, collector
82
- end
83
- collector
75
+ collector = visit o.left.collate, collector
76
+ collector << ' LIKE '
77
+ collector = visit o.right.collate, collector
78
+ if o.escape
79
+ collector << ' ESCAPE '
80
+ visit o.escape, collector
81
+ else
82
+ collector
83
+ end
84
84
  end
85
85
 
86
86
  def visit_ArelExtensions_Nodes_IDoesNotMatch o, collector
@@ -91,146 +91,125 @@ module ArelExtensions
91
91
  collector << ')'
92
92
  if o.escape
93
93
  collector << ' ESCAPE '
94
- collector = visit o.escape, collector
94
+ visit o.escape, collector
95
+ else
96
+ collector
95
97
  end
96
- collector
97
98
  end
98
99
 
99
100
  def visit_ArelExtensions_Nodes_Collate o, collector
100
- charset =
101
- case o.expressions.first
102
- when Arel::Attributes::Attribute
103
- case o.option
104
- when 'latin1', 'utf8'
101
+ case o.expressions.first
102
+ when Arel::Attributes::Attribute
103
+ charset = case o.option
104
+ when 'latin1','utf8'
105
105
  o.option
106
106
  else
107
107
  Arel::Table.engine.connection.charset || 'utf8'
108
108
  end
109
- else
110
- (o.option == 'latin1') ? 'latin1' : 'utf8'
111
- end
109
+ else
110
+ charset = (o.option == 'latin1') ? 'latin1' : 'utf8'
111
+ end
112
112
  collector = visit o.expressions.first, collector
113
- collector <<
114
- if o.ai
115
- " COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : 'utf8_unicode_ci'}"
116
- # doesn't work in latin1
117
- elsif o.ci
118
- " COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : 'utf8_unicode_ci'}"
119
- else
120
- " COLLATE #{charset}_bin"
121
- end
113
+ if o.ai
114
+ collector << " COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : 'utf8_unicode_ci' }"
115
+ #doesn't work in latin1
116
+ elsif o.ci
117
+ collector << " COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : 'utf8_unicode_ci' }"
118
+ else
119
+ collector << " COLLATE #{charset}_bin"
120
+ end
122
121
  collector
123
122
  end
124
123
 
125
124
  def visit_ArelExtensions_Nodes_Concat o, collector
126
- collector << 'CONCAT('
125
+ collector << "CONCAT("
127
126
  o.expressions.each_with_index { |arg, i|
128
- collector << COMMA if i != 0
129
- if arg.is_a?(Numeric) || arg.is_a?(Arel::Attributes::Attribute)
130
- collector << 'CAST('
127
+ collector << Arel::Visitors::MySQL::COMMA unless i == 0
128
+ if (arg.is_a?(Numeric)) || (arg.is_a?(Arel::Attributes::Attribute))
129
+ collector << "CAST("
131
130
  collector = visit arg, collector
132
- collector << ' AS char)'
131
+ collector << " AS char)"
133
132
  else
134
133
  collector = visit arg, collector
135
134
  end
136
135
  }
137
- collector << ')'
136
+ collector << ")"
138
137
  collector
139
138
  end
140
139
 
141
140
  def visit_ArelExtensions_Nodes_GroupConcat o, collector
142
- collector << 'GROUP_CONCAT('
141
+ collector << "GROUP_CONCAT("
143
142
  collector = visit o.left, collector
144
- if !o.order.blank?
143
+ if !o.orders.blank?
145
144
  collector << ' ORDER BY '
146
- o.order.each_with_index do |order, i|
147
- collector << Arel::Visitors::ToSql::COMMA if i != 0
145
+ o.orders.each_with_index do |order,i|
146
+ collector << Arel::Visitors::ToSql::COMMA unless i == 0
148
147
  collector = visit order, collector
149
148
  end
150
149
  end
151
- if o.separator && o.separator != 'NULL'
150
+ if o.right && o.right != 'NULL'
152
151
  collector << ' SEPARATOR '
153
- collector = visit o.separator, collector
152
+ collector = visit o.right, collector
154
153
  end
155
- collector << ')'
154
+ collector << ")"
156
155
  collector
157
156
  end
158
157
 
159
158
  def visit_ArelExtensions_Nodes_Trim o, collector
160
- collector << 'TRIM(' # BOTH
161
- collector = visit o.right, collector
162
- collector << ' FROM '
163
- collector = visit o.left, collector
164
- collector << ')'
165
- collector
159
+ collector << 'TRIM(' # BOTH
160
+ collector = visit o.right, collector
161
+ collector << " FROM "
162
+ collector = visit o.left, collector
163
+ collector << ")"
164
+ collector
166
165
  end
167
166
 
168
- def visit_ArelExtensions_Nodes_Ltrim o, collector
169
- collector << 'TRIM(LEADING '
170
- collector = visit o.right, collector
171
- collector << ' FROM '
172
- collector = visit o.left, collector
173
- collector << ')'
174
- collector
167
+ def visit_ArelExtensions_Nodes_Ltrim o , collector
168
+ collector << 'TRIM(LEADING '
169
+ collector = visit o.right, collector
170
+ collector << " FROM "
171
+ collector = visit o.left, collector
172
+ collector << ")"
173
+ collector
175
174
  end
176
175
 
177
- def visit_ArelExtensions_Nodes_Rtrim o, collector
176
+ def visit_ArelExtensions_Nodes_Rtrim o , collector
178
177
  collector << 'TRIM(TRAILING '
179
178
  collector = visit o.right, collector
180
- collector << ' FROM '
179
+ collector << " FROM "
181
180
  collector = visit o.left, collector
182
- collector << ')'
181
+ collector << ")"
183
182
  collector
184
183
  end
185
184
 
186
185
  def visit_ArelExtensions_Nodes_Repeat o, collector
187
- collector << 'REPEAT('
186
+ collector << "REPEAT("
188
187
  o.expressions.each_with_index { |arg, i|
189
- collector << Arel::Visitors::ToSql::COMMA if i != 0
188
+ collector << Arel::Visitors::ToSql::COMMA unless i == 0
190
189
  collector = visit arg, collector
191
190
  }
192
- collector << ')'
191
+ collector << ")"
193
192
  collector
194
193
  end
195
194
 
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
-
203
195
  def visit_ArelExtensions_Nodes_Format o, collector
204
196
  case o.col_type
205
- when :date, :datetime, :time
206
- fmt = ArelExtensions::Visitors::strftime_to_format(o.iso_format, DATE_FORMAT_DIRECTIVES)
207
- collector << 'DATE_FORMAT('
208
- collector << 'CONVERT_TZ(' if o.time_zone
197
+ when :date, :datetime
198
+ collector << "DATE_FORMAT("
209
199
  collector = visit o.left, collector
210
- case o.time_zone
211
- when Hash
212
- src_tz, dst_tz = o.time_zone.first
213
- collector << COMMA
214
- collector = visit Arel.quoted(src_tz), collector
215
- collector << COMMA
216
- collector = visit Arel.quoted(dst_tz), collector
217
- collector << ')'
218
- when String
219
- collector << COMMA << "'UTC'" << COMMA
220
- collector = visit Arel.quoted(o.time_zone), collector
221
- collector << ')'
222
- end
223
- collector << COMMA
224
- collector = visit Arel.quoted(fmt), collector
225
- collector << ')'
200
+ collector << Arel::Visitors::MySQL::COMMA
201
+ f = o.iso_format.dup
202
+ Arel::Visitors::MySQL::DATE_FORMAT_DIRECTIVES.each { |d, r| f.gsub!(d, r) }
203
+ collector = visit Arel::Nodes.build_quoted(f), collector
204
+ collector << ")"
226
205
  when :integer, :float, :decimal
227
- collector << 'FORMAT('
206
+ collector << "FORMAT("
228
207
  collector = visit o.left, collector
229
208
  collector << Arel::Visitors::ToSql::COMMA
230
209
  collector << '2'
231
210
  collector << Arel::Visitors::ToSql::COMMA
232
211
  collector = visit o.right, collector
233
- collector << ')'
212
+ collector << ")"
234
213
  else
235
214
  collector = visit o.left, collector
236
215
  end
@@ -238,17 +217,16 @@ module ArelExtensions
238
217
  end
239
218
 
240
219
  def visit_ArelExtensions_Nodes_DateDiff o, collector
241
- case o.right_node_type
242
- when :ruby_date, :ruby_time, :date, :datetime, :time
243
- collector <<
244
- case o.left_node_type
245
- when :ruby_time, :datetime, :time then 'TIMESTAMPDIFF(SECOND, '
246
- else 'DATEDIFF('
247
- end
220
+ if o.right_node_type == :ruby_date || o.right_node_type == :ruby_time || o.right_node_type == :date || o.right_node_type == :datetime || o.right_node_type == :time
221
+ collector << if o.left_node_type == :ruby_time || o.left_node_type == :datetime || o.left_node_type == :time
222
+ 'TIMESTAMPDIFF(SECOND, '
223
+ else
224
+ 'DATEDIFF('
225
+ end
248
226
  collector = visit o.right, collector
249
- collector << COMMA
227
+ collector << Arel::Visitors::MySQL::COMMA
250
228
  collector = visit o.left, collector
251
- collector << ')'
229
+ collector << ")"
252
230
  else
253
231
  collector << '('
254
232
  collector = visit o.left, collector
@@ -268,92 +246,101 @@ module ArelExtensions
268
246
  end
269
247
 
270
248
  def visit_ArelExtensions_Nodes_DateAdd o, collector
271
- collector << 'DATE_ADD('
249
+ collector << "DATE_ADD("
272
250
  collector = visit o.left, collector
273
- collector << COMMA
251
+ collector << Arel::Visitors::MySQL::COMMA
274
252
  collector = visit o.mysql_value(o.right), collector
275
- collector << ')'
253
+ collector << ")"
276
254
  collector
277
255
  end
278
256
 
257
+
279
258
  def visit_ArelExtensions_Nodes_Duration o, collector
280
259
  if o.left == 'wd'
281
- collector << '(WEEKDAY('
260
+ collector << "(WEEKDAY("
282
261
  collector = visit o.right, collector
283
- collector << ') + 1) % 7'
262
+ collector << ") + 1) % 7"
284
263
  else
285
264
  if o.with_interval
286
- interval =
287
- case o.left
288
- when 'd', 'm', 'y'
289
- 'DAY'
290
- when 'h', 'mn', 's'
291
- 'SECOND'
292
- when /i\z/
293
- DATE_MAPPING[o.left[0..-2]]
294
- end
265
+ case o.left
266
+ when 'd','m','y'
267
+ interval = 'DAY'
268
+ when 'h','mn','s'
269
+ interval = 'SECOND'
270
+ when /i\z/
271
+ interval = Arel::Visitors::MySQL::DATE_MAPPING[o.left[0..-2]]
272
+ else
273
+ interval = nil
274
+ end
295
275
  end
296
- collector << ' INTERVAL ' if o.with_interval && interval
297
- collector << "#{DATE_MAPPING[o.left]}("
276
+ collector << " INTERVAL " if o.with_interval && interval
277
+ collector << "#{Arel::Visitors::MySQL::DATE_MAPPING[o.left]}("
298
278
  collector = visit o.right, collector
299
- collector << ')'
279
+ collector << ")"
300
280
  collector << " #{interval} " if o.with_interval && interval
301
281
  end
302
282
  collector
303
283
  end
304
284
 
285
+
305
286
  def visit_ArelExtensions_Nodes_IsNull o, collector
306
- collector << 'ISNULL('
287
+ collector << "ISNULL("
307
288
  collector = visit o.expr, collector
308
- collector << ')'
289
+ collector << ")"
309
290
  collector
310
291
  end
311
292
 
312
293
  def visit_ArelExtensions_Nodes_IsNotNull o, collector
313
- collector << 'NOT ISNULL('
294
+ collector << "NOT ISNULL("
314
295
  collector = visit o.expr, collector
315
- collector << ')'
296
+ collector << ")"
316
297
  collector
317
298
  end
318
299
 
319
300
  def visit_ArelExtensions_Nodes_Wday o, collector
320
- collector << '(WEEKDAY('
301
+ collector << "(WEEKDAY("
321
302
  collector = visit o.date, collector
322
- collector << ') + 1) % 7'
303
+ collector << ") + 1) % 7"
323
304
  collector
324
305
  end
325
306
 
326
307
  def visit_ArelExtensions_Nodes_Cast o, collector
327
- as_attr =
328
- case o.as_attr
329
- when :binary then 'binary'
330
- when :date then 'date'
331
- when :datetime then 'datetime'
332
- when :int then 'signed'
333
- when :number, :decimal then 'decimal(20,6)'
334
- when :string then 'char'
335
- when :time then 'time'
336
- else o.as_attr.to_s
337
- end
338
-
339
- collector << 'CAST('
308
+ collector << "CAST("
340
309
  collector = visit o.left, collector
341
- collector << ' AS '
342
- collector = visit Arel::Nodes::SqlLiteral.new(as_attr), collector
343
- collector << ')'
310
+ collector << " AS "
311
+ case o.as_attr
312
+ when :string
313
+ as_attr = Arel::Nodes::SqlLiteral.new('char')
314
+ when :time
315
+ as_attr = Arel::Nodes::SqlLiteral.new('time')
316
+ when :int
317
+ as_attr = Arel::Nodes::SqlLiteral.new('signed')
318
+ when :number, :decimal
319
+ as_attr = Arel::Nodes::SqlLiteral.new('decimal(20,6)')
320
+ when :datetime
321
+ as_attr = Arel::Nodes::SqlLiteral.new('datetime')
322
+ when :date
323
+ as_attr = Arel::Nodes::SqlLiteral.new('date')
324
+ when :binary
325
+ as_attr = Arel::Nodes::SqlLiteral.new('binary')
326
+ else
327
+ as_attr = Arel::Nodes::SqlLiteral.new(o.as_attr.to_s)
328
+ end
329
+ collector = visit as_attr, collector
330
+ collector << ")"
344
331
  collector
345
332
  end
346
333
 
347
- alias_method(:old_visit_Arel_Nodes_SelectStatement, :visit_Arel_Nodes_SelectStatement) rescue nil
334
+ alias_method :old_visit_Arel_Nodes_SelectStatement, :visit_Arel_Nodes_SelectStatement
348
335
  def visit_Arel_Nodes_SelectStatement o, collector
349
336
  if !(collector.value.blank? || (collector.value.is_a?(Array) && collector.value[0].blank?)) && o.limit.blank? && o.offset.blank?
350
337
  o = o.dup
351
338
  o.orders = []
352
339
  end
353
- old_visit_Arel_Nodes_SelectStatement(o, collector)
340
+ old_visit_Arel_Nodes_SelectStatement(o,collector)
354
341
  end
355
342
 
356
- alias_method(:old_visit_Arel_Nodes_As, :visit_Arel_Nodes_As) rescue nil
343
+ alias_method :old_visit_Arel_Nodes_As, :visit_Arel_Nodes_As
357
344
  def visit_Arel_Nodes_As o, collector
358
345
  if o.left.is_a?(Arel::Nodes::Binary)
359
346
  collector << '('
@@ -362,56 +349,44 @@ module ArelExtensions
362
349
  else
363
350
  collector = visit o.left, collector
364
351
  end
365
- collector << ' AS '
366
-
367
- # sometimes these values are already quoted, if they are, don't double quote it
368
- quote = o.right.is_a?(Arel::Nodes::SqlLiteral) && o.right[0] != '`' && o.right[-1] != '`'
369
-
370
- collector << '`' if quote
352
+ collector << " AS `"
371
353
  collector = visit o.right, collector
372
- collector << '`' if quote
373
-
354
+ collector << "`"
374
355
  collector
375
356
  end
376
357
 
377
358
  def visit_ArelExtensions_Nodes_FormattedNumber o, collector
378
359
  col = o.left.coalesce(0)
379
- params = o.locale ? [o.precision, Arel.quoted(o.locale)] : [o.precision]
380
- sign = Arel.when(col < 0).
360
+ params = o.locale ? [o.precision,Arel::Nodes.build_quoted(o.locale)] : [o.precision]
361
+ sign = ArelExtensions::Nodes::Case.new.when(col<0).
381
362
  then('-').
382
363
  else(o.flags.include?('+') ? '+' : (o.flags.include?(' ') ? ' ' : ''))
383
364
  sign_length = ArelExtensions::Nodes::Length.new([sign])
384
365
 
385
- number =
386
- if o.scientific_notation
387
- ArelExtensions::Nodes::Concat.new([
388
- Arel::Nodes::NamedFunction.new('FORMAT', [
389
- col.abs / Arel.quoted(10).pow(col.abs.log10.floor)
390
- ] + params),
391
- o.type,
392
- Arel::Nodes::NamedFunction.new('FORMAT', [
393
- col.abs.log10.floor,
394
- 0
395
- ])
366
+ if o.scientific_notation
367
+ number = ArelExtensions::Nodes::Concat.new([
368
+ Arel::Nodes::NamedFunction.new('FORMAT',[
369
+ col.abs/Arel::Nodes.build_quoted(10).pow(col.abs.log10.floor)
370
+ ]+params),
371
+ o.type,
372
+ Arel::Nodes::NamedFunction.new('FORMAT',[
373
+ col.abs.log10.floor,
374
+ 0
396
375
  ])
397
- else
398
- Arel::Nodes::NamedFunction.new('FORMAT', [col.abs] + params)
399
- end
376
+ ])
377
+ else
378
+ number = Arel::Nodes::NamedFunction.new('FORMAT',[col.abs]+params)
379
+ end
400
380
 
401
- repeated_char =
402
- if o.width == 0
403
- Arel.quoted('')
404
- else
405
- Arel
406
- .when(Arel.quoted(o.width).abs - (number.length + sign_length) > 0)
407
- .then(Arel.quoted(
408
- o.flags.include?('-') ? ' ' : (o.flags.include?('0') ? '0' : ' ')
409
- ).repeat(Arel.quoted(o.width).abs - (number.length + sign_length))
410
- )
411
- .else('')
412
- end
413
- before = !o.flags.include?('0') && !o.flags.include?('-') ? repeated_char : ''
414
- middle = o.flags.include?('0') && !o.flags.include?('-') ? repeated_char : ''
381
+ repeated_char = (o.width == 0) ? Arel::Nodes.build_quoted('') : ArelExtensions::Nodes::Case.new().
382
+ when(Arel::Nodes.build_quoted(o.width).abs-(number.length+sign_length)>0).
383
+ then(Arel::Nodes.build_quoted(
384
+ o.flags.include?('-') ? ' ' : (o.flags.include?('0') ? '0' : ' ')
385
+ ).repeat(Arel::Nodes.build_quoted(o.width).abs-(number.length+sign_length))
386
+ ).
387
+ else('')
388
+ before = (!o.flags.include?('0'))&&(!o.flags.include?('-')) ? repeated_char : ''
389
+ middle = (o.flags.include?('0'))&&(!o.flags.include?('-')) ? repeated_char : ''
415
390
  after = o.flags.include?('-') ? repeated_char : ''
416
391
  full_number = ArelExtensions::Nodes::Concat.new([
417
392
  before,
@@ -420,97 +395,52 @@ module ArelExtensions
420
395
  number,
421
396
  after
422
397
  ])
423
- collector = visit ArelExtensions::Nodes::Concat.new([Arel.quoted(o.prefix), full_number, Arel.quoted(o.suffix)]), collector
424
- collector
425
- end
426
-
427
- def visit_Aggregate_For_AggregateFunction o, collector
428
- if !window_supported?
429
- warn('Warning: ArelExtensions: Window Functions are not available in the current version of the DBMS.')
430
- return collector
431
- end
432
-
433
- if !o.order.empty? || !o.group.empty?
434
- collector << ' OVER ('
435
- if !o.group.empty?
436
- collector << ' PARTITION BY ('
437
- visit o.group, collector
438
- collector << ')'
439
- end
440
- if !o.order.empty?
441
- collector << ' ORDER BY ('
442
- visit o.order, collector
443
- collector << ')'
444
- end
445
- collector << ')'
446
- end
398
+ collector = visit ArelExtensions::Nodes::Concat.new([Arel::Nodes.build_quoted(o.prefix),full_number,Arel::Nodes.build_quoted(o.suffix)]), collector
447
399
  collector
448
400
  end
449
401
 
450
402
  def visit_ArelExtensions_Nodes_Std o, collector
451
- collector << (o.unbiased_estimator ? 'STDDEV_SAMP(' : 'STDDEV_POP(')
403
+ collector << (o.unbiased_estimator ? "STDDEV_SAMP(" : "STDDEV_POP(")
452
404
  visit o.left, collector
453
- collector << ')'
454
- visit_Aggregate_For_AggregateFunction o, collector
405
+ collector << ")"
455
406
  collector
456
407
  end
457
408
 
458
409
  def visit_ArelExtensions_Nodes_Variance o, collector
459
- collector << (o.unbiased_estimator ? 'VAR_SAMP(' : 'VAR_POP(')
410
+ collector << (o.unbiased_estimator ? "VAR_SAMP(" : "VAR_POP(")
460
411
  visit o.left, collector
461
- collector << ')'
462
- visit_Aggregate_For_AggregateFunction o, collector
412
+ collector << ")"
463
413
  collector
464
414
  end
465
415
 
466
- # JSON if implemented only after 10.2.3 (aggregations after 10.5.0) in MariaDb and 5.7 (aggregations after 5.7.22) in MySql
416
+ # JSON if implemented only after 10.2.3 in MariaDb and 5.7 in MySql
467
417
  def json_supported?
468
- version_supported?('10.5.0', '5.7.22')
418
+ Arel::Table.engine.connection.send(:mariadb?) &&
419
+ Arel::Table.engine.connection.send(:version) >= '10.2.3' ||
420
+ !Arel::Table.engine.connection.send(:mariadb?) &&
421
+ Arel::Table.engine.connection.send(:version) >= '5.7.0'
469
422
  end
470
423
 
471
- def window_supported?
472
- version_supported?('10.2.3', '8.0')
473
- end
474
-
475
- def regexp_replace_supported?
476
- version_supported?('10.0.5', '8.0')
477
- end
478
-
479
- def version_supported?(mariadb_v = '10.2.3', mysql_v = '5.7.0')
480
- conn = Arel::Table.engine.connection
481
- conn.send(:mariadb?) && \
482
- (conn.respond_to?(:get_database_version) && conn.send(:get_database_version) >= mariadb_v || \
483
- conn.respond_to?(:version) && conn.send(:version) >= mariadb_v || \
484
- conn.instance_variable_get(:"@version") && conn.instance_variable_get(:"@version") >= mariadb_v) || \
485
- !conn.send(:mariadb?) && \
486
- (conn.respond_to?(:get_database_version) && conn.send(:get_database_version) >= mysql_v || \
487
- conn.respond_to?(:version) && conn.send(:version) >= mysql_v || \
488
- conn.instance_variable_get(:"@version") && conn.instance_variable_get(:"@version") >= mysql_v)
489
- # ideally we should parse the instance_variable @full_version because @version contains only the supposedly
490
- # corresponding mysql version of the current mariadb version (which is not very helpful most of the time)
491
- end
492
-
493
- def visit_ArelExtensions_Nodes_Json o, collector
424
+ def visit_ArelExtensions_Nodes_Json o,collector
494
425
  return super if !json_supported?
495
-
496
426
  case o.dict
497
427
  when Array
498
428
  collector << 'JSON_ARRAY('
499
- o.dict.each.with_index do |v, i|
429
+ o.dict.each.with_index do |v,i|
500
430
  if i != 0
501
- collector << COMMA
431
+ collector << Arel::Visitors::MySQL::COMMA
502
432
  end
503
433
  collector = visit v, collector
504
434
  end
505
435
  collector << ')'
506
436
  when Hash
507
437
  collector << 'JSON_OBJECT('
508
- o.dict.each.with_index do |(k, v), i|
438
+ o.dict.each.with_index do |(k,v),i|
509
439
  if i != 0
510
- collector << COMMA
440
+ collector << Arel::Visitors::MySQL::COMMA
511
441
  end
512
442
  collector = visit k, collector
513
- collector << COMMA
443
+ collector << Arel::Visitors::MySQL::COMMA
514
444
  collector = visit v, collector
515
445
  end
516
446
  collector << ')'
@@ -520,11 +450,11 @@ module ArelExtensions
520
450
  collector
521
451
  end
522
452
 
523
- def visit_ArelExtensions_Nodes_JsonMerge o, collector
453
+ def visit_ArelExtensions_Nodes_JsonMerge o,collector
524
454
  collector << 'JSON_MERGE_PATCH('
525
- o.expressions.each.with_index do |v, i|
455
+ o.expressions.each.with_index do |v,i|
526
456
  if i != 0
527
- collector << COMMA
457
+ collector << Arel::Visitors::MySQL::COMMA
528
458
  end
529
459
  collector = visit v, collector
530
460
  end
@@ -532,29 +462,29 @@ module ArelExtensions
532
462
  collector
533
463
  end
534
464
 
535
- def visit_ArelExtensions_Nodes_JsonGet o, collector
465
+ def visit_ArelExtensions_Nodes_JsonGet o,collector
536
466
  collector << 'JSON_EXTRACT('
537
467
  collector = visit o.dict, collector
538
- collector << COMMA
468
+ collector << Arel::Visitors::MySQL::COMMA
539
469
  if o.key.is_a?(Integer)
540
470
  collector << "\"$[#{o.key}]\""
541
471
  else
542
- collector = visit Arel.quoted('$.') + o.key, collector
472
+ collector = visit Arel::Nodes.build_quoted('$.')+o.key, collector
543
473
  end
544
474
  collector << ')'
545
475
  collector
546
476
  end
547
477
 
548
- def visit_ArelExtensions_Nodes_JsonSet o, collector
478
+ def visit_ArelExtensions_Nodes_JsonSet o,collector
549
479
  collector << 'JSON_SET('
550
480
  collector = visit o.dict, collector
551
- collector << COMMA
481
+ collector << Arel::Visitors::MySQL::COMMA
552
482
  if o.key.is_a?(Integer)
553
483
  collector << "\"$[#{o.key}]\""
554
484
  else
555
- collector = visit Arel.quoted('$.') + o.key, collector
485
+ collector = visit Arel::Nodes.build_quoted('$.')+o.key, collector
556
486
  end
557
- collector << COMMA
487
+ collector << Arel::Visitors::MySQL::COMMA
558
488
  collector = visit o.value, collector
559
489
  collector << ')'
560
490
  collector
@@ -562,7 +492,6 @@ module ArelExtensions
562
492
 
563
493
  def visit_ArelExtensions_Nodes_JsonGroup o, collector
564
494
  return super if !json_supported?
565
-
566
495
  if o.as_array
567
496
  collector << 'JSON_ARRAYAGG('
568
497
  collector = visit o.dict, collector
@@ -571,13 +500,13 @@ module ArelExtensions
571
500
  case o.dict
572
501
  when Hash
573
502
  collector << 'JSON_MERGE_PATCH(' if o.dict.length > 1
574
- o.dict.each.with_index do |(k, v), i|
503
+ o.dict.each.with_index do |(k,v),i|
575
504
  if i != 0
576
- collector << COMMA
505
+ collector << Arel::Visitors::MySQL::COMMA
577
506
  end
578
507
  collector << 'JSON_OBJECTAGG('
579
508
  collector = visit k, collector
580
- collector << COMMA
509
+ collector << Arel::Visitors::MySQL::COMMA
581
510
  collector = visit v, collector
582
511
  collector << ')'
583
512
  end
@@ -590,6 +519,7 @@ module ArelExtensions
590
519
  end
591
520
  collector
592
521
  end
522
+
593
523
  end
594
524
  end
595
525
  end