Passed
Push — master ( f4eeb8...0d22ee )
by Sergei
11:47 queued 01:39
created

TestQueryTrait::testMultipleLikeConditions()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 43
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 2.0005

Importance

Changes 0
Metric Value
cc 2
eloc 30
nc 2
nop 0
dl 0
loc 43
ccs 18
cts 19
cp 0.9474
crap 2.0005
rs 9.44
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\TestUtility;
6
7
use Yiisoft\Db\Connection\ConnectionInterface;
8
use Yiisoft\Db\Exception\Exception;
9
use Yiisoft\Db\Exception\InvalidArgumentException;
10
use Yiisoft\Db\Exception\InvalidConfigException;
11
use Yiisoft\Db\Exception\NotSupportedException;
12
use Yiisoft\Db\Expression\Expression;
13
use Yiisoft\Db\Query\Query;
14
use Yiisoft\Db\Schema\Schema;
15
16
trait TestQueryTrait
17
{
18
    use GetTablesAliasTestTrait;
19
20 5
    public function testSelect(): void
21
    {
22 5
        $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

22
        /** @scrutinizer ignore-call */ 
23
        $db = $this->getConnection();
Loading history...
23
24
        /* default */
25 5
        $query = new Query($db);
26
27 5
        $query->select('*');
28
29 5
        $this->assertEquals(['*' => '*'], $query->getSelect());
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

29
        $this->/** @scrutinizer ignore-call */ 
30
               assertEquals(['*' => '*'], $query->getSelect());
Loading history...
30 5
        $this->assertNull($query->getDistinct());
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

30
        $this->/** @scrutinizer ignore-call */ 
31
               assertNull($query->getDistinct());
Loading history...
31 5
        $this->assertNull($query->getSelectOption());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $query->getSelectOption() targeting Yiisoft\Db\Query\Query::getSelectOption() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
32
33 5
        $query = new Query($db);
34
35 5
        $query->select('id, name', 'something')->distinct(true);
36
37 5
        $this->assertEquals(['id' => 'id', 'name' => 'name'], $query->getSelect());
38 5
        $this->assertTrue($query->getDistinct());
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

38
        $this->/** @scrutinizer ignore-call */ 
39
               assertTrue($query->getDistinct());
Loading history...
39 5
        $this->assertEquals('something', $query->getSelectOption());
40
41 5
        $query = new Query($db);
42
43 5
        $query->addSelect('email');
44
45 5
        $this->assertEquals(['email' => 'email'], $query->getSelect());
46
47 5
        $query = new Query($db);
48
49 5
        $query->select('id, name');
50 5
        $query->addSelect('email');
51
52 5
        $this->assertEquals(['id' => 'id', 'name' => 'name', 'email' => 'email'], $query->getSelect());
53
54 5
        $query = new Query($db);
55
56 5
        $query->select('name, lastname');
57 5
        $query->addSelect('name');
58
59 5
        $this->assertEquals(['name' => 'name', 'lastname' => 'lastname'], $query->getSelect());
60
61 5
        $query = new Query($db);
62
63 5
        $query->addSelect(['*', 'abc']);
64 5
        $query->addSelect(['*', 'bca']);
65
66 5
        $this->assertEquals(['*' => '*', 'abc' => 'abc', 'bca' => 'bca'], $query->getSelect());
67
68 5
        $query = new Query($db);
69
70 5
        $query->addSelect(['field1 as a', 'field 1 as b']);
71
72 5
        $this->assertEquals(['a' => 'field1', 'b' => 'field 1'], $query->getSelect());
73
74 5
        $query = new Query($db);
75
76 5
        $query->addSelect(['field1 a', 'field 1 b']);
77
78 5
        $this->assertEquals(['a' => 'field1', 'b' => 'field 1'], $query->getSelect());
79
80 5
        $query = new Query($db);
81
82 5
        $query->select(['name' => 'firstname', 'lastname']);
83 5
        $query->addSelect(['firstname', 'surname' => 'lastname']);
84 5
        $query->addSelect(['firstname', 'lastname']);
85
86 5
        $this->assertEquals(
87 5
            ['name' => 'firstname', 'lastname' => 'lastname', 'firstname' => 'firstname', 'surname' => 'lastname'],
88 5
            $query->getSelect()
89
        );
90
91 5
        $query = new Query($db);
92
93 5
        $query->select('name, name, name as X, name as X');
94
95 5
        $this->assertEquals(['name' => 'name', 'X' => 'name'], $query->getSelect());
96
97
        /**
98
         * {@see https://github.com/yiisoft/yii2/issues/15676}
99
         */
100 5
        $query = (new Query($db))->select('id');
101
102 5
        $this->assertSame(['id' => 'id'], $query->getSelect());
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

102
        $this->/** @scrutinizer ignore-call */ 
103
               assertSame(['id' => 'id'], $query->getSelect());
Loading history...
103
104 5
        $query->select(['id', 'brand_id']);
105
106 5
        $this->assertSame(['id' => 'id', 'brand_id' => 'brand_id'], $query->getSelect());
107
108
        /**
109
         * {@see https://github.com/yiisoft/yii2/issues/15676}
110
         */
111 5
        $query = (new Query($db))
112 5
            ->select(['prefix' => 'LEFT(name, 7)', 'prefix_key' => 'LEFT(name, 7)']);
113
114 5
        $this->assertSame(['prefix' => 'LEFT(name, 7)', 'prefix_key' => 'LEFT(name, 7)'], $query->getSelect());
115
116 5
        $query->addSelect(['LEFT(name,7) as test']);
117
118 5
        $this->assertSame(
119 5
            ['prefix' => 'LEFT(name, 7)', 'prefix_key' => 'LEFT(name, 7)', 'test' => 'LEFT(name,7)'],
120 5
            $query->getSelect()
121
        );
122
123 5
        $query->addSelect(['LEFT(name,7) as test']);
124
125 5
        $this->assertSame(
126 5
            ['prefix' => 'LEFT(name, 7)', 'prefix_key' => 'LEFT(name, 7)', 'test' => 'LEFT(name,7)'],
127 5
            $query->getSelect()
128
        );
129
130 5
        $query->addSelect(['test' => 'LEFT(name,7)']);
131
132 5
        $this->assertSame(
133 5
            ['prefix' => 'LEFT(name, 7)', 'prefix_key' => 'LEFT(name, 7)', 'test' => 'LEFT(name,7)'],
134 5
            $query->getSelect()
135
        );
136
137
        /**
138
         * {@see https://github.com/yiisoft/yii2/issues/15731}
139
         */
140
        $selectedCols = [
141
            'total_sum' => 'SUM(f.amount)',
142
            'in_sum' => 'SUM(IF(f.type = :type_in, f.amount, 0))',
143
            'out_sum' => 'SUM(IF(f.type = :type_out, f.amount, 0))',
144
        ];
145
146 5
        $query = (new Query($db))->select($selectedCols)->addParams([
147
            ':type_in' => 'in',
148
            ':type_out' => 'out',
149
            ':type_partner' => 'partner',
150
        ]);
151
152 5
        $this->assertSame($selectedCols, $query->getSelect());
153
154 5
        $query->select($selectedCols);
155
156 5
        $this->assertSame($selectedCols, $query->getSelect());
157
158
        /**
159
         * {@see https://github.com/yiisoft/yii2/issues/17384}
160
         */
161 5
        $query = new Query($db);
162
163 5
        $query->select('DISTINCT ON(tour_dates.date_from) tour_dates.date_from, tour_dates.id');
164
165 5
        $this->assertEquals(
166 5
            ['DISTINCT ON(tour_dates.date_from) tour_dates.date_from', 'tour_dates.id' => 'tour_dates.id'],
167 5
            $query->getSelect()
168
        );
169
    }
170
171 5
    public function testFrom(): void
172
    {
173 5
        $db = $this->getConnection();
174
175 5
        $query = new Query($db);
176
177 5
        $query->from('user');
178
179 5
        $this->assertEquals(['user'], $query->getFrom());
180
    }
181
182 5
    public function testFromTableIsArrayWithExpression(): void
183
    {
184 5
        $db = $this->getConnection();
185
186 5
        $query = new Query($db);
187
188 5
        $tables = new Expression('(SELECT id,name FROM user) u');
189
190 5
        $query->from($tables);
191
192 5
        $this->assertInstanceOf(Expression::class, $query->getFrom()[0]);
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

192
        $this->/** @scrutinizer ignore-call */ 
193
               assertInstanceOf(Expression::class, $query->getFrom()[0]);
Loading history...
193
    }
194
195 50
    protected function createQuery(): Query
196
    {
197 50
        return new Query($this->getConnection());
198
    }
199
200 5
    public function testWhere(): void
201
    {
202 5
        $db = $this->getConnection();
203
204 5
        $query = new Query($db);
205
206 5
        $query->where('id = :id', [':id' => 1]);
207
208 5
        $this->assertEquals('id = :id', $query->getWhere());
209 5
        $this->assertEquals([':id' => 1], $query->getParams());
210
211 5
        $query->andWhere('name = :name', [':name' => 'something']);
212
213 5
        $this->assertEquals(['and', 'id = :id', 'name = :name'], $query->getWhere());
214 5
        $this->assertEquals([':id' => 1, ':name' => 'something'], $query->getParams());
215
216 5
        $query->orWhere('age = :age', [':age' => '30']);
217
218 5
        $this->assertEquals(['or', ['and', 'id = :id', 'name = :name'], 'age = :age'], $query->getWhere());
219 5
        $this->assertEquals([':id' => 1, ':name' => 'something', ':age' => '30'], $query->getParams());
220
    }
221
222 5
    public function testFilterWhereWithHashFormat(): void
223
    {
224 5
        $db = $this->getConnection();
225
226 5
        $query = new Query($db);
227
228 5
        $query->filterWhere([
229
            'id' => 0,
230
            'title' => '   ',
231
            'author_ids' => [],
232
        ]);
233
234 5
        $this->assertEquals(['id' => 0], $query->getWhere());
235
236 5
        $query->andFilterWhere(['status' => null]);
237
238 5
        $this->assertEquals(['id' => 0], $query->getWhere());
239
240 5
        $query->orFilterWhere(['name' => '']);
241
242 5
        $this->assertEquals(['id' => 0], $query->getWhere());
243
    }
244
245 5
    public function testFilterWhereWithOperatorFormat(): void
246
    {
247 5
        $db = $this->getConnection();
248
249 5
        $query = new Query($db);
250
251 5
        $condition = ['like', 'name', 'Alex'];
252
253 5
        $query->filterWhere($condition);
254
255 5
        $this->assertEquals($condition, $query->getWhere());
256
257 5
        $query->andFilterWhere(['between', 'id', null, null]);
258
259 5
        $this->assertEquals($condition, $query->getWhere());
260
261 5
        $query->orFilterWhere(['not between', 'id', null, null]);
262
263 5
        $this->assertEquals($condition, $query->getWhere());
264
265 5
        $query->andFilterWhere(['in', 'id', []]);
266
267 5
        $this->assertEquals($condition, $query->getWhere());
268
269 5
        $query->andFilterWhere(['not in', 'id', []]);
270
271 5
        $this->assertEquals($condition, $query->getWhere());
272
273 5
        $query->andFilterWhere(['like', 'id', '']);
274
275 5
        $this->assertEquals($condition, $query->getWhere());
276
277 5
        $query->andFilterWhere(['or like', 'id', '']);
278
279 5
        $this->assertEquals($condition, $query->getWhere());
280
281 5
        $query->andFilterWhere(['not like', 'id', '   ']);
282
283 5
        $this->assertEquals($condition, $query->getWhere());
284
285 5
        $query->andFilterWhere(['or not like', 'id', null]);
286
287 5
        $this->assertEquals($condition, $query->getWhere());
288
289 5
        $query->andFilterWhere(['or', ['eq', 'id', null], ['eq', 'id', []]]);
290
291 5
        $this->assertEquals($condition, $query->getWhere());
292
    }
293
294 5
    public function testFilterHavingWithHashFormat(): void
295
    {
296 5
        $db = $this->getConnection();
297
298 5
        $query = new Query($db);
299
300 5
        $query->filterHaving([
301
            'id' => 0,
302
            'title' => '   ',
303
            'author_ids' => [],
304
        ]);
305
306 5
        $this->assertEquals(['id' => 0], $query->getHaving());
307
308 5
        $query->andFilterHaving(['status' => null]);
309
310 5
        $this->assertEquals(['id' => 0], $query->getHaving());
311
312 5
        $query->orFilterHaving(['name' => '']);
313
314 5
        $this->assertEquals(['id' => 0], $query->getHaving());
315
    }
316
317 5
    public function testFilterHavingWithOperatorFormat(): void
318
    {
319 5
        $db = $this->getConnection();
320
321 5
        $query = new Query($db);
322
323 5
        $condition = ['like', 'name', 'Alex'];
324
325 5
        $query->filterHaving($condition);
326
327 5
        $this->assertEquals($condition, $query->getHaving());
328
329 5
        $query->andFilterHaving(['between', 'id', null, null]);
330
331 5
        $this->assertEquals($condition, $query->getHaving());
332
333 5
        $query->orFilterHaving(['not between', 'id', null, null]);
334
335 5
        $this->assertEquals($condition, $query->getHaving());
336
337 5
        $query->andFilterHaving(['in', 'id', []]);
338
339 5
        $this->assertEquals($condition, $query->getHaving());
340
341 5
        $query->andFilterHaving(['not in', 'id', []]);
342
343 5
        $this->assertEquals($condition, $query->getHaving());
344
345 5
        $query->andFilterHaving(['like', 'id', '']);
346
347 5
        $this->assertEquals($condition, $query->getHaving());
348
349 5
        $query->andFilterHaving(['or like', 'id', '']);
350
351 5
        $this->assertEquals($condition, $query->getHaving());
352
353 5
        $query->andFilterHaving(['not like', 'id', '   ']);
354
355 5
        $this->assertEquals($condition, $query->getHaving());
356
357 5
        $query->andFilterHaving(['or not like', 'id', null]);
358
359 5
        $this->assertEquals($condition, $query->getHaving());
360
361 5
        $query->andFilterHaving(['or', ['eq', 'id', null], ['eq', 'id', []]]);
362
363 5
        $this->assertEquals($condition, $query->getHaving());
364
    }
365
366 5
    public function testFilterRecursively(): void
367
    {
368 5
        $db = $this->getConnection();
369
370 5
        $query = new Query($db);
371
372 5
        $query->filterWhere(
373 5
            ['and', ['like', 'name', ''],
374
                ['like', 'title', ''],
375
                ['id' => 1],
376
                ['not',
377
                    ['like', 'name', ''], ], ]
378
        );
379
380 5
        $this->assertEquals(['and', ['id' => 1]], $query->getWhere());
381
    }
382
383 5
    public function testGroup(): void
384
    {
385 5
        $db = $this->getConnection();
386
387 5
        $query = new Query($db);
388
389 5
        $query->groupBy('team');
390
391 5
        $this->assertEquals(['team'], $query->getGroupBy());
392
393 5
        $query->addGroupBy('company');
394
395 5
        $this->assertEquals(['team', 'company'], $query->getGroupBy());
396
397 5
        $query->addGroupBy('age');
398
399 5
        $this->assertEquals(['team', 'company', 'age'], $query->getGroupBy());
400
    }
401
402 5
    public function testHaving(): void
403
    {
404 5
        $db = $this->getConnection();
405
406 5
        $query = new Query($db);
407
408 5
        $query->having('id = :id', [':id' => 1]);
409
410 5
        $this->assertEquals('id = :id', $query->getHaving());
411 5
        $this->assertEquals([':id' => 1], $query->getParams());
412
413 5
        $query->andHaving('name = :name', [':name' => 'something']);
414 5
        $this->assertEquals(['and', 'id = :id', 'name = :name'], $query->getHaving());
415 5
        $this->assertEquals([':id' => 1, ':name' => 'something'], $query->getParams());
416
417 5
        $query->orHaving('age = :age', [':age' => '30']);
418 5
        $this->assertEquals(['or', ['and', 'id = :id', 'name = :name'], 'age = :age'], $query->getHaving());
419 5
        $this->assertEquals([':id' => 1, ':name' => 'something', ':age' => '30'], $query->getParams());
420
    }
421
422 5
    public function testOrder(): void
423
    {
424 5
        $db = $this->getConnection();
425
426 5
        $query = new Query($db);
427
428 5
        $query->orderBy('team');
429
430 5
        $this->assertEquals(['team' => SORT_ASC], $query->getOrderBy());
431
432 5
        $query->addOrderBy('company');
433
434 5
        $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC], $query->getOrderBy());
