arel 6.0.4 → 7.1.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|