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
|
module Arel
class Relation
def session
Session.new
end
def to_sql(formatter = Sql::SelectStatement.new(self))
formatter.select select_sql, self
end
alias_method :to_s, :to_sql
def select_sql
[
"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 #{wheres .collect { |w| w.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless wheres.blank? ),
("ORDER BY #{orders .collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ),
("GROUP BY #{groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) }.join(', ')}" unless groupings.blank? ),
("LIMIT #{taken}" unless taken.blank? ),
("OFFSET #{skipped}" unless skipped.blank? )
].compact.join("\n")
end
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 root
self
end
def christener
@christener ||= Sql::Christener.new
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_relation = nil, join_type = "INNER JOIN")
case other_relation
when String
Join.new(other_relation, self)
when Relation
JoinOperation.new(join_type, self, other_relation)
else
self
end
end
def outer_join(other_relation = nil)
join(other_relation, "LEFT OUTER JOIN")
end
[:where, :project, :order, :take, :skip, :group].each do |operation_name|
operation = <<-OPERATION
def #{operation_name}(*arguments, &block)
arguments.all?(&:blank?) && !block_given?? self : #{operation_name.to_s.classify}.new(self, *arguments, &block)
end
OPERATION
class_eval operation, __FILE__, __LINE__
end
def alias
Alias.new(self)
end
module Writable
def insert(record)
session.create Insert.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
find_attribute_matching_name(index)
when Attribute, Expression
find_attribute_matching_attribute(index)
when Array
index.collect { |i| self[i] }
end
end
def find_attribute_matching_name(name)
attributes.detect { |a| a.named?(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
private
def matching_attributes(attribute)
(@matching_attributes ||= attributes.inject({}) do |hash, a|
(hash[a.root] ||= []) << a
hash
end)[attribute.root] || []
end
def has_attribute?(attribute)
!matching_attributes(attribute).empty?
end
end
include AttributeAccessable
module DefaultOperations
def attributes; [] end
def wheres; [] 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
|