FIX Trigger eagerloading for first() and last() (#10875)

This commit is contained in:
Guy Sartorelli 2023-07-20 16:37:03 +12:00 committed by GitHub
parent 60d65dd369
commit 642321db61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 56 additions and 4 deletions

View File

@ -1408,8 +1408,13 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
*/
public function first()
{
foreach ($this->dataQuery->firstRow()->execute() as $row) {
return $this->createDataObject($row);
// We need to trigger eager loading by iterating over the list, rather than just fetching
// the first row from the dataQuery.
// This limit and offset logic mimics that $this->dataQuery->firstRow() would ultimately do.
$limitOffset = $this->dataQuery->query()->getLimit() ?? [];
$offset = array_key_exists('start', $limitOffset) ? $limitOffset['start'] : 0;
foreach ($this->limit(1, $offset) as $record) {
return $record;
}
return null;
}
@ -1423,8 +1428,14 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
*/
public function last()
{
foreach ($this->dataQuery->lastRow()->execute() as $row) {
return $this->createDataObject($row);
// We need to trigger eager loading by iterating over the list, rather than just fetching
// the last row from the dataQuery.
// This limit and offset logic mimics that $this->dataQuery->lastRow() would ultimately do.
$limitOffset = $this->dataQuery->query()->getLimit() ?? [];
$offset = array_key_exists('start', $limitOffset) ? $limitOffset['start'] : 0;
$index = max($this->count() + $offset - 1, 0);
foreach ($this->limit(1, $index) as $record) {
return $record;
}
return null;
}

View File

@ -4,6 +4,7 @@ namespace SilverStripe\ORM\Tests;
use InvalidArgumentException;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\DataList;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DB;
@ -1115,4 +1116,22 @@ class DataListEagerLoadingTest extends SapphireTest
],
];
}
public function testFirstHasEagerloadedRelation()
{
$record = EagerLoadObject::create(['Title' => 'My obj']);
$record->write();
$record->HasManyEagerLoadObjects()->add(HasManyEagerLoadObject::create(['Title' => 'My related obj']));
$obj = EagerLoadObject::get()->eagerLoad('HasManyEagerLoadObjects')->first();
$this->assertInstanceOf(ArrayList::class, $obj->HasManyEagerLoadObjects());
}
public function testLastHasEagerloadedRelation()
{
$record = EagerLoadObject::create(['Title' => 'My obj']);
$record->write();
$record->HasManyEagerLoadObjects()->add(HasManyEagerLoadObject::create(['Title' => 'My related obj']));
$obj = EagerLoadObject::get()->eagerLoad('HasManyEagerLoadObjects')->last();
$this->assertInstanceOf(ArrayList::class, $obj->HasManyEagerLoadObjects());
}
}

View File

@ -2081,6 +2081,28 @@ class DataListTest extends SapphireTest
], $productTitles);
}
public function testFirst()
{
$list = Sortable::get()->sort('Sort');
$this->assertGreaterThanOrEqual(
3,
$list->count(),
'We must have at least 3 items for this test to be valid'
);
$this->assertSame('Steve', $list->first()->Name);
}
public function testLast()
{
$list = Sortable::get()->sort('Sort');
$this->assertGreaterThanOrEqual(
3,
$list->count(),
'We must have at least 3 items for this test to be valid'
);
$this->assertSame('John', $list->last()->Name);
}
public function testChunkedFetch()
{
$expectedIDs = Team::get()->map('ID', 'ID')->toArray();