435
436 5
        $query->addOrderBy('age');
437
438 5
        $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC, 'age' => SORT_ASC], $query->getOrderBy());
439
440 5
        $query->addOrderBy(['age' => SORT_DESC]);
441
442 5
        $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC, 'age' => SORT_DESC], $query->getOrderBy());
443
444 5
        $query->addOrderBy('age ASC, company DESC');
445
446 5
        $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_DESC, 'age' => SORT_ASC], $query->getOrderBy());
447
448 5
        $expression = new Expression('SUBSTR(name, 3, 4) DESC, x ASC');
449
450 5
        $query->orderBy($expression);
451
452 5
        $this->assertEquals([$expression], $query->getOrderBy());
453
454 5
        $expression = new Expression('SUBSTR(name, 3, 4) DESC, x ASC');
455
456 5
        $query->addOrderBy($expression);
457
458 5
        $this->assertEquals([$expression, $expression], $query->getOrderBy());
459
    }
460
461 5
    public function testLimitOffset(): void
462
    {
463 5
        $db = $this->getConnection();
464
465 5
        $query = new Query($db);
466
467 5
        $query->limit(10)->offset(5);
468
469 5
        $this->assertEquals(10, $query->getLimit());
470 5
        $this->assertEquals(5, $query->getOffset());
471
    }
