arel_extensions 2.1.4 → 2.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +162 -222
  3. data/.gitignore +7 -6
  4. data/.rubocop.yml +37 -0
  5. data/Gemfile +3 -3
  6. data/NEWS.md +15 -0
  7. data/README.md +119 -75
  8. data/appveyor.yml +82 -0
  9. data/arel_extensions.gemspec +0 -1
  10. data/gemfiles/rails3.gemfile +5 -5
  11. data/gemfiles/rails4_2.gemfile +38 -0
  12. data/gemfiles/{rails5_0.gemfile → rails5.gemfile} +6 -6
  13. data/gemfiles/rails5_1_4.gemfile +6 -6
  14. data/gemfiles/rails5_2.gemfile +6 -5
  15. data/gemfiles/rails6.gemfile +5 -4
  16. data/gemfiles/rails6_1.gemfile +5 -4
  17. data/gemfiles/rails7.gemfile +5 -4
  18. data/gemspecs/arel_extensions-v1.gemspec +0 -1
  19. data/gemspecs/arel_extensions-v2.gemspec +0 -1
  20. data/lib/arel_extensions/common_sql_functions.rb +2 -2
  21. data/lib/arel_extensions/helpers.rb +12 -12
  22. data/lib/arel_extensions/math.rb +32 -17
  23. data/lib/arel_extensions/nodes/case.rb +4 -3
  24. data/lib/arel_extensions/nodes/cast.rb +2 -2
  25. data/lib/arel_extensions/nodes/coalesce.rb +1 -1
  26. data/lib/arel_extensions/nodes/collate.rb +1 -1
  27. data/lib/arel_extensions/nodes/date_diff.rb +6 -6
  28. data/lib/arel_extensions/nodes/locate.rb +1 -1
  29. data/lib/arel_extensions/nodes/repeat.rb +2 -2
  30. data/lib/arel_extensions/nodes/rollup.rb +36 -0
  31. data/lib/arel_extensions/nodes/select.rb +10 -0
  32. data/lib/arel_extensions/nodes/substring.rb +1 -1
  33. data/lib/arel_extensions/nodes/then.rb +1 -1
  34. data/lib/arel_extensions/nodes/trim.rb +2 -2
  35. data/lib/arel_extensions/nodes/union.rb +3 -3
  36. data/lib/arel_extensions/nodes/union_all.rb +2 -2
  37. data/lib/arel_extensions/null_functions.rb +16 -0
  38. data/lib/arel_extensions/string_functions.rb +1 -0
  39. data/lib/arel_extensions/version.rb +1 -1
  40. data/lib/arel_extensions/visitors/ibm_db.rb +1 -1
  41. data/lib/arel_extensions/visitors/mssql.rb +123 -17
  42. data/lib/arel_extensions/visitors/mysql.rb +78 -11
  43. data/lib/arel_extensions/visitors/oracle.rb +39 -17
  44. data/lib/arel_extensions/visitors/postgresql.rb +17 -12
  45. data/lib/arel_extensions/visitors/sqlite.rb +4 -4
  46. data/lib/arel_extensions/visitors/to_sql.rb +4 -1
  47. data/lib/arel_extensions/visitors.rb +8 -0
  48. data/lib/arel_extensions.rb +26 -0
  49. data/test/arelx_test_helper.rb +1 -1
  50. data/test/real_db_test.rb +5 -5
  51. data/test/support/fake_record.rb +1 -1
  52. data/test/visitors/test_bulk_insert_oracle.rb +3 -3
  53. data/test/visitors/test_bulk_insert_sqlite.rb +1 -1
  54. data/test/visitors/test_bulk_insert_to_sql.rb +1 -1
  55. data/test/visitors/test_to_sql.rb +6 -6
  56. data/test/with_ar/all_agnostic_test.rb +177 -70
  57. data/test/with_ar/insert_agnostic_test.rb +3 -3
  58. data/test/with_ar/test_bulk_sqlite.rb +1 -1
  59. data/version_v1.rb +1 -1
  60. data/version_v2.rb +1 -1
  61. metadata +8 -18
  62. 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
- 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
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
- 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
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
@@ -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
- when Arel::Nodes::Quoted
20
- return self.concat(other)
21
- when Arel::Nodes::Grouping
22
- if self.expr.left.is_a?(String) || self.expr.right.is_a?(String)
23
- return self.concat(other)
24
- else
25
- return Arel.grouping(Arel::Nodes::Addition.new self, other)
26
- end
27
- when ArelExtensions::Nodes::Function, ArelExtensions::Nodes::Case
28
- return case self.return_type
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 = Arel.column_of(self.relation.table_name, self.name.to_s) if self.respond_to?(:relation)
42
- if (!col) # if the column doesn't exist in the database
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 || (!arg)
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 = Arel.column_of(self.relation.table_name, self.name.to_s)
86
- if (!col) # if the column doesn't exist in the database
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 = Arel.column_of(other.relation.table_name, other.name.to_s)
94
- if (!col2) # if the column doesn't exist in the database
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::Predications
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
- return super(tab)
35
+ super(tab)
36
36
  end
37
37
 
38
38
  def +(other)
39
39
  case @return_type
40
40
  when :string
41
- return ArelExtensions::Nodes::Concat.new [self, other]
41
+ ArelExtensions::Nodes::Concat.new [self, other]
42
42
  when :ruby_time
43
43
  ArelExtensions::Nodes::DateAdd.new [self, other]
44
44
  else
@@ -27,7 +27,7 @@ module ArelExtensions
27
27
  when DateTime, Time
