Passed
Pull Request — master (#380)
by Wilmer
04:47 queued 01:51
created

AbstractQueryBuilderTest::testSelectExists()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 8
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Tests;
6
7
use PHPUnit\Framework\TestCase;
8
use stdClass;
9
use Yiisoft\Db\Driver\PDO\ConnectionPDOInterface;
10
use Yiisoft\Db\Expression\Expression;
11
use Yiisoft\Db\Schema\SchemaBuilderTrait;
12
use Yiisoft\Db\Tests\Support\Assert;
13
use Yiisoft\Db\Tests\Support\DbHelper;
14
use Yiisoft\Db\Tests\Support\TestTrait;
15
16
abstract class AbstractQueryBuilderTest extends TestCase
17
{
18
    use SchemaBuilderTrait;
19
    use TestTrait;
20
21
    protected ConnectionPDOInterface $db;
22
23
    public function testAddColumn(): void
24
    {
25
        $db = $this->getConnection();
26
27
        $qb = $db->getQueryBuilder();
28
29
        $this->assertSame(
30
            <<<SQL
31
            ALTER TABLE `user` ADD `age` integer
32
            SQL,
33
            $qb->addColumn('user', 'age', 'integer')
34
        );
35
    }
36
37
    public function testAddCommentOnColumn(): void
38
    {
39
        $db = $this->getConnection();
40
41
        $qb = $db->getQueryBuilder();
42
43
        $this->assertSame(
44
            <<<SQL
45
            COMMENT ON COLUMN `user`.`name` IS 'This is a comment'
46
            SQL,
47
            $qb->addCommentOnColumn('user', 'name', 'This is a comment')
48
        );
49
    }
50
51
    public function testAddCommentOnTable(): void
52
    {
53
        $db = $this->getConnection();
54
55
        $qb = $db->getQueryBuilder();
56
57
        $this->assertSame(
58
            <<<SQL
59
            COMMENT ON TABLE `user` IS 'This is a comment'
60
            SQL,
61
            $qb->addCommentOnTable('user', 'This is a comment')
62
        );
63
    }
64
65
    public function testBuildColumnsWithString(): void
66
    {
67
        $db = $this->getConnection();
68
69
        $qb = $db->getQueryBuilder();
70
        $columns = '(id)';
71
72
        $this->assertSame($columns, $qb->buildColumns($columns));
73
    }
74
75
    public function testBuildColumnsWithArray(): void
76
    {
77
        $db = $this->getConnection();
78
79
        $qb = $db->getQueryBuilder();
80
        $columns = ['id', 'name', 'email', 'address', 'status'];
81
        $expected = '`id`, `name`, `email`, `address`, `status`';
82
83
        $this->assertSame($expected, $qb->buildColumns($columns));
84
    }
85
86
    public function testBuildColumnsWithExpression(): void
87
    {
88
        $db = $this->getConnection();
89
90
        $qb = $db->getQueryBuilder();
91
        $columns = ['id', 'name', 'email', 'address', 'status', new Expression('COUNT(*)')];
92
        $expected = '`id`, `name`, `email`, `address`, `status`, COUNT(*)';
93
94
        $this->assertSame($expected, $qb->buildColumns($columns));
95
    }
96
97
    public function testBuildLimit(): void
98
    {
99
        $db = $this->getConnection();
100
101
        $qb = $db->getQueryBuilder();
102
        $query = $this->getQuery($db)->limit(10);
103
104
        [$sql, $params] = $qb->build($query);
105
106
        $this->assertSame(
107
            <<<SQL
108
            SELECT * LIMIT 10
109
            SQL,
110
            $sql,
111
        );
112
        $this->assertSame([], $params);
113
    }
114
115
    public function testBuildOffset(): void
116
    {
117
        $db = $this->getConnection();
118
119
        $qb = $db->getQueryBuilder();
120
        $query = $this->getQuery($db)->offset(10);
121
122
        [$sql, $params] = $qb->build($query);
123
124
        $this->assertSame(
125
            <<<SQL
126
            SELECT * OFFSET 10
127
            SQL,
128
            $sql,
129
        );
130
        $this->assertSame([], $params);
131
    }
132
133
    public function testBuildSelectColumnWithoutParentheses(): void
134
    {
135
        $db = $this->getConnection();
136
137
        $qb = $db->getQueryBuilder();
138
        $params = [];
139
        $sql = $qb->buildSelect(['1'], $params);
140
141
        $this->assertSame(
142
            <<<SQL
143
            SELECT `1`
144
            SQL,
145
            $sql,
146
        );
147
    }
148
149
    public function testBuildSelectOptions(): void
150
    {
151
        $db = $this->getConnection();
152
153
        $qb = $db->getQueryBuilder();
154
        $query = $this->getQuery($db)->selectOption('DISTINCT');
155
156
        [$sql, $params] = $qb->build($query);
157
158
        $this->assertSame(
159
            <<<SQL
160
            SELECT DISTINCT *
161
            SQL,
162
            $sql,
163
        );
164
        $this->assertSame([], $params);
165
    }
166
167
    /**
168
     * This test contains three select queries connected with UNION and UNION ALL constructions.
169
     * It could be useful to use "phpunit --group=db --filter testBuildUnion" command for run it.
170
     */
171
    public function testBuildUnion(): void
172
    {
173
        $db = $this->getConnection();
174
175
        $qb = $db->getQueryBuilder();
176
        $expectedQuerySql = DbHelper::replaceQuotes(
177
            <<<SQL
178
            (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 )
179
            SQL,
180
            $db->getName(),
181
        );
182
183
        $secondQuery = $this->getQuery($db)->select('id')->from('TotalTotalExample t2')->where('w > 5');
184
        $thirdQuery = $this->getQuery($db)->select('id')->from('TotalTotalExample t3')->where('w = 3');
185
        $query = $this->getQuery($db)
186
            ->select('id')
187
            ->from('TotalExample t1')
188
            ->where(['and', 'w > 0', 'x < 2'])
189
            ->union($secondQuery)
190
            ->union($thirdQuery, true);
191
192
        [$actualQuerySql, $queryParams] = $qb->build($query);
193
194
        $this->assertSame($expectedQuerySql, $actualQuerySql);
195
        $this->assertSame([], $queryParams);
196
    }
197
198
    public function testBuildWithQuery(): void
199
    {
200
        $db = $this->getConnection();
201
202
        $qb = $db->getQueryBuilder();
203
        $expectedQuerySql = DbHelper::replaceQuotes(
204
            <<<SQL
205
            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]]
206
            SQL,
207
            $db->getName(),
208
        );
209
210
        $with1Query = $this->getQuery($db)->select('id')->from('t1')->where('expr = 1');
211
        $with2Query = $this->getQuery($db)->select('id')->from('t2')->innerJoin('a1', 't2.id = a1.id')->where('expr = 2');
212
        $with3Query = $this->getQuery($db)->select('id')->from('t3')->where('expr = 3');
213
        $query = $this->getQuery($db)
214
            ->withQuery($with1Query, 'a1')
215
            ->withQuery($with2Query->union($with3Query), 'a2')
216
            ->from('a2');
217
218
        [$actualQuerySql, $queryParams] = $qb->build($query);
219
220
        $this->assertSame($expectedQuerySql, $actualQuerySql);
221
        $this->assertSame([], $queryParams);
222
    }
