arel_extensions 2.0.21 → 2.2.2

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 (138) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +1 -2
  3. data/.github/workflows/publish.yml +29 -0
  4. data/.github/workflows/release.yml +30 -0
  5. data/.github/workflows/ruby.yml +377 -80
  6. data/.gitignore +7 -6
  7. data/.rubocop.yml +62 -1
  8. data/CONTRIBUTING.md +102 -0
  9. data/Gemfile +2 -23
  10. data/NEWS.md +89 -0
  11. data/README.md +228 -84
  12. data/Rakefile +11 -4
  13. data/TODO +0 -1
  14. data/appveyor.yml +60 -22
  15. data/arel_extensions.gemspec +11 -12
  16. data/bin/build +15 -0
  17. data/bin/compose +6 -0
  18. data/bin/publish +8 -0
  19. data/dev/arelx.dockerfile +44 -0
  20. data/dev/compose.yaml +71 -0
  21. data/dev/postgres.dockerfile +5 -0
  22. data/dev/rbenv +189 -0
  23. data/gemfiles/rails3.gemfile +10 -10
  24. data/gemfiles/rails4_2.gemfile +38 -0
  25. data/gemfiles/rails5.gemfile +29 -0
  26. data/gemfiles/rails5_1_4.gemfile +13 -13
  27. data/gemfiles/rails5_2.gemfile +16 -14
  28. data/gemfiles/rails6.gemfile +18 -15
  29. data/gemfiles/rails6_1.gemfile +18 -15
  30. data/gemfiles/rails7.gemfile +33 -0
  31. data/gemfiles/rails7_1.gemfile +33 -0
  32. data/gemfiles/rails7_2.gemfile +33 -0
  33. data/gemspecs/arel_extensions-v1.gemspec +12 -13
  34. data/gemspecs/arel_extensions-v2.gemspec +11 -12
  35. data/init/mssql.sql +0 -0
  36. data/init/mysql.sql +0 -0
  37. data/init/oracle.sql +0 -0
  38. data/init/postgresql.sql +0 -0
  39. data/init/sqlite.sql +0 -0
  40. data/lib/arel_extensions/aliases.rb +14 -0
  41. data/lib/arel_extensions/attributes.rb +10 -2
  42. data/lib/arel_extensions/boolean_functions.rb +2 -4
  43. data/lib/arel_extensions/common_sql_functions.rb +12 -12
  44. data/lib/arel_extensions/comparators.rb +14 -14
  45. data/lib/arel_extensions/date_duration.rb +14 -9
  46. data/lib/arel_extensions/helpers.rb +62 -0
  47. data/lib/arel_extensions/insert_manager.rb +19 -17
  48. data/lib/arel_extensions/math.rb +48 -45
  49. data/lib/arel_extensions/math_functions.rb +18 -18
  50. data/lib/arel_extensions/nodes/abs.rb +0 -0
  51. data/lib/arel_extensions/nodes/aggregate_function.rb +0 -0
  52. data/lib/arel_extensions/nodes/blank.rb +1 -1
  53. data/lib/arel_extensions/nodes/case.rb +10 -12
  54. data/lib/arel_extensions/nodes/cast.rb +6 -6
  55. data/lib/arel_extensions/nodes/ceil.rb +0 -0
  56. data/lib/arel_extensions/nodes/change_case.rb +0 -0
  57. data/lib/arel_extensions/nodes/coalesce.rb +1 -1
  58. data/lib/arel_extensions/nodes/collate.rb +9 -9
  59. data/lib/arel_extensions/nodes/concat.rb +2 -2
  60. data/lib/arel_extensions/nodes/date_diff.rb +33 -14
  61. data/lib/arel_extensions/nodes/duration.rb +0 -0
  62. data/lib/arel_extensions/nodes/find_in_set.rb +0 -0
  63. data/lib/arel_extensions/nodes/floor.rb +0 -0
  64. data/lib/arel_extensions/nodes/format.rb +3 -2
  65. data/lib/arel_extensions/nodes/formatted_date.rb +42 -0
  66. data/lib/arel_extensions/nodes/formatted_number.rb +2 -2
  67. data/lib/arel_extensions/nodes/function.rb +22 -26
  68. data/lib/arel_extensions/nodes/is_null.rb +0 -0
  69. data/lib/arel_extensions/nodes/json.rb +15 -9
  70. data/lib/arel_extensions/nodes/length.rb +6 -0
  71. data/lib/arel_extensions/nodes/levenshtein_distance.rb +1 -1
  72. data/lib/arel_extensions/nodes/locate.rb +1 -1
  73. data/lib/arel_extensions/nodes/log10.rb +0 -0
  74. data/lib/arel_extensions/nodes/matches.rb +1 -1
  75. data/lib/arel_extensions/nodes/md5.rb +0 -0
  76. data/lib/arel_extensions/nodes/power.rb +0 -0
  77. data/lib/arel_extensions/nodes/rand.rb +0 -0
  78. data/lib/arel_extensions/nodes/repeat.rb +2 -2
  79. data/lib/arel_extensions/nodes/replace.rb +2 -10
  80. data/lib/arel_extensions/nodes/rollup.rb +36 -0
  81. data/lib/arel_extensions/nodes/round.rb +0 -0
  82. data/lib/arel_extensions/nodes/select.rb +10 -0
  83. data/lib/arel_extensions/nodes/soundex.rb +2 -2
  84. data/lib/arel_extensions/nodes/std.rb +0 -0
  85. data/lib/arel_extensions/nodes/substring.rb +1 -1
  86. data/lib/arel_extensions/nodes/sum.rb +0 -0
  87. data/lib/arel_extensions/nodes/then.rb +1 -1
  88. data/lib/arel_extensions/nodes/trim.rb +2 -2
  89. data/lib/arel_extensions/nodes/union.rb +5 -5
  90. data/lib/arel_extensions/nodes/union_all.rb +4 -4
  91. data/lib/arel_extensions/nodes/wday.rb +0 -0
  92. data/lib/arel_extensions/nodes.rb +0 -0
  93. data/lib/arel_extensions/null_functions.rb +16 -0
  94. data/lib/arel_extensions/predications.rb +10 -10
  95. data/lib/arel_extensions/railtie.rb +1 -1
  96. data/lib/arel_extensions/set_functions.rb +3 -3
  97. data/lib/arel_extensions/string_functions.rb +19 -10
  98. data/lib/arel_extensions/tasks.rb +2 -2
  99. data/lib/arel_extensions/version.rb +1 -1
  100. data/lib/arel_extensions/visitors/convert_format.rb +0 -0
  101. data/lib/arel_extensions/visitors/ibm_db.rb +20 -20
  102. data/lib/arel_extensions/visitors/mssql.rb +394 -169
  103. data/lib/arel_extensions/visitors/mysql.rb +238 -151
  104. data/lib/arel_extensions/visitors/oracle.rb +170 -131
  105. data/lib/arel_extensions/visitors/oracle12.rb +16 -16
  106. data/lib/arel_extensions/visitors/postgresql.rb +170 -140
  107. data/lib/arel_extensions/visitors/sqlite.rb +88 -87
  108. data/lib/arel_extensions/visitors/to_sql.rb +185 -156
  109. data/lib/arel_extensions/visitors.rb +73 -60
  110. data/lib/arel_extensions.rb +173 -36
  111. data/test/arelx_test_helper.rb +49 -1
  112. data/test/database.yml +13 -7
  113. data/test/real_db_test.rb +101 -83
  114. data/test/support/fake_record.rb +8 -2
  115. data/test/test_comparators.rb +5 -5
  116. data/test/visitors/test_bulk_insert_oracle.rb +5 -5
  117. data/test/visitors/test_bulk_insert_sqlite.rb +5 -5
  118. data/test/visitors/test_bulk_insert_to_sql.rb +5 -5
  119. data/test/visitors/test_oracle.rb +14 -14
  120. data/test/visitors/test_to_sql.rb +121 -93
  121. data/test/with_ar/all_agnostic_test.rb +630 -320
  122. data/test/with_ar/insert_agnostic_test.rb +25 -18
  123. data/test/with_ar/test_bulk_sqlite.rb +11 -7
  124. data/test/with_ar/test_math_sqlite.rb +18 -14
  125. data/test/with_ar/test_string_mysql.rb +26 -22
  126. data/test/with_ar/test_string_sqlite.rb +26 -22
  127. data/version_v1.rb +1 -1
  128. data/version_v2.rb +1 -1
  129. metadata +24 -26
  130. data/.travis/oracle/download.js +0 -152
  131. data/.travis/oracle/download.sh +0 -30
  132. data/.travis/oracle/download_ojdbc.js +0 -116
  133. data/.travis/oracle/install.sh +0 -34
  134. data/.travis/setup_accounts.sh +0 -9
  135. data/.travis/sqlite3/extension-functions.sh +0 -6
  136. data/.travis.yml +0 -193
  137. data/gemfiles/rails4.gemfile +0 -29
  138. data/gemfiles/rails5_0.gemfile +0 -29
