19
19
use PDOStatement ;
20
20
use Closure ;
21
21
use DateTime ;
22
+ use Throwable ;
22
23
23
24
final class ResultShouldNotBeAffectedByOptimizationTest extends TestCase
24
25
{
@@ -116,10 +117,26 @@ public function tearDown(): void
116
117
* @test
117
118
* @dataProvider generateTestData
118
119
*/
119
- public function resultShouldNotBeAffectedByOptimization (string $ originalSql ): void
120
+ public function resultShouldNotBeAffectedByOptimization (string $ originalSql, bool $ expectSqlChange = null ): void
120
121
{
122
+ if ($ this ->pdo ->getAttribute (PDO ::ATTR_DRIVER_NAME ) === 'sqlite ' ) {
123
+ if (is_int (strpos ($ originalSql , 'RIGHT JOIN ' ))) {
124
+ $ this ->markTestSkipped ('Sqlite apparently does not support RIGHT JOIN?! ' );
125
+ }
126
+ if (is_int (strpos ($ originalSql , 'OUTER JOIN ' ))) {
127
+ $ this ->markTestSkipped ('Sqlite also does not support OUTER join .. :-/ ' );
128
+ }
129
+ }
130
+
121
131
/** @var string $optimizedSql */
122
132
$ optimizedSql = $ this ->optimizer ->optimizeSql ($ originalSql , $ this ->schemas );
133
+
134
+ if ($ expectSqlChange ) {
135
+ $ this ->assertNotEquals ($ originalSql , $ optimizedSql );
136
+
137
+ } elseif ($ expectSqlChange === false ) {
138
+ $ this ->assertEquals ($ originalSql , $ optimizedSql );
139
+ }
123
140
124
141
/** @var PDOStatement|false $originalStatement */
125
142
$ originalStatement = $ this ->pdo ->prepare ($ originalSql );
@@ -139,7 +156,18 @@ public function resultShouldNotBeAffectedByOptimization(string $originalSql): vo
139
156
/** @var array<array<string, string>> $actualResult */
140
157
$ actualResult = $ optimizedStatement ->fetchAll (PDO ::FETCH_ASSOC );
141
158
142
- $ this ->assertEquals ($ expectedResult , $ actualResult );
159
+ try {
160
+ $ this ->assertEquals ($ expectedResult , $ actualResult );
161
+
162
+ } catch (Throwable $ exception ) {
163
+ echo sprintf (
164
+ "\nOriginal (expected) SQL: <%s>, Optimized (actual) SQL: <%s> " ,
165
+ $ originalSql ,
166
+ $ optimizedSql
167
+ );
168
+
169
+ throw $ exception ;
170
+ }
143
171
}
144
172
145
173
public function generateTestData (): array
@@ -154,36 +182,36 @@ public function generateTestData(): array
154
182
SELECT *
155
183
FROM ratings r
156
184
LEFT JOIN sales s ON(s.id = r.sale_id)
157
- SQL ];
185
+ SQL , false ];
158
186
159
187
# Nullable ONE-to-ONE
160
188
$ tests [] = [<<<SQL
161
189
SELECT *
162
190
FROM articles a
163
191
LEFT JOIN articles b ON(a.id = b.successed_by)
164
- SQL ];
192
+ SQL , false ];
165
193
166
194
# Non-Nullable ONE-to-MANY
167
195
$ tests [] = [<<<SQL
168
196
SELECT *
169
197
FROM sales s
170
198
LEFT JOIN sale_items i ON(s.id = i.sale_id)
171
- SQL ];
199
+ SQL , false ];
172
200
173
201
# Nullable ONE-to-MANY
174
202
$ tests [] = [<<<SQL
175
203
SELECT *
176
204
FROM sales s
177
205
LEFT JOIN payments p ON(s.id = p.sale_id)
178
- SQL ];
206
+ SQL , false ];
179
207
180
208
# Many-To-Many
181
209
$ tests [] = [<<<SQL
182
210
SELECT *
183
211
FROM sales s
184
212
LEFT JOIN sale_items i ON(s.id = i.sale_id)
185
213
LEFT JOIN articles a ON(a.id = i.article_id)
186
- SQL ];
214
+ SQL , false ];
187
215
188
216
### Statements that would be optimized, if it were not for a change in result-set:
189
217
@@ -197,7 +225,69 @@ public function generateTestData(): array
197
225
SELECT r.*
198
226
FROM ratings r
199
227
LEFT JOIN sales s ON(s.id = r.sale_id)
200
- SQL ];
228
+ SQL , true ];
229
+
230
+
231
+ ### Different JOIN-Types
232
+
233
+ $ tables = [
234
+ 'customers ' => [
235
+ 'sales ' => 'customer_id '
236
+ ],
237
+ 'articles ' => [
238
+ 'sale_items ' => 'article_id ' ,
239
+ 'articles ' => 'successed_by ' ,
240
+ ],
241
+ 'sales ' => [
242
+ 'sale_items ' => 'sale_id ' ,
243
+ 'ratings ' => 'sale_id ' ,
244
+ 'payments ' => 'sale_id ' ,
245
+ ],
246
+ 'sale_items ' => [],
247
+ 'payments ' => [],
248
+ 'ratings ' => [],
249
+ ];
250
+
251
+ foreach ([
252
+ 'INNER JOIN ' ,
253
+ 'LEFT JOIN ' ,
254
+ 'RIGHT JOIN ' ,
255
+ 'OUTER JOIN ' ,
256
+ ] as $ joinType ) {
257
+ foreach ($ tables as $ leftTable => $ relations ) {
258
+ foreach ($ relations as $ rightTable => $ aliasOfLeftTable ) {
259
+
260
+ foreach ([
261
+ [$ leftTable , 'id ' , $ rightTable , $ aliasOfLeftTable ],
262
+ [$ rightTable , $ aliasOfLeftTable , $ leftTable , 'id ' ],
263
+ ] as [$ aTable , $ aRefColumn , $ bTable , $ bRefColumn ]) {
264
+
265
+ foreach ([
266
+ 'a.* ' => true ,
267
+ '* ' => false ,
268
+ 'b.* ' => true ,
269
+ ] as $ columns => $ expectSqlChange ) {
270
+
271
+ $ sql = sprintf (
272
+ <<<SQL
273
+ SELECT %s
274
+ FROM %s a
275
+ %s %s b ON(a.%s = b.%s)
276
+ SQL ,
277
+ $ columns ,
278
+ $ aTable ,
279
+ $ joinType ,
280
+ $ bTable ,
281
+ $ aRefColumn ,
282
+ $ bRefColumn
283
+ );
284
+
285
+ $ tests [$ sql ] = [$ sql ];
286
+ }
287
+ }
288
+ }
289
+ }
290
+ }
201
291
202
292
return $ tests ;
203
293
}
0 commit comments