arel_extensions 1.2.8 → 1.2.16
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 +54 -86
- data/README.md +1 -1
- data/Rakefile +13 -2
- data/gemfiles/rails4.gemfile +1 -1
- data/gemfiles/rails6.gemfile +1 -1
- data/generate_gems.sh +4 -3
- data/lib/arel_extensions.rb +45 -20
- data/lib/arel_extensions/attributes.rb +0 -1
- data/lib/arel_extensions/boolean_functions.rb +39 -12
- data/lib/arel_extensions/insert_manager.rb +7 -5
- data/lib/arel_extensions/nodes/abs.rb +0 -0
- data/lib/arel_extensions/nodes/case.rb +8 -2
- data/lib/arel_extensions/nodes/ceil.rb +0 -0
- data/lib/arel_extensions/nodes/coalesce.rb +0 -0
- data/lib/arel_extensions/nodes/concat.rb +0 -0
- data/lib/arel_extensions/nodes/duration.rb +0 -0
- 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/function.rb +0 -0
- data/lib/arel_extensions/nodes/is_null.rb +0 -0
- data/lib/arel_extensions/nodes/json.rb +40 -25
- data/lib/arel_extensions/nodes/length.rb +0 -0
- data/lib/arel_extensions/nodes/locate.rb +0 -0
- data/lib/arel_extensions/nodes/rand.rb +0 -0
- data/lib/arel_extensions/nodes/replace.rb +0 -0
- data/lib/arel_extensions/nodes/round.rb +0 -0
- data/lib/arel_extensions/nodes/soundex.rb +0 -0
- data/lib/arel_extensions/nodes/substring.rb +0 -0
- data/lib/arel_extensions/nodes/trim.rb +0 -0
- data/lib/arel_extensions/nodes/union.rb +0 -0
- data/lib/arel_extensions/nodes/wday.rb +0 -0
- data/lib/arel_extensions/predications.rb +22 -19
- data/lib/arel_extensions/set_functions.rb +2 -2
- data/lib/arel_extensions/string_functions.rb +13 -0
- 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/mysql.rb +24 -9
- data/lib/arel_extensions/visitors/oracle.rb +7 -8
- data/lib/arel_extensions/visitors/postgresql.rb +1 -1
- data/lib/arel_extensions/visitors/sqlite.rb +11 -17
- data/lib/arel_extensions/visitors/to_sql.rb +56 -55
- data/test/arelx_test_helper.rb +28 -0
- data/test/support/fake_record.rb +4 -0
- data/test/test_comparators.rb +8 -7
- data/test/visitors/test_bulk_insert_oracle.rb +4 -3
- data/test/visitors/test_bulk_insert_sqlite.rb +4 -3
- data/test/visitors/test_bulk_insert_to_sql.rb +3 -3
- data/test/visitors/test_oracle.rb +41 -41
- data/test/visitors/test_to_sql.rb +366 -206
- data/test/with_ar/all_agnostic_test.rb +19 -8
- data/test/with_ar/insert_agnostic_test.rb +1 -1
- data/test/with_ar/test_bulk_sqlite.rb +4 -3
- data/test/with_ar/test_math_sqlite.rb +1 -1
- data/test/with_ar/test_string_mysql.rb +1 -1
- data/test/with_ar/test_string_sqlite.rb +1 -1
- data/version_v1.rb +1 -1
- data/version_v2.rb +1 -1
- metadata +3 -3
- 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,28 +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
|
51
|
+
|
52
|
+
attr_reader :children
|
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
|
+
|
43
70
|
end
|
@@ -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
|
when String, Symbol
|
9
10
|
cols.each { |c|
|
10
|
-
|
11
|
+
res_columns << @ast.relation[c]
|
11
12
|
}
|
12
13
|
when Array
|
13
14
|
if String === cols.first.first
|
14
|
-
|
15
|
+
res_columns = cols.map {|c| [@ast.relation[c.first]] }
|
15
16
|
elsif Arel::Attributes::Attribute == cols.first.first
|
16
|
-
|
17
|
+
res_columns = cols
|
17
18
|
end
|
18
19
|
when NilClass
|
19
|
-
|
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
|
File without changes
|
@@ -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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -26,6 +26,44 @@ module ArelExtensions
|
|
26
26
|
[@dict].hash
|
27
27
|
end
|
28
28
|
|
29
|
+
def convert_to_json_node(n)
|
30
|
+
case n
|
31
|
+
when JsonNode
|
32
|
+
n.dict
|
33
|
+
when Array
|
34
|
+
n.map{|e|
|
35
|
+
(e.is_a?(Array) || e.is_a?(Hash)) ? Json.new(e) : convert_to_json_node(e)
|
36
|
+
}
|
37
|
+
when Hash
|
38
|
+
n.reduce({}){|acc,v|
|
39
|
+
acc[convert_to_json_node(v[0])] = (v[1].is_a?(Array) || v[1].is_a?(Hash)) ? Json.new(v[1]) : convert_to_json_node(v[1])
|
40
|
+
acc
|
41
|
+
}
|
42
|
+
when String, Numeric, TrueClass, FalseClass
|
43
|
+
convert_to_node(n)
|
44
|
+
when Date
|
45
|
+
convert_to_node(n.strftime("%Y-%m-%d"))
|
46
|
+
when DateTime, Time
|
47
|
+
convert_to_node(n.strftime("%Y-%m-%dT%H:%M:%S.%L%:z"))
|
48
|
+
when NilClass
|
49
|
+
Arel.sql('null')
|
50
|
+
else
|
51
|
+
convert_to_node(n)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def type_of_node(v)
|
56
|
+
if v.is_a?(Arel::Attributes::Attribute)
|
57
|
+
self.type_of_attribute(v)
|
58
|
+
elsif v.respond_to?(:return_type)
|
59
|
+
v.return_type
|
60
|
+
elsif v.nil?
|
61
|
+
:nil
|
62
|
+
else
|
63
|
+
:string
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
29
67
|
end
|
30
68
|
|
31
69
|
class Json < JsonNode
|
@@ -33,32 +71,9 @@ module ArelExtensions
|
|
33
71
|
def initialize *expr
|
34
72
|
@dict =
|
35
73
|
if expr.length == 1
|
36
|
-
|
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')
|
52
|
-
else
|
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
|
59
|
-
end
|
74
|
+
convert_to_json_node(expr.first)
|
60
75
|
else
|
61
|
-
expr.map{|e| (e
|
76
|
+
expr.map{|e| convert_to_json_node(e) }
|
62
77
|
end
|
63
78
|
super
|
64
79
|
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module ArelExtensions
|
2
2
|
module Predications
|
3
|
+
|
3
4
|
def when right, expression = nil
|
4
5
|
ArelExtensions::Nodes::Case.new(self).when(right,expression)
|
5
6
|
end
|
@@ -20,23 +21,25 @@ module ArelExtensions
|
|
20
21
|
ArelExtensions::Nodes::Cast.new([self,right])
|
21
22
|
end
|
22
23
|
|
23
|
-
def in(other) #In should handle nil element in the Array
|
24
|
+
def in(*other) #In should handle nil element in the Array
|
25
|
+
other = other.first if other.length <= 1
|
24
26
|
case other
|
25
27
|
when Range
|
26
28
|
self.between(other)
|
29
|
+
when Arel::Nodes::Grouping
|
30
|
+
Arel::Nodes::In.new(self, quoted_node(other))
|
27
31
|
when Enumerable
|
28
32
|
nils, values = other.partition{ |v| v.nil? }
|
29
33
|
ranges, values = values.partition{ |v| v.is_a?(Range) || v.is_a?(Arel::SelectManager)}
|
30
|
-
|
31
34
|
# In order of (imagined) decreasing efficiency: nil, values, and then more complex.
|
32
35
|
clauses =
|
33
36
|
nils.uniq.map { |r| self.in(r) } \
|
34
37
|
+ (case values.uniq.size
|
35
38
|
when 0 then []
|
36
|
-
when 1 then [self
|
39
|
+
when 1 then [values[0].is_a?(Arel::Nodes::Grouping) ? self.in(values[0]) : self.eq(values[0])]
|
37
40
|
else [Arel::Nodes::In.new(self, quoted_array(values))] end) \
|
38
41
|
+ ranges.uniq.map { |r| self.in(r) }
|
39
|
-
clauses.empty? ?
|
42
|
+
clauses.empty? ? Arel.false : clauses.reduce(&:or)
|
40
43
|
when nil
|
41
44
|
self.is_null
|
42
45
|
when Arel::SelectManager
|
@@ -46,24 +49,25 @@ module ArelExtensions
|
|
46
49
|
end
|
47
50
|
end
|
48
51
|
|
49
|
-
def not_in(other) #In should handle nil element in the Array
|
52
|
+
def not_in(*other) #In should handle nil element in the Array
|
53
|
+
other = other.first if other.length <= 1
|
50
54
|
case other
|
51
55
|
when Range
|
52
56
|
Arel::Nodes::Not.new(self.between(other))
|
57
|
+
when Arel::Nodes::Grouping
|
58
|
+
Arel::Nodes::NotIn.new(self, quoted_node(other))
|
53
59
|
when Enumerable
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
Arel::Nodes::NotIn.new(self,quoted_array(other))
|
66
|
-
end
|
60
|
+
nils, values = other.partition{ |v| v.nil? }
|
61
|
+
ranges, values = values.partition{ |v| v.is_a?(Range) || v.is_a?(Arel::SelectManager)}
|
62
|
+
# In order of (imagined) decreasing efficiency: nil, values, and then more complex.
|
63
|
+
clauses =
|
64
|
+
nils.uniq.map { |r| self.not_in(r) } \
|
65
|
+
+ (case values.uniq.size
|
66
|
+
when 0 then []
|
67
|
+
when 1 then [values[0].is_a?(Arel::Nodes::Grouping) ? self.not_in(values[0]) : self.not_eq(values[0])]
|
68
|
+
else [Arel::Nodes::NotIn.new(self, quoted_array(values))] end) \
|
69
|
+
+ ranges.uniq.map { |r| self.not_in(r) }
|
70
|
+
Arel::Nodes::And.new clauses
|
67
71
|
when nil
|
68
72
|
self.is_not_null
|
69
73
|
when Arel::SelectManager
|
@@ -93,6 +97,5 @@ module ArelExtensions
|
|
93
97
|
raise(ArgumentError, "#{object.class} can not be converted to CONCAT arg")
|
94
98
|
end
|
95
99
|
end
|
96
|
-
|
97
100
|
end
|
98
101
|
end
|
@@ -23,10 +23,10 @@ module ArelExtensions
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
Arel::Nodes::Union
|
26
|
+
class Arel::Nodes::Union
|
27
27
|
include ArelExtensions::SetFunctions
|
28
28
|
end
|
29
29
|
|
30
|
-
Arel::Nodes::UnionAll
|
30
|
+
class Arel::Nodes::UnionAll
|
31
31
|
include ArelExtensions::SetFunctions
|
32
32
|
end
|
@@ -64,6 +64,19 @@ module ArelExtensions
|
|
64
64
|
grouping_any :imatches, others, escape
|
65
65
|
end
|
66
66
|
|
67
|
+
# def grouping_any method, others, *extra
|
68
|
+
# puts "*******************"
|
69
|
+
# puts method
|
70
|
+
# puts others.inspect
|
71
|
+
# puts extra.inspect
|
72
|
+
# puts "-------------------"
|
73
|
+
# res = super(method,others,*extra)
|
74
|
+
# puts res.to_sql
|
75
|
+
# puts res.inspect
|
76
|
+
# puts "*******************"
|
77
|
+
# res
|
78
|
+
# end
|
79
|
+
|
67
80
|
def imatches_all others, escape = nil
|
68
81
|
grouping_all :imatches, others, escape, escape
|
69
82
|
end
|
@@ -6,7 +6,7 @@ require 'arel_extensions/visitors/postgresql'
|
|
6
6
|
require 'arel_extensions/visitors/sqlite'
|
7
7
|
require 'arel_extensions/visitors/mssql'
|
8
8
|
|
9
|
-
Arel::Visitors::MSSQL
|
9
|
+
class Arel::Visitors::MSSQL
|
10
10
|
include ArelExtensions::Visitors::MSSQL
|
11
11
|
|
12
12
|
alias_method :old_visit_Arel_Nodes_As, :visit_Arel_Nodes_As
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module ArelExtensions
|
2
2
|
module Visitors
|
3
|
-
Arel::Visitors::MySQL
|
3
|
+
class Arel::Visitors::MySQL
|
4
4
|
Arel::Visitors::MySQL::DATE_MAPPING = {'d' => 'DAY', 'm' => 'MONTH', 'w' => 'WEEK', 'y' => 'YEAR', 'wd' => 'WEEKDAY', 'h' => 'HOUR', 'mn' => 'MINUTE', 's' => 'SECOND'}
|
5
5
|
Arel::Visitors::MySQL::DATE_FORMAT_DIRECTIVES = { # ISO C / POSIX
|
6
6
|
'%Y' => '%Y', '%C' => '', '%y' => '%y', '%m' => '%m', '%B' => '%M', '%b' => '%b', '%^b' => '%b', # year, month
|
@@ -193,6 +193,13 @@ module ArelExtensions
|
|
193
193
|
collector
|
194
194
|
end
|
195
195
|
|
196
|
+
def visit_ArelExtensions_Nodes_RegexpReplace o, collector
|
197
|
+
if !regexp_replace_supported?
|
198
|
+
warn("Warning : ArelExtensions: REGEXP_REPLACE does not seem to be available in the current version of the DBMS, it might crash")
|
199
|
+
end
|
200
|
+
super(o,collector)
|
201
|
+
end
|
202
|
+
|
196
203
|
def visit_ArelExtensions_Nodes_Format o, collector
|
197
204
|
case o.col_type
|
198
205
|
when :date, :datetime
|
@@ -403,7 +410,7 @@ module ArelExtensions
|
|
403
410
|
|
404
411
|
def visit_Aggregate_For_AggregateFunction o, collector
|
405
412
|
if !window_supported?
|
406
|
-
warn("Warning : ArelExtensions: Window Functions are not available in the current version
|
413
|
+
warn("Warning : ArelExtensions: Window Functions are not available in the current version of the DBMS.")
|
407
414
|
return collector
|
408
415
|
end
|
409
416
|
|
@@ -449,14 +456,22 @@ module ArelExtensions
|
|
449
456
|
version_supported?('10.2.3', '8.0')
|
450
457
|
end
|
451
458
|
|
452
|
-
def
|
459
|
+
def regexp_replace_supported?
|
460
|
+
version_supported?('10.0.5', '8.0')
|
461
|
+
end
|
462
|
+
|
463
|
+
def version_supported?(mariadb_v = '10.2.3', mysql_v = '5.7.0')
|
453
464
|
conn = Arel::Table.engine.connection
|
454
|
-
conn.send(:mariadb?) &&
|
455
|
-
(conn.respond_to?(:get_database_version) && conn.send(:get_database_version) >=
|
456
|
-
conn.respond_to?(:version) && conn.send(:version) >=
|
457
|
-
|
458
|
-
|
459
|
-
conn.respond_to?(:
|
465
|
+
conn.send(:mariadb?) && \
|
466
|
+
(conn.respond_to?(:get_database_version) && conn.send(:get_database_version) >= mariadb_v || \
|
467
|
+
conn.respond_to?(:version) && conn.send(:version) >= mariadb_v || \
|
468
|
+
conn.instance_variable_get(:"@version") && conn.instance_variable_get(:"@version") >= mariadb_v) || \
|
469
|
+
!conn.send(:mariadb?) && \
|
470
|
+
(conn.respond_to?(:get_database_version) && conn.send(:get_database_version) >= mysql_v || \
|
471
|
+
conn.respond_to?(:version) && conn.send(:version) >= mysql_v || \
|
472
|
+
conn.instance_variable_get(:"@version") && conn.instance_variable_get(:"@version") >= mysql_v)
|
473
|
+
# ideally we should parse the instance_variable @full_version because @version contains only the supposedly
|
474
|
+
# corresponding mysql version of the current mariadb version (which is not very helpful most of the time)
|
460
475
|
end
|
461
476
|
|
462
477
|
def visit_ArelExtensions_Nodes_Json o,collector
|