@@ -14,7 +14,7 @@ module ArelExtensions
14
14
  }.freeze
15
15
 
16
16
  NUMBER_COMMA_MAPPING = {
17
- 'fr_FR' => {',' => ' ', '.' =>','}
17
+ 'fr_FR' => {',' => ' ', '.' => ','}
18
18
  }.freeze
19
19
 
20
20
  # String functions
@@ -31,27 +31,27 @@ module ArelExtensions
31
31
  end
32
32
 
33
33
  def visit_ArelExtensions_Nodes_AiMatches o, collector
34
- collector = visit o.left.ai_collate, collector
35
- collector << ' LIKE '
36
- collector = visit o.right.ai_collate, collector
37
- if o.escape
38
- collector << ' ESCAPE '
39
- visit o.escape, collector
40
- else
41
- collector
42
- end
34
+ collector = visit o.left.ai_collate, collector
35
+ collector << ' LIKE '
36
+ collector = visit o.right.ai_collate, collector
37
+ if o.escape
38
+ collector << ' ESCAPE '
39
+ visit o.escape, collector
40
+ else
41
+ collector
42
+ end
43
43
  end
44
44
 
45
45
  def visit_ArelExtensions_Nodes_AiIMatches o, collector
46
- collector = visit o.left.collate(true,true), collector
47
- collector << ' LIKE '
48
- collector = visit o.right.collate(true,true), collector
49
- if o.escape
50
- collector << ' ESCAPE '
51
- visit o.escape, collector
52
- else
53
- collector
54
- end
46
+ collector = visit o.left.collate(true, true), collector
47
+ collector << ' LIKE '
48
+ collector = visit o.right.collate(true, true), collector
49
+ if o.escape
50
+ collector << ' ESCAPE '
51
+ visit o.escape, collector
52
+ else
53
+ collector
54
+ end
55
55
  end
