Passed
Push — master ( 9f7d35...3f1c7e )
by Wilmer
08:50 queued 06:32
created

TestCommandTrait::testCreateView()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 29
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 3.0123

Importance

Changes 0
Metric Value
cc 3
eloc 18
nc 4
nop 0
dl 0
loc 29
ccs 16
cts 18
cp 0.8889
crap 3.0123
rs 9.6666
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\TestUtility;
6
7
use PDO;
8
use Throwable;
9
use Yiisoft\Db\Connection\ConnectionInterface;
10
use Yiisoft\Db\Data\DataReader;
11
use Yiisoft\Db\Exception\Exception;
12
use Yiisoft\Db\Exception\IntegrityException;
13
use Yiisoft\Db\Exception\InvalidArgumentException;
14
use Yiisoft\Db\Expression\Expression;
15
use Yiisoft\Db\Query\Query;
16
use Yiisoft\Db\Schema\Schema;
17
18
use function call_user_func;
19
use function call_user_func_array;
20
use function date;
21
use function is_array;
22
use function range;
23
use function rtrim;
24
use function setlocale;
25
use function time;
26
27
trait TestCommandTrait
28
{
29 4
    public function testConstruct(): void
30
    {
31 4
        $db = $this->getConnection();
0 ignored issues
show
Bug introduced by
It seems like getConnection() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

31
        /** @scrutinizer ignore-call */ 
32
        $db = $this->getConnection();
Loading history...
32
33
        /* null */
34 4
        $command = $db->createCommand();
35
36 4
        $this->assertNull($command->getSql());
0 ignored issues
show
Bug introduced by
It seems like assertNull() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

36
        $this->/** @scrutinizer ignore-call */ 
37
               assertNull($command->getSql());
Loading history...
37
38
        /* string */
39 4
        $sql = 'SELECT * FROM customer';
40
41 4
        $command = $db->createCommand($sql);
42
43 4
        $this->assertEquals($sql, $command->getSql());
0 ignored issues
show
Bug introduced by
It seems like assertEquals() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

43
        $this->/** @scrutinizer ignore-call */ 
44
               assertEquals($sql, $command->getSql());
Loading history...
44 4
    }
45
46 4
    public function testGetSetSql(): void
47
    {
48 4
        $db = $this->getConnection();
49
50 4
        $sql = 'SELECT * FROM customer';
51
52 4
        $command = $db->createCommand($sql);
53
54 4
        $this->assertEquals($sql, $command->getSql());
55
56 4
        $sql2 = 'SELECT * FROM order';
57
58 4
        $command->setSql($sql2);
59
60 4
        $this->assertEquals($sql2, $command->getSql());
61 4
    }
62
63 4
    public function testPrepareCancel(): void
64
    {
65 4
        $db = $this->getConnection();
66
67 4
        $command = $db->createCommand('SELECT * FROM {{customer}}');
68
69 4
        $this->assertNull($command->getPdoStatement());
70
71 4
        $command->prepare();
72
73 4
        $this->assertNotNull($command->getPdoStatement());
0 ignored issues
show
Bug introduced by
It seems like assertNotNull() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

73
        $this->/** @scrutinizer ignore-call */ 
74
               assertNotNull($command->getPdoStatement());
Loading history...
74
75 4
        $command->cancel();
76
77 4
        $this->assertNull($command->getPdoStatement());
78 4
    }
79
80 4
    public function testExecute(): void
81
    {
82 4
        $db = $this->getConnection(true);
83
84
        $sql = 'INSERT INTO {{customer}}([[email]], [[name]], [[address]])'
85 4
            . ' VALUES (\'[email protected]\', \'user4\', \'address4\')';
86
87 4
        $command = $db->createCommand($sql);
88
89 4
        $this->assertEquals(1, $command->execute());
90
91 4
        $sql = 'SELECT COUNT(*) FROM {{customer}} WHERE [[name]] = \'user4\'';
92
93 4
        $command = $db->createCommand($sql);
94
95 4
        $this->assertEquals(1, $command->queryScalar());
96
97 4
        $command = $db->createCommand('bad SQL');
98
99 4
        $this->expectException(Exception::class);
0 ignored issues
show
Bug introduced by
It seems like expectException() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

99
        $this->/** @scrutinizer ignore-call */ 
100
               expectException(Exception::class);
Loading history...
100
101 4
        $command->execute();
102
    }
103
104 4
    public function testQuery(): void
105
    {
106 4
        $db = $this->getConnection(true);
107
108
        /* query */
109 4
        $sql = 'SELECT * FROM {{customer}}';
110
111 4
        $reader = $db->createCommand($sql)->Query();
112
113 4
        $this->assertInstanceOf(DataReader::class, $reader);
0 ignored issues
show
Bug introduced by
It seems like assertInstanceOf() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

113
        $this->/** @scrutinizer ignore-call */ 
114
               assertInstanceOf(DataReader::class, $reader);
Loading history...
114
115
        /* queryAll */
116 4
        $rows = $db->createCommand('SELECT * FROM {{customer}}')->queryAll();
117
118 4
        $this->assertCount(3, $rows);
0 ignored issues
show
Bug introduced by
It seems like assertCount() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

118
        $this->/** @scrutinizer ignore-call */ 
119
               assertCount(3, $rows);
Loading history...
119
120 4
        $row = $rows[2];
121
122 4
        $this->assertEquals(3, $row['id']);
123 4
        $this->assertEquals('user3', $row['name']);
124
125 4
        $rows = $db->createCommand('SELECT * FROM {{customer}} WHERE [[id]] = 10')->queryAll();
126
127 4
        $this->assertEquals([], $rows);
128
129
        /* queryOne */
130 4
        $sql = 'SELECT * FROM {{customer}} ORDER BY [[id]]';
131
132 4
        $row = $db->createCommand($sql)->queryOne();
133
134 4
        $this->assertEquals(1, $row['id']);
135 4
        $this->assertEquals('user1', $row['name']);
136
137 4
        $sql = 'SELECT * FROM {{customer}} ORDER BY [[id]]';
138
139 4
        $command = $db->createCommand($sql);
140
141 4
        $command->prepare();
142
143 4
        $row = $command->queryOne();
144
145 4
        $this->assertEquals(1, $row['id']);
146 4
        $this->assertEquals('user1', $row['name']);
147
148 4
        $sql = 'SELECT * FROM {{customer}} WHERE [[id]] = 10';
149
150 4
        $command = $db->createCommand($sql);
151
152 4
        $this->assertFalse($command->queryOne());
0 ignored issues
show
Bug introduced by
It seems like assertFalse() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

152
        $this->/** @scrutinizer ignore-call */ 
153
               assertFalse($command->queryOne());
Loading history...
153
154
        /* queryColumn */
155 4
        $sql = 'SELECT * FROM {{customer}}';
156
157 4
        $column = $db->createCommand($sql)->queryColumn();
158
159 4
        $this->assertEquals(range(1, 3), $column);
160
161 4
        $command = $db->createCommand('SELECT [[id]] FROM {{customer}} WHERE [[id]] = 10');
162
163 4
        $this->assertEquals([], $command->queryColumn());
164
165
        /* queryScalar */
166 4
        $sql = 'SELECT * FROM {{customer}} ORDER BY [[id]]';
167
168 4
        $this->assertEquals($db->createCommand($sql)->queryScalar(), 1);
169
170 4
        $sql = 'SELECT [[id]] FROM {{customer}} ORDER BY [[id]]';
171
172 4
        $command = $db->createCommand($sql);
173
174 4
        $command->prepare();
175
176 4
        $this->assertEquals(1, $command->queryScalar());
177
178 4
        $command = $db->createCommand('SELECT [[id]] FROM {{customer}} WHERE [[id]] = 10');
179
180 4
        $this->assertFalse($command->queryScalar());
181
182 4
        $command = $db->createCommand('bad SQL');
183
184 4
        $this->expectException(Exception::class);
185
186 4
        $command->Query();
187
    }
188
189 4
    public function testFetchMode(): void
190
    {
191 4
        $db = $this->getConnection();
192
193
        /* default: FETCH_ASSOC */
194 4
        $sql = 'SELECT * FROM {{customer}}';
195
196 4
        $command = $db->createCommand($sql);
197
198 4
        $result = $command->queryOne();
199
200 4
        $this->assertTrue(is_array($result) && isset($result['id']));
0 ignored issues
show
Bug introduced by
It seems like assertTrue() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

200
        $this->/** @scrutinizer ignore-call */ 
201
               assertTrue(is_array($result) && isset($result['id']));
Loading history...
201
202
        /* FETCH_OBJ, customized via fetchMode property */
203 4
        $sql = 'SELECT * FROM {{customer}}';
204
205 4
        $command = $db->createCommand($sql);
206
207 4
        $command->setFetchMode(PDO::FETCH_OBJ);
208
209 4
        $result = $command->queryOne();
210
211 4
        $this->assertIsObject($result);
0 ignored issues
show
Bug introduced by
It seems like assertIsObject() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

211
        $this->/** @scrutinizer ignore-call */ 
212
               assertIsObject($result);
Loading history...
212
213
        /* FETCH_NUM, customized in query method */
214 4
        $sql = 'SELECT * FROM {{customer}}';
215
216 4
        $command = $db->createCommand($sql);
217
218 4
        $result = $command->queryOne(PDO::FETCH_NUM);
219
220 4
        $this->assertTrue(is_array($result) && isset($result[0]));
221 4
    }
222
223 4
    public function testBatchInsert(): void
224
    {
225 4
        $db = $this->getConnection();
226
227 4
        $command = $db->createCommand();
228
229 4
        $command->batchInsert(
230 4
            '{{customer}}',
231 4
            ['email', 'name', 'address'],
232
            [
233 4
                ['[email protected]', 't1', 't1 address'],
234
                ['[email protected]', null, false],
235
            ]
236
        );
237
238 4
        $this->assertEquals(2, $command->execute());
239
240
        /**
241
         * {@see https://github.com/yiisoft/yii2/issues/11693}
242
         */
243 4
        $command = $this->getConnection()->createCommand();
244
245 4
        $command->batchInsert(
246 4
            '{{customer}}',
247 4
            ['email', 'name', 'address'],
248 4
            []
249
        );
250
251 4
        $this->assertEquals(0, $command->execute());
252 4
    }
253
254 4
    public function testBatchInsertWithYield(): void
255
    {
256 4
        $rows = call_user_func(static function () {
257 4
            if (false) {
258
                yield [];
259
            }
260 4
        });
261
262 4
        $command = $this->getConnection()->createCommand();
263
264 4
        $command->batchInsert(
265 4
            '{{customer}}',
266 4
            ['email', 'name', 'address'],
267
            $rows
268
        );
269
270 4
        $this->assertEquals(0, $command->execute());
271 4
    }
272
273
    /**
274
     * Test batch insert with different data types.
275
     *
276
     * Ensure double is inserted with `.` decimal separator.
277
     *
278
     * {@see https://github.com/yiisoft/yii2/issues/6526}
279
     */
280 4
    public function testBatchInsertDataTypesLocale(): void
281
    {
282 4
        $locale = setlocale(LC_NUMERIC, 0);
283
284 4
        if (false === $locale) {
285
            $this->markTestSkipped('Your platform does not support locales.');
0 ignored issues
show
Bug introduced by
It seems like markTestSkipped() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

285
            $this->/** @scrutinizer ignore-call */ 
286
                   markTestSkipped('Your platform does not support locales.');
Loading history...
286
        }
287
288 4
        $db = $this->getConnection();
289
290
        try {
291
            /* This one sets decimal mark to comma sign */
292 4
            setlocale(LC_NUMERIC, 'ru_RU.utf8');
293
294 4
            $cols = ['int_col', 'char_col', 'float_col', 'bool_col'];
295
296
            $data = [
297 4
                [1, 'A', 9.735, true],
298
                [2, 'B', -2.123, false],
299
                [3, 'C', 2.123, false],
300
            ];
301
302
            /* clear data in "type" table */
303 4
            $db->createCommand()->delete('type')->execute();
304
305
            /* batch insert on "type" table */
306 4
            $db->createCommand()->batchInsert('type', $cols, $data)->execute();
307
308 4
            $data = $db->createCommand(
309 4
                'SELECT int_col, char_col, float_col, bool_col FROM {{type}} WHERE [[int_col]] IN (1,2,3)
310
                ORDER BY [[int_col]];'
311 4
            )->queryAll();
312
313 4
            $this->assertCount(3, $data);
314 4
            $this->assertEquals(1, $data[0]['int_col']);
315 4
            $this->assertEquals(2, $data[1]['int_col']);
316 4
            $this->assertEquals(3, $data[2]['int_col']);
317
318
            /* rtrim because Postgres padds the column with whitespace */
319 4
            $this->assertEquals('A', rtrim($data[0]['char_col']));
320 4
            $this->assertEquals('B', rtrim($data[1]['char_col']));
321 4
            $this->assertEquals('C', rtrim($data[2]['char_col']));
322 4
            $this->assertEquals('9.735', $data[0]['float_col']);
323 4
            $this->assertEquals('-2.123', $data[1]['float_col']);
324 4
            $this->assertEquals('2.123', $data[2]['float_col']);
325 4
            $this->assertEquals('1', $data[0]['bool_col']);
326 4
            $this->assertIsOneOf($data[1]['bool_col'], ['0', false]);
0 ignored issues
show
Bug introduced by
It seems like assertIsOneOf() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

326
            $this->/** @scrutinizer ignore-call */ 
327
                   assertIsOneOf($data[1]['bool_col'], ['0', false]);
Loading history...
327 4
            $this->assertIsOneOf($data[2]['bool_col'], ['0', false]);
328
        } catch (Exception $e) {
329
            setlocale(LC_NUMERIC, $locale);
330
331
            throw $e;
332
        } catch (Throwable $e) {
333
            setlocale(LC_NUMERIC, $locale);
334
335
            throw $e;
336
        }
337
338 4
        setlocale(LC_NUMERIC, $locale);
339 4
    }
340
341 4
    public function testInsert(): void
342
    {
343 4
        $db = $this->getConnection();
344
345 4
        $db->createCommand('DELETE FROM {{customer}}')->execute();
346
347 4
        $command = $db->createCommand();
348
349 4
        $command->insert(
350 4
            '{{customer}}',
351
            [
352 4
                'email'   => '[email protected]',
353
                'name'    => 'test',
354
                'address' => 'test address',
355
            ]
356 4
        )->execute();
357
358 4
        $this->assertEquals(1, $db->createCommand('SELECT COUNT(*) FROM {{customer}};')->queryScalar());
359
360 4
        $record = $db->createCommand('SELECT [[email]], [[name]], [[address]] FROM {{customer}}')->queryOne();
361
362 4
        $this->assertEquals([
363 4
            'email'   => '[email protected]',
364
            'name'    => 'test',
365
            'address' => 'test address',
366
        ], $record);
367 4
    }
368
369
    /**
370
     * verify that {{}} are not going to be replaced in parameters.
371
     */
372 4
    public function testNoTablenameReplacement(): void
373
    {
374 4
        $db = $this->getConnection(true);
375
376 4
        $db->createCommand()->insert(
377 4
            '{{customer}}',
378
            [
379 4
                'name'    => 'Some {{weird}} name',
380
                'email'   => '[email protected]',
381
                'address' => 'Some {{%weird}} address',
382
            ]
383 4
        )->execute();
384
385 4
        if ($db->getDriverName() === 'pgsql') {
386 1
            $customerId = $db->getLastInsertID('public.customer_id_seq');
387
        } else {
388 3
            $customerId = $db->getLastInsertID();
389
        }
390
391 4
        $customer = $db->createCommand('SELECT * FROM {{customer}} WHERE id=' . $customerId)->queryOne();
392
393 4
        $this->assertEquals('Some {{weird}} name', $customer['name']);
394 4
        $this->assertEquals('Some {{%weird}} address', $customer['address']);
395
396 4
        $db->createCommand()->update(
397 4
            '{{customer}}',
398
            [
399 4
                'name'    => 'Some {{updated}} name',
400
                'address' => 'Some {{%updated}} address',
401
            ],
402 4
            ['id' => $customerId]
403 4
        )->execute();
404
405 4
        $customer = $db->createCommand('SELECT * FROM {{customer}} WHERE id=' . $customerId)->queryOne();
406
407 4
        $this->assertEquals('Some {{updated}} name', $customer['name']);
408 4
        $this->assertEquals('Some {{%updated}} address', $customer['address']);
409 4
    }
410
411
    /**
412
     * Test INSERT INTO ... SELECT SQL statement.
413
     */
414 4
    public function testInsertSelect(): void
415
    {
416 4
        $db = $this->getConnection();
417
418 4
        $db->createCommand('DELETE FROM {{customer}}')->execute();
419
420 4
        $command = $db->createCommand();
421
422 4
        $command->insert(
423 4
            '{{customer}}',
424
            [
425 4
                'email'   => '[email protected]',
426
                'name'    => 'test',
427
                'address' => 'test address',
428
            ]
429 4
        )->execute();
430
431 4
        $query = new Query($db);
432
433 4
        $query->select(
434
            [
435 4
                '{{customer}}.[[email]] as name',
436
                '[[name]] as email',
437
                '[[address]]',
438
            ]
439
        )
440 4
            ->from('{{customer}}')
441 4
            ->where([
442 4
                'and',
443
                ['<>', 'name', 'foo'],
444
                ['status' => [0, 1, 2, 3]],
445
            ]);
446
447 4
        $command = $db->createCommand();
448
449 4
        $command->insert(
450 4
            '{{customer}}',
451
            $query
452 4
        )->execute();
453
454 4
        $this->assertEquals(2, $db->createCommand('SELECT COUNT(*) FROM {{customer}}')->queryScalar());
455
456 4
        $record = $db->createCommand('SELECT [[email]], [[name]], [[address]] FROM {{customer}}')->queryAll();
457
458 4
        $this->assertEquals([
459
            [
460 4
                'email'   => '[email protected]',
461
                'name'    => 'test',
462
                'address' => 'test address',
463
            ],
464
            [
465
                'email'   => 'test',
466
                'name'    => '[email protected]',
467
                'address' => 'test address',
468
            ],
469
        ], $record);
470 4
    }
471
472
    /**
473
     * Test INSERT INTO ... SELECT SQL statement with alias syntax.
474
     */
475 4
    public function testInsertSelectAlias(): void
476
    {
477 4
        $db = $this->getConnection();
478
479 4
        $db->createCommand('DELETE FROM {{customer}}')->execute();
480
481 4
        $command = $db->createCommand();
482
483 4
        $command->insert(
484 4
            '{{customer}}',
485
            [
486 4
                'email'   => '[email protected]',
487
                'name'    => 'test',
488
                'address' => 'test address',
489
            ]
490 4
        )->execute();
491
492 4
        $query = new Query($db);
493
494 4
        $query->select(
495
            [
496 4
                'email'   => '{{customer}}.[[email]]',
497
                'address' => 'name',
498
                'name'    => 'address',
499
            ]
500
        )
501 4
            ->from('{{customer}}')
502 4
            ->where([
503 4
                'and',
504
                ['<>', 'name', 'foo'],
505
                ['status' => [0, 1, 2, 3]],
506
            ]);
507
508 4
        $command = $db->createCommand();
509
510 4
        $command->insert(
511 4
            '{{customer}}',
512
            $query
513 4
        )->execute();
514
515 4
        $this->assertEquals(2, $db->createCommand('SELECT COUNT(*) FROM {{customer}}')->queryScalar());
516
517 4
        $record = $db->createCommand('SELECT [[email]], [[name]], [[address]] FROM {{customer}}')->queryAll();
518
519 4
        $this->assertEquals([
520
            [
521 4
                'email'   => '[email protected]',
522
                'name'    => 'test',
523
                'address' => 'test address',
524
            ],
525
            [
526
                'email'   => '[email protected]',
527
                'name'    => 'test address',
528
                'address' => 'test',
529
            ],
530
        ], $record);
531 4
    }
532
533 4
    public function testInsertExpression(): void
534
    {
535 4
        $db = $this->getConnection();
536
537 4
        $db->createCommand('DELETE FROM {{order_with_null_fk}}')->execute();
538
539 4
        switch ($db->getDriverName()) {
540 4
            case 'pgsql':
541 1
                $expression = "EXTRACT(YEAR FROM TIMESTAMP 'now')";
542 1
                break;
543 3
            case 'mysql':
544 1
                $expression = 'YEAR(NOW())';
545 1
                break;
546 2
            case 'sqlite':
547 1
                $expression = "strftime('%Y')";
548 1
                break;
549 1
            case 'sqlsrv':
550 1
                $expression = 'YEAR(GETDATE())';
551
        }
552
553 4
        $command = $db->createCommand();
554
555 4
        $command->insert(
556 4
            '{{order_with_null_fk}}',
557
            [
558 4
                'created_at' => new Expression($expression),
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $expression does not seem to be defined for all execution paths leading up to this point.
Loading history...
559 4
                'total' => 1,
560
            ]
561 4
        )->execute();
562
563 4
        $this->assertEquals(1, $db->createCommand('SELECT COUNT(*) FROM {{order_with_null_fk}}')->queryScalar());
564
565 4
        $record = $db->createCommand('SELECT [[created_at]] FROM {{order_with_null_fk}}')->queryOne();
566
567 4
        $this->assertEquals([
568 4
            'created_at' => date('Y'),
569
        ], $record);
570 4
    }
571
572 4
    public function testsInsertQueryAsColumnValue(): void
573
    {
574 4
        $time = time();
575
576 4
        $db = $this->getConnection(true);
577
578 4
        $db->createCommand('DELETE FROM {{order_with_null_fk}}')->execute();
579
580 4
        $command = $db->createCommand();
581
582 4
        $command->insert('{{order}}', [
583 4
            'customer_id' => 1,
584 4
            'created_at'  => $time,
585 4
            'total'       => 42,
586 4
        ])->execute();
587
588 4
        if ($db->getDriverName() === 'pgsql') {
589 1
            $orderId = $db->getLastInsertID('public.order_id_seq');
590
        } else {
591 3
            $orderId = $db->getLastInsertID();
592
        }
593
594 4
        $columnValueQuery = new Query($db);
595
596 4
        $columnValueQuery->select('created_at')->from('{{order}}')->where(['id' => $orderId]);
597
598 4
        $command = $db->createCommand();
599
600 4
        $command->insert(
601 4
            '{{order_with_null_fk}}',
602
            [
603 4
                'customer_id' => $orderId,
604 4
                'created_at'  => $columnValueQuery,
605 4
                'total'       => 42,
606
            ]
607 4
        )->execute();
608
609 4
        $this->assertEquals(
610
            $time,
611 4
            $db->createCommand(
612 4
                'SELECT [[created_at]] FROM {{order_with_null_fk}} WHERE [[customer_id]] = ' . $orderId
613 4
            )->queryScalar()
614
        );
615
616 4
        $db->createCommand('DELETE FROM {{order_with_null_fk}}')->execute();
617 4
        $db->createCommand('DELETE FROM {{order}} WHERE [[id]] = ' . $orderId)->execute();
618 4
    }
619
620 4
    public function testCreateTable(): void
621
    {
622 4
        $db = $this->getConnection();
623
624 4
        if ($db->getSchema()->getTableSchema('testCreateTable') !== null) {
625
            $db->createCommand()->dropTable('testCreateTable')->execute();
626
        }
627
628 4
        $db->createCommand()->createTable(
629 4
            'testCreateTable',
630 4
            ['id' => Schema::TYPE_PK, 'bar' => Schema::TYPE_INTEGER]
631 4
        )->execute();
632
633 4
        $db->createCommand()->insert('testCreateTable', ['bar' => 1])->execute();
634
635 4
        $records = $db->createCommand('SELECT [[id]], [[bar]] FROM {{testCreateTable}};')->queryAll();
636
637 4
        $this->assertEquals([
638 4
            ['id' => 1, 'bar' => 1],
639
        ], $records);
640 4
    }
641
642 4
    public function testDropTable(): void
643
    {
644 4
        $db = $this->getConnection();
645
646 4
        $tableName = 'type';
647
648 4
        $this->assertNotNull($db->getSchema()->getTableSchema($tableName));
649
650 4
        $db->createCommand()->dropTable($tableName)->execute();
651
652 4
        $this->assertNull($db->getSchema()->getTableSchema($tableName));
653 4
    }
654
655 4
    public function testTruncateTable(): void
656
    {
657 4
        $db = $this->getConnection();
658
659 4
        $rows = $db->createCommand('SELECT * FROM {{animal}}')->queryAll();
660
661 4
        $this->assertCount(2, $rows);
662
663 4
        $db->createCommand()->truncateTable('animal')->execute();
664
665 4
        $rows = $db->createCommand('SELECT * FROM {{animal}}')->queryAll();
666
667 4
        $this->assertCount(0, $rows);
668 4
    }
669
670 4
    public function testRenameTable(): void
671
    {
672 4
        $db = $this->getConnection(true);
673
674 4
        $fromTableName = 'type';
675 4
        $toTableName = 'new_type';
676
677 4
        if ($db->getSchema()->getTableSchema($toTableName) !== null) {
678
            $db->createCommand()->dropTable($toTableName)->execute();
679
        }
680
681 4
        $this->assertNotNull($db->getSchema()->getTableSchema($fromTableName));
682 4
        $this->assertNull($db->getSchema()->getTableSchema($toTableName));
683
684 4
        $db->createCommand()->renameTable($fromTableName, $toTableName)->execute();
685
686 4
        $this->assertNull($db->getSchema()->getTableSchema($fromTableName, true));
687 4
        $this->assertNotNull($db->getSchema()->getTableSchema($toTableName, true));
688 4
    }
689
690 24
    protected function performAndCompareUpsertResult(ConnectionInterface $db, array $data): void
691
    {
692 24
        $params = $data['params'];
693 24
        $expected = $data['expected'] ?? $params[1];
694
695 24
        $command = $db->createCommand();
696
697 24
        call_user_func_array([$command, 'upsert'], $params);
698
699 24
        $command->execute();
700
701 24
        $actual = (new Query($db))
702 24
            ->select([
703 24
                'email',
704 24
                'address' => new Expression($this->upsertTestCharCast),
705 24
                'status',
706
            ])
707 24
            ->from('T_upsert')
708 24
            ->one();
709
710 24
        $this->assertEquals($expected, $actual, $this->upsertTestCharCast);
711 24
    }
712
713 4
    public function testAddDropForeignKey(): void
714
    {
715 4
        $db = $this->getConnection();
716
717 4
        $tableName = 'test_fk';
718 4
        $name = 'test_fk_constraint';
719
720 4
        $schema = $db->getSchema();
721
722 4
        if ($schema->getTableSchema($tableName) !== null) {
723
            $db->createCommand()->dropTable($tableName)->execute();
724
        }
725
726 4
        $db->createCommand()->createTable($tableName, [
727 4
            'int1' => 'integer not null unique',
728
            'int2' => 'integer not null unique',
729
            'int3' => 'integer not null unique',
730
            'int4' => 'integer not null unique',
731
            'unique ([[int1]], [[int2]])',
732
            'unique ([[int3]], [[int4]])',
733 4
        ])->execute();
734
735 4
        $this->assertEmpty($schema->getTableForeignKeys($tableName, true));
0 ignored issues
show
Bug introduced by
It seems like assertEmpty() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

735
        $this->/** @scrutinizer ignore-call */ 
736
               assertEmpty($schema->getTableForeignKeys($tableName, true));
Loading history...
736
737 4
        $db->createCommand()->addForeignKey($name, $tableName, ['int1'], $tableName, ['int3'])->execute();
738
739 4
        $this->assertEquals(['int1'], $schema->getTableForeignKeys($tableName, true)[0]->getColumnNames());
740 4
        $this->assertEquals(['int3'], $schema->getTableForeignKeys($tableName, true)[0]->getForeignColumnNames());
741
742 4
        $db->createCommand()->dropForeignKey($name, $tableName)->execute();
743
744 4
        $this->assertEmpty($schema->getTableForeignKeys($tableName, true));
745
746 4
        $db->createCommand()->addForeignKey(
747
            $name,
748
            $tableName,
749 4
            ['int1', 'int2'],
750
            $tableName,
751 4
            ['int3', 'int4']
752 4
        )->execute();
753
754 4
        $this->assertEquals(
755 4
            ['int1', 'int2'],
756 4
            $schema->getTableForeignKeys($tableName, true)[0]->getColumnNames()
757
        );
758 4
        $this->assertEquals(
759 4
            ['int3', 'int4'],
760 4
            $schema->getTableForeignKeys($tableName, true)[0]->getForeignColumnNames()
761
        );
762 4
    }
763
764 4
    public function testCreateDropIndex(): void
765
    {
766 4
        $db = $this->getConnection();
767
768 4
        $tableName = 'test_idx';
769 4
        $name = 'test_idx_constraint';
770
771 4
        $schema = $db->getSchema();
772
773 4
        if ($schema->getTableSchema($tableName) !== null) {
774
            $db->createCommand()->dropTable($tableName)->execute();
775
        }
776
777 4
        $db->createCommand()->createTable($tableName, [
778 4
            'int1' => 'integer not null',
779
            'int2' => 'integer not null',
780 4
        ])->execute();
781
782 4
        $this->assertEmpty($schema->getTableIndexes($tableName, true));
783
784 4
        $db->createCommand()->createIndex($name, $tableName, ['int1'])->execute();
785
786 4
        $this->assertEquals(['int1'], $schema->getTableIndexes($tableName, true)[0]->getColumnNames());
787 4
        $this->assertFalse($schema->getTableIndexes($tableName, true)[0]->isUnique());
788
789 4
        $db->createCommand()->dropIndex($name, $tableName)->execute();
790
791 4
        $this->assertEmpty($schema->getTableIndexes($tableName, true));
792
793 4
        $db->createCommand()->createIndex($name, $tableName, ['int1', 'int2'])->execute();
794
795 4
        $this->assertEquals(['int1', 'int2'], $schema->getTableIndexes($tableName, true)[0]->getColumnNames());
796 4
        $this->assertFalse($schema->getTableIndexes($tableName, true)[0]->isUnique());
797
798 4
        $db->createCommand()->dropIndex($name, $tableName)->execute();
799
800 4
        $this->assertEmpty($schema->getTableIndexes($tableName, true));
801 4
        $this->assertEmpty($schema->getTableIndexes($tableName, true));
802
803 4
        $db->createCommand()->createIndex($name, $tableName, ['int1'], true)->execute();
804
805 4
        $this->assertEquals(['int1'], $schema->getTableIndexes($tableName, true)[0]->getColumnNames());
806 4
        $this->assertTrue($schema->getTableIndexes($tableName, true)[0]->isUnique());
807
808 4
        $db->createCommand()->dropIndex($name, $tableName)->execute();
809
810 4
        $this->assertEmpty($schema->getTableIndexes($tableName, true));
811
812 4
        $db->createCommand()->createIndex($name, $tableName, ['int1', 'int2'], true)->execute();
813
814 4
        $this->assertEquals(['int1', 'int2'], $schema->getTableIndexes($tableName, true)[0]->getColumnNames());
815 4
        $this->assertTrue($schema->getTableIndexes($tableName, true)[0]->isUnique());
816 4
    }
817
818 4
    public function testAddDropUnique(): void
819
    {
820 4
        $db = $this->getConnection();
821
822 4
        $tableName = 'test_uq';
823 4
        $name = 'test_uq_constraint';
824
825 4
        $schema = $db->getSchema();
826
827 4
        if ($schema->getTableSchema($tableName) !== null) {
828
            $db->createCommand()->dropTable($tableName)->execute();
829
        }
830
831 4
        $db->createCommand()->createTable($tableName, [
832 4
            'int1' => 'integer not null',
833
            'int2' => 'integer not null',
834 4
        ])->execute();
835
836 4
        $this->assertEmpty($schema->getTableUniques($tableName, true));
837
838 4
        $db->createCommand()->addUnique($name, $tableName, ['int1'])->execute();
839
840 4
        $this->assertEquals(['int1'], $schema->getTableUniques($tableName, true)[0]->getColumnNames());
841
842 4
        $db->createCommand()->dropUnique($name, $tableName)->execute();
843
844 4
        $this->assertEmpty($schema->getTableUniques($tableName, true));
845
846 4
        $db->createCommand()->addUnique($name, $tableName, ['int1', 'int2'])->execute();
847
848 4
        $this->assertEquals(['int1', 'int2'], $schema->getTableUniques($tableName, true)[0]->getColumnNames());
849 4
    }
850
851 4
    public function testIntegrityViolation(): void
852
    {
853 4
        $this->expectException(IntegrityException::class);
854
855 4
        $db = $this->getConnection();
856
857 4
        $sql = 'INSERT INTO {{profile}}([[id]], [[description]]) VALUES (123, \'duplicate\')';
858
859 4
        $command = $db->createCommand($sql);
860
861 4
        $command->execute();
862 3
        $command->execute();
863
    }
864
865 3
    public function testLastInsertId(): void
866
    {
867 3
        $db = $this->getConnection(true);
868
869 3
        $sql = 'INSERT INTO {{profile}}([[description]]) VALUES (\'non duplicate\')';
870
871 3
        $command = $db->createCommand($sql);
872
873 3
        $command->execute();
874
875 3
        $this->assertEquals(3, $db->getSchema()->getLastInsertID());
876 3
    }
877
878 4
    public function testQueryCache(): void
879
    {
880 4
        $db = $this->getConnection();
881
882 4
        $db->setEnableQueryCache(true);
883 4
        $db->setQueryCache($this->cache);
884
885 4
        $command = $db->createCommand('SELECT [[name]] FROM {{customer}} WHERE [[id]] = :id');
886
887 4
        $this->assertEquals('user1', $command->bindValue(':id', 1)->queryScalar());
888
889 4
        $update = $db->createCommand('UPDATE {{customer}} SET [[name]] = :name WHERE [[id]] = :id');
890
891 4
        $update->bindValues([':id' => 1, ':name' => 'user11'])->execute();
892
893 4
        $this->assertEquals('user11', $command->bindValue(':id', 1)->queryScalar());
894
895 4
        $db->cache(function (ConnectionInterface $db) use ($command, $update) {
896 4
            $this->assertEquals('user2', $command->bindValue(':id', 2)->queryScalar());
897
898 4
            $update->bindValues([':id' => 2, ':name' => 'user22'])->execute();
899
900 4
            $this->assertEquals('user2', $command->bindValue(':id', 2)->queryScalar());
901
902 4
            $db->noCache(function () use ($command) {
0 ignored issues
show
Bug introduced by
The method noCache() does not exist on Yiisoft\Db\Connection\ConnectionInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Yiisoft\Db\Connection\ConnectionInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

902
            $db->/** @scrutinizer ignore-call */ 
903
                 noCache(function () use ($command) {
Loading history...
903 4
                $this->assertEquals('user22', $command->bindValue(':id', 2)->queryScalar());
904 4
            });
905
906 4
            $this->assertEquals('user2', $command->bindValue(':id', 2)->queryScalar());
907 4
        }, 10);
908
909 4
        $db->setEnableQueryCache(false);
910
911 4
        $db->cache(function () use ($command, $update) {
912 4
            $this->assertEquals('user22', $command->bindValue(':id', 2)->queryScalar());
913 4
            $update->bindValues([':id' => 2, ':name' => 'user2'])->execute();
914 4
            $this->assertEquals('user2', $command->bindValue(':id', 2)->queryScalar());
915 4
        }, 10);
916
917 4
        $db->setEnableQueryCache(true);
918
919 4
        $command = $db->createCommand('SELECT [[name]] FROM {{customer}} WHERE [[id]] = :id')->cache();
920
921 4
        $this->assertEquals('user11', $command->bindValue(':id', 1)->queryScalar());
922
923 4
        $update->bindValues([':id' => 1, ':name' => 'user1'])->execute();
924
925 4
        $this->assertEquals('user11', $command->bindValue(':id', 1)->queryScalar());
926 4
        $this->assertEquals('user1', $command->noCache()->bindValue(':id', 1)->queryScalar());
927
928 4
        $command = $db->createCommand('SELECT [[name]] FROM {{customer}} WHERE [[id]] = :id');
929
930 4
        $db->cache(function () use ($command) {
931 4
            $this->assertEquals('user11', $command->bindValue(':id', 1)->queryScalar());
932 4
            $this->assertEquals('user1', $command->noCache()->bindValue(':id', 1)->queryScalar());
933 4
        }, 10);
934 4
    }
935
936 4
    public function testColumnCase(): void
937
    {
938 4
        $db = $this->getConnection();
939
940 4
        $this->assertEquals(PDO::CASE_NATURAL, $db->getSlavePdo()->getAttribute(PDO::ATTR_CASE));
941
942 4
        $sql = 'SELECT [[customer_id]], [[total]] FROM {{order}}';
943
944 4
        $rows = $db->createCommand($sql)->queryAll();
945
946 4
        $this->assertTrue(isset($rows[0]));
947 4
        $this->assertTrue(isset($rows[0]['customer_id']));
948 4
        $this->assertTrue(isset($rows[0]['total']));
949
950 4
        $db->getSlavePdo()->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
951
952 4
        $rows = $db->createCommand($sql)->queryAll();
953
954 4
        $this->assertTrue(isset($rows[0]));
955 4
        $this->assertTrue(isset($rows[0]['customer_id']));
956 4
        $this->assertTrue(isset($rows[0]['total']));
957
958 4
        $db->getSlavePdo()->setAttribute(PDO::ATTR_CASE, PDO::CASE_UPPER);
959
960 4
        $rows = $db->createCommand($sql)->queryAll();
961
962 4
        $this->assertTrue(isset($rows[0]));
963 4
        $this->assertTrue(isset($rows[0]['CUSTOMER_ID']));
964 4
        $this->assertTrue(isset($rows[0]['TOTAL']));
965 4
    }
966
967 4
    public function testTransaction(): void
968
    {
969 4
        $db = $this->getConnection();
970
971 4
        $this->assertNull($db->getTransaction());
972
973 4
        $command = $db->createCommand("INSERT INTO {{profile}}([[description]]) VALUES('command transaction')");
974
975 4
        $this->invokeMethod($command, 'requireTransaction');
0 ignored issues
show
Bug introduced by
It seems like invokeMethod() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

975
        $this->/** @scrutinizer ignore-call */ 
976
               invokeMethod($command, 'requireTransaction');
Loading history...
976
977 4
        $command->execute();
978
979 4
        $this->assertNull($db->getTransaction());
980 4
        $this->assertEquals(
981 4
            1,
982 4
            $db->createCommand(
983 4
                "SELECT COUNT(*) FROM {{profile}} WHERE [[description]] = 'command transaction'"
984 4
            )->queryScalar()
985
        );
986 4
    }
987
988 4
    public function testRetryHandler(): void
989
    {
990 4
        $db = $this->getConnection();
991
992 4
        $this->assertNull($db->getTransaction());
993
994 4
        $db->createCommand("INSERT INTO {{profile}}([[description]]) VALUES('command retry')")->execute();
995
996 4
        $this->assertNull($db->getTransaction());
997 4
        $this->assertEquals(
998 4
            1,
999 4
            $db->createCommand(
1000 4
                "SELECT COUNT(*) FROM {{profile}} WHERE [[description]] = 'command retry'"
1001 4
            )->queryScalar()
1002
        );
1003
1004 4
        $attempts = null;
1005 4
        $hitHandler = false;
1006 4
        $hitCatch = false;
1007
1008 4
        $command = $db->createCommand(
1009 4
            "INSERT INTO {{profile}}([[id]], [[description]]) VALUES(1, 'command retry')"
1010
        );
1011
1012 4
        $this->invokeMethod(
1013
            $command,
1014 4
            'setRetryHandler',
1015 4
            [static function ($exception, $attempt) use (&$attempts, &$hitHandler) {
1016 4
                $attempts = $attempt;
1017 4
                $hitHandler = true;
1018
1019 4
                return $attempt <= 2;
1020 4
            }]
1021
        );
1022
1023
        try {
1024 4
            $command->execute();
1025 4
        } catch (Exception $e) {
1026 4
            $hitCatch = true;
1027 4
            $this->assertInstanceOf(IntegrityException::class, $e);
1028
        }
1029
1030 4
        $this->assertNull($db->getTransaction());
1031 4
        $this->assertSame(3, $attempts);
0 ignored issues
show
Bug introduced by
It seems like assertSame() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1031
        $this->/** @scrutinizer ignore-call */ 
1032
               assertSame(3, $attempts);
Loading history...
1032 4
        $this->assertTrue($hitHandler);
1033 4
        $this->assertTrue($hitCatch);
1034 4
    }
1035
1036 4
    public function testCreateView(): void
1037
    {
1038 4
        $db = $this->getConnection();
1039
1040 4
        $subquery = (new Query($db))
1041 4
            ->select('bar')
1042 4
            ->from('testCreateViewTable')
1043 4
            ->where(['>', 'bar', '5']);
1044
1045 4
        if ($db->getSchema()->getTableSchema('testCreateView') !== null) {
1046
            $db->createCommand()->dropView('testCreateView')->execute();
1047
        }
1048
1049 4
        if ($db->getSchema()->getTableSchema('testCreateViewTable')) {
1050
            $db->createCommand()->dropTable('testCreateViewTable')->execute();
1051
        }
1052
1053 4
        $db->createCommand()->createTable('testCreateViewTable', [
1054 4
            'id'  => Schema::TYPE_PK,
1055
            'bar' => Schema::TYPE_INTEGER,
1056 4
        ])->execute();
1057
1058 4
        $db->createCommand()->insert('testCreateViewTable', ['bar' => 1])->execute();
1059 4
        $db->createCommand()->insert('testCreateViewTable', ['bar' => 6])->execute();
1060 4
        $db->createCommand()->createView('testCreateView', $subquery)->execute();
1061
1062 4
        $records = $db->createCommand('SELECT [[bar]] FROM {{testCreateView}};')->queryAll();
1063
1064 4
        $this->assertEquals([['bar' => 6]], $records);
1065 4
    }
1066
1067 4
    public function testDropView(): void
1068
    {
1069 4
        $db = $this->getConnection();
1070
1071
        /* since it already exists in the fixtures */
1072 4
        $viewName = 'animal_view';
1073
1074 4
        $this->assertNotNull($db->getSchema()->getTableSchema($viewName));
1075
1076 4
        $db->createCommand()->dropView($viewName)->execute();
1077
1078 4
        $this->assertNull($db->getSchema()->getTableSchema($viewName));
1079 4
    }
1080
1081
    public function batchInsertSqlProviderTrait(): array
1082
    {
1083
        return [
1084
            'issue11242' => [
1085
                'type',
1086
                ['int_col', 'float_col', 'char_col'],
1087
                [['', '', 'Kyiv {{city}}, Ukraine']],
1088
                /**
1089
                 * {@see https://github.com/yiisoft/yii2/issues/11242}
1090
                 *
1091
                 * Make sure curly bracelets (`{{..}}`) in values will not be escaped
1092
                 */
1093
                'expected' => "INSERT INTO `type` (`int_col`, `float_col`, `char_col`)"
1094
                    . " VALUES (NULL, NULL, 'Kyiv {{city}}, Ukraine')"
1095
            ],
1096
            'wrongBehavior' => [
1097
                '{{%type}}',
1098
                ['{{%type}}.[[int_col]]', '[[float_col]]', 'char_col'],
1099
                [['', '', 'Kyiv {{city}}, Ukraine']],
1100
                /**
1101
                 * Test covers potentially wrong behavior and marks it as expected!.
1102
                 *
1103
                 * In case table name or table column is passed with curly or square bracelets, QueryBuilder can not
1104
                 * determine the table schema and typecast values properly.
1105
                 * TODO: make it work. Impossible without BC breaking for public methods.
1106
                 */
1107
                'expected' => "INSERT INTO `type` (`type`.`int_col`, `float_col`, `char_col`)"
1108
                    . " VALUES ('', '', 'Kyiv {{city}}, Ukraine')"
1109
            ],
1110
            'batchInsert binds params from expression' => [
1111
                '{{%type}}',
1112
                ['int_col'],
1113
                /**
1114
                 * This example is completely useless. This feature of batchInsert is intended to be used with complex
1115
                 * expression objects, such as JsonExpression.
1116
                 */
1117
                [[new Expression(':qp1', [':qp1' => 42])]],
1118
                'expected'       => 'INSERT INTO `type` (`int_col`) VALUES (:qp1)',
1119
                'expectedParams' => [':qp1' => 42]
1120
            ],
1121
        ];
1122
    }
1123
1124
    public function bindParamsNonWhereProviderTrait(): array
1125
    {
1126
        return [
1127
            ['SELECT SUBSTR(name, :len) FROM {{customer}} WHERE [[email]] = :email GROUP BY SUBSTR(name, :len)'],
1128
            ['SELECT SUBSTR(name, :len) FROM {{customer}} WHERE [[email]] = :email ORDER BY SUBSTR(name, :len)'],
1129
            ['SELECT SUBSTR(name, :len) FROM {{customer}} WHERE [[email]] = :email']
1130
        ];
1131
    }
1132
1133
    public function getRawSqlProviderTrait(): array
1134
    {
1135
        return [
1136
            [
1137
                'SELECT * FROM customer WHERE id = :id',
1138
                [':id' => 1],
1139
                'SELECT * FROM customer WHERE id = 1',
1140
            ],
1141
            [
1142
                'SELECT * FROM customer WHERE id = :id',
1143
                ['id' => 1],
1144
                'SELECT * FROM customer WHERE id = 1',
1145
            ],
1146
            [
1147
                'SELECT * FROM customer WHERE id = :id',
1148
                ['id' => null],
1149
                'SELECT * FROM customer WHERE id = NULL',
1150
            ],
1151
            [
1152
                'SELECT * FROM customer WHERE id = :base OR id = :basePrefix',
1153
                [
1154
                    'base'       => 1,
1155
                    'basePrefix' => 2,
1156
                ],
1157
                'SELECT * FROM customer WHERE id = 1 OR id = 2',
1158
            ],
1159
            /**
1160
             * {@see https://github.com/yiisoft/yii2/issues/9268}
1161
             */
1162
            [
1163
                'SELECT * FROM customer WHERE active = :active',
1164
                [':active' => false],
1165
                'SELECT * FROM customer WHERE active = FALSE',
1166
            ],
1167
            /**
1168
             * {@see https://github.com/yiisoft/yii2/issues/15122}
1169
             */
1170
            [
1171
                'SELECT * FROM customer WHERE id IN (:ids)',
1172
                [':ids' => new Expression(implode(', ', [1, 2]))],
1173
                'SELECT * FROM customer WHERE id IN (1, 2)',
1174
            ],
1175
        ];
1176
    }
1177
1178
    public function invalidSelectColumnsProviderTrait(): array
1179
    {
1180
        return [
1181
            [[]],
1182
            ['*'],
1183
            [['*']],
1184
        ];
1185
    }
1186
1187
    public function upsertProviderTrait(): array
1188
    {
1189
        return [
1190
            'regular values' => [
1191
                [
1192
                    'params' => [
1193
                        'T_upsert',
1194
                        [
1195
                            'email'   => '[email protected]',
1196
                            'address' => 'Earth',
1197
                            'status'  => 3,
1198
                        ],
1199
                    ],
1200
                ],
1201
                [
1202
                    'params' => [
1203
                        'T_upsert',
1204
                        [
1205
                            'email'   => '[email protected]',
1206
                            'address' => 'Universe',
1207
                            'status'  => 1,
1208
                        ],
1209
                    ],
1210
                ],
1211
            ],
1212
            'regular values with update part' => [
1213
                [
1214
                    'params' => [
1215
                        'T_upsert',
1216
                        [
1217
                            'email'   => '[email protected]',
1218
                            'address' => 'Earth',
1219
                            'status'  => 3,
1220
                        ],
1221
                        [
1222
                            'address' => 'Moon',
1223
                            'status'  => 2,
1224
                        ],
1225
                    ],
1226
                ],
1227
                [
1228
                    'params' => [
1229
                        'T_upsert',
1230
                        [
1231
                            'email'   => '[email protected]',
1232
                            'address' => 'Universe',
1233
                            'status'  => 1,
1234
                        ],
1235
                        [
1236
                            'address' => 'Moon',
1237
                            'status'  => 2,
1238
                        ],
1239
                    ],
1240
                    'expected' => [
1241
                        'email'   => '[email protected]',
1242
                        'address' => 'Moon',
1243
                        'status'  => 2,
1244
                    ],
1245
                ],
1246
            ],
1247
            'regular values without update part' => [
1248
                [
1249
                    'params' => [
1250
                        'T_upsert',
1251
                        [
1252
                            'email'   => '[email protected]',
1253
                            'address' => 'Earth',
1254
                            'status'  => 3,
1255
                        ],
1256
                        false,
1257
                    ],
1258
                ],
1259
                [
1260
                    'params' => [
1261
                        'T_upsert',
1262
                        [
1263
                            'email'   => '[email protected]',
1264
                            'address' => 'Universe',
1265
                            'status'  => 1,
1266
                        ],
1267
                        false,
1268
                    ],
1269
                    'expected' => [
1270
                        'email'   => '[email protected]',
1271
                        'address' => 'Earth',
1272
                        'status'  => 3,
1273
                    ],
1274
                ],
1275
            ],
1276
            'query' => [
1277
                [
1278
                    'params' => [
1279
                        'T_upsert',
1280
                        (new Query($this->getConnection()))
1281
                            ->select([
1282
                                'email',
1283
                                'address',
1284
                                'status' => new Expression('1'),
1285
                            ])
1286
                            ->from('customer')
1287
                            ->where(['name' => 'user1'])
1288
                            ->limit(1),
1289
                    ],
1290
                    'expected' => [
1291
                        'email'   => '[email protected]',
1292
                        'address' => 'address1',
1293
                        'status'  => 1,
1294
                    ],
1295
                ],
1296
                [
1297
                    'params' => [
1298
                        'T_upsert',
1299
                        (new Query($this->getConnection()))
1300
                            ->select([
1301
                                'email',
1302
                                'address',
1303
                                'status' => new Expression('2'),
1304
                            ])
1305
                            ->from('customer')
1306
                            ->where(['name' => 'user1'])
1307
                            ->limit(1),
1308
                    ],
1309
                    'expected' => [
1310
                        'email'   => '[email protected]',
1311
                        'address' => 'address1',
1312
                        'status'  => 2,
1313
                    ],
1314
                ],
1315
            ],
1316
            'query with update part' => [
1317
                [
1318
                    'params' => [
1319
                        'T_upsert',
1320
                        (new Query($this->getConnection()))
1321
                            ->select([
1322
                                'email',
1323
                                'address',
1324
                                'status' => new Expression('1'),
1325
                            ])
1326
                            ->from('customer')
1327
                            ->where(['name' => 'user1'])
1328
                            ->limit(1),
1329
                        [
1330
                            'address' => 'Moon',
1331
                            'status'  => 2,
1332
                        ],
1333
                    ],
1334
                    'expected' => [
1335
                        'email'   => '[email protected]',
1336
                        'address' => 'address1',
1337
                        'status'  => 1,
1338
                    ],
1339
                ],
1340
                [
1341
                    'params' => [
1342
                        'T_upsert',
1343
                        (new Query($this->getConnection()))
1344
                            ->select([
1345
                                'email',
1346
                                'address',
1347
                                'status' => new Expression('3'),
1348
                            ])
1349
                            ->from('customer')
1350
                            ->where(['name' => 'user1'])
1351
                            ->limit(1),
1352
                        [
1353
                            'address' => 'Moon',
1354
                            'status'  => 2,
1355
                        ],
1356
                    ],
1357
                    'expected' => [
1358
                        'email'   => '[email protected]',
1359
                        'address' => 'Moon',
1360
                        'status'  => 2,
1361
                    ],
1362
                ],
1363
            ],
1364
            'query without update part' => [
1365
                [
1366
                    'params' => [
1367
                        'T_upsert',
1368
                        (new Query($this->getConnection()))
1369
                            ->select([
1370
                                'email',
1371
                                'address',
1372
                                'status' => new Expression('1'),
1373
                            ])
1374
                            ->from('customer')
1375
                            ->where(['name' => 'user1'])
1376
                            ->limit(1),
1377
                        false,
1378
                    ],
1379
                    'expected' => [
1380
                        'email'   => '[email protected]',
1381
                        'address' => 'address1',
1382
                        'status'  => 1,
1383
                    ],
1384
                ],
1385
                [
1386
                    'params' => [
1387
                        'T_upsert',
1388
                        (new Query($this->getConnection()))
1389
                            ->select([
1390
                                'email',
1391
                                'address',
1392
                                'status' => new Expression('2'),
1393
                            ])
1394
                            ->from('customer')
1395
                            ->where(['name' => 'user1'])
1396
                            ->limit(1),
1397
                        false,
1398
                    ],
1399
                    'expected' => [
1400
                        'email'   => '[email protected]',
1401
                        'address' => 'address1',
1402
                        'status'  => 1,
1403
                    ],
1404
                ],
1405
            ],
1406
        ];
1407
    }
1408
}
1409