arel_extensions 1.3.4 → 1.3.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +162 -222
- data/.gitignore +7 -6
- data/.rubocop.yml +37 -0
- data/Gemfile +3 -3
- data/NEWS.md +15 -0
- data/README.md +119 -75
- data/appveyor.yml +82 -0
- data/arel_extensions.gemspec +0 -1
- data/gemfiles/rails3.gemfile +5 -5
- data/gemfiles/rails4_2.gemfile +38 -0
- data/gemfiles/{rails5_0.gemfile → rails5.gemfile} +6 -6
- data/gemfiles/rails5_1_4.gemfile +6 -6
- data/gemfiles/rails5_2.gemfile +6 -5
- data/gemfiles/rails6.gemfile +5 -4
- data/gemfiles/rails6_1.gemfile +5 -4
- data/gemfiles/rails7.gemfile +5 -4
- data/gemspecs/arel_extensions-v1.gemspec +0 -1
- data/gemspecs/arel_extensions-v2.gemspec +0 -1
- data/lib/arel_extensions/common_sql_functions.rb +2 -2
- data/lib/arel_extensions/helpers.rb +12 -12
- data/lib/arel_extensions/math.rb +32 -17
- data/lib/arel_extensions/nodes/case.rb +4 -3
- data/lib/arel_extensions/nodes/cast.rb +2 -2
- data/lib/arel_extensions/nodes/coalesce.rb +1 -1
- data/lib/arel_extensions/nodes/collate.rb +1 -1
- data/lib/arel_extensions/nodes/date_diff.rb +6 -6
- data/lib/arel_extensions/nodes/locate.rb +1 -1
- data/lib/arel_extensions/nodes/repeat.rb +2 -2
- data/lib/arel_extensions/nodes/rollup.rb +36 -0
- data/lib/arel_extensions/nodes/select.rb +10 -0
- data/lib/arel_extensions/nodes/substring.rb +1 -1
- data/lib/arel_extensions/nodes/then.rb +1 -1
- data/lib/arel_extensions/nodes/trim.rb +2 -2
- data/lib/arel_extensions/nodes/union.rb +3 -3
- data/lib/arel_extensions/nodes/union_all.rb +2 -2
- data/lib/arel_extensions/null_functions.rb +16 -0
- data/lib/arel_extensions/string_functions.rb +1 -0
- data/lib/arel_extensions/version.rb +1 -1
- data/lib/arel_extensions/visitors/ibm_db.rb +1 -1
- data/lib/arel_extensions/visitors/mssql.rb +123 -17
- data/lib/arel_extensions/visitors/mysql.rb +78 -11
- data/lib/arel_extensions/visitors/oracle.rb +39 -17
- data/lib/arel_extensions/visitors/postgresql.rb +17 -12
- data/lib/arel_extensions/visitors/sqlite.rb +4 -4
- data/lib/arel_extensions/visitors/to_sql.rb +4 -1
- data/lib/arel_extensions/visitors.rb +8 -0
- data/lib/arel_extensions.rb +26 -0
- data/test/arelx_test_helper.rb +1 -1
- data/test/real_db_test.rb +5 -5
- data/test/support/fake_record.rb +1 -1
- data/test/visitors/test_bulk_insert_oracle.rb +3 -3
- data/test/visitors/test_bulk_insert_sqlite.rb +1 -1
- data/test/visitors/test_bulk_insert_to_sql.rb +1 -1
- data/test/visitors/test_to_sql.rb +6 -6
- data/test/with_ar/all_agnostic_test.rb +177 -70
- data/test/with_ar/insert_agnostic_test.rb +3 -3
- data/test/with_ar/test_bulk_sqlite.rb +1 -1
- data/version_v1.rb +1 -1
- data/version_v2.rb +1 -1
- metadata +8 -18
- data/gemfiles/rails4.gemfile +0 -29
@@ -17,11 +17,11 @@ module ArelExtensions
|
|
17
17
|
|
18
18
|
def self.column_of_via_arel_table(table_name, column_name)
|
19
19
|
Arel::Table.engine.connection.schema_cache.columns_hash(table_name)[column_name]
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
20
|
+
rescue NoMethodError
|
21
|
+
nil
|
22
|
+
rescue => e
|
23
|
+
warn("Warning: Unexpected exception caught while fetching column name for #{table_name}.#{column_name} in `column_of_via_arel_table`\n#{e.class}: #{e}")
|
24
|
+
nil
|
25
25
|
end
|
26
26
|
|
27
27
|
def self.column_of(table_name, column_name)
|
@@ -40,12 +40,12 @@ module ArelExtensions
|
|
40
40
|
column_of_via_arel_table(table_name, column_name)
|
41
41
|
end
|
42
42
|
end
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
43
|
+
rescue ActiveRecord::ConnectionNotEstablished
|
44
|
+
column_of_via_arel_table(table_name, column_name)
|
45
|
+
rescue ActiveRecord::StatementInvalid
|
46
|
+
nil
|
47
|
+
rescue => e
|
48
|
+
warn("Warning: Unexpected exception caught while fetching column name for #{table_name}.#{column_name} in `column_of`\n#{e.class}: #{e}")
|
49
|
+
nil
|
50
50
|
end
|
51
51
|
end
|
data/lib/arel_extensions/math.rb
CHANGED
@@ -16,16 +16,16 @@ module ArelExtensions
|
|
16
16
|
# Date and integer adds or subtracts a specified time interval from a date.
|
17
17
|
def +(other)
|
18
18
|
case self
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
19
|
+
when Arel::Nodes::Quoted
|
20
|
+
self.concat(other)
|
21
|
+
when Arel::Nodes::Grouping
|
22
|
+
if self.expr.left.is_a?(String) || self.expr.right.is_a?(String)
|
23
|
+
self.concat(other)
|
24
|
+
else
|
25
|
+
Arel.grouping(Arel::Nodes::Addition.new self, other)
|
26
|
+
end
|
27
|
+
when ArelExtensions::Nodes::Function, ArelExtensions::Nodes::Case
|
28
|
+
case self.return_type
|
29
29
|
when :string, :text
|
30
30
|
self.concat(other)
|
31
31
|
when :integer, :decimal, :float, :number, :int
|
@@ -38,12 +38,17 @@ module ArelExtensions
|
|
38
38
|
when Arel::Nodes::Function
|
39
39
|
Arel.grouping(Arel::Nodes::Addition.new self, other)
|
40
40
|
else
|
41
|
-
col =
|
42
|
-
|
41
|
+
col =
|
42
|
+
if self.is_a?(Arel::Attribute) && self.respond_to?(:type_caster) && self.able_to_type_cast?
|
43
|
+
self.type_caster
|
44
|
+
else
|
45
|
+
Arel.column_of(self.relation.table_name, self.name.to_s) if self.respond_to?(:relation)
|
46
|
+
end
|
47
|
+
if !col # if the column doesn't exist in the database
|
43
48
|
Arel.grouping(Arel::Nodes::Addition.new(self, Arel.quoted(other)))
|
44
49
|
else
|
45
50
|
arg = col.type
|
46
|
-
if arg == :integer ||
|
51
|
+
if arg == :integer || !arg
|
47
52
|
other = other.to_i if other.is_a?(String)
|
48
53
|
Arel.grouping(Arel::Nodes::Addition.new self, Arel.quoted(other))
|
49
54
|
elsif arg == :decimal || arg == :float
|
@@ -82,16 +87,26 @@ module ArelExtensions
|
|
82
87
|
when Arel::Nodes::Function
|
83
88
|
Arel.grouping(Arel::Nodes::Subtraction.new(self, Arel.quoted(other)))
|
84
89
|
else
|
85
|
-
col =
|
86
|
-
|
90
|
+
col =
|
91
|
+
if self.is_a?(Arel::Attribute) && self.respond_to?(:type_caster) && self.able_to_type_cast?
|
92
|
+
self.type_caster
|
93
|
+
else
|
94
|
+
Arel.column_of(self.relation.table_name, self.name.to_s) if self.respond_to?(:relation)
|
95
|
+
end
|
96
|
+
if !col # if the column doesn't exist in the database
|
87
97
|
Arel.grouping(Arel::Nodes::Subtraction.new(self, Arel.quoted(other)))
|
88
98
|
else
|
89
99
|
arg = col.type
|
90
100
|
if (arg == :date || arg == :datetime)
|
91
101
|
case other
|
92
102
|
when Arel::Attributes::Attribute
|
93
|
-
col2 =
|
94
|
-
|
103
|
+
col2 =
|
104
|
+
if other.is_a?(Arel::Attribute) && other.respond_to?(:type_caster) && other.able_to_type_cast?
|
105
|
+
other.type_caster
|
106
|
+
else
|
107
|
+
Arel.column_of(other.relation.table_name, other.name.to_s) if other.respond_to?(:relation)
|
108
|
+
end
|
109
|
+
if !col2 # if the column doesn't exist in the database
|
95
110
|
ArelExtensions::Nodes::DateSub.new [self, other]
|
96
111
|
else
|
97
112
|
arg2 = col2.type
|
@@ -35,12 +35,13 @@ module ArelExtensions
|
|
35
35
|
include Arel::Predications
|
36
36
|
include Arel::OrderPredications
|
37
37
|
include ArelExtensions::Aliases
|
38
|
-
include ArelExtensions::Math
|
39
38
|
include ArelExtensions::Comparators
|
40
|
-
include ArelExtensions::
|
39
|
+
include ArelExtensions::DateDuration
|
40
|
+
include ArelExtensions::Math
|
41
41
|
include ArelExtensions::MathFunctions
|
42
|
-
include ArelExtensions::StringFunctions
|
43
42
|
include ArelExtensions::NullFunctions
|
43
|
+
include ArelExtensions::Predications
|
44
|
+
include ArelExtensions::StringFunctions
|
44
45
|
|
45
46
|
def return_type
|
46
47
|
obj = if @conditions.length > 0
|
@@ -32,13 +32,13 @@ module ArelExtensions
|
|
32
32
|
@as_attr = :string
|
33
33
|
end
|
34
34
|
tab = [convert_to_node(expr.first)]
|
35
|
-
|
35
|
+
super(tab)
|
36
36
|
end
|
37
37
|
|
38
38
|
def +(other)
|
39
39
|
case @return_type
|
40
40
|
when :string
|
41
|
-
|
41
|
+
ArelExtensions::Nodes::Concat.new [self, other]
|
42
42
|
when :ruby_time
|
43
43
|
ArelExtensions::Nodes::DateAdd.new [self, other]
|
44
44
|
else
|
@@ -19,7 +19,7 @@ module ArelExtensions
|
|
19
19
|
when DateTime, Time
|
20
20
|
@left_node_type = :ruby_time
|
21
21
|
end
|
22
|
-
res << ([
|
22
|
+
res << (%i[date ruby_date].include?(@left_node_type) ? convert_to_date_node(col) : convert_to_datetime_node(col))
|
23
23
|
case expr[1]
|
24
24
|
when Arel::Nodes::Node, Arel::Attributes::Attribute
|
25
25
|
@right_node_type = type_of_attribute(expr[1])
|
@@ -28,7 +28,7 @@ module ArelExtensions
|
|
28
28
|
when DateTime, Time
|
29
29
|
@right_node_type = :ruby_time
|
30
30
|
end
|
31
|
-
res << ([
|
31
|
+
res << (%i[date ruby_date].include?(@left_node_type) ? convert_to_date_node(expr[1]) : convert_to_datetime_node(expr[1]))
|
32
32
|
super res
|
33
33
|
end
|
34
34
|
end
|
@@ -43,19 +43,19 @@ module ArelExtensions
|
|
43
43
|
tab = expr.map do |arg|
|
44
44
|
convert(arg)
|
45
45
|
end
|
46
|
-
|
46
|
+
super(tab)
|
47
47
|
end
|
48
48
|
|
49
49
|
def sqlite_value
|
50
50
|
v = self.expressions.last
|
51
51
|
if defined?(ActiveSupport::Duration) && ActiveSupport::Duration === v
|
52
52
|
if @date_type == :date
|
53
|
-
|
53
|
+
Arel.quoted((v.value >= 0 ? '+' : '-') + v.inspect)
|
54
54
|
elsif @date_type == :datetime
|
55
|
-
|
55
|
+
Arel.quoted((v.value >= 0 ? '+' : '-') + v.inspect)
|
56
56
|
end
|
57
57
|
else
|
58
|
-
|
58
|
+
v
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
@@ -7,11 +7,11 @@ module ArelExtensions
|
|
7
7
|
tab = expr.map { |arg|
|
8
8
|
convert_to_node(arg)
|
9
9
|
}
|
10
|
-
|
10
|
+
super(tab)
|
11
11
|
end
|
12
12
|
|
13
13
|
def +(other)
|
14
|
-
|
14
|
+
ArelExtensions::Nodes::Concat.new(self.expressions + [other])
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# The following is a patch to activerecord when it doesn't
|
2
|
+
# have RollUp defined, i.e. for rails < 5.2
|
3
|
+
|
4
|
+
begin
|
5
|
+
Arel::Nodes.const_get('RollUp')
|
6
|
+
rescue NameError => e
|
7
|
+
module Arel
|
8
|
+
module Nodes
|
9
|
+
class RollUp < Arel::Nodes::Unary
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module Arel
|
15
|
+
module Visitors
|
16
|
+
class PostgreSQL
|
17
|
+
# Utilized by GroupingSet, Cube & RollUp visitors to
|
18
|
+
# handle grouping aggregation semantics
|
19
|
+
def grouping_array_or_grouping_element(o, collector)
|
20
|
+
if o.expr.is_a? Array
|
21
|
+
collector << "( "
|
22
|
+
visit o.expr, collector
|
23
|
+
collector << " )"
|
24
|
+
else
|
25
|
+
visit o.expr, collector
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def visit_Arel_Nodes_RollUp(o, collector)
|
30
|
+
collector << "ROLLUP"
|
31
|
+
grouping_array_or_grouping_element o, collector
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -7,11 +7,11 @@ module ArelExtensions
|
|
7
7
|
tab = expr.map { |arg|
|
8
8
|
convert_to_node(arg)
|
9
9
|
}
|
10
|
-
|
10
|
+
super(tab)
|
11
11
|
end
|
12
12
|
|
13
13
|
def +(other)
|
14
|
-
|
14
|
+
ArelExtensions::Nodes::Concat.new(self.expressions + [other])
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
@@ -2,15 +2,15 @@ module ArelExtensions
|
|
2
2
|
module Nodes
|
3
3
|
class Union < Arel::Nodes::Union
|
4
4
|
def initialize left, right
|
5
|
-
|
5
|
+
super(left, right)
|
6
6
|
end
|
7
7
|
|
8
8
|
def +(other)
|
9
|
-
|
9
|
+
ArelExtensions::Nodes::Union.new(self, other)
|
10
10
|
end
|
11
11
|
|
12
12
|
def union(other)
|
13
|
-
|
13
|
+
ArelExtensions::Nodes::UnionAll.new(self, other)
|
14
14
|
end
|
15
15
|
|
16
16
|
def as other
|
@@ -2,11 +2,11 @@ module ArelExtensions
|
|
2
2
|
module Nodes
|
3
3
|
class UnionAll < Arel::Nodes::UnionAll
|
4
4
|
def initialize left, right
|
5
|
-
|
5
|
+
super(left, right)
|
6
6
|
end
|
7
7
|
|
8
8
|
def union_all(other)
|
9
|
-
|
9
|
+
ArelExtensions::Nodes::UnionAll.new(self, other)
|
10
10
|
end
|
11
11
|
|
12
12
|
def as other
|
@@ -3,6 +3,12 @@ require 'arel_extensions/nodes/is_null'
|
|
3
3
|
|
4
4
|
module ArelExtensions
|
5
5
|
module NullFunctions
|
6
|
+
|
7
|
+
# if_present returns nil if the the value is nil or blank
|
8
|
+
def if_present
|
9
|
+
Arel.when(self.cast(:string).present).then(self)
|
10
|
+
end
|
11
|
+
|
6
12
|
# ISNULL function lets you return an alternative value when an expression is NULL.
|
7
13
|
def is_null
|
8
14
|
ArelExtensions::Nodes::IsNull.new [self]
|
@@ -19,5 +25,15 @@ module ArelExtensions
|
|
19
25
|
args.unshift(self)
|
20
26
|
ArelExtensions::Nodes::Coalesce.new args
|
21
27
|
end
|
28
|
+
|
29
|
+
def coalesce_blank *args
|
30
|
+
res = Arel.when(self.cast(:string).present).then(self)
|
31
|
+
args[0...-1].each do |a|
|
32
|
+
val = a.is_a?(Arel::Nodes::Node) ? a : Arel.quoted(a)
|
33
|
+
res = res.when(val.present).then(a)
|
34
|
+
end
|
35
|
+
res = res.else(args[-1])
|
36
|
+
res
|
37
|
+
end
|
22
38
|
end
|
23
39
|
end
|
@@ -56,7 +56,7 @@ module ArelExtensions
|
|
56
56
|
collector << 'COALESCE('
|
57
57
|
collector = visit o.left, collector
|
58
58
|
collector << ','
|
59
|
-
if
|
59
|
+
if o.right.is_a?(Arel::Attributes::Attribute)
|
60
60
|
collector = visit o.right, collector
|
61
61
|
else
|
62
62
|
collector << "'#{o.right}'"
|
@@ -49,6 +49,82 @@ module ArelExtensions
|
|
49
49
|
'YYYY-MM-DDTHH:MM:SS:MMM' => 126
|
50
50
|
}.freeze
|
51
51
|
|
52
|
+
# Quoting in JRuby + AR < 5 requires special handling for MSSQL.
|
53
|
+
#
|
54
|
+
# It relied on @connection.quote, which in turn relied on column type for
|
55
|
+
# quoting. We need only to rely on the value type.
|
56
|
+
#
|
57
|
+
# It didn't handle numbers correctly: `quote(1, nil)` translated into
|
58
|
+
# `N'1'` which we don't want.
|
59
|
+
#
|
60
|
+
# The following is adapted from activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
|
61
|
+
#
|
62
|
+
if RUBY_PLATFORM == 'java' && ActiveRecord::VERSION::MAJOR < 5
|
63
|
+
def quote_string(s)
|
64
|
+
s.gsub('\\', '\&\&').gsub("'", "''") # ' (for ruby-mode)
|
65
|
+
end
|
66
|
+
|
67
|
+
def quoted_binary(value) # :nodoc:
|
68
|
+
"'#{quote_string(value.to_s)}'"
|
69
|
+
end
|
70
|
+
|
71
|
+
def quoted_date(value)
|
72
|
+
if value.acts_like?(:time)
|
73
|
+
if ActiveRecord::Base.default_timezone == :utc
|
74
|
+
value = value.getutc if value.respond_to?(:getutc) && !value.utc?
|
75
|
+
else
|
76
|
+
value = value.getlocal if value.respond_to?(:getlocal)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
result = value.to_s(:db)
|
81
|
+
if value.respond_to?(:usec) && value.usec > 0
|
82
|
+
result << '.' << sprintf('%06d', value.usec)
|
83
|
+
else
|
84
|
+
result
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def quoted_true
|
89
|
+
'TRUE'
|
90
|
+
end
|
91
|
+
|
92
|
+
def quoted_false
|
93
|
+
'FALSE'
|
94
|
+
end
|
95
|
+
|
96
|
+
def quoted_time(value) # :nodoc:
|
97
|
+
value = value.change(year: 2000, month: 1, day: 1)
|
98
|
+
quoted_date(value).sub(/\A\d{4}-\d{2}-\d{2} /, "")
|
99
|
+
end
|
100
|
+
|
101
|
+
def quote value, column = nil
|
102
|
+
case value
|
103
|
+
when Arel::Nodes::SqlLiteral
|
104
|
+
value
|
105
|
+
when String, Symbol, ActiveSupport::Multibyte::Chars
|
106
|
+
"'#{quote_string(value.to_s)}'"
|
107
|
+
when true
|
108
|
+
quoted_true
|
109
|
+
when false
|
110
|
+
quoted_false
|
111
|
+
when nil
|
112
|
+
'NULL'
|
113
|
+
# BigDecimals need to be put in a non-normalized form and quoted.
|
114
|
+
when BigDecimal
|
115
|
+
value.to_s('F')
|
116
|
+
when Numeric, ActiveSupport::Duration
|
117
|
+
value.to_s
|
118
|
+
when Date, Time
|
119
|
+
"'#{quoted_date(value)}'"
|
120
|
+
when Class
|
121
|
+
"'#{value}'"
|
122
|
+
else
|
123
|
+
raise TypeError, "can't quote #{value.class.name}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
52
128
|
# Math Functions
|
53
129
|
def visit_ArelExtensions_Nodes_Ceil o, collector
|
54
130
|
collector << 'CEILING('
|
@@ -157,7 +233,7 @@ module ArelExtensions
|
|
157
233
|
collector = visit o.right, collector
|
158
234
|
else
|
159
235
|
left = o.left.end_with?('i') ? o.left[0..-2] : o.left
|
160
|
-
conv = [
|
236
|
+
conv = %w[h mn s].include?(o.left)
|
161
237
|
collector << 'DATEPART('
|
162
238
|
collector << LOADED_VISITOR::DATE_MAPPING[left]
|
163
239
|
collector << LOADED_VISITOR::COMMA
|
@@ -220,11 +296,19 @@ module ArelExtensions
|
|
220
296
|
end
|
221
297
|
|
222
298
|
def visit_ArelExtensions_Nodes_Trim o, collector
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
299
|
+
# NOTE: in MSSQL's `blank`, o.right is the space char so we need to
|
300
|
+
# account for it.
|
301
|
+
if o.right && !/\A\s\Z/.match(o.right.expr)
|
302
|
+
collector << 'dbo.TrimChar('
|
303
|
+
collector = visit o.left, collector
|
304
|
+
collector << Arel::Visitors::MSSQL::COMMA
|
305
|
+
collector = visit o.right, collector
|
306
|
+
collector << ')'
|
307
|
+
else
|
308
|
+
collector << "LTRIM(RTRIM("
|
309
|
+
collector = visit o.left, collector
|
310
|
+
collector << "))"
|
311
|
+
end
|
228
312
|
collector
|
229
313
|
end
|
230
314
|
|
@@ -308,7 +392,7 @@ module ArelExtensions
|
|
308
392
|
dir = LOADED_VISITOR::DATE_FORMAT_DIRECTIVES[s.matched]
|
309
393
|
fmt = LOADED_VISITOR::DATE_FORMAT_FORMAT[dir]
|
310
394
|
date_name = LOADED_VISITOR::DATE_NAME.include?(s.matched)
|
311
|
-
collector << '
|
395
|
+
collector << 'LTRIM(RTRIM('
|
312
396
|
collector << 'FORMAT(' if fmt
|
313
397
|
collector << 'STR(' if !fmt && !date_name
|
314
398
|
collector << (date_name ? 'DATENAME(' : 'DATEPART(')
|
@@ -334,7 +418,7 @@ module ArelExtensions
|
|
334
418
|
collector << ')'
|
335
419
|
collector << ')' if !fmt && !date_name
|
336
420
|
collector << LOADED_VISITOR::COMMA << "'#{fmt}')" if fmt
|
337
|
-
collector << ')'
|
421
|
+
collector << '))'
|
338
422
|
when s.scan(/^%%/)
|
339
423
|
collector = visit Arel.quoted('%'), collector
|
340
424
|
when s.scan(/[^%]+|./)
|
@@ -479,6 +563,11 @@ module ArelExtensions
|
|
479
563
|
collector
|
480
564
|
end
|
481
565
|
|
566
|
+
def visit_Arel_Nodes_RollUp(o, collector)
|
567
|
+
collector << "ROLLUP"
|
568
|
+
grouping_array_or_grouping_element o, collector
|
569
|
+
end
|
570
|
+
|
482
571
|
# TODO;
|
483
572
|
def visit_ArelExtensions_Nodes_GroupConcat o, collector
|
484
573
|
collector << '(STRING_AGG('
|
@@ -575,15 +664,20 @@ module ArelExtensions
|
|
575
664
|
])
|
576
665
|
end
|
577
666
|
|
578
|
-
repeated_char =
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
667
|
+
repeated_char =
|
668
|
+
if o.width == 0
|
669
|
+
Arel.quoted('')
|
670
|
+
else
|
671
|
+
Arel
|
672
|
+
.when(Arel.quoted(o.width).abs - (number.length + sign_length) > 0)
|
673
|
+
.then(Arel.quoted(
|
674
|
+
o.flags.include?('-') ? ' ' : (o.flags.include?('0') ? '0' : ' ')
|
675
|
+
).repeat(Arel.quoted(o.width).abs - (number.length + sign_length))
|
676
|
+
)
|
677
|
+
.else('')
|
678
|
+
end
|
679
|
+
before = !o.flags.include?('0') && !o.flags.include?('-') ? repeated_char : ''
|
680
|
+
middle = o.flags.include?('0') && !o.flags.include?('-') ? repeated_char : ''
|
587
681
|
after = o.flags.include?('-') ? repeated_char : ''
|
588
682
|
full_number =
|
589
683
|
ArelExtensions::Nodes::Concat.new([
|
@@ -634,6 +728,18 @@ module ArelExtensions
|
|
634
728
|
collector << ')'
|
635
729
|
collector
|
636
730
|
end
|
731
|
+
|
732
|
+
# Utilized by GroupingSet, Cube & RollUp visitors to
|
733
|
+
# handle grouping aggregation semantics
|
734
|
+
def grouping_array_or_grouping_element(o, collector)
|
735
|
+
if o.expr.is_a? Array
|
736
|
+
collector << "( "
|
737
|
+
visit o.expr, collector
|
738
|
+
collector << " )"
|
739
|
+
else
|
740
|
+
visit o.expr, collector
|
741
|
+
end
|
742
|
+
end
|
637
743
|
end
|
638
744
|
end
|
639
745
|
end
|