arel_extensions 1.2.5 → 1.2.8
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +7 -4
- data/README.md +7 -2
- data/Rakefile +23 -23
- data/arel_extensions.gemspec +1 -1
- data/functions.html +2 -2
- data/gemfiles/rails6.gemfile +30 -0
- data/gemspec_v2/arel_extensions-v2.gemspec +28 -0
- data/generate_gems.sh +13 -0
- data/lib/arel_extensions.rb +4 -1
- data/lib/arel_extensions/boolean_functions.rb +0 -2
- data/lib/arel_extensions/common_sql_functions.rb +5 -4
- data/lib/arel_extensions/insert_manager.rb +24 -24
- data/lib/arel_extensions/math.rb +3 -3
- data/lib/arel_extensions/math_functions.rb +4 -4
- data/lib/arel_extensions/nodes/case.rb +0 -2
- data/lib/arel_extensions/nodes/collate.rb +1 -1
- data/lib/arel_extensions/nodes/date_diff.rb +1 -3
- data/lib/arel_extensions/nodes/duration.rb +0 -2
- data/lib/arel_extensions/nodes/formatted_number.rb +20 -20
- data/lib/arel_extensions/nodes/json.rb +28 -30
- data/lib/arel_extensions/nodes/power.rb +5 -4
- data/lib/arel_extensions/nodes/replace.rb +23 -5
- data/lib/arel_extensions/nodes/round.rb +5 -5
- data/lib/arel_extensions/nodes/soundex.rb +14 -13
- data/lib/arel_extensions/nodes/substring.rb +8 -15
- data/lib/arel_extensions/nodes/trim.rb +1 -1
- data/lib/arel_extensions/nodes/union.rb +0 -1
- data/lib/arel_extensions/nodes/union_all.rb +0 -1
- data/lib/arel_extensions/predications.rb +16 -17
- data/lib/arel_extensions/string_functions.rb +12 -6
- data/lib/arel_extensions/tasks.rb +5 -5
- data/lib/arel_extensions/version.rb +1 -1
- data/lib/arel_extensions/visitors/mssql.rb +13 -12
- data/lib/arel_extensions/visitors/mysql.rb +50 -35
- data/lib/arel_extensions/visitors/oracle.rb +7 -6
- data/lib/arel_extensions/visitors/oracle12.rb +1 -1
- data/lib/arel_extensions/visitors/postgresql.rb +45 -27
- data/lib/arel_extensions/visitors/sqlite.rb +41 -27
- data/lib/arel_extensions/visitors/to_sql.rb +18 -5
- data/test/visitors/test_bulk_insert_oracle.rb +6 -6
- data/test/visitors/test_bulk_insert_sqlite.rb +5 -5
- data/test/visitors/test_to_sql.rb +10 -2
- data/test/with_ar/all_agnostic_test.rb +44 -33
- data/test/with_ar/test_bulk_sqlite.rb +1 -1
- data/test/with_ar/test_math_sqlite.rb +1 -1
- data/test/with_ar/test_string_mysql.rb +1 -3
- data/test/with_ar/test_string_sqlite.rb +1 -5
- data/version_v1.rb +3 -0
- data/version_v2.rb +3 -0
- metadata +9 -4
@@ -97,26 +97,28 @@ module ArelExtensions
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def visit_ArelExtensions_Nodes_Collate o, collector
|
100
|
-
|
101
|
-
|
102
|
-
|
100
|
+
charset =
|
101
|
+
case o.expressions.first
|
102
|
+
when Arel::Attributes::Attribute
|
103
|
+
case o.option
|
103
104
|
when 'latin1','utf8'
|
104
105
|
o.option
|
105
106
|
else
|
106
107
|
Arel::Table.engine.connection.charset || 'utf8'
|
107
108
|
end
|
108
|
-
|
109
|
-
|
110
|
-
|
109
|
+
else
|
110
|
+
(o.option == 'latin1') ? 'latin1' : 'utf8'
|
111
|
+
end
|
111
112
|
collector = visit o.expressions.first, collector
|
112
|
-
|
113
|
-
|
113
|
+
collector <<
|
114
|
+
if o.ai
|
115
|
+
" COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : 'utf8_unicode_ci' }"
|
114
116
|
#doesn't work in latin1
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
117
|
+
elsif o.ci
|
118
|
+
" COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : 'utf8_unicode_ci' }"
|
119
|
+
else
|
120
|
+
" COLLATE #{charset}_bin"
|
121
|
+
end
|
120
122
|
collector
|
121
123
|
end
|
122
124
|
|
@@ -262,7 +264,7 @@ module ArelExtensions
|
|
262
264
|
else
|
263
265
|
if o.with_interval
|
264
266
|
case o.left
|
265
|
-
when
|
267
|
+
when 'd','m','y'
|
266
268
|
interval = 'DAY'
|
267
269
|
when 'h','mn','s'
|
268
270
|
interval = 'SECOND'
|
@@ -362,20 +364,21 @@ module ArelExtensions
|
|
362
364
|
else(o.flags.include?('+') ? '+' : (o.flags.include?(' ') ? ' ' : ''))
|
363
365
|
sign_length = ArelExtensions::Nodes::Length.new([sign])
|
364
366
|
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
367
|
+
number =
|
368
|
+
if o.scientific_notation
|
369
|
+
ArelExtensions::Nodes::Concat.new([
|
370
|
+
Arel::Nodes::NamedFunction.new('FORMAT',[
|
371
|
+
col.abs/Arel::Nodes.build_quoted(10).pow(col.abs.log10.floor)
|
372
|
+
]+params),
|
373
|
+
o.type,
|
374
|
+
Arel::Nodes::NamedFunction.new('FORMAT',[
|
375
|
+
col.abs.log10.floor,
|
376
|
+
0
|
377
|
+
])
|
374
378
|
])
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
end
|
379
|
+
else
|
380
|
+
Arel::Nodes::NamedFunction.new('FORMAT',[col.abs]+params)
|
381
|
+
end
|
379
382
|
|
380
383
|
repeated_char = (o.width == 0) ? Arel::Nodes.build_quoted('') : ArelExtensions::Nodes::Case.new().
|
381
384
|
when(Arel::Nodes.build_quoted(o.width).abs-(number.length+sign_length)>0).
|
@@ -399,19 +402,19 @@ module ArelExtensions
|
|
399
402
|
end
|
400
403
|
|
401
404
|
def visit_Aggregate_For_AggregateFunction o, collector
|
402
|
-
if !
|
405
|
+
if !window_supported?
|
403
406
|
warn("Warning : ArelExtensions: Window Functions are not available in the current version on the DBMS.")
|
404
407
|
return collector
|
405
408
|
end
|
406
409
|
|
407
|
-
if o.order || o.group
|
410
|
+
if !o.order.empty? || !o.group.empty?
|
408
411
|
collector << " OVER ("
|
409
|
-
if o.group
|
412
|
+
if !o.group.empty?
|
410
413
|
collector << " PARTITION BY ("
|
411
414
|
visit o.group, collector
|
412
415
|
collector << ")"
|
413
416
|
end
|
414
|
-
if o.order
|
417
|
+
if !o.order.empty?
|
415
418
|
collector << " ORDER BY ("
|
416
419
|
visit o.order, collector
|
417
420
|
collector << ")"
|
@@ -433,15 +436,27 @@ module ArelExtensions
|
|
433
436
|
collector << (o.unbiased_estimator ? "VAR_SAMP(" : "VAR_POP(")
|
434
437
|
visit o.left, collector
|
435
438
|
collector << ")"
|
439
|
+
visit_Aggregate_For_AggregateFunction o, collector
|
436
440
|
collector
|
437
441
|
end
|
438
442
|
|
439
443
|
# JSON if implemented only after 10.2.3 in MariaDb and 5.7 in MySql
|
440
444
|
def json_supported?
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
+
version_supported?('10.2.3', '5.7.0')
|
446
|
+
end
|
447
|
+
|
448
|
+
def window_supported?
|
449
|
+
version_supported?('10.2.3', '8.0')
|
450
|
+
end
|
451
|
+
|
452
|
+
def version_supported?(mysql_v = '10.2.3',mariadb_v = '5.7.0')
|
453
|
+
conn = Arel::Table.engine.connection
|
454
|
+
conn.send(:mariadb?) &&
|
455
|
+
(conn.respond_to?(:get_database_version) && conn.send(:get_database_version) >= mysql_v ||
|
456
|
+
conn.respond_to?(:version) && conn.send(:version) >= mysql_v) ||
|
457
|
+
!Arel::Table.engine.connection.send(:mariadb?) &&
|
458
|
+
(conn.respond_to?(:get_database_version) && conn.send(:get_database_version) >= mariadb_v ||
|
459
|
+
conn.respond_to?(:version) && conn.send(:version) >= mariadb_v)
|
445
460
|
end
|
446
461
|
|
447
462
|
def visit_ArelExtensions_Nodes_Json o,collector
|
@@ -131,11 +131,12 @@ module ArelExtensions
|
|
131
131
|
collector << "(LISTAGG("
|
132
132
|
collector = visit o.left, collector
|
133
133
|
collector << Arel::Visitors::Oracle::COMMA
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
134
|
+
collector =
|
135
|
+
if o.separator && o.separator != 'NULL'
|
136
|
+
visit o.separator, collector
|
137
|
+
else
|
138
|
+
visit Arel::Nodes.build_quoted(','), collector
|
139
|
+
end
|
139
140
|
collector << ") WITHIN GROUP (ORDER BY "
|
140
141
|
if !o.order.blank?
|
141
142
|
o.order.each_with_index do |order,i|
|
@@ -154,7 +155,7 @@ module ArelExtensions
|
|
154
155
|
o.expressions.each_with_index { |arg, i|
|
155
156
|
collector << Arel::Visitors::Oracle::COMMA unless i == 0
|
156
157
|
if i > 0 && o.left_node_type == :text
|
157
|
-
if arg == ''
|
158
|
+
if arg == '' || (arg.is_a?(Arel::Nodes::Quoted) && (arg.expr == ''))
|
158
159
|
collector << "NULL"
|
159
160
|
else
|
160
161
|
collector << 'TO_CLOB('
|
@@ -120,11 +120,12 @@ module ArelExtensions
|
|
120
120
|
o.order = nil
|
121
121
|
visit_Aggregate_For_AggregateFunction o, collector
|
122
122
|
collector << Arel::Visitors::PostgreSQL::COMMA
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
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
|
128
129
|
collector << ")"
|
129
130
|
collector
|
130
131
|
end
|
@@ -302,6 +303,22 @@ module ArelExtensions
|
|
302
303
|
collector
|
303
304
|
end
|
304
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
|
+
|
305
322
|
def visit_ArelExtensions_Nodes_IsNull o, collector
|
306
323
|
collector = visit o.expr, collector
|
307
324
|
collector << ' IS NULL'
|
@@ -371,27 +388,28 @@ module ArelExtensions
|
|
371
388
|
else(o.flags.include?('+') ? '+' : (o.flags.include?(' ') ? ' ' : ''))
|
372
389
|
sign_length = ArelExtensions::Nodes::Length.new([sign])
|
373
390
|
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
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
|
395
413
|
|
396
414
|
repeated_char = (o.width == 0) ? Arel::Nodes.build_quoted('') : ArelExtensions::Nodes::Case.new().
|
397
415
|
when(Arel::Nodes.build_quoted(o.width).abs-(number.length+sign_length)>0).
|
@@ -466,7 +484,7 @@ module ArelExtensions
|
|
466
484
|
if i != 0
|
467
485
|
collector << Arel::Visitors::MySQL::COMMA
|
468
486
|
end
|
469
|
-
collector
|
487
|
+
collector = visit v, collector
|
470
488
|
end
|
471
489
|
collector << '])'
|
472
490
|
when Hash
|
@@ -193,18 +193,28 @@ module ArelExtensions
|
|
193
193
|
collector
|
194
194
|
end
|
195
195
|
|
196
|
-
#
|
197
|
-
#
|
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
|
205
|
+
collector << "CAST(CASE WHEN "
|
200
206
|
collector = visit o.left, collector
|
201
|
-
collector << "
|
207
|
+
collector << " >= 0 THEN CAST("
|
202
208
|
collector = visit o.left, collector
|
203
|
-
collector << ")
|
209
|
+
collector << " AS INT) WHEN CAST("
|
210
|
+
collector = visit o.left, collector
|
211
|
+
collector << " AS INT) = "
|
204
212
|
collector = visit o.left, collector
|
205
|
-
collector << "
|
213
|
+
collector << " THEN CAST("
|
206
214
|
collector = visit o.left, collector
|
207
|
-
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
|
|
@@ -270,32 +280,36 @@ module ArelExtensions
|
|
270
280
|
end
|
271
281
|
|
272
282
|
def visit_ArelExtensions_Nodes_Union o, collector
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
283
|
+
collector =
|
284
|
+
if o.left.is_a?(Arel::SelectManager)
|
285
|
+
visit o.left.ast, collector
|
286
|
+
else
|
287
|
+
visit o.left, collector
|
288
|
+
end
|
278
289
|
collector << " UNION "
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
290
|
+
collector =
|
291
|
+
if o.right.is_a?(Arel::SelectManager)
|
292
|
+
visit o.right.ast, collector
|
293
|
+
else
|
294
|
+
visit o.right, collector
|
295
|
+
end
|
284
296
|
collector
|
285
297
|
end
|
286
298
|
|
287
299
|
def visit_ArelExtensions_Nodes_UnionAll o, collector
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
300
|
+
collector =
|
301
|
+
if o.left.is_a?(Arel::SelectManager)
|
302
|
+
visit o.left.ast, collector
|
303
|
+
else
|
304
|
+
visit o.left, collector
|
305
|
+
end
|
293
306
|
collector << " UNION ALL "
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
307
|
+
collector =
|
308
|
+
if o.right.is_a?(Arel::SelectManager)
|
309
|
+
visit o.right.ast, collector
|
310
|
+
else
|
311
|
+
visit o.right, collector
|
312
|
+
end
|
299
313
|
collector
|
300
314
|
end
|
301
315
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module ArelExtensions
|
2
2
|
module Visitors
|
3
|
-
|
3
|
+
Arel::Visitors::ToSql.class_eval do
|
4
|
+
Arel::Visitors::ToSql::COMMA = ', ' unless defined?(Arel::Visitors::ToSql::COMMA)
|
4
5
|
|
5
6
|
# Math Functions
|
6
7
|
def visit_ArelExtensions_Nodes_Abs o, collector
|
@@ -134,10 +135,22 @@ module ArelExtensions
|
|
134
135
|
|
135
136
|
def visit_ArelExtensions_Nodes_Replace o, collector
|
136
137
|
collector << "REPLACE("
|
137
|
-
o.
|
138
|
-
|
139
|
-
|
140
|
-
|
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
|
141
154
|
collector << ")"
|
142
155
|
collector
|
143
156
|
end
|
@@ -9,8 +9,8 @@ module ArelExtensions
|
|
9
9
|
@table = Arel::Table.new(:users)
|
10
10
|
@cols = ['name', 'comments', 'created_at']
|
11
11
|
@data = [
|
12
|
-
|
13
|
-
|
12
|
+
['nom1', "sdfdsfdsfsdf", '2016-01-01'],
|
13
|
+
['nom2', "sdfdsfdsfsdf", '2016-01-01']
|
14
14
|
]
|
15
15
|
end
|
16
16
|
|
@@ -24,11 +24,11 @@ module ArelExtensions
|
|
24
24
|
|
25
25
|
it "should import large set of data in Oracle" do
|
26
26
|
insert_manager = Arel::VERSION.to_i > 6 ? Arel::InsertManager.new().into(@table) : Arel::InsertManager.new(@conn).into(@table)
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
insert_manager.bulk_insert(@cols, @data)
|
28
|
+
sql = compile(insert_manager.ast)
|
29
|
+
sql.must_be_like %Q[INSERT INTO "users" ("name", "comments", "created_at") ((SELECT 'nom1', 'sdfdsfdsfsdf', '2016-01-01' FROM DUAL) UNION ALL (SELECT 'nom2', 'sdfdsfdsfsdf', '2016-01-01' FROM DUAL))]
|
30
30
|
end
|
31
31
|
|
32
|
-
|
32
|
+
end
|
33
33
|
end
|
34
34
|
end
|
@@ -11,8 +11,8 @@ module ArelExtensions
|
|
11
11
|
Arel::Table.engine = @conn
|
12
12
|
@cols = ['id', 'name', 'comments', 'created_at']
|
13
13
|
@data = [
|
14
|
-
|
15
|
-
|
14
|
+
[23, 'nom1', "sdfdsfdsfsdf", '2016-01-01'],
|
15
|
+
[25, 'nom2', "sdfdsfdsfsdf", '2016-01-01']
|
16
16
|
]
|
17
17
|
end
|
18
18
|
|
@@ -28,9 +28,9 @@ module ArelExtensions
|
|
28
28
|
insert_manager = Arel::VERSION.to_i > 6 ? Arel::InsertManager.new().into(@table) : Arel::InsertManager.new(@conn).into(@table)
|
29
29
|
insert_manager.bulk_insert(@cols, @data)
|
30
30
|
sql = compile(insert_manager.ast)
|
31
|
-
|
31
|
+
sql.must_be_like %Q[INSERT INTO "users" ("id", "name", "comments", "created_at") SELECT 23 AS 'id', 'nom1' AS 'name', 'sdfdsfdsfsdf' AS 'comments', '2016-01-01' AS 'created_at' UNION ALL SELECT 25, 'nom2', 'sdfdsfdsfsdf', '2016-01-01']
|
32
32
|
end
|
33
33
|
|
34
|
-
|
34
|
+
end
|
35
35
|
end
|
36
|
-
end
|
36
|
+
end
|