Skip to content

Commit

Permalink
Add throttle method to LazyCollection
Browse files Browse the repository at this point in the history
  • Loading branch information
JosephSilber committed Apr 14, 2024
1 parent 48246da commit aadf9b0
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 0 deletions.
50 changes: 50 additions & 0 deletions src/Illuminate/Collections/LazyCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -1570,6 +1570,28 @@ public function tapEach(callable $callback)
});
}

/**
* Throttle the values, releasing them at most once per the given seconds.
*
* @return static<TKey, TValue>
*/
public function throttle(float $seconds)
{
return new static(function () use ($seconds) {
$microseconds = $seconds * 1_000_000;

foreach ($this as $key => $value) {
$fetchedAt = $this->preciseNow();

yield $key => $value;

$sleep = $microseconds - ($this->preciseNow() - $fetchedAt);

$this->usleep((int) $sleep);
}
});
}

/**
* Flatten a multi-dimensional associative array with dots.
*
Expand Down Expand Up @@ -1781,4 +1803,32 @@ protected function now()
? Carbon::now()->timestamp
: time();
}

/**
* Get the precise current time.
*
* @return float
*/
protected function preciseNow()
{
return class_exists(Carbon::class)
? Carbon::now()->getPreciseTimestamp()
: microtime(true) * 1_000_000;
}

/**
* Sleep for the given amount of microseconds.
*
* @return void
*/
protected function usleep(int $microseconds)
{
if ($microseconds <= 0) {
return;
}

class_exists(Sleep::class)
? Sleep::usleep($microseconds)
: usleep($microseconds);
}
}
20 changes: 20 additions & 0 deletions tests/Support/SupportLazyCollectionIsLazyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Illuminate\Support\ItemNotFoundException;
use Illuminate\Support\LazyCollection;
use Illuminate\Support\MultipleItemsFoundException;
use Illuminate\Support\Sleep;
use Mockery as m;
use PHPUnit\Framework\TestCase;
use stdClass;
Expand Down Expand Up @@ -1370,6 +1371,25 @@ public function testTapEachIsLazy()
});
}

public function testThrottleIsLazy()
{
Sleep::fake();

$this->assertDoesNotEnumerate(function ($collection) {
$collection->throttle(10);
});

$this->assertEnumerates(5, function ($collection) {
$collection->throttle(10)->take(5)->all();
});

$this->assertEnumeratesOnce(function ($collection) {
$collection->throttle(10)->all();
});

Sleep::fake(false);
}

public function testTimesIsLazy()
{
$data = LazyCollection::times(INF);
Expand Down
55 changes: 55 additions & 0 deletions tests/Support/SupportLazyCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

namespace Illuminate\Tests\Support;

use Carbon\CarbonInterval as Duration;
use Illuminate\Foundation\Testing\Wormhole;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\LazyCollection;
use Illuminate\Support\Sleep;
use InvalidArgumentException;
use Mockery as m;
use PHPUnit\Framework\TestCase;
Expand Down Expand Up @@ -223,6 +226,58 @@ public function testTapEach()
$this->assertSame([1, 2, 3, 4, 5], $tapped);
}

public function testThrottle()
{
Sleep::fake();

$data = LazyCollection::times(3)
->throttle(2)
->all();

Sleep::assertSlept(function (Duration $duration) {
$this->assertEqualsWithDelta(
2_000_000, $duration->totalMicroseconds, 1_000
);

return true;
}, times: 3);

$this->assertSame([1, 2, 3], $data);

Sleep::fake(false);
}

public function testThrottleAccountsForTimePassed()
{
Sleep::fake();
Carbon::setTestNow(now());

$data = LazyCollection::times(3)
->throttle(3)
->tapEach(function ($value, $index) {
if ($index == 1) {
// Travel in time...
(new Wormhole(1))->second();
}
})
->all();

Sleep::assertSlept(function (Duration $duration, int $index) {
$expectation = $index == 1 ? 2_000_000 : 3_000_000;

$this->assertEqualsWithDelta(
$expectation, $duration->totalMicroseconds, 1_000
);

return true;
}, times: 3);

$this->assertSame([1, 2, 3], $data);

Sleep::fake(false);
Carbon::setTestNow();
}

public function testUniqueDoubleEnumeration()
{
$data = LazyCollection::times(2)->unique();
Expand Down

0 comments on commit aadf9b0

Please sign in to comment.