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.
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/lib/arel/session.rb CHANGED
@@ -1,51 +1,35 @@
1
1
  module Arel
2
2
  class Session
3
- class << self
4
- attr_accessor :instance
5
- alias_method :manufacture, :new
3
+ @instance = nil
6
4
 
7
- def start
8
- if defined?(@started) && @started
9
- yield
10
- else
11
- begin
12
- @started = true
13
- @instance = manufacture
14
- singleton_class.class_eval do
15
- undef :new
16
- alias_method :new, :instance
17
- end
18
- yield
19
- ensure
20
- singleton_class.class_eval do
21
- undef :new
22
- alias_method :new, :manufacture
23
- end
24
- @started = false
25
- end
26
- end
27
- end
5
+ def self.instance
6
+ @instance || new
28
7
  end
29
8
 
30
- module CRUD
31
- def create(insert)
32
- insert.call
33
- end
9
+ def self.start
10
+ @instance ||= new
11
+ yield @instance
12
+ ensure
13
+ @instance = nil
14
+ end
34
15
 
35
- def read(select)
36
- (@read ||= Hash.new do |hash, select|
37
- hash[select] = select.call
38
- end)[select]
39
- end
16
+ def create(insert)
17
+ insert.call
18
+ end
40
19
 
41
- def update(update)
42
- update.call
43
- end
20
+ def read(select)
21
+ @read ||= {}
22
+ key = select.object_id
23
+ return @read[key] if @read.key? key
24
+ @read[key] = select.call
25
+ end
26
+
27
+ def update(update)
28
+ update.call
29
+ end
44
30
 
45
- def delete(delete)
46
- delete.call
47
- end
31
+ def delete(delete)
32
+ delete.call
48
33
  end
49
- include CRUD
50
34
  end
51
35
  end
@@ -0,0 +1,13 @@
1
+ module Arel
2
+ class SqlLiteral < String
3
+ def relation
4
+ nil
5
+ end
6
+
7
+ def to_sql(formatter = nil)
8
+ self
9
+ end
10
+
11
+ include Attribute::Expressions
12
+ end
13
+ end
data/lib/arel/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Arel
2
- VERSION = "0.4.0" unless defined?(Arel::VERSION)
2
+ VERSION = "1.0.0.rc1" unless defined?(Arel::VERSION)
3
3
  end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ module Arel
4
+ module Predicates
5
+ describe Inequality do
6
+ before do
7
+ relation1 = Arel::Table.new(:users)
8
+ relation2 = Arel::Table.new(:photos)
9
+ left = relation1[:id]
10
+ right = relation2[:user_id]
11
+ @a = Inequality.new(left, right)
12
+ @b = Inequality.new(right, left)
13
+ end
14
+
15
+ describe 'operator' do
16
+ it "should have one" do
17
+ @a.operator.should == :"!="
18
+ end
19
+ end
20
+
21
+ describe '==' do
22
+ it "is equal to itself" do
23
+ @a.should == @a
24
+ end
25
+
26
+ it "should not care abount children order" do
27
+ @a.should == @b
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ module Arel
4
+ module Predicates
5
+ describe Polyadic do
6
+ before do
7
+ @relation1 = Arel::Table.new(:users)
8
+ @relation2 = Arel::Table.new(:photos)
9
+ @a = @relation1[:id]
10
+ @b = @relation2[:user_id]
11
+ end
12
+
13
+ describe '==' do
14
+ left = Polyadic.new @a, @b
15
+ right = Polyadic.new @b, @a
16
+
17
+ left.should != right
18
+ left.should == right
19
+ end
20
+ end
21
+ end
22
+ end
@@ -7,13 +7,7 @@ module Arel
7
7
  @attribute = @relation[:id]
8
8
  end
9
9
 
10
- describe "#inspect" do
11
- it "returns a simple, short inspect string" do
12
- @attribute.inspect.should == "<Attribute id>"
13
- end
14
- end
15
-
16
- describe Attribute::Transformations do
10
+ describe 'Attribute::Transformations' do
17
11
  describe '#as' do