56
56
 
57
57
  def visit_ArelExtensions_Nodes_SMatches o, collector
@@ -94,11 +94,11 @@ module ArelExtensions
94
94
 
95
95
  # Date operations
96
96
  def visit_ArelExtensions_Nodes_DateAdd o, collector
97
- collector << "date("
97
+ collector << 'date('
98
98
  collector = visit o.expressions.first, collector
99
99
  collector << COMMA
100
100
  collector = visit o.sqlite_value, collector
101
- collector << ")"
101
+ collector << ')'
102
102
  collector
103
103
  end
104
104
 
@@ -110,28 +110,28 @@ module ArelExtensions
110
110
  collector << ") - strftime('%s', "
111
111
  collector = visit o.right, collector
112
112
  else
113
- collector << "julianday("
113
+ collector << 'julianday('
114
114
  collector = visit o.left, collector
115
- collector << ") - julianday("
115
+ collector << ') - julianday('
116
116
  collector = visit o.right, collector
117
117
  end
118
- collector << ")"
118
+ collector << ')'
119
119
  collector
120
120
  end
121
121
 
122
122
  def visit_ArelExtensions_Nodes_Duration o, collector
123
123
  collector << "strftime('#{DATE_MAPPING[o.left]}'#{COMMA}"
124
124
  collector = visit o.right, collector