223
224
    public function testBuildWithQueryRecursive(): void
225
    {
226
        $db = $this->getConnection();
227
228
        $qb = $db->getQueryBuilder();
229
        $expectedQuerySql = DbHelper::replaceQuotes(
230
            <<<SQL
231
            WITH RECURSIVE a1 AS (SELECT [[id]] FROM [[t1]] WHERE expr = 1) SELECT * FROM [[a1]]
232
            SQL,
233
            $db->getName(),
234
        );
235
        $with1Query = $this->getQuery($db)->select('id')->from('t1')->where('expr = 1');
236
        $query = $this->getQuery($db)->withQuery($with1Query, 'a1', true)->from('a1');
237
238
        [$actualQuerySql, $queryParams] = $qb->build($query);
239
240
        $this->assertSame($expectedQuerySql, $actualQuerySql);
241
        $this->assertSame([], $queryParams);
242
    }
243
244
    public function testBuildWhereExistsWithArrayParameters(): void
245
    {
246
        $db = $this->getConnection();
247
248
        $qb = $db->getQueryBuilder();
249
        $expectedQuerySql = DbHelper::replaceQuotes(
250
            <<<SQL
251
            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)
252
            SQL,
253
            $db->getName(),
254
        );
255
256
        $expectedQueryParams = [':qp0' => 6, ':qp1' => 210, ':qp2' => 'asd'];