18
12
  it "manufactures an aliased attributed" do
19
13
  @attribute.as(:alias).should == Attribute.new(@relation, @attribute.name, :alias => :alias, :ancestor => @attribute)
@@ -58,7 +52,7 @@ module Arel
58
52
  end
59
53
  end
60
54
 
61
- describe Attribute::Congruence do
55
+ describe 'Attribute::Congruence' do
62
56
  describe '/' do
63
57
  before do
64
58
  @aliased_relation = @relation.alias
@@ -80,7 +74,7 @@ module Arel
80
74
  end
81
75
  end
82
76
 
83
- describe Attribute::Predications do
77
+ describe 'Attribute::Predications' do
84
78
  before do
85
79
  @attribute = Attribute.new(@relation, :name)
86
80
  end
@@ -7,13 +7,7 @@ module Arel
7
7
  @attribute = @relation[:id]
8
8
  end
9
9
 
10
- describe "#inspect" do
11
- it "returns a simple, short inspect string" do
12
- @attribute.count.inspect.should == "<Arel::Count <Attribute id>>"
13
- end
14
- end
15
-
16
- describe Expression::Transformations do
10
+ describe 'Expression::Transformations' do
17
11
  before do
18
12
  @expression = Count.new(@attribute)
19
13
  end
@@ -8,13 +8,6 @@ module Arel
8
8
  @predicate = @relation1[:id].eq(@relation2[:user_id])
9
9
  end
10
10
 
11
- describe 'hashing' do
12
- it 'implements hash equality' do
13
- InnerJoin.new(@relation1, @relation2, @predicate) \
14
- .should hash_the_same_as(InnerJoin.new(@relation1, @relation2, @predicate))
15
- end
16
- end
17
-
18
11
  describe '#attributes' do
19
12
  it 'combines the attributes of the two relations' do
20
13
  join = InnerJoin.new(@relation1, @relation2, @predicate)
@@ -9,7 +9,7 @@ module Arel
9
9
 
10
10
  describe '#attributes' do
11
11
  before do
12
- @projection = Project.new(@relation, @attribute)
12
+ @projection = Project.new(@relation, [@attribute])
13
13
  end
14
14
 
15
15
  it "manufactures attributes associated with the projection relation" do
@@ -20,13 +20,13 @@ module Arel
20
20
  describe '#externalizable?' do
21
21
  describe 'when the projections are attributes' do
22
22
  it 'returns false' do
23
- Project.new(@relation, @attribute).should_not be_externalizable
23
+ Project.new(@relation, [@attribute]).should_not be_externalizable
24
24
  end
25
25
  end
26
26
 
27
27
  describe 'when the projections include an aggregation' do
28
28
  it "obtains" do
29
- Project.new(@relation, @attribute.sum).should be_externalizable
29
+ Project.new(@relation, [@attribute.sum]).should be_externalizable
30
30
  end
31
31
  end
32
32
  end
@@ -23,7 +23,7 @@ module Arel
23
23
  end
24
24
  end
25
25
 
26
- describe Relation::Operable do
26
+ describe 'Relation::Operable' do
27
27
  describe 'joins' do
28
28
  before do
29
29
  @predicate = @relation[:id].eq(@relation[:id])
@@ -32,14 +32,23 @@ module Arel
32
32
  describe '#join' do
33
33
  describe 'when given a relation' do
34
34
  it "manufactures an inner join operation between those two relations" do
35
- @relation.join(@relation).on(@predicate). \
36
- should == InnerJoin.new(@relation, @relation, @predicate)
35
+ join = @relation.join(@relation).on(@predicate)
36
+ join.relation1.should == @relation
37
+ join.relation2.should == @relation
38
+ join.predicates.should == [@predicate]
39
+ join.should be_kind_of(InnerJoin)
37
40
  end
38
41
  end
39
42
 
40
43
  describe "when given a string" do
41
44
  it "manufactures a join operation with the string passed through" do