28
28
  @left_node_type = :ruby_time
29
29
  end
30
- return super(tab)
30
+ super(tab)
31
31
  end
32
32
  end
33
33
  end
@@ -10,7 +10,7 @@ module ArelExtensions
10
10
  @ci = ci
11
11
  @option = option
12
12
  tab = [convert_to_node(left)]
13
- return super(tab)
13
+ super(tab)
14
14
  end
15
15
  end
16
16
  end
@@ -19,7 +19,7 @@ module ArelExtensions
19
19
  when DateTime, Time
20
20
  @left_node_type = :ruby_time
21
21
  end
22
- res << ([:date, :ruby_date].include?(@left_node_type) ? convert_to_date_node(col) : convert_to_datetime_node(col))
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 << ([:date, :ruby_date].include?(@left_node_type) ? convert_to_date_node(expr[1]) : convert_to_datetime_node(expr[1]))
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
- return super(tab)
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
- return Arel.quoted((v.value >= 0 ? '+' : '-') + v.inspect)
53
+ Arel.quoted((v.value >= 0 ? '+' : '-') + v.inspect)
54
54
  elsif @date_type == :datetime
55
- return Arel.quoted((v.value >= 0 ? '+' : '-') + v.inspect)
55
+ Arel.quoted((v.value >= 0 ? '+' : '-') + v.inspect)
56
56
  end
57
57
  else
58
- return v
58
+ v
59
59
  end
60
60
  end
61
61
 
@@ -7,7 +7,7 @@ module ArelExtensions
7
7
  tab = expr.map do |arg|
8
8
  convert_to_node(arg)
9
9
  end
10
- return super(tab)
10
+ super(tab)
11
11
  end
12
12
  end
13
13
  end
@@ -7,11 +7,11 @@ module ArelExtensions
7
7
  tab = expr.map { |arg|
8
8
  convert_to_node(arg)
9
9
  }
10
- return super(tab)
10
+ super(tab)
11
11
  end
12
12
 
13
13
  def +(other)
14
- return ArelExtensions::Nodes::Concat.new(self.expressions + [other])
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
@@ -0,0 +1,10 @@
1
+ module Arel
2
+ module Nodes
3
+ class SelectCore
4
+ # havings did not exist in rails < 5.2
5
+ if !method_defined?(:havings)
6
+ alias :havings :having
7
+ end
8
+ end
9
+ end
10
+ end
@@ -8,7 +8,7 @@ module ArelExtensions
8
8
  if expr[2]
9
9
  tab << convert_to_node(expr[2])
10
10
  end
11
- return super(tab)
11
+ super(tab)
12
12
  end
13
13
  end
14
14
  end
@@ -5,7 +5,7 @@ module ArelExtensions
5
5
  tab = expr.map { |arg|
6
6
  convert_to_node(arg)
7
7
  }
8
- return super(tab)
8
+ super(tab)
9
9
  end
10
10
  end
11
11
  end
@@ -7,11 +7,11 @@ module ArelExtensions
7
7
  tab = expr.map { |arg|
8
8
  convert_to_node(arg)
9
9
  }
10
- return super(tab)
10
+ super(tab)
11
11
  end
12
12
 
13
13
  def +(other)
14
- return ArelExtensions::Nodes::Concat.new(self.expressions + [other])
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
- return super(left, right)
5
+ super(left, right)
6
6
  end
7
7
 
8
8
  def +(other)
9
- return ArelExtensions::Nodes::Union.new(self, other)
9
+ ArelExtensions::Nodes::Union.new(self, other)
10
10
  end
11
11
 
12
12
  def union(other)
13
- return ArelExtensions::Nodes::UnionAll.new(self, other)
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
- return super(left, right)
5
+ super(left, right)
6
6
  end
7
7
 
8
8
  def union_all(other)
9
- return ArelExtensions::Nodes::UnionAll.new(self, other)
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
@@ -184,6 +184,7 @@ module ArelExtensions
184
184
  def not_blank
185
185
  ArelExtensions::Nodes::NotBlank.new [self]
186
186
  end
187
+ alias present not_blank
187
188
 
188
189
  def repeat other = 1
189
190
  ArelExtensions::Nodes::Repeat.new [self, other]
@@ -1,3 +1,3 @@
1
1
  module ArelExtensions
2
- VERSION = '2.1.4'.freeze
2
+ VERSION = '2.1.6'.freeze
3
3
  end
@@ -56,7 +56,7 @@ module ArelExtensions
56
56
  collector << 'COALESCE('
57
57
  collector = visit o.left, collector
58
58
  collector << ','
59
- if (o.right.is_a?(Arel::Attributes::Attribute))
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 = ['h', 'mn', 's'].include?(o.left)
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
- collector << 'TRIM( '
224
- collector = visit o.right, collector
225
- collector << ' FROM '
226
- collector = visit o.left, collector
227
- collector << ')'
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 << 'TRIM('
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 = (o.width == 0) ? Arel.quoted('') : ArelExtensions::Nodes::Case.new.
579
- when(Arel.quoted(o.width).abs - (number.length + sign_length) > 0).
580
- then(Arel.quoted(
581
- o.flags.include?('-') ? ' ' : (o.flags.include?('0') ? '0' : ' ')
582
- ).repeat(Arel.quoted(o.width).abs - (number.length + sign_length))
583
- ).
584
- else('')
585
- before = (!o.flags.include?('0')) && (!o.flags.include?('-')) ? repeated_char : ''
586
- middle = (o.flags.include?('0')) && (!o.flags.include?('-')) ? repeated_char : ''
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