257
258
        $subQuery = $this->getQuery($db)
259
            ->select('1')
260
            ->from('Website w')
261
            ->where('w.id = t.website_id')
262
            ->andWhere(['w.merchant_id' => 6, 'w.user_id' => 210]);
263
264
        $query = $this->getQuery($db)
265
            ->select('id')
266
            ->from('TotalExample t')
267
            ->where(['exists', $subQuery])
268
            ->andWhere(['t.some_column' => 'asd']);
269
270
        [$actualQuerySql, $queryParams] = $qb->build($query);
271
272
        $this->assertSame($expectedQuerySql, $actualQuerySql);
273
        $this->assertSame($expectedQueryParams, $queryParams);
274
    }
275
276
    public function testBuildWhereExistsWithParameters(): void
277
    {
278
        $db = $this->getConnection();
279
280
        $qb = $db->getQueryBuilder();
281
        $expectedQuerySql = DbHelper::replaceQuotes(
282
            <<<SQL
283
            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)
284
            SQL,
285
            $db->getName(),
286
        );
287
288
        $expectedQueryParams = [':some_value' => 'asd', ':merchant_id' => 6];
289
290
        $subQuery = $this->getQuery($db)
291
            ->select('1')
292
            ->from('Website w')
293
            ->where('w.id = t.website_id')
294
            ->andWhere('w.merchant_id = :merchant_id', [':merchant_id' => 6]);
295
296
        $query = $this->getQuery($db)
297
            ->select('id')
298
            ->from('TotalExample t')
299
            ->where(['exists', $subQuery])
300
            ->andWhere('t.some_column = :some_value', [':some_value' => 'asd']);
301
302
        [$actualQuerySql, $queryParams] = $qb->build($query);
303
304
        $this->assertSame($expectedQuerySql, $actualQuerySql);
305
        $this->assertSame($expectedQueryParams, $queryParams);
306
    }
307
308
    public function testComplexSelect(): void
309
    {
310
        $db = $this->getConnection();
311
312
        $qb = $db->getQueryBuilder();
313
        $expressionString = DbHelper::replaceQuotes(
314
            <<<SQL
315
            case t.Status_Id when 1 then 'Acknowledge' when 2 then 'No Action' else 'Unknown Action' END as [[Next Action]]
316
            SQL,
317
            $db->getName(),
318
        );
319
        $expected = DbHelper::replaceQuotes(
320
            <<<SQL
321
            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]]
322
            SQL,
323
            $db->getName(),
324
        );
325
326
        $this->assertIsString($expressionString);
327
328
        $query = $this->getQuery($db)
329
            ->select(
330
                [
331
                    'ID' => 't.id',
332
                    'gsm.username as GSM',
333
                    'part.Part',
334
                    'Part Cost' => 't.Part_Cost',
335
                    'st_x(location::geometry) as lon',
336
                    new Expression($expressionString),
337
                ]
338
            )
339
            ->from('tablename');
340
341
        [$sql, $params] = $qb->build($query);
342
343
        $this->assertSame($expected, $sql);
344
        $this->assertEmpty($params);
345
    }
346
347
    public function testCreateTable(): void
