arel 0.4.0 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. data/README.markdown +24 -0
  2. data/lib/arel.rb +3 -1
  3. data/lib/arel/algebra/attributes/attribute.rb +175 -141
  4. data/lib/arel/algebra/core_extensions.rb +0 -1
  5. data/lib/arel/algebra/core_extensions/hash.rb +5 -9
  6. data/lib/arel/algebra/core_extensions/object.rb +0 -4
  7. data/lib/arel/algebra/expression.rb +37 -24
  8. data/lib/arel/algebra/header.rb +5 -6
  9. data/lib/arel/algebra/ordering.rb +13 -5
  10. data/lib/arel/algebra/predicates.rb +143 -27
  11. data/lib/arel/algebra/relations.rb +0 -1
  12. data/lib/arel/algebra/relations/operations/from.rb +10 -2
  13. data/lib/arel/algebra/relations/operations/group.rb +8 -6
  14. data/lib/arel/algebra/relations/operations/having.rb +3 -6
  15. data/lib/arel/algebra/relations/operations/join.rb +52 -18
  16. data/lib/arel/algebra/relations/operations/lock.rb +4 -6
  17. data/lib/arel/algebra/relations/operations/order.rb +11 -7
  18. data/lib/arel/algebra/relations/operations/project.rb +10 -10
  19. data/lib/arel/algebra/relations/operations/skip.rb +10 -3
  20. data/lib/arel/algebra/relations/operations/take.rb +10 -3
  21. data/lib/arel/algebra/relations/operations/where.rb +12 -6
  22. data/lib/arel/algebra/relations/relation.rb +161 -92
  23. data/lib/arel/algebra/relations/row.rb +8 -5
  24. data/lib/arel/algebra/relations/utilities/compound.rb +34 -33
  25. data/lib/arel/algebra/relations/utilities/externalization.rb +10 -8
  26. data/lib/arel/algebra/relations/writes.rb +24 -13
  27. data/lib/arel/algebra/value.rb +41 -2
  28. data/lib/arel/engines/memory.rb +0 -2
  29. data/lib/arel/engines/memory/engine.rb +3 -9
  30. data/lib/arel/engines/memory/relations.rb +0 -3
  31. data/lib/arel/engines/memory/relations/array.rb +5 -3
  32. data/lib/arel/engines/memory/relations/operations.rb +2 -60
  33. data/lib/arel/engines/sql.rb +0 -2
  34. data/lib/arel/engines/sql/christener.rb +12 -6
  35. data/lib/arel/engines/sql/compilers/oracle_compiler.rb +34 -23
  36. data/lib/arel/engines/sql/compilers/postgresql_compiler.rb +23 -15
  37. data/lib/arel/engines/sql/engine.rb +19 -27
  38. data/lib/arel/engines/sql/formatters.rb +26 -10
  39. data/lib/arel/engines/sql/relations.rb +0 -7
  40. data/lib/arel/engines/sql/relations/compiler.rb +70 -35
  41. data/lib/arel/engines/sql/relations/table.rb +44 -32
  42. data/lib/arel/{engines/sql/relations/utilities/recursion.rb → recursion/base_case.rb} +0 -0
  43. data/lib/arel/session.rb +24 -40
  44. data/lib/arel/sql_literal.rb +13 -0
  45. data/lib/arel/version.rb +1 -1
  46. data/spec/algebra/unit/predicates/inequality_spec.rb +32 -0
  47. data/spec/algebra/unit/predicates/predicate_spec.rb +22 -0
  48. data/spec/algebra/unit/primitives/attribute_spec.rb +3 -9
  49. data/spec/algebra/unit/primitives/expression_spec.rb +1 -7
  50. data/spec/algebra/unit/relations/join_spec.rb +0 -7
  51. data/spec/algebra/unit/relations/project_spec.rb +3 -3
  52. data/spec/algebra/unit/relations/relation_spec.rb +74 -25
  53. data/spec/algebra/unit/session/session_spec.rb +7 -7
  54. data/spec/engines/memory/integration/joins/cross_engine_spec.rb +20 -10
  55. data/spec/engines/memory/unit/relations/array_spec.rb +6 -5
  56. data/spec/engines/memory/unit/relations/join_spec.rb +7 -6
  57. data/spec/engines/memory/unit/relations/order_spec.rb +7 -6
  58. data/spec/engines/memory/unit/relations/project_spec.rb +6 -6
  59. data/spec/engines/memory/unit/relations/skip_spec.rb +10 -5
  60. data/spec/engines/memory/unit/relations/take_spec.rb +7 -5
  61. data/spec/engines/memory/unit/relations/where_spec.rb +13 -9
  62. data/spec/engines/sql/unit/engine_spec.rb +20 -0
  63. data/spec/engines/sql/unit/relations/group_spec.rb +2 -2
  64. data/spec/engines/sql/unit/relations/order_spec.rb +5 -5
  65. data/spec/engines/sql/unit/relations/project_spec.rb +4 -4
  66. data/spec/engines/sql/unit/relations/table_spec.rb +0 -7
  67. data/spec/engines/sql/unit/relations/take_spec.rb +26 -0
  68. data/spec/engines/sql/unit/relations/where_spec.rb +1 -1
  69. data/spec/spec_helper.rb +1 -4
  70. data/spec/sql/christener_spec.rb +70 -0
  71. data/spec/support/model.rb +7 -2
  72. metadata +109 -23
  73. data/lib/arel/algebra/core_extensions/class.rb +0 -32
  74. data/lib/arel/algebra/relations/operations/alias.rb +0 -7
  75. data/lib/arel/engines/memory/predicates.rb +0 -99
  76. data/lib/arel/engines/memory/primitives.rb +0 -27
  77. data/lib/arel/engines/memory/relations/compound.rb +0 -9
  78. data/lib/arel/engines/memory/relations/writes.rb +0 -7
  79. data/lib/arel/engines/sql/predicates.rb +0 -103
  80. data/lib/arel/engines/sql/primitives.rb +0 -97
  81. data/lib/arel/engines/sql/relations/operations/alias.rb +0 -5
  82. data/lib/arel/engines/sql/relations/operations/join.rb +0 -33
  83. data/lib/arel/engines/sql/relations/relation.rb +0 -65
  84. data/lib/arel/engines/sql/relations/utilities/compound.rb +0 -10
  85. data/lib/arel/engines/sql/relations/utilities/externalization.rb +0 -14
  86. 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
