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,209 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe Join do
5
+ before do
6
+ @relation1 = Table(:users)
7
+ @relation2 = @relation1.alias
8
+ @predicate = @relation1[:id].eq(@relation2[:id])
9
+ end
10
+
11
+ describe 'when joining a relation to itself' do
12
+ describe '#to_sql' do
13
+ it 'manufactures sql aliasing the table and attributes properly in the join predicate and the where clause' do
14
+ sql = @relation1.join(@relation2).on(@predicate).to_sql
15
+
16
+ adapter_is :mysql do
17
+ sql.should be_like(%Q{
18
+ SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`
19
+ FROM `users`
20
+ INNER JOIN `users` AS `users_2`
21
+ ON `users`.`id` = `users_2`.`id`
22
+ })
23
+ end
24
+
25
+ adapter_is_not :mysql do
26
+ sql.should be_like(%Q{
27
+ SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name"
28
+ FROM "users"
29
+ INNER JOIN "users" AS "users_2"
30
+ ON "users"."id" = "users_2"."id"
31
+ })
32
+ end
33
+ end
34
+
35
+ describe 'when joining with a where on the same relation' do
36
+ it 'manufactures sql aliasing the tables properly' do
37
+ sql = @relation1 \
38
+ .join(@relation2.where(@relation2[:id].eq(1))) \
39
+ .on(@predicate) \
40
+ .to_sql
41
+
42
+ adapter_is :mysql do
43
+ sql.should be_like(%Q{
44
+ SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`
45
+ FROM `users`
46
+ INNER JOIN `users` AS `users_2`
47
+ ON `users`.`id` = `users_2`.`id` AND `users_2`.`id` = 1
48
+ })
49
+ end
50
+
51
+ adapter_is_not :mysql do
52
+ sql.should be_like(%Q{
53
+ SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name"
54
+ FROM "users"
55
+ INNER JOIN "users" AS "users_2"
56
+ ON "users"."id" = "users_2"."id" AND "users_2"."id" = 1
57
+ })
58
+ end
59
+ end
60
+
61
+ describe 'when the where occurs before the alias' do
62
+ it 'manufactures sql aliasing the predicates properly' do
63
+ relation2 = @relation1.where(@relation1[:id].eq(1)).alias
64
+
65
+ sql = @relation1 \
66
+ .join(relation2) \
67
+ .on(relation2[:id].eq(@relation1[:id])) \
68
+ .to_sql
69
+
70
+ adapter_is :mysql do
71
+ sql.should be_like(%Q{
72
+ SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`
73
+ FROM `users`
74
+ INNER JOIN `users` AS `users_2`
75
+ ON `users_2`.`id` = `users`.`id` AND `users_2`.`id` = 1
76
+ })
77
+ end
78
+
79
+ adapter_is_not :mysql do
80
+ sql.should be_like(%Q{
81
+ SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name"
82
+ FROM "users"
83
+ INNER JOIN "users" AS "users_2"
84
+ ON "users_2"."id" = "users"."id" AND "users_2"."id" = 1
85
+ })
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ describe 'when joining the relation to itself multiple times' do
92
+ before do
93
+ @relation3 = @relation1.alias
94
+ end
95
+
96
+ describe 'when joining left-associatively' do
97
+ it 'manufactures sql aliasing the tables properly' do
98
+ sql = @relation1 \
99
+ .join(@relation2 \
100
+ .join(@relation3) \
101
+ .on(@relation2[:id].eq(@relation3[:id]))) \
102
+ .on(@relation1[:id].eq(@relation2[:id])) \
103
+ .to_sql
104
+
105
+ adapter_is :mysql do
106
+ sql.should be_like(%Q{
107
+ SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name`
108
+ FROM `users`
109
+ INNER JOIN `users` AS `users_2`
110
+ ON `users`.`id` = `users_2`.`id`
111
+ INNER JOIN `users` AS `users_3`
112
+ ON `users_2`.`id` = `users_3`.`id`
113
+ })
114
+ end
115
+
116
+ adapter_is_not :mysql do
117
+ sql.should be_like(%Q{
118
+ SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name", "users_3"."id", "users_3"."name"
119
+ FROM "users"
120
+ INNER JOIN "users" AS "users_2"
121
+ ON "users"."id" = "users_2"."id"
122
+ INNER JOIN "users" AS "users_3"
123
+ ON "users_2"."id" = "users_3"."id"
124
+ })
125
+ end
126
+ end
127
+ end
128
+
129
+ describe 'when joining right-associatively' do
130
+ it 'manufactures sql aliasing the tables properly' do
131
+ sql = @relation1 \
132
+ .join(@relation2).on(@relation1[:id].eq(@relation2[:id])) \
133
+ .join(@relation3).on(@relation2[:id].eq(@relation3[:id])) \
134
+ .to_sql
135
+
136
+ adapter_is :mysql do
137
+ sql.should be_like(%Q{
138
+ SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name`
139
+ FROM `users`
140
+ INNER JOIN `users` AS `users_2`
141
+ ON `users`.`id` = `users_2`.`id`
142
+ INNER JOIN `users` AS `users_3`
143
+ ON `users_2`.`id` = `users_3`.`id`
144
+ })
145
+ end
146
+
147
+ adapter_is_not :mysql do
148
+ sql.should be_like(%Q{
149
+ SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name", "users_3"."id", "users_3"."name"
150
+ FROM "users"
151
+ INNER JOIN "users" AS "users_2"
152
+ ON "users"."id" = "users_2"."id"
153
+ INNER JOIN "users" AS "users_3"
154
+ ON "users_2"."id" = "users_3"."id"
155
+ })
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+ describe '[]' do
163
+ describe 'when given an attribute belonging to both sub-relations' do
164
+ it 'disambiguates the relation that serves as the ancestor to the attribute' do
165
+ @relation1 \
166
+ .join(@relation2) \
167
+ .on(@predicate) \
168
+ .should disambiguate_attributes(@relation1[:id], @relation2[:id])
169
+ end
170
+
171
+ describe 'when both relations are compound and only one is an alias' do
172
+ it 'disambiguates the relation that serves as the ancestor to the attribute' do
173
+ compound1 = @relation1.where(@predicate)
174
+ compound2 = compound1.alias
175
+ compound1 \
176
+ .join(compound2) \
177
+ .on(@predicate) \
178
+ .should disambiguate_attributes(compound1[:id], compound2[:id])
179
+ end
180
+ end
181
+
182
+ describe 'when the left relation is extremely compound' do
183
+ it 'disambiguates the relation that serves as the ancestor to the attribute' do
184
+ @relation1 \
185
+ .where(@predicate) \
186
+ .where(@predicate) \
187
+ .join(@relation2) \
188
+ .on(@predicate) \
189
+ .should disambiguate_attributes(@relation1[:id], @relation2[:id])
190
+ end
191
+ end
192
+
193
+ describe 'when the right relation is extremely compound' do
194
+ it 'disambiguates the relation that serves as the ancestor to the attribute' do
195
+ @relation1 \
196
+ .join( \
197
+ @relation2 \
198
+ .where(@predicate) \
199
+ .where(@predicate) \
200
+ .where(@predicate)) \
201
+ .on(@predicate) \
202
+ .should disambiguate_attributes(@relation1[:id], @relation2[:id])
203
+ end
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,167 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe Join do
5
+ before do
6
+ @relation1 = Table(:users)
7
+ @relation2 = Table(:photos)
8
+ @predicate = @relation1[:id].eq(@relation2[:user_id])
9
+ end
10
+
11
+ describe 'when joining aggregated relations' do
12
+ before do
13
+ @aggregation = @relation2 \
14
+ .group(@relation2[:user_id]) \
15
+ .project(@relation2[:user_id], @relation2[:id].count.as(:cnt)) \
16
+ end
17
+
18
+ describe '#to_sql' do
19
+ # CLEANUP
20
+ it '' do
21
+ sql = @relation1.join(@relation2.take(3)).on(@predicate).to_sql
22
+
23
+ adapter_is :mysql do
24
+ sql.should be_like(%Q{
25
+ SELECT `users`.`id`, `users`.`name`, `photos_external`.`id`, `photos_external`.`user_id`, `photos_external`.`camera_id`
26
+ FROM `users`
27
+ INNER JOIN (SELECT `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `photos` LIMIT 3) AS `photos_external`
28
+ ON `users`.`id` = `photos_external`.`user_id`
29
+ })
30
+ end
31
+
32
+ adapter_is_not :mysql do
33
+ sql.should be_like(%Q{
34
+ SELECT "users"."id", "users"."name", "photos_external"."id", "photos_external"."user_id", "photos_external"."camera_id"
35
+ FROM "users"
36
+ INNER JOIN (SELECT "photos"."id", "photos"."user_id", "photos"."camera_id" FROM "photos" LIMIT 3) AS "photos_external"
37
+ ON "users"."id" = "photos_external"."user_id"
38
+ })
39
+ end
40
+ end
41
+
42
+ describe 'with the aggregation on the right' do
43
+ it 'manufactures sql joining the left table to a derived table' do
44
+ sql = @relation1.join(@aggregation).on(@predicate).to_sql
45
+
46
+ adapter_is :mysql do
47
+ sql.should be_like(%Q{
48
+ SELECT `users`.`id`, `users`.`name`, `photos_external`.`user_id`, `photos_external`.`cnt`
49
+ FROM `users`
50
+ INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external`
51
+ ON `users`.`id` = `photos_external`.`user_id`
52
+ })
53
+ end
54
+
55
+ adapter_is_not :mysql do
56
+ sql.should be_like(%Q{
57
+ SELECT "users"."id", "users"."name", "photos_external"."user_id", "photos_external"."cnt"
58
+ FROM "users"
59
+ INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external"
60
+ ON "users"."id" = "photos_external"."user_id"
61
+ })
62
+ end
63
+ end
64
+ end
65
+
66
+ describe 'with the aggregation on the left' do
67
+ it 'manufactures sql joining the right table to a derived table' do
68
+ sql = @aggregation.join(@relation1).on(@predicate).to_sql
69
+
70
+ adapter_is :mysql do
71
+ sql.should be_like(%Q{
72
+ SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `users`.`id`, `users`.`name`
73
+ FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external`
74
+ INNER JOIN `users`
75
+ ON `users`.`id` = `photos_external`.`user_id`
76
+ })
77
+ end
78
+
79
+ adapter_is_not :mysql do
80
+ sql.should be_like(%Q{
81
+ SELECT "photos_external"."user_id", "photos_external"."cnt", "users"."id", "users"."name"
82
+ FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external"
83
+ INNER JOIN "users"
84
+ ON "users"."id" = "photos_external"."user_id"
85
+ })
86
+ end
87
+ end
88
+ end
89
+
90
+ describe 'with the aggregation on both sides' do
91
+ it 'it properly aliases the aggregations' do
92
+ aggregation2 = @aggregation.alias
93
+ sql = @aggregation.join(aggregation2).on(aggregation2[:user_id].eq(@aggregation[:user_id])).to_sql
94
+
95
+ adapter_is :mysql do
96
+ sql.should be_like(%Q{
97
+ SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `photos_external_2`.`user_id`, `photos_external_2`.`cnt`
98
+ FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external`
99
+ INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external_2`
100
+ ON `photos_external_2`.`user_id` = `photos_external`.`user_id`
101
+ })
102
+ end
103
+
104
+ adapter_is_not :mysql do
105
+ sql.should be_like(%Q{
106
+ SELECT "photos_external"."user_id", "photos_external"."cnt", "photos_external_2"."user_id", "photos_external_2"."cnt"
107
+ FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external"
108
+ INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external_2"
109
+ ON "photos_external_2"."user_id" = "photos_external"."user_id"
110
+ })
111
+ end
112
+ end
113
+ end
114
+
115
+ describe 'when the aggration has a where' do
116
+ describe 'with the aggregation on the left' do
117
+ it "manufactures sql keeping wheres on the aggregation within the derived table" do
118
+ sql = @relation1.join(@aggregation.where(@aggregation[:user_id].eq(1))).on(@predicate).to_sql
119
+
120
+ adapter_is :mysql do
121
+ sql.should be_like(%Q{
122
+ SELECT `users`.`id`, `users`.`name`, `photos_external`.`user_id`, `photos_external`.`cnt`
123
+ FROM `users`
124
+ INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_external`
125
+ ON `users`.`id` = `photos_external`.`user_id`
126
+ })
127
+ end
128
+
129
+ adapter_is_not :mysql do
130
+ sql.should be_like(%Q{
131
+ SELECT "users"."id", "users"."name", "photos_external"."user_id", "photos_external"."cnt"
132
+ FROM "users"
133
+ INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" WHERE "photos"."user_id" = 1 GROUP BY "photos"."user_id") AS "photos_external"
134
+ ON "users"."id" = "photos_external"."user_id"
135
+ })
136
+ end
137
+ end
138
+ end
139
+
140
+ describe 'with the aggregation on the right' do
141
+ it "manufactures sql keeping wheres on the aggregation within the derived table" do
142
+ sql = @aggregation.where(@aggregation[:user_id].eq(1)).join(@relation1).on(@predicate).to_sql
143
+
144
+ adapter_is :mysql do
145
+ sql.should be_like(%Q{
146
+ SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `users`.`id`, `users`.`name`
147
+ FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_external`
148
+ INNER JOIN `users`
149
+ ON `users`.`id` = `photos_external`.`user_id`
150
+ })
151
+ end
152
+
153
+ adapter_is_not :mysql do
154
+ sql.should be_like(%Q{
155
+ SELECT "photos_external"."user_id", "photos_external"."cnt", "users"."id", "users"."name"
156
+ FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" WHERE "photos"."user_id" = 1 GROUP BY "photos"."user_id") AS "photos_external"
157
+ INNER JOIN "users"
158
+ ON "users"."id" = "photos_external"."user_id"
159
+ })
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,107 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper')
2
+
3
+ module Arel
4
+ describe Join do
5
+ before do
6
+ @relation1 = Table(:users)
7
+ @relation2 = Table(:photos)
8
+ @predicate = @relation1[:id].eq(@relation2[:user_id])
9
+ end
10
+
11
+ describe '#to_sql' do
12
+ describe 'when the join contains a where' do
13
+ describe 'and the where is given a string' do
14
+ it 'does not escape the string' do
15
+ sql = @relation1 \
16
+ .join(@relation2.where("asdf")) \
17
+ .on(@predicate) \
18
+ .to_sql
19
+
20
+ adapter_is :mysql do
21
+ sql.should be_like(%Q{
22
+ SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id`
23
+ FROM `users`
24
+ INNER JOIN `photos`
25
+ ON `users`.`id` = `photos`.`user_id` AND asdf
26
+ })
27
+ end
28
+
29
+ adapter_is_not :mysql do
30
+ sql.should be_like(%Q{
31
+ SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id"
32
+ FROM "users"
33
+ INNER JOIN "photos"
34
+ ON "users"."id" = "photos"."user_id" AND asdf
35
+ })
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ describe 'when a compound contains a join' do
42
+ describe 'and the compound is a where' do
43
+ it 'manufactures sql disambiguating the tables' do
44
+ sql = @relation1 \
45
+ .where(@relation1[:id].eq(1)) \
46
+ .join(@relation2) \
47
+ .on(@predicate) \
48
+ .where(@relation1[:id].eq(1)) \
49
+ .to_sql
50
+
51
+ adapter_is :mysql do
52
+ sql.should be_like(%Q{
53
+ SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id`
54
+ FROM `users`
55
+ INNER JOIN `photos`
56
+ ON `users`.`id` = `photos`.`user_id`
57
+ WHERE `users`.`id` = 1
58
+ AND `users`.`id` = 1
59
+ })
60
+ end
61
+
62
+ adapter_is_not :mysql do
63
+ sql.should be_like(%Q{
64
+ SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id"
65
+ FROM "users"
66
+ INNER JOIN "photos"
67
+ ON "users"."id" = "photos"."user_id"
68
+ WHERE "users"."id" = 1
69
+ AND "users"."id" = 1
70
+ })
71
+ end
72
+ end
73
+ end
74
+
75
+ describe 'and the compound is a group' do
76
+ it 'manufactures sql disambiguating the tables' do
77
+ sql = @relation1 \
78
+ .join(@relation2) \
79
+ .on(@predicate) \
80
+ .group(@relation1[:id]) \
81
+ .to_sql
82
+
83
+ adapter_is :mysql do
84
+ sql.should be_like(%Q{
85
+ SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id`
86
+ FROM `users`
87
+ INNER JOIN `photos`
88
+ ON `users`.`id` = `photos`.`user_id`
89
+ GROUP BY `users`.`id`
90
+ })
91
+ end
92
+
93
+ adapter_is_not :mysql do
94
+ sql.should be_like(%Q{
95
+ SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id"
96
+ FROM "users"
97
+ INNER JOIN "photos"
98
+ ON "users"."id" = "photos"."user_id"
99
+ GROUP BY "users"."id"
100
+ })
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end