348
    {
349
        $this->db = $this->getConnection();
350
351
        $qb = $this->db->getQueryBuilder();
352
        $expected = DbHelper::replaceQuotes(
353
            <<<SQL
354
            CREATE TABLE [[test_table]] (
355
            \t[[id]] pk,
356
            \t[[name]] string(255) NOT NULL,
357
            \t[[email]] string(255) NOT NULL,
358
            \t[[address]] string(255) NOT NULL,
359
            \t[[status]] integer NOT NULL,
360
            \t[[profile_id]] integer NOT NULL,
361
            \t[[created_at]] timestamp NOT NULL,
362
            \t[[updated_at]] timestamp NOT NULL
363
            ) CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB
364
            SQL,
365
            $this->db->getName(),
366
        );
367
        $columns = [
368
            'id' => $this->primaryKey(5),
369
            'name' => $this->string(255)->notNull(),
370
            'email' => $this->string(255)->notNull(),
371
            'address' => $this->string(255)->notNull(),
372
            'status' => $this->integer()->notNull(),
373
            'profile_id' => $this->integer()->notNull(),
374
            'created_at' => $this->timestamp()->notNull(),
375
            'updated_at' => $this->timestamp()->notNull(),
376
        ];
377
        $options = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
378
        $sql = $qb->createTable('test_table', $columns, $options);
379
380
        Assert::equalsWithoutLE($expected, $sql);
381
    }
382
383
    public function testCreateView(): void
384
    {
385
        $db = $this->getConnection();
386
387
        $qb = $db->getQueryBuilder();
388
        $expected = DbHelper::replaceQuotes(
389
            <<<SQL
390
            CREATE VIEW [[test_view]] AS SELECT [[id]], [[name]] FROM [[test_table]]
391
            SQL,
392
            $db->getName(),
393
        );
394
        $sql = $qb->createView(
395
            'test_view',
396
            $this->getQuery($db)->select(['id', 'name'])->from('test_table'),
397
        );
398
399
        $this->assertSame($expected, $sql);
400
    }
401
402
    public function testCreateViewWithParams(): void
403
    {
404
        $db = $this->getConnection();
405
406
        $qb = $db->getQueryBuilder();
407
        $expected = DbHelper::replaceQuotes(
408
            <<<SQL
409
            CREATE VIEW `test_view` AS SELECT `id`, `name` FROM `test_table` WHERE `id`=1
410
            SQL,
411
            $db->getName(),
412
        );
413
        $sql = $qb->createView(
414
            'test_view',
415
            $this->getQuery($db)->select(['id', 'name'])->from('test_table')->where(['id' => 1]),
416
        );
417
418
        $this->assertSame($expected, $sql);
419
    }
420
421
    public function testDropColumn(): void
422
    {
423
        $db = $this->getConnection();
424
425
        $qb = $db->getQueryBuilder();
426
        $expected = DbHelper::replaceQuotes(
427
            <<<SQL
428
            ALTER TABLE [[test_table]] DROP COLUMN [[test_column]]
429
            SQL,
430
            $db->getName(),
431
        );
432
        $sql = $qb->dropColumn('test_table', 'test_column');
433
434
        $this->assertSame($expected, $sql);
435
    }
436
437
    public function testdropCommentFromColumn(): void
438
    {
439
        $db = $this->getConnection();
440
441
        $qb = $db->getQueryBuilder();
442
        $expected = DbHelper::replaceQuotes(
443
            <<<SQL
444
            COMMENT ON COLUMN `test_table`.`test_column` IS NULL
445
            SQL,
446
            $db->getName(),
447
        );
448
        $sql = $qb->dropCommentFromColumn('test_table', 'test_column');
449
450
        $this->assertSame($expected, $sql);
451
    }
452
453
    public function testsDropCommentFromTable(): void
454
    {
455
        $db = $this->getConnection();
456
457
        $qb = $db->getQueryBuilder();
458
        $expected = DbHelper::replaceQuotes(
459
            <<<SQL
460
            COMMENT ON TABLE `test_table` IS NULL
461
            SQL,
462
            $db->getName(),
463
        );
464
465
        $sql = $qb->dropCommentFromTable('test_table');
466
467
        $this->assertSame($expected, $sql);
468
    }
469
470
    public function testDropTable(): void
471
    {
472
        $db = $this->getConnection();
473
474
        $qb = $db->getQueryBuilder();
475
        $expected = DbHelper::replaceQuotes(
476
            <<<SQL
477
            DROP TABLE [[test_table]]
478
            SQL,
479
            $db->getName(),
480
        );
481
        $sql = $qb->dropTable('test_table');
482
483
        $this->assertSame($expected, $sql);
484
    }
485
486
    public function testDropView(): void
487
    {
488
        $db = $this->getConnection();
489
490
        $qb = $db->getQueryBuilder();
491
        $expected = <<<SQL
492
        DROP VIEW `test_view`
493
        SQL;
494
        $sql = $qb->dropView('test_view');
495
496
        $this->assertSame($expected, $sql);
497
    }
