Skip to content

Commit

Permalink
Added result caching for QueryBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
twoleds committed Jul 28, 2022
1 parent d6aaae9 commit b13f970
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 27 deletions.
66 changes: 56 additions & 10 deletions src/Query/QueryBuilder.php
Expand Up @@ -2,6 +2,7 @@

namespace Doctrine\DBAL\Query;

use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\ParameterType;
Expand Down Expand Up @@ -123,6 +124,13 @@ class QueryBuilder
*/
private int $boundCounter = 0;

/**
* The query cache profile used for caching results.
*
* @var QueryCacheProfile|null
*/
private $resultCacheProfile = null;

/**
* Initializes a new <tt>QueryBuilder</tt>.
*
Expand Down Expand Up @@ -194,7 +202,7 @@ public function getState()
*/
public function fetchAssociative()
{
return $this->connection->fetchAssociative($this->getSQL(), $this->params, $this->paramTypes);
return $this->executeQuery()->fetchAssociative();
}

/**
Expand All @@ -207,7 +215,7 @@ public function fetchAssociative()
*/
public function fetchNumeric()
{
return $this->connection->fetchNumeric($this->getSQL(), $this->params, $this->paramTypes);
return $this->executeQuery()->fetchNumeric();
}

/**
Expand All @@ -220,7 +228,7 @@ public function fetchNumeric()
*/
public function fetchOne()
{
return $this->connection->fetchOne($this->getSQL(), $this->params, $this->paramTypes);
return $this->executeQuery()->fetchOne();
}

/**
Expand All @@ -232,7 +240,7 @@ public function fetchOne()
*/
public function fetchAllNumeric(): array
{
return $this->connection->fetchAllNumeric($this->getSQL(), $this->params, $this->paramTypes);
return $this->executeQuery()->fetchAllNumeric();
}

/**
Expand All @@ -244,7 +252,7 @@ public function fetchAllNumeric(): array
*/
public function fetchAllAssociative(): array
{
return $this->connection->fetchAllAssociative($this->getSQL(), $this->params, $this->paramTypes);
return $this->executeQuery()->fetchAllAssociative();
}

/**
Expand All @@ -257,7 +265,7 @@ public function fetchAllAssociative(): array
*/
public function fetchAllKeyValue(): array
{
return $this->connection->fetchAllKeyValue($this->getSQL(), $this->params, $this->paramTypes);
return $this->executeQuery()->fetchAllKeyValue();
}

/**
Expand All @@ -271,7 +279,7 @@ public function fetchAllKeyValue(): array
*/
public function fetchAllAssociativeIndexed(): array
{
return $this->connection->fetchAllAssociativeIndexed($this->getSQL(), $this->params, $this->paramTypes);
return $this->executeQuery()->fetchAllAssociativeIndexed();
}

/**
Expand All @@ -283,7 +291,7 @@ public function fetchAllAssociativeIndexed(): array
*/
public function fetchFirstColumn(): array
{
return $this->connection->fetchFirstColumn($this->getSQL(), $this->params, $this->paramTypes);
return $this->executeQuery()->fetchFirstColumn();
}

/**
Expand All @@ -293,7 +301,12 @@ public function fetchFirstColumn(): array
*/
public function executeQuery(): Result
{
return $this->connection->executeQuery($this->getSQL(), $this->params, $this->paramTypes);
return $this->connection->executeQuery(
$this->getSQL(),
$this->params,
$this->paramTypes,
$this->resultCacheProfile
);
}

/**
Expand Down Expand Up @@ -328,7 +341,7 @@ public function execute()
'QueryBuilder::execute() is deprecated, use QueryBuilder::executeQuery() for SQL queries instead.'
);

return $this->connection->executeQuery($this->getSQL(), $this->params, $this->paramTypes);
return $this->executeQuery();
}

Deprecation::trigger(
Expand Down Expand Up @@ -1548,4 +1561,37 @@ public function __clone()
$this->params[$name] = clone $param;
}
}

/**
* Enables caching of the results of this query, for given amount of seconds
* and optionally specified witch key to use for the cache entry.
*
* @return $this
*/
public function enableResultCache(QueryCacheProfile $cacheProfile): self
{
$this->resultCacheProfile = $cacheProfile;

return $this;
}