472
473 3
    public function testLimitOffsetWithExpression(): void
474
    {
475 3
        $db = $this->getConnection();
476
477 3
        $query = (new Query($db))->from('customer')->select('id')->orderBy('id');
478
479
        $query
480 3
            ->limit(new Expression('1 + 1'))
481 3
            ->offset(new Expression('1 + 0'));
482
483 3
        $result = $query->column();
484
485 3
        $this->assertCount(2, $result);
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

485
        $this->/** @scrutinizer ignore-call */ 
486
               assertCount(2, $result);
Loading history...
486
487 3
        if ($db->getDriverName() !== 'sqlsrv' && $db->getDriverName() !== 'oci') {
488 1
            $this->assertContains(2, $result);
0 ignored issues
show
Bug introduced by
It seems like assertContains() 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

488
            $this->/** @scrutinizer ignore-call */ 
489
                   assertContains(2, $result);
Loading history...
489 1
            $this->assertContains(3, $result);
490
        } else {
491 2
            $this->assertContains('2', $result);
492 2
            $this->assertContains('3', $result);
493
        }
494
495 3
        $this->assertNotContains(1, $result);
0 ignored issues
show
Bug introduced by
It seems like assertNotContains() 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

495
        $this->/** @scrutinizer ignore-call */ 
496
               assertNotContains(1, $result);
Loading history...
496
    }