42
- @relation.join(arbitrary_string = "ASDF").should == StringJoin.new(@relation, arbitrary_string)
45
+ arbitrary_string = "ASDF"
46
+
47
+ join = @relation.join(arbitrary_string)
48
+ join.relation1.should == @relation
49
+ join.relation2.should == arbitrary_string
50
+ join.predicates.should == []
51
+ join.should be_kind_of StringJoin
43
52
  end
44
53
  end
45
54
 
@@ -52,16 +61,21 @@ module Arel
52
61
 
53
62
  describe '#outer_join' do
54
63
  it "manufactures a left outer join operation between those two relations" do
55
- @relation.outer_join(@relation).on(@predicate). \
56
- should == OuterJoin.new(@relation, @relation, @predicate)
64
+ join = @relation.outer_join(@relation).on(@predicate)
65
+ join.relation1.should == @relation
66
+ join.relation2.should == @relation
67
+ join.predicates.should == [@predicate]
68
+ join.should be_kind_of OuterJoin
57
69
  end
58
70
  end
59
71
  end
60
72
 
61
73
  describe '#project' do
62
74
  it "manufactures a projection relation" do
63
- @relation.project(@attribute1, @attribute2). \
64
- should == Project.new(@relation, @attribute1, @attribute2)
75
+ project = @relation.project(@attribute1, @attribute2)
76
+ project.relation.should == @relation
77
+ project.projections.should == [@attribute1, @attribute2]
78
+ project.should be_kind_of Project
65
79
  end
66
80
 
67
81
  describe "when given blank attributes" do
@@ -83,11 +97,20 @@ module Arel
83
97
  end
84
98
 
85
99
  it "manufactures a where relation" do
86
- @relation.where(@predicate).should == Where.new(@relation, @predicate)
100
+ where = @relation.where(@predicate)
101
+ where.relation.should == @relation
102
+ where.predicates.should == [@predicate]
103
+ where.should be_kind_of Where
87
104
  end
88
105
 
89
106
  it "accepts arbitrary strings" do
90
- @relation.where("arbitrary").should == Where.new(@relation, "arbitrary")
107
+ where = @relation.where("arbitrary")
108
+ where.relation.should == @relation
109
+
110
+ where.predicates.length.should == 1
111
+ where.predicates.first.value.should == "arbitrary"
112
+
113
+ where.should be_kind_of Where
91
114
  end
92
115
 
93
116
  describe 'when given a blank predicate' do
@@ -99,7 +122,10 @@ module Arel
99
122
 
100
123
  describe '#order' do
101
124
  it "manufactures an order relation" do
102
- @relation.order(@attribute1, @attribute2).should == Order.new(@relation, @attribute1, @attribute2)
125
+ order = @relation.order(@attribute1, @attribute2)
126
+ order.relation.should == @relation
127
+ order.orderings.should == [@attribute1, @attribute2]
128
+ order.should be_kind_of Order
103
129
  end
104
130
 
105
131
  describe 'when given a blank ordering' do
@@ -111,19 +137,24 @@ module Arel
111
137
 
112
138
  describe '#take' do
113
139
  it "manufactures a take relation" do
114
- @relation.take(5).should == Take.new(@relation, 5)
140
+ take = @relation.take(5)
141
+ take.relation.should == @relation
142
+ take.taken.should == 5
115
143
  end
116
144
 
117
145
  describe 'when given a blank number of items' do
118
- it 'returns self' do
119
- @relation.take.should == @relation
146
+ it 'raises error' do
147
+ lambda { @relation.take }.should raise_exception
120
148
  end
121
149
  end
122
150
  end
123
151
 
124
152
  describe '#skip' do
125
153
  it "manufactures a skip relation" do
126
- @relation.skip(4).should == Skip.new(@relation, 4)
154
+ skip = @relation.skip(4)
155
+ skip.relation.should == @relation
156
+ skip.skipped.should == 4
157
+ skip.should be_kind_of Skip
127
158
  end
128
159
 
129
160
  describe 'when given a blank number of items' do
