arel 0.1.0

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 (132) hide show
  1. data/.gitignore +6 -0
  2. data/README.markdown +184 -0
  3. data/Rakefile +60 -0
  4. data/VERSION +1 -0
  5. data/arel.gemspec +233 -0
  6. data/doc/CONVENTIONS +17 -0
  7. data/doc/TODO +118 -0
  8. data/lib/arel.rb +10 -0
  9. data/lib/arel/algebra.rb +4 -0
  10. data/lib/arel/algebra/extensions.rb +4 -0
  11. data/lib/arel/algebra/extensions/class.rb +32 -0
  12. data/lib/arel/algebra/extensions/hash.rb +11 -0
  13. data/lib/arel/algebra/extensions/object.rb +17 -0
  14. data/lib/arel/algebra/extensions/symbol.rb +9 -0
  15. data/lib/arel/algebra/predicates.rb +41 -0
  16. data/lib/arel/algebra/primitives.rb +5 -0
  17. data/lib/arel/algebra/primitives/attribute.rb +150 -0
  18. data/lib/arel/algebra/primitives/expression.rb +43 -0
  19. data/lib/arel/algebra/primitives/ordering.rb +23 -0
  20. data/lib/arel/algebra/primitives/value.rb +14 -0
  21. data/lib/arel/algebra/relations.rb +14 -0
  22. data/lib/arel/algebra/relations/operations/alias.rb +7 -0
  23. data/lib/arel/algebra/relations/operations/group.rb +12 -0
  24. data/lib/arel/algebra/relations/operations/join.rb +64 -0
  25. data/lib/arel/algebra/relations/operations/order.rb +18 -0
  26. data/lib/arel/algebra/relations/operations/project.rb +20 -0
  27. data/lib/arel/algebra/relations/operations/skip.rb +6 -0
  28. data/lib/arel/algebra/relations/operations/take.rb +10 -0
  29. data/lib/arel/algebra/relations/operations/where.rb +16 -0
  30. data/lib/arel/algebra/relations/relation.rb +136 -0
  31. data/lib/arel/algebra/relations/row.rb +26 -0
  32. data/lib/arel/algebra/relations/utilities/compound.rb +30 -0
  33. data/lib/arel/algebra/relations/utilities/externalization.rb +24 -0
  34. data/lib/arel/algebra/relations/utilities/nil.rb +7 -0
  35. data/lib/arel/algebra/relations/writes.rb +36 -0
  36. data/lib/arel/engines.rb +2 -0
  37. data/lib/arel/engines/memory.rb +4 -0
  38. data/lib/arel/engines/memory/engine.rb +16 -0
  39. data/lib/arel/engines/memory/predicates.rb +35 -0
  40. data/lib/arel/engines/memory/primitives.rb +27 -0
  41. data/lib/arel/engines/memory/relations.rb +5 -0
  42. data/lib/arel/engines/memory/relations/array.rb +25 -0
  43. data/lib/arel/engines/memory/relations/compound.rb +9 -0
  44. data/lib/arel/engines/memory/relations/operations.rb +61 -0
  45. data/lib/arel/engines/memory/relations/writes.rb +7 -0
  46. data/lib/arel/engines/sql.rb +7 -0
  47. data/lib/arel/engines/sql/christener.rb +13 -0
  48. data/lib/arel/engines/sql/engine.rb +37 -0
  49. data/lib/arel/engines/sql/extensions.rb +4 -0
  50. data/lib/arel/engines/sql/extensions/array.rb +16 -0
  51. data/lib/arel/engines/sql/extensions/nil_class.rb +11 -0
  52. data/lib/arel/engines/sql/extensions/object.rb +15 -0
  53. data/lib/arel/engines/sql/extensions/range.rb +15 -0
  54. data/lib/arel/engines/sql/formatters.rb +113 -0
  55. data/lib/arel/engines/sql/predicates.rb +51 -0
  56. data/lib/arel/engines/sql/primitives.rb +85 -0
  57. data/lib/arel/engines/sql/relations.rb +9 -0
  58. data/lib/arel/engines/sql/relations/operations/alias.rb +5 -0
  59. data/lib/arel/engines/sql/relations/operations/join.rb +33 -0
  60. data/lib/arel/engines/sql/relations/relation.rb +50 -0
  61. data/lib/arel/engines/sql/relations/table.rb +52 -0
  62. data/lib/arel/engines/sql/relations/utilities/compound.rb +10 -0
  63. data/lib/arel/engines/sql/relations/utilities/externalization.rb +14 -0
  64. data/lib/arel/engines/sql/relations/utilities/nil.rb +6 -0
  65. data/lib/arel/engines/sql/relations/utilities/recursion.rb +13 -0
  66. data/lib/arel/engines/sql/relations/writes.rb +39 -0
  67. data/lib/arel/session.rb +48 -0
  68. data/spec/arel/algebra/unit/predicates/binary_spec.rb +33 -0
  69. data/spec/arel/algebra/unit/predicates/equality_spec.rb +27 -0
  70. data/spec/arel/algebra/unit/predicates/in_spec.rb +10 -0
  71. data/spec/arel/algebra/unit/primitives/attribute_spec.rb +183 -0
  72. data/spec/arel/algebra/unit/primitives/expression_spec.rb +45 -0
  73. data/spec/arel/algebra/unit/primitives/value_spec.rb +15 -0
  74. data/spec/arel/algebra/unit/relations/alias_spec.rb +16 -0
  75. data/spec/arel/algebra/unit/relations/delete_spec.rb +9 -0
  76. data/spec/arel/algebra/unit/relations/group_spec.rb +10 -0
  77. data/spec/arel/algebra/unit/relations/insert_spec.rb +9 -0
  78. data/spec/arel/algebra/unit/relations/join_spec.rb +26 -0
  79. data/spec/arel/algebra/unit/relations/order_spec.rb +21 -0
  80. data/spec/arel/algebra/unit/relations/project_spec.rb +34 -0
  81. data/spec/arel/algebra/unit/relations/relation_spec.rb +188 -0
  82. data/spec/arel/algebra/unit/relations/skip_spec.rb +10 -0
  83. data/spec/arel/algebra/unit/relations/table_spec.rb +39 -0
  84. data/spec/arel/algebra/unit/relations/take_spec.rb +10 -0
  85. data/spec/arel/algebra/unit/relations/update_spec.rb +9 -0
  86. data/spec/arel/algebra/unit/relations/where_spec.rb +18 -0
  87. data/spec/arel/algebra/unit/session/session_spec.rb +84 -0
  88. data/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb +48 -0
  89. data/spec/arel/engines/memory/unit/relations/array_spec.rb +32 -0
  90. data/spec/arel/engines/memory/unit/relations/insert_spec.rb +28 -0
  91. data/spec/arel/engines/memory/unit/relations/join_spec.rb +31 -0
  92. data/spec/arel/engines/memory/unit/relations/order_spec.rb +27 -0
  93. data/spec/arel/engines/memory/unit/relations/project_spec.rb +27 -0
  94. data/spec/arel/engines/memory/unit/relations/skip_spec.rb +26 -0
  95. data/spec/arel/engines/memory/unit/relations/take_spec.rb +26 -0
  96. data/spec/arel/engines/memory/unit/relations/where_spec.rb +39 -0
  97. data/spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb +209 -0
  98. data/spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb +167 -0
  99. data/spec/arel/engines/sql/integration/joins/with_compounds_spec.rb +107 -0
  100. data/spec/arel/engines/sql/unit/engine_spec.rb +45 -0
  101. data/spec/arel/engines/sql/unit/predicates/binary_spec.rb +117 -0
  102. data/spec/arel/engines/sql/unit/predicates/equality_spec.rb +46 -0
  103. data/spec/arel/engines/sql/unit/predicates/in_spec.rb +86 -0
  104. data/spec/arel/engines/sql/unit/predicates/predicates_spec.rb +65 -0
  105. data/spec/arel/engines/sql/unit/primitives/attribute_spec.rb +32 -0
  106. data/spec/arel/engines/sql/unit/primitives/expression_spec.rb +24 -0
  107. data/spec/arel/engines/sql/unit/primitives/literal_spec.rb +23 -0
  108. data/spec/arel/engines/sql/unit/primitives/value_spec.rb +29 -0
  109. data/spec/arel/engines/sql/unit/relations/alias_spec.rb +43 -0
  110. data/spec/arel/engines/sql/unit/relations/delete_spec.rb +63 -0
  111. data/spec/arel/engines/sql/unit/relations/group_spec.rb +56 -0
  112. data/spec/arel/engines/sql/unit/relations/insert_spec.rb +107 -0
  113. data/spec/arel/engines/sql/unit/relations/join_spec.rb +57 -0
  114. data/spec/arel/engines/sql/unit/relations/order_spec.rb +113 -0
  115. data/spec/arel/engines/sql/unit/relations/project_spec.rb +110 -0
  116. data/spec/arel/engines/sql/unit/relations/skip_spec.rb +32 -0
  117. data/spec/arel/engines/sql/unit/relations/table_spec.rb +69 -0
  118. data/spec/arel/engines/sql/unit/relations/take_spec.rb +32 -0
  119. data/spec/arel/engines/sql/unit/relations/update_spec.rb +151 -0
  120. data/spec/arel/engines/sql/unit/relations/where_spec.rb +56 -0
  121. data/spec/connections/mysql_connection.rb +16 -0
  122. data/spec/connections/postgresql_connection.rb +15 -0
  123. data/spec/connections/sqlite3_connection.rb +25 -0
  124. data/spec/doubles/hash.rb +23 -0
  125. data/spec/matchers/be_like.rb +24 -0
  126. data/spec/matchers/disambiguate_attributes.rb +28 -0
  127. data/spec/matchers/hash_the_same_as.rb +26 -0
  128. data/spec/schemas/mysql_schema.rb +18 -0
  129. data/spec/schemas/postgresql_schema.rb +18 -0
  130. data/spec/schemas/sqlite3_schema.rb +18 -0
  131. data/spec/spec_helper.rb +47 -0
  132. metadata +250 -0