497
498 5
    public function testOne(): void
499
    {
500 5
        $db = $this->getConnection(true);
501
502 5
        $result = (new Query($db))->from('customer')->where(['status' => 2])->one();
503
504 5
        $this->assertEquals('user3', $result['name']);
505
506 5
        $result = (new Query($db))->from('customer')->where(['status' => 3])->one();
507
508 5
        $this->assertFalse($result);
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

508
        $this->/** @scrutinizer ignore-call */ 
509
               assertFalse($result);
Loading history...
509
    }
510
511 5
    public function testExists(): void
512
    {
513 5
        $db = $this->getConnection();
514
515 5
        $result = (new Query($db))->from('customer')->where(['status' => 2])->exists();
516
517 5
        $this->assertTrue($result);
518
519 5
        $result = (new Query($db))->from('customer')->where(['status' => 3])->exists();
520
521 5
        $this->assertFalse($result);
522
    }
523
524 5
    public function testColumn(): void
525
    {
526 5
        $db = $this->getConnection();
527
528 5
        $result = (new Query($db))
529 5
            ->select('name')
530 5
            ->from('customer')
531 5
            ->orderBy(['id' => SORT_DESC])
532 5
            ->column();
533
534 5
        $this->assertEquals(['user3', 'user2', 'user1'], $result);
535
536
        /**
537
         * {@see https://github.com/yiisoft/yii2/issues/7515}
538
         */
539 5
        $result = (new Query($db))->from('customer')
540 5
            ->select('name')
541 5
            ->orderBy(['id' => SORT_DESC])
542 5
            ->indexBy('id')
543 5
            ->column();
544
545 5
        $this->assertEquals([3 => 'user3', 2 => 'user2', 1 => 'user1'], $result);
546
547
        /**
548
         * {@see https://github.com/yiisoft/yii2/issues/12649}
549
         */
550 5
        $result = (new Query($db))->from('customer')
551 5
            ->select(['name', 'id'])
552 5
            ->orderBy(['id' => SORT_DESC])
553 5
            ->indexBy(function ($row) {
554 5
                return $row['id'] * 2;
555
            })
556 5
            ->column();
557
558 5
        $this->assertEquals([6 => 'user3', 4 => 'user2', 2 => 'user1'], $result);
559
560 5
        $result = (new Query($db))->from('customer')
561 5
            ->select(['name'])
562 5
            ->indexBy('name')
563 5
            ->orderBy(['id' => SORT_DESC])
564 5
            ->column($db);
0 ignored issues
show
Unused Code introduced by
The call to Yiisoft\Db\Query\Query::column() has too many arguments starting with $db. ( Ignorable by Annotation )

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

564
            ->/** @scrutinizer ignore-call */ column($db);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
565
566 5
        $this->assertEquals(['user3' => 'user3', 'user2' => 'user2', 'user1' => 'user1'], $result);
567
    }
