-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This can be used to page through an iterable of entity IDs without having to load it into memory all at once, as an alternative to: new InMemoryEntityIdPager( ...$iterable )
- Loading branch information
1 parent
fceb49c
commit ccf7e7a
Showing
3 changed files
with
153 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<?php | ||
|
||
namespace Wikibase\DataModel\Services\EntityId; | ||
|
||
use ArrayIterator; | ||
use Iterator; | ||
use IteratorIterator; | ||
use Wikibase\DataModel\Entity\EntityId; | ||
|
||
/** | ||
* An entity ID pager that wraps an iterable and traverses it once. | ||
* It is not seekable or rewindable. | ||
* | ||
* @since 5.3 | ||
*/ | ||
class IterableEntityIdPager implements EntityIdPager { | ||
|
||
/** @var Iterator */ | ||
private $iterator; | ||
|
||
/** | ||
* @param iterable<EntityId> $iterable | ||
*/ | ||
public function __construct( iterable $iterable ) { | ||
if ( $iterable instanceof Iterator ) { | ||
$this->iterator = $iterable; | ||
} elseif ( is_array( $iterable ) ) { | ||
$this->iterator = new ArrayIterator( $iterable ); | ||
} else { | ||
$this->iterator = new IteratorIterator( $iterable ); | ||
} | ||
$this->iterator->rewind(); | ||
} | ||
|
||
/** | ||
* @see EntityIdPager::fetchIds | ||
* | ||
* @param int $limit | ||
* | ||
* @return EntityId[] | ||
*/ | ||
public function fetchIds( $limit ) { | ||
$ids = []; | ||
while ( $limit-- > 0 && $this->iterator->valid() ) { | ||
$ids[] = $this->iterator->current(); | ||
$this->iterator->next(); | ||
} | ||
return $ids; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
<?php | ||
|
||
namespace Wikibase\DataModel\Services\Tests\EntityId; | ||
|
||
use ArrayIterator; | ||
use IteratorAggregate; | ||
use PHPUnit\Framework\TestCase; | ||
use Wikibase\DataModel\Services\EntityId\IterableEntityIdPager; | ||
|
||
/** | ||
* Note: this test has the pager iterate through numbers, not entity IDs. | ||
* It simplifies the test, and the pager doesn’t care. | ||
* | ||
* @covers \Wikibase\DataModel\Services\EntityId\IterableEntityIdPager | ||
* | ||
* @license GPL-2.0-or-later | ||
*/ | ||
class IterableEntityIdPagerTest extends TestCase { | ||
|
||
private const ONE_THROUGH_TEN = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; | ||
|
||
private function yieldOneThroughTenIndividually() { | ||
foreach ( self::ONE_THROUGH_TEN as $number ) { | ||
yield $number; | ||
} | ||
} | ||
|
||
private function yieldOneThroughTenAsYieldFrom() { | ||
yield from self::ONE_THROUGH_TEN; | ||
} | ||
|
||
/** Various iterables which all yield the numbers one through ten (both inclusive). */ | ||
public function provideIterables() { | ||
yield 'array' => [ self::ONE_THROUGH_TEN ]; | ||
yield 'ArrayIterator' => [ new ArrayIterator( self::ONE_THROUGH_TEN ) ]; | ||
yield 'generator I' => [ $this->yieldOneThroughTenIndividually() ]; | ||
yield 'generator II' => [ $this->yieldOneThroughTenAsYieldFrom() ]; | ||
$aggregate = $this->createMock( IteratorAggregate::class ); | ||
$aggregate->method( 'getIterator' )->willReturn( new ArrayIterator( self::ONE_THROUGH_TEN ) ); | ||
yield 'IteratorAggregate' => [ $aggregate ]; | ||
} | ||
|
||
public function providePagers() { | ||
foreach ( $this->provideIterables() as $key => $iterable ) { | ||
yield $key => [ new IterableEntityIdPager( $iterable[0] ) ]; | ||
} | ||
} | ||
|
||
/** @dataProvider providePagers */ | ||
public function testOneBatchLimit10( IterableEntityIdPager $pager ) { | ||
$this->assertSame( self::ONE_THROUGH_TEN, $pager->fetchIds( 10 ) ); | ||
$this->assertSame( [], $pager->fetchIds( 1 ) ); | ||
$this->assertSame( [], $pager->fetchIds( 10 ) ); | ||
} | ||
|
||
/** @dataProvider providePagers */ | ||
public function testOneBatchLimit100( IterableEntityIdPager $pager ) { | ||
$this->assertSame( self::ONE_THROUGH_TEN, $pager->fetchIds( 100 ) ); | ||
$this->assertSame( [], $pager->fetchIds( 1 ) ); | ||
$this->assertSame( [], $pager->fetchIds( 10 ) ); | ||
} | ||
|
||
/** @dataProvider providePagers */ | ||
public function testTwoBatchesLimits5And5( IterableEntityIdPager $pager ) { | ||
$this->assertSame( [ 1, 2, 3, 4, 5 ], $pager->fetchIds( 5 ) ); | ||
$this->assertSame( [ 6, 7, 8, 9, 10 ], $pager->fetchIds( 5 ) ); | ||
$this->assertSame( [], $pager->fetchIds( 5 ) ); | ||
$this->assertSame( [], $pager->fetchIds( 1 ) ); | ||
$this->assertSame( [], $pager->fetchIds( 0 ) ); | ||
} | ||
|
||
/** @dataProvider providePagers */ | ||
public function testThreeBatchesLimits0And5And5( IterableEntityIdPager $pager ) { | ||
$this->assertSame( [], $pager->fetchIds( 0 ) ); | ||
$this->assertSame( [ 1, 2, 3, 4, 5 ], $pager->fetchIds( 5 ) ); | ||
$this->assertSame( [ 6, 7, 8, 9, 10 ], $pager->fetchIds( 5 ) ); | ||
$this->assertSame( [], $pager->fetchIds( 5 ) ); | ||
$this->assertSame( [], $pager->fetchIds( 1 ) ); | ||
$this->assertSame( [], $pager->fetchIds( 0 ) ); | ||
} | ||
|
||
/** @dataProvider providePagers */ | ||
public function testFourBatchesLimits1And2And3And4( IterableEntityIdPager $pager ) { | ||
$this->assertSame( [ 1 ], $pager->fetchIds( 1 ) ); | ||
$this->assertSame( [ 2, 3 ], $pager->fetchIds( 2 ) ); | ||
$this->assertSame( [ 4, 5, 6 ], $pager->fetchIds( 3 ) ); | ||
$this->assertSame( [ 7, 8, 9, 10 ], $pager->fetchIds( 4 ) ); | ||
$this->assertSame( [], $pager->fetchIds( 5 ) ); | ||
} | ||
|
||
/** @dataProvider providePagers */ | ||
public function testTenBatchesEachLimit1( IterableEntityIdPager $pager ) { | ||
foreach ( self::ONE_THROUGH_TEN as $i ) { | ||
$this->assertSame( [ $i ], $pager->fetchIds( 1 ) ); | ||
} | ||
$this->assertSame( [], $pager->fetchIds( 1 ) ); | ||
} | ||
|
||
} |