498
499
    /**
500
     * {@see https://github.com/yiisoft/yii2/issues/10869}
501
     */
502
    public function testFromIndexHint(): void
503
    {
504
        $db = $this->getConnection();
505
506
        $qb = $db->getQueryBuilder();
507
        $query = $this->getQuery($db)->from([new Expression('{{%user}} USE INDEX (primary)')]);
508
509
        [$sql, $params] = $qb->build($query);
510
511
        $expected = DbHelper::replaceQuotes(
512
            <<<SQL
513
            SELECT * FROM {{%user}} USE INDEX (primary)
514
            SQL,
515
            $db->getName(),
516
        );
517
518
        $this->assertSame($expected, $sql);
519
        $this->assertEmpty($params);
520
521
        $query = $this->getQuery($db)
522
            ->from([new Expression('{{user}} {{t}} FORCE INDEX (primary) IGNORE INDEX FOR ORDER BY (i1)')])
523
            ->leftJoin(['p' => 'profile'], 'user.id = profile.user_id USE INDEX (i2)');
524
525
        [$sql, $params] = $qb->build($query);
526
527
        $expected = DbHelper::replaceQuotes(
528
            <<<SQL
529
            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)
530
            SQL,
531
            $db->getName(),
532
        );
533
534
        $this->assertSame($expected, $sql);
535
        $this->assertEmpty($params);
536
    }
537
538
    public function testFromSubquery(): void
539
    {
540
        $db = $this->getConnection();
541
542
        $qb = $db->getQueryBuilder();
543
544
        /* subquery */
545
        $subquery = $this->getQuery($db)->from('user')->where('account_id = accounts.id');
546
        $query = $this->getQuery($db)->from(['activeusers' => $subquery]);
547
548
        /* SELECT * FROM (SELECT * FROM [[user]] WHERE [[active]] = 1) [[activeusers]]; */
549
        [$sql, $params] = $qb->build($query);
550
551
        $expected = DbHelper::replaceQuotes(
552
            <<<SQL
553
            SELECT * FROM (SELECT * FROM [[user]] WHERE account_id = accounts.id) [[activeusers]]
554
            SQL,
555
            $db->getName(),
556
        );
557
558
        $this->assertSame($expected, $sql);
559
        $this->assertEmpty($params);
560
561
        /* subquery with params */
562
        $subquery = $this->getQuery($db)->from('user')->where('account_id = :id', ['id' => 1]);
563
        $query = $this->getQuery($db)->from(['activeusers' => $subquery])->where('abc = :abc', ['abc' => 'abc']);
564
565
        /* SELECT * FROM (SELECT * FROM [[user]] WHERE [[active]] = 1) [[activeusers]]; */
566
        [$sql, $params] = $qb->build($query);
567
568
        $expected = DbHelper::replaceQuotes(
569
            <<<SQL
570
            SELECT * FROM (SELECT * FROM [[user]] WHERE account_id = :id) [[activeusers]] WHERE abc = :abc
571
            SQL,
572
            $db->getName(),
573
        );
574
575
        $this->assertSame($expected, $sql);
576
        $this->assertSame(['abc' => 'abc', 'id' => 1], $params);
577
578
        /* simple subquery */
579
        $subquery = '(SELECT * FROM user WHERE account_id = accounts.id)';
580
        $query = $this->getQuery($db)->from(['activeusers' => $subquery]);
581
582
        /* SELECT * FROM (SELECT * FROM [[user]] WHERE [[active]] = 1) [[activeusers]]; */
583
        [$sql, $params] = $qb->build($query);
584
585
        $expected = DbHelper::replaceQuotes(
586
            <<<SQL
587
            SELECT * FROM (SELECT * FROM user WHERE account_id = accounts.id) [[activeusers]]
588
            SQL,
589
            $db->getName(),
590
        );
591
592
        $this->assertSame($expected, $sql);
593
        $this->assertEmpty($params);
594
    }
595
596
    public function testGroupBy(): void