- attributes :relation, :name, :alias, :ancestor
7
- deriving :==
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, @name, @alias, @ancestor = relation, name, options[:alias], options[:ancestor]
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 inspect
23
- "<Attribute #{name}>"
50
+ def eval(row)
51
+ row[self]
24
52
  end
25
53
 
26
- module Transformations
27
- def self.included(klass)
28
- klass.send :alias_method, :eql?, :==
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
- def as(aliaz = nil)
36
- Attribute.new(relation, name, :alias => aliaz, :ancestor => self)
37
- end
58
+ def bind(new_relation)
59
+ relation == new_relation ? self : Attribute.new(new_relation, name, :alias => @alias, :ancestor => self)
60
+ end
38
61
 
39
- def bind(new_relation)
40
- relation == new_relation ? self : Attribute.new(new_relation, name, :alias => @alias, :ancestor => self)
41
- end
62
+ def to_attribute(relation)
63
+ bind(relation)
64
+ end
42
65
 
43
- def to_attribute(relation)
44
- bind(relation)
45
- end
66
+ def join?
67
+ relation.join?
46
68
  end
47
- include Transformations
48
69
 
49
- module Congruence
50
- def history
51
- @history ||= [self] + (ancestor ? ancestor.history : [])
52
- end
70
+ def root
71
+ history.last
72
+ end
53
73
 
54
- def join?
55
- relation.join?
56
- end
74
+ def original_relation
75
+ @original_relation ||= original_attribute.relation
76
+ end
57
77
 
58
- def root
59
- history.last
60
- end
78
+ def original_attribute
79
+ @original_attribute ||= history.detect { |a| !a.join? }
80
+ end
61
81
 
62
- def original_relation
63
- @original_relation ||= original_attribute.relation
64
- end
82
+ def find_correlate_in(relation)
83
+ relation[self] || self
84
+ end
65
85
 