@@ -0,0 +1,27 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe Equality do
5
+ before do
6
+ @relation1 = Table.new(:users)
7
+ @relation2 = Table.new(:photos)
8
+ @attribute1 = @relation1[:id]
9
+ @attribute2 = @relation2[:user_id]
10
+ end
11
+
12
+ describe '==' do
13
+ it "obtains if attribute1 and attribute2 are identical" do
14
+ Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute1, @attribute2)
15
+ Equality.new(@attribute1, @attribute2).should_not == Equality.new(@attribute1, @attribute1)
16
+ end
17
+
18
+ it "obtains if the concrete type of the predicates are identical" do
19
+ Equality.new(@attribute1, @attribute2).should_not == Binary.new(@attribute1, @attribute2)
20
+ end
21
+
22
+ it "is commutative on the attributes" do
23
+ Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute2, @attribute1)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,10 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe In do
5
+ before do
6
+ @relation = Table.new(:users)
7
+ @attribute = @relation[:id]
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,183 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe Attribute do
5
+ before do
6
+ @relation = Table.new(:users)
7
+ @attribute = @relation[:id]
8
+ end
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
17
+ describe '#as' do
18
+ it "manufactures an aliased attributed" do
19
+ @attribute.as(:alias).should == Attribute.new(@relation, @attribute.name, :alias => :alias, :ancestor => @attribute)
20
+ end
21
+ end
22
+
23
+ describe '#bind' do
24
+ it "manufactures an attribute with the relation bound and self as an ancestor" do
25
+ derived_relation = @relation.where(@relation[:id].eq(1))
26
+ @attribute.bind(derived_relation).should == Attribute.new(derived_relation, @attribute.name, :ancestor => @attribute)
27
+ end
28
+
29
+ it "returns self if the substituting to the same relation" do
30
+ @attribute.bind(@relation).should == @attribute
31
+ end
32
+ end
33
+
34
+ describe '#to_attribute' do
35
+ describe 'when the given relation is the same as the attributes relation' do
36
+ it "returns self" do
37
+ @attribute.to_attribute(@relation).should == @attribute
38
+ end
39
+ end
40
+
41
+ describe 'when the given relation differs from the attributes relation' do
42
+ it 'binds to the new relation' do
43
+ @attribute.to_attribute(new_relation = @relation.alias).should == @attribute.bind(new_relation)
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ describe '#column' do
50
+ it "returns the corresponding column in the relation" do
51
+ @attribute.column.should == @relation.column_for(@attribute)
52
+ end
53
+ end
54
+
55
+ describe '#engine' do
56
+ it "delegates to its relation" do
57
+ Attribute.new(@relation, :id).engine.should == @relation.engine
58
+ end
59
+ end
60
+
61
+ describe Attribute::Congruence do
62
+ describe '/' do
63
+ before do
64
+ @aliased_relation = @relation.alias
65
+ @doubly_aliased_relation = @aliased_relation.alias
66
+ end
67
+
68
+ describe 'when dividing two unrelated attributes' do
69
+ it "returns 0.0" do
70
+ (@relation[:id] / @relation[:name]).should == 0.0
71
+ end
72
+ end
73
+
74
+ describe 'when dividing two matching attributes' do
75
+ it 'returns a the highest score for the most similar attributes' do
76
+ (@aliased_relation[:id] / @relation[:id]) \
77
+ .should == (@aliased_relation[:id] / @relation[:id])
78
+ (@aliased_relation[:id] / @relation[:id]) \
79
+ .should < (@aliased_relation[:id] / @aliased_relation[:id])
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ describe Attribute::Predications do
86
+ before do
87
+ @attribute = Attribute.new(@relation, :name)
88
+ end
89
+
90
+ describe '#eq' do
91
+ it "manufactures an equality predicate" do
92
+ @attribute.eq('name').should == Equality.new(@attribute, 'name')
93
+ end
94
+ end
95
+
96
+ describe '#lt' do
97
+ it "manufactures a less-than predicate" do
98
+ @attribute.lt(10).should == LessThan.new(@attribute, 10)
99
+ end
100
+ end
101
+
102
+ describe '#lteq' do
103
+ it "manufactures a less-than or equal-to predicate" do
104
+ @attribute.lteq(10).should == LessThanOrEqualTo.new(@attribute, 10)
105
+ end
106
+ end
107
+
108
+ describe '#gt' do
109
+ it "manufactures a greater-than predicate" do
110
+ @attribute.gt(10).should == GreaterThan.new(@attribute, 10)
111
+ end
112
+ end
113
+
114
+ describe '#gteq' do
115
+ it "manufactures a greater-than or equal-to predicate" do
116
+ @attribute.gteq(10).should == GreaterThanOrEqualTo.new(@attribute, 10)
117
+ end
118
+ end
119
+
120
+ describe '#matches' do
121
+ it "manufactures a match predicate" do
122
+ @attribute.matches(/.*/).should == Match.new(@attribute, /.*/)
123
+ end
124
+ end
125
+
126
+ describe '#in' do
127
+ it "manufactures an in predicate" do
128
+ @attribute.in(1..30).should == In.new(@attribute, (1..30))
129
+ end
130
+ end
131
+ end
132
+
133
+ describe Attribute::Expressions do
134
+ before do
135
+ @attribute = Attribute.new(@relation, :name)
136
+ end
137
+
138
+ describe '#count' do
139
+ it "manufactures a count Expression" do
140
+ @attribute.count.should == Count.new(@attribute)
141
+ end
142
+ end
143
+
144
+ describe '#sum' do
145
+ it "manufactures a sum Expression" do
146
+ @attribute.sum.should == Sum.new(@attribute)
147
+ end
148
+ end
149
+
150
+ describe '#maximum' do
151
+ it "manufactures a maximum Expression" do
152
+ @attribute.maximum.should == Maximum.new(@attribute)
153
+ end
154
+ end
155
+
156
+ describe '#minimum' do
157
+ it "manufactures a minimum Expression" do
158
+ @attribute.minimum.should == Minimum.new(@attribute)
159
+ end
160
+ end
161
+
162
+ describe '#average' do
163
+ it "manufactures an average Expression" do
164
+ @attribute.average.should == Average.new(@attribute)
165
+ end
166
+ end
167
+ end
168
+
169
+ describe Attribute::Orderings do
170
+ describe '#asc' do
171
+ it 'manufactures an ascending ordering' do
172
+ @attribute.asc.should == Ascending.new(@attribute)
173
+ end
174
+ end
175
+
176
+ describe '#desc' do
177
+ it 'manufactures a descending ordering' do
178
+ @attribute.desc.should == Descending.new(@attribute)
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,45 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe Expression do
5
+ before do
6
+ @relation = Table.new(:users)
7
+ @attribute = @relation[:id]
8
+ end
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
17
+ before do
18
+ @expression = Count.new(@attribute)
19
+ end
20
+
21
+ describe '#bind' do
22
+ it "manufactures an attribute with a rebound relation and self as the ancestor" do
23
+ derived_relation = @relation.where(@relation[:id].eq(1))
24
+ @expression.bind(derived_relation).should == Count.new(@attribute.bind(derived_relation), nil, @expression)
25
+ end
26
+
27
+ it "returns self if the substituting to the same relation" do
28
+ @expression.bind(@relation).should == @expression
29
+ end
30
+ end
31
+
32
+ describe '#as' do
33
+ it "manufactures an aliased expression" do
34
+ @expression.as(:alias).should == Expression.new(@attribute, :alias, @expression)
35
+ end
36
+ end
37
+
38
+ describe '#to_attribute' do
39
+ it "manufactures an attribute with the expression as an ancestor" do
40
+ @expression.to_attribute(@relation).should == Attribute.new(@relation, @expression.alias, :ancestor => @expression)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,15 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe Value do
5
+ before do
6
+ @relation = Table.new(:users)
7
+ end
8
+
9
+ describe '#bind' do
10
+ it "manufactures a new value whose relation is the provided relation" do
11
+ Value.new(1, @relation).bind(another_relation = Table.new(:photos)).should == Value.new(1, another_relation)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe Alias do
5
+ before do
6
+ @relation = Table.new(:users)
7
+ end
8
+
9
+ describe '==' do
10
+ it "obtains if the objects are the same" do
11
+ Alias.new(@relation).should_not == Alias.new(@relation)
12
+ (aliaz = Alias.new(@relation)).should == aliaz
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,9 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe Deletion do
5
+ before do
6
+ @relation = Table.new(:users)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe Group do
5
+ before do
6
+ @relation = Table.new(:users)
7
+ @attribute = @relation[:id]
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe Insert do
5
+ before do
6
+ @relation = Table.new(:users)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,26 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe Join do
5
+ before do
6
+ @relation1 = Table.new(:users)
7
+ @relation2 = Table.new(:photos)
8
+ @predicate = @relation1[:id].eq(@relation2[:user_id])
9
+ end
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
+ describe '#attributes' do
19
+ it 'combines the attributes of the two relations' do
20
+ join = InnerJoin.new(@relation1, @relation2, @predicate)
21
+ join.attributes.should ==
22
+ (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(join) }
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,21 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe Order do
5
+ before do
6
+ @relation = Table.new(:users)
7
+ @attribute = @relation[:id]
8
+ end
9
+
10
+ describe "#==" do
11
+ it "returns true when the Orders are for the same attribute and direction" do
12
+ Ascending.new(@attribute).should == Ascending.new(@attribute)
13
+ end
14
+
15
+ it "returns false when the Orders are for a diferent direction" do
16
+ Ascending.new(@attribute).should_not == Descending.new(@attribute)
17
+ end
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,34 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe Project do
5
+ before do
6
+ @relation = Table.new(:users)
7
+ @attribute = @relation[:id]
8
+ end
9
+
10
+ describe '#attributes' do
11
+ before do
12
+ @projection = Project.new(@relation, @attribute)
13
+ end
14
+
15
+ it "manufactures attributes associated with the projection relation" do
16
+ @projection.attributes.should == [@attribute].collect { |a| a.bind(@projection) }
17
+ end
18
+ end
19
+
20
+ describe '#externalizable?' do
21
+ describe 'when the projections are attributes' do
22
+ it 'returns false' do
23
+ Project.new(@relation, @attribute).should_not be_externalizable
24
+ end
25
+ end
26
+
27
+ describe 'when the projections include an aggregation' do
28
+ it "obtains" do
29
+ Project.new(@relation, @attribute.sum).should be_externalizable
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,188 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe Relation do
5
+ before do
6
+ @relation = Table.new(:users)
7
+ @attribute1 = @relation[:id]
8
+ @attribute2 = @relation[:name]
9
+ end
10
+
11
+ describe '[]' do
12
+ describe 'when given an', Attribute do
13
+ it "return the attribute congruent to the provided attribute" do
14
+ @relation[@attribute1].should == @attribute1
15
+ end
16
+ end
17
+
18
+ describe 'when given a', Symbol, String do
19
+ it "returns the attribute with the same name, if it exists" do
20
+ @relation[:id].should == @attribute1
21
+ @relation['id'].should == @attribute1
22
+ @relation[:does_not_exist].should be_nil
23
+ end
24
+ end
25
+ end
26
+
27
+ describe Relation::Operable do
28
+ describe 'joins' do
29
+ before do
30
+ @predicate = @relation[:id].eq(@relation[:id])
31
+ end
32
+
33
+ describe '#join' do
34
+ describe 'when given a relation' do
35
+ it "manufactures an inner join operation between those two relations" do
36
+ @relation.join(@relation).on(@predicate). \
37
+ should == InnerJoin.new(@relation, @relation, @predicate)
38
+ end
39
+ end
40
+
41
+ describe "when given a string" do
42
+ it "manufactures a join operation with the string passed through" do
43
+ @relation.join(arbitrary_string = "ASDF").should == StringJoin.new(@relation, arbitrary_string)
44
+ end
45
+ end
46
+
47
+ describe "when given something blank" do
48
+ it "returns self" do
49
+ @relation.join.should == @relation
50
+ end
51
+ end
52
+ end
53
+
54
+ describe '#outer_join' do
55
+ it "manufactures a left outer join operation between those two relations" do
56
+ @relation.outer_join(@relation).on(@predicate). \
57
+ should == OuterJoin.new(@relation, @relation, @predicate)
58
+ end
59
+ end
60
+ end
61
+
62
+ describe '#project' do
63
+ it "manufactures a projection relation" do
64
+ @relation.project(@attribute1, @attribute2). \
65
+ should == Project.new(@relation, @attribute1, @attribute2)
66
+ end
67
+
68
+ describe "when given blank attributes" do
69
+ it "returns self" do
70
+ @relation.project.should == @relation
71
+ end
72
+ end
73
+ end
74
+
75
+ describe '#alias' do
76
+ it "manufactures an alias relation" do
77
+ @relation.alias.relation.should == Alias.new(@relation).relation
78
+ end
79
+ end
80
+
81
+ describe '#where' do
82
+ before do
83
+ @predicate = Equality.new(@attribute1, @attribute2)
84
+ end
85
+
86
+ it "manufactures a where relation" do
87
+ @relation.where(@predicate).should == Where.new(@relation, @predicate)
88
+ end
89
+
90
+ it "accepts arbitrary strings" do
91
+ @relation.where("arbitrary").should == Where.new(@relation, "arbitrary")
92
+ end
93
+
94
+ describe 'when given a blank predicate' do
95
+ it 'returns self' do
96
+ @relation.where.should == @relation
97
+ end
98
+ end
99
+ end
100
+
101
+ describe '#order' do
102
+ it "manufactures an order relation" do
103
+ @relation.order(@attribute1, @attribute2).should == Order.new(@relation, @attribute1, @attribute2)
104
+ end
105
+
106
+ describe 'when given a blank ordering' do
107
+ it 'returns self' do
108
+ @relation.order.should == @relation
109
+ end
110
+ end
111
+ end
112
+
113
+ describe '#take' do
114
+ it "manufactures a take relation" do
115
+ @relation.take(5).should == Take.new(@relation, 5)
116
+ end
117
+
118
+ describe 'when given a blank number of items' do
119
+ it 'returns self' do
120
+ @relation.take.should == @relation
121
+ end
122
+ end
123
+ end
124
+
125
+ describe '#skip' do
126
+ it "manufactures a skip relation" do
127
+ @relation.skip(4).should == Skip.new(@relation, 4)
128
+ end
129
+
130
+ describe 'when given a blank number of items' do
131
+ it 'returns self' do
132
+ @relation.skip.should == @relation
133
+ end
134
+ end
135
+ end
136
+
137
+ describe '#group' do
138
+ it 'manufactures a group relation' do
139
+ @relation.group(@attribute1, @attribute2).should == Group.new(@relation, @attribute1, @attribute2)
140
+ end
141
+
142
+ describe 'when given blank groupings' do
143
+ it 'returns self' do
144
+ @relation.group.should == @relation
145
+ end
146
+ end
147
+ end
148
+
149
+ describe Relation::Operable::Writable do
150
+ describe '#delete' do
151
+ it 'manufactures a deletion relation' do
152
+ Session.start do
153
+ mock(Session.new).delete(Deletion.new(@relation))
154
+ @relation.delete
155
+ end
156
+ end
157
+ end
158
+
159
+ describe '#insert' do
160
+ it 'manufactures an insertion relation' do
161
+ Session.start do
162
+ record = { @relation[:name] => 'carl' }
163
+ mock(Session.new).create(Insert.new(@relation, record))
164
+ @relation.insert(record)
165
+ end
166
+ end
167
+ end
168
+
169
+ describe '#update' do
170
+ it 'manufactures an update relation' do
171
+ Session.start do
172
+ assignments = { @relation[:name] => Value.new('bob', @relation) }
173
+ mock(Session.new).update(Update.new(@relation, assignments))
174
+ @relation.update(assignments)
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
180
+
181
+ describe Relation::Enumerable do
182
+ it "implements enumerable" do
183
+ @relation.collect.should == @relation.session.read(@relation).collect
184
+ @relation.first.should == @relation.session.read(@relation).first
185
+ end
186
+ end
187
+ end
188
+ end