597
    {
598
        $db = $this->getConnection();
599
600
        $qb = $db->getQueryBuilder();
601
602
        /* simple string */
603
        $query = $this->getQuery($db)->select('*')->from('operations')->groupBy('name, date');
604
605
        [$sql, $params] = $qb->build($query);
606
607
        $expected = DbHelper::replaceQuotes(
608
            <<<SQL
609
            SELECT * FROM [[operations]] GROUP BY [[name]], [[date]]
610
            SQL,
611
            $db->getName(),
612
        );
613
614
        $this->assertSame($expected, $sql);
615
        $this->assertEmpty($params);
616
617
        /* array syntax */
618
        $query = $this->getQuery($db)->select('*')->from('operations')->groupBy(['name', 'date']);
619
620
        [$sql, $params] = $qb->build($query);
621
622
        $expected = DbHelper::replaceQuotes(
623
            <<<SQL
624
            SELECT * FROM [[operations]] GROUP BY [[name]], [[date]]
625
            SQL,
626
            $db->getName(),
627
        );
628
629
        $this->assertSame($expected, $sql);
630
        $this->assertEmpty($params);
631
632
        /* expression */
633
        $query = $this->getQuery($db)
634
            ->select('*')
635
            ->from('operations')
636
            ->where('account_id = accounts.id')
637
            ->groupBy(new Expression('SUBSTR(name, 0, 1), x'));
638
639
        [$sql, $params] = $qb->build($query);
640
641
        $expected = DbHelper::replaceQuotes(
642
            <<<SQL
643
            SELECT * FROM [[operations]] WHERE account_id = accounts.id GROUP BY SUBSTR(name, 0, 1), x
644
            SQL,
645
            $db->getName(),
646
        );
647
648
        $this->assertSame($expected, $sql);
649
        $this->assertEmpty($params);
650
651
        /* expression with params */
652
        $query = $this->getQuery($db)
653
            ->select('*')
654
            ->from('operations')
655
            ->groupBy(new Expression('SUBSTR(name, 0, :to), x', [':to' => 4]));
656
657
        [$sql, $params] = $qb->build($query);
658
659
        $expected = DbHelper::replaceQuotes(
660
            <<<SQL
661
            SELECT * FROM [[operations]] GROUP BY SUBSTR(name, 0, :to), x
662
            SQL,
663
            $db->getName(),
664
        );
665
666
        $this->assertSame($expected, $sql);
667
        $this->assertSame([':to' => 4], $params);
668
    }
669
670
    /**
671
     * {@see https://github.com/yiisoft/yii2/issues/15653}
672
     */
673
    public function testIssue15653(): void
674
    {
675
        $db = $this->getConnection();
676
677
        $qb = $db->getQueryBuilder();
678
        $query = $this->getQuery($db)->from('admin_user')->where(['is_deleted' => false]);
679
        $query->where([])->andWhere(['in', 'id', ['1', '0']]);
680
681
        [$sql, $params] = $qb->build($query);
682
683
        $this->assertSame(
684
            DbHelper::replaceQuotes(
685
                <<<SQL
686
                SELECT * FROM [[admin_user]] WHERE [[id]] IN (:qp0, :qp1)
687
                SQL,
688
                $db->getName(),
689
            ),
690
            $sql,
691
        );
692
        $this->assertSame([':qp0' => '1', ':qp1' => '0'], $params);
693
    }
694
695
    public function testOrderBy(): void
