arel_extensions 1.1.8 → 1.1.9
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/.travis.yml +2 -0
- data/Gemfile +1 -1
- data/gemfiles/rails3.gemfile +12 -12
- data/gemfiles/rails4.gemfile +17 -17
- data/gemfiles/rails5_0.gemfile +17 -17
- data/gemfiles/rails5_1_4.gemfile +17 -17
- data/gemfiles/rails5_2.gemfile +17 -17
- data/lib/arel_extensions/boolean_functions.rb +30 -11
- data/lib/arel_extensions/math.rb +111 -112
- data/lib/arel_extensions/math_functions.rb +50 -31
- data/lib/arel_extensions/nodes/function.rb +25 -26
- data/lib/arel_extensions/nodes/json.rb +81 -0
- data/lib/arel_extensions/predications.rb +95 -97
- data/lib/arel_extensions/version.rb +1 -1
- data/lib/arel_extensions/visitors/mssql.rb +121 -108
- data/lib/arel_extensions/visitors/mysql.rb +230 -148
- data/lib/arel_extensions/visitors/oracle.rb +242 -232
- data/lib/arel_extensions/visitors/oracle12.rb +39 -1
- data/lib/arel_extensions/visitors/postgresql.rb +216 -134
- data/lib/arel_extensions/visitors/sqlite.rb +200 -189
- data/lib/arel_extensions/visitors/to_sql.rb +239 -171
- data/lib/arel_extensions/visitors.rb +63 -33
- data/lib/arel_extensions.rb +1 -0
- data/test/visitors/test_oracle.rb +1 -1
- data/test/visitors/test_to_sql.rb +206 -195
- data/test/with_ar/all_agnostic_test.rb +278 -235
- metadata +3 -2
@@ -11,6 +11,26 @@ require 'arel_extensions/nodes/std'
|
|
11
11
|
module ArelExtensions
|
12
12
|
module MathFunctions
|
13
13
|
|
14
|
+
# Arel does not handle Decimal literal properly
|
15
|
+
def * other
|
16
|
+
case other
|
17
|
+
when Float, BigDecimal
|
18
|
+
super(Arel::Nodes.build_quoted(other))
|
19
|
+
else
|
20
|
+
super(other)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Arel does not handle Decimal literal properly
|
25
|
+
def / other
|
26
|
+
case other
|
27
|
+
when Float, BigDecimal
|
28
|
+
super(Arel::Nodes.build_quoted(other))
|
29
|
+
else
|
30
|
+
super(other)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
14
34
|
# Abs function returns the absolute value of a number passed as argument #
|
15
35
|
def abs
|
16
36
|
ArelExtensions::Nodes::Abs.new [self]
|
@@ -25,32 +45,31 @@ module ArelExtensions
|
|
25
45
|
def floor
|
26
46
|
ArelExtensions::Nodes::Floor.new [self]
|
27
47
|
end
|
28
|
-
|
29
|
-
# function gives the base 10 log
|
48
|
+
|
49
|
+
# function gives the base 10 log
|
30
50
|
def log10
|
31
51
|
ArelExtensions::Nodes::Log10.new [self]
|
32
52
|
end
|
33
|
-
|
53
|
+
|
34
54
|
# function gives the power of a number
|
35
55
|
def pow exposant = 0
|
36
56
|
ArelExtensions::Nodes::Power.new [self,exposant]
|
37
57
|
end
|
38
|
-
|
58
|
+
|
39
59
|
# function gives the power of a number
|
40
60
|
def power exposant = 0
|
41
61
|
ArelExtensions::Nodes::Power.new [self,exposant]
|
42
62
|
end
|
43
|
-
|
44
|
-
# Aggregate Functions
|
63
|
+
|
64
|
+
# Aggregate Functions
|
45
65
|
def std unbiased = true
|
46
|
-
|
66
|
+
ArelExtensions::Nodes::Std.new [self,unbiased]
|
47
67
|
end
|
48
|
-
|
68
|
+
|
49
69
|
def variance unbiased = true
|
50
|
-
|
70
|
+
ArelExtensions::Nodes::Variance.new [self,unbiased]
|
51
71
|
end
|
52
72
|
|
53
|
-
|
54
73
|
#function that can be invoked to produce random numbers between 0 and 1
|
55
74
|
# def rand seed = nil
|
56
75
|
# ArelExtensions::Nodes::Rand.new [seed]
|
@@ -65,28 +84,28 @@ module ArelExtensions
|
|
65
84
|
ArelExtensions::Nodes::Round.new [self]
|
66
85
|
end
|
67
86
|
end
|
68
|
-
|
87
|
+
|
69
88
|
# function returning a number at a specific format
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
89
|
+
def format_number format_string, locale=nil
|
90
|
+
begin
|
91
|
+
sprintf(format_string,0) # this line is to get the right error message if the format_string is not correct
|
92
|
+
m = /^(.*)%([ #+\-0]*)([1-9][0-9]+|[1-9]?)[.]?([0-9]*)([a-zA-Z])(.*)$/.match(format_string)
|
93
|
+
opts = {
|
94
|
+
:prefix => m[1],
|
95
|
+
:flags => m[2].split(//).uniq.join,
|
96
|
+
:width => m[3].to_i,
|
97
|
+
:precision => m[4] != '' ? m[4].to_i : 6,
|
98
|
+
:type => m[5],
|
99
|
+
:suffix => m[6],
|
100
|
+
:locale => locale,
|
101
|
+
:original_string => format_string
|
102
|
+
}
|
103
|
+
# opts = {:locale => 'fr_FR', :type => "e"/"f"/"d", :prefix => "$ ", :suffix => " %", :flags => " +-#0", :width => 5, :precision => 6}
|
104
|
+
ArelExtensions::Nodes::FormattedNumber.new [self,opts]
|
105
|
+
rescue Exception
|
106
|
+
Arel::Nodes.build_quoted('Wrong Format')
|
107
|
+
end
|
108
|
+
end
|
90
109
|
|
91
110
|
end
|
92
111
|
end
|
@@ -2,27 +2,26 @@ require 'arel_extensions/predications'
|
|
2
2
|
|
3
3
|
module ArelExtensions
|
4
4
|
module Nodes
|
5
|
-
class Function < Arel::Nodes::Function
|
5
|
+
class Function < Arel::Nodes::Function
|
6
6
|
include Arel::Math
|
7
|
-
include Arel::Expressions
|
7
|
+
include Arel::Expressions
|
8
8
|
include Arel::OrderPredications
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
include ArelExtensions::Predications
|
10
|
+
|
11
|
+
RETURN_TYPE = :string # by default...
|
12
|
+
|
13
|
+
# overrides as to make new Node like AliasPredication
|
14
|
+
|
15
|
+
def return_type
|
16
|
+
self.class.const_get(:RETURN_TYPE)
|
17
|
+
end
|
12
18
|
|
13
|
-
# overrides as to make new Node like AliasPredication
|
14
|
-
|
15
|
-
def return_type
|
16
|
-
self.class.const_get(:RETURN_TYPE)
|
17
|
-
end
|
18
|
-
|
19
|
-
|
20
19
|
def as other
|
21
20
|
ArelExtensions::Nodes::As.new(self, Arel.sql(other))
|
22
21
|
end
|
23
22
|
|
24
23
|
def expr
|
25
|
-
|
24
|
+
@expressions.first
|
26
25
|
end
|
27
26
|
|
28
27
|
def left
|
@@ -33,14 +32,14 @@ module ArelExtensions
|
|
33
32
|
@expressions[1]
|
34
33
|
end
|
35
34
|
|
36
|
-
def type_of_attribute(att)
|
35
|
+
def type_of_attribute(att)
|
37
36
|
case att
|
38
37
|
when Arel::Attributes::Attribute
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
38
|
+
begin
|
39
|
+
Arel::Table.engine.connection.schema_cache.columns_hash(att.relation.table_name)[att.name.to_s].type
|
40
|
+
rescue
|
41
|
+
att
|
42
|
+
end
|
44
43
|
when ArelExtensions::Nodes::Function
|
45
44
|
att.return_type
|
46
45
|
# else
|
@@ -53,17 +52,17 @@ module ArelExtensions
|
|
53
52
|
when Arel::Attributes::Attribute, Arel::Nodes::Node, Integer
|
54
53
|
object
|
55
54
|
when DateTime
|
56
|
-
|
55
|
+
Arel::Nodes.build_quoted(object, self)
|
57
56
|
when Time
|
58
57
|
Arel::Nodes.build_quoted(object.strftime('%H:%M:%S'), self)
|
59
|
-
when String
|
60
|
-
Arel::Nodes.build_quoted(object)
|
58
|
+
when String, Symbol
|
59
|
+
Arel::Nodes.build_quoted(object.to_s)
|
61
60
|
when Date
|
62
61
|
Arel::Nodes.build_quoted(object.to_s, self)
|
63
62
|
when NilClass
|
64
63
|
Arel.sql('NULL')
|
65
64
|
when ActiveSupport::Duration
|
66
|
-
object.to_i
|
65
|
+
Arel.sql(object.to_i)
|
67
66
|
else
|
68
67
|
raise(ArgumentError, "#{object.class} can not be converted to CONCAT arg")
|
69
68
|
end
|
@@ -85,7 +84,7 @@ module ArelExtensions
|
|
85
84
|
object
|
86
85
|
end
|
87
86
|
when DateTime
|
88
|
-
|
87
|
+
Arel::Nodes.build_quoted(object, self)
|
89
88
|
when Time
|
90
89
|
Arel::Nodes.build_quoted(object.strftime('%H:%M:%S'), self)
|
91
90
|
when String
|
@@ -93,7 +92,7 @@ module ArelExtensions
|
|
93
92
|
when Date
|
94
93
|
Arel::Nodes.build_quoted(object, self)
|
95
94
|
when NilClass
|
96
|
-
Arel.sql(
|
95
|
+
Arel.sql(nil)
|
97
96
|
when ActiveSupport::Duration
|
98
97
|
Arel::Nodes.build_quoted(object.to_i.to_s)
|
99
98
|
else
|
@@ -145,7 +144,7 @@ module ArelExtensions
|
|
145
144
|
raise(ArgumentError, "#{object.class} can not be converted to NUMBER arg")
|
146
145
|
end
|
147
146
|
end
|
148
|
-
|
147
|
+
|
149
148
|
end
|
150
149
|
end
|
151
150
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module ArelExtensions
|
2
|
+
module Nodes
|
3
|
+
class JsonNode < Function
|
4
|
+
RETURN_TYPE = :json
|
5
|
+
|
6
|
+
attr_accessor :hash
|
7
|
+
|
8
|
+
def merge *expr
|
9
|
+
args = [self] + expr.map{|e| Json.new(e)}
|
10
|
+
JsonMerge.new(args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def get key
|
14
|
+
JsonGet.new(self,key)
|
15
|
+
end
|
16
|
+
|
17
|
+
def set key, value
|
18
|
+
JsonSet.new(self,key,value)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Json < JsonNode
|
23
|
+
|
24
|
+
def initialize *expr
|
25
|
+
if expr.length == 1
|
26
|
+
case expr.first
|
27
|
+
when JsonNode
|
28
|
+
@hash = expr.first.hash
|
29
|
+
when Array
|
30
|
+
@hash = expr.first.map{|e|
|
31
|
+
(e.is_a?(Array) || e.is_a?(Hash)) ? Json.new(e) : convert_to_node(e)
|
32
|
+
}
|
33
|
+
when Hash
|
34
|
+
@hash = expr.first.inject({}){|acc,v|
|
35
|
+
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])
|
36
|
+
acc
|
37
|
+
}
|
38
|
+
when String, Numeric, TrueClass, FalseClass
|
39
|
+
@hash = convert_to_node(expr.first)
|
40
|
+
when NilClass
|
41
|
+
@hash = Arel.sql('null')
|
42
|
+
else
|
43
|
+
if expr.first.is_a?(String) || (expr.first.is_a?(Arel::Attributes::Attribute) && type_of_attribute(expr.first) == :string) || (expr.first.return_type == :string)
|
44
|
+
@hash = convert_to_node(expr.first)
|
45
|
+
else
|
46
|
+
@hash = [convert_to_node(expr.first)]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
else
|
50
|
+
@hash = expr.map{|e| (e.is_a?(Array) || e.is_a?(Hash)) ? Json.new(e) : convert_to_node(e) }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
class JsonMerge < JsonNode
|
57
|
+
end
|
58
|
+
|
59
|
+
class JsonGet < JsonNode
|
60
|
+
attr_accessor :key
|
61
|
+
|
62
|
+
def initialize json, key
|
63
|
+
@hash = json
|
64
|
+
@key = convert_to_node(key)
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
class JsonSet < JsonNode
|
70
|
+
attr_accessor :key, :value
|
71
|
+
|
72
|
+
def initialize json, key, value
|
73
|
+
@hash = json
|
74
|
+
@key = convert_to_node(key)
|
75
|
+
@value = Json.new(value)
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
@@ -1,101 +1,99 @@
|
|
1
1
|
module ArelExtensions
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
2
|
+
module Predications
|
3
|
+
def when right, expression=nil
|
4
|
+
ArelExtensions::Nodes::Case.new(self).when(right,expression)
|
5
|
+
end
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
def imatches(other, escape=nil)
|
16
|
-
ArelExtensions::Nodes::IMatches.new(self, other, escape)
|
17
|
-
end
|
18
|
-
|
19
|
-
def cast right
|
20
|
-
ArelExtensions::Nodes::Cast.new([self,right])
|
21
|
-
end
|
7
|
+
def matches(other, escape=nil,case_sensitive= nil)
|
8
|
+
if Arel::VERSION.to_i < 7
|
9
|
+
Arel::Nodes::Matches.new(self, Arel::Nodes.build_quoted(other), escape)
|
10
|
+
else
|
11
|
+
Arel::Nodes::Matches.new(self, Arel::Nodes.build_quoted(other), escape, case_sensitive)
|
12
|
+
end
|
13
|
+
end
|
22
14
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
15
|
+
def imatches(other, escape=nil)
|
16
|
+
ArelExtensions::Nodes::IMatches.new(self, other, escape)
|
17
|
+
end
|
18
|
+
|
19
|
+
def cast right
|
20
|
+
ArelExtensions::Nodes::Cast.new([self,right])
|
21
|
+
end
|
22
|
+
|
23
|
+
def in(other) #In should handle nil element in the Array
|
24
|
+
case other
|
25
|
+
when Range
|
26
|
+
self.between(other)
|
27
|
+
when Enumerable
|
28
|
+
if other.include?(nil)
|
29
|
+
other.delete(nil)
|
30
|
+
case other.length
|
31
|
+
when 0
|
32
|
+
self.is_null
|
33
|
+
when 1
|
34
|
+
self.is_null.or(self==other[0])
|
35
|
+
else
|
36
|
+
self.is_null.or(Arel::Nodes::In.new(self,quoted_array(other)))
|
37
|
+
end
|
38
|
+
else
|
39
|
+
Arel::Nodes::In.new(self,quoted_array(other))
|
40
|
+
end
|
41
|
+
when nil
|
42
|
+
self.is_null
|
43
|
+
when Arel::SelectManager
|
44
|
+
Arel::Nodes::In.new(self, other.ast)
|
45
|
+
else
|
46
|
+
Arel::Nodes::In.new(self,quoted_node(other))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def not_in(other) #In should handle nil element in the Array
|
51
|
+
case other
|
52
|
+
when Range
|
53
|
+
Arel::Nodes::Not.new(self.between(other))
|
54
|
+
when Enumerable
|
55
|
+
if other.include?(nil)
|
56
|
+
other.delete(nil)
|
57
|
+
case other.length
|
58
|
+
when 0
|
59
|
+
self.is_not_null
|
60
|
+
when 1
|
61
|
+
self.is_not_null.and(self!=other[0])
|
62
|
+
else
|
63
|
+
self.is_not_null.and(Arel::Nodes::NotIn.new(self,quoted_array(other)))
|
64
|
+
end
|
65
|
+
else
|
66
|
+
Arel::Nodes::NotIn.new(self,quoted_array(other))
|
67
|
+
end
|
68
|
+
when nil
|
69
|
+
self.is_not_null
|
70
|
+
when Arel::SelectManager
|
71
|
+
Arel::Nodes::NotIn.new(self, other.ast)
|
72
|
+
else
|
73
|
+
Arel::Nodes::NotIn.new(self,quoted_node(other))
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def convert_to_node(object)
|
78
|
+
case object
|
79
|
+
when Arel::Attributes::Attribute, Arel::Nodes::Node, Integer
|
80
|
+
object
|
81
|
+
when DateTime
|
82
|
+
Arel::Nodes.build_quoted(object, self)
|
83
|
+
when Time
|
84
|
+
Arel::Nodes.build_quoted(object.strftime('%H:%M:%S'), self)
|
85
|
+
when String
|
86
|
+
Arel::Nodes.build_quoted(object)
|
87
|
+
when Date
|
88
|
+
Arel::Nodes.build_quoted(object.to_s, self)
|
89
|
+
when NilClass
|
90
|
+
Arel.sql('NULL')
|
91
|
+
when ActiveSupport::Duration
|
92
|
+
object.to_i
|
93
|
+
else
|
94
|
+
raise(ArgumentError, "#{object.class} can not be converted to CONCAT arg")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
101
99
|
end
|