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
|
module Arel
class Relation
attr_reader :count
def session
Session.new
end
def call
engine.read(self)
end
def bind(relation)
self
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_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
[:where, :project, :order, :take, :skip, :group, :from].each do |operation_name|
class_eval <<-OPERATION, __FILE__, __LINE__
def #{operation_name}(*arguments, &block)
arguments.all?(&:blank?) && !block_given?? self : #{operation_name.to_s.classify}.new(self, *arguments, &block)
end
OPERATION
end
def lock(locking = nil)
Lock.new(self, locking)
end
def alias
Alias.new(self)
end
module Writable
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
end
include Writable
JoinOperation = Struct.new(:join_class, :relation1, :relation2) do
def on(*predicates)
join_class.new(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
# TESTME
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
def position_of(attribute)
(@position_of ||= Hash.new do |h, attribute|
h[attribute] = attributes.index(self[attribute])
end)[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
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 # FIXME
def taken; nil end
def skipped; nil end
def sources; [] end
def locked; [] end
end
include DefaultOperations
end
end
|