arel_extensions 1.2.18 → 1.3.0
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/.github/workflows/ruby.yml +183 -0
- data/README.md +42 -0
- data/arel_extensions.gemspec +3 -3
- data/gemfiles/rails5_2.gemfile +6 -5
- data/gemfiles/rails6.gemfile +6 -6
- data/gemfiles/rails6_1.gemfile +30 -0
- data/gemfiles/rails7.gemfile +30 -0
- data/gemspecs/arel_extensions-v1.gemspec +28 -0
- data/{gemspec_v2 → gemspecs}/arel_extensions-v2.gemspec +1 -1
- data/generate_gems.sh +4 -3
- data/lib/arel_extensions/aliases.rb +14 -0
- data/lib/arel_extensions/attributes.rb +2 -0
- data/lib/arel_extensions/insert_manager.rb +19 -17
- data/lib/arel_extensions/math.rb +16 -16
- data/lib/arel_extensions/math_functions.rb +7 -3
- data/lib/arel_extensions/nodes/case.rb +2 -1
- data/lib/arel_extensions/nodes/cast.rb +1 -1
- data/lib/arel_extensions/nodes/concat.rb +1 -1
- data/lib/arel_extensions/nodes/function.rb +9 -3
- data/lib/arel_extensions/nodes/json.rb +3 -1
- data/lib/arel_extensions/nodes/length.rb +6 -0
- data/lib/arel_extensions/nodes/replace.rb +0 -8
- data/lib/arel_extensions/nodes/std.rb +4 -4
- data/lib/arel_extensions/nodes/union.rb +1 -1
- data/lib/arel_extensions/nodes/union_all.rb +1 -1
- data/lib/arel_extensions/string_functions.rb +10 -2
- data/lib/arel_extensions/version.rb +1 -1
- data/lib/arel_extensions/visitors/mssql.rb +1 -1
- data/lib/arel_extensions/visitors/mysql.rb +9 -2
- data/lib/arel_extensions/visitors/oracle.rb +2 -2
- data/lib/arel_extensions/visitors/oracle12.rb +0 -12
- data/lib/arel_extensions/visitors/postgresql.rb +14 -8
- data/lib/arel_extensions/visitors/to_sql.rb +26 -9
- data/lib/arel_extensions/visitors.rb +9 -1
- data/lib/arel_extensions.rb +64 -14
- data/test/database.yml +2 -0
- data/test/real_db_test.rb +5 -1
- data/test/visitors/test_to_sql.rb +18 -11
- data/test/with_ar/all_agnostic_test.rb +20 -4
- data/test/with_ar/insert_agnostic_test.rb +6 -2
- data/test/with_ar/test_bulk_sqlite.rb +6 -2
- data/test/with_ar/test_math_sqlite.rb +6 -2
- data/test/with_ar/test_string_mysql.rb +6 -2
- data/test/with_ar/test_string_sqlite.rb +6 -2
- data/version_v1.rb +1 -1
- data/version_v2.rb +1 -1
- metadata +14 -9
@@ -21,7 +21,11 @@ module ArelExtensions
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def as other
|
24
|
-
Arel::Nodes::As.new(self, Arel.sql(other))
|
24
|
+
res = Arel::Nodes::As.new(self.clone, Arel.sql(other))
|
25
|
+
if Gem::Version.new(Arel::VERSION) >= Gem::Version.new("9.0.0")
|
26
|
+
self.alias = Arel.sql(other)
|
27
|
+
end
|
28
|
+
res
|
25
29
|
end
|
26
30
|
|
27
31
|
def expr
|
@@ -48,7 +52,9 @@ module ArelExtensions
|
|
48
52
|
case att
|
49
53
|
when Arel::Attributes::Attribute
|
50
54
|
begin
|
51
|
-
Arel::Table.engine.connection.
|
55
|
+
if Arel::Table.engine.connection.tables.include? att.relation.table_name
|
56
|
+
Arel::Table.engine.connection.schema_cache.columns_hash(att.relation.table_name)[att.name.to_s].type
|
57
|
+
end
|
52
58
|
rescue
|
53
59
|
att
|
54
60
|
end
|
@@ -76,7 +82,7 @@ module ArelExtensions
|
|
76
82
|
when ActiveSupport::Duration
|
77
83
|
Arel.sql(object.to_i)
|
78
84
|
when Array
|
79
|
-
Arel
|
85
|
+
Arel.grouping(object.map{|e| convert_to_node(e)})
|
80
86
|
else
|
81
87
|
raise(ArgumentError, "#{object.class} cannot be converted to CONCAT arg")
|
82
88
|
end
|
@@ -10,10 +10,6 @@ module ArelExtensions
|
|
10
10
|
@substitute = convert_to_node(substitute)
|
11
11
|
super([@left,@pattern,@substitute])
|
12
12
|
end
|
13
|
-
|
14
|
-
def +(other)
|
15
|
-
return ArelExtensions::Nodes::Concat.new(self.expressions + [other])
|
16
|
-
end
|
17
13
|
end
|
18
14
|
|
19
15
|
class RegexpReplace < Function
|
@@ -26,10 +22,6 @@ module ArelExtensions
|
|
26
22
|
@substitute = convert_to_node(substitute)
|
27
23
|
super([@left,@pattern,@substitute])
|
28
24
|
end
|
29
|
-
|
30
|
-
def +(other)
|
31
|
-
return ArelExtensions::Nodes::Concat.new(self.expressions + [other])
|
32
|
-
end
|
33
25
|
end
|
34
26
|
end
|
35
27
|
end
|
@@ -4,9 +4,9 @@ module ArelExtensions
|
|
4
4
|
RETURN_TYPE = :number
|
5
5
|
attr_accessor :unbiased_estimator
|
6
6
|
|
7
|
-
def initialize node, opts
|
7
|
+
def initialize node, **opts
|
8
8
|
@unbiased_estimator = opts[:unbiased] ? true : false
|
9
|
-
super node, opts
|
9
|
+
super node, **opts
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
@@ -14,9 +14,9 @@ module ArelExtensions
|
|
14
14
|
RETURN_TYPE = :number
|
15
15
|
attr_accessor :unbiased_estimator
|
16
16
|
|
17
|
-
def initialize node, opts
|
17
|
+
def initialize node, **opts
|
18
18
|
@unbiased_estimator = opts[:unbiased] ? true : false
|
19
|
-
super node, opts
|
19
|
+
super node, **opts
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
@@ -14,7 +14,7 @@ module ArelExtensions
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def as other
|
17
|
-
Arel::Nodes::TableAlias.new Arel
|
17
|
+
Arel::Nodes::TableAlias.new Arel.grouping(self), Arel::Nodes::SqlLiteral.new(other.to_s)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -10,7 +10,7 @@ module ArelExtensions
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def as other
|
13
|
-
Arel::Nodes::TableAlias.new Arel
|
13
|
+
Arel::Nodes::TableAlias.new Arel.grouping(self), Arel::Nodes::SqlLiteral.new(other.to_s)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
@@ -24,9 +24,17 @@ module ArelExtensions
|
|
24
24
|
ArelExtensions::Nodes::FindInSet.new [other, self]
|
25
25
|
end
|
26
26
|
|
27
|
-
# LENGTH function returns the length of the value in a text field.
|
27
|
+
# LENGTH function returns the length (bytewise) of the value in a text field.
|
28
28
|
def length
|
29
|
-
ArelExtensions::Nodes::Length.new
|
29
|
+
ArelExtensions::Nodes::Length.new self, true
|
30
|
+
end
|
31
|
+
|
32
|
+
def byte_length
|
33
|
+
ArelExtensions::Nodes::Length.new self, true
|
34
|
+
end
|
35
|
+
|
36
|
+
def char_length
|
37
|
+
ArelExtensions::Nodes::Length.new self, false
|
30
38
|
end
|
31
39
|
|
32
40
|
# LOCATE function returns the first starting position of a string in another string.
|
@@ -354,9 +354,16 @@ module ArelExtensions
|
|
354
354
|
else
|
355
355
|
collector = visit o.left, collector
|
356
356
|
end
|
357
|
-
collector << " AS
|
357
|
+
collector << " AS "
|
358
|
+
|
359
|
+
# sometimes these values are already quoted, if they are, don't double quote it
|
360
|
+
quote = o.right.is_a?(Arel::Nodes::SqlLiteral) && o.right[0] != '`' && o.right[-1] != '`'
|
361
|
+
|
362
|
+
collector << '`' if quote
|
358
363
|
collector = visit o.right, collector
|
359
|
-
collector <<
|
364
|
+
collector << '`' if quote
|
365
|
+
|
366
|
+
collector
|
360
367
|
collector
|
361
368
|
end
|
362
369
|
|
@@ -5,7 +5,7 @@ module ArelExtensions
|
|
5
5
|
SPECIAL_CHARS = {"\t" => 'CHR(9)', "\n" => 'CHR(10)', "\r" => 'CHR(13)'}
|
6
6
|
DATE_MAPPING = {'d' => 'DAY', 'm' => 'MONTH', 'w' => 'IW', 'y' => 'YEAR', 'wd' => 'D', 'h' => 'HOUR', 'mn' => 'MINUTE', 's' => 'SECOND'}
|
7
7
|
DATE_FORMAT_DIRECTIVES = {
|
8
|
-
'%Y' => '
|
8
|
+
'%Y' => 'YYYY', '%C' => 'CC', '%y' => 'YY', '%m' => 'MM', '%B' => 'Month', '%^B' => 'MONTH', '%b' => 'Mon', '%^b' => 'MON',
|
9
9
|
'%d' => 'DD', '%e' => 'FMDD', '%j' => 'DDD', '%w' => '', '%A' => 'Day', # day, weekday
|
10
10
|
'%H' => 'HH24', '%k' => '', '%I' => 'HH', '%l' => '', '%P' => 'am', '%p' => 'AM', # hours
|
11
11
|
'%M' => 'MI', '%S' => 'SS', '%L' => 'MS', '%N' => 'US', '%z' => 'tz' # seconds, subseconds
|
@@ -308,7 +308,7 @@ module ArelExtensions
|
|
308
308
|
end
|
309
309
|
|
310
310
|
def visit_ArelExtensions_Nodes_Length o, collector
|
311
|
-
collector << "LENGTH("
|
311
|
+
collector << "LENGTH#{o.bytewise ? 'B' : ''}("
|
312
312
|
collector = visit o.expr, collector
|
313
313
|
collector << ")"
|
314
314
|
collector
|
@@ -2,18 +2,6 @@ module ArelExtensions
|
|
2
2
|
module Visitors
|
3
3
|
Arel::Visitors.send(:remove_const,'Oracle12') if Arel::Visitors.const_defined?('Oracle12')
|
4
4
|
Arel::Visitors.const_set('Oracle12',Class.new(Arel::Visitors::Oracle)).class_eval do
|
5
|
-
def visit_Arel_Nodes_SelectStatement(o, collector)
|
6
|
-
# Oracle does not allow LIMIT clause with select for update
|
7
|
-
if o.limit && o.lock
|
8
|
-
raise ArgumentError, <<-MSG
|
9
|
-
'Combination of limit and lock is not supported.
|
10
|
-
because generated SQL statements
|
11
|
-
`SELECT FOR UPDATE and FETCH FIRST n ROWS` generates ORA-02014.`
|
12
|
-
MSG
|
13
|
-
end
|
14
|
-
|
15
|
-
super
|
16
|
-
end
|
17
5
|
|
18
6
|
def visit_Arel_Nodes_SelectOptions(o, collector)
|
19
7
|
collector = maybe_visit o.offset, collector
|
@@ -7,7 +7,7 @@ module ArelExtensions
|
|
7
7
|
}.freeze
|
8
8
|
|
9
9
|
DATE_FORMAT_DIRECTIVES = {
|
10
|
-
'%Y' => '
|
10
|
+
'%Y' => 'YYYY', '%C' => 'CC', '%y' => 'YY',
|
11
11
|
'%m' => 'MM', '%B' => 'Month', '%^B' => 'MONTH', '%b' => 'Mon', '%^b' => 'MON',
|
12
12
|
'%d' => 'DD', '%e' => 'FMDD', '%j' => 'DDD', '%w' => '', '%A' => 'Day', # day, weekday
|
13
13
|
'%H' => 'HH24', '%k' => '', '%I' => 'HH', '%l' => '', '%P' => 'am', '%p' => 'AM', # hours
|
@@ -86,9 +86,15 @@ module ArelExtensions
|
|
86
86
|
else
|
87
87
|
collector = visit o.left, collector
|
88
88
|
end
|
89
|
-
collector << " AS
|
89
|
+
collector << " AS "
|
90
|
+
|
91
|
+
# sometimes these values are already quoted, if they are, don't double quote it
|
92
|
+
quote = o.right.is_a?(Arel::Nodes::SqlLiteral) && o.right[0] != '"' && o.right[-1] != '"'
|
93
|
+
|
94
|
+
collector << '"' if quote
|
90
95
|
collector = visit o.right, collector
|
91
|
-
collector << "
|
96
|
+
collector << '"' if quote
|
97
|
+
|
92
98
|
collector
|
93
99
|
end
|
94
100
|
|
@@ -373,6 +379,8 @@ module ArelExtensions
|
|
373
379
|
Arel::Nodes::SqlLiteral.new('date')
|
374
380
|
when :binary
|
375
381
|
Arel::Nodes::SqlLiteral.new('binary')
|
382
|
+
when :jsonb
|
383
|
+
Arel::Nodes::SqlLiteral.new('jsonb')
|
376
384
|
else
|
377
385
|
Arel::Nodes::SqlLiteral.new(o.as_attr.to_s)
|
378
386
|
end
|
@@ -401,13 +409,13 @@ module ArelExtensions
|
|
401
409
|
ArelExtensions::Nodes::Concat.new([
|
402
410
|
Arel::Nodes::NamedFunction.new('TRIM',[
|
403
411
|
Arel::Nodes::NamedFunction.new('TO_CHAR',[
|
404
|
-
col.abs/Arel::Nodes.build_quoted(10).pow(col.abs.log10.floor),
|
412
|
+
Arel.when(col.not_eq 0).then(col.abs/Arel::Nodes.build_quoted(10).pow(col.abs.log10.floor)).else(1),
|
405
413
|
Arel::Nodes.build_quoted('FM'+nines_before+'"'+comma+'"V'+nines_after)
|
406
414
|
])]),
|
407
415
|
o.type,
|
408
416
|
Arel::Nodes::NamedFunction.new('TRIM',[
|
409
417
|
Arel::Nodes::NamedFunction.new('TO_CHAR',[
|
410
|
-
col.abs.log10.floor,
|
418
|
+
Arel.when(col.not_eq 0).then(col.abs.log10.floor).else(0),
|
411
419
|
Arel::Nodes.build_quoted('FM'+nines_before)
|
412
420
|
])])
|
413
421
|
])
|
@@ -511,8 +519,6 @@ module ArelExtensions
|
|
511
519
|
collector << '::jsonb'
|
512
520
|
when NilClass
|
513
521
|
collector << %Q['null'::jsonb]
|
514
|
-
when Arel::Attributes::Attribute
|
515
|
-
collector = visit o.dict.cast(:jsonb), collector
|
516
522
|
else
|
517
523
|
collector = visit o.dict, collector
|
518
524
|
collector << '::jsonb'
|
@@ -532,7 +538,7 @@ module ArelExtensions
|
|
532
538
|
|
533
539
|
def visit_ArelExtensions_Nodes_JsonGet o,collector
|
534
540
|
collector = visit o.dict, collector
|
535
|
-
collector << '
|
541
|
+
collector << ' ->> '
|
536
542
|
collector = visit o.key, collector
|
537
543
|
collector
|
538
544
|
end
|
@@ -3,6 +3,20 @@ module ArelExtensions
|
|
3
3
|
class Arel::Visitors::ToSql
|
4
4
|
COMMA = ', ' unless defined?(COMMA)
|
5
5
|
|
6
|
+
# Escape properly the string expression expr.
|
7
|
+
# Take care of escaping.
|
8
|
+
def make_json_string expr
|
9
|
+
Arel::Nodes.build_quoted('"') \
|
10
|
+
+ expr
|
11
|
+
.coalesce('')
|
12
|
+
.replace('\\','\\\\').replace('"','\"').replace("\n", '\n') \
|
13
|
+
+ '"'
|
14
|
+
end
|
15
|
+
|
16
|
+
def make_json_null
|
17
|
+
Arel::Nodes.build_quoted("null")
|
18
|
+
end
|
19
|
+
|
6
20
|
# Math Functions
|
7
21
|
def visit_ArelExtensions_Nodes_Abs o, collector
|
8
22
|
collector << "ABS("
|
@@ -108,7 +122,7 @@ module ArelExtensions
|
|
108
122
|
end
|
109
123
|
|
110
124
|
def visit_ArelExtensions_Nodes_Length o, collector
|
111
|
-
collector << "LENGTH("
|
125
|
+
collector << "#{o.bytewise ? '' : 'CHAR_'}LENGTH("
|
112
126
|
collector = visit o.left, collector
|
113
127
|
collector << ")"
|
114
128
|
collector
|
@@ -339,6 +353,9 @@ module ArelExtensions
|
|
339
353
|
# override
|
340
354
|
remove_method(:visit_Arel_Nodes_As) rescue nil # if Arel::Visitors::ToSql.method_defined?(:visit_Arel_Nodes_As)
|
341
355
|
def visit_Arel_Nodes_As o, collector
|
356
|
+
if o.left.respond_to?(:alias)
|
357
|
+
o.left.alias = nil
|
358
|
+
end
|
342
359
|
if o.left.is_a?(Arel::Nodes::Binary)
|
343
360
|
collector << '('
|
344
361
|
collector = visit o.left, collector
|
@@ -589,20 +606,20 @@ module ArelExtensions
|
|
589
606
|
def json_value(o,v)
|
590
607
|
case o.type_of_node(v)
|
591
608
|
when :string
|
592
|
-
Arel.when(v.is_null).then(
|
609
|
+
Arel.when(v.is_null).then(make_json_null).else(make_json_string(v))
|
593
610
|
when :date
|
594
611
|
s = v.format('%Y-%m-%d')
|
595
|
-
Arel.when(s.is_null).then(
|
612
|
+
Arel.when(s.is_null).then(make_json_null).else(make_json_string(s))
|
596
613
|
when :datetime
|
597
614
|
s = v.format('%Y-%m-%dT%H:%M:%S')
|
598
|
-
Arel.when(s.is_null).then(
|
615
|
+
Arel.when(s.is_null).then(make_json_null).else(make_json_string(s))
|
599
616
|
when :time
|
600
617
|
s = v.format('%H:%M:%S')
|
601
|
-
Arel.when(s.is_null).then(
|
618
|
+
Arel.when(s.is_null).then(make_json_null).else(make_json_string(s))
|
602
619
|
when :nil
|
603
|
-
|
620
|
+
make_json_null
|
604
621
|
else
|
605
|
-
ArelExtensions::Nodes::Cast.new([v, :string]).coalesce(
|
622
|
+
ArelExtensions::Nodes::Cast.new([v, :string]).coalesce(make_json_null)
|
606
623
|
end
|
607
624
|
end
|
608
625
|
|
@@ -624,7 +641,7 @@ module ArelExtensions
|
|
624
641
|
if i != 0
|
625
642
|
res += ', '
|
626
643
|
end
|
627
|
-
res +=
|
644
|
+
res += make_json_string(ArelExtensions::Nodes::Cast.new([k, :string])) + ': '
|
628
645
|
res += json_value(o,v)
|
629
646
|
end
|
630
647
|
res += '}'
|
@@ -646,7 +663,7 @@ module ArelExtensions
|
|
646
663
|
if i != 0
|
647
664
|
res = res + ', '
|
648
665
|
end
|
649
|
-
kv =
|
666
|
+
kv = make_json_string(ArelExtensions::Nodes::Cast.new([k, :string])) + ': '
|
650
667
|
kv += json_value(o,v)
|
651
668
|
res = res + kv.group_concat(', ', order: Array(orders)).coalesce('')
|
652
669
|
end
|
@@ -9,9 +9,17 @@ if defined?(Arel::Visitors::Oracle)
|
|
9
9
|
require 'arel_extensions/visitors/oracle12'
|
10
10
|
end
|
11
11
|
|
12
|
-
if defined?(Arel::Visitors::MSSQL)
|
12
|
+
if defined?(Arel::Visitors::SQLServer) || defined?(Arel::Visitors::MSSQL)
|
13
13
|
require 'arel_extensions/visitors/mssql'
|
14
|
+
end
|
14
15
|
|
16
|
+
if defined?(Arel::Visitors::SQLServer)
|
17
|
+
class Arel::Visitors::SQLServer
|
18
|
+
include ArelExtensions::Visitors::MSSQL
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
if defined?(Arel::Visitors::MSSQL)
|
15
23
|
class Arel::Visitors::MSSQL
|
16
24
|
include ArelExtensions::Visitors::MSSQL
|
17
25
|
|
data/lib/arel_extensions.rb
CHANGED
@@ -16,8 +16,10 @@ class Arel::Nodes::Casted
|
|
16
16
|
include Arel::AliasPredication
|
17
17
|
|
18
18
|
# They forget to define hash.
|
19
|
-
|
20
|
-
|
19
|
+
if Gem::Version.new(Arel::VERSION) < Gem::Version.new("10.0.0")
|
20
|
+
def hash
|
21
|
+
[self.class, self.val, self.attribute].hash
|
22
|
+
end
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
@@ -31,6 +33,12 @@ class Arel::Nodes::Grouping
|
|
31
33
|
include Arel::OrderPredications
|
32
34
|
end
|
33
35
|
|
36
|
+
class Arel::Nodes::Ordering
|
37
|
+
def eql? other
|
38
|
+
self.hash.eql? other.hash
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
34
42
|
class Arel::Nodes::Function
|
35
43
|
include Arel::Math
|
36
44
|
include Arel::Expressions
|
@@ -44,6 +52,7 @@ if Gem::Version.new(Arel::VERSION) >= Gem::Version.new("7.1.0")
|
|
44
52
|
end
|
45
53
|
|
46
54
|
require 'arel_extensions/version'
|
55
|
+
require 'arel_extensions/aliases'
|
47
56
|
require 'arel_extensions/attributes'
|
48
57
|
require 'arel_extensions/visitors'
|
49
58
|
require 'arel_extensions/nodes'
|
@@ -80,11 +89,13 @@ module Arel
|
|
80
89
|
end
|
81
90
|
|
82
91
|
def self.json *expr
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
92
|
+
ArelExtensions::Nodes::Json.new(
|
93
|
+
if expr.length == 1
|
94
|
+
expr.first
|
95
|
+
else
|
96
|
+
expr
|
97
|
+
end
|
98
|
+
)
|
88
99
|
end
|
89
100
|
|
90
101
|
def self.when condition
|
@@ -92,20 +103,31 @@ module Arel
|
|
92
103
|
end
|
93
104
|
|
94
105
|
def self.duration s, expr
|
95
|
-
ArelExtensions::Nodes::Duration.new(s
|
106
|
+
ArelExtensions::Nodes::Duration.new("#{s}i", expr)
|
96
107
|
end
|
97
108
|
|
109
|
+
def self.grouping *v
|
110
|
+
Arel::Nodes::Grouping.new(*v)
|
111
|
+
end
|
112
|
+
|
113
|
+
# The TRUE pseudo literal.
|
98
114
|
def self.true
|
99
|
-
Arel::Nodes::Equality.new(1,1)
|
115
|
+
Arel::Nodes::Equality.new(1, 1)
|
100
116
|
end
|
101
117
|
|
118
|
+
# The FALSE pseudo literal.
|
102
119
|
def self.false
|
103
|
-
Arel::Nodes::Equality.new(1,0)
|
120
|
+
Arel::Nodes::Equality.new(1, 0)
|
121
|
+
end
|
122
|
+
|
123
|
+
# The NULL literal.
|
124
|
+
def self.null
|
125
|
+
Arel::Nodes.build_quoted(nil)
|
104
126
|
end
|
105
127
|
|
106
128
|
def self.tuple *v
|
107
|
-
tmp = Arel
|
108
|
-
Arel
|
129
|
+
tmp = Arel.grouping(nil)
|
130
|
+
Arel.grouping v.map{|e| tmp.convert_to_node(e)}
|
109
131
|
end
|
110
132
|
end
|
111
133
|
|
@@ -115,6 +137,7 @@ class Arel::Attributes::Attribute
|
|
115
137
|
end
|
116
138
|
|
117
139
|
class Arel::Nodes::Function
|
140
|
+
include ArelExtensions::Aliases
|
118
141
|
include ArelExtensions::Math
|
119
142
|
include ArelExtensions::Comparators
|
120
143
|
include ArelExtensions::DateDuration
|
@@ -126,7 +149,11 @@ class Arel::Nodes::Function
|
|
126
149
|
|
127
150
|
alias_method(:old_as, :as) rescue nil
|
128
151
|
def as other
|
129
|
-
Arel::Nodes::As.new(self, Arel.sql(other))
|
152
|
+
res = Arel::Nodes::As.new(self.clone, Arel.sql(other))
|
153
|
+
if Gem::Version.new(Arel::VERSION) >= Gem::Version.new("9.0.0")
|
154
|
+
self.alias = Arel.sql(other)
|
155
|
+
end
|
156
|
+
res
|
130
157
|
end
|
131
158
|
end
|
132
159
|
|
@@ -146,6 +173,9 @@ class Arel::Nodes::Unary
|
|
146
173
|
include ArelExtensions::MathFunctions
|
147
174
|
include ArelExtensions::Comparators
|
148
175
|
include ArelExtensions::Predications
|
176
|
+
def eql? other
|
177
|
+
hash == other.hash
|
178
|
+
end
|
149
179
|
end
|
150
180
|
|
151
181
|
class Arel::Nodes::Binary
|
@@ -155,6 +185,9 @@ class Arel::Nodes::Binary
|
|
155
185
|
include ArelExtensions::Comparators
|
156
186
|
include ArelExtensions::BooleanFunctions
|
157
187
|
include ArelExtensions::Predications
|
188
|
+
def eql? other
|
189
|
+
hash == other.hash
|
190
|
+
end
|
158
191
|
end
|
159
192
|
|
160
193
|
class Arel::Nodes::Equality
|
@@ -171,6 +204,19 @@ end
|
|
171
204
|
class Arel::SelectManager
|
172
205
|
include ArelExtensions::SetFunctions
|
173
206
|
include ArelExtensions::Nodes
|
207
|
+
|
208
|
+
def as table_name
|
209
|
+
Arel::Nodes::TableAlias.new(self, table_name)
|
210
|
+
end
|
211
|
+
|
212
|
+
# Install an alias, if present.
|
213
|
+
def xas table_name
|
214
|
+
if table_name.present?
|
215
|
+
as table_name
|
216
|
+
else
|
217
|
+
self
|
218
|
+
end
|
219
|
+
end
|
174
220
|
end
|
175
221
|
|
176
222
|
class Arel::Nodes::As
|
@@ -180,7 +226,11 @@ end
|
|
180
226
|
class Arel::Table
|
181
227
|
alias_method(:old_alias, :alias) rescue nil
|
182
228
|
def alias(name = "#{self.name}_2")
|
183
|
-
name.
|
229
|
+
if name.present?
|
230
|
+
Arel::Nodes::TableAlias.new(self, name)
|
231
|
+
else
|
232
|
+
self
|
233
|
+
end
|
184
234
|
end
|
185
235
|
end
|
186
236
|
|
data/test/database.yml
CHANGED
data/test/real_db_test.rb
CHANGED
@@ -8,7 +8,11 @@ require 'arel_extensions'
|
|
8
8
|
def setup_db
|
9
9
|
ActiveRecord::Base.configurations = YAML.load_file('test/database.yml')
|
10
10
|
ActiveRecord::Base.establish_connection(ENV['DB'].try(:to_sym) || (RUBY_PLATFORM == 'java' ? :"jdbc-sqlite" : :sqlite))
|
11
|
-
ActiveRecord::
|
11
|
+
if ActiveRecord::VERSION::MAJOR >= 7
|
12
|
+
ActiveRecord.default_timezone = :utc
|
13
|
+
else
|
14
|
+
ActiveRecord::Base.default_timezone = :utc
|
15
|
+
end
|
12
16
|
@cnx = ActiveRecord::Base.connection
|
13
17
|
if ActiveRecord::Base.connection.adapter_name =~ /sqlite/i
|
14
18
|
$sqlite = true
|
@@ -282,16 +282,23 @@ module ArelExtensions
|
|
282
282
|
.must_be_like %{CASE "users"."name" WHEN 'smith' THEN 'cool' ELSE 'uncool' END ILIKE 'value'}
|
283
283
|
end
|
284
284
|
|
285
|
-
it "should be possible to use as on anything" do
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
.
|
285
|
+
it "should be possible to use as/xas on anything" do
|
286
|
+
{
|
287
|
+
@table[:name] => %{"users"."name" AS alias},
|
288
|
+
@table[:name].concat(' test') => %{CONCAT("users"."name", ' test') AS alias},
|
289
|
+
(@table[:name] + ' test') => %{CONCAT("users"."name", ' test') AS alias},
|
290
|
+
(@table[:age] + 42) => %{("users"."age" + 42) AS alias},
|
291
|
+
@table[:name].coalesce('') => %{COALESCE("users"."name", '') AS alias},
|
292
|
+
Arel::Nodes.build_quoted('test') => %{'test' AS alias},
|
293
|
+
@table.project(@table[:name]) => %{(SELECT "users"."name" FROM "users") "alias"},
|
294
|
+
@table[:name].when("smith").then("cool").else("uncool") => %{CASE "users"."name" WHEN 'smith' THEN 'cool' ELSE 'uncool' END AS alias},
|
295
|
+
}.each do |exp, res|
|
296
|
+
_(compile(exp.as('alias'))).must_be_like res
|
297
|
+
_(compile(exp.xas('alias'))).must_be_like res
|
298
|
+
|
299
|
+
res_no_alias = res.gsub(/\s*(?:AS alias|"alias")\s*\z/, '')
|
300
|
+
_(compile(exp.xas(nil))).must_be_like res_no_alias
|
301
|
+
end
|
295
302
|
end
|
296
303
|
|
297
304
|
it "should accept comparators on functions" do
|
@@ -373,7 +380,7 @@ module ArelExtensions
|
|
373
380
|
end
|
374
381
|
|
375
382
|
it "should respecting Grouping" do
|
376
|
-
g = ->(*v) { Arel
|
383
|
+
g = ->(*v) { Arel.grouping(v) }
|
377
384
|
_(compile(g[@table[:id], @table[:age]].in [g[1, 42]]))
|
378
385
|
.must_be_like %{("users"."id", "users"."age") IN ((1, 42))}
|
379
386
|
_(compile(g[@table[:id], @table[:age]].in [g[1, 42], g[2, 51]]))
|