1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
|
module Arel
module Relation
include Enumerable
@@connection_tables_primary_keys = {}
attr_reader :count
def session
Session.instance
end
def join?
false
end
def call
engine.read(self)
end
def bind(relation)
self
end
def externalize
@externalized ||= externalizable?? Externalization.new(self) : self
end
def externalizable?
false
end
def compiler
@compiler ||= begin
Arel::SqlCompiler.const_get("#{engine.adapter_name}Compiler").new(self)
rescue
Arel::SqlCompiler::GenericCompiler.new(self)
end
end
def to_sql(formatter = nil)
sql = compiler.select_sql
return sql unless formatter
formatter.select sql, self
end
def christener
@christener ||= Sql::Christener.new
end
def inclusion_predicate_sql
"IN"
end
def exclusion_predicate_sql
"NOT IN"
end
def primary_key
connection_id = engine.connection.object_id
if @@connection_tables_primary_keys[connection_id] && @@connection_tables_primary_keys[connection_id].has_key?(table.name)
@@connection_tables_primary_keys[connection_id][table.name]
else
@@connection_tables_primary_keys[connection_id] ||= {}
@@connection_tables_primary_keys[connection_id][table.name] = engine.connection.primary_key(table.name)
end
end
def select_clauses
attributes.map { |a|
case a
when Value
a.value
else
a.to_sql(Sql::SelectClause.new(self))
end
}
end
def from_clauses
sources.empty? ? table_sql : sources
end
def where_clauses
wheres.collect { |w|
case w
when Value
w.value
else # FIXME: why do we have to pass in a whereclause?
w.to_sql(Sql::WhereClause.new(self))
end
}
end
def group_clauses
groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) }
end
def having_clauses
havings.collect { |g| g.to_sql(Sql::HavingClause.new(self)) }
end
def order_clauses
orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) }
end
def each
session.read(self).each { |e| yield e }
end
module Operable
def join(other_relation = nil, join_class = InnerJoin)
case other_relation
when String
StringJoin.new(self, other_relation)
when Relation
JoinOperation.new(join_class, self, other_relation)
else
self
end
end
def outer_join(other_relation = nil)
join(other_relation, OuterJoin)
end
%w{
having group order project
}.each do |op|
class_eval <<-OPERATION, __FILE__, __LINE__
def #{op}(*args)
args.all? { |x| x.blank? } ? self : #{op.capitalize}.new(self, args)
end
OPERATION
end
def where clause = nil
clause ? Where.new(self, [clause]) : self
end
def skip thing = nil
thing ? Skip.new(self, thing) : self
end
def take thing
Take.new self, thing
end
def from thing
From.new self, thing
end
def lock(locking = nil)
Lock.new(self, locking)
end
def alias
Alias.new(self)
end
def insert(record)
session.create Insert.new(self, record)
end
def update(assignments)
session.update Update.new(self, assignments)
end
def delete
session.delete Deletion.new(self)
end
JoinOperation = Struct.new(:join_class, :relation1, :relation2) do
def on(*predicates)
join_class.new(relation1, relation2, *predicates)
end
end
end
include Operable
def [](index)
attributes[index]
end
def find_attribute_matching_name(name)
attributes.detect { |a| a.named?(name) } || Attribute.new(self, name)
end
def find_attribute_matching_attribute(attribute)
matching_attributes(attribute).max do |a1, a2|
(a1.original_attribute / attribute) <=> (a2.original_attribute / attribute)
end
end
def position_of(attribute)
@position_of ||= {}
return @position_of[attribute] if @position_of.key? attribute
@position_of[attribute] = attributes.index(attributes[attribute])
end
private
def matching_attributes(attribute)
(@matching_attributes ||= attributes.inject({}) do |hash, a|
(hash[a.is_a?(Value) ? a.value : a.root] ||= []) << a
hash
end)[attribute.root] || []
end
def has_attribute?(attribute)
!matching_attributes(attribute).empty?
end
module DefaultOperations
def attributes; Header.new end
def projections; [] end
def wheres; [] end
def orders; [] end
def inserts; [] end
def groupings; [] end
def havings; [] end
def joins(formatter = nil); nil end # FIXME
def taken; nil end
def skipped; nil end
def sources; [] end
def locked; [] end
end
include DefaultOperations
end
end
|