66
- def original_attribute
67
- @original_attribute ||= history.detect { |a| !a.join? }
68
- end
86
+ def descends_from?(other)
87
+ history.include?(other)
88
+ end
69
89
 
70
- def find_correlate_in(relation)
71
- relation[self] || self
72
- end
90
+ def /(other)
91
+ other ? (history & other.history).size : 0
92
+ end
73
93
 
74
- def descends_from?(other)
75
- history.include?(other)
76
- end
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
- def /(other)
79
- other ? (history & other.history).size : 0
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
- module Predications
85
- def eq(other)
86
- Predicates::Equality.new(self, other)
87
- end
109
+ def eq(other)
110
+ Predicates::Equality.new(self, other)
111
+ end
88
112
 
89
- def eq_any(*others)
90
- Predicates::Any.build(Predicates::Equality, self, *others)
91
- end
113
+ def eq_any(*others)
114
+ Predicates::Any.build(Predicates::Equality, self, *others)
115
+ end
92
116
 
93
- def eq_all(*others)
94
- Predicates::All.build(Predicates::Equality, self, *others)
95
- end
117
+ def eq_all(*others)
118
+ Predicates::All.build(Predicates::Equality, self, *others)
119
+ end
96
120
 
97
- def not_eq(other)
98
- Predicates::Inequality.new(self, other)
99
- end
121
+ def not_eq(other)
122
+ Predicates::Inequality.new(self, other)
123
+ end
100
124
 
101
- def not_eq_any(*others)
102
- Predicates::Any.build(Predicates::Inequality, self, *others)
103
- end
125
+ def not_eq_any(*others)
126
+ Predicates::Any.build(Predicates::Inequality, self, *others)
127
+ end
104
128
 
105
- def not_eq_all(*others)
106
- Predicates::All.build(Predicates::Inequality, self, *others)
107
- end
129
+ def not_eq_all(*others)
130
+ Predicates::All.build(Predicates::Inequality, self, *others)
131
+ end
108
132
 
109
- def lt(other)
110
- Predicates::LessThan.new(self, other)
111
- end
133
+ def lt(other)
134
+ Predicates::LessThan.new(self, other)
135
+ end
112
136
 
113
- def lt_any(*others)
114
- Predicates::Any.build(Predicates::LessThan, self, *others)
115
- end
137
+ def lt_any(*others)
138
+ Predicates::Any.build(Predicates::LessThan, self, *others)
139
+ end
116
140
 
117
- def lt_all(*others)
118
- Predicates::All.build(Predicates::LessThan, self, *others)
119
- end
141
+ def lt_all(*others)
142
+ Predicates::All.build(Predicates::LessThan, self, *others)
143
+ end
120
144
 
121
- def lteq(other)
122
- Predicates::LessThanOrEqualTo.new(self, other)
123
- end
145
+ def lteq(other)
146
+ Predicates::LessThanOrEqualTo.new(self, other)
147
+ end
124
148
 
125
- def lteq_any(*others)
126
- Predicates::Any.build(Predicates::LessThanOrEqualTo, self, *others)
127
- end
149
+ def lteq_any(*others)
150
+ Predicates::Any.build(Predicates::LessThanOrEqualTo, self, *others)
151
+ end
128
152
 
129
- def lteq_all(*others)
130
- Predicates::All.build(Predicates::LessThanOrEqualTo, self, *others)
131
- end
153
+ def lteq_all(*others)
154
+ Predicates::All.build(Predicates::LessThanOrEqualTo, self, *others)
155
+ end
132
156
 
133
- def gt(other)
134
- Predicates::GreaterThan.new(self, other)
135
- end
157
+ def gt(other)
158
+ Predicates::GreaterThan.new(self, other)
159
+ end
136
160
 
137
- def gt_any(*others)
138
- Predicates::Any.build(Predicates::GreaterThan, self, *others)
139
- end
161
+ def gt_any(*others)
162
+ Predicates::Any.build(Predicates::GreaterThan, self, *others)
163
+ end
140
164
 
141
- def gt_all(*others)
142
- Predicates::All.build(Predicates::GreaterThan, self, *others)
143
- end
165
+ def gt_all(*others)
166
+ Predicates::All.build(Predicates::GreaterThan, self, *others)
167
+ end
144
168
 