568
569 5
    public function testCount(): void
570
    {
571 5
        $db = $this->getConnection();
572
573 5
        $count = (new Query($db))->from('customer')->count('*');
574
575 5
        $this->assertEquals(3, $count);
576
577 5
        $count = (new Query($db))->from('customer')->where(['status' => 2])->count('*');
578
579 5
        $this->assertEquals(1, $count);
580
581 5
        $count = (new Query($db))
582 5
            ->select('[[status]], COUNT([[id]]) cnt')
583 5
            ->from('customer')
584 5
            ->groupBy('status')
585 5
            ->count('*');
586
587 5
        $this->assertEquals(2, $count);
588
589
        /* testing that orderBy() should be ignored here as it does not affect the count anyway. */
590 5
        $count = (new Query($db))->from('customer')->orderBy('status')->count('*');
591
592 5
        $this->assertEquals(3, $count);
593
594 5
        $count = (new Query($db))->from('customer')->orderBy('id')->limit(1)->count('*');
595
596 5
        $this->assertEquals(3, $count);
597
    }
598
599
    /**
600
     * @depends testFilterWhereWithHashFormat
601
     * @depends testFilterWhereWithOperatorFormat
602
     */
603 5
    public function testAndFilterCompare(): void
604
    {
605 5
        $db = $this->getConnection();
606
607 5
        $query = new Query($db);
608
609 5
        $result = $query->andFilterCompare('name', null);
610
611 5
        $this->assertInstanceOf(Query::class, $result);
612 5
        $this->assertNull($query->getWhere());
613
614 5
        $query->andFilterCompare('name', '');
615
616 5
        $this->assertNull($query->getWhere());
617
618 5
        $query->andFilterCompare('name', 'John Doe');
619 5
        $condition = ['=', 'name', 'John Doe'];
620
621 5
        $this->assertEquals($condition, $query->getWhere());
622
623 5
        $condition = ['and', $condition, ['like', 'name', 'Doe']];
624 5
        $query->andFilterCompare('name', 'Doe', 'like');
625
626 5
        $this->assertEquals($condition, $query->getWhere());
627
628 5
        $condition[] = ['>', 'rating', '9'];
629 5
        $query->andFilterCompare('rating', '>9');
630
631 5
        $this->assertEquals($condition, $query->getWhere());
632
633 5
        $condition[] = ['<=', 'value', '100'];
634 5
        $query->andFilterCompare('value', '<=100');
635
636 5
        $this->assertEquals($condition, $query->getWhere());
637
    }