696
    {
697
        $db = $this->getConnection();
698
699
        $qb = $db->getQueryBuilder();
700
701
        /* simple string */
702
        $query = $this->getQuery($db)->select('*')->from('operations')->orderBy('name ASC, date DESC');
703
704
        [$sql, $params] = $qb->build($query);
705
706
        $expected = DbHelper::replaceQuotes(
707
            <<<SQL
708
            SELECT * FROM [[operations]] ORDER BY [[name]], [[date]] DESC
709
            SQL,
710
            $db->getName(),
711
        );
712
713
        $this->assertSame($expected, $sql);
714
        $this->assertEmpty($params);
715
716
        /* array syntax */
717
        $query = $this->getQuery($db)->select('*')->from('operations')->orderBy(['name' => SORT_ASC, 'date' => SORT_DESC]);
718
719
        [$sql, $params] = $qb->build($query);
720
721
        $expected = DbHelper::replaceQuotes(
722
            <<<SQL
723
            SELECT * FROM [[operations]] ORDER BY [[name]], [[date]] DESC
724
            SQL,
725
            $db->getName(),
726
        );
727
728
        $this->assertSame($expected, $sql);
729
        $this->assertEmpty($params);
730
731
        /* expression */
732
        $query = $this->getQuery($db)
733
            ->select('*')
734
            ->from('operations')
735
            ->where('account_id = accounts.id')
736
            ->orderBy(new Expression('SUBSTR(name, 3, 4) DESC, x ASC'));
737
738
        [$sql, $params] = $qb->build($query);
739
740
        $expected = DbHelper::replaceQuotes(
741
            <<<SQL
742
            SELECT * FROM [[operations]] WHERE account_id = accounts.id ORDER BY SUBSTR(name, 3, 4) DESC, x ASC
743
            SQL,
744
            $db->getName(),
745
        );
746
747
        $this->assertSame($expected, $sql);
748
        $this->assertEmpty($params);
749
750
        /* expression with params */
751
        $query = $this->getQuery($db)
752
            ->select('*')
753
            ->from('operations')
754
            ->orderBy(new Expression('SUBSTR(name, 3, :to) DESC, x ASC', [':to' => 4]));
755
756
        [$sql, $params] = $qb->build($query);
757
758
        $expected = DbHelper::replaceQuotes(
759
            <<<SQL
760
            SELECT * FROM [[operations]] ORDER BY SUBSTR(name, 3, :to) DESC, x ASC
761
            SQL,
762
            $db->getName(),
763
        );
764
765
        $this->assertSame($expected, $sql);
766
        $this->assertSame([':to' => 4], $params);
767
    }
768
769
    public function testRenameColumn(): void
770
    {
771
        $db = $this->getConnection();
772
773
        $qb = $db->getQueryBuilder();
774
        $sql = $qb->renameColumn('alpha', 'string_identifier', 'string_identifier_test');
775
776
        $this->assertSame(
777
            <<<SQL
778
            ALTER TABLE `alpha` RENAME COLUMN `string_identifier` TO `string_identifier_test`
779
            SQL,
780
            $sql,
781
        );
782
783
        $sql = $qb->renameColumn('alpha', 'string_identifier_test', 'string_identifier');
784
785
        $this->assertSame(
786
            <<<SQL
787
            ALTER TABLE `alpha` RENAME COLUMN `string_identifier_test` TO `string_identifier`
788
            SQL,
789
            $sql,
790
        );
791
    }
792
793
    public function testRenameTable(): void
794
    {
795
        $db = $this->getConnection();
796
797
        $qb = $db->getQueryBuilder();
798
        $sql = $qb->renameTable('table_from', 'table_to');
799
800
        $this->assertSame(
801
            <<<SQL
802
            RENAME TABLE `table_from` TO `table_to`
803
            SQL,
804
            $sql,
805
        );
806
    }
807
808
    public function testSelectExpression(): void
809
    {
810
        $db = $this->getConnection();
811
812
        $qb = $db->getQueryBuilder();
813
        $query = $this->getQuery($db)->select(new Expression('1 AS ab'))->from('tablename');
814
815
        [$sql, $params] = $qb->build($query);
816
817
        $expected = DbHelper::replaceQuotes(
818
            <<<SQL
819
            SELECT 1 AS ab FROM [[tablename]]
820
            SQL,
821
            $db->getName(),
822
        );
823
824
        $this->assertSame($expected, $sql);
825
        $this->assertEmpty($params);
826
827
        $query = $this->getQuery($db)
828
            ->select(new Expression('1 AS ab'))
829
            ->addSelect(new Expression('2 AS cd'))
830
            ->addSelect(['ef' => new Expression('3')])
831
            ->from('tablename');
832
833
        [$sql, $params] = $qb->build($query);
834
835
        $expected = DbHelper::replaceQuotes(
836
            <<<SQL
837
            SELECT 1 AS ab, 2 AS cd, 3 AS [[ef]] FROM [[tablename]]
838
            SQL,
839
            $db->getName(),
840
        );
841
842
        $this->assertSame($expected, $sql);
843
        $this->assertEmpty($params);
844
845
        $query = $this->getQuery($db)
846
            ->select(new Expression('SUBSTR(name, 0, :len)', [':len' => 4]))
847
            ->from('tablename');
848
849
        [$sql, $params] = $qb->build($query);
850
851
        $expected = DbHelper::replaceQuotes(
852
            <<<SQL
853
            SELECT SUBSTR(name, 0, :len) FROM [[tablename]]
854
            SQL,
855
            $db->getName(),
856
        );
857
858
        $this->assertSame($expected, $sql);
859
        $this->assertSame([':len' => 4], $params);
860
    }
