Passed
Push — master ( 383493...d29574 )
by Chito
02:01
created

QueryTest::testOrderClear()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 7
c 1
b 1
f 0
dl 0
loc 13
rs 10
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Lampager\Cake\Test\TestCase\ORM;
4
5
use Cake\Database\Expression\OrderClauseExpression;
6
use Cake\I18n\Time;
7
use Cake\ORM\Entity;
8
use Cake\ORM\Table;
9
use Cake\ORM\TableRegistry;
10
use Lampager\Cake\Model\Behavior\LampagerBehavior;
11
use Lampager\Cake\ORM\Query;
12
use Lampager\Cake\PaginationResult;
13
use Lampager\Cake\Paginator;
14
use Lampager\Cake\Test\TestCase\TestCase;
15
use Lampager\Contracts\Exceptions\LampagerException;
16
use Lampager\Exceptions\Query\BadKeywordException;
17
use Lampager\Exceptions\Query\InsufficientConstraintsException;
18
use Lampager\Exceptions\Query\LimitParameterException;
19
use PHPUnit\Framework\MockObject\MockObject;
20
21
class QueryTest extends TestCase
22
{
23
    public $fixtures = [
24
        'plugin.Lampager\\Cake.Posts',
25
    ];
26
27
    /**
28
     * @param        callable         $factory
29
     * @param        PaginationResult $expected
30
     * @dataProvider orderProvider
31
     */
32
    public function testOrder(callable $factory, PaginationResult $expected)
33
    {
34
        /** @var LampagerBehavior&Table $posts */
35
        $posts = TableRegistry::getTableLocator()->get('Posts');
36
        $posts->addBehavior(LampagerBehavior::class);
37
38
        /** @var Query $query */
39
        $query = $factory($posts);
40
        $this->assertJsonEquals($expected, $query->all());
41
    }
42
43
    /**
44
     * @param        callable         $factory
45
     * @param        PaginationResult $expected
46
     * @dataProvider orderProvider
47
     */
48
    public function testOrderClear(callable $factory)
49
    {
50
        $this->expectException(LampagerException::class);
51
        $this->expectExceptionMessage('At least one order constraint required');
52
53
        /** @var LampagerBehavior&Table $posts */
54
        $posts = TableRegistry::getTableLocator()->get('Posts');
55
        $posts->addBehavior(LampagerBehavior::class);
56
57
        /** @var Query $query */
58
        $query = $factory($posts);
59
        $query->order([], true);
60
        $query->all();
61
    }
62
63
    public function testOrderIllegal()
64
    {
65
        $this->expectException(BadKeywordException::class);
66
        $this->expectExceptionMessage('OrderClauseExpression does not have direction');
67
68
        /** @var MockObject&OrderClauseExpression */
69
        $expression = $this->getMockBuilder(OrderClauseExpression::class)->disableOriginalConstructor()->getMock();
70
        $expression->method('sql')->willReturn('modified');
71
72
        /** @var LampagerBehavior&Table $posts */
73
        $posts = TableRegistry::getTableLocator()->get('Posts');
74
        $posts->addBehavior(LampagerBehavior::class);
75
        $posts->lampager()
76
            ->order([$expression])
77
            ->all();
78
    }
79
80
    public function testOrderQueryExpression()
81
    {
82
        /** @var LampagerBehavior&Table $posts */
83
        $posts = TableRegistry::getTableLocator()->get('Posts');
84
        $posts->addBehavior(LampagerBehavior::class);
85
86
        $expected = new PaginationResult(
87
            [
88
                new Entity([
89
                    'id' => 1,
90
                    'modified' => new Time('2017-01-01 10:00:00'),
91
                ]),
92
            ],
93
            [
94
                'hasPrevious' => null,
95
                'previousCursor' => null,
96
                'hasNext' => true,
97
                'nextCursor' => [
98
                    'id' => 3,
99
                    'modified' => new Time('2017-01-01 10:00:00'),
100
                ],
101
            ]
102
        );
103
104
        $actual = $posts->lampager()
105
            ->order([$posts->query()->newExpr(['modified'])])
106
            ->order([$posts->query()->newExpr(['id'])])
107
            ->limit(1)
108
            ->all();
109
110
        $this->assertJsonEquals($expected, $actual);
111
    }
112
113
    public function testLimitQueryExpression()
114
    {
115
        /** @var LampagerBehavior&Table $posts */
116
        $posts = TableRegistry::getTableLocator()->get('Posts');
117
        $posts->addBehavior(LampagerBehavior::class);
118
119
        $expected = new PaginationResult(
120
            [
121
                new Entity([
122
                    'id' => 1,
123
                    'modified' => new Time('2017-01-01 10:00:00'),
124
                ]),
125
            ],
126
            [
127
                'hasPrevious' => null,
128
                'previousCursor' => null,
129
                'hasNext' => true,
130
                'nextCursor' => [
131
                    'id' => 3,
132
                    'modified' => new Time('2017-01-01 10:00:00'),
133
                ],
134
            ]
135
        );
136
137
        $actual = $posts->lampager()
138
            ->orderAsc('modified')
139
            ->orderAsc('id')
140
            ->limit($posts->query()->newExpr(['1']))
141
            ->all();
142
143
        $this->assertJsonEquals($expected, $actual);
144
    }
145
146
    public function testLimitIllegalQueryExpression()
147
    {
148
        $this->expectException(LimitParameterException::class);
149
        $this->expectExceptionMessage('Limit must be positive integer');
150
151
        /** @var LampagerBehavior&Table $posts */
152
        $posts = TableRegistry::getTableLocator()->get('Posts');
153
        $posts->addBehavior(LampagerBehavior::class);
154
        $posts->lampager()
155
            ->orderAsc('modified')
156
            ->orderAsc('id')
157
            ->limit($posts->query()->newExpr(['1 + 1']))
158
            ->all();
159
    }
160
161
    public function testWhere()
162
    {
163
        /** @var LampagerBehavior&Table $posts */
164
        $posts = TableRegistry::getTableLocator()->get('Posts');
165
        $posts->addBehavior(LampagerBehavior::class);
166
167
        $expected = new PaginationResult(
168
            [
169
                new Entity([
170
                    'id' => 3,
171
                    'modified' => new Time('2017-01-01 10:00:00'),
172
                ]),
173
            ],
174
            [
175
                'hasPrevious' => null,
176
                'previousCursor' => null,
177
                'hasNext' => true,
178
                'nextCursor' => [
179
                    'id' => 5,
180
                    'modified' => new Time('2017-01-01 10:00:00'),
181
                ],
182
            ]
183
        );
184
185
        $actual = $posts->lampager()
186
            ->where(['id >' => 1])
187
            ->orderAsc('modified')
188
            ->orderAsc('id')
189
            ->limit(1)
190
            ->all();
191
192
        $this->assertJsonEquals($expected, $actual);
193
    }
194
195
    public function testGroup()
196
    {
197
        $this->expectException(InsufficientConstraintsException::class);
198
        $this->expectExceptionMessage('group()/union() are not supported');
199
200
        /** @var LampagerBehavior&Table $posts */
201
        $posts = TableRegistry::getTableLocator()->get('Posts');
202
        $posts->addBehavior(LampagerBehavior::class);
203
        $posts->lampager()
204
            ->orderAsc('modified')
205
            ->orderAsc('id')
206
            ->group('modified')
207
            ->all();
208
    }
209
210
    public function testUnion()
211
    {
212
        $this->expectException(InsufficientConstraintsException::class);
213
        $this->expectExceptionMessage('group()/union() are not supported');
214
215
        /** @var LampagerBehavior&Table $posts */
216
        $posts = TableRegistry::getTableLocator()->get('Posts');
217
        $posts->addBehavior(LampagerBehavior::class);
218
        $posts->lampager()
219
            ->orderAsc('modified')
220
            ->orderAsc('id')
221
            ->union($posts->query()->select())
222
            ->all();
223
    }
224
225
    public function testCall()
226
    {
227
        /** @var LampagerBehavior&Table $posts */
228
        $posts = TableRegistry::getTableLocator()->get('Posts');
229
        $posts->addBehavior(LampagerBehavior::class);
230
231
        $actual = $posts->lampager()
232
            ->orderAsc('id')
233
            ->take();
234
235
        $expected = [
236
            new Entity([
237
                'id' => 1,
238
                'modified' => new Time('2017-01-01 10:00:00'),
239
            ]),
240
        ];
241
242
        $this->assertJsonEquals($expected, $actual);
243
    }
244
245
    public function testDebugInfo()
246
    {
247
        /** @var LampagerBehavior&Table $posts */
248
        $posts = TableRegistry::getTableLocator()->get('Posts');
249
        $posts->addBehavior(LampagerBehavior::class);
250
251
        $actual = $posts->lampager()
252
            ->orderAsc('modified')
253
            ->orderAsc('id')
254
            ->limit(3)
255
            ->__debugInfo();
256
257
        $this->assertSame('This is a Lampager Query object to get the paginated results.', $actual['(help)']);
258
        $this->assertInstanceOf(Paginator::class, $actual['paginator']);
259
        $this->assertTextStartsWith('SELECT ', $actual['sql']);
260
        $this->assertSame($posts, $actual['repository']);
261
262
        $this->assertArrayHasKey('params', $actual);
263
        $this->assertArrayHasKey('defaultTypes', $actual);
264
        $this->assertArrayHasKey('decorators', $actual);
265
        $this->assertArrayHasKey('executed', $actual);
266
        $this->assertArrayHasKey('hydrate', $actual);
267
        $this->assertArrayHasKey('buffered', $actual);
268
        $this->assertArrayHasKey('formatters', $actual);
269
        $this->assertArrayHasKey('mapReducers', $actual);
270
        $this->assertArrayHasKey('contain', $actual);
271
        $this->assertArrayHasKey('matching', $actual);
272
        $this->assertArrayHasKey('extraOptions', $actual);
273
    }
274
275
    public function testDebugInfoIncomplete()
276
    {
277
        /** @var LampagerBehavior&Table $posts */
278
        $posts = TableRegistry::getTableLocator()->get('Posts');
279
        $posts->addBehavior(LampagerBehavior::class);
280
281
        $actual = $posts->lampager()
282
            ->limit(3)
283
            ->__debugInfo();
284
285
        $this->assertSame('This is a Lampager Query object to get the paginated results.', $actual['(help)']);
286
        $this->assertInstanceOf(Paginator::class, $actual['paginator']);
287
        $this->assertSame('SQL could not be generated for this query as it is incomplete: At least one order constraint required', $actual['sql']);
288
        $this->assertSame($posts, $actual['repository']);
289
290
        $this->assertArrayHasKey('params', $actual);
291
        $this->assertArrayHasKey('defaultTypes', $actual);
292
        $this->assertArrayHasKey('decorators', $actual);
293
        $this->assertArrayHasKey('executed', $actual);
294
        $this->assertArrayHasKey('hydrate', $actual);
295
        $this->assertArrayHasKey('buffered', $actual);
296
        $this->assertArrayHasKey('formatters', $actual);
297
        $this->assertArrayHasKey('mapReducers', $actual);
298
        $this->assertArrayHasKey('contain', $actual);
299
        $this->assertArrayHasKey('matching', $actual);
300
        $this->assertArrayHasKey('extraOptions', $actual);
301
    }
302
303
    /**
304
     * @param        callable      $factory
305
     * @param        int           $expected
306
     * @dataProvider countProvider
307
     */
308
    public function testCount(callable $factory, $expected)
309
    {
310
        /** @var LampagerBehavior&Table $posts */
311
        $posts = TableRegistry::getTableLocator()->get('Posts');
312
        $posts->addBehavior(LampagerBehavior::class);
313
314
        $this->assertSame($expected, $factory($posts));
315
    }
316
317
    public function orderProvider()
318
    {
319
        yield 'Ascending and ascending' => [
320
            function (Table $posts) {
321
                /** @var LampagerBehavior&Table $posts */
322
                return $posts->lampager()
323
                    ->forward()
324
                    ->seekable()
325
                    ->limit(3)
326
                    ->order([
327
                        'modified' => 'asc',
328
                        'id' => 'asc',
329
                    ]);
330
            },
331
            new PaginationResult(
332
                [
333
                    new Entity([
334
                        'id' => 1,
335
                        'modified' => new Time('2017-01-01 10:00:00'),
336
                    ]),
337
                    new Entity([
338
                        'id' => 3,
339
                        'modified' => new Time('2017-01-01 10:00:00'),
340
                    ]),
341
                    new Entity([
342
                        'id' => 5,
343
                        'modified' => new Time('2017-01-01 10:00:00'),
344
                    ]),
345
                ],
346
                [
347
                    'hasPrevious' => null,
348
                    'previousCursor' => null,
349
                    'hasNext' => true,
350
                    'nextCursor' => [
351
                        'id' => 2,
352
                        'modified' => new Time('2017-01-01 11:00:00'),
353
                    ],
354
                ]
355
            ),
356
        ];
357
358
        yield 'Descending and descending' => [
359
            function (Table $posts) {
360
                /** @var LampagerBehavior&Table $posts */
361
                return $posts->lampager()
362
                    ->forward()
363
                    ->seekable()
364
                    ->limit(3)
365
                    ->order([
366
                        'modified' => 'desc',
367
                        'id' => 'desc',
368
                    ]);
369
            },
370
            new PaginationResult(
371
                [
372
                    new Entity([
373
                        'id' => 4,
374
                        'modified' => new Time('2017-01-01 11:00:00'),
375
                    ]),
376
                    new Entity([
377
                        'id' => 2,
378
                        'modified' => new Time('2017-01-01 11:00:00'),
379
                    ]),
380
                    new Entity([
381
                        'id' => 5,
382
                        'modified' => new Time('2017-01-01 10:00:00'),
383
                    ]),
384
                ],
385
                [
386
                    'hasPrevious' => null,
387
                    'previousCursor' => null,
388
                    'hasNext' => true,
389
                    'nextCursor' => [
390
                        'id' => 3,
391
                        'modified' => new Time('2017-01-01 10:00:00'),
392
                    ],
393
                ]
394
            ),
395
        ];
396
    }
397
398
    public function countProvider()
399
    {
400
        yield 'Ascending forward start inclusive' => [
401
            function (Table $posts) {
402
                /** @var LampagerBehavior&Table $posts */
403
                return $posts->lampager()
404
                    ->forward()
405
                    ->seekable()
406
                    ->limit(3)
407
                    ->orderAsc('modified')
408
                    ->orderAsc('id')
409
                    ->count();
410
            },
411
            3,
412
        ];
413
414
        yield 'Ascending forward start exclusive' => [
415
            function (Table $posts) {
416
                /** @var LampagerBehavior&Table $posts */
417
                return $posts->lampager()
418
                    ->forward()
419
                    ->seekable()
420
                    ->exclusive()
421
                    ->limit(3)
422
                    ->orderAsc('modified')
423
                    ->orderAsc('id')
424
                    ->count();
425
            },
426
            3,
427
        ];
428
429
        yield 'Ascending forward inclusive' => [
430
            function (Table $posts) {
431
                /** @var LampagerBehavior&Table $posts */
432
                return $posts->lampager()
433
                    ->forward()
434
                    ->seekable()
435
                    ->limit(3)
436
                    ->orderAsc('modified')
437
                    ->orderAsc('id')
438
                    ->cursor([
439
                        'id' => 3,
440
                        'modified' => new Time('2017-01-01 10:00:00'),
441
                    ])
442
                    ->count();
443
            },
444
            3,
445
        ];
446
447
        yield 'Ascending forward exclusive' => [
448
            function (Table $posts) {
449
                /** @var LampagerBehavior&Table $posts */
450
                return $posts->lampager()
451
                    ->forward()
452
                    ->seekable()
453
                    ->exclusive()
454
                    ->limit(3)
455
                    ->orderAsc('modified')
456
                    ->orderAsc('id')
457
                    ->cursor([
458
                        'id' => 3,
459
                        'modified' => new Time('2017-01-01 10:00:00'),
460
                    ])
461
                    ->count();
462
            },
463
            3,
464
        ];
465
466
        yield 'Ascending backward start inclusive' => [
467
            function (Table $posts) {
468
                /** @var LampagerBehavior&Table $posts */
469
                return $posts->lampager()
470
                    ->backward()
471
                    ->seekable()
472
                    ->limit(3)
473
                    ->orderAsc('modified')
474
                    ->orderAsc('id')
475
                    ->count();
476
            },
477
            3,
478
        ];
479
480
        yield 'Ascending backward start exclusive' => [
481
            function (Table $posts) {
482
                /** @var LampagerBehavior&Table $posts */
483
                return $posts->lampager()
484
                    ->backward()
485
                    ->seekable()
486
                    ->exclusive()
487
                    ->limit(3)
488
                    ->orderAsc('modified')
489
                    ->orderAsc('id')
490
                    ->count();
491
            },
492
            3,
493
        ];
494
495
        yield 'Ascending backward inclusive' => [
496
            function (Table $posts) {
497
                /** @var LampagerBehavior&Table $posts */
498
                return $posts->lampager()
499
                    ->backward()
500
                    ->seekable()
501
                    ->limit(3)
502
                    ->orderAsc('modified')
503
                    ->orderAsc('id')
504
                    ->cursor([
505
                        'id' => 3,
506
                        'modified' => new Time('2017-01-01 10:00:00'),
507
                    ])
508
                    ->count();
509
            },
510
            2,
511
        ];
512
513
        yield 'Ascending backward exclusive' => [
514
            function (Table $posts) {
515
                /** @var LampagerBehavior&Table $posts */
516
                return $posts->lampager()
517
                    ->backward()
518
                    ->seekable()
519
                    ->exclusive()
520
                    ->limit(3)
521
                    ->orderAsc('modified')
522
                    ->orderAsc('id')
523
                    ->cursor([
524
                        'id' => 3,
525
                        'modified' => new Time('2017-01-01 10:00:00'),
526
                    ])
527
                    ->count();
528
            },
529
            1,
530
        ];
531
532
        yield 'Descending forward start inclusive' => [
533
            function (Table $posts) {
534
                /** @var LampagerBehavior&Table $posts */
535
                return $posts->lampager()
536
                    ->forward()
537
                    ->seekable()
538
                    ->limit(3)
539
                    ->orderDesc('modified')
540
                    ->orderDesc('id')
541
                    ->count();
542
            },
543
            3,
544
        ];
545
546
        yield 'Descending forward start exclusive' => [
547
            function (Table $posts) {
548
                /** @var LampagerBehavior&Table $posts */
549
                return $posts->lampager()
550
                    ->forward()
551
                    ->seekable()
552
                    ->exclusive()
553
                    ->limit(3)
554
                    ->orderDesc('modified')
555
                    ->orderDesc('id')
556
                    ->count();
557
            },
558
            3,
559
        ];
560
561
        yield 'Descending forward inclusive' => [
562
            function (Table $posts) {
563
                /** @var LampagerBehavior&Table $posts */
564
                return $posts->lampager()
565
                    ->forward()
566
                    ->seekable()
567
                    ->limit(3)
568
                    ->orderDesc('modified')
569
                    ->orderDesc('id')
570
                    ->cursor([
571
                        'id' => 3,
572
                        'modified' => new Time('2017-01-01 10:00:00'),
573
                    ])
574
                    ->count();
575
            },
576
            2,
577
        ];
578
579
        yield 'Descending forward exclusive' => [
580
            function (Table $posts) {
581
                /** @var LampagerBehavior&Table $posts */
582
                return $posts->lampager()
583
                    ->forward()
584
                    ->seekable()
585
                    ->exclusive()
586
                    ->limit(3)
587
                    ->orderDesc('modified')
588
                    ->orderDesc('id')
589
                    ->cursor([
590
                        'id' => 3,
591
                        'modified' => new Time('2017-01-01 10:00:00'),
592
                    ])
593
                    ->count();
594
            },
595
            1,
596
        ];
597
598
        yield 'Descending backward start inclusive' => [
599
            function (Table $posts) {
600
                /** @var LampagerBehavior&Table $posts */
601
                return $posts->lampager()
602
                    ->backward()
603
                    ->seekable()
604
                    ->limit(3)
605
                    ->orderDesc('modified')
606
                    ->orderDesc('id')
607
                    ->count();
608
            },
609
            3,
610
        ];
611
612
        yield 'Descending backward start exclusive' => [
613
            function (Table $posts) {
614
                /** @var LampagerBehavior&Table $posts */
615
                return $posts->lampager()
616
                    ->backward()
617
                    ->seekable()
618
                    ->exclusive()
619
                    ->limit(3)
620
                    ->orderDesc('modified')
621
                    ->orderDesc('id')
622
                    ->count();
623
            },
624
            3,
625
        ];
626
627
        yield 'Descending backward inclusive' => [
628
            function (Table $posts) {
629
                /** @var LampagerBehavior&Table $posts */
630
                return $posts->lampager()
631
                    ->backward()
632
                    ->seekable()
633
                    ->limit(3)
634
                    ->orderDesc('modified')
635
                    ->orderDesc('id')
636
                    ->cursor([
637
                        'id' => 3,
638
                        'modified' => new Time('2017-01-01 10:00:00'),
639
                    ])
640
                    ->count();
641
            },
642
            3,
643
        ];
644
645
        yield 'Descending backward exclusive' => [
646
            function (Table $posts) {
647
                /** @var LampagerBehavior&Table $posts */
648
                return $posts->lampager()
649
                    ->backward()
650
                    ->seekable()
651
                    ->exclusive()
652
                    ->limit(3)
653
                    ->orderDesc('modified')
654
                    ->orderDesc('id')
655
                    ->cursor([
656
                        'id' => 3,
657
                        'modified' => new Time('2017-01-01 10:00:00'),
658
                    ])
659
                    ->count();
660
            },
661
            3,
662
        ];
663
    }
664
}
665