638
639 5
    public function testEmulateExecution(): void
640
    {
641 5
        $db = $this->getConnection();
642
643 5
        $this->assertGreaterThan(0, (new Query($db))->from('customer')->count('*'));
0 ignored issues
show
Bug introduced by
It seems like assertGreaterThan() 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

643
        $this->/** @scrutinizer ignore-call */ 
644
               assertGreaterThan(0, (new Query($db))->from('customer')->count('*'));
Loading history...
644
645 5
        $rows = (new Query($db))->from('customer')->emulateExecution()->all();
646
647 5
        $this->assertSame([], $rows);
648
649 5
        $row = (new Query($db))->from('customer')->emulateExecution()->one();
650
651 5
        $this->assertFalse($row);
652
653 5
        $exists = (new Query($db))->from('customer')->emulateExecution()->exists($db);
0 ignored issues
show
Unused Code introduced by
The call to Yiisoft\Db\Query\Query::exists() has too many arguments starting with $db. ( Ignorable by Annotation )

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

653
        $exists = (new Query($db))->from('customer')->emulateExecution()->/** @scrutinizer ignore-call */ exists($db);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
654
655 5
        $this->assertFalse($exists);
656
657 5
        $count = (new Query($db))->from('customer')->emulateExecution()->count('*');
658
659 5
        $this->assertSame(0, $count);
660
661 5
        $sum = (new Query($db))->from('customer')->emulateExecution()->sum('id');
662
663 5
        $this->assertSame(0, $sum);
664
665 5
        $sum = (new Query($db))->from('customer')->emulateExecution()->average('id');
666
667 5
        $this->assertSame(0, $sum);
668
669 5
        $max = (new Query($db))->from('customer')->emulateExecution()->max('id');
670
671 5
        $this->assertNull($max);
672
673 5
        $min = (new Query($db))->from('customer')->emulateExecution()->min('id');
674
675 5
        $this->assertNull($min);
676
677 5
        $scalar = (new Query($db))->select(['id'])->from('customer')->emulateExecution()->scalar();
678
679 5
        $this->assertNull($scalar);
680
681 5
        $column = (new Query($db))->select(['id'])->from('customer')->emulateExecution()->column();
682
683 5
        $this->assertSame([], $column);
684
    }
685
686
    /**
687
     * @param Connection $db
0 ignored issues
show
Bug introduced by
The type Yiisoft\Db\TestUtility\Connection was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
688
     * @param string $tableName
689
     * @param string $columnName
690
     * @param array $condition
691
     * @param string $operator
692
     *
693
     * @throws Exception
694
     * @throws InvalidArgumentException
695
     * @throws InvalidConfigException
696
     * @throws NotSupportedException
697
     *
698
     * @return int
699
     */
700 5
    protected function countLikeQuery(
701
        ConnectionInterface $db,
0 ignored issues
show
Unused Code introduced by
The parameter $db is not used and could be removed. ( Ignorable by Annotation )

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

701
        /** @scrutinizer ignore-unused */ ConnectionInterface $db,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
702
        string $tableName,
703
        string $columnName,
704
        array $condition,
705
        string $operator = 'or'
706
    ): int {
707 5
        $db = $this->getConnection();
708
709 5
        $whereCondition = [$operator];
710
711 5
        foreach ($condition as $value) {
712 5
            $whereCondition[] = ['like', $columnName, $value];
713
        }
714
715 5
        $result = (new Query($db))->from($tableName)->where($whereCondition)->count('*');
716
717 5
        if (is_numeric($result)) {
718 5
            $result = (int) $result;
719
        }
720
721 5
        return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result could return the type string which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
722
    }
