|
5 | 5 | use Carbon\Carbon; |
6 | 6 | use Illuminate\Database\Eloquent\Collection as EloquentCollection; |
7 | 7 | use Illuminate\Database\Eloquent\ModelNotFoundException; |
| 8 | +use Illuminate\Support\Facades\DB; |
| 9 | +use Illuminate\Support\LazyCollection; |
8 | 10 | use Illuminate\Support\Str; |
9 | 11 | use PDPhilip\Elasticsearch\Connection; |
10 | 12 | use PDPhilip\Elasticsearch\Data\ModelMeta; |
|
578 | 580 | expect($names)->toHaveCount(15000); |
579 | 581 | }); |
580 | 582 |
|
| 583 | +it('returns a chunkable lazy collection from cursor', function () { |
| 584 | + User::insert([ |
| 585 | + ['name' => 'User 1'], |
| 586 | + ['name' => 'User 2'], |
| 587 | + ['name' => 'User 3'], |
| 588 | + ]); |
| 589 | + |
| 590 | + $cursor = User::query()->orderBy('name.keyword')->cursor(); |
| 591 | + |
| 592 | + expect($cursor)->toBeInstanceOf(LazyCollection::class); |
| 593 | + |
| 594 | + $chunkSizes = $cursor->chunk(2)->map(fn ($chunk) => $chunk->count())->all(); |
| 595 | + expect($chunkSizes)->toBe([2, 1]); |
| 596 | +}); |
| 597 | + |
| 598 | +it('cursors on a connection that has not run a query yet', function () { |
| 599 | + User::insert([ |
| 600 | + ['name' => 'User 1'], |
| 601 | + ['name' => 'User 2'], |
| 602 | + ['name' => 'User 3'], |
| 603 | + ]); |
| 604 | + |
| 605 | + // A scroll populates no raw response, so a cursor that is the first query |
| 606 | + // on its connection has no earlier select or insert to inherit one from. |
| 607 | + DB::purge('elasticsearch'); |
| 608 | + |
| 609 | + $names = User::query()->orderBy('name.keyword')->cursor()->pluck('name')->all(); |
| 610 | + |
| 611 | + expect($names)->toBe(['User 1', 'User 2', 'User 3']); |
| 612 | +}); |
| 613 | + |
| 614 | +it('keeps the cursor lazy, hydrating only what is consumed', function () { |
| 615 | + User::insert(array_map(fn ($i) => ['name' => "User {$i}"], range(1, 10))); |
| 616 | + |
| 617 | + $hydrated = 0; |
| 618 | + User::retrieved(function () use (&$hydrated) { |
| 619 | + $hydrated++; |
| 620 | + }); |
| 621 | + |
| 622 | + $cursor = User::query()->orderBy('name.keyword')->cursor(); |
| 623 | + |
| 624 | + // Building the collection must not touch the cluster. |
| 625 | + expect($hydrated)->toBe(0); |
| 626 | + |
| 627 | + $taken = $cursor->take(3)->all(); |
| 628 | + |
| 629 | + // Three, not ten - an eagerly materialised collection would fail here while |
| 630 | + // every other assertion about cursor() carried on passing. |
| 631 | + expect($taken)->toHaveCount(3) |
| 632 | + ->and($hydrated)->toBe(3); |
| 633 | +}); |
| 634 | + |
| 635 | +it('re-runs the scroll when the cursor is iterated twice', function () { |
| 636 | + User::insert([ |
| 637 | + ['name' => 'User 1'], |
| 638 | + ['name' => 'User 2'], |
| 639 | + ['name' => 'User 3'], |
| 640 | + ]); |
| 641 | + |
| 642 | + $cursor = User::query()->orderBy('name.keyword')->cursor(); |
| 643 | + |
| 644 | + // A bare generator throws "Cannot rewind a generator" on the second pass. |
| 645 | + $first = $cursor->pluck('name')->all(); |
| 646 | + $second = $cursor->pluck('name')->all(); |
| 647 | + |
| 648 | + expect($first)->toBe(['User 1', 'User 2', 'User 3']) |
| 649 | + ->and($second)->toBe($first); |
| 650 | +}); |
| 651 | + |
581 | 652 | it('tests truncate model', function () { |
582 | 653 | User::create(['name' => 'John Doe']); |
583 | 654 |
|
|
0 commit comments