Skip to content

Commit

Permalink
Rename dbal business methods and add default conversion (#288)
Browse files Browse the repository at this point in the history
* Rename dbal business methods and add default conversion

* Change naming

* allow for int and string conversion

* php 8 support

* test on php 8

* php 8.2 on split testing

* php 8 compatibility
  • Loading branch information
dgafka authored Jan 13, 2024
1 parent 40e5eb9 commit a64097e
Show file tree
Hide file tree
Showing 18 changed files with 326 additions and 107 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test-monorepo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
strategy:
matrix:
operating-system: [ ubuntu-latest ]
php-versions: [ '8.1', '8.2', '8.3' ]
php-versions: [ '8.0', '8.3' ]
stability: [prefer-lowest, prefer-stable]
services:
rabbitmq:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
use Enqueue\Dbal\DbalConnectionFactory;

#[Attribute(Attribute::TARGET_METHOD)]
class DbalQueryBusinessMethod
class DbalQuery
{
public function __construct(
private string $sql,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use Enqueue\Dbal\DbalConnectionFactory;

#[Attribute(Attribute::TARGET_METHOD)]
class DbalWriteBusinessMethod
class DbalWrite
{
public function __construct(
private string $sql,
Expand Down
18 changes: 9 additions & 9 deletions packages/Dbal/src/DbaBusinessMethod/DbaBusinessMethodModule.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
use Ecotone\AnnotationFinder\AnnotatedMethod;
use Ecotone\AnnotationFinder\AnnotationFinder;
use Ecotone\Dbal\Attribute\DbalParameter;
use Ecotone\Dbal\Attribute\DbalQueryBusinessMethod;
use Ecotone\Dbal\Attribute\DbalWriteBusinessMethod;
use Ecotone\Dbal\Attribute\DbalQuery;
use Ecotone\Dbal\Attribute\DbalWrite;
use Ecotone\Messaging\Attribute\ModuleAnnotation;
use Ecotone\Messaging\Config\Annotation\AnnotatedDefinitionReference;
use Ecotone\Messaging\Config\Annotation\AnnotationModule;
Expand Down Expand Up @@ -62,8 +62,8 @@ public static function create(AnnotationFinder $annotationRegistrationService, I
{
$connectionReferences = [];
$gatewayProxyBuilders = [];
foreach ($annotationRegistrationService->findAnnotatedMethods(DbalWriteBusinessMethod::class) as $businessMethod) {
/** @var DbalWriteBusinessMethod $attribute */
foreach ($annotationRegistrationService->findAnnotatedMethods(DbalWrite::class) as $businessMethod) {
/** @var DbalWrite $attribute */
$attribute = $businessMethod->getAnnotationForMethod();

$gateway = self::getGateway($businessMethod, $attribute);
Expand All @@ -77,8 +77,8 @@ public static function create(AnnotationFinder $annotationRegistrationService, I
$connectionReferences[] = $attribute->getConnectionReferenceName();
}

foreach ($annotationRegistrationService->findAnnotatedMethods(DbalQueryBusinessMethod::class) as $businessMethod) {
/** @var DbalQueryBusinessMethod $attribute */
foreach ($annotationRegistrationService->findAnnotatedMethods(DbalQuery::class) as $businessMethod) {
/** @var DbalQuery $attribute */
$attribute = $businessMethod->getAnnotationForMethod();

$gateway = self::getGateway($businessMethod, $attribute);
Expand Down Expand Up @@ -171,19 +171,19 @@ public function canHandle($extensionObject): bool
return false;
}

private static function getGateway(AnnotatedMethod $businessMethod, DbalWriteBusinessMethod|DbalQueryBusinessMethod $attribute): GatewayProxyBuilder
private static function getGateway(AnnotatedMethod $businessMethod, DbalWrite|DbalQuery $attribute): GatewayProxyBuilder
{
return GatewayProxyBuilder::create(
AnnotatedDefinitionReference::getReferenceFor($businessMethod),
$businessMethod->getClassName(),
$businessMethod->getMethodName(),
$attribute instanceof DbalWriteBusinessMethod
$attribute instanceof DbalWrite
? self::getWriteRequestChannelName($attribute->getConnectionReferenceName())
: self::getQueryRequestChannelName($attribute->getConnectionReferenceName())
);
}

private static function getParameterConverters(DbalWriteBusinessMethod|DbalQueryBusinessMethod $attribute, InterfaceToCall $interface): array
private static function getParameterConverters(DbalWrite|DbalQuery $attribute, InterfaceToCall $interface): array
{
$parameterConverters = [
GatewayHeaderValueBuilder::create(
Expand Down
34 changes: 32 additions & 2 deletions packages/Dbal/src/DbaBusinessMethod/DbalBusinessMethodHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Ecotone\Messaging\Conversion\MediaType;
use Ecotone\Messaging\Handler\ExpressionEvaluationService;
use Ecotone\Messaging\Handler\TypeDescriptor;
use Ecotone\Messaging\Handler\UnionTypeDescriptor;
use Ecotone\Messaging\Message;
use Ecotone\Messaging\Support\MessageBuilder;
use Enqueue\Dbal\DbalContext;
Expand Down Expand Up @@ -110,7 +111,7 @@ private function getParameters(array $headers): array
}
}

$preparedParameters[$parameterName] = $parameterValue;
$preparedParameters[$parameterName] = $this->getParameterValueWithDefaultConversion($parameterValue);
}

/** Class/Method leve DbalParameters */
Expand Down Expand Up @@ -153,7 +154,7 @@ private function getParameterValue(DbalParameter $dbalParameter, array $context,
);
}

return $parameterValue;
return $this->getParameterValueWithDefaultConversion($parameterValue);
}

private function autoResolveTypesIfNeeded(array $preparedParameters, array $preparedParameterTypes): array
Expand Down Expand Up @@ -188,4 +189,33 @@ private function prepareGenerator(\Doctrine\DBAL\Result $query): Generator
yield $row;
}
}

private function getParameterValueWithDefaultConversion(mixed $parameterValue): mixed
{
$type = TypeDescriptor::createFromVariable($parameterValue);
if ($type->isClassOrInterface() && $this->conversionService->canConvert(
$type,
MediaType::createApplicationXPHP(),
UnionTypeDescriptor::createWith([TypeDescriptor::createStringType(), TypeDescriptor::createIntegerType()]),
MediaType::createApplicationXPHP()
)) {
return $this->conversionService->convert(
$parameterValue,
$type,
MediaType::createApplicationXPHP(),
UnionTypeDescriptor::createWith([TypeDescriptor::createStringType(), TypeDescriptor::createIntegerType()]),
MediaType::createApplicationXPHP(),
);
}

if ($parameterValue instanceof \DateTimeInterface) {
return $parameterValue->format('Y-m-d H:i:s.u');
}

if ($type->isClassOrInterface() && method_exists($parameterValue, '__toString')) {
return (string) $parameterValue;
}

return $parameterValue;
}
}
14 changes: 14 additions & 0 deletions packages/Dbal/tests/DbalMessagingTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public function setUp(): void
$this->deleteTable(DbalDocumentStore::ECOTONE_DOCUMENT_STORE, $connection);
$this->deleteTable(DeduplicationInterceptor::DEFAULT_DEDUPLICATION_TABLE, $connection);
$this->deleteTable('persons', $connection);
$this->deleteTable('activities', $connection);
}

protected function checkIfTableExists(Connection $connection, string $table): bool
Expand Down Expand Up @@ -92,4 +93,17 @@ protected function setupUserTable(): void
SQL);
}
}

protected function setupActivityTable(): void
{
if (! $this->checkIfTableExists($this->getConnection(), 'activities')) {
$this->getConnection()->executeStatement(<<<SQL
CREATE TABLE activities (
person_id VARCHAR(36) PRIMARY KEY,
type VARCHAR(255),
occurred_at TIMESTAMP
)
SQL);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace Test\Ecotone\Dbal\Fixture\DbalBusinessInterface;

use Ecotone\Dbal\Attribute\DbalQuery;
use Ecotone\Dbal\Attribute\DbalWrite;
use Ecotone\Dbal\DbaBusinessMethod\FetchMode;

interface ActivityService
{
#[DbalWrite('INSERT INTO activities VALUES (:personId, :activity, :time)')]
public function add(string $personId, string $activity, \DateTimeImmutable $time): void;

/**
* @return string[]
*/
#[DbalQuery(
'SELECT person_id FROM activities WHERE type = :activity AND occurred_at >= :atOrAfter',
fetchMode: FetchMode::FIRST_COLUMN
)]
public function findAfterOrAt(string $activity, \DateTimeImmutable $atOrAfter): array;

/**
* @return string[]
*/
#[DbalQuery(
'SELECT person_id FROM activities WHERE type = :activity AND occurred_at < :atOrAfter',
fetchMode: FetchMode::FIRST_COLUMN
)]
public function findBefore(string $activity, \DateTimeImmutable $atOrAfter): array;