723
724
    /**
725
     * {@see https://github.com/yiisoft/yii2/issues/13745}
726
     */
727 5
    public function testMultipleLikeConditions(): void
728
    {
729 5
        $db = $this->getConnection();
730
731 5
        $tableName = 'like_test';
732 5
        $columnName = 'col';
733
734 5
        if ($db->getSchema()->getTableSchema($tableName) !== null) {
735
            $db->createCommand()->dropTable($tableName)->execute();
736
        }
737
738 5
        $db->createCommand()->createTable($tableName, [
739 5
            $columnName => $db->getSchema()->createColumnSchemaBuilder(Schema::TYPE_STRING, 64),
740 5
        ])->execute();
741
742 5
        $db->createCommand()->batchInsert($tableName, ['col'], [
743 5
            ['test0'],
744
            ['test\1'],
745
            ['test\2'],
746
            ['foo%'],
747
            ['%bar'],
748
            ['%baz%'],
749 5
        ])->execute();
750
751
        /* Basic tests */
752 5
        $this->assertSame(1, $this->countLikeQuery($db, $tableName, $columnName, ['test0']));
753 5
        $this->assertSame(2, $this->countLikeQuery($db, $tableName, $columnName, ['test\\']));
754 5
        $this->assertSame(0, $this->countLikeQuery($db, $tableName, $columnName, ['test%']));
755 5
        $this->assertSame(3, $this->countLikeQuery($db, $tableName, $columnName, ['%']));
756
757
        /* Multiple condition tests */
758 5
        $this->assertSame(2, $this->countLikeQuery($db, $tableName, $columnName, [
759
            'test0',
760
            'test\1',
761
        ]));
762 5
        $this->assertSame(3, $this->countLikeQuery($db, $tableName, $columnName, [
763
            'test0',
764
            'test\1',
765
            'test\2',
766
        ]));
767 5
        $this->assertSame(3, $this->countLikeQuery($db, $tableName, $columnName, [
768
            'foo',
769
            '%ba',
770
        ]));
771
    }
772
773
    /**
774
     * {@see https://github.com/yiisoft/yii2/issues/15355}
775
     */
776 5
    public function testExpressionInFrom(): void
777
    {
778 5
        $db = $this->getConnection(true);
779
780 5
        $query = (new Query($db))
781 5
            ->from(
782 5
                new Expression(
783
                    '(SELECT [[id]], [[name]], [[email]], [[address]], [[status]] FROM {{customer}}) c'
784
                )
785
            )
786 5
            ->where(['status' => 2]);
787
788 5
        $result = $query->one();
789
790 5
        $this->assertEquals('user3', $result['name']);
791
    }
792
793 5
    public function testQueryCache()
