Skip to content

Commit cfb0e78

Browse files
committed
Add NativeQueryResultMapper::first() method
1 parent 5eddfe7 commit cfb0e78

2 files changed

Lines changed: 69 additions & 2 deletions

File tree

src/ORM/NativeQueryResultMapper.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Bancer\NativeQueryMapper\ORM;
66

77
use Cake\Database\StatementInterface;
8+
use Cake\Datasource\EntityInterface;
89
use Cake\ORM\Table;
910

1011
/**
@@ -104,6 +105,23 @@ public function all(): array
104105
return $hydrator->hydrateMany($rows);
105106
}
106107

108+
/**
109+
* Returns the first hydrated entity from the native query result.
110+
*
111+
* This executes the native SQL, hydrates entities using the mapping strategy,
112+
* and returns only the first entity (or null if no rows were returned).
113+
*
114+
* @return \Cake\Datasource\EntityInterface|null
115+
*/
116+
public function first(): ?EntityInterface
117+
{
118+
$entities = $this->all();
119+
if ($entities === []) {
120+
return null;
121+
}
122+
return $entities[0];
123+
}
124+
107125
/**
108126
* Extract column aliases used in the SQL result set.
109127
*

tests/TestCase/ORM/NativeQueryMapperTest.php

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,57 @@ public function testHasManyMinimalSQL(): void
307307
],
308308
])
309309
->toArray();
310-
$this->assertEqualsEntities($cakeEntities, $actual);
311-
//static::assertEquals($cakeEntities, $actual);
310+
static::assertEquals($cakeEntities, $actual);
311+
}
312+
313+
public function testHasManyFirst(): void
314+
{
315+
/** @var \Bancer\NativeQueryMapperTest\TestApp\Model\Table\ArticlesTable $ArticlesTable */
316+
$ArticlesTable = $this->fetchTable(ArticlesTable::class);
317+
$stmt = $ArticlesTable->prepareNativeStatement("
318+
SELECT
319+
a.id AS Articles__id,
320+
title AS Articles__title,
321+
c.id AS Comments__id,
322+
article_id AS Comments__article_id,
323+
content AS Comments__content
324+
FROM articles AS a
325+
LEFT JOIN comments AS c ON a.id=c.article_id
326+
WHERE a.id=1
327+
");
328+
$actual = $ArticlesTable->mapNativeStatement($stmt)->first();
329+
static::assertInstanceOf(Article::class, $actual);
330+
$actualComments = $actual->get('comments');
331+
static::assertIsArray($actualComments);
332+
static::assertCount(2, $actualComments);
333+
static::assertInstanceOf(Comment::class, $actualComments[0]);
334+
$expected = [
335+
'id' => 1,
336+
'title' => 'Article 1',
337+
'comments' => [
338+
[
339+
'id' => 1,
340+
'article_id' => 1,
341+
'content' => 'Comment 1',
342+
],
343+
[
344+
'id' => 2,
345+
'article_id' => 1,
346+
'content' => 'Comment 2',
347+
],
348+
],
349+
];
350+
static::assertEquals($expected, $actual->toArray());
351+
$cakeEntity = $ArticlesTable->find()
352+
->select(['Articles.id', 'Articles.title'])
353+
->contain([
354+
'Comments' => [
355+
'fields' => ['Comments.id', 'Comments.article_id', 'Comments.content'],
356+
],
357+
])
358+
->where(['Articles.id' => 1])
359+
->first();
360+
static::assertEquals($cakeEntity, $actual);
312361
}
313362

314363
public function testBelongsTo(): void

0 commit comments

Comments
 (0)