Skip to content

Commit

Permalink
Fixes missing lazy() and lazyById() on BelongsToMany and HasManyT…
Browse files Browse the repository at this point in the history
…hrough relation query builder.

Signed-off-by: Mior Muhammad Zaki <[email protected]>
  • Loading branch information
crynobone committed Mar 26, 2021
1 parent f75e510 commit e16140f
Show file tree
Hide file tree
Showing 5 changed files with 278 additions and 7 deletions.
58 changes: 51 additions & 7 deletions src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -865,9 +865,7 @@ public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'p
*/
public function chunk($count, callable $callback)
{
$this->query->addSelect($this->shouldSelect());

return $this->query->chunk($count, function ($results, $page) use ($callback) {
return $this->prepareQueryBuilder()->chunk($count, function ($results, $page) use ($callback) {
$this->hydratePivotRelation($results->all());

return $callback($results, $page);
Expand All @@ -885,7 +883,7 @@ public function chunk($count, callable $callback)
*/
public function chunkById($count, callable $callback, $column = null, $alias = null)
{
$this->query->addSelect($this->shouldSelect());
$this->prepareQueryBuilder();

$column = $column ?? $this->getRelated()->qualifyColumn(
$this->getRelatedKeyName()
Expand Down Expand Up @@ -918,22 +916,68 @@ public function each(callable $callback, $count = 1000)
});
}

/**
* Query lazily, by chunks of the given size.
*
* @param int $chunkSize
* @return \Illuminate\Support\LazyCollection
*/
public function lazy($chunkSize = 1000)
{
return $this->prepareQueryBuilder()->lazy($chunkSize)->map(function ($model) {
$this->hydratePivotRelation([$model]);

return $model;
});
}

/**
* Query lazily, by chunking the results of a query by comparing IDs.
*
* @param int $count
* @param string|null $column
* @param string|null $alias
* @return \Illuminate\Support\LazyCollection
*/
public function lazyById($chunkSize = 1000, $column = null, $alias = null)
{
$column = $column ?? $this->getRelated()->qualifyColumn(
$this->getRelatedKeyName()
);

$alias = $alias ?? $this->getRelatedKeyName();

return $this->prepareQueryBuilder()->lazyById($chunkSize, $column, $alias)->map(function ($model) {
$this->hydratePivotRelation([$model]);

return $model;
});
}

/**
* Get a lazy collection for the given query.
*
* @return \Illuminate\Support\LazyCollection
*/
public function cursor()
{
$this->query->addSelect($this->shouldSelect());

return $this->query->cursor()->map(function ($model) {
return $this->prepareQueryBuilder()->cursor()->map(function ($model) {
$this->hydratePivotRelation([$model]);

return $model;
});
}

/**
* Prepare the query builder for query execution.
*
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function prepareQueryBuilder()
{
return $this->query->addSelect($this->shouldSelect());
}

/**
* Hydrate the pivot table relationship on the models.
*
Expand Down
28 changes: 28 additions & 0 deletions src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,34 @@ public function each(callable $callback, $count = 1000)
});
}

/**
* Query lazily, by chunks of the given size.
*
* @param int $chunkSize
* @return \Illuminate\Support\LazyCollection
*/
public function lazy($chunkSize = 1000)
{
return $this->prepareQueryBuilder()->lazy($chunkSize);
}

/**
* Query lazily, by chunking the results of a query by comparing IDs.
*
* @param int $count
* @param string|null $column
* @param string|null $alias
* @return \Illuminate\Support\LazyCollection
*/
public function lazyById($chunkSize = 1000, $column = null, $alias = null)
{
$column = $column ?? $this->getRelated()->getQualifiedKeyName();

$alias = $alias ?? $this->getRelated()->getKeyName();

return $this->prepareQueryBuilder()->lazyById($chunkSize, $column, $alias);
}

/**
* Prepare the query builder for query execution.
*
Expand Down
134 changes: 134 additions & 0 deletions tests/Database/DatabaseEloquentBelongsToManyLazyByIdTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<?php

namespace Illuminate\Tests\Database;

use Illuminate\Database\Capsule\Manager as DB;
use Illuminate\Database\Eloquent\Model as Eloquent;
use PHPUnit\Framework\TestCase;

class DatabaseEloquentBelongsToManyLazyByIdTest extends TestCase
{
protected function setUp(): void
{
$db = new DB;

$db->addConnection([
'driver' => 'sqlite',
'database' => ':memory:',
]);

$db->bootEloquent();
$db->setAsGlobal();

$this->createSchema();
}

/**
* Setup the database schema.
*
* @return void
*/
public function createSchema()
{
$this->schema()->create('users', function ($table) {
$table->increments('id');
$table->string('email')->unique();
});

$this->schema()->create('articles', function ($table) {
$table->increments('aid');
$table->string('title');
});

$this->schema()->create('article_user', function ($table) {
$table->integer('article_id')->unsigned();
$table->foreign('article_id')->references('aid')->on('articles');
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
});
}

public function testBelongsToLazyById()
{
$this->seedData();

$user = BelongsToManyLazyByIdTestTestUser::query()->first();
$i = 0;

$user->articles()->lazyById(1)->each(function ($model) use (&$i) {
$i++;
$this->assertEquals($i, $model->aid);
});

$this->assertSame(3, $i);
}

/**
* Tear down the database schema.
*
* @return void
*/
protected function tearDown(): void
{
$this->schema()->drop('users');
$this->schema()->drop('articles');
$this->schema()->drop('article_user');
}

/**
* Helpers...
*/
protected function seedData()
{
$user = BelongsToManyLazyByIdTestTestUser::create(['id' => 1, 'email' => '[email protected]']);
BelongsToManyLazyByIdTestTestArticle::query()->insert([
['aid' => 1, 'title' => 'Another title'],
['aid' => 2, 'title' => 'Another title'],
['aid' => 3, 'title' => 'Another title'],
]);

$user->articles()->sync([3, 1, 2]);
}

/**
* Get a database connection instance.
*
* @return \Illuminate\Database\ConnectionInterface
*/
protected function connection()
{
return Eloquent::getConnectionResolver()->connection();
}

/**
* Get a schema builder instance.
*
* @return \Illuminate\Database\Schema\Builder
*/
protected function schema()
{
return $this->connection()->getSchemaBuilder();
}
}

class BelongsToManyLazyByIdTestTestUser extends Eloquent
{
protected $table = 'users';
protected $fillable = ['id', 'email'];
public $timestamps = false;

public function articles()
{
return $this->belongsToMany(BelongsToManyLazyByIdTestTestArticle::class, 'article_user', 'user_id', 'article_id');
}
}

class BelongsToManyLazyByIdTestTestArticle extends Eloquent
{
protected $primaryKey = 'aid';
protected $table = 'articles';
protected $keyType = 'string';
public $incrementing = false;
public $timestamps = false;
protected $fillable = ['aid', 'title'];
}
46 changes: 46 additions & 0 deletions tests/Database/DatabaseEloquentHasManyThroughIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,52 @@ public function testEachReturnsCorrectModels()
});
}

public function testLazyReturnsCorrectModels()
{
$this->seedData();
$this->seedDataExtended();
$country = HasManyThroughTestCountry::find(2);

$country->posts()->lazy(10)->each(function ($post) {
$this->assertEquals([
'id',
'user_id',
'title',
'body',
'email',
'created_at',
'updated_at',
'laravel_through_key',
], array_keys($post->getAttributes()));
});
}

public function testLazyById()
{
$this->seedData();
$this->seedDataExtended();
$country = HasManyThroughTestCountry::find(2);

$i = 0;

$country->posts()->lazyById(2)->each(function ($post) use (&$i, &$count) {
$i++;

$this->assertEquals([
'id',
'user_id',
'title',
'body',
'email',
'created_at',
'updated_at',
'laravel_through_key',
], array_keys($post->getAttributes()));
});

$this->assertEquals(6, $i);
}

public function testIntermediateSoftDeletesAreIgnored()
{
$this->seedData();
Expand Down
19 changes: 19 additions & 0 deletions tests/Database/DatabaseEloquentHasOneThroughIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,25 @@ public function testEachReturnsCorrectModels()
});
}

public function testLazyReturnsCorrectModels()
{
$this->seedData();
$this->seedDataExtended();
$position = HasOneThroughTestPosition::find(1);

$position->contract()->lazy()->each(function ($contract) {
$this->assertEquals([
'id',
'user_id',
'title',
'body',
'email',
'created_at',
'updated_at',
'laravel_through_key', ], array_keys($contract->getAttributes()));
});
}

public function testIntermediateSoftDeletesAreIgnored()
{
$this->seedData();
Expand Down

0 comments on commit e16140f

Please sign in to comment.