Passed
Pull Request — master (#380)
by Wilmer
02:36
created

QueryBuilderTest   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 745
Duplicated Lines 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 428
c 2
b 1
f 0
dl 0
loc 745
rs 10
wmc 30

28 Methods

Rating   Name   Duplication   Size   Complexity  
A testBuildFilterCondition() 0 15 2
A testGroupBy() 0 70 1
A testRenameTable() 0 9 1
A testRenameColumn() 0 16 1
A testBuildWhereExistsWithParameters() 0 29 1
A testBuildWithQueryRecursive() 0 24 1
A testSetConditionClasses() 0 7 1
A testSetSeparator() 0 19 1
A testDelete() 0 7 1
A tearDown() 0 5 1
A setUp() 0 6 1
A testFromSubquery() 0 52 1
A testBuildWithQuery() 0 38 1
A testSelectExists() 0 5 1
A testComplexSelect() 0 36 1
A testSelectExpression() 0 51 1
A testSelectSubquery() 0 25 1
A testCreateDropIndex() 0 3 1
A testBuildFrom() 0 8 1
A testBuildUnion() 0 33 1
A testBuildWhereExistsWithArrayParameters() 0 29 1
A testFromIndexHint() 0 32 1
A testBuildWhereExists() 0 10 1
A testOrderBy() 0 70 1
A testBatchInsert() 0 12 1
A testIssue15653() 0 17 1
A testBuildCondition() 0 18 2
A testSelectExpressionBuilder() 0 7 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Tests\QueryBuilder;
6
7
use Closure;
8
use PHPUnit\Framework\TestCase;
9
use stdClass;
10
use Yiisoft\Db\Expression\Expression;
11
use Yiisoft\Db\Expression\ExpressionInterface;
12
use Yiisoft\Db\QueryBuilder\QueryBuilderInterface;
13
use Yiisoft\Db\Tests\Support\Assert;
14
use Yiisoft\Db\Tests\Support\DbHelper;
15
use Yiisoft\Db\Tests\Support\Mock;
16
17
/**
18
 * @group db
19
 */
20
final class QueryBuilderTest extends TestCase
21
{
22
    private QueryBuilderInterface $queryBuilder;
23
    private Mock $mock;
24
25
    public function setUp(): void
26
    {
27
        parent::setUp();
28
29
        $this->mock = new Mock();
30
        $this->queryBuilder = $this->mock->queryBuilder();
31
    }
32
33
    public function tearDown(): void
34
    {
35
        parent::tearDown();
36
37
        unset($this->queryBuilder, $this->mock);
38
    }
39
40
    /**
41
     * @dataProvider \Yiisoft\Db\Tests\Provider\QueryBuilderProvider::batchInsert()
42
     */
43
    public function testBatchInsert(
44
        string $table,
45
        array $columns,
46
        array $value,
47
        string|null $expected,
48
        array $expectedParams = []
49
    ): void {
50
        $params = [];
51
        $sql = $this->queryBuilder->batchInsert($table, $columns, $value, $params);
52
53
        $this->assertSame($expected, $sql);
54
        $this->assertSame($expectedParams, $params);
55
    }
56
57
    /**
58
     * @dataProvider \Yiisoft\Db\Tests\Provider\QueryBuilderProvider::buildConditions()
59
     */
60
    public function testBuildCondition(
61
        array|ExpressionInterface|string $conditions,
62
        string $expected,
63
        array $expectedParams = []
64
    ): void {
65
        $query = $this->mock->query()->where($conditions);
66
        [$sql, $params] = $this->queryBuilder->build($query);
67
68
        $this->assertSame(
69
            'SELECT *' . (
70
                empty($expected) ? '' : ' WHERE ' . DbHelper::replaceQuotes(
71
                    $expected,
72
                    $this->mock->getDriverName(),
73
                )
74
            ),
75
            $sql,
76
        );
77
        $this->assertSame($expectedParams, $params);
78
    }
79
80
    /**
81
     * @dataProvider \Yiisoft\Db\Tests\Provider\QueryBuilderProvider::buildFilterCondition()
82
     */
83
    public function testBuildFilterCondition(array $condition, string $expected, array $expectedParams): void
84
    {
85
        $query = $this->mock->query()->filterWhere($condition);
86
        [$sql, $params] = $this->queryBuilder->build($query);
87
88
        $this->assertSame(
89
            'SELECT *' . (
90
                empty($expected) ? '' : ' WHERE ' . DbHelper::replaceQuotes(
91
                    $expected,
92
                    $this->mock->getDriverName(),
93
                )
94
            ),
95
            $sql,
96
        );
97
        $this->assertSame($expectedParams, $params);
98
    }
99
100
    /**
101
     * @dataProvider \Yiisoft\Db\Tests\Provider\QueryBuilderProvider::buildFrom()
102
     */
103
    public function testBuildFrom(string $table, string $expected): void
104
    {
105
        $params = [];
106
        $sql = $this->queryBuilder->buildFrom([$table], $params);
107
        $replacedQuotes = DbHelper::replaceQuotes($expected, $this->mock->getDriverName());
108
109
        $this->assertIsString($replacedQuotes);
110
        $this->assertSame('FROM ' . $replacedQuotes, $sql);
111
    }
112
113
    /**
114
     * This test contains three select queries connected with UNION and UNION ALL constructions.
115
     * It could be useful to use "phpunit --group=db --filter testBuildUnion" command for run it.
116
     */
117
    public function testBuildUnion(): void
118
    {
119
        $expectedQuerySql = DbHelper::replaceQuotes(
120
            <<<SQL
121
            (SELECT [[id]] FROM [[TotalExample]] [[t1]] WHERE (w > 0) AND (x < 2)) UNION ( SELECT [[id]] FROM [[TotalTotalExample]] [[t2]] WHERE w > 5 ) UNION ALL ( SELECT [[id]] FROM [[TotalTotalExample]] [[t3]] WHERE w = 3 )
122
            SQL,
123
            $this->mock->getDriverName(),
124
        );
125
126
        $secondQuery = $this->mock
127
            ->query()
128
            ->select('id')
129
            ->from('TotalTotalExample t2')
130
            ->where('w > 5');
131
132
        $thirdQuery = $this->mock
133
            ->query()
134
            ->select('id')
135
            ->from('TotalTotalExample t3')
136
            ->where('w = 3');
137
138
        $query = $this->mock
139
            ->query()
140
            ->select('id')
141
            ->from('TotalExample t1')
142
            ->where(['and', 'w > 0', 'x < 2'])
143
            ->union($secondQuery)
144
            ->union($thirdQuery, true);
145
146
        [$actualQuerySql, $queryParams] = $this->queryBuilder->build($query);
147
148
        $this->assertSame($expectedQuerySql, $actualQuerySql);
149
        $this->assertSame([], $queryParams);
150
    }
151
152
    public function testBuildWithQuery(): void
153
    {
154
        $expectedQuerySql = DbHelper::replaceQuotes(
155
            <<<SQL
156
            WITH a1 AS (SELECT [[id]] FROM [[t1]] WHERE expr = 1), a2 AS ((SELECT [[id]] FROM [[t2]] INNER JOIN [[a1]] ON t2.id = a1.id WHERE expr = 2) UNION ( SELECT [[id]] FROM [[t3]] WHERE expr = 3 )) SELECT * FROM [[a2]]
157
            SQL,
158
            $this->mock->getDriverName(),
159
        );
160
161
        $with1Query = $this->mock
162
            ->query()
163
            ->select('id')
164
            ->from('t1')
165
            ->where('expr = 1');
166
167
        $with2Query = $this->mock
168
            ->query()
169
            ->select('id')
170
            ->from('t2')
171
            ->innerJoin('a1', 't2.id = a1.id')
172
            ->where('expr = 2');
173
174
        $with3Query = $this->mock
175
            ->query()
176
            ->select('id')
177
            ->from('t3')
178
            ->where('expr = 3');
179
180
        $query = $this->mock
181
            ->query()
182
            ->withQuery($with1Query, 'a1')
183
            ->withQuery($with2Query->union($with3Query), 'a2')
184
            ->from('a2');
185
186
        [$actualQuerySql, $queryParams] = $this->queryBuilder->build($query);
187
188
        $this->assertSame($expectedQuerySql, $actualQuerySql);
189
        $this->assertSame([], $queryParams);
190
    }
191
192
    public function testBuildWithQueryRecursive(): void
193
    {
194
        $expectedQuerySql = DbHelper::replaceQuotes(
195
            <<<SQL
196
            WITH RECURSIVE a1 AS (SELECT [[id]] FROM [[t1]] WHERE expr = 1) SELECT * FROM [[a1]]
197
            SQL,
198
            $this->mock->getDriverName(),
199
        );
200
201
        $with1Query = $this->mock
202
            ->query()
203
            ->select('id')
204
            ->from('t1')
205
            ->where('expr = 1');
206
207
        $query = $this->mock
208
            ->query()
209
            ->withQuery($with1Query, 'a1', true)
210
            ->from('a1');
211
212
        [$actualQuerySql, $queryParams] = $this->queryBuilder->build($query);
213
214
        $this->assertSame($expectedQuerySql, $actualQuerySql);
215
        $this->assertSame([], $queryParams);
216
    }
217
218
    /**
219
     * @dataProvider \Yiisoft\Db\Tests\Provider\QueryBuilderProvider::buildWhereExists()
220
     */
221
    public function testBuildWhereExists(string $cond, string $expectedQuerySql): void
222
    {
223
        $expectedQueryParams = [];
224
        $subQuery = $this->mock->query()->select('1')->from('Website w');
225
        $query = $this->mock->query()->select('id')->from('TotalExample t')->where([$cond, $subQuery]);
226
227
        [$actualQuerySql, $actualQueryParams] = $this->queryBuilder->build($query);
228
229
        $this->assertSame($expectedQuerySql, $actualQuerySql);
230
        $this->assertSame($expectedQueryParams, $actualQueryParams);
231
    }
232
233
    public function testBuildWhereExistsWithArrayParameters(): void
234
    {
235
        $expectedQuerySql = DbHelper::replaceQuotes(
236
            <<<SQL
237
            SELECT [[id]] FROM [[TotalExample]] [[t]] WHERE (EXISTS (SELECT [[1]] FROM [[Website]] [[w]] WHERE (w.id = t.website_id) AND (([[w]].[[merchant_id]]=:qp0) AND ([[w]].[[user_id]]=:qp1)))) AND ([[t]].[[some_column]]=:qp2)
238
            SQL,
239
            $this->mock->getDriverName(),
240
        );
241
242
        $expectedQueryParams = [':qp0' => 6, ':qp1' => 210, ':qp2' => 'asd'];
243
244
        $subQuery = $this->mock
245
            ->query()
246
            ->select('1')
247
            ->from('Website w')
248
            ->where('w.id = t.website_id')
249
            ->andWhere(['w.merchant_id' => 6, 'w.user_id' => 210]);
250
251
        $query = $this->mock
252
            ->query()
253
            ->select('id')
254
            ->from('TotalExample t')
255
            ->where(['exists', $subQuery])
256
            ->andWhere(['t.some_column' => 'asd']);
257
258
        [$actualQuerySql, $queryParams] = $this->queryBuilder->build($query);
259
260
        $this->assertSame($expectedQuerySql, $actualQuerySql);
261
        $this->assertSame($expectedQueryParams, $queryParams);
262
    }
263
264
    public function testBuildWhereExistsWithParameters(): void
265
    {
266
        $expectedQuerySql = DbHelper::replaceQuotes(
267
            <<<SQL
268
            SELECT [[id]] FROM [[TotalExample]] [[t]] WHERE (EXISTS (SELECT [[1]] FROM [[Website]] [[w]] WHERE (w.id = t.website_id) AND (w.merchant_id = :merchant_id))) AND (t.some_column = :some_value)
269
            SQL,
270
            $this->mock->getDriverName(),
271
        );
272
273
        $expectedQueryParams = [':some_value' => 'asd', ':merchant_id' => 6];
274
275
        $subQuery = $this->mock
276
            ->query()
277
            ->select('1')
278
            ->from('Website w')
279
            ->where('w.id = t.website_id')
280
            ->andWhere('w.merchant_id = :merchant_id', [':merchant_id' => 6]);
281
282
        $query = $this->mock
283
            ->query()
284
            ->select('id')
285
            ->from('TotalExample t')
286
            ->where(['exists', $subQuery])
287
            ->andWhere('t.some_column = :some_value', [':some_value' => 'asd']);
288
289
        [$actualQuerySql, $queryParams] = $this->queryBuilder->build($query);
290
291
        $this->assertSame($expectedQuerySql, $actualQuerySql);
292
        $this->assertSame($expectedQueryParams, $queryParams);
293
    }
294
295
    /**
296
     * @dataProvider \Yiisoft\Db\Tests\Provider\QueryBuilderProvider::createDropIndex()
297
     */
298
    public function testCreateDropIndex(string $sql, Closure $builder): void
299
    {
300
        $this->assertSame($this->mock->quoter()->quoteSql($sql), $builder($this->queryBuilder));
301
    }
302
303
    public function testComplexSelect(): void
304
    {
305
        $expressionString = DbHelper::replaceQuotes(
306
            <<<SQL
307
            case t.Status_Id when 1 then 'Acknowledge' when 2 then 'No Action' else 'Unknown Action' END as [[Next Action]]
308
            SQL,
309
            $this->mock->getDriverName(),
310
        );
311
312
        $expected = DbHelper::replaceQuotes(
313
            <<<SQL
314
            SELECT [[t]].[[id]] AS [[ID]], [[gsm]].[[username]] AS [[GSM]], [[part]].[[Part]], [[t]].[[Part_Cost]] AS [[Part Cost]], st_x(location::geometry) AS [[lon]], case t.Status_Id when 1 then 'Acknowledge' when 2 then 'No Action' else 'Unknown Action' END as [[Next Action]] FROM [[tablename]]
315
            SQL,
316
            $this->mock->getDriverName(),
317
        );
318
319
        $this->assertIsString($expressionString);
320
321
        $query = $this->mock
322
            ->query()
323
            ->select(
324
                [
325
                    'ID' => 't.id',
326
                    'gsm.username as GSM',
327
                    'part.Part',
328
                    'Part Cost' => 't.Part_Cost',
329
                    'st_x(location::geometry) as lon',
330
                    new Expression($expressionString),
331
                ]
332
            )
333
            ->from('tablename');
334
335
        [$sql, $params] = $this->queryBuilder->build($query);
336
337
        $this->assertSame($expected, $sql);
338
        $this->assertEmpty($params);
339
    }
340
341
    /**
342
     * @dataProvider \Yiisoft\Db\Tests\Provider\QueryBuilderProvider::delete()
343
     */
344
    public function testDelete(string $table, array|string $condition, string $expectedSQL, array $expectedParams): void
345
    {
346
        $actualParams = [];
347
        $actualSQL = $this->queryBuilder->delete($table, $condition, $actualParams);
348
349
        $this->assertSame($expectedSQL, $actualSQL);
350
        $this->assertSame($expectedParams, $actualParams);
351
    }
352
353
    /**
354
     * {@see https://github.com/yiisoft/yii2/issues/10869}
355
     */
356
    public function testFromIndexHint(): void
357
    {
358
        $query = $this->mock->query()->from([new Expression('{{%user}} USE INDEX (primary)')]);
359
360
        [$sql, $params] = $this->queryBuilder->build($query);
361
362
        $expected = DbHelper::replaceQuotes(
363
            <<<SQL
364
            SELECT * FROM {{%user}} USE INDEX (primary)
365
            SQL,
366
            $this->mock->getDriverName(),
367
        );
368
369
        $this->assertSame($expected, $sql);
370
        $this->assertEmpty($params);
371
372
        $query = $this->mock
373
            ->query()
374
            ->from([new Expression('{{user}} {{t}} FORCE INDEX (primary) IGNORE INDEX FOR ORDER BY (i1)')])
375
            ->leftJoin(['p' => 'profile'], 'user.id = profile.user_id USE INDEX (i2)');
376
377
        [$sql, $params] = $this->queryBuilder->build($query);
378
379
        $expected = DbHelper::replaceQuotes(
380
            <<<SQL
381
            SELECT * FROM {{user}} {{t}} FORCE INDEX (primary) IGNORE INDEX FOR ORDER BY (i1) LEFT JOIN [[profile]] [[p]] ON user.id = profile.user_id USE INDEX (i2)
382
            SQL,
383
            $this->mock->getDriverName(),
384
        );
385
386
        $this->assertSame($expected, $sql);
387
        $this->assertEmpty($params);
388
    }
389
390
    public function testFromSubquery(): void
391
    {
392
        /* subquery */
393
        $subquery = $this->mock->query()->from('user')->where('account_id = accounts.id');
394
        $query = $this->mock->query()->from(['activeusers' => $subquery]);
395
396
        /* SELECT * FROM (SELECT * FROM [[user]] WHERE [[active]] = 1) [[activeusers]]; */
397
        [$sql, $params] = $this->queryBuilder->build($query);
398
399
        $expected = DbHelper::replaceQuotes(
400
            <<<SQL
401
            SELECT * FROM (SELECT * FROM [[user]] WHERE account_id = accounts.id) [[activeusers]]
402
            SQL,
403
            $this->mock->getDriverName(),
404
        );
405
406
        $this->assertSame($expected, $sql);
407
        $this->assertEmpty($params);
408
409
        /* subquery with params */
410
        $subquery = $this->mock->query()->from('user')->where('account_id = :id', ['id' => 1]);
411
        $query = $this->mock->query()->from(['activeusers' => $subquery])->where('abc = :abc', ['abc' => 'abc']);
412
413
        /* SELECT * FROM (SELECT * FROM [[user]] WHERE [[active]] = 1) [[activeusers]]; */
414
        [$sql, $params] = $this->queryBuilder->build($query);
415
416
        $expected = DbHelper::replaceQuotes(
417
            <<<SQL
418
            SELECT * FROM (SELECT * FROM [[user]] WHERE account_id = :id) [[activeusers]] WHERE abc = :abc
419
            SQL,
420
            $this->mock->getDriverName(),
421
        );
422
423
        $this->assertSame($expected, $sql);
424
        $this->assertSame(['abc' => 'abc', 'id' => 1], $params);
425
426
        /* simple subquery */
427
        $subquery = '(SELECT * FROM user WHERE account_id = accounts.id)';
428
        $query = $this->mock->query()->from(['activeusers' => $subquery]);
429
430
        /* SELECT * FROM (SELECT * FROM [[user]] WHERE [[active]] = 1) [[activeusers]]; */
431
        [$sql, $params] = $this->queryBuilder->build($query);
432
433
        $expected = DbHelper::replaceQuotes(
434
            <<<SQL
435
            SELECT * FROM (SELECT * FROM user WHERE account_id = accounts.id) [[activeusers]]
436
            SQL,
437
            $this->mock->getDriverName(),
438
        );
439
440
        $this->assertSame($expected, $sql);
441
        $this->assertEmpty($params);
442
    }
443
444
    public function testGroupBy(): void
445
    {
446
        /* simple string */
447
        $query = $this->mock->query()->select('*')->from('operations')->groupBy('name, date');
448
449
        [$sql, $params] = $this->queryBuilder->build($query);
450
451
        $expected = DbHelper::replaceQuotes(
452
            <<<SQL
453
            SELECT * FROM [[operations]] GROUP BY [[name]], [[date]]
454
            SQL,
455
            $this->mock->getDriverName(),
456
        );
457
458
        $this->assertSame($expected, $sql);
459
        $this->assertEmpty($params);
460
461
        /* array syntax */
462
        $query = $this->mock->query()->select('*')->from('operations')->groupBy(['name', 'date']);
463
464
        [$sql, $params] = $this->queryBuilder->build($query);
465
466
        $expected = DbHelper::replaceQuotes(
467
            <<<SQL
468
            SELECT * FROM [[operations]] GROUP BY [[name]], [[date]]
469
            SQL,
470
            $this->mock->getDriverName(),
471
        );
472
473
        $this->assertSame($expected, $sql);
474
        $this->assertEmpty($params);
475
476
        /* expression */
477
        $query = $this->mock
478
            ->query()
479
            ->select('*')
480
            ->from('operations')
481
            ->where('account_id = accounts.id')
482
            ->groupBy(new Expression('SUBSTR(name, 0, 1), x'));
483
484
        [$sql, $params] = $this->queryBuilder->build($query);
485
486
        $expected = DbHelper::replaceQuotes(
487
            <<<SQL
488
            SELECT * FROM [[operations]] WHERE account_id = accounts.id GROUP BY SUBSTR(name, 0, 1), x
489
            SQL,
490
            $this->mock->getDriverName(),
491
        );
492
493
        $this->assertSame($expected, $sql);
494
        $this->assertEmpty($params);
495
496
        /* expression with params */
497
        $query = $this->mock
498
            ->query()
499
            ->select('*')
500
            ->from('operations')
501
            ->groupBy(new Expression('SUBSTR(name, 0, :to), x', [':to' => 4]));
502
503
        [$sql, $params] = $this->queryBuilder->build($query);
504
505
        $expected = DbHelper::replaceQuotes(
506
            <<<SQL
507
            SELECT * FROM [[operations]] GROUP BY SUBSTR(name, 0, :to), x
508
            SQL,
509
            $this->mock->getDriverName(),
510
        );
511
512
        $this->assertSame($expected, $sql);
513
        $this->assertSame([':to' => 4], $params);
514
    }
515
516
    /**
517
     * {@see https://github.com/yiisoft/yii2/issues/15653}
518
     */
519
    public function testIssue15653(): void
520
    {
521
        $query = $this->mock->query()->from('admin_user')->where(['is_deleted' => false]);
522
        $query->where([])->andWhere(['in', 'id', ['1', '0']]);
523
524
        [$sql, $params] = $this->queryBuilder->build($query);
525
526
        $this->assertSame(
527
            DbHelper::replaceQuotes(
528
                <<<SQL
529
                SELECT * FROM [[admin_user]] WHERE [[id]] IN (:qp0, :qp1)
530
                SQL,
531
                $this->mock->getDriverName(),
532
            ),
533
            $sql,
534
        );
535
        $this->assertSame([':qp0' => '1', ':qp1' => '0'], $params);
536
    }
537
538
    public function testOrderBy(): void
539
    {
540
        /* simple string */
541
        $query = $this->mock->query()->select('*')->from('operations')->orderBy('name ASC, date DESC');
542
543
        [$sql, $params] = $this->queryBuilder->build($query);
544
545
        $expected = DbHelper::replaceQuotes(
546
            <<<SQL
547
            SELECT * FROM [[operations]] ORDER BY [[name]], [[date]] DESC
548
            SQL,
549
            $this->mock->getDriverName(),
550
        );
551
552
        $this->assertSame($expected, $sql);
553
        $this->assertEmpty($params);
554
555
        /* array syntax */
556
        $query = $this->mock->query()->select('*')->from('operations')->orderBy(['name' => SORT_ASC, 'date' => SORT_DESC]);
557
558
        [$sql, $params] = $this->queryBuilder->build($query);
559
560
        $expected = DbHelper::replaceQuotes(
561
            <<<SQL
562
            SELECT * FROM [[operations]] ORDER BY [[name]], [[date]] DESC
563
            SQL,
564
            $this->mock->getDriverName(),
565
        );
566
567
        $this->assertSame($expected, $sql);
568
        $this->assertEmpty($params);
569
570
        /* expression */
571
        $query = $this->mock
572
            ->query()
573
            ->select('*')
574
            ->from('operations')
575
            ->where('account_id = accounts.id')
576
            ->orderBy(new Expression('SUBSTR(name, 3, 4) DESC, x ASC'));
577
578
        [$sql, $params] = $this->queryBuilder->build($query);
579
580
        $expected = DbHelper::replaceQuotes(
581
            <<<SQL
582
            SELECT * FROM [[operations]] WHERE account_id = accounts.id ORDER BY SUBSTR(name, 3, 4) DESC, x ASC
583
            SQL,
584
            $this->mock->getDriverName(),
585
        );
586
587
        $this->assertSame($expected, $sql);
588
        $this->assertEmpty($params);
589
590
        /* expression with params */
591
        $query = $this->mock
592
            ->query()
593
            ->select('*')
594
            ->from('operations')
595
            ->orderBy(new Expression('SUBSTR(name, 3, :to) DESC, x ASC', [':to' => 4]));
596
597
        [$sql, $params] = $this->queryBuilder->build($query);
598
599
        $expected = DbHelper::replaceQuotes(
600
            <<<SQL
601
            SELECT * FROM [[operations]] ORDER BY SUBSTR(name, 3, :to) DESC, x ASC
602
            SQL,
603
            $this->mock->getDriverName(),
604
        );
605
606
        $this->assertSame($expected, $sql);
607
        $this->assertSame([':to' => 4], $params);
608
    }
609
610
    public function testRenameColumn(): void
611
    {
612
        $sql = $this->queryBuilder->renameColumn('alpha', 'string_identifier', 'string_identifier_test');
613
        $this->assertSame(
614
            <<<SQL
615
            ALTER TABLE `alpha` RENAME COLUMN `string_identifier` TO `string_identifier_test`
616
            SQL,
617
            $sql,
618
        );
619
620
        $sql = $this->queryBuilder->renameColumn('alpha', 'string_identifier_test', 'string_identifier');
621
        $this->assertSame(
622
            <<<SQL
623
            ALTER TABLE `alpha` RENAME COLUMN `string_identifier_test` TO `string_identifier`
624
            SQL,
625
            $sql,
626
        );
627
    }
628
629
    public function testRenameTable(): void
630
    {
631
        $sql = $this->queryBuilder->renameTable('table_from', 'table_to');
632
633
        $this->assertSame(
634
            <<<SQL
635
            RENAME TABLE `table_from` TO `table_to`
636
            SQL,
637
            $sql,
638
        );
639
    }
640
641
    public function testSelectExpression(): void
642
    {
643
        $query = $this->mock->query()->select(new Expression('1 AS ab'))->from('tablename');
644
645
        [$sql, $params] = $this->queryBuilder->build($query);
646
647
        $expected = DbHelper::replaceQuotes(
648
            <<<SQL
649
            SELECT 1 AS ab FROM [[tablename]]
650
            SQL,
651
            $this->mock->getDriverName(),
652
        );
653
654
        $this->assertSame($expected, $sql);
655
        $this->assertEmpty($params);
656
657
        $query = $this->mock
658
            ->query()
659
            ->select(new Expression('1 AS ab'))
660
            ->addSelect(new Expression('2 AS cd'))
661
            ->addSelect(['ef' => new Expression('3')])
662
            ->from('tablename');
663
664
        [$sql, $params] = $this->queryBuilder->build($query);
665
666
        $expected = DbHelper::replaceQuotes(
667
            <<<SQL
668
            SELECT 1 AS ab, 2 AS cd, 3 AS [[ef]] FROM [[tablename]]
669
            SQL,
670
            $this->mock->getDriverName(),
671
        );
672
673
        $this->assertSame($expected, $sql);
674
        $this->assertEmpty($params);
675
676
        $query = $this->mock
677
            ->query()
678
            ->select(new Expression('SUBSTR(name, 0, :len)', [':len' => 4]))
679
            ->from('tablename');
680
681
        [$sql, $params] = $this->queryBuilder->build($query);
682
683
        $expected = DbHelper::replaceQuotes(
684
            <<<SQL
685
            SELECT SUBSTR(name, 0, :len) FROM [[tablename]]
686
            SQL,
687
            $this->mock->getDriverName(),
688
        );
689
690
        $this->assertSame($expected, $sql);
691
        $this->assertSame([':len' => 4], $params);
692
    }
693
694
    public function testSelectExists(): void
695
    {
696
        $sql = $this->queryBuilder->selectExists('SELECT 1 FROM `table` WHERE `id` = 1');
697
698
        $this->assertSame('SELECT EXISTS(SELECT 1 FROM `table` WHERE `id` = 1)', $sql);
699
    }
700
701
    public function testSelectSubquery(): void
702
    {
703
        $expected = DbHelper::replaceQuotes(
704
            <<<SQL
705
            SELECT *, (SELECT COUNT(*) FROM [[operations]] WHERE account_id = accounts.id) AS [[operations_count]] FROM [[accounts]]
706
            SQL,
707
            $this->mock->getDriverName(),
708
        );
709
710
        $subquery = $this->mock
711
            ->query()
712
            ->select('COUNT(*)')
713
            ->from('operations')
714
            ->where('account_id = accounts.id');
715
716
        $query = $this->mock
717
            ->query()
718
            ->select('*')
719
            ->from('accounts')
720
            ->addSelect(['operations_count' => $subquery]);
721
722
        [$sql, $params] = $this->queryBuilder->build($query);
723
724
        $this->assertSame($expected, $sql);
725
        $this->assertEmpty($params);
726
    }
727
728
    public function testSetConditionClasses(): void
729
    {
730
        $this->queryBuilder->setConditionClasses(['stdClass' => stdClass::class]);
731
        $dqlBuilder = Assert::getInaccessibleProperty($this->queryBuilder, 'dqlBuilder');
732
        $conditionClasses = Assert::getInaccessibleProperty($dqlBuilder, 'conditionClasses');
733
734
        $this->assertSame(stdClass::class, $conditionClasses['stdClass']);
735
    }
736
737
    public function testSelectExpressionBuilder(): void
738
    {
739
        $this->queryBuilder->setExpressionBuilders(['stdClass' => stdClass::class]);
740
        $dqlBuilder = Assert::getInaccessibleProperty($this->queryBuilder, 'dqlBuilder');
741
        $expressionBuilders = Assert::getInaccessibleProperty($dqlBuilder, 'expressionBuilders');
742
743
        $this->assertSame(stdClass::class, $expressionBuilders['stdClass']);
744
    }
745
746
    public function testSetSeparator(): void
747
    {
748
        $this->queryBuilder->setSeparator(' ');
749
        [$sql, $params] = $this->queryBuilder->build($this->mock->query()->select('*')->from('table'));
750
751
        $this->assertSame('SELECT * FROM `table`', $sql);
752
        $this->assertEmpty($params);
753
754
        $this->queryBuilder->setSeparator("\n");
755
        [$sql, $params] = $this->queryBuilder->build($this->mock->query()->select('*')->from('table'));
756
757
        $this->assertSame(
758
            <<<SQL
759
            SELECT *
760
            FROM `table`
761
            SQL,
762
            $sql,
763
        );
764
        $this->assertEmpty($params);
765
    }
766
}
767