arel_extensions 2.0.0 → 2.0.10
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/.travis.yml +59 -91
- data/Gemfile +14 -19
- data/README.md +17 -12
- data/Rakefile +38 -27
- data/appveyor.yml +1 -1
- data/arel_extensions.gemspec +2 -2
- data/functions.html +3 -3
- data/gemfiles/rails4.gemfile +1 -1
- data/gemfiles/rails6.gemfile +30 -0
- data/gemspec_v2/arel_extensions-v2.gemspec +28 -0
- data/generate_gems.sh +14 -0
- data/init/mssql.sql +4 -4
- data/init/mysql.sql +38 -38
- data/init/postgresql.sql +21 -21
- data/lib/arel_extensions.rb +63 -19
- data/lib/arel_extensions/attributes.rb +0 -1
- data/lib/arel_extensions/boolean_functions.rb +38 -13
- data/lib/arel_extensions/common_sql_functions.rb +5 -4
- data/lib/arel_extensions/comparators.rb +4 -2
- data/lib/arel_extensions/insert_manager.rb +15 -13
- data/lib/arel_extensions/math.rb +3 -3
- data/lib/arel_extensions/math_functions.rb +10 -5
- data/lib/arel_extensions/nodes.rb +1 -1
- data/lib/arel_extensions/nodes/abs.rb +0 -0
- data/lib/arel_extensions/nodes/aggregate_function.rb +14 -0
- data/lib/arel_extensions/nodes/case.rb +8 -4
- data/lib/arel_extensions/nodes/ceil.rb +0 -0
- data/lib/arel_extensions/nodes/coalesce.rb +2 -2
- data/lib/arel_extensions/nodes/collate.rb +1 -1
- data/lib/arel_extensions/nodes/concat.rb +6 -13
- data/lib/arel_extensions/nodes/date_diff.rb +3 -5
- data/lib/arel_extensions/nodes/duration.rb +0 -2
- data/lib/arel_extensions/nodes/find_in_set.rb +0 -0
- data/lib/arel_extensions/nodes/floor.rb +0 -0
- data/lib/arel_extensions/nodes/format.rb +8 -8
- data/lib/arel_extensions/nodes/formatted_number.rb +23 -23
- data/lib/arel_extensions/nodes/function.rb +2 -0
- data/lib/arel_extensions/nodes/is_null.rb +0 -0
- data/lib/arel_extensions/nodes/json.rb +28 -30
- data/lib/arel_extensions/nodes/length.rb +0 -0
- data/lib/arel_extensions/nodes/locate.rb +0 -0
- data/lib/arel_extensions/nodes/matches.rb +4 -4
- data/lib/arel_extensions/nodes/power.rb +6 -5
- data/lib/arel_extensions/nodes/rand.rb +0 -0
- data/lib/arel_extensions/nodes/repeat.rb +2 -2
- data/lib/arel_extensions/nodes/replace.rb +24 -6
- data/lib/arel_extensions/nodes/round.rb +5 -5
- data/lib/arel_extensions/nodes/soundex.rb +16 -15
- data/lib/arel_extensions/nodes/std.rb +19 -21
- data/lib/arel_extensions/nodes/substring.rb +8 -15
- data/lib/arel_extensions/nodes/sum.rb +7 -0
- data/lib/arel_extensions/nodes/trim.rb +3 -3
- data/lib/arel_extensions/nodes/union.rb +2 -3
- data/lib/arel_extensions/nodes/union_all.rb +0 -1
- data/lib/arel_extensions/nodes/wday.rb +0 -0
- data/lib/arel_extensions/null_functions.rb +2 -2
- data/lib/arel_extensions/predications.rb +35 -33
- data/lib/arel_extensions/set_functions.rb +2 -2
- data/lib/arel_extensions/string_functions.rb +34 -12
- data/lib/arel_extensions/tasks.rb +5 -5
- data/lib/arel_extensions/version.rb +1 -1
- data/lib/arel_extensions/visitors.rb +1 -1
- data/lib/arel_extensions/visitors/ibm_db.rb +1 -1
- data/lib/arel_extensions/visitors/mssql.rb +14 -13
- data/lib/arel_extensions/visitors/mysql.rb +90 -37
- data/lib/arel_extensions/visitors/oracle.rb +15 -15
- data/lib/arel_extensions/visitors/oracle12.rb +1 -1
- data/lib/arel_extensions/visitors/postgresql.rb +78 -32
- data/lib/arel_extensions/visitors/sqlite.rb +61 -53
- data/lib/arel_extensions/visitors/to_sql.rb +70 -58
- data/test/arelx_test_helper.rb +28 -0
- data/test/real_db_test.rb +1 -1
- data/test/support/fake_record.rb +1 -1
- data/test/test_comparators.rb +9 -8
- data/test/visitors/test_bulk_insert_oracle.rb +8 -7
- data/test/visitors/test_bulk_insert_sqlite.rb +9 -8
- data/test/visitors/test_bulk_insert_to_sql.rb +8 -10
- data/test/visitors/test_oracle.rb +41 -40
- data/test/visitors/test_to_sql.rb +367 -193
- data/test/with_ar/all_agnostic_test.rb +68 -35
- data/test/with_ar/insert_agnostic_test.rb +3 -2
- data/test/with_ar/test_bulk_sqlite.rb +6 -5
- data/test/with_ar/test_math_sqlite.rb +4 -4
- data/test/with_ar/test_string_mysql.rb +4 -6
- data/test/with_ar/test_string_sqlite.rb +3 -7
- data/version_v1.rb +3 -0
- data/version_v2.rb +3 -0
- metadata +14 -7
- data/test/helper.rb +0 -18
@@ -1,3 +1,4 @@
|
|
1
|
+
# coding: utf-8
|
1
2
|
require 'arel_extensions/nodes/then'
|
2
3
|
|
3
4
|
module ArelExtensions
|
@@ -8,7 +9,7 @@ module ArelExtensions
|
|
8
9
|
end
|
9
10
|
|
10
11
|
def and *others
|
11
|
-
Arel::Nodes::And.new
|
12
|
+
Arel::Nodes::And.new self, others
|
12
13
|
end
|
13
14
|
|
14
15
|
def ⋁(other)
|
@@ -16,30 +17,54 @@ module ArelExtensions
|
|
16
17
|
end
|
17
18
|
|
18
19
|
def or *others
|
19
|
-
|
20
|
-
if args.length == 1
|
21
|
-
Arel::Nodes::Or.new(self, args.first)
|
22
|
-
else
|
23
|
-
ArelExtensions::Nodes::Or.new([self]+ args)
|
24
|
-
end
|
20
|
+
Arel::Nodes::Or.new self, others
|
25
21
|
end
|
26
22
|
|
27
23
|
def then(t, f = nil)
|
28
24
|
ArelExtensions::Nodes::Then.new [self, t, f]
|
29
25
|
end
|
26
|
+
|
30
27
|
end
|
31
28
|
end
|
32
29
|
|
33
|
-
Arel::Nodes::And
|
30
|
+
class Arel::Nodes::And
|
34
31
|
include ArelExtensions::BooleanFunctions
|
35
|
-
end
|
36
32
|
|
37
|
-
|
38
|
-
|
33
|
+
def self.new *children
|
34
|
+
children =
|
35
|
+
children.flatten.map { |c|
|
36
|
+
c.is_a?(self) ? c.children : c
|
37
|
+
}.flatten
|
38
|
+
super(children)
|
39
|
+
end
|
40
|
+
|
39
41
|
end
|
40
42
|
|
41
|
-
|
43
|
+
# For some reason, Arel's And is properly defined as variadic (it
|
44
|
+
# stores @children, and hashes it all). However Arel's Or is defined
|
45
|
+
# as binary, with only @left and @right, and hashing only @left and @right.
|
46
|
+
#
|
47
|
+
# So reimplement its ctor and accessors.
|
48
|
+
|
49
|
+
class Arel::Nodes::Or
|
42
50
|
include ArelExtensions::BooleanFunctions
|
43
|
-
end
|
44
51
|
|
52
|
+
attr_reader :children
|
45
53
|
|
54
|
+
def self.new *children
|
55
|
+
children =
|
56
|
+
children.flatten.map { |c|
|
57
|
+
c.is_a?(self) ? c.children : c
|
58
|
+
}.flatten
|
59
|
+
super(*children)
|
60
|
+
end
|
61
|
+
|
62
|
+
def initialize *children
|
63
|
+
@children = children
|
64
|
+
end
|
65
|
+
|
66
|
+
def hash
|
67
|
+
children.hash
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
@@ -39,6 +39,7 @@ module ArelExtensions
|
|
39
39
|
|
40
40
|
def add_sql_functions(env_db = nil)
|
41
41
|
env_db ||= @cnx.adapter_name
|
42
|
+
env_db = 'mysql' if env_db =~ /mysql/i
|
42
43
|
if env_db =~ /sqlite/i
|
43
44
|
begin
|
44
45
|
add_sqlite_functions
|
@@ -52,10 +53,10 @@ module ArelExtensions
|
|
52
53
|
sql.split(/^GO\s*$/).each {|str|
|
53
54
|
@cnx.execute(str.strip) unless str.blank?
|
54
55
|
}
|
55
|
-
elsif env_db ==
|
56
|
-
|
57
|
-
|
58
|
-
|
56
|
+
elsif env_db =='mysql'
|
57
|
+
sql.split("$$")[1..-2].each { |str|
|
58
|
+
@cnx.execute(str.strip) unless str.strip.blank?
|
59
|
+
}
|
59
60
|
else
|
60
61
|
@cnx.execute(sql) unless sql.blank?
|
61
62
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module ArelExtensions
|
2
2
|
module Comparators
|
3
3
|
|
4
|
+
|
4
5
|
def >(other)
|
5
6
|
Arel::Nodes::GreaterThan.new self, Arel::Nodes.build_quoted(other, self)
|
6
7
|
end
|
@@ -37,13 +38,14 @@ module ArelExtensions
|
|
37
38
|
end
|
38
39
|
|
39
40
|
private
|
40
|
-
#Function
|
41
|
+
# Function used for not_regexp.
|
41
42
|
def convert_regexp(other)
|
42
43
|
case other
|
43
44
|
when String
|
44
|
-
#Do nothing
|
45
|
+
# Do nothing.
|
45
46
|
when Regexp
|
46
47
|
other = other.source.gsub('\A','^')
|
48
|
+
other.gsub!('\z','$')
|
47
49
|
other.gsub!('\Z','$')
|
48
50
|
other.gsub!('\d','[0-9]')
|
49
51
|
other.gsub!('\D','[^0-9]')
|
@@ -4,21 +4,23 @@ module ArelExtensions
|
|
4
4
|
module InsertManager
|
5
5
|
|
6
6
|
def bulk_insert(cols, data)
|
7
|
+
res_columns = []
|
7
8
|
case cols.first
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
9
|
+
when String, Symbol
|
10
|
+
cols.each { |c|
|
11
|
+
res_columns << @ast.relation[c]
|
12
|
+
}
|
13
|
+
when Array
|
14
|
+
if String === cols.first.first
|
15
|
+
res_columns = cols.map {|c| [@ast.relation[c.first]] }
|
16
|
+
elsif Arel::Attributes::Attribute == cols.first.first
|
17
|
+
res_columns = cols
|
18
|
+
end
|
19
|
+
when NilClass
|
20
|
+
res_columns = @ast.relation.columns
|
20
21
|
end
|
21
|
-
self.values = BulkValues.new(
|
22
|
+
self.values = BulkValues.new(res_columns, data)
|
23
|
+
@ast.columns = res_columns
|
22
24
|
end
|
23
25
|
|
24
26
|
class BulkValues < Arel::Nodes::Node
|
data/lib/arel_extensions/math.rb
CHANGED
@@ -24,7 +24,7 @@ module ArelExtensions
|
|
24
24
|
else
|
25
25
|
return Arel::Nodes::Grouping.new(Arel::Nodes::Addition.new self, other)
|
26
26
|
end
|
27
|
-
when
|
27
|
+
when ArelExtensions::Nodes::Function,ArelExtensions::Nodes::Case
|
28
28
|
return case self.return_type
|
29
29
|
when :string, :text
|
30
30
|
self.concat(other)
|
@@ -35,7 +35,7 @@ module ArelExtensions
|
|
35
35
|
else
|
36
36
|
self.concat(other)
|
37
37
|
end
|
38
|
-
when
|
38
|
+
when Arel::Nodes::Function
|
39
39
|
Arel::Nodes::Grouping.new(Arel::Nodes::Addition.new self, other)
|
40
40
|
else
|
41
41
|
begin
|
@@ -115,7 +115,7 @@ module ArelExtensions
|
|
115
115
|
end
|
116
116
|
when Arel::Nodes::Node, DateTime, Time, String, Date
|
117
117
|
ArelExtensions::Nodes::DateDiff.new [self, other]
|
118
|
-
when
|
118
|
+
when ArelExtensions::Nodes::Duration, Integer
|
119
119
|
ArelExtensions::Nodes::DateSub.new [self, other]
|
120
120
|
else # ActiveSupport::Duration
|
121
121
|
ArelExtensions::Nodes::DateAdd.new [self, -other]
|
@@ -7,6 +7,7 @@ require 'arel_extensions/nodes/formatted_number'
|
|
7
7
|
require 'arel_extensions/nodes/log10'
|
8
8
|
require 'arel_extensions/nodes/power'
|
9
9
|
require 'arel_extensions/nodes/std'
|
10
|
+
require 'arel_extensions/nodes/sum'
|
10
11
|
|
11
12
|
module ArelExtensions
|
12
13
|
module MathFunctions
|
@@ -62,12 +63,16 @@ module ArelExtensions
|
|
62
63
|
end
|
63
64
|
|
64
65
|
# Aggregate Functions
|
65
|
-
def std
|
66
|
-
ArelExtensions::Nodes::Std.new
|
66
|
+
def std opts = {unbiased: true}
|
67
|
+
ArelExtensions::Nodes::Std.new self, opts
|
67
68
|
end
|
68
69
|
|
69
|
-
def variance
|
70
|
-
ArelExtensions::Nodes::Variance.new
|
70
|
+
def variance opts = {unbiased: true}
|
71
|
+
ArelExtensions::Nodes::Variance.new self, opts
|
72
|
+
end
|
73
|
+
|
74
|
+
def sum opts = {unbiased: true}
|
75
|
+
ArelExtensions::Nodes::Sum.new self, opts
|
71
76
|
end
|
72
77
|
|
73
78
|
#function that can be invoked to produce random numbers between 0 and 1
|
@@ -86,7 +91,7 @@ module ArelExtensions
|
|
86
91
|
end
|
87
92
|
|
88
93
|
# function returning a number at a specific format
|
89
|
-
def format_number format_string, locale=nil
|
94
|
+
def format_number format_string, locale = nil
|
90
95
|
begin
|
91
96
|
sprintf(format_string,0) # this line is to get the right error message if the format_string is not correct
|
92
97
|
m = /^(.*)%([ #+\-0]*)([1-9][0-9]+|[1-9]?)[.]?([0-9]*)([a-zA-Z])(.*)$/.match(format_string)
|
@@ -1,2 +1,2 @@
|
|
1
1
|
require 'arel_extensions/nodes/function'
|
2
|
-
|
2
|
+
require 'arel_extensions/nodes/aggregate_function'
|
File without changes
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module ArelExtensions
|
2
|
+
module Nodes
|
3
|
+
class AggregateFunction < Function
|
4
|
+
attr_accessor :order, :group
|
5
|
+
|
6
|
+
def initialize node, **opts
|
7
|
+
@order = Array(opts[:order]).map{|e| convert_to_node(e)}
|
8
|
+
@group = Array(opts[:group]).map{|e| convert_to_node(e)}
|
9
|
+
super [node]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -1,7 +1,11 @@
|
|
1
1
|
module ArelExtensions
|
2
2
|
module Nodes
|
3
|
-
if Arel::VERSION < "7.1.0"
|
3
|
+
if Gem::Version.new(Arel::VERSION) < Gem::Version.new("7.1.0")
|
4
4
|
class Case < Arel::Nodes::Node
|
5
|
+
include Arel::Expressions
|
6
|
+
include Arel::Math
|
7
|
+
include Arel::Predications
|
8
|
+
include Arel::OrderPredications
|
5
9
|
attr_accessor :case, :conditions, :default
|
6
10
|
|
7
11
|
def initialize expression = nil, default = nil
|
@@ -26,8 +30,10 @@ module ArelExtensions
|
|
26
30
|
end
|
27
31
|
end
|
28
32
|
|
29
|
-
ArelExtensions::Nodes::Case
|
33
|
+
class ArelExtensions::Nodes::Case
|
30
34
|
include Arel::Expressions
|
35
|
+
include Arel::Math
|
36
|
+
include Arel::Predications
|
31
37
|
include Arel::OrderPredications
|
32
38
|
include ArelExtensions::Math
|
33
39
|
include ArelExtensions::Comparators
|
@@ -41,8 +47,6 @@ module ArelExtensions
|
|
41
47
|
@conditions.last.right
|
42
48
|
elsif @default
|
43
49
|
@default.expr
|
44
|
-
else
|
45
|
-
nil
|
46
50
|
end
|
47
51
|
if obj.respond_to?(:return_type)
|
48
52
|
obj.return_type
|
File without changes
|
@@ -2,7 +2,7 @@ module ArelExtensions
|
|
2
2
|
module Nodes
|
3
3
|
class Coalesce < Function
|
4
4
|
RETURN_TYPE = :string
|
5
|
-
|
5
|
+
|
6
6
|
attr_accessor :left_node_type
|
7
7
|
|
8
8
|
def return_type
|
@@ -20,7 +20,7 @@ module ArelExtensions
|
|
20
20
|
@left_node_type = :number
|
21
21
|
when ArelExtensions::Nodes::Coalesce, ArelExtensions::Nodes::Function
|
22
22
|
@left_node_type = expr.first.respond_to?(:left_node_type) ? expr.first.left_node_type : nil
|
23
|
-
when Arel::Nodes::Node, Arel::Attributes::Attribute
|
23
|
+
when Arel::Nodes::Node, Arel::Attributes::Attribute
|
24
24
|
@left_node_type = type_of_attribute(expr.first)
|
25
25
|
when Date
|
26
26
|
@left_node_type = :ruby_date
|
@@ -40,21 +40,14 @@ module ArelExtensions::Nodes
|
|
40
40
|
|
41
41
|
end
|
42
42
|
|
43
|
-
class GroupConcat <
|
43
|
+
class GroupConcat < AggregateFunction
|
44
44
|
RETURN_TYPE = :string
|
45
45
|
|
46
|
-
attr_accessor :
|
47
|
-
|
48
|
-
def initialize
|
49
|
-
|
50
|
-
|
51
|
-
@orders = arg
|
52
|
-
nil
|
53
|
-
else
|
54
|
-
convert_to_node(arg)
|
55
|
-
end
|
56
|
-
}.compact
|
57
|
-
super(tab)
|
46
|
+
attr_accessor :separator
|
47
|
+
|
48
|
+
def initialize node, separator = ', ', **opts
|
49
|
+
@separator = convert_to_node(separator)
|
50
|
+
super node, opts
|
58
51
|
end
|
59
52
|
|
60
53
|
end
|
@@ -12,7 +12,7 @@ module ArelExtensions
|
|
12
12
|
res = []
|
13
13
|
col = expr.first
|
14
14
|
case col
|
15
|
-
when Arel::Nodes::Node, Arel::Attributes::Attribute
|
15
|
+
when Arel::Nodes::Node, Arel::Attributes::Attribute
|
16
16
|
@left_node_type = type_of_attribute(col)
|
17
17
|
when Date
|
18
18
|
@left_node_type = :ruby_date
|
@@ -21,7 +21,7 @@ module ArelExtensions
|
|
21
21
|
end
|
22
22
|
res << ([:date, :ruby_date].include?(@left_node_type) ? convert_to_date_node(col) : convert_to_datetime_node(col))
|
23
23
|
case expr[1]
|
24
|
-
when Arel::Nodes::Node, Arel::Attributes::Attribute
|
24
|
+
when Arel::Nodes::Node, Arel::Attributes::Attribute
|
25
25
|
@right_node_type = type_of_attribute(expr[1])
|
26
26
|
when Date
|
27
27
|
@right_node_type = :ruby_date
|
@@ -136,7 +136,7 @@ module ArelExtensions
|
|
136
136
|
if ArelExtensions::Nodes::Duration === v
|
137
137
|
v.with_interval = true
|
138
138
|
case v.left
|
139
|
-
when
|
139
|
+
when 'd','m','y'
|
140
140
|
Arel.sql('day')
|
141
141
|
when 'h','mn','s'
|
142
142
|
Arel.sql('second')
|
@@ -145,8 +145,6 @@ module ArelExtensions
|
|
145
145
|
else
|
146
146
|
Arel.sql(Arel::Visitors::MSSQL::DATE_MAPPING[v.left])
|
147
147
|
end
|
148
|
-
else
|
149
|
-
nil
|
150
148
|
end
|
151
149
|
end
|
152
150
|
end
|
File without changes
|
File without changes
|
@@ -1,15 +1,15 @@
|
|
1
1
|
module ArelExtensions
|
2
2
|
module Nodes
|
3
|
-
class Format < Function
|
3
|
+
class Format < Function
|
4
4
|
RETURN_TYPE = :string
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
attr_accessor :col_type, :iso_format
|
7
|
+
def initialize expr
|
8
|
+
col = expr.first
|
9
|
+
@iso_format = expr[1]
|
10
|
+
@col_type = type_of_attribute(col)
|
11
|
+
super [col, convert_to_string_node(@iso_format)]
|
12
|
+
end
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
@@ -1,25 +1,25 @@
|
|
1
1
|
module ArelExtensions
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
2
|
+
module Nodes
|
3
|
+
class FormattedNumber < Function
|
4
|
+
RETURN_TYPE = :string
|
5
|
+
|
6
|
+
attr_accessor :locale, :prefix, :suffix, :flags, :scientific_notation, :width,:precision, :type, :original_string
|
7
|
+
|
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
|
+
|
23
|
+
end
|
24
|
+
end
|
25
25
|
end
|