Passed
Push — master ( 0dc7c1...a9f887 )
by Chito
01:43
created

PaginatorTest.php$5 ➔ valueProvider()   B

Complexity

Conditions 1

Size

Total Lines 643

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 643
rs 8
cc 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Lampager\Cake\Test\TestCase\Datasource;
6
7
use Cake\Controller\Controller;
8
use Cake\Database\Expression\OrderClauseExpression;
9
use Cake\Datasource\QueryInterface;
10
use Cake\Http\ServerRequest;
11
use Cake\I18n\DateTime;
12
use Cake\ORM\Entity;
13
use Cake\ORM\Table;
14
use Exception;
15
use Generator;
16
use Lampager\Cake\Datasource\Paginator;
17
use Lampager\Cake\Model\Behavior\LampagerBehavior;
18
use Lampager\Cake\PaginationResult;
19
use Lampager\Cake\Test\TestCase\TestCase;
20
use Lampager\Exceptions\InvalidArgumentException;
21
use PHPUnit\Framework\MockObject\MockObject;
22
23
class PaginatorTest extends TestCase
24
{
25
    public array $fixtures = [
26
        'plugin.Lampager\\Cake.Posts',
27
    ];
28
29
    /**
30
     * @dataProvider valueProvider
31
     * @dataProvider queryExpressionProvider
32
     */
33
    public function testPaginateTable(callable $factory, PaginationResult $expected): void
34
    {
35
        $controller = new class(new ServerRequest()) extends Controller {
36
            public $Posts = null;
37
38
            public array $paginate = [
39
                'className' => Paginator::class,
40
            ];
41
        };
42
43
        $posts = $controller->fetchTable('Posts');
44
45
        /** @var mixed[] $options */
46
        $options = $factory($posts);
47
48
        $this->assertJsonEquals($expected, $controller->paginate('Posts', $options));
49
    }
50
51
    /**
52
     * @dataProvider valueProvider
53
     * @dataProvider queryExpressionProvider
54
     */
55
    public function testPaginateTableFinder(callable $factory, PaginationResult $expected): void
56
    {
57
        $controller = new class(new ServerRequest()) extends Controller {
58
            public $Posts = null;
59
60
            public array $paginate = [
61
                'className' => Paginator::class,
62
            ];
63
        };
64
65
        $posts = $controller->fetchTable('Posts');
66
67
        /** @var mixed[] $options */
68
        $options = $factory($posts) + [
69
            'finder' => [
70
                'all' => [],
71
            ],
72
        ];
73
74
        $this->assertJsonEquals($expected, $controller->paginate('Posts', $options));
75
    }
76
77
    /**
78
     * @dataProvider valueProvider
79
     * @dataProvider queryExpressionProvider
80
     */
81
    public function testPaginateCakeQuery(callable $factory, PaginationResult $expected): void
82
    {
83
        $controller = new class(new ServerRequest()) extends Controller {
84
            public $Posts = null;
85
86
            public array $paginate = [
87
                'className' => Paginator::class,
88
            ];
89
        };
90
91
        $posts = $controller->fetchTable('Posts');
92
93
        /** @var mixed[] $options */
94
        $options = $factory($posts);
95
96
        $this->assertJsonEquals($expected, $controller->paginate($posts->find('all'), $options));
97
    }
98
99
    /**
100
     * @dataProvider valueProvider
101
     * @dataProvider queryExpressionProvider
102
     */
103
    public function testPaginateExtraSettings(callable $factory): void
104
    {
105
        $controller = new class(new ServerRequest()) extends Controller {
106
            public $Posts = null;
107
108
            public array $paginate = [
109
                'className' => Paginator::class,
110
            ];
111
        };
112
113
        $posts = $controller->fetchTable('Posts');
114
115
        /** @var mixed[] $options */
116
        $options = $factory($posts) + [
117
            'extraOption' => true,
118
        ];
119
120
        $this->expectWarningMessageMatches('/Extra keys found are: `extraOption`\./', function () use ($controller, $options) {
121
            $controller->paginate('Posts', $options);
122
        });
123
    }
124
125
    /**
126
     * @dataProvider valueProvider
127
     * @dataProvider queryExpressionProvider
128
     */
129
    public function testPaginateLampagerCakeQuery(callable $factory): void
130
    {
131
        $this->expectException(InvalidArgumentException::class);
132
        $this->expectExceptionMessage('Lampager\Cake\ORM\Query cannot be paginated by Lampager\Cake\Datasource\Paginator::paginate()');
133
134
        $controller = new class(new ServerRequest()) extends Controller {
135
            public $Posts = null;
136
137
            public array $paginate = [
138
                'className' => Paginator::class,
139
            ];
140
        };
141
142
        /** @var LampagerBehavior&Table $posts */
143
        $posts = $controller->fetchTable('Posts');
144
        $posts->addBehavior(LampagerBehavior::class);
145
146
        /** @var mixed[] $options */
147
        $options = $factory($posts);
148
        $query = $posts->lampager()->applyOptions($options);
149
        $controller->paginate($query);
150
    }
151
152
    public function testPaginateInvalidQuery(): void
153
    {
154
        $this->expectException(Exception::class);
155
        $this->expectExceptionMessage('No repository set for query.');
156
157
        $controller = new class(new ServerRequest()) extends Controller {
158
            public $Posts = null;
159
160
            public array $paginate = [
161
                'className' => Paginator::class,
162
            ];
163
        };
164
165
        /** @var MockObject&QueryInterface $query */
166
        $query = $this->getMockBuilder(QueryInterface::class)->getMock();
167
        $query->method('getRepository')->willReturn(null);
168
169
        $controller->paginate($query);
170
    }
171
172
    public static function valueProvider(): Generator
173
    {
174
        yield 'Ascending forward start inclusive' => [
175
            function () {
176
                return [
177
                    'forward' => true,
178
                    'seekable' => true,
179
                    'limit' => 3,
180
                    'order' => [
181
                        'modified' => 'asc',
182
                        'id' => 'asc',
183
                    ],
184
                ];
185
            },
186
            new PaginationResult(
187
                [
188
                    new Entity([
189
                        'id' => 1,
190
                        'modified' => new DateTime('2017-01-01 10:00:00'),
191
                    ]),
192
                    new Entity([
193
                        'id' => 3,
194
                        'modified' => new DateTime('2017-01-01 10:00:00'),
195
                    ]),
196
                    new Entity([
197
                        'id' => 5,
198
                        'modified' => new DateTime('2017-01-01 10:00:00'),
199
                    ]),
200
                ],
201
                [
202
                    'hasPrevious' => null,
203
                    'previousCursor' => null,
204
                    'hasNext' => true,
205
                    'nextCursor' => [
206
                        'Posts.id' => 2,
207
                        'Posts.modified' => new DateTime('2017-01-01 11:00:00'),
208
                    ],
209
                ]
210
            ),
211
        ];
212
213
        yield 'Ascending forward start exclusive' => [
214
            function () {
215
                return [
216
                    'forward' => true,
217
                    'seekable' => true,
218
                    'exclusive' => true,
219
                    'limit' => 3,
220
                    'order' => [
221
                        'modified' => 'asc',
222
                        'id' => 'asc',
223
                    ],
224
                ];
225
            },
226
            new PaginationResult(
227
                [
228
                    new Entity([
229
                        'id' => 1,
230
                        'modified' => new DateTime('2017-01-01 10:00:00'),
231
                    ]),
232
                    new Entity([
233
                        'id' => 3,
234
                        'modified' => new DateTime('2017-01-01 10:00:00'),
235
                    ]),
236
                    new Entity([
237
                        'id' => 5,
238
                        'modified' => new DateTime('2017-01-01 10:00:00'),
239
                    ]),
240
                ],
241
                [
242
                    'hasPrevious' => null,
243
                    'previousCursor' => null,
244
                    'hasNext' => true,
245
                    'nextCursor' => [
246
                        'Posts.id' => 5,
247
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
248
                    ],
249
                ]
250
            ),
251
        ];
252
253
        yield 'Ascending forward inclusive' => [
254
            function () {
255
                return [
256
                    'forward' => true,
257
                    'seekable' => true,
258
                    'limit' => 3,
259
                    'order' => [
260
                        'modified' => 'asc',
261
                        'id' => 'asc',
262
                    ],
263
                    'cursor' => [
264
                        'Posts.id' => 3,
265
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
266
                    ],
267
                ];
268
            },
269
            new PaginationResult(
270
                [
271
                    new Entity([
272
                        'id' => 3,
273
                        'modified' => new DateTime('2017-01-01 10:00:00'),
274
                    ]),
275
                    new Entity([
276
                        'id' => 5,
277
                        'modified' => new DateTime('2017-01-01 10:00:00'),
278
                    ]),
279
                    new Entity([
280
                        'id' => 2,
281
                        'modified' => new DateTime('2017-01-01 11:00:00'),
282
                    ]),
283
                ],
284
                [
285
                    'hasPrevious' => true,
286
                    'previousCursor' => [
287
                        'Posts.id' => 1,
288
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
289
                    ],
290
                    'hasNext' => true,
291
                    'nextCursor' => [
292
                        'Posts.id' => 4,
293
                        'Posts.modified' => new DateTime('2017-01-01 11:00:00'),
294
                    ],
295
                ]
296
            ),
297
        ];
298
299
        yield 'Ascending forward exclusive' => [
300
            function () {
301
                return [
302
                    'forward' => true,
303
                    'seekable' => true,
304
                    'exclusive' => true,
305
                    'limit' => 3,
306
                    'order' => [
307
                        'modified' => 'asc',
308
                        'id' => 'asc',
309
                    ],
310
                    'cursor' => [
311
                        'Posts.id' => 3,
312
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
313
                    ],
314
                ];
315
            },
316
            new PaginationResult(
317
                [
318
                    new Entity([
319
                        'id' => 5,
320
                        'modified' => new DateTime('2017-01-01 10:00:00'),
321
                    ]),
322
                    new Entity([
323
                        'id' => 2,
324
                        'modified' => new DateTime('2017-01-01 11:00:00'),
325
                    ]),
326
                    new Entity([
327
                        'id' => 4,
328
                        'modified' => new DateTime('2017-01-01 11:00:00'),
329
                    ]),
330
                ],
331
                [
332
                    'hasPrevious' => true,
333
                    'previousCursor' => [
334
                        'Posts.id' => 5,
335
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
336
                    ],
337
                    'hasNext' => false,
338
                    'nextCursor' => null,
339
                ]
340
            ),
341
        ];
342
343
        yield 'Ascending backward start inclusive' => [
344
            function () {
345
                return [
346
                    'backward' => true,
347
                    'seekable' => true,
348
                    'limit' => 3,
349
                    'order' => [
350
                        'modified' => 'asc',
351
                        'id' => 'asc',
352
                    ],
353
                ];
354
            },
355
            new PaginationResult(
356
                [
357
                    new Entity([
358
                        'id' => 5,
359
                        'modified' => new DateTime('2017-01-01 10:00:00'),
360
                    ]),
361
                    new Entity([
362
                        'id' => 2,
363
                        'modified' => new DateTime('2017-01-01 11:00:00'),
364
                    ]),
365
                    new Entity([
366
                        'id' => 4,
367
                        'modified' => new DateTime('2017-01-01 11:00:00'),
368
                    ]),
369
                ],
370
                [
371
                    'hasPrevious' => true,
372
                    'previousCursor' => [
373
                        'Posts.id' => 3,
374
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
375
                    ],
376
                    'hasNext' => null,
377
                    'nextCursor' => null,
378
                ]
379
            ),
380
        ];
381
382
        yield 'Ascending backward start exclusive' => [
383
            function () {
384
                return [
385
                    'backward' => true,
386
                    'seekable' => true,
387
                    'exclusive' => true,
388
                    'limit' => 3,
389
                    'order' => [
390
                        'modified' => 'asc',
391
                        'id' => 'asc',
392
                    ],
393
                ];
394
            },
395
            new PaginationResult(
396
                [
397
                    new Entity([
398
                        'id' => 5,
399
                        'modified' => new DateTime('2017-01-01 10:00:00'),
400
                    ]),
401
                    new Entity([
402
                        'id' => 2,
403
                        'modified' => new DateTime('2017-01-01 11:00:00'),
404
                    ]),
405
                    new Entity([
406
                        'id' => 4,
407
                        'modified' => new DateTime('2017-01-01 11:00:00'),
408
                    ]),
409
                ],
410
                [
411
                    'hasPrevious' => true,
412
                    'previousCursor' => [
413
                        'Posts.id' => 5,
414
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
415
                    ],
416
                    'hasNext' => null,
417
                    'nextCursor' => null,
418
                ]
419
            ),
420
        ];
421
422
        yield 'Ascending backward inclusive' => [
423
            function () {
424
                return [
425
                    'backward' => true,
426
                    'seekable' => true,
427
                    'limit' => 3,
428
                    'order' => [
429
                        'modified' => 'asc',
430
                        'id' => 'asc',
431
                    ],
432
                    'cursor' => [
433
                        'Posts.id' => 3,
434
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
435
                    ],
436
                ];
437
            },
438
            new PaginationResult(
439
                [
440
                    new Entity([
441
                        'id' => 1,
442
                        'modified' => new DateTime('2017-01-01 10:00:00'),
443
                    ]),
444
                    new Entity([
445
                        'id' => 3,
446
                        'modified' => new DateTime('2017-01-01 10:00:00'),
447
                    ]),
448
                ],
449
                [
450
                    'hasPrevious' => false,
451
                    'previousCursor' => null,
452
                    'hasNext' => true,
453
                    'nextCursor' => [
454
                        'Posts.id' => 5,
455
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
456
                    ],
457
                ]
458
            ),
459
        ];
460
461
        yield 'Ascending backward exclusive' => [
462
            function () {
463
                return [
464
                    'backward' => true,
465
                    'seekable' => true,
466
                    'exclusive' => true,
467
                    'limit' => 3,
468
                    'order' => [
469
                        'modified' => 'asc',
470
                        'id' => 'asc',
471
                    ],
472
                    'cursor' => [
473
                        'Posts.id' => 3,
474
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
475
                    ],
476
                ];
477
            },
478
            new PaginationResult(
479
                [
480
                    new Entity([
481
                        'id' => 1,
482
                        'modified' => new DateTime('2017-01-01 10:00:00'),
483
                    ]),
484
                ],
485
                [
486
                    'hasPrevious' => false,
487
                    'previousCursor' => null,
488
                    'hasNext' => true,
489
                    'nextCursor' => [
490
                        'Posts.id' => 1,
491
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
492
                    ],
493
                ]
494
            ),
495
        ];
496
497
        yield 'Descending forward start inclusive' => [
498
            function () {
499
                return [
500
                    'forward' => true,
501
                    'seekable' => true,
502
                    'limit' => 3,
503
                    'order' => [
504
                        'modified' => 'desc',
505
                        'id' => 'desc',
506
                    ],
507
                ];
508
            },
509
            new PaginationResult(
510
                [
511
                    new Entity([
512
                        'id' => 4,
513
                        'modified' => new DateTime('2017-01-01 11:00:00'),
514
                    ]),
515
                    new Entity([
516
                        'id' => 2,
517
                        'modified' => new DateTime('2017-01-01 11:00:00'),
518
                    ]),
519
                    new Entity([
520
                        'id' => 5,
521
                        'modified' => new DateTime('2017-01-01 10:00:00'),
522
                    ]),
523
                ],
524
                [
525
                    'hasPrevious' => null,
526
                    'previousCursor' => null,
527
                    'hasNext' => true,
528
                    'nextCursor' => [
529
                        'Posts.id' => 3,
530
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
531
                    ],
532
                ]
533
            ),
534
        ];
535
536
        yield 'Descending forward start exclusive' => [
537
            function () {
538
                return [
539
                    'forward' => true,
540
                    'seekable' => true,
541
                    'exclusive' => true,
542
                    'limit' => 3,
543
                    'order' => [
544
                        'modified' => 'desc',
545
                        'id' => 'desc',
546
                    ],
547
                ];
548
            },
549
            new PaginationResult(
550
                [
551
                    new Entity([
552
                        'id' => 4,
553
                        'modified' => new DateTime('2017-01-01 11:00:00'),
554
                    ]),
555
                    new Entity([
556
                        'id' => 2,
557
                        'modified' => new DateTime('2017-01-01 11:00:00'),
558
                    ]),
559
                    new Entity([
560
                        'id' => 5,
561
                        'modified' => new DateTime('2017-01-01 10:00:00'),
562
                    ]),
563
                ],
564
                [
565
                    'hasPrevious' => null,
566
                    'previousCursor' => null,
567
                    'hasNext' => true,
568
                    'nextCursor' => [
569
                        'Posts.id' => 5,
570
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
571
                    ],
572
                ]
573
            ),
574
        ];
575
576
        yield 'Descending forward inclusive' => [
577
            function () {
578
                return [
579
                    'forward' => true,
580
                    'seekable' => true,
581
                    'limit' => 3,
582
                    'order' => [
583
                        'modified' => 'desc',
584
                        'id' => 'desc',
585
                    ],
586
                    'cursor' => [
587
                        'Posts.id' => 3,
588
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
589
                    ],
590
                ];
591
            },
592
            new PaginationResult(
593
                [
594
                    new Entity([
595
                        'id' => 3,
596
                        'modified' => new DateTime('2017-01-01 10:00:00'),
597
                    ]),
598
                    new Entity([
599
                        'id' => 1,
600
                        'modified' => new DateTime('2017-01-01 10:00:00'),
601
                    ]),
602
                ],
603
                [
604
                    'hasPrevious' => true,
605
                    'previousCursor' => [
606
                        'Posts.id' => 5,
607
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
608
                    ],
609
                    'hasNext' => false,
610
                    'nextCursor' => null,
611
                ]
612
            ),
613
        ];
614
615
        yield 'Descending forward exclusive' => [
616
            function () {
617
                return [
618
                    'forward' => true,
619
                    'seekable' => true,
620
                    'exclusive' => true,
621
                    'limit' => 3,
622
                    'order' => [
623
                        'modified' => 'desc',
624
                        'id' => 'desc',
625
                    ],
626
                    'cursor' => [
627
                        'Posts.id' => 3,
628
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
629
                    ],
630
                ];
631
            },
632
            new PaginationResult(
633
                [
634
                    new Entity([
635
                        'id' => 1,
636
                        'modified' => new DateTime('2017-01-01 10:00:00'),
637
                    ]),
638
                ],
639
                [
640
                    'hasPrevious' => true,
641
                    'previousCursor' => [
642
                        'Posts.id' => 1,
643
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
644
                    ],
645
                    'hasNext' => false,
646
                    'nextCursor' => null,
647
                ]
648
            ),
649
        ];
650
651
        yield 'Descending backward start inclusive' => [
652
            function () {
653
                return [
654
                    'backward' => true,
655
                    'seekable' => true,
656
                    'limit' => 3,
657
                    'order' => [
658
                        'modified' => 'desc',
659
                        'id' => 'desc',
660
                    ],
661
                ];
662
            },
663
            new PaginationResult(
664
                [
665
                    new Entity([
666
                        'id' => 5,
667
                        'modified' => new DateTime('2017-01-01 10:00:00'),
668
                    ]),
669
                    new Entity([
670
                        'id' => 3,
671
                        'modified' => new DateTime('2017-01-01 10:00:00'),
672
                    ]),
673
                    new Entity([
674
                        'id' => 1,
675
                        'modified' => new DateTime('2017-01-01 10:00:00'),
676
                    ]),
677
                ],
678
                [
679
                    'hasPrevious' => true,
680
                    'previousCursor' => [
681
                        'Posts.id' => 2,
682
                        'Posts.modified' => new DateTime('2017-01-01 11:00:00'),
683
                    ],
684
                    'hasNext' => null,
685
                    'nextCursor' => null,
686
                ]
687
            ),
688
        ];
689
690
        yield 'Descending backward start exclusive' => [
691
            function () {
692
                return [
693
                    'backward' => true,
694
                    'seekable' => true,
695
                    'exclusive' => true,
696
                    'limit' => 3,
697
                    'order' => [
698
                        'modified' => 'desc',
699
                        'id' => 'desc',
700
                    ],
701
                ];
702
            },
703
            new PaginationResult(
704
                [
705
                    new Entity([
706
                        'id' => 5,
707
                        'modified' => new DateTime('2017-01-01 10:00:00'),
708
                    ]),
709
                    new Entity([
710
                        'id' => 3,
711
                        'modified' => new DateTime('2017-01-01 10:00:00'),
712
                    ]),
713
                    new Entity([
714
                        'id' => 1,
715
                        'modified' => new DateTime('2017-01-01 10:00:00'),
716
                    ]),
717
                ],
718
                [
719
                    'hasPrevious' => true,
720
                    'previousCursor' => [
721
                        'Posts.id' => 5,
722
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
723
                    ],
724
                    'hasNext' => null,
725
                    'nextCursor' => null,
726
                ]
727
            ),
728
        ];
729
730
        yield 'Descending backward inclusive' => [
731
            function () {
732
                return [
733
                    'backward' => true,
734
                    'seekable' => true,
735
                    'limit' => 3,
736
                    'order' => [
737
                        'modified' => 'desc',
738
                        'id' => 'desc',
739
                    ],
740
                    'cursor' => [
741
                        'Posts.id' => 3,
742
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
743
                    ],
744
                ];
745
            },
746
            new PaginationResult(
747
                [
748
                    new Entity([
749
                        'id' => 2,
750
                        'modified' => new DateTime('2017-01-01 11:00:00'),
751
                    ]),
752
                    new Entity([
753
                        'id' => 5,
754
                        'modified' => new DateTime('2017-01-01 10:00:00'),
755
                    ]),
756
                    new Entity([
757
                        'id' => 3,
758
                        'modified' => new DateTime('2017-01-01 10:00:00'),
759
                    ]),
760
                ],
761
                [
762
                    'hasPrevious' => true,
763
                    'previousCursor' => [
764
                        'Posts.id' => 4,
765
                        'Posts.modified' => new DateTime('2017-01-01 11:00:00'),
766
                    ],
767
                    'hasNext' => true,
768
                    'nextCursor' => [
769
                        'Posts.id' => 1,
770
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
771
                    ],
772
                ]
773
            ),
774
        ];
775
776
        yield 'Descending backward exclusive' => [
777
            function () {
778
                return [
779
                    'backward' => true,
780
                    'seekable' => true,
781
                    'exclusive' => true,
782
                    'limit' => 3,
783
                    'order' => [
784
                        'modified' => 'desc',
785
                        'id' => 'desc',
786
                    ],
787
                    'cursor' => [
788
                        'Posts.id' => 3,
789
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
790
                    ],
791
                ];
792
            },
793
            new PaginationResult(
794
                [
795
                    new Entity([
796
                        'id' => 4,
797
                        'modified' => new DateTime('2017-01-01 11:00:00'),
798
                    ]),
799
                    new Entity([
800
                        'id' => 2,
801
                        'modified' => new DateTime('2017-01-01 11:00:00'),
802
                    ]),
803
                    new Entity([
804
                        'id' => 5,
805
                        'modified' => new DateTime('2017-01-01 10:00:00'),
806
                    ]),
807
                ],
808
                [
809
                    'hasPrevious' => false,
810
                    'previousCursor' => null,
811
                    'hasNext' => true,
812
                    'nextCursor' => [
813
                        'Posts.id' => 5,
814
                        'Posts.modified' => new DateTime('2017-01-01 10:00:00'),
815
                    ],
816
                ]
817
            ),
818
        ];
819
    }
820
821
    public static function queryExpressionProvider(): Generator
822
    {
823
        yield 'Ascending forward start inclusive with QueryExpression' => [
824
            function () {
825
                return [
826
                    'forward' => true,
827
                    'seekable' => true,
828
                    'limit' => 3,
829
                    'order' => [
830
                        new OrderClauseExpression('modified', 'asc'),
831
                        new OrderClauseExpression('id', 'asc'),
832
                    ],
833
                ];
834
            },
835
            new PaginationResult(
836
                [
837
                    new Entity([
838
                        'id' => 1,
839
                        'modified' => new DateTime('2017-01-01 10:00:00'),
840
                    ]),
841
                    new Entity([
842
                        'id' => 3,
843
                        'modified' => new DateTime('2017-01-01 10:00:00'),
844
                    ]),
845
                    new Entity([
846
                        'id' => 5,
847
                        'modified' => new DateTime('2017-01-01 10:00:00'),
848
                    ]),
849
                ],
850
                [
851
                    'hasPrevious' => null,
852
                    'previousCursor' => null,
853
                    'hasNext' => true,
854
                    'nextCursor' => [
855
                        'id' => 2,
856
                        'modified' => new DateTime('2017-01-01 11:00:00'),
857
                    ],
858
                ]
859
            ),
860
        ];
861
862
        yield 'Ascending forward start exclusive with QueryExpression' => [
863
            function () {
864
                return [
865
                    'forward' => true,
866
                    'seekable' => true,
867
                    'exclusive' => true,
868
                    'limit' => 3,
869
                    'order' => [
870
                        new OrderClauseExpression('modified', 'asc'),
871
                        new OrderClauseExpression('id', 'asc'),
872
                    ],
873
                ];
874
            },
875
            new PaginationResult(
876
                [
877
                    new Entity([
878
                        'id' => 1,
879
                        'modified' => new DateTime('2017-01-01 10:00:00'),
880
                    ]),
881
                    new Entity([
882
                        'id' => 3,
883
                        'modified' => new DateTime('2017-01-01 10:00:00'),
884
                    ]),
885
                    new Entity([
886
                        'id' => 5,
887
                        'modified' => new DateTime('2017-01-01 10:00:00'),
888
                    ]),
889
                ],
890
                [
891
                    'hasPrevious' => null,
892
                    'previousCursor' => null,
893
                    'hasNext' => true,
894
                    'nextCursor' => [
895
                        'id' => 5,
896
                        'modified' => new DateTime('2017-01-01 10:00:00'),
897
                    ],
898
                ]
899
            ),
900
        ];
901
902
        yield 'Ascending forward inclusive with QueryExpression' => [
903
            function () {
904
                return [
905
                    'forward' => true,
906
                    'seekable' => true,
907
                    'limit' => 3,
908
                    'order' => [
909
                        new OrderClauseExpression('modified', 'asc'),
910
                        new OrderClauseExpression('id', 'asc'),
911
                    ],
912
                    'cursor' => [
913
                        'id' => 3,
914
                        'modified' => new DateTime('2017-01-01 10:00:00'),
915
                    ],
916
                ];
917
            },
918
            new PaginationResult(
919
                [
920
                    new Entity([
921
                        'id' => 3,
922
                        'modified' => new DateTime('2017-01-01 10:00:00'),
923
                    ]),
924
                    new Entity([
925
                        'id' => 5,
926
                        'modified' => new DateTime('2017-01-01 10:00:00'),
927
                    ]),
928
                    new Entity([
929
                        'id' => 2,
930
                        'modified' => new DateTime('2017-01-01 11:00:00'),
931
                    ]),
932
                ],
933
                [
934
                    'hasPrevious' => true,
935
                    'previousCursor' => [
936
                        'id' => 1,
937
                        'modified' => new DateTime('2017-01-01 10:00:00'),
938
                    ],
939
                    'hasNext' => true,
940
                    'nextCursor' => [
941
                        'id' => 4,
942
                        'modified' => new DateTime('2017-01-01 11:00:00'),
943
                    ],
944
                ]
945
            ),
946
        ];
947
948
        yield 'Ascending forward exclusive with QueryExpression' => [
949
            function () {
950
                return [
951
                    'forward' => true,
952
                    'seekable' => true,
953
                    'exclusive' => true,
954
                    'limit' => 3,
955
                    'order' => [
956
                        new OrderClauseExpression('modified', 'asc'),
957
                        new OrderClauseExpression('id', 'asc'),
958
                    ],
959
                    'cursor' => [
960
                        'id' => 3,
961
                        'modified' => new DateTime('2017-01-01 10:00:00'),
962
                    ],
963
                ];
964
            },
965
            new PaginationResult(
966
                [
967
                    new Entity([
968
                        'id' => 5,
969
                        'modified' => new DateTime('2017-01-01 10:00:00'),
970
                    ]),
971
                    new Entity([
972
                        'id' => 2,
973
                        'modified' => new DateTime('2017-01-01 11:00:00'),
974
                    ]),
975
                    new Entity([
976
                        'id' => 4,
977
                        'modified' => new DateTime('2017-01-01 11:00:00'),
978
                    ]),
979
                ],
980
                [
981
                    'hasPrevious' => true,
982
                    'previousCursor' => [
983
                        'id' => 5,
984
                        'modified' => new DateTime('2017-01-01 10:00:00'),
985
                    ],
986
                    'hasNext' => false,
987
                    'nextCursor' => null,
988
                ]
989
            ),
990
        ];
991
992
        yield 'Ascending backward start inclusive with QueryExpression' => [
993
            function () {
994
                return [
995
                    'backward' => true,
996
                    'seekable' => true,
997
                    'limit' => 3,
998
                    'order' => [
999
                        new OrderClauseExpression('modified', 'asc'),
1000
                        new OrderClauseExpression('id', 'asc'),
1001
                    ],
1002
                ];
1003
            },
1004
            new PaginationResult(
1005
                [
1006
                    new Entity([
1007
                        'id' => 5,
1008
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1009
                    ]),
1010
                    new Entity([
1011
                        'id' => 2,
1012
                        'modified' => new DateTime('2017-01-01 11:00:00'),
1013
                    ]),
1014
                    new Entity([
1015
                        'id' => 4,
1016
                        'modified' => new DateTime('2017-01-01 11:00:00'),
1017
                    ]),
1018
                ],
1019
                [
1020
                    'hasPrevious' => true,
1021
                    'previousCursor' => [
1022
                        'id' => 3,
1023
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1024
                    ],
1025
                    'hasNext' => null,
1026
                    'nextCursor' => null,
1027
                ]
1028
            ),
1029
        ];
1030
1031
        yield 'Ascending backward start exclusive with QueryExpression' => [
1032
            function () {
1033
                return [
1034
                    'backward' => true,
1035
                    'seekable' => true,
1036
                    'exclusive' => true,
1037
                    'limit' => 3,
1038
                    'order' => [
1039
                        new OrderClauseExpression('modified', 'asc'),
1040
                        new OrderClauseExpression('id', 'asc'),
1041
                    ],
1042
                ];
1043
            },
1044
            new PaginationResult(
1045
                [
1046
                    new Entity([
1047
                        'id' => 5,
1048
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1049
                    ]),
1050
                    new Entity([
1051
                        'id' => 2,
1052
                        'modified' => new DateTime('2017-01-01 11:00:00'),
1053
                    ]),
1054
                    new Entity([
1055
                        'id' => 4,
1056
                        'modified' => new DateTime('2017-01-01 11:00:00'),
1057
                    ]),
1058
                ],
1059
                [
1060
                    'hasPrevious' => true,
1061
                    'previousCursor' => [
1062
                        'id' => 5,
1063
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1064
                    ],
1065
                    'hasNext' => null,
1066
                    'nextCursor' => null,
1067
                ]
1068
            ),
1069
        ];
1070
1071
        yield 'Ascending backward inclusive with QueryExpression' => [
1072
            function () {
1073
                return [
1074
                    'backward' => true,
1075
                    'seekable' => true,
1076
                    'limit' => 3,
1077
                    'order' => [
1078
                        new OrderClauseExpression('modified', 'asc'),
1079
                        new OrderClauseExpression('id', 'asc'),
1080
                    ],
1081
                    'cursor' => [
1082
                        'id' => 3,
1083
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1084
                    ],
1085
                ];
1086
            },
1087
            new PaginationResult(
1088
                [
1089
                    new Entity([
1090
                        'id' => 1,
1091
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1092
                    ]),
1093
                    new Entity([
1094
                        'id' => 3,
1095
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1096
                    ]),
1097
                ],
1098
                [
1099
                    'hasPrevious' => false,
1100
                    'previousCursor' => null,
1101
                    'hasNext' => true,
1102
                    'nextCursor' => [
1103
                        'id' => 5,
1104
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1105
                    ],
1106
                ]
1107
            ),
1108
        ];
1109
1110
        yield 'Ascending backward exclusive with QueryExpression' => [
1111
            function () {
1112
                return [
1113
                    'backward' => true,
1114
                    'seekable' => true,
1115
                    'exclusive' => true,
1116
                    'limit' => 3,
1117
                    'order' => [
1118
                        new OrderClauseExpression('modified', 'asc'),
1119
                        new OrderClauseExpression('id', 'asc'),
1120
                    ],
1121
                    'cursor' => [
1122
                        'id' => 3,
1123
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1124
                    ],
1125
                ];
1126
            },
1127
            new PaginationResult(
1128
                [
1129
                    new Entity([
1130
                        'id' => 1,
1131
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1132
                    ]),
1133
                ],
1134
                [
1135
                    'hasPrevious' => false,
1136
                    'previousCursor' => null,
1137
                    'hasNext' => true,
1138
                    'nextCursor' => [
1139
                        'id' => 1,
1140
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1141
                    ],
1142
                ]
1143
            ),
1144
        ];
1145
1146
        yield 'Descending forward start inclusive with QueryExpression' => [
1147
            function () {
1148
                return [
1149
                    'forward' => true,
1150
                    'seekable' => true,
1151
                    'limit' => 3,
1152
                    'order' => [
1153
                        new OrderClauseExpression('modified', 'desc'),
1154
                        new OrderClauseExpression('id', 'desc'),
1155
                    ],
1156
                ];
1157
            },
1158
            new PaginationResult(
1159
                [
1160
                    new Entity([
1161
                        'id' => 4,
1162
                        'modified' => new DateTime('2017-01-01 11:00:00'),
1163
                    ]),
1164
                    new Entity([
1165
                        'id' => 2,
1166
                        'modified' => new DateTime('2017-01-01 11:00:00'),
1167
                    ]),
1168
                    new Entity([
1169
                        'id' => 5,
1170
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1171
                    ]),
1172
                ],
1173
                [
1174
                    'hasPrevious' => null,
1175
                    'previousCursor' => null,
1176
                    'hasNext' => true,
1177
                    'nextCursor' => [
1178
                        'id' => 3,
1179
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1180
                    ],
1181
                ]
1182
            ),
1183
        ];
1184
1185
        yield 'Descending forward start exclusive with QueryExpression' => [
1186
            function () {
1187
                return [
1188
                    'forward' => true,
1189
                    'seekable' => true,
1190
                    'exclusive' => true,
1191
                    'limit' => 3,
1192
                    'order' => [
1193
                        new OrderClauseExpression('modified', 'desc'),
1194
                        new OrderClauseExpression('id', 'desc'),
1195
                    ],
1196
                ];
1197
            },
1198
            new PaginationResult(
1199
                [
1200
                    new Entity([
1201
                        'id' => 4,
1202
                        'modified' => new DateTime('2017-01-01 11:00:00'),
1203
                    ]),
1204
                    new Entity([
1205
                        'id' => 2,
1206
                        'modified' => new DateTime('2017-01-01 11:00:00'),
1207
                    ]),
1208
                    new Entity([
1209
                        'id' => 5,
1210
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1211
                    ]),
1212
                ],
1213
                [
1214
                    'hasPrevious' => null,
1215
                    'previousCursor' => null,
1216
                    'hasNext' => true,
1217
                    'nextCursor' => [
1218
                        'id' => 5,
1219
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1220
                    ],
1221
                ]
1222
            ),
1223
        ];
1224
1225
        yield 'Descending forward inclusive with QueryExpression' => [
1226
            function () {
1227
                return [
1228
                    'forward' => true,
1229
                    'seekable' => true,
1230
                    'limit' => 3,
1231
                    'order' => [
1232
                        new OrderClauseExpression('modified', 'desc'),
1233
                        new OrderClauseExpression('id', 'desc'),
1234
                    ],
1235
                    'cursor' => [
1236
                        'id' => 3,
1237
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1238
                    ],
1239
                ];
1240
            },
1241
            new PaginationResult(
1242
                [
1243
                    new Entity([
1244
                        'id' => 3,
1245
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1246
                    ]),
1247
                    new Entity([
1248
                        'id' => 1,
1249
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1250
                    ]),
1251
                ],
1252
                [
1253
                    'hasPrevious' => true,
1254
                    'previousCursor' => [
1255
                        'id' => 5,
1256
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1257
                    ],
1258
                    'hasNext' => false,
1259
                    'nextCursor' => null,
1260
                ]
1261
            ),
1262
        ];
1263
1264
        yield 'Descending forward exclusive with QueryExpression' => [
1265
            function () {
1266
                return [
1267
                    'forward' => true,
1268
                    'seekable' => true,
1269
                    'exclusive' => true,
1270
                    'limit' => 3,
1271
                    'order' => [
1272
                        new OrderClauseExpression('modified', 'desc'),
1273
                        new OrderClauseExpression('id', 'desc'),
1274
                    ],
1275
                    'cursor' => [
1276
                        'id' => 3,
1277
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1278
                    ],
1279
                ];
1280
            },
1281
            new PaginationResult(
1282
                [
1283
                    new Entity([
1284
                        'id' => 1,
1285
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1286
                    ]),
1287
                ],
1288
                [
1289
                    'hasPrevious' => true,
1290
                    'previousCursor' => [
1291
                        'id' => 1,
1292
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1293
                    ],
1294
                    'hasNext' => false,
1295
                    'nextCursor' => null,
1296
                ]
1297
            ),
1298
        ];
1299
1300
        yield 'Descending backward start inclusive with QueryExpression' => [
1301
            function () {
1302
                return [
1303
                    'backward' => true,
1304
                    'seekable' => true,
1305
                    'limit' => 3,
1306
                    'order' => [
1307
                        new OrderClauseExpression('modified', 'desc'),
1308
                        new OrderClauseExpression('id', 'desc'),
1309
                    ],
1310
                ];
1311
            },
1312
            new PaginationResult(
1313
                [
1314
                    new Entity([
1315
                        'id' => 5,
1316
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1317
                    ]),
1318
                    new Entity([
1319
                        'id' => 3,
1320
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1321
                    ]),
1322
                    new Entity([
1323
                        'id' => 1,
1324
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1325
                    ]),
1326
                ],
1327
                [
1328
                    'hasPrevious' => true,
1329
                    'previousCursor' => [
1330
                        'id' => 2,
1331
                        'modified' => new DateTime('2017-01-01 11:00:00'),
1332
                    ],
1333
                    'hasNext' => null,
1334
                    'nextCursor' => null,
1335
                ]
1336
            ),
1337
        ];
1338
1339
        yield 'Descending backward start exclusive with QueryExpression' => [
1340
            function () {
1341
                return [
1342
                    'backward' => true,
1343
                    'seekable' => true,
1344
                    'exclusive' => true,
1345
                    'limit' => 3,
1346
                    'order' => [
1347
                        new OrderClauseExpression('modified', 'desc'),
1348
                        new OrderClauseExpression('id', 'desc'),
1349
                    ],
1350
                ];
1351
            },
1352
            new PaginationResult(
1353
                [
1354
                    new Entity([
1355
                        'id' => 5,
1356
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1357
                    ]),
1358
                    new Entity([
1359
                        'id' => 3,
1360
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1361
                    ]),
1362
                    new Entity([
1363
                        'id' => 1,
1364
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1365
                    ]),
1366
                ],
1367
                [
1368
                    'hasPrevious' => true,
1369
                    'previousCursor' => [
1370
                        'id' => 5,
1371
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1372
                    ],
1373
                    'hasNext' => null,
1374
                    'nextCursor' => null,
1375
                ]
1376
            ),
1377
        ];
1378
1379
        yield 'Descending backward inclusive with QueryExpression' => [
1380
            function () {
1381
                return [
1382
                    'backward' => true,
1383
                    'seekable' => true,
1384
                    'limit' => 3,
1385
                    'order' => [
1386
                        new OrderClauseExpression('modified', 'desc'),
1387
                        new OrderClauseExpression('id', 'desc'),
1388
                    ],
1389
                    'cursor' => [
1390
                        'id' => 3,
1391
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1392
                    ],
1393
                ];
1394
            },
1395
            new PaginationResult(
1396
                [
1397
                    new Entity([
1398
                        'id' => 2,
1399
                        'modified' => new DateTime('2017-01-01 11:00:00'),
1400
                    ]),
1401
                    new Entity([
1402
                        'id' => 5,
1403
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1404
                    ]),
1405
                    new Entity([
1406
                        'id' => 3,
1407
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1408
                    ]),
1409
                ],
1410
                [
1411
                    'hasPrevious' => true,
1412
                    'previousCursor' => [
1413
                        'id' => 4,
1414
                        'modified' => new DateTime('2017-01-01 11:00:00'),
1415
                    ],
1416
                    'hasNext' => true,
1417
                    'nextCursor' => [
1418
                        'id' => 1,
1419
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1420
                    ],
1421
                ]
1422
            ),
1423
        ];
1424
1425
        yield 'Descending backward exclusive with QueryExpression' => [
1426
            function () {
1427
                return [
1428
                    'backward' => true,
1429
                    'seekable' => true,
1430
                    'exclusive' => true,
1431
                    'limit' => 3,
1432
                    'order' => [
1433
                        new OrderClauseExpression('modified', 'desc'),
1434
                        new OrderClauseExpression('id', 'desc'),
1435
                    ],
1436
                    'cursor' => [
1437
                        'id' => 3,
1438
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1439
                    ],
1440
                ];
1441
            },
1442
            new PaginationResult(
1443
                [
1444
                    new Entity([
1445
                        'id' => 4,
1446
                        'modified' => new DateTime('2017-01-01 11:00:00'),
1447
                    ]),
1448
                    new Entity([
1449
                        'id' => 2,
1450
                        'modified' => new DateTime('2017-01-01 11:00:00'),
1451
                    ]),
1452
                    new Entity([
1453
                        'id' => 5,
1454
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1455
                    ]),
1456
                ],
1457
                [
1458
                    'hasPrevious' => false,
1459
                    'previousCursor' => null,
1460
                    'hasNext' => true,
1461
                    'nextCursor' => [
1462
                        'id' => 5,
1463
                        'modified' => new DateTime('2017-01-01 10:00:00'),
1464
                    ],
1465
                ]
1466
            ),
1467
        ];
1468
    }
1469
}
1470