145
- def gteq(other)
146
- Predicates::GreaterThanOrEqualTo.new(self, other)
147
- end
169
+ def gteq(other)
170
+ Predicates::GreaterThanOrEqualTo.new(self, other)
171
+ end
148
172
 
149
- def gteq_any(*others)
150
- Predicates::Any.build(Predicates::GreaterThanOrEqualTo, self, *others)
151
- end
173
+ def gteq_any(*others)
174
+ Predicates::Any.build(Predicates::GreaterThanOrEqualTo, self, *others)
175
+ end
152
176
 
153
- def gteq_all(*others)
154
- Predicates::All.build(Predicates::GreaterThanOrEqualTo, self, *others)
155
- end
177
+ def gteq_all(*others)
178
+ Predicates::All.build(Predicates::GreaterThanOrEqualTo, self, *others)
179
+ end
156
180
 
157
- def matches(other)
158
- Predicates::Match.new(self, other)
159
- end
181
+ def matches(other)
182
+ Predicates::Match.new(self, other)
183
+ end
160
184
 
161
- def matches_any(*others)
162
- Predicates::Any.build(Predicates::Match, self, *others)
163
- end
185
+ def matches_any(*others)
186
+ Predicates::Any.build(Predicates::Match, self, *others)
187
+ end
164
188
 
165
- def matches_all(*others)
166
- Predicates::All.build(Predicates::Match, self, *others)
167
- end
189
+ def matches_all(*others)
190
+ Predicates::All.build(Predicates::Match, self, *others)
191
+ end
168
192
 
169
- def not_matches(other)
170
- Predicates::NotMatch.new(self, other)
171
- end
193
+ def not_matches(other)
194
+ Predicates::NotMatch.new(self, other)
195
+ end
172
196
 
173
- def not_matches_any(*others)
174
- Predicates::Any.build(Predicates::NotMatch, self, *others)
175
- end
197
+ def not_matches_any(*others)
198
+ Predicates::Any.build(Predicates::NotMatch, self, *others)
199
+ end
176
200
 
177
- def not_matches_all(*others)
178
- Predicates::All.build(Predicates::NotMatch, self, *others)
179
- end
201
+ def not_matches_all(*others)
202
+ Predicates::All.build(Predicates::NotMatch, self, *others)
203
+ end
180
204
 
181
- def in(other)
182
- Predicates::In.new(self, other)
183
- end
205
+ def in(other)
206
+ Predicates::In.new(self, other)
207
+ end
184
208
 
185
- def in_any(*others)
186
- Predicates::Any.build(Predicates::In, self, *others)
187
- end
209
+ def in_any(*others)
210
+ Predicates::Any.build(Predicates::In, self, *others)
211
+ end
188
212
 
189
- def in_all(*others)
190
- Predicates::All.build(Predicates::In, self, *others)
191
- end
213
+ def in_all(*others)
214
+ Predicates::All.build(Predicates::In, self, *others)
215
+ end
192
216
 
193
- def not_in(other)
194
- Predicates::NotIn.new(self, other)
195
- end
217
+ def not_in(other)
218
+ Predicates::NotIn.new(self, other)
219
+ end
196
220
 
197
- def not_in_any(*others)
198
- Predicates::Any.build(Predicates::NotIn, self, *others)
199
- end
221
+ def not_in_any(*others)
222
+ Predicates::Any.build(Predicates::NotIn, self, *others)
223
+ end
200
224
 
201
- def not_in_all(*others)
202
- Predicates::All.build(Predicates::NotIn, self, *others)
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,4 +1,3 @@
1
1
  require 'arel/algebra/core_extensions/object'
2
- require 'arel/algebra/core_extensions/class'
3
2
  require 'arel/algebra/core_extensions/symbol'
4
3
  require 'arel/algebra/core_extensions/hash'
@@ -1,11 +1,7 @@
1
- module Arel
2
- module HashExtensions
3
- def bind(relation)
4
- inject({}) do |bound, (key, value)|
5
- bound.merge(key.bind(relation) => value.bind(relation))
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