#[DbalWrite('INSERT INTO activities VALUES (:personId, :activity, :time)')]
public function store(PersonId $personId, string $activity, \DateTimeImmutable $time): void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
namespace Test\Ecotone\Dbal\Fixture\DbalBusinessInterface;

use Ecotone\Dbal\Attribute\DbalParameter;
use Ecotone\Dbal\Attribute\DbalWriteBusinessMethod;
use Ecotone\Dbal\Attribute\DbalWrite;
use Ecotone\Messaging\Conversion\MediaType;

#[DbalParameter(name: 'roles', expression: "name === 'Johny' ? ['ROLE_ADMIN'] : []", convertToMediaType: MediaType::APPLICATION_JSON)]
interface ClassLevelDbalParameterWriteApi
{
#[DbalWriteBusinessMethod('INSERT INTO persons VALUES (:personId, :name, :roles)')]
#[DbalWrite('INSERT INTO persons VALUES (:personId, :name, :roles)')]
public function registerUsingMethodParameters(int $personId, string $name): void;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace Test\Ecotone\Dbal\Fixture\DbalBusinessInterface;

use Ecotone\Messaging\Attribute\Converter;

final class DateTimeToDayStringConverter
{
#[Converter]
public function to(\DateTimeInterface $dateTime): string
{
return $dateTime->format('Y-m-d');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,25 @@

use Doctrine\DBAL\Connection;
use Ecotone\Dbal\Attribute\DbalParameter;
use Ecotone\Dbal\Attribute\DbalQueryBusinessMethod;
use Ecotone\Dbal\Attribute\DbalQuery;

interface ParameterDbalTypeConversion
{
#[DbalQueryBusinessMethod('SELECT person_id, name FROM persons WHERE person_id IN (:personIds)')]
#[DbalQuery('SELECT person_id, name FROM persons WHERE person_id IN (:personIds)')]
public function getPersonsWith(
#[DbalParameter(type: Connection::PARAM_INT_ARRAY)] array $personIds
): array;

#[DbalQueryBusinessMethod('SELECT person_id, name FROM persons WHERE person_id IN (:personIds)')]
#[DbalQuery('SELECT person_id, name FROM persons WHERE person_id IN (:personIds)')]
#[DbalParameter('personIds', type: Connection::PARAM_INT_ARRAY, expression: '[1]')]
public function getPersonsWithWithMethodLevelParameter(): array;

#[DbalQueryBusinessMethod('SELECT person_id, name FROM persons WHERE person_id IN (:personIds)')]
#[DbalQuery('SELECT person_id, name FROM persons WHERE person_id IN (:personIds)')]
public function getPersonsWithAutoresolve(
array $personIds
): array;

#[DbalQueryBusinessMethod('SELECT person_id, name FROM persons WHERE name IN (:names)')]
#[DbalQuery('SELECT person_id, name FROM persons WHERE name IN (:names)')]
#[DbalParameter('names', expression: "['John']")]
public function getPersonsWithMethodLevelParameterAndAutoresolve(
array $names
Expand Down
18 changes: 18 additions & 0 deletions packages/Dbal/tests/Fixture/DbalBusinessInterface/PersonId.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace Test\Ecotone\Dbal\Fixture\DbalBusinessInterface;

final class PersonId
{
public function __construct(private string $id)
{

}

public function __toString(): string
{
return $this->id;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<?php

declare(strict_types=1);

namespace Test\Ecotone\Dbal\Fixture\DbalBusinessInterface;

use Ecotone\Messaging\Attribute\Converter;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Test\Ecotone\Dbal\Fixture\DbalBusinessInterface;

use Ecotone\Dbal\Attribute\DbalQueryBusinessMethod;
use Ecotone\Dbal\Attribute\DbalQuery;
use Ecotone\Dbal\DbaBusinessMethod\FetchMode;
use Ecotone\Messaging\Conversion\MediaType;

Expand All @@ -13,47 +13,47 @@ interface PersonQueryApi
/**
* @return array<int, array{person_id: string}>
*/
#[DbalQueryBusinessMethod('SELECT person_id FROM persons ORDER BY person_id ASC LIMIT :limit OFFSET :offset')]
#[DbalQuery('SELECT person_id FROM persons ORDER BY person_id ASC LIMIT :limit OFFSET :offset')]
public function getPersonIds(int $limit, int $offset): array;

/**
* @return int[]
*/
#[DbalQueryBusinessMethod(
#[DbalQuery(
'SELECT person_id FROM persons ORDER BY person_id ASC LIMIT :limit OFFSET :offset',
fetchMode: FetchMode::FIRST_COLUMN
)]
public function getExtractedPersonIds(int $limit, int $offset): array;

#[DbalQueryBusinessMethod(
#[DbalQuery(
'SELECT COUNT(*) FROM persons',
fetchMode: FetchMode::FIRST_COLUMN_OF_FIRST_ROW
)]
public function countPersons(): int;

#[DbalQueryBusinessMethod('SELECT person_id, name FROM persons LIMIT :limit OFFSET :offset')]
#[DbalQuery('SELECT person_id, name FROM persons LIMIT :limit OFFSET :offset')]
public function getNameList(int $limit, int $offset): array;

#[DbalQueryBusinessMethod(
#[DbalQuery(
'SELECT person_id, name FROM persons WHERE person_id = :personId',
fetchMode: FetchMode::FIRST_ROW
)]
public function getNameDTO(int $personId): PersonNameDTO;

#[DbalQueryBusinessMethod(
#[DbalQuery(
'SELECT person_id, name FROM persons WHERE person_id = :personId',
fetchMode: FetchMode::FIRST_ROW,
replyContentType: MediaType::APPLICATION_JSON
)]
public function getNameDTOInJson(int $personId): string;

#[DbalQueryBusinessMethod(
#[DbalQuery(
'SELECT person_id, name FROM persons WHERE person_id = :personId',
fetchMode: FetchMode::FIRST_ROW
)]
public function getNameDTOOrNull(int $personId): PersonNameDTO|null;

#[DbalQueryBusinessMethod(
#[DbalQuery(
'SELECT person_id, name FROM persons WHERE person_id = :personId',
fetchMode: FetchMode::FIRST_ROW
)]
Expand All @@ -62,13 +62,13 @@ public function getNameDTOOrFalse(int $personId): PersonNameDTO|false;
/**
* @return PersonNameDTO[]
*/
#[DbalQueryBusinessMethod('SELECT person_id, name FROM persons LIMIT :limit OFFSET :offset')]
#[DbalQuery('SELECT person_id, name FROM persons LIMIT :limit OFFSET :offset')]
public function getNameListDTO(int $limit, int $offset): array;

/**
* @return iterable<PersonNameDTO>
*/
#[DbalQueryBusinessMethod(
#[DbalQuery(
'SELECT person_id, name FROM persons ORDER BY person_id ASC',
fetchMode: FetchMode::ITERATE
)]
Expand Down
Loading

0 comments on commit a64097e

Please sign in to comment.