/**
* Disables caching of the results of this query.
*
* @return $this
*/
public function disableResultCache(): self
{
$this->resultCacheProfile = null;

return $this;
}

/**
* Gets the cache profile for the result caching.
*/
public function getResultCacheProfile(): ?QueryCacheProfile
{
return $this->resultCacheProfile;
}
}
127 changes: 110 additions & 17 deletions tests/Query/QueryBuilderTest.php
Expand Up @@ -2,6 +2,7 @@

namespace Doctrine\DBAL\Tests\Query;

use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Query\Expression\ExpressionBuilder;
Expand Down Expand Up @@ -965,11 +966,16 @@ public function testFetchAssociative(
array $parameterTypes,
string $expectedSql
): void {
$qb = new QueryBuilder($this->conn);
$qb = new QueryBuilder($this->conn);
$mockedResult = $this->createMock(Result::class);

$this->conn->expects(self::once())
->method('executeQuery')
->with($expectedSql, $parameters, $parameterTypes, null)
->willReturn($mockedResult);

$mockedResult->expects(self::once())
->method('fetchAssociative')
->with($expectedSql, $parameters, $parameterTypes)
->willReturn(['username' => 'jwage', 'password' => 'changeme']);

$row = $qb->select($select)
Expand All @@ -995,11 +1001,16 @@ public function testFetchNumeric(
array $parameterTypes,
string $expectedSql
): void {
$qb = new QueryBuilder($this->conn);
$qb = new QueryBuilder($this->conn);
$mockedResult = $this->createMock(Result::class);

$this->conn->expects(self::once())
->method('executeQuery')
->with($expectedSql, $parameters, $parameterTypes, null)
->willReturn($mockedResult);

$mockedResult->expects(self::once())
->method('fetchNumeric')
->with($expectedSql, $parameters, $parameterTypes)
->willReturn(['jwage', 'changeme']);

$row = $qb->select($select)
Expand All @@ -1025,11 +1036,16 @@ public function testFetchOne(
array $parameterTypes,
string $expectedSql
): void {
$qb = new QueryBuilder($this->conn);
$qb = new QueryBuilder($this->conn);
$mockedResult = $this->createMock(Result::class);

$this->conn->expects(self::once())
->method('executeQuery')
->with($expectedSql, $parameters, $parameterTypes, null)
->willReturn($mockedResult);

$mockedResult->expects(self::once())
->method('fetchOne')
->with($expectedSql, $parameters, $parameterTypes)
->willReturn('jwage');

$username = $qb->select($select)
Expand All @@ -1055,11 +1071,16 @@ public function testFetchAllAssociative(
array $parameterTypes,
string $expectedSql
): void {
$qb = new QueryBuilder($this->conn);
$qb = new QueryBuilder($this->conn);
$mockedResult = $this->createMock(Result::class);

$this->conn->expects(self::once())
->method('executeQuery')
->with($expectedSql, $parameters, $parameterTypes, null)
->willReturn($mockedResult);

$mockedResult->expects(self::once())
->method('fetchAllAssociative')
->with($expectedSql, $parameters, $parameterTypes)
->willReturn(
[
['username' => 'jwage', 'password' => 'changeme'],
Expand Down Expand Up @@ -1096,11 +1117,16 @@ public function testFetchAllNumeric(
array $parameterTypes,
string $expectedSql
): void {
$qb = new QueryBuilder($this->conn);
$qb = new QueryBuilder($this->conn);
$mockedResult = $this->createMock(Result::class);

$this->conn->expects(self::once())
->method('executeQuery')
->with($expectedSql, $parameters, $parameterTypes, null)
->willReturn($mockedResult);

$mockedResult->expects(self::once())
->method('fetchAllNumeric')
->with($expectedSql, $parameters, $parameterTypes)
->willReturn(
[
['jwage', 'changeme'],
Expand Down Expand Up @@ -1137,11 +1163,16 @@ public function testFetchAllKeyValue(
array $parameterTypes,
string $expectedSql
): void {
$qb = new QueryBuilder($this->conn);
$qb = new QueryBuilder($this->conn);
$mockedResult = $this->createMock(Result::class);

$this->conn->expects(self::once())
->method('executeQuery')
->with($expectedSql, $parameters, $parameterTypes, null)
->willReturn($mockedResult);

$mockedResult->expects(self::once())
->method('fetchAllKeyValue')
->with($expectedSql, $parameters, $parameterTypes)
->willReturn(
[
'jwage' => 'changeme',
Expand Down Expand Up @@ -1178,11 +1209,16 @@ public function testFetchAllAssociativeIndexed(
array $parameterTypes,
string $expectedSql
): void {
$qb = new QueryBuilder($this->conn);
$qb = new QueryBuilder($this->conn);
$mockedResult = $this->createMock(Result::class);

$this->conn->expects(self::once())
->method('executeQuery')
->with($expectedSql, $parameters, $parameterTypes, null)
->willReturn($mockedResult);

$mockedResult->expects(self::once())
->method('fetchAllAssociativeIndexed')
->with($expectedSql, $parameters, $parameterTypes)
->willReturn(
[
1 => [
Expand Down Expand Up @@ -1223,11 +1259,16 @@ public function testFetchFirstColumn(
array $parameterTypes,
string $expectedSql
): void {
$qb = new QueryBuilder($this->conn);
$qb = new QueryBuilder($this->conn);
$mockedResult = $this->createMock(Result::class);

$this->conn->expects(self::once())
->method('executeQuery')
->with($expectedSql, $parameters, $parameterTypes, null)
->willReturn($mockedResult);

$mockedResult->expects(self::once())
->method('fetchFirstColumn')
->with($expectedSql, $parameters, $parameterTypes)
->willReturn(
[
'jwage',
Expand Down Expand Up @@ -1320,7 +1361,7 @@ public function testExecuteQuery(

$this->conn->expects(self::once())
->method('executeQuery')
->with($expectedSql, $parameters, $parameterTypes)
->with($expectedSql, $parameters, $parameterTypes, null)
->willReturn($mockedResult);

$results = $qb->select($select)
Expand All @@ -1335,6 +1376,42 @@ public function testExecuteQuery(
);
}

/**
* @param list<mixed>|array<string, mixed> $parameters
* @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $parameterTypes
*
* @dataProvider fetchProvider
*/
public function testExecuteQueryWithResultCaching(
string $select,
string $from,
string $where,
array $parameters,
array $parameterTypes,
string $expectedSql
): void {
$qb = new QueryBuilder($this->conn);
$qcp = new QueryCacheProfile(300);
$mockedResult = $this->createMock(Result::class);

$this->conn->expects(self::once())
->method('executeQuery')
->with($expectedSql, $parameters, $parameterTypes, $qcp)
->willReturn($mockedResult);

$results = $qb->select($select)
->from($from)
->where($where)
->setParameters($parameters, $parameterTypes)
->enableResultCache($qcp)
->executeQuery();

self::assertSame(
$mockedResult,
$results
);
}

public function testExecuteStatement(): void
{
$qb = new QueryBuilder($this->conn);
Expand Down Expand Up @@ -1368,4 +1445,20 @@ public function testExecuteStatement(): void
$results
);
}

public function testGetResultCacheProfile(): void
{
$qb = new QueryBuilder($this->conn);

$qb->enableResultCache(new QueryCacheProfile(300));

self::assertEquals(
new QueryCacheProfile(300),
$qb->getResultCacheProfile(),
);

$qb->disableResultCache();

self::assertNull($qb->getResultCacheProfile());
}
}

0 comments on commit b13f970

Please sign in to comment.