125
- collector << ")"
125
+ collector << ')'
126
126
  collector
127
127
  end
128
128
 
129
129
  def visit_ArelExtensions_Nodes_Locate o, collector
130
- collector << "instr("
130
+ collector << 'instr('
131
131
  collector = visit o.expr, collector
132
132
  collector << COMMA
133
133
  collector = visit o.right, collector
134
- collector << ")"
134
+ collector << ')'
135
135
  collector
136
136
  end
137
137
 
@@ -141,17 +141,17 @@ module ArelExtensions
141
141
  collector = visit arg, collector
142
142
  collector << ' || ' unless i == o.expressions.length - 1
143
143
  }
144
- collector << ")"
144
+ collector << ')'
145
145
  collector
146
146
  end
147
147
 
148
148
  def visit_ArelExtensions_Nodes_Substring o, collector
149
- collector << "SUBSTR("
149
+ collector << 'SUBSTR('
150
150
  o.expressions.each_with_index { |arg, i|
151
151
  collector << COMMA if i != 0
152
152
  collector = visit arg, collector
153
153
  }
154
- collector << ")"
154
+ collector << ')'
155
155
  collector
156
156
  end
157
157
 
@@ -162,32 +162,32 @@ module ArelExtensions
162
162
  end
163
163
 
164
164
  def visit_ArelExtensions_Nodes_IsNotNull o, collector
165
- collector = visit o.expr, collector
165
+ collector = visit o.expr, collector
166
166
  collector << ' IS NOT NULL'
167
167
  collector
168
168
  end
169
169
 
170
170
  def visit_ArelExtensions_Nodes_Rand o, collector
171
- collector << "RANDOM("
171
+ collector << 'RANDOM('
172
172
  if o.left != nil && o.right != nil
173
173
  collector = visit o.left, collector
174
174
  collector << COMMA
175
175
  collector = visit o.right, collector
176
176
  end
177
- collector << ")"
177
+ collector << ')'
178
178
  collector
179
179
  end
180
180
 
181
181
  def visit_Arel_Nodes_Regexp o, collector
182
182
  collector = visit o.left, collector
183
- collector << " REGEXP"
183
+ collector << ' REGEXP'
184
184
  collector = visit o.right, collector
185
185
  collector
186
186
  end
187
187
 
188
188
  def visit_Arel_Nodes_NotRegexp o, collector
189
189
  collector = visit o.left, collector
190
- collector << " NOT REGEXP "
190
+ collector << ' NOT REGEXP '
191
191
  collector = visit o.right, collector
192
192
  collector
193
193
  end
@@ -195,7 +195,7 @@ module ArelExtensions
195
195
  def visit_ArelExtensions_Nodes_Wday o, collector
196
196
  collector << "STRFTIME('%w',"
197
197
  collector = visit o.date, collector
198
- collector << ")"
198
+ collector << ')'
199
199
  collector
200
200
  end
201
201
 
@@ -208,32 +208,32 @@ module ArelExtensions
208
208
  # AS FLOAT
209
209
  # )
210
210
  def visit_ArelExtensions_Nodes_Floor o, collector
211
- collector << "CAST(CASE WHEN "
211
+ collector << 'CAST(CASE WHEN '
212
212
  collector = visit o.left, collector
213
- collector << " >= 0 THEN CAST("
213
+ collector << ' >= 0 THEN CAST('
214
214
  collector = visit o.left, collector
215
- collector << " AS INT) WHEN CAST("
215
+ collector << ' AS INT) WHEN CAST('
216
216
  collector = visit o.left, collector
217
- collector << " AS INT) = "
217
+ collector << ' AS INT) = '
218
218
  collector = visit o.left, collector
219
- collector << " THEN CAST("
219
+ collector << ' THEN CAST('
220
220
  collector = visit o.left, collector
221
- collector << " AS INT) ELSE CAST(("
221
+ collector << ' AS INT) ELSE CAST(('
222
222
  collector = visit o.left, collector
