arel 6.0.4 → 7.1.4
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/History.txt +31 -12
- data/MIT-LICENSE.txt +2 -1
- data/{README.markdown → README.md} +88 -31
- data/lib/arel.rb +1 -1
- data/lib/arel/attributes/attribute.rb +8 -0
- data/lib/arel/crud.rb +4 -3
- data/lib/arel/delete_manager.rb +6 -1
- data/lib/arel/insert_manager.rb +1 -1
- data/lib/arel/math.rb +24 -0
- data/lib/arel/nodes.rb +6 -38
- data/lib/arel/nodes/binary.rb +0 -2
- data/lib/arel/nodes/bind_param.rb +3 -0
- data/lib/arel/nodes/case.rb +57 -0
- data/lib/arel/nodes/casted.rb +44 -0
- data/lib/arel/nodes/delete_statement.rb +2 -0
- data/lib/arel/nodes/infix_operation.rb +36 -1
- data/lib/arel/nodes/matches.rb +3 -1
- data/lib/arel/nodes/regexp.rb +14 -0
- data/lib/arel/nodes/select_core.rb +5 -5
- data/lib/arel/nodes/table_alias.rb +6 -2
- data/lib/arel/nodes/unary.rb +6 -3
- data/lib/arel/nodes/unary_operation.rb +25 -0
- data/lib/arel/predications.rb +38 -14
- data/lib/arel/select_manager.rb +6 -6
- data/lib/arel/table.rb +34 -59
- data/lib/arel/tree_manager.rb +3 -8
- data/lib/arel/update_manager.rb +1 -1
- data/lib/arel/visitors.rb +1 -23
- data/lib/arel/visitors/depth_first.rb +14 -2
- data/lib/arel/visitors/dot.rb +12 -1
- data/lib/arel/visitors/informix.rb +6 -1
- data/lib/arel/visitors/mssql.rb +35 -3
- data/lib/arel/visitors/mysql.rb +8 -0
- data/lib/arel/visitors/oracle.rb +13 -2
- data/lib/arel/visitors/oracle12.rb +59 -0
- data/lib/arel/visitors/postgresql.rb +56 -4
- data/lib/arel/visitors/sqlite.rb +9 -0
- data/lib/arel/visitors/to_sql.rb +94 -52
- data/lib/arel/visitors/where_sql.rb +10 -1
- metadata +11 -6
data/lib/arel/table.rb
CHANGED
@@ -6,54 +6,35 @@ module Arel
|
|
6
6
|
@engine = nil
|
7
7
|
class << self; attr_accessor :engine; end
|
8
8
|
|
9
|
-
attr_accessor :name, :
|
9
|
+
attr_accessor :name, :table_alias
|
10
10
|
|
11
11
|
# TableAlias and Table both have a #table_name which is the name of the underlying table
|
12
12
|
alias :table_name :name
|
13
13
|
|
14
|
-
def initialize
|
14
|
+
def initialize(name, as: nil, type_caster: nil)
|
15
15
|
@name = name.to_s
|
16
|
-
@engine = engine
|
17
16
|
@columns = nil
|
18
|
-
@
|
19
|
-
@table_alias = nil
|
20
|
-
@primary_key = nil
|
17
|
+
@type_caster = type_caster
|
21
18
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
# TableAlias node?
|
28
|
-
@table_alias = engine[:as] unless engine[:as].to_s == @name
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def primary_key
|
33
|
-
if $VERBOSE
|
34
|
-
warn <<-eowarn
|
35
|
-
primary_key (#{caller.first}) is deprecated and will be removed in Arel 4.0.0
|
36
|
-
eowarn
|
37
|
-
end
|
38
|
-
@primary_key ||= begin
|
39
|
-
primary_key_name = @engine.connection.primary_key(name)
|
40
|
-
# some tables might be without primary key
|
41
|
-
primary_key_name && self[primary_key_name]
|
19
|
+
# Sometime AR sends an :as parameter to table, to let the table know
|
20
|
+
# that it is an Alias. We may want to override new, and return a
|
21
|
+
# TableAlias node?
|
22
|
+
if as.to_s == @name
|
23
|
+
as = nil
|
42
24
|
end
|
25
|
+
@table_alias = as
|
43
26
|
end
|
44
27
|
|
45
28
|
def alias name = "#{self.name}_2"
|
46
|
-
Nodes::TableAlias.new(self, name)
|
47
|
-
@aliases << node
|
48
|
-
end
|
29
|
+
Nodes::TableAlias.new(self, name)
|
49
30
|
end
|
50
31
|
|
51
|
-
def from
|
52
|
-
SelectManager.new(
|
32
|
+
def from
|
33
|
+
SelectManager.new(self)
|
53
34
|
end
|
54
35
|
|
55
36
|
def join relation, klass = Nodes::InnerJoin
|
56
|
-
return from
|
37
|
+
return from unless relation
|
57
38
|
|
58
39
|
case relation
|
59
40
|
when String, Nodes::SqlLiteral
|
@@ -61,7 +42,7 @@ primary_key (#{caller.first}) is deprecated and will be removed in Arel 4.0.0
|
|
61
42
|
klass = Nodes::StringJoin
|
62
43
|
end
|
63
44
|
|
64
|
-
from
|
45
|
+
from.join(relation, klass)
|
65
46
|
end
|
66
47
|
|
67
48
|
def outer_join relation
|
@@ -69,55 +50,39 @@ primary_key (#{caller.first}) is deprecated and will be removed in Arel 4.0.0
|
|
69
50
|
end
|
70
51
|
|
71
52
|
def group *columns
|
72
|
-
from
|
53
|
+
from.group(*columns)
|
73
54
|
end
|
74
55
|
|
75
56
|
def order *expr
|
76
|
-
from
|
57
|
+
from.order(*expr)
|
77
58
|
end
|
78
59
|
|
79
60
|
def where condition
|
80
|
-
from
|
61
|
+
from.where condition
|
81
62
|
end
|
82
63
|
|
83
64
|
def project *things
|
84
|
-
from
|
65
|
+
from.project(*things)
|
85
66
|
end
|
86
67
|
|
87
68
|
def take amount
|
88
|
-
from
|
69
|
+
from.take amount
|
89
70
|
end
|
90
71
|
|
91
72
|
def skip amount
|
92
|
-
from
|
73
|
+
from.skip amount
|
93
74
|
end
|
94
75
|
|
95
76
|
def having expr
|
96
|
-
from
|
77
|
+
from.having expr
|
97
78
|
end
|
98
79
|
|
99
80
|
def [] name
|
100
81
|
::Arel::Attribute.new self, name
|
101
82
|
end
|
102
83
|
|
103
|
-
def select_manager
|
104
|
-
SelectManager.new(@engine)
|
105
|
-
end
|
106
|
-
|
107
|
-
def insert_manager
|
108
|
-
InsertManager.new(@engine)
|
109
|
-
end
|
110
|
-
|
111
|
-
def update_manager
|
112
|
-
UpdateManager.new(@engine)
|
113
|
-
end
|
114
|
-
|
115
|
-
def delete_manager
|
116
|
-
DeleteManager.new(@engine)
|
117
|
-
end
|
118
|
-
|
119
84
|
def hash
|
120
|
-
# Perf note: aliases
|
85
|
+
# Perf note: aliases and table alias is excluded from the hash
|
121
86
|
# aliases can have a loop back to this table breaking hashes in parent
|
122
87
|
# relations, for the vast majority of cases @name is unique to a query
|
123
88
|
@name.hash
|
@@ -126,12 +91,22 @@ primary_key (#{caller.first}) is deprecated and will be removed in Arel 4.0.0
|
|
126
91
|
def eql? other
|
127
92
|
self.class == other.class &&
|
128
93
|
self.name == other.name &&
|
129
|
-
self.engine == other.engine &&
|
130
|
-
self.aliases == other.aliases &&
|
131
94
|
self.table_alias == other.table_alias
|
132
95
|
end
|
133
96
|
alias :== :eql?
|
134
97
|
|
98
|
+
def type_cast_for_database(attribute_name, value)
|
99
|
+
type_caster.type_cast_for_database(attribute_name, value)
|
100
|
+
end
|
101
|
+
|
102
|
+
def able_to_type_cast?
|
103
|
+
!type_caster.nil?
|
104
|
+
end
|
105
|
+
|
106
|
+
protected
|
107
|
+
|
108
|
+
attr_reader :type_caster
|
109
|
+
|
135
110
|
private
|
136
111
|
|
137
112
|
def attributes_for columns
|
data/lib/arel/tree_manager.rb
CHANGED
@@ -8,8 +8,7 @@ module Arel
|
|
8
8
|
|
9
9
|
attr_accessor :bind_values
|
10
10
|
|
11
|
-
def initialize
|
12
|
-
@engine = engine
|
11
|
+
def initialize
|
13
12
|
@ctx = nil
|
14
13
|
@bind_values = []
|
15
14
|
end
|
@@ -20,13 +19,9 @@ module Arel
|
|
20
19
|
collector.value
|
21
20
|
end
|
22
21
|
|
23
|
-
def
|
24
|
-
engine.connection.visitor
|
25
|
-
end
|
26
|
-
|
27
|
-
def to_sql
|
22
|
+
def to_sql engine = Table.engine
|
28
23
|
collector = Arel::Collectors::SQLString.new
|
29
|
-
collector = visitor.accept @ast, collector
|
24
|
+
collector = engine.connection.visitor.accept @ast, collector
|
30
25
|
collector.value
|
31
26
|
end
|
32
27
|
|
data/lib/arel/update_manager.rb
CHANGED
data/lib/arel/visitors.rb
CHANGED
@@ -6,6 +6,7 @@ require 'arel/visitors/postgresql'
|
|
6
6
|
require 'arel/visitors/mysql'
|
7
7
|
require 'arel/visitors/mssql'
|
8
8
|
require 'arel/visitors/oracle'
|
9
|
+
require 'arel/visitors/oracle12'
|
9
10
|
require 'arel/visitors/where_sql'
|
10
11
|
require 'arel/visitors/dot'
|
11
12
|
require 'arel/visitors/ibm_db'
|
@@ -13,28 +14,5 @@ require 'arel/visitors/informix'
|
|
13
14
|
|
14
15
|
module Arel
|
15
16
|
module Visitors
|
16
|
-
VISITORS = {
|
17
|
-
'postgresql' => Arel::Visitors::PostgreSQL,
|
18
|
-
'mysql' => Arel::Visitors::MySQL,
|
19
|
-
'mysql2' => Arel::Visitors::MySQL,
|
20
|
-
'mssql' => Arel::Visitors::MSSQL,
|
21
|
-
'sqlserver' => Arel::Visitors::MSSQL,
|
22
|
-
'oracle_enhanced' => Arel::Visitors::Oracle,
|
23
|
-
'sqlite' => Arel::Visitors::SQLite,
|
24
|
-
'sqlite3' => Arel::Visitors::SQLite,
|
25
|
-
'ibm_db' => Arel::Visitors::IBM_DB,
|
26
|
-
'informix' => Arel::Visitors::Informix,
|
27
|
-
}
|
28
|
-
|
29
|
-
ENGINE_VISITORS = Hash.new do |hash, engine|
|
30
|
-
pool = engine.connection_pool
|
31
|
-
adapter = pool.spec.config[:adapter]
|
32
|
-
hash[engine] = (VISITORS[adapter] || Visitors::ToSql).new(engine)
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.visitor_for engine
|
36
|
-
ENGINE_VISITORS[engine]
|
37
|
-
end
|
38
|
-
class << self; alias :for :visitor_for; end
|
39
17
|
end
|
40
18
|
end
|
@@ -16,7 +16,12 @@ module Arel
|
|
16
16
|
def unary o
|
17
17
|
visit o.expr
|
18
18
|
end
|
19
|
+
alias :visit_Arel_Nodes_Else :unary
|
19
20
|
alias :visit_Arel_Nodes_Group :unary
|
21
|
+
alias :visit_Arel_Nodes_Cube :unary
|
22
|
+
alias :visit_Arel_Nodes_RollUp :unary
|
23
|
+
alias :visit_Arel_Nodes_GroupingSet :unary
|
24
|
+
alias :visit_Arel_Nodes_GroupingElement :unary
|
20
25
|
alias :visit_Arel_Nodes_Grouping :unary
|
21
26
|
alias :visit_Arel_Nodes_Having :unary
|
22
27
|
alias :visit_Arel_Nodes_Limit :unary
|
@@ -53,6 +58,12 @@ module Arel
|
|
53
58
|
visit o.distinct
|
54
59
|
end
|
55
60
|
|
61
|
+
def visit_Arel_Nodes_Case o
|
62
|
+
visit o.case
|
63
|
+
visit o.conditions
|
64
|
+
visit o.default
|
65
|
+
end
|
66
|
+
|
56
67
|
def nary o
|
57
68
|
o.children.each { |child| visit child}
|
58
69
|
end
|
@@ -65,6 +76,7 @@ module Arel
|
|
65
76
|
alias :visit_Arel_Nodes_As :binary
|
66
77
|
alias :visit_Arel_Nodes_Assignment :binary
|
67
78
|
alias :visit_Arel_Nodes_Between :binary
|
79
|
+
alias :visit_Arel_Nodes_Concat :binary
|
68
80
|
alias :visit_Arel_Nodes_DeleteStatement :binary
|
69
81
|
alias :visit_Arel_Nodes_DoesNotMatch :binary
|
70
82
|
alias :visit_Arel_Nodes_Equality :binary
|
@@ -87,7 +99,7 @@ module Arel
|
|
87
99
|
alias :visit_Arel_Nodes_RightOuterJoin :binary
|
88
100
|
alias :visit_Arel_Nodes_TableAlias :binary
|
89
101
|
alias :visit_Arel_Nodes_Values :binary
|
90
|
-
alias :
|
102
|
+
alias :visit_Arel_Nodes_When :binary
|
91
103
|
|
92
104
|
def visit_Arel_Nodes_StringJoin o
|
93
105
|
visit o.left
|
@@ -147,7 +159,7 @@ module Arel
|
|
147
159
|
visit o.wheres
|
148
160
|
visit o.groups
|
149
161
|
visit o.windows
|
150
|
-
visit o.
|
162
|
+
visit o.havings
|
151
163
|
end
|
152
164
|
|
153
165
|
def visit_Arel_Nodes_SelectStatement o
|
data/lib/arel/visitors/dot.rb
CHANGED
@@ -69,6 +69,10 @@ module Arel
|
|
69
69
|
visit_edge o, "expr"
|
70
70
|
end
|
71
71
|
alias :visit_Arel_Nodes_Group :unary
|
72
|
+
alias :visit_Arel_Nodes_Cube :unary
|
73
|
+
alias :visit_Arel_Nodes_RollUp :unary
|
74
|
+
alias :visit_Arel_Nodes_GroupingSet :unary
|
75
|
+
alias :visit_Arel_Nodes_GroupingElement :unary
|
72
76
|
alias :visit_Arel_Nodes_Grouping :unary
|
73
77
|
alias :visit_Arel_Nodes_Having :unary
|
74
78
|
alias :visit_Arel_Nodes_Limit :unary
|
@@ -151,6 +155,11 @@ module Arel
|
|
151
155
|
visit_edge o, "name"
|
152
156
|
end
|
153
157
|
|
158
|
+
def visit_Arel_Nodes_Casted o
|
159
|
+
visit_edge o, 'val'
|
160
|
+
visit_edge o, 'attribute'
|
161
|
+
end
|
162
|
+
|
154
163
|
def visit_Arel_Attribute o
|
155
164
|
visit_edge o, "relation"
|
156
165
|
visit_edge o, "name"
|
@@ -176,6 +185,7 @@ module Arel
|
|
176
185
|
alias :visit_Arel_Nodes_As :binary
|
177
186
|
alias :visit_Arel_Nodes_Assignment :binary
|
178
187
|
alias :visit_Arel_Nodes_Between :binary
|
188
|
+
alias :visit_Arel_Nodes_Concat :binary
|
179
189
|
alias :visit_Arel_Nodes_DoesNotMatch :binary
|
180
190
|
alias :visit_Arel_Nodes_Equality :binary
|
181
191
|
alias :visit_Arel_Nodes_GreaterThan :binary
|
@@ -199,7 +209,6 @@ module Arel
|
|
199
209
|
alias :visit_NilClass :visit_String
|
200
210
|
alias :visit_TrueClass :visit_String
|
201
211
|
alias :visit_FalseClass :visit_String
|
202
|
-
alias :visit_Arel_Nodes_BindParam :visit_String
|
203
212
|
alias :visit_Integer :visit_String
|
204
213
|
alias :visit_Fixnum :visit_String
|
205
214
|
alias :visit_BigDecimal :visit_String
|
@@ -207,6 +216,8 @@ module Arel
|
|
207
216
|
alias :visit_Symbol :visit_String
|
208
217
|
alias :visit_Arel_Nodes_SqlLiteral :visit_String
|
209
218
|
|
219
|
+
def visit_Arel_Nodes_BindParam o; end
|
220
|
+
|
210
221
|
def visit_Hash o
|
211
222
|
o.each_with_index do |pair, i|
|
212
223
|
edge("pair_#{i}") { visit pair }
|
@@ -34,8 +34,13 @@ module Arel
|
|
34
34
|
collector = inject_join o.groups, collector, ", "
|
35
35
|
end
|
36
36
|
|
37
|
-
|
37
|
+
if o.havings.any?
|
38
|
+
collector << " HAVING "
|
39
|
+
collector = inject_join o.havings, collector, " AND "
|
40
|
+
end
|
41
|
+
collector
|
38
42
|
end
|
43
|
+
|
39
44
|
def visit_Arel_Nodes_Offset o, collector
|
40
45
|
collector << "SKIP "
|
41
46
|
visit o.expr, collector
|
data/lib/arel/visitors/mssql.rb
CHANGED
@@ -3,6 +3,11 @@ module Arel
|
|
3
3
|
class MSSQL < Arel::Visitors::ToSql
|
4
4
|
RowNumber = Struct.new :children
|
5
5
|
|
6
|
+
def initialize(*)
|
7
|
+
@primary_keys = {}
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
6
11
|
private
|
7
12
|
|
8
13
|
# `top` wouldn't really work here. I.e. User.select("distinct first_name").limit(10) would generate
|
@@ -61,6 +66,23 @@ module Arel
|
|
61
66
|
end
|
62
67
|
end
|
63
68
|
|
69
|
+
def visit_Arel_Nodes_DeleteStatement o, collector
|
70
|
+
collector << 'DELETE '
|
71
|
+
if o.limit
|
72
|
+
collector << 'TOP ('
|
73
|
+
visit o.limit.expr, collector
|
74
|
+
collector << ') '
|
75
|
+
end
|
76
|
+
collector << 'FROM '
|
77
|
+
collector = visit o.relation, collector
|
78
|
+
if o.wheres.any?
|
79
|
+
collector << ' WHERE '
|
80
|
+
inject_join o.wheres, collector, AND
|
81
|
+
else
|
82
|
+
collector
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
64
86
|
def determine_order_by orders, x
|
65
87
|
if orders.any?
|
66
88
|
orders
|
@@ -81,10 +103,20 @@ module Arel
|
|
81
103
|
end
|
82
104
|
|
83
105
|
# FIXME raise exception of there is no pk?
|
84
|
-
# FIXME!! Table.primary_key will be deprecated. What is the replacement??
|
85
106
|
def find_left_table_pk o
|
86
|
-
|
87
|
-
|
107
|
+
if o.kind_of?(Arel::Nodes::Join)
|
108
|
+
find_left_table_pk(o.left)
|
109
|
+
elsif o.instance_of?(Arel::Table)
|
110
|
+
find_primary_key(o)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def find_primary_key(o)
|
115
|
+
@primary_keys[o.name] ||= begin
|
116
|
+
primary_key_name = @connection.primary_key(o.name)
|
117
|
+
# some tables might be without primary key
|
118
|
+
primary_key_name && o[primary_key_name]
|
119
|
+
end
|
88
120
|
end
|
89
121
|
end
|
90
122
|
end
|
data/lib/arel/visitors/mysql.rb
CHANGED
@@ -72,6 +72,14 @@ module Arel
|
|
72
72
|
maybe_visit o.limit, collector
|
73
73
|
end
|
74
74
|
|
75
|
+
def visit_Arel_Nodes_Concat o, collector
|
76
|
+
collector << " CONCAT("
|
77
|
+
visit o.left, collector
|
78
|
+
collector << ", "
|
79
|
+
visit o.right, collector
|
80
|
+
collector << ") "
|
81
|
+
collector
|
82
|
+
end
|
75
83
|
end
|
76
84
|
end
|
77
85
|
end
|
data/lib/arel/visitors/oracle.rb
CHANGED
@@ -26,11 +26,22 @@ module Arel
|
|
26
26
|
FROM ("
|
27
27
|
|
28
28
|
collector = super(o, collector)
|
29
|
-
|
29
|
+
|
30
|
+
if offset.expr.is_a? Nodes::BindParam
|
31
|
+
offset_bind = nil
|
32
|
+
collector << ') raw_sql_ WHERE rownum <= ('
|
33
|
+
collector.add_bind(offset.expr) { |i| offset_bind = ":a#{i}" }
|
34
|
+
collector << ' + '
|
35
|
+
collector.add_bind(limit) { |i| ":a#{i}" }
|
36
|
+
collector << ") ) WHERE raw_rnum_ > #{offset_bind}"
|
37
|
+
return collector
|
38
|
+
else
|
39
|
+
collector << ") raw_sql_
|
30
40
|
WHERE rownum <= #{offset.expr.to_i + limit}
|
31
41
|
)
|
32
42
|
WHERE "
|
33
|
-
|
43
|
+
return visit(offset, collector)
|
44
|
+
end
|
34
45
|
end
|
35
46
|
|
36
47
|
if o.limit
|