arel_extensions 2.0.24 → 2.1.2
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/.github/workflows/ruby.yml +358 -71
- data/Gemfile +8 -8
- data/README.md +107 -0
- data/gemfiles/rails5_2.gemfile +8 -7
- data/gemfiles/rails6.gemfile +7 -8
- data/gemfiles/rails6_1.gemfile +6 -7
- data/gemfiles/rails7.gemfile +22 -0
- data/lib/arel_extensions/aliases.rb +14 -0
- data/lib/arel_extensions/attributes.rb +2 -0
- data/lib/arel_extensions/date_duration.rb +2 -2
- data/lib/arel_extensions/helpers.rb +48 -0
- data/lib/arel_extensions/math.rb +17 -27
- data/lib/arel_extensions/nodes/case.rb +5 -10
- data/lib/arel_extensions/nodes/date_diff.rb +23 -4
- data/lib/arel_extensions/nodes/format.rb +3 -2
- data/lib/arel_extensions/nodes/function.rb +1 -7
- data/lib/arel_extensions/version.rb +1 -1
- data/lib/arel_extensions/visitors/mssql.rb +123 -51
- data/lib/arel_extensions/visitors/mysql.rb +23 -2
- data/lib/arel_extensions/visitors/oracle.rb +13 -1
- data/lib/arel_extensions/visitors/postgresql.rb +23 -5
- data/lib/arel_extensions/visitors/sqlite.rb +6 -3
- data/lib/arel_extensions/visitors/to_sql.rb +13 -8
- data/lib/arel_extensions.rb +27 -7
- data/test/arelx_test_helper.rb +45 -1
- data/test/database.yml +8 -2
- data/test/real_db_test.rb +5 -1
- data/test/support/fake_record.rb +1 -1
- data/test/visitors/test_to_sql.rb +38 -10
- data/test/with_ar/all_agnostic_test.rb +83 -5
- data/test/with_ar/insert_agnostic_test.rb +6 -2
- data/test/with_ar/test_bulk_sqlite.rb +6 -2
- data/test/with_ar/test_math_sqlite.rb +6 -2
- data/test/with_ar/test_string_mysql.rb +6 -2
- data/test/with_ar/test_string_sqlite.rb +6 -2
- data/version_v1.rb +1 -1
- data/version_v2.rb +1 -1
- metadata +6 -4
- data/appveyor.yml +0 -44
data/gemfiles/rails6.gemfile
CHANGED
@@ -8,23 +8,22 @@ group :development, :test do
|
|
8
8
|
gem 'activemodel', '~> 6.0.0'
|
9
9
|
gem 'activerecord', '~> 6.0.0'
|
10
10
|
|
11
|
-
gem "sqlite3", '~> 1.4', platforms: [:mri
|
12
|
-
gem "mysql2", '0.5.2', platforms: [:mri
|
13
|
-
gem "pg",'< 1.0.0', platforms: [:mri
|
11
|
+
gem "sqlite3", '~> 1.4', platforms: [:mri]
|
12
|
+
gem "mysql2", '0.5.2', platforms: [:mri]
|
13
|
+
gem "pg",'< 1.0.0', platforms: [:mri]
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
gem "tiny_tds", platforms: [:mri, :mingw, :x64_mingw, :mswin]
|
16
|
+
gem "activerecord-sqlserver-adapter", '~> 6.0', platforms: [:mri, :mingw, :x64_mingw, :mswin]
|
17
17
|
|
18
18
|
gem 'ruby-oci8', platforms: [:mri, :mswin, :mingw] if ENV.has_key? 'ORACLE_HOME'
|
19
19
|
gem 'activerecord-oracle_enhanced-adapter', '~> 6.0.0' if ENV.has_key? 'ORACLE_HOME'
|
20
20
|
|
21
21
|
# for JRuby
|
22
|
-
gem 'activerecord-jdbc-adapter', platforms: :jruby
|
22
|
+
gem 'activerecord-jdbc-adapter', github: 'jruby/activerecord-jdbc-adapter', tag: 'v60.4', platforms: :jruby
|
23
23
|
gem "jdbc-sqlite3", platforms: :jruby
|
24
24
|
gem "activerecord-jdbcsqlite3-adapter", platforms: :jruby
|
25
25
|
gem "activerecord-jdbcmysql-adapter", platforms: :jruby
|
26
26
|
gem "activerecord-jdbcpostgresql-adapter", platforms: :jruby
|
27
|
-
gem "activerecord-jdbcmssql-adapter", platforms: :jruby
|
28
27
|
end
|
29
28
|
|
30
|
-
gemspec path: "../"
|
29
|
+
gemspec path: "../"
|
data/gemfiles/rails6_1.gemfile
CHANGED
@@ -8,23 +8,22 @@ group :development, :test do
|
|
8
8
|
gem 'activemodel', '~> 6.1.0'
|
9
9
|
gem 'activerecord', '~> 6.1.0'
|
10
10
|
|
11
|
-
gem "sqlite3", '~> 1.4', platforms: [:mri
|
12
|
-
gem "mysql2", '0.5.2', platforms: [:mri
|
13
|
-
gem "pg",'~> 1.1', platforms: [:mri
|
11
|
+
gem "sqlite3", '~> 1.4', platforms: [:mri]
|
12
|
+
gem "mysql2", '0.5.2', platforms: [:mri]
|
13
|
+
gem "pg",'~> 1.1', platforms: [:mri]
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
gem "tiny_tds", platforms: [:mri, :mingw, :x64_mingw, :mswin]
|
16
|
+
gem "activerecord-sqlserver-adapter", '~> 6.1.0', platforms: [:mri, :mingw, :x64_mingw, :mswin]
|
17
17
|
|
18
18
|
gem 'ruby-oci8', platforms: [:mri, :mswin, :mingw] if ENV.has_key? 'ORACLE_HOME'
|
19
19
|
gem 'activerecord-oracle_enhanced-adapter', '~> 6.0.0' if ENV.has_key? 'ORACLE_HOME'
|
20
20
|
|
21
21
|
# for JRuby
|
22
|
-
gem 'activerecord-jdbc-adapter', platforms: :jruby
|
22
|
+
gem 'activerecord-jdbc-adapter', github: 'jruby/activerecord-jdbc-adapter', tag: 'v61.1', platforms: :jruby
|
23
23
|
gem "jdbc-sqlite3", platforms: :jruby
|
24
24
|
gem "activerecord-jdbcsqlite3-adapter", platforms: :jruby
|
25
25
|
gem "activerecord-jdbcmysql-adapter", platforms: :jruby
|
26
26
|
gem "activerecord-jdbcpostgresql-adapter", platforms: :jruby
|
27
|
-
gem "activerecord-jdbcmssql-adapter", platforms: :jruby
|
28
27
|
end
|
29
28
|
|
30
29
|
gemspec path: "../"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
gem 'rails', '~> 7.0.1'
|
4
|
+
|
5
|
+
|
6
|
+
group :development, :test do
|
7
|
+
gem 'activesupport', '~> 7.0.1'
|
8
|
+
gem 'activemodel', '~> 7.0.1'
|
9
|
+
gem 'activerecord', '~> 7.0.1'
|
10
|
+
|
11
|
+
gem "sqlite3", '~> 1.4', platforms: [:mri]
|
12
|
+
gem "mysql2", '0.5.2', platforms: [:mri]
|
13
|
+
gem "pg",'~> 1.1', platforms: [:mri]
|
14
|
+
|
15
|
+
gem "tiny_tds", platforms: [:mri, :mingw, :x64_mingw, :mswin]
|
16
|
+
gem "activerecord-sqlserver-adapter", '~> 7.0.0.0', platforms: [:mri, :mingw, :x64_mingw, :mswin]
|
17
|
+
|
18
|
+
gem 'ruby-oci8', platforms: [:mri, :mswin, :mingw] if ENV.has_key? 'ORACLE_HOME'
|
19
|
+
gem 'activerecord-oracle_enhanced-adapter', '~> 6.0.0' if ENV.has_key? 'ORACLE_HOME'
|
20
|
+
end
|
21
|
+
|
22
|
+
gemspec path: "../"
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'arel_extensions/aliases'
|
1
2
|
require 'arel_extensions/math'
|
2
3
|
require 'arel_extensions/comparators'
|
3
4
|
require 'arel_extensions/date_duration'
|
@@ -8,6 +9,7 @@ require 'arel_extensions/predications'
|
|
8
9
|
|
9
10
|
module ArelExtensions
|
10
11
|
module Attributes
|
12
|
+
include ArelExtensions::Aliases
|
11
13
|
include ArelExtensions::Math
|
12
14
|
include ArelExtensions::Comparators
|
13
15
|
include ArelExtensions::DateDuration
|
@@ -40,8 +40,8 @@ module ArelExtensions
|
|
40
40
|
ArelExtensions::Nodes::Duration.new "s", self
|
41
41
|
end
|
42
42
|
|
43
|
-
def format(tpl)
|
44
|
-
ArelExtensions::Nodes::Format.new [self, tpl]
|
43
|
+
def format(tpl, time_zone = nil)
|
44
|
+
ArelExtensions::Nodes::Format.new [self, tpl, time_zone]
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module ArelExtensions
|
2
|
+
|
3
|
+
#
|
4
|
+
# column_of
|
5
|
+
#
|
6
|
+
# Before the creation of these methods, getting the column name was done
|
7
|
+
# uniquely through the code found in `column_of_via_arel_table`.
|
8
|
+
#
|
9
|
+
# This turned out to be unreliable, most notably when using adapters that do
|
10
|
+
# not come with activerecord standard batteries. SQL Server is the most
|
11
|
+
# notorious example.
|
12
|
+
#
|
13
|
+
# Currently, we're using a needlessly complicated way to address this issue.
|
14
|
+
# Different versions of activerecord are behaving differently; the public APIs
|
15
|
+
# do not seem to come with any guarantees, so we need to be sure that we're
|
16
|
+
# coveing all these cases.
|
17
|
+
|
18
|
+
def self.column_of_via_arel_table(table_name, column_name)
|
19
|
+
begin
|
20
|
+
Arel::Table.engine.connection.schema_cache.columns_hash(table_name)[column_name]
|
21
|
+
rescue NoMethodError
|
22
|
+
nil
|
23
|
+
rescue Exception => e
|
24
|
+
puts "Failed to fetch column info for #{table_name}.#{column_name} ."
|
25
|
+
puts "This should never be reached."
|
26
|
+
puts "#{e.class}: #{e}"
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.column_of(table_name, column_name)
|
32
|
+
use_arel_table = !ActiveRecord::Base.connected? || \
|
33
|
+
(ActiveRecord::Base.connection.pool.respond_to?(:schema_cache) && ActiveRecord::Base.connection.pool.schema_cache.nil?)
|
34
|
+
|
35
|
+
if use_arel_table
|
36
|
+
column_of_via_arel_table(table_name, column_name)
|
37
|
+
else
|
38
|
+
if ActiveRecord::Base.connection.pool.respond_to?(:pool_config)
|
39
|
+
ActiveRecord::Base.connection.pool.pool_config.schema_cache.columns_hash(table_name)[column_name]
|
40
|
+
elsif ActiveRecord::Base.connection.pool.respond_to?(:schema_cache)
|
41
|
+
ActiveRecord::Base.connection.pool.schema_cache.columns_hash(table_name)[column_name]
|
42
|
+
else
|
43
|
+
puts ">>> We really shouldn't be here #{table_name}.#{column_name}"
|
44
|
+
column_of_via_arel_table(table_name, column_name)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/arel_extensions/math.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'arel_extensions/helpers'
|
2
|
+
|
1
3
|
require 'arel_extensions/nodes'
|
2
4
|
require 'arel_extensions/nodes/function'
|
3
5
|
require 'arel_extensions/nodes/concat'
|
@@ -38,21 +40,17 @@ module ArelExtensions
|
|
38
40
|
when Arel::Nodes::Function
|
39
41
|
Arel.grouping(Arel::Nodes::Addition.new self, other)
|
40
42
|
else
|
41
|
-
|
42
|
-
col = Arel::Table.engine.connection.schema_cache.columns_hash(self.relation.table_name)[self.name.to_s]
|
43
|
-
rescue Exception
|
44
|
-
col = nil
|
45
|
-
end
|
43
|
+
col = self.respond_to?(:relation)? ArelExtensions::column_of(self.relation.table_name, self.name.to_s) : nil
|
46
44
|
if (!col) # if the column doesn't exist in the database
|
47
|
-
Arel.grouping(Arel::Nodes::Addition.new(self, other))
|
45
|
+
Arel.grouping(Arel::Nodes::Addition.new(self, Arel::Nodes.build_quoted(other)))
|
48
46
|
else
|
49
47
|
arg = col.type
|
50
48
|
if arg == :integer || (!arg)
|
51
49
|
other = other.to_i if other.is_a?(String)
|
52
|
-
Arel.grouping(Arel::Nodes::Addition.new self, other)
|
50
|
+
Arel.grouping(Arel::Nodes::Addition.new self, Arel::Nodes.build_quoted(other))
|
53
51
|
elsif arg == :decimal || arg == :float
|
54
52
|
other = Arel.sql(other) if other.is_a?(String) # Arel should accept Float & BigDecimal!
|
55
|
-
Arel.grouping(Arel::Nodes::Addition.new self, other)
|
53
|
+
Arel.grouping(Arel::Nodes::Addition.new self, Arel::Nodes.build_quoted(other))
|
56
54
|
elsif arg == :datetime || arg == :date
|
57
55
|
ArelExtensions::Nodes::DateAdd.new [self, other]
|
58
56
|
elsif arg == :string || arg == :text
|
@@ -68,41 +66,33 @@ module ArelExtensions
|
|
68
66
|
case self
|
69
67
|
when Arel::Nodes::Grouping
|
70
68
|
if self.expr.left.is_a?(Date) || self.expr.left.is_a?(DateTime)
|
71
|
-
Arel.grouping(ArelExtensions::Nodes::DateSub.new [self, other])
|
69
|
+
Arel.grouping(ArelExtensions::Nodes::DateSub.new [self, Arel::Nodes.build_quoted(other)])
|
72
70
|
else
|
73
|
-
Arel.grouping(Arel::Nodes::Subtraction.new(self, other))
|
71
|
+
Arel.grouping(Arel::Nodes::Subtraction.new(self, Arel::Nodes.build_quoted(other)))
|
74
72
|
end
|
75
73
|
when ArelExtensions::Nodes::Function, ArelExtensions::Nodes::Case
|
76
74
|
case self.return_type
|
77
75
|
when :string, :text # ???
|
78
|
-
Arel.grouping(Arel::Nodes::Subtraction.new(self, other)) # ??
|
76
|
+
Arel.grouping(Arel::Nodes::Subtraction.new(self, Arel::Nodes.build_quoted(other))) # ??
|
79
77
|
when :integer, :decimal, :float, :number
|
80
|
-
Arel.grouping(Arel::Nodes::Subtraction.new(self, other))
|
78
|
+
Arel.grouping(Arel::Nodes::Subtraction.new(self, Arel::Nodes.build_quoted(other)))
|
81
79
|
when :date, :datetime
|
82
|
-
ArelExtensions::Nodes::DateSub.new [self, other]
|
80
|
+
ArelExtensions::Nodes::DateSub.new [self, Arel::Nodes.build_quoted(other)]
|
83
81
|
else
|
84
|
-
Arel.grouping(Arel::Nodes::Subtraction.new(self, other))
|
82
|
+
Arel.grouping(Arel::Nodes::Subtraction.new(self, Arel::Nodes.build_quoted(other)))
|
85
83
|
end
|
86
84
|
when Arel::Nodes::Function
|
87
|
-
Arel.grouping(Arel::Nodes::Subtraction.new(self, other))
|
85
|
+
Arel.grouping(Arel::Nodes::Subtraction.new(self, Arel::Nodes.build_quoted(other)))
|
88
86
|
else
|
89
|
-
|
90
|
-
col = Arel::Table.engine.connection.schema_cache.columns_hash(self.relation.table_name)[self.name.to_s]
|
91
|
-
rescue Exception
|
92
|
-
col = nil
|
93
|
-
end
|
87
|
+
col = ArelExtensions::column_of(self.relation.table_name, self.name.to_s)
|
94
88
|
if (!col) # if the column doesn't exist in the database
|
95
|
-
Arel.grouping(Arel::Nodes::Subtraction.new(self, other))
|
89
|
+
Arel.grouping(Arel::Nodes::Subtraction.new(self, Arel::Nodes.build_quoted(other)))
|
96
90
|
else
|
97
91
|
arg = col.type
|
98
92
|
if (arg == :date || arg == :datetime)
|
99
93
|
case other
|
100
94
|
when Arel::Attributes::Attribute
|
101
|
-
|
102
|
-
col2 = Arel::Table.engine.connection.schema_cache.columns_hash(other.relation.table_name)[other.name.to_s]
|
103
|
-
rescue Exception
|
104
|
-
col2 = nil
|
105
|
-
end
|
95
|
+
col2 = ArelExtensions::column_of(other.relation.table_name, other.name.to_s)
|
106
96
|
if (!col2) # if the column doesn't exist in the database
|
107
97
|
ArelExtensions::Nodes::DateSub.new [self, other]
|
108
98
|
else
|
@@ -127,7 +117,7 @@ module ArelExtensions
|
|
127
117
|
when String
|
128
118
|
Arel.grouping(Arel::Nodes::Subtraction.new(self, Arel.sql(other)))
|
129
119
|
else
|
130
|
-
Arel.grouping(Arel::Nodes::Subtraction.new(self, other))
|
120
|
+
Arel.grouping(Arel::Nodes::Subtraction.new(self, Arel::Nodes.build_quoted(other)))
|
131
121
|
end
|
132
122
|
end
|
133
123
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'arel_extensions/helpers'
|
2
|
+
|
1
3
|
module ArelExtensions
|
2
4
|
module Nodes
|
3
5
|
if Gem::Version.new(Arel::VERSION) < Gem::Version.new("7.1.0")
|
@@ -34,6 +36,7 @@ module ArelExtensions
|
|
34
36
|
include Arel::Math
|
35
37
|
include Arel::Predications
|
36
38
|
include Arel::OrderPredications
|
39
|
+
include ArelExtensions::Aliases
|
37
40
|
include ArelExtensions::Math
|
38
41
|
include ArelExtensions::Comparators
|
39
42
|
include ArelExtensions::Predications
|
@@ -56,11 +59,7 @@ module ArelExtensions
|
|
56
59
|
when Date, DateTime,Time
|
57
60
|
:datetime
|
58
61
|
when Arel::Attributes::Attribute
|
59
|
-
|
60
|
-
Arel::Table.engine.connection.schema_cache.columns_hash(obj.relation.table_name)[obj.name.to_s].type
|
61
|
-
rescue Exception
|
62
|
-
:string
|
63
|
-
end
|
62
|
+
ArelExtensions::column_of(obj.relation.table_name, obj.name.to_s)&.type || :string
|
64
63
|
else
|
65
64
|
:string
|
66
65
|
end
|
@@ -102,11 +101,7 @@ module ArelExtensions
|
|
102
101
|
alias :== :eql?
|
103
102
|
|
104
103
|
def as other
|
105
|
-
Arel::Nodes::As.new self, Arel
|
106
|
-
end
|
107
|
-
|
108
|
-
def xas other
|
109
|
-
Arel::Nodes::As.new self, Arel::Nodes::SqlLiteral.new(other)
|
104
|
+
Arel::Nodes::As.new self, Arel.sql(other)
|
110
105
|
end
|
111
106
|
end
|
112
107
|
end
|
@@ -117,7 +117,16 @@ module ArelExtensions
|
|
117
117
|
if @date_type == :date
|
118
118
|
v.to_i / (24*3600)
|
119
119
|
elsif @date_type == :datetime
|
120
|
-
v.
|
120
|
+
if v.parts.size == 1
|
121
|
+
# first entry in the dict v.parts; one of [:years, :months, :weeks, :days, :hours, :minutes, :seconds]
|
122
|
+
# | the value
|
123
|
+
# | |
|
124
|
+
# | |
|
125
|
+
# v v
|
126
|
+
v.parts.first.second
|
127
|
+
else
|
128
|
+
v.to_i
|
129
|
+
end
|
121
130
|
end
|
122
131
|
else
|
123
132
|
v
|
@@ -130,7 +139,17 @@ module ArelExtensions
|
|
130
139
|
if @date_type == :date
|
131
140
|
Arel.sql('day')
|
132
141
|
elsif @date_type == :datetime
|
133
|
-
|
142
|
+
res = if v.parts.size == 1
|
143
|
+
# first entry in the dict v.parts; one of [:years, :months, :weeks, :days, :hours, :minutes, :seconds]
|
144
|
+
# | the key
|
145
|
+
# | | convert symbol to string
|
146
|
+
# | | | remove the plural suffix `s`
|
147
|
+
# v v v v
|
148
|
+
v.parts.first.first.to_s[0..-2]
|
149
|
+
else
|
150
|
+
'second'
|
151
|
+
end
|
152
|
+
Arel.sql(res)
|
134
153
|
end
|
135
154
|
else
|
136
155
|
if ArelExtensions::Nodes::Duration === v
|
@@ -141,9 +160,9 @@ module ArelExtensions
|
|
141
160
|
when 'h','mn','s'
|
142
161
|
Arel.sql('second')
|
143
162
|
when /i\z/
|
144
|
-
Arel.sql(
|
163
|
+
Arel.sql(ArelExtensions::Visitors::MSSQL::LOADED_VISITOR::DATE_MAPPING[v.left[0..-2]])
|
145
164
|
else
|
146
|
-
Arel.sql(
|
165
|
+
Arel.sql(ArelExtensions::Visitors::MSSQL::LOADED_VISITOR::DATE_MAPPING[v.left])
|
147
166
|
end
|
148
167
|
end
|
149
168
|
end
|
@@ -5,11 +5,12 @@ module ArelExtensions
|
|
5
5
|
class Format < Function
|
6
6
|
RETURN_TYPE = :string
|
7
7
|
|
8
|
-
attr_accessor :col_type, :iso_format
|
8
|
+
attr_accessor :col_type, :iso_format, :time_zone
|
9
9
|
|
10
10
|
def initialize expr
|
11
|
-
col = expr
|
11
|
+
col = expr[0]
|
12
12
|
@iso_format = convert_format(expr[1])
|
13
|
+
@time_zone = expr[2]
|
13
14
|
@col_type = type_of_attribute(col)
|
14
15
|
super [col, convert_to_string_node(@iso_format)]
|
15
16
|
end
|
@@ -51,13 +51,7 @@ module ArelExtensions
|
|
51
51
|
def type_of_attribute(att)
|
52
52
|
case att
|
53
53
|
when Arel::Attributes::Attribute
|
54
|
-
|
55
|
-
if Arel::Table.engine.connection.tables.include? att.relation.table_name
|
56
|
-
Arel::Table.engine.connection.schema_cache.columns_hash(att.relation.table_name)[att.name.to_s].type
|
57
|
-
end
|
58
|
-
rescue
|
59
|
-
att
|
60
|
-
end
|
54
|
+
ArelExtensions::column_of(att.relation.table_name, att.name.to_s)&.type || att
|
61
55
|
when ArelExtensions::Nodes::Function
|
62
56
|
att.return_type
|
63
57
|
# else
|