PaginatorTest.php$3 ➔ testPaginateExtraSettings()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

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