861
862
    public function testSelectExists(): void
863
    {
864
        $db = $this->getConnection();
865
866
        $qb = $db->getQueryBuilder();
867
        $sql = $qb->selectExists('SELECT 1 FROM `table` WHERE `id` = 1');
868
869
        $this->assertSame('SELECT EXISTS(SELECT 1 FROM `table` WHERE `id` = 1)', $sql);
870
    }
871
872
    public function testSelectSubquery(): void
873
    {
874
        $db = $this->getConnection();
875
876
        $qb = $db->getQueryBuilder();
877
        $expected = DbHelper::replaceQuotes(
878
            <<<SQL
879
            SELECT *, (SELECT COUNT(*) FROM [[operations]] WHERE account_id = accounts.id) AS [[operations_count]] FROM [[accounts]]
880
            SQL,
881
            $db->getName(),
882
        );
883
        $subquery = $this->getQuery($db)->select('COUNT(*)')->from('operations')->where('account_id = accounts.id');
884
        $query = $this->getQuery($db)->select('*')->from('accounts')->addSelect(['operations_count' => $subquery]);
885
886
        [$sql, $params] = $qb->build($query);
887
888
        $this->assertSame($expected, $sql);
889
        $this->assertEmpty($params);
890
    }
891
892
    public function testSetConditionClasses(): void
893
    {
894
        $db = $this->getConnection();
895
896
        $qb = $db->getQueryBuilder();
897
        $qb->setConditionClasses(['stdClass' => stdClass::class]);
898
        $dqlBuilder = Assert::getInaccessibleProperty($qb, 'dqlBuilder');
899
        $conditionClasses = Assert::getInaccessibleProperty($dqlBuilder, 'conditionClasses');
900
901
        $this->assertSame(stdClass::class, $conditionClasses['stdClass']);
902
    }
903
904
    public function testSelectExpressionBuilder(): void
905
    {
906
        $db = $this->getConnection();
907
908
        $qb = $db->getQueryBuilder();
909
        $qb->setExpressionBuilders(['stdClass' => stdClass::class]);
910
        $dqlBuilder = Assert::getInaccessibleProperty($qb, 'dqlBuilder');
911
        $expressionBuilders = Assert::getInaccessibleProperty($dqlBuilder, 'expressionBuilders');
912
913
        $this->assertSame(stdClass::class, $expressionBuilders['stdClass']);
914
    }
915
916
    public function testSetSeparator(): void
917
    {
918
        $db = $this->getConnection();
919
920
        $qb = $db->getQueryBuilder();
921
        $qb->setSeparator(' ');
922
        [$sql, $params] = $qb->build($this->getQuery($db)->select('*')->from('table'));
923
924
        $this->assertSame('SELECT * FROM `table`', $sql);
925
        $this->assertEmpty($params);
926
927
        $qb->setSeparator("\n");
928
        [$sql, $params] = $qb->build($this->getQuery($db)->select('*')->from('table'));
929
930
        $this->assertSame(
931
            <<<SQL
932
            SELECT *
933
            FROM `table`
934
            SQL,
935
            $sql,
936
        );
937
        $this->assertEmpty($params);
938
    }
939
940
    public function testTruncateTable(): void
941
    {
942
        $db = $this->getConnection();
943
944
        $qb = $db->getQueryBuilder();
945
        $sql = $qb->truncateTable('table');
946
947
        $this->assertSame('TRUNCATE TABLE `table`', $sql);
948
949
        $sql = $qb->truncateTable('table2');
950
951
        $this->assertSame('TRUNCATE TABLE `table2`', $sql);
952
    }
953
}
954