Passed
Pull Request — master (#163)
by Wilmer
19:50 queued 04:50
created

TestCommandTrait::testLastInsertId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 5
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 11
rs 10
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\Connection;
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
    protected string $upsertTestCharCast = 'CAST([[address]] AS VARCHAR(255))';
30
31
    public function testConstruct(): void
32
    {
33
        $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

33
        /** @scrutinizer ignore-call */ 
34
        $db = $this->getConnection();
Loading history...
34
35
        /* null */
36
        $command = $db->createCommand();
37
38
        $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

38
        $this->/** @scrutinizer ignore-call */ 
39
               assertNull($command->getSql());
Loading history...
39
40
        /* string */
41
        $sql = 'SELECT * FROM customer';
42
43
        $command = $db->createCommand($sql);
44
45
        $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

45
        $this->/** @scrutinizer ignore-call */ 
46
               assertEquals($sql, $command->getSql());
Loading history...
46
    }
47
48
    public function testGetSetSql(): void
49
    {
50
        $db = $this->getConnection();
51
52
        $sql = 'SELECT * FROM customer';
53
54
        $command = $db->createCommand($sql);
55
56
        $this->assertEquals($sql, $command->getSql());
57
58
        $sql2 = 'SELECT * FROM order';
59
60
        $command->setSql($sql2);
61
62
        $this->assertEquals($sql2, $command->getSql());
63
    }
64
65
    public function testPrepareCancel(): void
66
    {
67
        $db = $this->getConnection();
68
69
        $command = $db->createCommand('SELECT * FROM {{customer}}');
70
71
        $this->assertNull($command->getPdoStatement());
72
73
        $command->prepare();
74
75
        $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

75
        $this->/** @scrutinizer ignore-call */ 
76
               assertNotNull($command->getPdoStatement());
Loading history...
76
77
        $command->cancel();
78
79
        $this->assertNull($command->getPdoStatement());
80
    }
81
82
    public function testExecute(): void
83
    {
84
        $db = $this->getConnection(true);
85
86
        $sql = 'INSERT INTO {{customer}}([[email]], [[name]], [[address]])'
87
            . ' VALUES (\'[email protected]\', \'user4\', \'address4\')';
88
89
        $command = $db->createCommand($sql);
90
91
        $this->assertEquals(1, $command->execute());
92
93
        $sql = 'SELECT COUNT(*) FROM {{customer}} WHERE [[name]] = \'user4\'';
94
95
        $command = $db->createCommand($sql);
96
97
        $this->assertEquals(1, $command->queryScalar());
98
99
        $command = $db->createCommand('bad SQL');
100
101
        $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

101
        $this->/** @scrutinizer ignore-call */ 
102
               expectException(Exception::class);
Loading history...
102
103
        $command->execute();
104
    }
105
106
    public function testQuery(): void
107
    {
108
        $db = $this->getConnection(true);
109
110
        /* query */
111
        $sql = 'SELECT * FROM {{customer}}';
112
113
        $reader = $db->createCommand($sql)->Query();
114
115
        $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

115
        $this->/** @scrutinizer ignore-call */ 
116
               assertInstanceOf(DataReader::class, $reader);
Loading history...
116
117
        /* queryAll */
118
        $rows = $db->createCommand('SELECT * FROM {{customer}}')->queryAll();
119
120
        $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

120
        $this->/** @scrutinizer ignore-call */ 
121
               assertCount(3, $rows);
Loading history...
121
122
        $row = $rows[2];
123
124
        $this->assertEquals(3, $row['id']);
125
        $this->assertEquals('user3', $row['name']);
126
127
        $rows = $db->createCommand('SELECT * FROM {{customer}} WHERE [[id]] = 10')->queryAll();
128
129
        $this->assertEquals([], $rows);
130
131
        /* queryOne */
132
        $sql = 'SELECT * FROM {{customer}} ORDER BY [[id]]';
133
134
        $row = $db->createCommand($sql)->queryOne();
135
136
        $this->assertEquals(1, $row['id']);
137
        $this->assertEquals('user1', $row['name']);
138
139
        $sql = 'SELECT * FROM {{customer}} ORDER BY [[id]]';
140
141
        $command = $db->createCommand($sql);
142
143
        $command->prepare();
144
145
        $row = $command->queryOne();
146
147
        $this->assertEquals(1, $row['id']);
148
        $this->assertEquals('user1', $row['name']);
149
150
        $sql = 'SELECT * FROM {{customer}} WHERE [[id]] = 10';
151
152
        $command = $db->createCommand($sql);
153
154
        $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

154
        $this->/** @scrutinizer ignore-call */ 
155
               assertFalse($command->queryOne());
Loading history...
155
156
        /* queryColumn */
157
        $sql = 'SELECT * FROM {{customer}}';
158
159
        $column = $db->createCommand($sql)->queryColumn();
160
161
        $this->assertEquals(range(1, 3), $column);
162
163
        $command = $db->createCommand('SELECT [[id]] FROM {{customer}} WHERE [[id]] = 10');
164
165
        $this->assertEquals([], $command->queryColumn());
166
167
        /* queryScalar */
168
        $sql = 'SELECT * FROM {{customer}} ORDER BY [[id]]';
169
170
        $this->assertEquals($db->createCommand($sql)->queryScalar(), 1);
171
172
        $sql = 'SELECT [[id]] FROM {{customer}} ORDER BY [[id]]';
173
174
        $command = $db->createCommand($sql);
175
176
        $command->prepare();
177
178
        $this->assertEquals(1, $command->queryScalar());
179
180
        $command = $db->createCommand('SELECT [[id]] FROM {{customer}} WHERE [[id]] = 10');
181
182
        $this->assertFalse($command->queryScalar());
183
184
        $command = $db->createCommand('bad SQL');
185
186
        $this->expectException(Exception::class);
187
188
        $command->Query();
189
    }
190
191
    public function testFetchMode(): void
192
    {
193
        $db = $this->getConnection();
194
195
        /* default: FETCH_ASSOC */
196
        $sql = 'SELECT * FROM {{customer}}';
197
198
        $command = $db->createCommand($sql);
199
200
        $result = $command->queryOne();
201
202
        $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

202
        $this->/** @scrutinizer ignore-call */ 
203
               assertTrue(is_array($result) && isset($result['id']));
Loading history...
203
204
        /* FETCH_OBJ, customized via fetchMode property */
205
        $sql = 'SELECT * FROM {{customer}}';
206
207
        $command = $db->createCommand($sql);
208
209
        $command->setFetchMode(PDO::FETCH_OBJ);
210
211
        $result = $command->queryOne();
212
213
        $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

213
        $this->/** @scrutinizer ignore-call */ 
214
               assertIsObject($result);
Loading history...
214
215
        /* FETCH_NUM, customized in query method */
216
        $sql = 'SELECT * FROM {{customer}}';
217
218
        $command = $db->createCommand($sql);
219
220
        $result = $command->queryOne(PDO::FETCH_NUM);
221
222
        $this->assertTrue(is_array($result) && isset($result[0]));
223
    }
224
225
    public function testBatchInsert(): void
226
    {
227
        $db = $this->getConnection();
228
229
        $command = $db->createCommand();
230
231
        $command->batchInsert(
232
            '{{customer}}',
233
            ['email', 'name', 'address'],
234
            [
235
                ['[email protected]', 't1', 't1 address'],
236
                ['[email protected]', null, false],
237
            ]
238
        );
239
240
        $this->assertEquals(2, $command->execute());
241
242
        /**
243
         * {@see https://github.com/yiisoft/yii2/issues/11693}
244
         */
245
        $command = $this->getConnection()->createCommand();
246
247
        $command->batchInsert(
248
            '{{customer}}',
249
            ['email', 'name', 'address'],
250
            []
251
        );
252
253
        $this->assertEquals(0, $command->execute());
254
    }
255
256
    public function testBatchInsertWithYield(): void
257
    {
258
        $rows = call_user_func(static function () {
259
            if (false) {
260
                yield [];
261
            }
262
        });
263
264
        $command = $this->getConnection()->createCommand();
265
266
        $command->batchInsert(
267
            '{{customer}}',
268
            ['email', 'name', 'address'],
269
            $rows
270
        );
271
272
        $this->assertEquals(0, $command->execute());
273
    }
274
275
    /**
276
     * Test batch insert with different data types.
277
     *
278
     * Ensure double is inserted with `.` decimal separator.
279
     *
280
     * {@see https://github.com/yiisoft/yii2/issues/6526}
281
     */
282
    public function testBatchInsertDataTypesLocale(): void
283
    {
284
        $locale = setlocale(LC_NUMERIC, 0);
285
286
        if (false === $locale) {
287
            $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

287
            $this->/** @scrutinizer ignore-call */ 
288
                   markTestSkipped('Your platform does not support locales.');
Loading history...
288
        }
289
290
        $db = $this->getConnection();
291
292
        try {
293
            /* This one sets decimal mark to comma sign */
294
            setlocale(LC_NUMERIC, 'ru_RU.utf8');
295
296
            $cols = ['int_col', 'char_col', 'float_col', 'bool_col'];
297
298
            $data = [
299
                [1, 'A', 9.735, true],
300
                [2, 'B', -2.123, false],
301
                [3, 'C', 2.123, false],
302
            ];
303
304
            /* clear data in "type" table */
305
            $db->createCommand()->delete('type')->execute();
306
307
            /* batch insert on "type" table */
308
            $db->createCommand()->batchInsert('type', $cols, $data)->execute();
309
310
            $data = $db->createCommand(
311
                'SELECT int_col, char_col, float_col, bool_col FROM {{type}} WHERE [[int_col]] IN (1,2,3)
312
                ORDER BY [[int_col]];'
313
            )->queryAll();
314
315
            $this->assertCount(3, $data);
316
            $this->assertEquals(1, $data[0]['int_col']);
317
            $this->assertEquals(2, $data[1]['int_col']);
318
            $this->assertEquals(3, $data[2]['int_col']);
319
320
            /* rtrim because Postgres padds the column with whitespace */
321
            $this->assertEquals('A', rtrim($data[0]['char_col']));
322
            $this->assertEquals('B', rtrim($data[1]['char_col']));
323
            $this->assertEquals('C', rtrim($data[2]['char_col']));
324
            $this->assertEquals('9.735', $data[0]['float_col']);
325
            $this->assertEquals('-2.123', $data[1]['float_col']);
326
            $this->assertEquals('2.123', $data[2]['float_col']);
327
            $this->assertEquals('1', $data[0]['bool_col']);
328
            $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

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

770
        $this->/** @scrutinizer ignore-call */ 
771
               assertEmpty($schema->getTableForeignKeys($tableName, true));
Loading history...
771
772
        $db->createCommand()->addForeignKey($name, $tableName, ['int1'], $tableName, ['int3'])->execute();
773
774
        $this->assertEquals(['int1'], $schema->getTableForeignKeys($tableName, true)[0]->getColumnNames());
775
        $this->assertEquals(['int3'], $schema->getTableForeignKeys($tableName, true)[0]->getForeignColumnNames());
776
777
        $db->createCommand()->dropForeignKey($name, $tableName)->execute();
778
779
        $this->assertEmpty($schema->getTableForeignKeys($tableName, true));
780
781
        $db->createCommand()->addForeignKey(
782
            $name,
783
            $tableName,
784
            ['int1', 'int2'],
785
            $tableName,
786
            ['int3', 'int4']
787
        )->execute();
788
789
        $this->assertEquals(
790
            ['int1', 'int2'],
791
            $schema->getTableForeignKeys($tableName, true)[0]->getColumnNames()
792
        );
793
        $this->assertEquals(
794
            ['int3', 'int4'],
795
            $schema->getTableForeignKeys($tableName, true)[0]->getForeignColumnNames()
796
        );
797
    }
798
799
    public function testCreateDropIndex(): void
800
    {
801
        $db = $this->getConnection();
802
803
        $tableName = 'test_idx';
804
        $name = 'test_idx_constraint';
805
806
        $schema = $db->getSchema();
807
808
        if ($schema->getTableSchema($tableName) !== null) {
809
            $db->createCommand()->dropTable($tableName)->execute();
810
        }
811
812
        $db->createCommand()->createTable($tableName, [
813
            'int1' => 'integer not null',
814
            'int2' => 'integer not null',
815
        ])->execute();
816
817
        $this->assertEmpty($schema->getTableIndexes($tableName, true));
818
819
        $db->createCommand()->createIndex($name, $tableName, ['int1'])->execute();
820
821
        $this->assertEquals(['int1'], $schema->getTableIndexes($tableName, true)[0]->getColumnNames());
822
        $this->assertFalse($schema->getTableIndexes($tableName, true)[0]->isUnique());
823
824
        $db->createCommand()->dropIndex($name, $tableName)->execute();
825
826
        $this->assertEmpty($schema->getTableIndexes($tableName, true));
827
828
        $db->createCommand()->createIndex($name, $tableName, ['int1', 'int2'])->execute();
829
830
        $this->assertEquals(['int1', 'int2'], $schema->getTableIndexes($tableName, true)[0]->getColumnNames());
831
        $this->assertFalse($schema->getTableIndexes($tableName, true)[0]->isUnique());
832
833
        $db->createCommand()->dropIndex($name, $tableName)->execute();
834
835
        $this->assertEmpty($schema->getTableIndexes($tableName, true));
836
        $this->assertEmpty($schema->getTableIndexes($tableName, true));
837
838
        $db->createCommand()->createIndex($name, $tableName, ['int1'], true)->execute();
839
840
        $this->assertEquals(['int1'], $schema->getTableIndexes($tableName, true)[0]->getColumnNames());
841
        $this->assertTrue($schema->getTableIndexes($tableName, true)[0]->isUnique());
842
843
        $db->createCommand()->dropIndex($name, $tableName)->execute();
844
845
        $this->assertEmpty($schema->getTableIndexes($tableName, true));
846
847
        $db->createCommand()->createIndex($name, $tableName, ['int1', 'int2'], true)->execute();
848
849
        $this->assertEquals(['int1', 'int2'], $schema->getTableIndexes($tableName, true)[0]->getColumnNames());
850
        $this->assertTrue($schema->getTableIndexes($tableName, true)[0]->isUnique());
851
    }
852
853
    public function testAddDropUnique(): void
854
    {
855
        $db = $this->getConnection();
856
857
        $tableName = 'test_uq';
858
        $name = 'test_uq_constraint';
859
860
        $schema = $db->getSchema();
861
862
        if ($schema->getTableSchema($tableName) !== null) {
863
            $db->createCommand()->dropTable($tableName)->execute();
864
        }
865
866
        $db->createCommand()->createTable($tableName, [
867
            'int1' => 'integer not null',
868
            'int2' => 'integer not null',
869
        ])->execute();
870
871
        $this->assertEmpty($schema->getTableUniques($tableName, true));
872
873
        $db->createCommand()->addUnique($name, $tableName, ['int1'])->execute();
874
875
        $this->assertEquals(['int1'], $schema->getTableUniques($tableName, true)[0]->getColumnNames());
876
877
        $db->createCommand()->dropUnique($name, $tableName)->execute();
878
879
        $this->assertEmpty($schema->getTableUniques($tableName, true));
880
881
        $db->createCommand()->addUnique($name, $tableName, ['int1', 'int2'])->execute();
882
883
        $this->assertEquals(['int1', 'int2'], $schema->getTableUniques($tableName, true)[0]->getColumnNames());
884
    }
885
886
    public function testAddDropCheck(): void
887
    {
888
        $db = $this->getConnection();
889
890
        $tableName = 'test_ck';
891
        $name = 'test_ck_constraint';
892
893
        $schema = $db->getSchema();
894
895
        if ($schema->getTableSchema($tableName) !== null) {
896
            $db->createCommand()->dropTable($tableName)->execute();
897
        }
898
899
        $db->createCommand()->createTable($tableName, [
900
            'int1' => 'integer',
901
        ])->execute();
902
903
        $this->assertEmpty($schema->getTableChecks($tableName, true));
904
905
        $db->createCommand()->addCheck($name, $tableName, '[[int1]] > 1')->execute();
906
907
        $this->assertMatchesRegularExpression(
0 ignored issues
show
Bug introduced by
It seems like assertMatchesRegularExpression() 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

907
        $this->/** @scrutinizer ignore-call */ 
908
               assertMatchesRegularExpression(
Loading history...
908
            '/^.*int1.*>.*1.*$/',
909
            $schema->getTableChecks($tableName, true)[0]->getExpression()
910
        );
911
912
        $db->createCommand()->dropCheck($name, $tableName)->execute();
913
914
        $this->assertEmpty($schema->getTableChecks($tableName, true));
915
    }
916
917
    public function testIntegrityViolation(): void
918
    {
919
        $this->expectException(IntegrityException::class);
920
921
        $db = $this->getConnection();
922
923
        $sql = 'INSERT INTO {{profile}}([[id]], [[description]]) VALUES (123, \'duplicate\')';
924
925
        $command = $db->createCommand($sql);
926
927
        $command->execute();
928
        $command->execute();
929
    }
930
931
    public function testLastInsertId(): void
932
    {
933
        $db = $this->getConnection();
934
935
        $sql = 'INSERT INTO {{profile}}([[description]]) VALUES (\'non duplicate\')';
936
937
        $command = $db->createCommand($sql);
938
939
        $command->execute();
940
941
        $this->assertEquals(3, $db->getSchema()->getLastInsertID());
942
    }
943
944
    public function testQueryCache(): void
945
    {
946
        $db = $this->getConnection();
947
948
        $db->setEnableQueryCache(true);
949
        $db->setQueryCache($this->cache);
950
951
        $command = $db->createCommand('SELECT [[name]] FROM {{customer}} WHERE [[id]] = :id');
952
953
        $this->assertEquals('user1', $command->bindValue(':id', 1)->queryScalar());
954
955
        $update = $db->createCommand('UPDATE {{customer}} SET [[name]] = :name WHERE [[id]] = :id');
956
957
        $update->bindValues([':id' => 1, ':name' => 'user11'])->execute();
958
959
        $this->assertEquals('user11', $command->bindValue(':id', 1)->queryScalar());
960
961
        $db->cache(function (Connection $db) use ($command, $update) {
962
            $this->assertEquals('user2', $command->bindValue(':id', 2)->queryScalar());
963
964
            $update->bindValues([':id' => 2, ':name' => 'user22'])->execute();
965
966
            $this->assertEquals('user2', $command->bindValue(':id', 2)->queryScalar());
967
968
            $db->noCache(function () use ($command) {
969
                $this->assertEquals('user22', $command->bindValue(':id', 2)->queryScalar());
970
            });
971
972
            $this->assertEquals('user2', $command->bindValue(':id', 2)->queryScalar());
973
        }, 10);
974
975
        $db->setEnableQueryCache(false);
976
977
        $db->cache(function () use ($command, $update) {
978
            $this->assertEquals('user22', $command->bindValue(':id', 2)->queryScalar());
979
            $update->bindValues([':id' => 2, ':name' => 'user2'])->execute();
980
            $this->assertEquals('user2', $command->bindValue(':id', 2)->queryScalar());
981
        }, 10);
982
983
        $db->setEnableQueryCache(true);
984
985
        $command = $db->createCommand('SELECT [[name]] FROM {{customer}} WHERE [[id]] = :id')->cache();
986
987
        $this->assertEquals('user11', $command->bindValue(':id', 1)->queryScalar());
988
989
        $update->bindValues([':id' => 1, ':name' => 'user1'])->execute();
990
991
        $this->assertEquals('user11', $command->bindValue(':id', 1)->queryScalar());
992
        $this->assertEquals('user1', $command->noCache()->bindValue(':id', 1)->queryScalar());
993
994
        $command = $db->createCommand('SELECT [[name]] FROM {{customer}} WHERE [[id]] = :id');
995
996
        $db->cache(function () use ($command) {
997
            $this->assertEquals('user11', $command->bindValue(':id', 1)->queryScalar());
998
            $this->assertEquals('user1', $command->noCache()->bindValue(':id', 1)->queryScalar());
999
        }, 10);
1000
    }
1001
1002
    public function testColumnCase(): void
1003
    {
1004
        $db = $this->getConnection();
1005
1006
        $this->assertEquals(PDO::CASE_NATURAL, $db->getSlavePdo()->getAttribute(PDO::ATTR_CASE));
1007
1008
        $sql = 'SELECT [[customer_id]], [[total]] FROM {{order}}';
1009
1010
        $rows = $db->createCommand($sql)->queryAll();
1011
1012
        $this->assertTrue(isset($rows[0]));
1013
        $this->assertTrue(isset($rows[0]['customer_id']));
1014
        $this->assertTrue(isset($rows[0]['total']));
1015
1016
        $db->getSlavePdo()->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
1017
1018
        $rows = $db->createCommand($sql)->queryAll();
1019
1020
        $this->assertTrue(isset($rows[0]));
1021
        $this->assertTrue(isset($rows[0]['customer_id']));
1022
        $this->assertTrue(isset($rows[0]['total']));
1023
1024
        $db->getSlavePdo()->setAttribute(PDO::ATTR_CASE, PDO::CASE_UPPER);
1025
1026
        $rows = $db->createCommand($sql)->queryAll();
1027
1028
        $this->assertTrue(isset($rows[0]));
1029
        $this->assertTrue(isset($rows[0]['CUSTOMER_ID']));
1030
        $this->assertTrue(isset($rows[0]['TOTAL']));
1031
    }
1032
1033
    public function testTransaction(): void
1034
    {
1035
        $db = $this->getConnection();
1036
1037
        $this->assertNull($db->getTransaction());
1038
1039
        $command = $db->createCommand("INSERT INTO {{profile}}([[description]]) VALUES('command transaction')");
1040
1041
        $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

1041
        $this->/** @scrutinizer ignore-call */ 
1042
               invokeMethod($command, 'requireTransaction');
Loading history...
1042
1043
        $command->execute();
1044
1045
        $this->assertNull($db->getTransaction());
1046
        $this->assertEquals(
1047
            1,
1048
            $db->createCommand(
1049
                "SELECT COUNT(*) FROM {{profile}} WHERE [[description]] = 'command transaction'"
1050
            )->queryScalar()
1051
        );
1052
    }
1053
1054
    public function testRetryHandler(): void
1055
    {
1056
        $db = $this->getConnection();
1057
1058
        $this->assertNull($db->getTransaction());
1059
1060
        $db->createCommand("INSERT INTO {{profile}}([[description]]) VALUES('command retry')")->execute();
1061
1062
        $this->assertNull($db->getTransaction());
1063
        $this->assertEquals(
1064
            1,
1065
            $db->createCommand(
1066
                "SELECT COUNT(*) FROM {{profile}} WHERE [[description]] = 'command retry'"
1067
            )->queryScalar()
1068
        );
1069
1070
        $attempts = null;
1071
        $hitHandler = false;
1072
        $hitCatch = false;
1073
1074
        $command = $db->createCommand(
1075
            "INSERT INTO {{profile}}([[id]], [[description]]) VALUES(1, 'command retry')"
1076
        );
1077
1078
        $this->invokeMethod(
1079
            $command,
1080
            'setRetryHandler',
1081
            [static function ($exception, $attempt) use (&$attempts, &$hitHandler) {
1082
                $attempts = $attempt;
1083
                $hitHandler = true;
1084
1085
                return $attempt <= 2;
1086
            }]
1087
        );
1088
1089
        try {
1090
            $command->execute();
1091
        } catch (Exception $e) {
1092
            $hitCatch = true;
1093
            $this->assertInstanceOf(IntegrityException::class, $e);
1094
        }
1095
1096
        $this->assertNull($db->getTransaction());
1097
        $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

1097
        $this->/** @scrutinizer ignore-call */ 
1098
               assertSame(3, $attempts);
Loading history...
1098
        $this->assertTrue($hitHandler);
1099
        $this->assertTrue($hitCatch);
1100
    }
1101
1102
    public function testCreateView(): void
1103
    {
1104
        $db = $this->getConnection();
1105
1106
        $subquery = (new Query($db))
1107
            ->select('bar')
1108
            ->from('testCreateViewTable')
1109
            ->where(['>', 'bar', '5']);
1110
1111
        if ($db->getSchema()->getTableSchema('testCreateView') !== null) {
1112
            $db->createCommand()->dropView('testCreateView')->execute();
1113
        }
1114
1115
        if ($db->getSchema()->getTableSchema('testCreateViewTable')) {
1116
            $db->createCommand()->dropTable('testCreateViewTable')->execute();
1117
        }
1118
1119
        $db->createCommand()->createTable('testCreateViewTable', [
1120
            'id'  => Schema::TYPE_PK,
1121
            'bar' => Schema::TYPE_INTEGER,
1122
        ])->execute();
1123
1124
        $db->createCommand()->insert('testCreateViewTable', ['bar' => 1])->execute();
1125
        $db->createCommand()->insert('testCreateViewTable', ['bar' => 6])->execute();
1126
        $db->createCommand()->createView('testCreateView', $subquery)->execute();
1127
1128
        $records = $db->createCommand('SELECT [[bar]] FROM {{testCreateView}};')->queryAll();
1129
1130
        $this->assertEquals([['bar' => 6]], $records);
1131
    }
1132
1133
    public function testDropView(): void
1134
    {
1135
        $db = $this->getConnection();
1136
1137
        /* since it already exists in the fixtures */
1138
        $viewName = 'animal_view';
1139
1140
        $this->assertNotNull($db->getSchema()->getTableSchema($viewName));
1141
1142
        $db->createCommand()->dropView($viewName)->execute();
1143
1144
        $this->assertNull($db->getSchema()->getTableSchema($viewName));
1145
    }
1146
1147
    public function batchInsertSqlProviderTrait(): array
1148
    {
1149
        return [
1150
            'issue11242' => [
1151
                'type',
1152
                ['int_col', 'float_col', 'char_col'],
1153
                [['', '', 'Kyiv {{city}}, Ukraine']],
1154
                /**
1155
                 * {@see https://github.com/yiisoft/yii2/issues/11242}
1156
                 *
1157
                 * Make sure curly bracelets (`{{..}}`) in values will not be escaped
1158
                 */
1159
                'expected' => "INSERT INTO `type` (`int_col`, `float_col`, `char_col`)"
1160
                    . " VALUES (NULL, NULL, 'Kyiv {{city}}, Ukraine')"
1161
            ],
1162
            'wrongBehavior' => [
1163
                '{{%type}}',
1164
                ['{{%type}}.[[int_col]]', '[[float_col]]', 'char_col'],
1165
                [['', '', 'Kyiv {{city}}, Ukraine']],
1166
                /**
1167
                 * Test covers potentially wrong behavior and marks it as expected!.
1168
                 *
1169
                 * In case table name or table column is passed with curly or square bracelets, QueryBuilder can not
1170
                 * determine the table schema and typecast values properly.
1171
                 * TODO: make it work. Impossible without BC breaking for public methods.
1172
                 */
1173
                'expected' => "INSERT INTO `type` (`type`.`int_col`, `float_col`, `char_col`)"
1174
                    . " VALUES ('', '', 'Kyiv {{city}}, Ukraine')"
1175
            ],
1176
            'batchInsert binds params from expression' => [
1177
                '{{%type}}',
1178
                ['int_col'],
1179
                /**
1180
                 * This example is completely useless. This feature of batchInsert is intended to be used with complex
1181
                 * expression objects, such as JsonExpression.
1182
                 */
1183
                [[new Expression(':qp1', [':qp1' => 42])]],
1184
                'expected'       => 'INSERT INTO `type` (`int_col`) VALUES (:qp1)',
1185
                'expectedParams' => [':qp1' => 42]
1186
            ],
1187
        ];
1188
    }
1189
1190
    public function bindParamsNonWhereProviderTrait(): array
1191
    {
1192
        return [
1193
            ['SELECT SUBSTR(name, :len) FROM {{customer}} WHERE [[email]] = :email GROUP BY SUBSTR(name, :len)'],
1194
            ['SELECT SUBSTR(name, :len) FROM {{customer}} WHERE [[email]] = :email ORDER BY SUBSTR(name, :len)'],
1195
            ['SELECT SUBSTR(name, :len) FROM {{customer}} WHERE [[email]] = :email']
1196
        ];
1197
    }
1198
1199
    public function getRawSqlProviderTrait(): array
1200
    {
1201
        return [
1202
            [
1203
                'SELECT * FROM customer WHERE id = :id',
1204
                [':id' => 1],
1205
                'SELECT * FROM customer WHERE id = 1',
1206
            ],
1207
            [
1208
                'SELECT * FROM customer WHERE id = :id',
1209
                ['id' => 1],
1210
                'SELECT * FROM customer WHERE id = 1',
1211
            ],
1212
            [
1213
                'SELECT * FROM customer WHERE id = :id',
1214
                ['id' => null],
1215
                'SELECT * FROM customer WHERE id = NULL',
1216
            ],
1217
            [
1218
                'SELECT * FROM customer WHERE id = :base OR id = :basePrefix',
1219
                [
1220
                    'base'       => 1,
1221
                    'basePrefix' => 2,
1222
                ],
1223
                'SELECT * FROM customer WHERE id = 1 OR id = 2',
1224
            ],
1225
            /**
1226
             * {@see https://github.com/yiisoft/yii2/issues/9268}
1227
             */
1228
            [
1229
                'SELECT * FROM customer WHERE active = :active',
1230
                [':active' => false],
1231
                'SELECT * FROM customer WHERE active = FALSE',
1232
            ],
1233
            /**
1234
             * {@see https://github.com/yiisoft/yii2/issues/15122}
1235
             */
1236
            [
1237
                'SELECT * FROM customer WHERE id IN (:ids)',
1238
                [':ids' => new Expression(implode(', ', [1, 2]))],
1239
                'SELECT * FROM customer WHERE id IN (1, 2)',
1240
            ],
1241
        ];
1242
    }
1243
1244
    public function invalidSelectColumnsProviderTrait(): array
1245
    {
1246
        return [
1247
            [[]],
1248
            ['*'],
1249
            [['*']],
1250
        ];
1251
    }
1252
1253
    public function upsertProviderTrait(): array
1254
    {
1255
        return [
1256
            'regular values' => [
1257
                [
1258
                    'params' => [
1259
                        'T_upsert',
1260
                        [
1261
                            'email'   => '[email protected]',
1262
                            'address' => 'Earth',
1263
                            'status'  => 3,
1264
                        ],
1265
                    ],
1266
                ],
1267
                [
1268
                    'params' => [
1269
                        'T_upsert',
1270
                        [
1271
                            'email'   => '[email protected]',
1272
                            'address' => 'Universe',
1273
                            'status'  => 1,
1274
                        ],
1275
                    ],
1276
                ],
1277
            ],
1278
            'regular values with update part' => [
1279
                [
1280
                    'params' => [
1281
                        'T_upsert',
1282
                        [
1283
                            'email'   => '[email protected]',
1284
                            'address' => 'Earth',
1285
                            'status'  => 3,
1286
                        ],
1287
                        [
1288
                            'address' => 'Moon',
1289
                            'status'  => 2,
1290
                        ],
1291
                    ],
1292
                ],
1293
                [
1294
                    'params' => [
1295
                        'T_upsert',
1296
                        [
1297
                            'email'   => '[email protected]',
1298
                            'address' => 'Universe',
1299
                            'status'  => 1,
1300
                        ],
1301
                        [
1302
                            'address' => 'Moon',
1303
                            'status'  => 2,
1304
                        ],
1305
                    ],
1306
                    'expected' => [
1307
                        'email'   => '[email protected]',
1308
                        'address' => 'Moon',
1309
                        'status'  => 2,
1310
                    ],
1311
                ],
1312
            ],
1313
            'regular values without update part' => [
1314
                [
1315
                    'params' => [
1316
                        'T_upsert',
1317
                        [
1318
                            'email'   => '[email protected]',
1319
                            'address' => 'Earth',
1320
                            'status'  => 3,
1321
                        ],
1322
                        false,
1323
                    ],
1324
                ],
1325
                [
1326
                    'params' => [
1327
                        'T_upsert',
1328
                        [
1329
                            'email'   => '[email protected]',
1330
                            'address' => 'Universe',
1331
                            'status'  => 1,
1332
                        ],
1333
                        false,
1334
                    ],
1335
                    'expected' => [
1336
                        'email'   => '[email protected]',
1337
                        'address' => 'Earth',
1338
                        'status'  => 3,
1339
                    ],
1340
                ],
1341
            ],
1342
            'query' => [
1343
                [
1344
                    'params' => [
1345
                        'T_upsert',
1346
                        (new Query($this->getConnection()))
1347
                            ->select([
1348
                                'email',
1349
                                'address',
1350
                                'status' => new Expression('1'),
1351
                            ])
1352
                            ->from('customer')
1353
                            ->where(['name' => 'user1'])
1354
                            ->limit(1),
1355
                    ],
1356
                    'expected' => [
1357
                        'email'   => '[email protected]',
1358
                        'address' => 'address1',
1359
                        'status'  => 1,
1360
                    ],
1361
                ],
1362
                [
1363
                    'params' => [
1364
                        'T_upsert',
1365
                        (new Query($this->getConnection()))
1366
                            ->select([
1367
                                'email',
1368
                                'address',
1369
                                'status' => new Expression('2'),
1370
                            ])
1371
                            ->from('customer')
1372
                            ->where(['name' => 'user1'])
1373
                            ->limit(1),
1374
                    ],
1375
                    'expected' => [
1376
                        'email'   => '[email protected]',
1377
                        'address' => 'address1',
1378
                        'status'  => 2,
1379
                    ],
1380
                ],
1381
            ],
1382
            'query with update part' => [
1383
                [
1384
                    'params' => [
1385
                        'T_upsert',
1386
                        (new Query($this->getConnection()))
1387
                            ->select([
1388
                                'email',
1389
                                'address',
1390
                                'status' => new Expression('1'),
1391
                            ])
1392
                            ->from('customer')
1393
                            ->where(['name' => 'user1'])
1394
                            ->limit(1),
1395
                        [
1396
                            'address' => 'Moon',
1397
                            'status'  => 2,
1398
                        ],
1399
                    ],
1400
                    'expected' => [
1401
                        'email'   => '[email protected]',
1402
                        'address' => 'address1',
1403
                        'status'  => 1,
1404
                    ],
1405
                ],
1406
                [
1407
                    'params' => [
1408
                        'T_upsert',
1409
                        (new Query($this->getConnection()))
1410
                            ->select([
1411
                                'email',
1412
                                'address',
1413
                                'status' => new Expression('3'),
1414
                            ])
1415
                            ->from('customer')
1416
                            ->where(['name' => 'user1'])
1417
                            ->limit(1),
1418
                        [
1419
                            'address' => 'Moon',
1420
                            'status'  => 2,
1421
                        ],
1422
                    ],
1423
                    'expected' => [
1424
                        'email'   => '[email protected]',
1425
                        'address' => 'Moon',
1426
                        'status'  => 2,
1427
                    ],
1428
                ],
1429
            ],
1430
            'query without update part' => [
1431
                [
1432
                    'params' => [
1433
                        'T_upsert',
1434
                        (new Query($this->getConnection()))
1435
                            ->select([
1436
                                'email',
1437
                                'address',
1438
                                'status' => new Expression('1'),
1439
                            ])
1440
                            ->from('customer')
1441
                            ->where(['name' => 'user1'])
1442
                            ->limit(1),
1443
                        false,
1444
                    ],
1445
                    'expected' => [
1446
                        'email'   => '[email protected]',
1447
                        'address' => 'address1',
1448
                        'status'  => 1,
1449
                    ],
1450
                ],
1451
                [
1452
                    'params' => [
1453
                        'T_upsert',
1454
                        (new Query($this->getConnection()))
1455
                            ->select([
1456
                                'email',
1457
                                'address',
1458
                                'status' => new Expression('2'),
1459
                            ])
1460
                            ->from('customer')
1461
                            ->where(['name' => 'user1'])
1462
                            ->limit(1),
1463
                        false,
1464
                    ],
1465
                    'expected' => [
1466
                        'email'   => '[email protected]',
1467
                        'address' => 'address1',
1468
                        'status'  => 1,
1469
                    ],
1470
                ],
1471
            ],
1472
        ];
1473
    }
1474
}
1475