223
- collector << " - 1.0) AS INT) END AS FLOAT)"
223
+ collector << ' - 1.0) AS INT) END AS FLOAT)'
224
224
  collector
225
225
  end
226
226
 
227
227
  def visit_ArelExtensions_Nodes_Ceil o, collector
228
- collector << "CASE WHEN ROUND("
228
+ collector << 'CASE WHEN ROUND('
229
229
  collector = visit o.left, collector
230
- collector << ", 1) > ROUND("
230
+ collector << ', 1) > ROUND('
231
231
  collector = visit o.left, collector
232
- collector << ") THEN ROUND("
232
+ collector << ') THEN ROUND('
233
233
  collector = visit o.left, collector
234
- collector << ") + 1 ELSE ROUND("
234
+ collector << ') + 1 ELSE ROUND('
235
235
  collector = visit o.left, collector
236
- collector << ") END"
236
+ collector << ') END'
237
237
  collector
238
238
  end
239
239
 
@@ -243,16 +243,16 @@ module ArelExtensions
243
243
  collector << 'SELECT '
244
244
  len = row.length - 1
245
245
  row.zip(o.cols).each_with_index { |(value, attr), i|
246
- case value
247
- when Arel::Nodes::SqlLiteral, Arel::Nodes::BindParam
248
- collector = visit value.as(attr.name), collector
249
- else
250
- collector << quote(value, attr && column_for(attr)).to_s
251
- if idx == 0
252
- collector << " AS "
253
- collector << quote(attr.name)
254
- end
246
+ case value
247
+ when Arel::Nodes::SqlLiteral, Arel::Nodes::BindParam
248
+ collector = visit value.as(attr.name), collector
249
+ else
250
+ collector << quote(value, attr && column_for(attr)).to_s
251
+ if idx == 0
252
+ collector << ' AS '
253
+ collector << quote(attr.name)
255
254
  end
255
+ end
256
256
  collector << COMMA unless i == len
257
257
  }
258
258
  collector << ' UNION ALL ' unless idx == o.left.length - 1
@@ -265,22 +265,22 @@ module ArelExtensions
265
265
  collector << 'SELECT '
266
266
  len = row.length - 1
267
267
  row.zip(o.cols).each_with_index { |(value, attr), i|
268
- case value
269
- when Arel::Nodes::SqlLiteral, Arel::Nodes::BindParam
270
- collector = visit value.as(attr.name), collector
271
- when Integer
272
- collector << value.to_s
273
- if idx == 0
274
- collector << " AS "
275
- collector << quote(attr.name)
276
- end
277
- else
278
- collector << (attr && attr.able_to_type_cast? ? quote(attr.type_cast_for_database(value)) : quote(value).to_s)
279
- if idx == 0
280
- collector << " AS "
281
- collector << quote(attr.name)
282
- end
268
+ case value
269
+ when Arel::Nodes::SqlLiteral, Arel::Nodes::BindParam
270
+ collector = visit value.as(attr.name), collector
271
+ when Integer
272
+ collector << value.to_s
273
+ if idx == 0
274
+ collector << ' AS '
275
+ collector << quote(attr.name)
276
+ end
277
+ else
278
+ collector << (attr && attr.able_to_type_cast? ? quote(attr.type_cast_for_database(value)) : quote(value).to_s)
279
+ if idx == 0
280
+ collector << ' AS '
281
+ collector << quote(attr.name)
283
282
  end
283
+ end
284
284
  collector << COMMA unless i == len
285
285
  }
286
286
  collector << ' UNION ALL ' unless idx == o.left.length - 1
@@ -296,7 +296,7 @@ module ArelExtensions
296
296
  else
297
297
  visit o.left, collector
298
298
  end
299
- collector << " UNION "
299
+ collector << ' UNION '
300
300
  collector =
301
301
  if o.right.is_a?(Arel::SelectManager)
302
302
  visit o.right.ast, collector
@@ -313,7 +313,7 @@ module ArelExtensions
313
313
  else
314
314
  visit o.left, collector
315
315
  end
316
- collector << " UNION ALL "
316
+ collector << ' UNION ALL '
317
317
  collector =