@@ -135,7 +166,12 @@ module Arel
135
166
 
136
167
  describe '#group' do
137
168
  it 'manufactures a group relation' do
138
- @relation.group(@attribute1, @attribute2).should == Group.new(@relation, @attribute1, @attribute2)
169
+ group = @relation.group(@attribute1, @attribute2)
170
+ group.relation.should == @relation
171
+ group.groupings.should == [@attribute1, @attribute2]
172
+ group.should be_kind_of Group
173
+ sql = group.to_sql
174
+ sql.should =~ /GROUP BY/
139
175
  end
140
176
 
141
177
  describe 'when given blank groupings' do
@@ -145,11 +181,14 @@ module Arel
145
181
  end
146
182
  end
147
183
 
148
- describe Relation::Operable::Writable do
184
+ describe 'relation is writable' do
149
185
  describe '#delete' do
150
186
  it 'manufactures a deletion relation' do
151
- Session.start do
152
- Session.new.should_receive(:delete).with(Deletion.new(@relation))
187
+ Session.start do |s|
188
+ s.should_receive(:delete) do |delete|
189
+ delete.relation.should == @relation
190
+ delete.should be_kind_of Deletion
191
+ end
153
192
  @relation.delete
154
193
  end
155
194
  end
@@ -157,9 +196,14 @@ module Arel
157
196
 
158
197
  describe '#insert' do
159
198
  it 'manufactures an insertion relation' do
160
- Session.start do
161
- record = { @relation[:name] => 'carl' }
162
- Session.new.should_receive(:create).with(Insert.new(@relation, record))
199
+ Session.start do |s|
200
+ record = { @relation[:name] => Value.new('carl', @relation) }
201
+ s.should_receive(:create) do |insert|
202
+ insert.relation.should == @relation
203
+ insert.record.should == record
204
+ insert.should be_kind_of Insert
205
+ insert
206
+ end
163
207
  @relation.insert(record)
164
208
  end
165
209
  end
@@ -167,9 +211,14 @@ module Arel
167
211
 
168
212
  describe '#update' do
169
213
  it 'manufactures an update relation' do
170
- Session.start do
214
+ Session.start do |s|
171
215
  assignments = { @relation[:name] => Value.new('bob', @relation) }
172
- Session.new.should_receive(:update).with(Update.new(@relation, assignments))
216
+ s.should_receive(:update) do |update|
217
+ update.relation.should == @relation
218
+ update.assignments.should == assignments
219
+ update.should be_kind_of Update
220
+ update
221
+ end
173
222
  @relation.update(assignments)
174
223
  end
175
224
  end
@@ -177,7 +226,7 @@ module Arel
177
226
  end
178
227
  end
179
228
 
180
- describe Relation::Enumerable do
229
+ describe 'is enumerable' do
181
230
  it "implements enumerable" do
182
231
  @relation.map { |value| value }.should ==
183
232
  @relation.session.read(@relation).map { |value| value }
@@ -10,16 +10,16 @@ module Arel
10
10
  describe '::start' do
11
11
  describe '::instance' do
12
12
  it "it is a singleton within the started session" do
13
- Session.start do
14
- Session.new.should == Session.new
13
+ Session.start do |session|
14
+ Session.instance.should == session
15
15
  end
16
16
  end
17
17
 
18
18
  it "is a singleton across nested sessions" do
19
- Session.start do
20
- outside = Session.new
21
- Session.start do
22
- Session.new.should == outside
19
+ Session.start do |s1|
20
+ outside = Session.instance
21
+ Session.start do |s2|
22
+ Session.instance.should == outside
23
23
  end
24
24
  end
25
25
  end
@@ -30,7 +30,7 @@ module Arel
30
30
  end
31
31
  end
32
32
 
33
- describe Session::CRUD do
33
+ describe 'session crud' do
34
34
  before do
35
35
  @insert = Insert.new(@relation, @relation[:name] => 'nick')
36
36
  @update = Update.new(@relation, @relation[:name] => 'nick')