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
|
module Arel
class Relation
def session
Session.new
end
# INVESTIGATE
def name_for(relation)
relation.name
end
def to_sql(formatter = Sql::SelectStatement.new(self))
formatter.select [
"SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) }.join(', ')}",
"FROM #{table_sql(Sql::TableReference.new(self))}",
(joins(self) unless joins(self).blank? ),
("WHERE #{selects.collect { |s| s.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless selects.blank? ),
("ORDER BY #{orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ),
("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank? ),
("LIMIT #{taken}" unless taken.blank? ),
("OFFSET #{skipped}" unless skipped.blank? )
].compact.join("\n"), name
end
alias_method :to_s, :to_sql
def inclusion_predicate_sql
"IN"
end
def call(connection = engine.connection)
results = connection.execute(to_sql)
rows = []
results.each do |row|
rows << attributes.zip(row).to_hash
end
rows
end
def bind(relation)
self
end
def christener
@christener ||= Sql::Christener.new
end
def aggregation?
false
end
module Enumerable
include ::Enumerable
def each(&block)
session.read(self).each(&block)
end
def first
session.read(self).first
end
end
include Enumerable
module Operable
def join(other = nil, join_type = "INNER JOIN")
case other
when String
Join.new(other, self)
when Relation
JoinOperation.new(join_type, self, other)
else
self
end
end
def outer_join(other = nil)
join(other, "LEFT OUTER JOIN")
end
def select(*predicates)
predicates.all?(&:blank?) ? self : Selection.new(self, *predicates)
end
def project(*attributes)
attributes.all?(&:blank?) ? self : Projection.new(self, *attributes)
end
def alias
Alias.new(self)
end
def order(*attributes)
attributes.all?(&:blank?) ? self : Order.new(self, *attributes)
end
def take(taken = nil)
taken.blank?? self : Take.new(self, taken)
end
def skip(skipped = nil)
skipped.blank?? self : Skip.new(self, skipped)
end
def group(*groupings)
groupings.all?(&:blank?) ? self : Grouping.new(self, *groupings)
end
module Writable
def insert(record)
session.create Insertion.new(self, record); self
end
def update(assignments)
session.update Update.new(self, assignments); self
end
def delete
session.delete Deletion.new(self); self
end
end
include Writable
JoinOperation = Struct.new(:join_sql, :relation1, :relation2) do
def on(*predicates)
Join.new(join_sql, relation1, relation2, *predicates)
end
end
end
include Operable
module AttributeAccessable
def [](index)
case index
when Symbol, String
attribute_for_name(index)
when Attribute, Expression
attribute_for_attribute(index)
when Array
index.collect { |i| self[i] }
end
end
def attribute_for_name(name)
attributes.detect { |a| a.alias_or_name.to_s == name.to_s }
end
def attribute_for_attribute(attribute)
attributes.select { |a| a =~ attribute }.min do |a1, a2|
(attribute % a1).size <=> (attribute % a2).size
end
end
end
include AttributeAccessable
module DefaultOperations
def attributes; [] end
def selects; [] end
def orders; [] end
def inserts; [] end
def groupings; [] end
def joins(formatter = nil); nil end
def taken; nil end
def skipped; nil end
end
include DefaultOperations
end
end
|