318
318
  if o.right.is_a?(Arel::SelectManager)
319
319
  visit o.right.ast, collector
@@ -325,23 +325,23 @@ module ArelExtensions
325
325
 
326
326
  def get_time_converted element
327
327
  if element.is_a?(Time)
328
- return Arel::Nodes::NamedFunction.new('STRFTIME',[element, '%H:%M:%S'])
328
+ Arel::Nodes::NamedFunction.new('STRFTIME', [element, '%H:%M:%S'])
329
329
  elsif element.is_a?(Arel::Attributes::Attribute)
330
- col = Arel::Table.engine.connection.schema_cache.columns_hash(element.relation.table_name)[element.name.to_s]
330
+ col = Arel.column_of(element.relation.table_name, element.name.to_s)
331
331
  if col && (col.type == :time)
332
- return Arel::Nodes::NamedFunction.new('STRFTIME',[element, '%H:%M:%S'])
332
+ Arel::Nodes::NamedFunction.new('STRFTIME', [element, '%H:%M:%S'])
333
333
  else
334
- return element
334
+ element
335
335
  end
336
336
  else
337
- return element
337
+ element
338
338
  end
339
339
  end
340
340
 
341
341
  remove_method(:visit_Arel_Nodes_GreaterThanOrEqual) rescue nil
342
342
  def visit_Arel_Nodes_GreaterThanOrEqual o, collector
343
343
  collector = visit get_time_converted(o.left), collector
344
- collector << " >= "
344
+ collector << ' >= '
345
345
  collector = visit get_time_converted(o.right), collector
346
346
  collector
347
347
  end
@@ -349,7 +349,7 @@ module ArelExtensions
349
349
  remove_method(:visit_Arel_Nodes_GreaterThan) rescue nil
350
350
  def visit_Arel_Nodes_GreaterThan o, collector
351
351
  collector = visit get_time_converted(o.left), collector
352
- collector << " > "
352
+ collector << ' > '
353
353
  collector = visit get_time_converted(o.right), collector
354
354
  collector
355
355
  end
@@ -357,7 +357,7 @@ module ArelExtensions
357
357
  remove_method(:visit_Arel_Nodes_LessThanOrEqual) rescue nil
358
358
  def visit_Arel_Nodes_LessThanOrEqual o, collector
359
359
  collector = visit get_time_converted(o.left), collector
360
- collector << " <= "
360
+ collector << ' <= '
361
361
  collector = visit get_time_converted(o.right), collector
362
362
  collector
363
363
  end
@@ -365,7 +365,7 @@ module ArelExtensions
365
365
  remove_method(:visit_Arel_Nodes_LessThan) rescue nil
366
366
  def visit_Arel_Nodes_LessThan o, collector
367
367
  collector = visit get_time_converted(o.left), collector
368
- collector << " < "
368
+ collector << ' < '
369
369
  collector = visit get_time_converted(o.right), collector
370
370
  collector
371
371
  end
@@ -379,17 +379,18 @@ module ArelExtensions
379
379
  else
380
380
  collector = visit o.left, collector
381
381
  end
382
- collector << " AS \""
382
+ sep = o.right.size > 1 && o.right[0] == '"' && o.right[-1] == '"' ? '' : '"'
383
+ collector << " AS #{sep}"
383
384
  collector = visit o.right, collector
384
- collector << "\""
385
+ collector << "#{sep}"
385
386
  collector
386
387
  end
387
388
 
388
389
  def visit_ArelExtensions_Nodes_FormattedNumber o, collector
389
- format = Arel::Nodes::NamedFunction.new('printf',[Arel::Nodes.build_quoted(o.original_string),o.left])
390
+ format = Arel::Nodes::NamedFunction.new('printf', [Arel.quoted(o.original_string), o.left])
390
391
  locale_map = NUMBER_COMMA_MAPPING[o.locale]
391
392
  if locale_map
392
- format = format.replace(',',locale_map[',']).replace('.',locale_map['.'])
393
+ format = format.replace(',', locale_map[',']).replace('.', locale_map['.'])
393
394
  end
394
395
  visit format, collector
395
396
  collector