794
    {
795 5
        $db = $this->getConnection();
796
797 5
        $this->queryCache->setEnable(true);
798
799 5
        $query = (new Query($db))
800 5
            ->select(['name'])
801 5
            ->from('customer');
802
803 5
        $update = $db->createCommand('UPDATE {{customer}} SET [[name]] = :name WHERE [[id]] = :id');
804
805 5
        $this->assertEquals('user1', $query->where(['id' => 1])->scalar(), 'Asserting initial value');
806
807
        /* No cache */
808 5
        $update->bindValues([':id' => 1, ':name' => 'user11'])->execute();
809
810 5
        $this->assertEquals(
811
            'user11',
812 5
            $query->where(['id' => 1])->scalar(),
813
            'Query reflects DB changes when caching is disabled'
814
        );
815
816
        /* Connection cache */
817 5
        $db->cache(function (ConnectionInterface $db) use ($query, $update) {
818 5
            $this->assertEquals(
819
                'user2',
820 5
                $query->where(['id' => 2])->scalar(),
821
                'Asserting initial value for user #2'
822
            );
823
824 5
            $update->bindValues([':id' => 2, ':name' => 'user22'])->execute();
825
826 5
            $this->assertEquals(
827
                'user2',
828 5
                $query->where(['id' => 2])->scalar(),
829
                'Query does NOT reflect DB changes when wrapped in connection caching'
830
            );
831
832 5
            $db->noCache(function () use ($query) {
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

832
            $db->/** @scrutinizer ignore-call */ 
833
                 noCache(function () use ($query) {
Loading history...
833 5
                $this->assertEquals(
834
                    'user22',
835 5
                    $query->where(['id' => 2])->scalar(),
836
                    'Query reflects DB changes when wrapped in connection caching and noCache simultaneously'
837
                );
838
            });
839
840 5
            $this->assertEquals(
841
                'user2',
842 5
                $query->where(['id' => 2])->scalar(),
843
                'Cache does not get changes after getting newer data from DB in noCache block.'
844
            );
845
        }, 10);
846
847 5
        $this->queryCache->setEnable(false);
848
849 5
        $db->cache(function () use ($query, $update) {
850 5
            $this->assertEquals(
851
                'user22',
852 5
                $query->where(['id' => 2])->scalar(),
853
                'When cache is disabled for the whole connection, Query inside cache block does not get cached'
854
            );
855
856 5
            $update->bindValues([':id' => 2, ':name' => 'user2'])->execute();
857
858 5
            $this->assertEquals('user2', $query->where(['id' => 2])->scalar());
859
        }, 10);
860
861 5
        $this->queryCache->setEnable(true);
862
863 5
        $query->cache();
864
865 5
        $this->assertEquals('user11', $query->where(['id' => 1])->scalar());
866
867 5
        $update->bindValues([':id' => 1, ':name' => 'user1'])->execute();
868
869 5
        $this->assertEquals(
870
            'user11',
871 5
            $query->where(['id' => 1])->scalar(),
872
            'When both Connection and Query have cache enabled, we get cached value'
873
        );
874 5
        $this->assertEquals(
875
            'user1',
876 5
            $query->noCache()->where(['id' => 1])->scalar(),
877
            'When Query has disabled cache, we get actual data'
878
        );
879
880 5
        $db->cache(function () use ($query) {
881 5
            $this->assertEquals('user1', $query->noCache()->where(['id' => 1])->scalar());
882 5
            $this->assertEquals('user11', $query->cache()->where(['id' => 1])->scalar());
883
        }, 10);
884
    }
885
886
    /**
887
     * checks that all needed properties copied from source to new query
888
     */
889 5
    public function testQueryCreation(): void
890
    {
891 5
        $db = $this->getConnection();
892
893 5
        $where = 'id > :min_user_id';
894 5
        $limit = 50;
895 5
        $offset = 2;
896 5
        $orderBy = ['name' => SORT_ASC];
897 5
        $indexBy = 'id';
898 5
        $select = ['id' => 'id', 'name' => 'name', 'articles_count' => 'count(*)'];
899 5
        $selectOption = 'SQL_NO_CACHE';
900 5
        $from = 'recent_users';
901 5
        $groupBy = 'id';
902 5
        $having = ['>', 'articles_count', 0];
903 5
        $params = [':min_user_id' => 100];
904
905 5
        [$joinType, $joinTable, $joinOn] = $join = ['INNER', 'articles', 'articles.author_id=users.id'];
906
907 5
        $unionQuery = (new Query($db))
908 5
            ->select('id, name, 1000 as articles_count')
909 5
            ->from('admins');
910
911 5
        $withQuery = (new Query($db))
912 5
            ->select('id, name')
913 5
            ->from('users')
914 5
            ->where('DATE(registered_at) > "2020-01-01"');
915
916
        /** build target query */
917 5
        $sourceQuery = (new Query($db))
918 5
            ->where($where)
919 5
            ->limit($limit)
920 5
            ->offset($offset)
921 5
            ->orderBy($orderBy)
922 5
            ->indexBy($indexBy)
923 5
            ->select($select, $selectOption)
924 5
            ->distinct()
925 5
            ->from($from)
926 5
            ->groupBy($groupBy)
927 5
            ->having($having)
928 5
            ->addParams($params)
929 5
            ->join($joinType, $joinTable, $joinOn)
930 5
            ->union($unionQuery)
931 5
            ->withQuery($withQuery, $from);
932
933 5
        $newQuery = Query::create($db, $sourceQuery);
934
935 5
        $this->assertEquals($where, $newQuery->getWhere());
936 5
        $this->assertEquals($limit, $newQuery->getLimit());
937 5
        $this->assertEquals($offset, $newQuery->getOffset());
938 5
        $this->assertEquals($orderBy, $newQuery->getOrderBy());
939 5
        $this->assertEquals($indexBy, $newQuery->getIndexBy());
940 5
        $this->assertEquals($select, $newQuery->getSelect());
941 5
        $this->assertEquals($selectOption, $newQuery->getSelectOption());
942 5
        $this->assertTrue($newQuery->getDistinct());
943 5
        $this->assertEquals([$from], $newQuery->getFrom());
944 5
        $this->assertEquals([$groupBy], $newQuery->getGroupBy());
945 5
        $this->assertEquals($having, $newQuery->getHaving());
946 5
        $this->assertEquals($params, $newQuery->getParams());
947 5
        $this->assertEquals([$join], $newQuery->getJoin());
948 5
        $this->assertEquals([['query' => $unionQuery, 'all' => false]], $newQuery->getUnion());
949 5
        $this->assertEquals(
950 5
            [['query' => $withQuery, 'alias' => $from, 'recursive' => false]],
951 5
            $newQuery->getWithQueries()
952
        );
953
    }
954
}
955