Skip to content

Commit

Permalink
CountMethodCompiler generates SQL and passes it to SQLMethodCompiler
Browse files Browse the repository at this point in the history
  • Loading branch information
jakubkulhan committed May 24, 2024
1 parent 16a7baf commit 47e7481
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 35 deletions.
2 changes: 1 addition & 1 deletion data-access-kit/src/Repository/Compiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public function __construct(
{
$this->registerMethodCompiler(SQL::class, $sqlMethodCompiler = new SQLMethodCompiler());
$this->registerMethodCompiler(Find::class, new FindMethodCompiler($registry, $sqlMethodCompiler));
$this->registerMethodCompiler(Count::class, new CountMethodCompiler());
$this->registerMethodCompiler(Count::class, new CountMethodCompiler($registry, $sqlMethodCompiler));
$this->registerMethodCompiler(Delegate::class, new DelegateMethodCompiler());
}

Expand Down
42 changes: 42 additions & 0 deletions data-access-kit/src/Repository/Method/BuildWhereTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php declare(strict_types=1);

namespace DataAccessKit\Repository\Method;

use DataAccessKit\Attribute\Table;
use DataAccessKit\Repository\Attribute\Count;
use DataAccessKit\Repository\Attribute\Find;
use DataAccessKit\Repository\Result;
use DataAccessKit\Repository\ResultMethod;
use LogicException;
use function implode;
use function sprintf;

trait BuildWhereTrait
{
private function buildWhere(ResultMethod $method, Table $table, Result $result, Find|Count $attribute): string
{
$conditions = [];
foreach ($method->reflection->getParameters() as $parameter) {
$column = null;
foreach ($table->columns as $candidate) {
if ($candidate->reflection->getName() === $parameter->getName()) {
$column = $candidate;
break;
}
}
if ($column === null) {
throw new LogicException(sprintf(
"Method [%s::%s] parameter [%s] does not match any property of [%s], and therefore cannot be used as a query condition.",
$result->reflection->getName(),
$method->reflection->getName(),
$parameter->getName(),
$result->repository->class,
));
}

$conditions[] = "{$attribute->alias}.{$column->name} = @{$parameter->getName()}";
}

return implode(" AND ", $conditions);
}
}
21 changes: 19 additions & 2 deletions data-access-kit/src/Repository/Method/CountMethodCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,36 @@

namespace DataAccessKit\Repository\Method;

use DataAccessKit\Registry;
use DataAccessKit\Repository\Attribute\Count;
use DataAccessKit\Repository\Attribute\SQL;
use DataAccessKit\Repository\MethodCompilerInterface;
use DataAccessKit\Repository\Result;
use DataAccessKit\Repository\ResultMethod;
use LogicException;

/**
* @implements MethodCompilerInterface<Count>
*/
class CountMethodCompiler implements MethodCompilerInterface
{
use BuildWhereTrait;

public function __construct(
private readonly Registry $registry,
private readonly SQLMethodCompiler $sqlMethodCompiler,
)
{
}

public function compile(Result $result, ResultMethod $method, $attribute): void
{
throw new LogicException("TODO: count");
$table = $this->registry->get($result->repository->class, true);
$from = $attribute->from ?? $table->name;
$where = $attribute->where ?? $this->buildWhere($method, $table, $result, $attribute);
$this->sqlMethodCompiler->compile(
$result,
$method,
new SQL("SELECT COUNT(*) FROM {$from} {$attribute->alias} WHERE {$where}"),
);
}
}
34 changes: 2 additions & 32 deletions data-access-kit/src/Repository/Method/FindMethodCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,21 @@

namespace DataAccessKit\Repository\Method;

use DataAccessKit\PersistenceInterface;
use DataAccessKit\Registry;
use DataAccessKit\Repository\Attribute\Find;
use DataAccessKit\Repository\Attribute\SQL;
use DataAccessKit\Repository\Compiler;
use DataAccessKit\Repository\MethodCompilerInterface;
use DataAccessKit\Repository\Result;
use DataAccessKit\Repository\ResultMethod;
use DataAccessKit\ValueConverterInterface;
use LogicException;
use ReflectionNamedType;
use function array_map;
use function assert;
use function implode;
use function sprintf;

/**
* @implements MethodCompilerInterface<Find>
*/
class FindMethodCompiler implements MethodCompilerInterface
{
use BuildWhereTrait;

public function __construct(
private readonly Registry $registry,
Expand All @@ -39,31 +33,7 @@ public function compile(Result $result, ResultMethod $method, $attribute): void
$select = implode(", ", array_map(fn($column) => $attribute->alias . "." . $column->name, $table->columns));
}
$from = $attribute->from ?? $table->name;
$where = $attribute->where;
if ($where === null) {
$conditions = [];
foreach ($method->reflection->getParameters() as $parameter) {
$column = null;
foreach ($table->columns as $candidate) {
if ($candidate->reflection->getName() === $parameter->getName()) {
$column = $candidate;
break;
}
}
if ($column === null) {
throw new LogicException(sprintf(
"Method [%s::%s] parameter [%s] does not match any property of [%s], and therefore cannot be used as a query condition.",
$result->reflection->getName(),
$method->reflection->getName(),
$parameter->getName(),
$result->repository->class,
));
}

$conditions[] = "{$attribute->alias}.{$column->name} = @{$parameter->getName()}";
}
$where = implode(" AND ", $conditions);
}
$where = $attribute->where ?? $this->buildWhere($method, $table, $result, $attribute);

$sql = "SELECT {$select} FROM {$from} {$attribute->alias} WHERE {$where}";
if ($attribute->orderBy !== null) {
Expand Down
2 changes: 2 additions & 0 deletions data-access-kit/src/Repository/Method/SQLMethodCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public function compile(Result $result, ResultMethod $method, $attribute): void
} else {
$itemAlias = $result->use($attribute->itemType);
}
} else if ($returnType->isBuiltin()) {
$itemAlias = $returnType->getName();
} else {
$itemAlias = $result->use($returnType->getName());
}
Expand Down
2 changes: 2 additions & 0 deletions data-access-kit/test/Repository/CompilerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use DataAccessKit\DefaultNameConverter;
use DataAccessKit\Registry;
use DataAccessKit\Repository\Fixture\CountRepositoryInterface;
use DataAccessKit\Repository\Fixture\DelegateToClassRepositoryInterface;
use DataAccessKit\Repository\Fixture\DelegateToInterfaceRepositoryInterface;
use DataAccessKit\Repository\Fixture\DelegateToTraitRepositoryInterface;
Expand Down Expand Up @@ -71,6 +72,7 @@ public static function provideCompile()
FindArrayRepositoryInterface::class,
GetRepositoryInterface::class,
NullableGetRepositoryInterface::class,
CountRepositoryInterface::class,
PassClassAttributesRepositoryInterface::class,
PassMethodAttributesRepositoryInterface::class,
SimpleSQLIterableRepositoryInterface::class,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php declare(strict_types=1);

namespace DataAccessKit\Repository\Fixture;

use DataAccessKit\Repository\Attribute\Repository;

#[Repository(Foo::class)]
interface CountRepositoryInterface
{
public function countByTitle(string $title): int;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php declare(strict_types=1);

namespace DataAccessKit\Repository\Fixture;

use DataAccessKit\PersistenceInterface;

final class CountRepository implements CountRepositoryInterface
{
public function __construct(
private readonly PersistenceInterface $persistence,
)
{
}

public function countByTitle(
string $title,
): int
{
$result = $this->persistence->query(int::class, 'SELECT COUNT(*) FROM foos t WHERE t.title = ?', [$title]);
$objects = iterator_to_array($result);
if (count($objects) === 0) {
throw new LogicException("Not found");
} else if (count($objects) > 1) {
throw new LogicException("Multiple objects found");
}
return $objects[0];
}
}

0 comments on commit 47e7481

Please sign in to comment.