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
@@ -1,25 +1,25 @@
|
|
1
1
|
module ArelExtensions
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
module Nodes
|
3
|
+
class FormattedNumber < Function
|
4
|
+
RETURN_TYPE = :string
|
5
5
|
|
6
|
-
|
6
|
+
attr_accessor :locale, :prefix, :suffix, :flags, :scientific_notation, :width,:precision, :type, :original_string
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
8
|
+
def initialize expr
|
9
|
+
# expr[1] = {:locale => 'fr_FR', :type => "e"/"f"/"d", :prefix => "$ ", :suffix => " %", :flags => " +-#0", :width => 5, :precision => 6}
|
10
|
+
col = expr.first
|
11
|
+
@locale = expr[1][:locale]
|
12
|
+
@prefix = expr[1][:prefix]
|
13
|
+
@suffix = expr[1][:suffix]
|
14
|
+
@width = expr[1][:width]
|
15
|
+
@precision = expr[1][:precision]
|
16
|
+
@type = expr[1][:type]
|
17
|
+
@flags = expr[1][:flags]
|
18
|
+
@scientific_notation = /[eE]/.match(expr[1][:type]) || false
|
19
|
+
@original_string = expr[1][:original_string]
|
20
|
+
super [col]
|
21
|
+
end
|
22
22
|
|
23
|
-
|
24
|
-
|
23
|
+
end
|
24
|
+
end
|
25
25
|
end
|
@@ -18,7 +18,7 @@ module ArelExtensions
|
|
18
18
|
JsonSet.new(self,key,value)
|
19
19
|
end
|
20
20
|
|
21
|
-
def group as_array = true, orders= nil
|
21
|
+
def group as_array = true, orders = nil
|
22
22
|
JsonGroup.new(self,as_array, orders)
|
23
23
|
end
|
24
24
|
|
@@ -31,33 +31,35 @@ module ArelExtensions
|
|
31
31
|
class Json < JsonNode
|
32
32
|
|
33
33
|
def initialize *expr
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
if expr.first.is_a?(String) || (expr.first.is_a?(Arel::Attributes::Attribute) && type_of_attribute(expr.first) == :string) || (expr.first.return_type == :string)
|
53
|
-
@dict = convert_to_node(expr.first)
|
34
|
+
@dict =
|
35
|
+
if expr.length == 1
|
36
|
+
case exp = expr.first
|
37
|
+
when JsonNode
|
38
|
+
exp.dict
|
39
|
+
when Array
|
40
|
+
exp.map{|e|
|
41
|
+
(e.is_a?(Array) || e.is_a?(Hash)) ? Json.new(e) : convert_to_node(e)
|
42
|
+
}
|
43
|
+
when Hash
|
44
|
+
exp.reduce({}){|acc,v|
|
45
|
+
acc[convert_to_node(v[0])] = (v[1].is_a?(Array) || v[1].is_a?(Hash)) ? Json.new(v[1]) : convert_to_node(v[1])
|
46
|
+
acc
|
47
|
+
}
|
48
|
+
when String, Numeric, TrueClass, FalseClass
|
49
|
+
convert_to_node(exp)
|
50
|
+
when NilClass
|
51
|
+
Arel.sql('null')
|
54
52
|
else
|
55
|
-
|
53
|
+
if (exp.is_a?(Arel::Attributes::Attribute) && type_of_attribute(exp) == :string) \
|
54
|
+
|| (exp.return_type == :string)
|
55
|
+
convert_to_node(exp)
|
56
|
+
else
|
57
|
+
[convert_to_node(exp)]
|
58
|
+
end
|
56
59
|
end
|
60
|
+
else
|
61
|
+
expr.map{|e| (e.is_a?(Array) || e.is_a?(Hash)) ? Json.new(e) : convert_to_node(e) }
|
57
62
|
end
|
58
|
-
else
|
59
|
-
@dict = expr.map{|e| (e.is_a?(Array) || e.is_a?(Hash)) ? Json.new(e) : convert_to_node(e) }
|
60
|
-
end
|
61
63
|
super
|
62
64
|
end
|
63
65
|
|
@@ -73,11 +75,7 @@ module ArelExtensions
|
|
73
75
|
@dict = as_array ? json : json.dict
|
74
76
|
@as_array = as_array
|
75
77
|
if orders
|
76
|
-
|
77
|
-
@orders = orders
|
78
|
-
else
|
79
|
-
@orders = [orders]
|
80
|
-
end
|
78
|
+
@orders = Array(orders)
|
81
79
|
end
|
82
80
|
end
|
83
81
|
end
|
@@ -1,11 +1,12 @@
|
|
1
1
|
module ArelExtensions
|
2
2
|
module Nodes
|
3
3
|
class Power < Function
|
4
|
-
|
4
|
+
RETURN_TYPE = :number
|
5
|
+
|
6
|
+
def initialize expr
|
7
|
+
super [convert_to_node(expr.first), convert_to_number(expr[1])]
|
8
|
+
end
|
5
9
|
|
6
|
-
def initialize expr
|
7
|
-
super [convert_to_node(expr.first), convert_to_number(expr[1])]
|
8
|
-
end
|
9
10
|
end
|
10
11
|
end
|
11
12
|
end
|
@@ -2,12 +2,13 @@ module ArelExtensions
|
|
2
2
|
module Nodes
|
3
3
|
class Replace < Function
|
4
4
|
RETURN_TYPE = :string
|
5
|
+
attr_accessor :left, :pattern, :substitute
|
5
6
|
|
6
|
-
def initialize
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
def initialize left, pattern, substitute
|
8
|
+
@left = convert_to_node(left)
|
9
|
+
@pattern = convert_to_node(pattern)
|
10
|
+
@substitute = convert_to_node(substitute)
|
11
|
+
super([@left,@pattern,@substitute])
|
11
12
|
end
|
12
13
|
|
13
14
|
def +(other)
|
@@ -15,5 +16,22 @@ module ArelExtensions
|
|
15
16
|
end
|
16
17
|
|
17
18
|
end
|
19
|
+
|
20
|
+
class RegexpReplace < Function
|
21
|
+
RETURN_TYPE = :string
|
22
|
+
attr_accessor :left, :pattern, :substitute
|
23
|
+
|
24
|
+
def initialize left, pattern, substitute
|
25
|
+
@left = convert_to_node(left)
|
26
|
+
@pattern = (pattern.is_a?(Regexp) ? pattern : %r[#{pattern}])
|
27
|
+
@substitute = convert_to_node(substitute)
|
28
|
+
super([@left,@pattern,@substitute])
|
29
|
+
end
|
30
|
+
|
31
|
+
def +(other)
|
32
|
+
return ArelExtensions::Nodes::Concat.new(self.expressions + [other])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
18
36
|
end
|
19
37
|
end
|
@@ -4,11 +4,11 @@ module ArelExtensions
|
|
4
4
|
RETURN_TYPE = :number
|
5
5
|
|
6
6
|
def initialize expr
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
if expr && expr.length == 1
|
8
|
+
super [convert_to_node(expr.first)]
|
9
|
+
else
|
10
|
+
super [convert_to_node(expr.first), convert_to_number(expr[1])]
|
11
|
+
end
|
12
12
|
end
|
13
13
|
|
14
14
|
end
|
@@ -1,18 +1,19 @@
|
|
1
1
|
module ArelExtensions
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
2
|
+
module Nodes
|
3
|
+
class Soundex < Function
|
4
|
+
include Arel::Expressions
|
5
|
+
include ArelExtensions::Comparators
|
6
6
|
|
7
|
-
|
7
|
+
RETURN_TYPE = :string
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
def ==(other)
|
10
|
+
Arel::Nodes::Equality.new self, Arel::Nodes.build_quoted(other, self)
|
11
|
+
end
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
def !=(other)
|
14
|
+
Arel::Nodes::NotEqual.new self, Arel::Nodes.build_quoted(other, self)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
18
19
|
end
|
@@ -1,22 +1,15 @@
|
|
1
1
|
module ArelExtensions
|
2
2
|
module Nodes
|
3
3
|
class Substring < Function
|
4
|
-
|
4
|
+
RETURN_TYPE = :string
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
return super(tab)
|
14
|
-
end
|
15
|
-
|
16
|
-
# def +(other)
|
17
|
-
# puts "[Substring] : #{other.inspect} (#{self.expressions.inspect})"
|
18
|
-
# return ArelExtensions::Nodes::Concat.new(self.expressions + [other])
|
19
|
-
# end
|
6
|
+
def initialize expr
|
7
|
+
tab = [convert_to_node(expr[0]), convert_to_node(expr[1])]
|
8
|
+
if expr[2]
|
9
|
+
tab << convert_to_node(expr[2])
|
10
|
+
end
|
11
|
+
return super(tab)
|
12
|
+
end
|
20
13
|
|
21
14
|
end
|
22
15
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module ArelExtensions
|
2
2
|
module Predications
|
3
|
-
def when right, expression=nil
|
3
|
+
def when right, expression = nil
|
4
4
|
ArelExtensions::Nodes::Case.new(self).when(right,expression)
|
5
5
|
end
|
6
6
|
|
7
|
-
def matches(other, escape=nil,case_sensitive= nil)
|
7
|
+
def matches(other, escape = nil,case_sensitive = nil)
|
8
8
|
if Arel::VERSION.to_i < 7
|
9
9
|
Arel::Nodes::Matches.new(self, Arel::Nodes.build_quoted(other), escape)
|
10
10
|
else
|
@@ -12,7 +12,7 @@ module ArelExtensions
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
def imatches(other, escape=nil)
|
15
|
+
def imatches(other, escape = nil)
|
16
16
|
ArelExtensions::Nodes::IMatches.new(self, other, escape)
|
17
17
|
end
|
18
18
|
|
@@ -25,25 +25,24 @@ module ArelExtensions
|
|
25
25
|
when Range
|
26
26
|
self.between(other)
|
27
27
|
when Enumerable
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
end
|
28
|
+
nils, values = other.partition{ |v| v.nil? }
|
29
|
+
ranges, values = values.partition{ |v| v.is_a?(Range) || v.is_a?(Arel::SelectManager)}
|
30
|
+
|
31
|
+
# In order of (imagined) decreasing efficiency: nil, values, and then more complex.
|
32
|
+
clauses =
|
33
|
+
nils.uniq.map { |r| self.in(r) } \
|
34
|
+
+ (case values.uniq.size
|
35
|
+
when 0 then []
|
36
|
+
when 1 then [self == values[0]]
|
37
|
+
else [Arel::Nodes::In.new(self, quoted_array(values))] end) \
|
38
|
+
+ ranges.uniq.map { |r| self.in(r) }
|
39
|
+
clauses.empty? ? self.is_null : clauses.reduce(&:or)
|
41
40
|
when nil
|
42
41
|
self.is_null
|
43
42
|
when Arel::SelectManager
|
44
43
|
Arel::Nodes::In.new(self, other.ast)
|
45
44
|
else
|
46
|
-
Arel::Nodes::In.new(self,quoted_node(other))
|
45
|
+
Arel::Nodes::In.new(self, quoted_node(other))
|
47
46
|
end
|
48
47
|
end
|
49
48
|
|
@@ -100,13 +100,21 @@ module ArelExtensions
|
|
100
100
|
ArelExtensions::Nodes::Collate.new(self,nil,false,true)
|
101
101
|
end
|
102
102
|
|
103
|
-
def collate ai=false,ci=false, option=nil
|
103
|
+
def collate ai = false,ci = false, option = nil
|
104
104
|
ArelExtensions::Nodes::Collate.new(self,option,ai,ci)
|
105
105
|
end
|
106
106
|
|
107
107
|
#REPLACE function replaces a sequence of characters in a string with another set of characters, not case-sensitive.
|
108
|
-
def replace
|
109
|
-
|
108
|
+
def replace pattern, substitute
|
109
|
+
if pattern.is_a? Regexp
|
110
|
+
ArelExtensions::Nodes::RegexpReplace.new self, pattern, substitute
|
111
|
+
else
|
112
|
+
ArelExtensions::Nodes::Replace.new self, pattern, substitute
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def regexp_replace pattern, substitute
|
117
|
+
ArelExtensions::Nodes::RegexpReplace.new self, pattern, substitute
|
110
118
|
end
|
111
119
|
|
112
120
|
def concat other
|
@@ -114,7 +122,7 @@ module ArelExtensions
|
|
114
122
|
end
|
115
123
|
|
116
124
|
#concat elements of a group, separated by sep and ordered by a list of Ascending or Descending
|
117
|
-
def group_concat(sep= nil, *orders, group: nil, order: nil)
|
125
|
+
def group_concat(sep = nil, *orders, group: nil, order: nil)
|
118
126
|
if orders.present?
|
119
127
|
warn("Warning : ArelExtensions: group_concat: you should now use the kwarg 'order' to specify an order in the group_concat.")
|
120
128
|
end
|
@@ -123,8 +131,6 @@ module ArelExtensions
|
|
123
131
|
o
|
124
132
|
elsif o.respond_to?(:asc)
|
125
133
|
o.asc
|
126
|
-
else
|
127
|
-
nil
|
128
134
|
end
|
129
135
|
}.compact
|
130
136
|
ArelExtensions::Nodes::GroupConcat.new(self, sep, group: group, order: (order || order_tabs))
|
@@ -1,12 +1,12 @@
|
|
1
1
|
namespace :arel_extensions do
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
desc 'Install DB functions into current DB'
|
3
|
+
task :install_functions => :environment do
|
4
|
+
@env_db = if ENV['DB'] == 'oracle' && ((defined?(RUBY_ENGINE) && RUBY_ENGINE == "rbx") || (RUBY_PLATFORM == 'java')) # not supported
|
5
5
|
(RUBY_PLATFORM == 'java' ? "jdbc-sqlite" : 'sqlite')
|
6
6
|
else
|
7
7
|
ENV['DB'] || ActiveRecord::Base.connection.adapter_name
|
8
8
|
end
|
9
|
-
ActiveRecord::Base.establish_connection(Rails.env)
|
9
|
+
ActiveRecord::Base.establish_connection(Rails.env.to_sym)
|
10
10
|
CommonSqlFunctions.new(ActiveRecord::Base.connection).add_sql_functions(@env_db)
|
11
|
-
|
11
|
+
end
|
12
12
|
end
|
@@ -400,13 +400,14 @@ module ArelExtensions
|
|
400
400
|
collector << "(STRING_AGG("
|
401
401
|
collector = visit o.left, collector
|
402
402
|
collector << Arel::Visitors::Oracle::COMMA
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
403
|
+
collector =
|
404
|
+
if o.separator && o.separator != 'NULL'
|
405
|
+
visit o.separator, collector
|
406
|
+
else
|
407
|
+
visit Arel::Nodes.build_quoted(','), collector
|
408
|
+
end
|
408
409
|
collector << ") WITHIN GROUP (ORDER BY "
|
409
|
-
if
|
410
|
+
if o.order.present?
|
410
411
|
o.order.each_with_index do |order,i|
|
411
412
|
collector << Arel::Visitors::Oracle::COMMA unless i == 0
|
412
413
|
collector = visit order, collector
|
@@ -466,8 +467,9 @@ module ArelExtensions
|
|
466
467
|
Arel::Nodes.build_quoted(1) :
|
467
468
|
ArelExtensions::Nodes::Case.new.when(col<0).then(1).else(0)
|
468
469
|
|
469
|
-
|
470
|
-
|
470
|
+
number =
|
471
|
+
if o.scientific_notation
|
472
|
+
ArelExtensions::Nodes::Concat.new([
|
471
473
|
Arel::Nodes::NamedFunction.new('FORMAT',[
|
472
474
|
col.abs/Arel::Nodes.build_quoted(10).pow(col.abs.log10.floor),
|
473
475
|
param,
|
@@ -480,13 +482,13 @@ module ArelExtensions
|
|
480
482
|
locale
|
481
483
|
])
|
482
484
|
])
|
483
|
-
|
484
|
-
|
485
|
+
else
|
486
|
+
Arel::Nodes::NamedFunction.new('FORMAT',[
|
485
487
|
Arel::Nodes.build_quoted(col.abs),
|
486
488
|
param,
|
487
489
|
locale
|
488
490
|
])
|
489
|
-
|
491
|
+
end
|
490
492
|
|
491
493
|
repeated_char = (o.width == 0) ? Arel::Nodes.build_quoted('') : ArelExtensions::Nodes::Case.new().
|
492
494
|
when(Arel::Nodes.build_quoted(o.width).abs-(number.length+sign_length)>0).
|
@@ -548,7 +550,6 @@ module ArelExtensions
|
|
548
550
|
collector
|
549
551
|
end
|
550
552
|
|
551
|
-
|
552
553
|
end
|
553
554
|
end
|
554
555
|
end
|