arel_extensions 2.1.4 → 2.1.6

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 (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