arel 0.4.0 → 1.0.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +24 -0
- data/lib/arel.rb +3 -1
- data/lib/arel/algebra/attributes/attribute.rb +175 -141
- data/lib/arel/algebra/core_extensions.rb +0 -1
- data/lib/arel/algebra/core_extensions/hash.rb +5 -9
- data/lib/arel/algebra/core_extensions/object.rb +0 -4
- data/lib/arel/algebra/expression.rb +37 -24
- data/lib/arel/algebra/header.rb +5 -6
- data/lib/arel/algebra/ordering.rb +13 -5
- data/lib/arel/algebra/predicates.rb +143 -27
- data/lib/arel/algebra/relations.rb +0 -1
- data/lib/arel/algebra/relations/operations/from.rb +10 -2
- data/lib/arel/algebra/relations/operations/group.rb +8 -6
- data/lib/arel/algebra/relations/operations/having.rb +3 -6
- data/lib/arel/algebra/relations/operations/join.rb +52 -18
- data/lib/arel/algebra/relations/operations/lock.rb +4 -6
- data/lib/arel/algebra/relations/operations/order.rb +11 -7
- data/lib/arel/algebra/relations/operations/project.rb +10 -10
- data/lib/arel/algebra/relations/operations/skip.rb +10 -3
- data/lib/arel/algebra/relations/operations/take.rb +10 -3
- data/lib/arel/algebra/relations/operations/where.rb +12 -6
- data/lib/arel/algebra/relations/relation.rb +161 -92
- data/lib/arel/algebra/relations/row.rb +8 -5
- data/lib/arel/algebra/relations/utilities/compound.rb +34 -33
- data/lib/arel/algebra/relations/utilities/externalization.rb +10 -8
- data/lib/arel/algebra/relations/writes.rb +24 -13
- data/lib/arel/algebra/value.rb +41 -2
- data/lib/arel/engines/memory.rb +0 -2
- data/lib/arel/engines/memory/engine.rb +3 -9
- data/lib/arel/engines/memory/relations.rb +0 -3
- data/lib/arel/engines/memory/relations/array.rb +5 -3
- data/lib/arel/engines/memory/relations/operations.rb +2 -60
- data/lib/arel/engines/sql.rb +0 -2
- data/lib/arel/engines/sql/christener.rb +12 -6
- data/lib/arel/engines/sql/compilers/oracle_compiler.rb +34 -23
- data/lib/arel/engines/sql/compilers/postgresql_compiler.rb +23 -15
- data/lib/arel/engines/sql/engine.rb +19 -27
- data/lib/arel/engines/sql/formatters.rb +26 -10
- data/lib/arel/engines/sql/relations.rb +0 -7
- data/lib/arel/engines/sql/relations/compiler.rb +70 -35
- data/lib/arel/engines/sql/relations/table.rb +44 -32
- data/lib/arel/{engines/sql/relations/utilities/recursion.rb → recursion/base_case.rb} +0 -0
- data/lib/arel/session.rb +24 -40
- data/lib/arel/sql_literal.rb +13 -0
- data/lib/arel/version.rb +1 -1
- data/spec/algebra/unit/predicates/inequality_spec.rb +32 -0
- data/spec/algebra/unit/predicates/predicate_spec.rb +22 -0
- data/spec/algebra/unit/primitives/attribute_spec.rb +3 -9
- data/spec/algebra/unit/primitives/expression_spec.rb +1 -7
- data/spec/algebra/unit/relations/join_spec.rb +0 -7
- data/spec/algebra/unit/relations/project_spec.rb +3 -3
- data/spec/algebra/unit/relations/relation_spec.rb +74 -25
- data/spec/algebra/unit/session/session_spec.rb +7 -7
- data/spec/engines/memory/integration/joins/cross_engine_spec.rb +20 -10
- data/spec/engines/memory/unit/relations/array_spec.rb +6 -5
- data/spec/engines/memory/unit/relations/join_spec.rb +7 -6
- data/spec/engines/memory/unit/relations/order_spec.rb +7 -6
- data/spec/engines/memory/unit/relations/project_spec.rb +6 -6
- data/spec/engines/memory/unit/relations/skip_spec.rb +10 -5
- data/spec/engines/memory/unit/relations/take_spec.rb +7 -5
- data/spec/engines/memory/unit/relations/where_spec.rb +13 -9
- data/spec/engines/sql/unit/engine_spec.rb +20 -0
- data/spec/engines/sql/unit/relations/group_spec.rb +2 -2
- data/spec/engines/sql/unit/relations/order_spec.rb +5 -5
- data/spec/engines/sql/unit/relations/project_spec.rb +4 -4
- data/spec/engines/sql/unit/relations/table_spec.rb +0 -7
- data/spec/engines/sql/unit/relations/take_spec.rb +26 -0
- data/spec/engines/sql/unit/relations/where_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -4
- data/spec/sql/christener_spec.rb +70 -0
- data/spec/support/model.rb +7 -2
- metadata +109 -23
- data/lib/arel/algebra/core_extensions/class.rb +0 -32
- data/lib/arel/algebra/relations/operations/alias.rb +0 -7
- data/lib/arel/engines/memory/predicates.rb +0 -99
- data/lib/arel/engines/memory/primitives.rb +0 -27
- data/lib/arel/engines/memory/relations/compound.rb +0 -9
- data/lib/arel/engines/memory/relations/writes.rb +0 -7
- data/lib/arel/engines/sql/predicates.rb +0 -103
- data/lib/arel/engines/sql/primitives.rb +0 -97
- data/lib/arel/engines/sql/relations/operations/alias.rb +0 -5
- data/lib/arel/engines/sql/relations/operations/join.rb +0 -33
- data/lib/arel/engines/sql/relations/relation.rb +0 -65
- data/lib/arel/engines/sql/relations/utilities/compound.rb +0 -10
- data/lib/arel/engines/sql/relations/utilities/externalization.rb +0 -14
- data/lib/arel/engines/sql/relations/writes.rb +0 -19
data/README.markdown
CHANGED
@@ -180,3 +180,27 @@ As you can see, we're completely missing data for user with id 3. `dumpty` has n
|
|
180
180
|
FROM users
|
181
181
|
LEFT OUTER JOIN (SELECT user_id, count(*) as cnt FROM photos GROUP BY user_id) AS photos_aggregation
|
182
182
|
ON photos_aggregation.user_id = users.id
|
183
|
+
|
184
|
+
## ActiveRecord Adapter Support
|
185
|
+
|
186
|
+
Arel provides built-in support for the following ActiveRecord DB adapters:
|
187
|
+
|
188
|
+
* IBM DB
|
189
|
+
* MySQL
|
190
|
+
* Oracle
|
191
|
+
* PostgreSQL
|
192
|
+
* SQLite
|
193
|
+
|
194
|
+
You can add support for other adapters by defining a SQL compiler at the appropriate place. Here's an example: let's say
|
195
|
+
you've got a YourSQL adapter. Create a file at `yoursql/arel_compiler.rb` somewhere on the load path (presumably in
|
196
|
+
the YourSQL adapter gem). The contents of that file can be as simple as:
|
197
|
+
|
198
|
+
module Arel
|
199
|
+
module SqlCompiler
|
200
|
+
class YourSQLCompiler < GenericCompiler
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
Override any methods as necessary. See examples at
|
206
|
+
[lib/arel/engines/sql/compilers](http://github.com/rails/arel/tree/master/lib/arel/engines/sql/compilers/).
|
data/lib/arel.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
require 'active_support/inflector'
|
2
|
-
require 'active_support/core_ext/class/attribute_accessors'
|
3
2
|
require 'active_support/core_ext/module/delegation'
|
4
3
|
require 'active_support/core_ext/object/blank'
|
5
4
|
|
5
|
+
require 'arel/recursion/base_case'
|
6
|
+
|
6
7
|
module Arel
|
7
8
|
require 'arel/algebra'
|
9
|
+
require 'arel/sql_literal'
|
8
10
|
require 'arel/engines'
|
9
11
|
require 'arel/version'
|
10
12
|
|
@@ -3,14 +3,42 @@ require 'set'
|
|
3
3
|
module Arel
|
4
4
|
class TypecastError < StandardError ; end
|
5
5
|
class Attribute
|
6
|
-
|
7
|
-
|
8
|
-
delegate :engine, :christener, :to => :relation
|
6
|
+
attr_reader :relation, :name, :alias, :ancestor, :hash
|
7
|
+
attr_reader :history
|
9
8
|
|
10
9
|
def initialize(relation, name, options = {})
|
11
|
-
@relation
|
10
|
+
@relation = relation # this is actually a table (I think)
|
11
|
+
@name = name
|
12
|
+
@alias = options[:alias]
|
13
|
+
@ancestor = options[:ancestor]
|
14
|
+
@history = [self] + (@ancestor ? @ancestor.history : [])
|
15
|
+
@root = @history.last
|
16
|
+
@original_relation = nil
|
17
|
+
@original_attribute = nil
|
18
|
+
|
19
|
+
# FIXME: I think we can remove this eventually
|
20
|
+
@hash = name.hash + root.relation.class.hash
|
12
21
|
end
|
13
22
|
|
23
|
+
def engine
|
24
|
+
@relation.engine
|
25
|
+
end
|
26
|
+
|
27
|
+
def christener
|
28
|
+
@relation.christener
|
29
|
+
end
|
30
|
+
|
31
|
+
def == other
|
32
|
+
super ||
|
33
|
+
Attribute === other &&
|
34
|
+
@name == other.name &&
|
35
|
+
@alias == other.alias &&
|
36
|
+
@ancestor == other.ancestor &&
|
37
|
+
@relation == other.relation
|
38
|
+
end
|
39
|
+
|
40
|
+
alias :eql? :==
|
41
|
+
|
14
42
|
def named?(hypothetical_name)
|
15
43
|
(@alias || name).to_s == hypothetical_name.to_s
|
16
44
|
end
|
@@ -19,190 +47,184 @@ module Arel
|
|
19
47
|
false
|
20
48
|
end
|
21
49
|
|
22
|
-
def
|
23
|
-
|
50
|
+
def eval(row)
|
51
|
+
row[self]
|
24
52
|
end
|
25
53
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
30
|
-
|
31
|
-
def hash
|
32
|
-
@hash ||= name.hash + root.relation.hash
|
33
|
-
end
|
54
|
+
def as(aliaz = nil)
|
55
|
+
Attribute.new(relation, name, :alias => aliaz, :ancestor => self)
|
56
|
+
end
|
34
57
|
|
35
|
-
|
36
|
-
|
37
|
-
|
58
|
+
def bind(new_relation)
|
59
|
+
relation == new_relation ? self : Attribute.new(new_relation, name, :alias => @alias, :ancestor => self)
|
60
|
+
end
|
38
61
|
|
39
|
-
|
40
|
-
|
41
|
-
|
62
|
+
def to_attribute(relation)
|
63
|
+
bind(relation)
|
64
|
+
end
|
42
65
|
|
43
|
-
|
44
|
-
|
45
|
-
end
|
66
|
+
def join?
|
67
|
+
relation.join?
|
46
68
|
end
|
47
|
-
include Transformations
|
48
69
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
end
|
70
|
+
def root
|
71
|
+
history.last
|
72
|
+
end
|
53
73
|
|
54
|
-
|
55
|
-
|
56
|
-
|
74
|
+
def original_relation
|
75
|
+
@original_relation ||= original_attribute.relation
|
76
|
+
end
|
57
77
|
|
58
|
-
|
59
|
-
|
60
|
-
|
78
|
+
def original_attribute
|
79
|
+
@original_attribute ||= history.detect { |a| !a.join? }
|
80
|
+
end
|
61
81
|
|
62
|
-
|
63
|
-
|
64
|
-
|
82
|
+
def find_correlate_in(relation)
|
83
|
+
relation[self] || self
|
84
|
+
end
|
65
85
|
|
66
|
-
|
67
|
-
|
68
|
-
|
86
|
+
def descends_from?(other)
|
87
|
+
history.include?(other)
|
88
|
+
end
|
69
89
|
|
70
|
-
|
71
|
-
|
72
|
-
|
90
|
+
def /(other)
|
91
|
+
other ? (history & other.history).size : 0
|
92
|
+
end
|
73
93
|
|
74
|
-
|
75
|
-
|
76
|
-
|
94
|
+
PREDICATES = [
|
95
|
+
:eq, :eq_any, :eq_all, :not_eq, :not_eq_any, :not_eq_all, :lt, :lt_any,
|
96
|
+
:lt_all, :lteq, :lteq_any, :lteq_all, :gt, :gt_any, :gt_all, :gteq,
|
97
|
+
:gteq_any, :gteq_all, :matches, :matches_any, :matches_all, :not_matches,
|
98
|
+
:not_matches_any, :not_matches_all, :in, :in_any, :in_all, :not_in,
|
99
|
+
:not_in_any, :not_in_all
|
100
|
+
]
|
77
101
|
|
78
|
-
|
79
|
-
|
102
|
+
Predications = Class.new do
|
103
|
+
def self.instance_methods *args
|
104
|
+
warn "this module is deprecated, please use the PREDICATES constant"
|
105
|
+
PREDICATES
|
80
106
|
end
|
81
107
|
end
|
82
|
-
include Congruence
|
83
108
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
end
|
109
|
+
def eq(other)
|
110
|
+
Predicates::Equality.new(self, other)
|
111
|
+
end
|
88
112
|
|
89
|
-
|
90
|
-
|
91
|
-
|
113
|
+
def eq_any(*others)
|
114
|
+
Predicates::Any.build(Predicates::Equality, self, *others)
|
115
|
+
end
|
92
116
|
|
93
|
-
|
94
|
-
|
95
|
-
|
117
|
+
def eq_all(*others)
|
118
|
+
Predicates::All.build(Predicates::Equality, self, *others)
|
119
|
+
end
|
96
120
|
|
97
|
-
|
98
|
-
|
99
|
-
|
121
|
+
def not_eq(other)
|
122
|
+
Predicates::Inequality.new(self, other)
|
123
|
+
end
|
100
124
|
|
101
|
-
|
102
|
-
|
103
|
-
|
125
|
+
def not_eq_any(*others)
|
126
|
+
Predicates::Any.build(Predicates::Inequality, self, *others)
|
127
|
+
end
|
104
128
|
|
105
|
-
|
106
|
-
|
107
|
-
|
129
|
+
def not_eq_all(*others)
|
130
|
+
Predicates::All.build(Predicates::Inequality, self, *others)
|
131
|
+
end
|
108
132
|
|
109
|
-
|
110
|
-
|
111
|
-
|
133
|
+
def lt(other)
|
134
|
+
Predicates::LessThan.new(self, other)
|
135
|
+
end
|
112
136
|
|
113
|
-
|
114
|
-
|
115
|
-
|
137
|
+
def lt_any(*others)
|
138
|
+
Predicates::Any.build(Predicates::LessThan, self, *others)
|
139
|
+
end
|
116
140
|
|
117
|
-
|
118
|
-
|
119
|
-
|
141
|
+
def lt_all(*others)
|
142
|
+
Predicates::All.build(Predicates::LessThan, self, *others)
|
143
|
+
end
|
120
144
|
|
121
|
-
|
122
|
-
|
123
|
-
|
145
|
+
def lteq(other)
|
146
|
+
Predicates::LessThanOrEqualTo.new(self, other)
|
147
|
+
end
|
124
148
|
|
125
|
-
|
126
|
-
|
127
|
-
|
149
|
+
def lteq_any(*others)
|
150
|
+
Predicates::Any.build(Predicates::LessThanOrEqualTo, self, *others)
|
151
|
+
end
|
128
152
|
|
129
|
-
|
130
|
-
|
131
|
-
|
153
|
+
def lteq_all(*others)
|
154
|
+
Predicates::All.build(Predicates::LessThanOrEqualTo, self, *others)
|
155
|
+
end
|
132
156
|
|
133
|
-
|
134
|
-
|
135
|
-
|
157
|
+
def gt(other)
|
158
|
+
Predicates::GreaterThan.new(self, other)
|
159
|
+
end
|
136
160
|
|
137
|
-
|
138
|
-
|
139
|
-
|
161
|
+
def gt_any(*others)
|
162
|
+
Predicates::Any.build(Predicates::GreaterThan, self, *others)
|
163
|
+
end
|
140
164
|
|
141
|
-
|
142
|
-
|
143
|
-
|
165
|
+
def gt_all(*others)
|
166
|
+
Predicates::All.build(Predicates::GreaterThan, self, *others)
|
167
|
+
end
|
144
168
|
|
145
|
-
|
146
|
-
|
147
|
-
|
169
|
+
def gteq(other)
|
170
|
+
Predicates::GreaterThanOrEqualTo.new(self, other)
|
171
|
+
end
|
148
172
|
|
149
|
-
|
150
|
-
|
151
|
-
|
173
|
+
def gteq_any(*others)
|
174
|
+
Predicates::Any.build(Predicates::GreaterThanOrEqualTo, self, *others)
|
175
|
+
end
|
152
176
|
|
153
|
-
|
154
|
-
|
155
|
-
|
177
|
+
def gteq_all(*others)
|
178
|
+
Predicates::All.build(Predicates::GreaterThanOrEqualTo, self, *others)
|
179
|
+
end
|
156
180
|
|
157
|
-
|
158
|
-
|
159
|
-
|
181
|
+
def matches(other)
|
182
|
+
Predicates::Match.new(self, other)
|
183
|
+
end
|
160
184
|
|
161
|
-
|
162
|
-
|
163
|
-
|
185
|
+
def matches_any(*others)
|
186
|
+
Predicates::Any.build(Predicates::Match, self, *others)
|
187
|
+
end
|
164
188
|
|
165
|
-
|
166
|
-
|
167
|
-
|
189
|
+
def matches_all(*others)
|
190
|
+
Predicates::All.build(Predicates::Match, self, *others)
|
191
|
+
end
|
168
192
|
|
169
|
-
|
170
|
-
|
171
|
-
|
193
|
+
def not_matches(other)
|
194
|
+
Predicates::NotMatch.new(self, other)
|
195
|
+
end
|
172
196
|
|
173
|
-
|
174
|
-
|
175
|
-
|
197
|
+
def not_matches_any(*others)
|
198
|
+
Predicates::Any.build(Predicates::NotMatch, self, *others)
|
199
|
+
end
|
176
200
|
|
177
|
-
|
178
|
-
|
179
|
-
|
201
|
+
def not_matches_all(*others)
|
202
|
+
Predicates::All.build(Predicates::NotMatch, self, *others)
|
203
|
+
end
|
180
204
|
|
181
|
-
|
182
|
-
|
183
|
-
|
205
|
+
def in(other)
|
206
|
+
Predicates::In.new(self, other)
|
207
|
+
end
|
184
208
|
|
185
|
-
|
186
|
-
|
187
|
-
|
209
|
+
def in_any(*others)
|
210
|
+
Predicates::Any.build(Predicates::In, self, *others)
|
211
|
+
end
|
188
212
|
|
189
|
-
|
190
|
-
|
191
|
-
|
213
|
+
def in_all(*others)
|
214
|
+
Predicates::All.build(Predicates::In, self, *others)
|
215
|
+
end
|
192
216
|
|
193
|
-
|
194
|
-
|
195
|
-
|
217
|
+
def not_in(other)
|
218
|
+
Predicates::NotIn.new(self, other)
|
219
|
+
end
|
196
220
|
|
197
|
-
|
198
|
-
|
199
|
-
|
221
|
+
def not_in_any(*others)
|
222
|
+
Predicates::Any.build(Predicates::NotIn, self, *others)
|
223
|
+
end
|
200
224
|
|
201
|
-
|
202
|
-
|
203
|
-
end
|
225
|
+
def not_in_all(*others)
|
226
|
+
Predicates::All.build(Predicates::NotIn, self, *others)
|
204
227
|
end
|
205
|
-
include Predications
|
206
228
|
|
207
229
|
module Expressions
|
208
230
|
def count(distinct = false)
|
@@ -266,5 +288,17 @@ module Arel
|
|
266
288
|
end
|
267
289
|
end
|
268
290
|
include Types
|
291
|
+
|
292
|
+
def column
|
293
|
+
original_relation.column_for(self)
|
294
|
+
end
|
295
|
+
|
296
|
+
def format(object)
|
297
|
+
object.to_sql(Sql::Attribute.new(self))
|
298
|
+
end
|
299
|
+
|
300
|
+
def to_sql(formatter = Sql::WhereCondition.new(relation))
|
301
|
+
formatter.attribute self
|
302
|
+
end
|
269
303
|
end
|
270
304
|
end
|
@@ -1,11 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
Hash.send(:include, self)
|
1
|
+
class Hash
|
2
|
+
def bind(relation)
|
3
|
+
Hash[map { |key, value|
|
4
|
+
[key.bind(relation), value.bind(relation)]
|
5
|
+
}]
|
10
6
|
end
|
11
7
|
end
|