diff --git a/src/Bridge/AbstractBridge.php b/src/Bridge/AbstractBridge.php index 46286ec..bb4bd98 100644 --- a/src/Bridge/AbstractBridge.php +++ b/src/Bridge/AbstractBridge.php @@ -26,6 +26,7 @@ abstract class AbstractBridge extends DefaultQueryBuilder implements Bridge { + private ?Converter $converter = null; private ?ConverterPluginRegistry $converterPluginRegistry = null; private ?Writer $writer = null; private ?string $serverName = null; @@ -236,7 +237,7 @@ protected function lookupServerVersion(): ?string /** * Create default writer based upon server name and version and driver. */ - protected function createConverter(ConverterPluginRegistry $converterPluginRegistry): Converter + protected function getConverter(): Converter { $ret = match ($this->getServerFlavor()) { Platform::MARIADB => new MySQLConverter(), @@ -244,7 +245,7 @@ protected function createConverter(ConverterPluginRegistry $converterPluginRegis default => new Converter(), }; - $ret->setConverterPluginRegistry($converterPluginRegistry); + $ret->setConverterPluginRegistry($this->getConverterPluginRegistry()); return $ret; } @@ -299,11 +300,6 @@ protected function createWriter(Escaper $escaper, Converter $converter): Writer */ public function getWriter(): Writer { - return $this->writer ??= $this->createWriter( - $this->createEscaper(), - $this->createConverter( - $this->getConverterPluginRegistry(), - ), - ); + return $this->writer ??= $this->createWriter($this->createEscaper(), $this->getConverter()); } } diff --git a/src/Bridge/Doctrine/DoctrineQueryBuilder.php b/src/Bridge/Doctrine/DoctrineQueryBuilder.php index 8ec31dd..d7ea09b 100644 --- a/src/Bridge/Doctrine/DoctrineQueryBuilder.php +++ b/src/Bridge/Doctrine/DoctrineQueryBuilder.php @@ -106,7 +106,10 @@ protected function doExecuteQuery(string $expression, array $arguments = []): Re $doctrineResult = $this->connection->executeQuery($expression, $arguments); - return new IterableResult($doctrineResult->iterateAssociative(), $doctrineResult->rowCount(), fn () => $doctrineResult->free()); + $result = new IterableResult($doctrineResult->iterateAssociative(), $doctrineResult->rowCount(), fn () => $doctrineResult->free()); + $result->setConverter($this->getConverter()); + + return $result; } /** diff --git a/src/Bridge/Pdo/PdoQueryBuilder.php b/src/Bridge/Pdo/PdoQueryBuilder.php index 319b514..81e25cd 100644 --- a/src/Bridge/Pdo/PdoQueryBuilder.php +++ b/src/Bridge/Pdo/PdoQueryBuilder.php @@ -102,11 +102,14 @@ protected function doExecuteQuery(string $expression, array $arguments = []): Re $statement = $this->connection->prepare($expression); $statement->execute($arguments); - return new IterableResult( + $result = new IterableResult( $statement->getIterator(), $statement->rowCount(), fn () => $statement->closeCursor(), ); + $result->setConverter($this->getConverter()); + + return $result; } /** diff --git a/src/Platform/Writer/MySQLWriter.php b/src/Platform/Writer/MySQLWriter.php index 0d6ca40..d651946 100644 --- a/src/Platform/Writer/MySQLWriter.php +++ b/src/Platform/Writer/MySQLWriter.php @@ -8,7 +8,6 @@ use MakinaCorpus\QueryBuilder\Converter\Converter; use MakinaCorpus\QueryBuilder\Error\QueryBuilderError; use MakinaCorpus\QueryBuilder\Expression\Aggregate; -use MakinaCorpus\QueryBuilder\Expression\Cast; use MakinaCorpus\QueryBuilder\Expression\Concat; use MakinaCorpus\QueryBuilder\Expression\ConstantTable; use MakinaCorpus\QueryBuilder\Expression\CurrentTimestamp; diff --git a/src/Result/AbstractResult.php b/src/Result/AbstractResult.php index 9d5aadf..fb6fb34 100644 --- a/src/Result/AbstractResult.php +++ b/src/Result/AbstractResult.php @@ -4,6 +4,7 @@ namespace MakinaCorpus\QueryBuilder\Result; +use MakinaCorpus\QueryBuilder\Converter\Converter; use MakinaCorpus\QueryBuilder\Error\ResultAlreadyStartedError; use MakinaCorpus\QueryBuilder\Error\ResultError; use MakinaCorpus\QueryBuilder\Error\ResultLockedError; @@ -24,11 +25,23 @@ abstract class AbstractResult implements Result, \IteratorAggregate private bool $iterationCompleted = false; private bool $justRewinded = false; private bool $rewindable = false; + private ?Converter $converter = null; public function __construct( private bool $countIsReliable = true, ) {} + /** + * Set converter. + * + * @internal + * For bridge only. + */ + public function setConverter(Converter $converter): void + { + $this->converter = $converter; + } + /** * Get row count from driver. */ @@ -131,7 +144,7 @@ public function setColumnTypes(array $columnTypes): static public function fetchRow(): ?ResultRow { if ($row = $this->fetchNext()) { - return new DefaultResultRow($row); + return new DefaultResultRow($row, $this->converter); } return null; } @@ -151,7 +164,7 @@ public function fetchHydrated(): mixed return null; } - return ($this->hydrator)($this->hydratorUsesArray ? $row : new DefaultResultRow($row)); + return ($this->hydrator)($this->hydratorUsesArray ? $row : new DefaultResultRow($row, $this->converter)); } /** diff --git a/src/Result/DefaultResultRow.php b/src/Result/DefaultResultRow.php index 6e5c328..1e4fe92 100644 --- a/src/Result/DefaultResultRow.php +++ b/src/Result/DefaultResultRow.php @@ -4,6 +4,7 @@ namespace MakinaCorpus\QueryBuilder\Result; +use MakinaCorpus\QueryBuilder\Converter\Converter; use MakinaCorpus\QueryBuilder\Error\ResultError; class DefaultResultRow implements ResultRow @@ -12,6 +13,7 @@ class DefaultResultRow implements ResultRow public function __construct( private array $rawValues, + private ?Converter $converter = null, ) { $this->names = \array_keys($rawValues); } @@ -28,7 +30,10 @@ public function get(int|string $columnName, ?string $phpType = null): mixed } if ($phpType) { - throw new \Exception("Type conversion from SQL to PHP is not implemented yet."); + if (!$this->converter) { + $this->converter = new Converter(); + } + $value = $this->converter->fromSql($phpType, $value); } return $value; diff --git a/src/Writer/Writer.php b/src/Writer/Writer.php index 0164c6e..42348dd 100644 --- a/src/Writer/Writer.php +++ b/src/Writer/Writer.php @@ -74,26 +74,22 @@ class Writer { private string $matchParametersRegex; + private ?Converter $converter = null; protected Escaper $escaper; - protected Converter $converter; public function __construct(?Escaper $escaper = null, ?Converter $converter = null) { - $this->converter = $converter ?? $this->createConverter(); + $this->converter = $converter; $this->escaper = $escaper ?? new StandardEscaper(); $this->buildParameterRegex(); } /** - * Create default converter. - * - * This is a fallback, during production runtime, the converter should have - * been injected by setup code, in order to inherit from the converter - * registry and user implementations. + * Get converter. */ - protected function createConverter(): Converter + protected function getConverter(): Converter { - return new Converter(); + return $this->converter ??= new Converter(); } /** @@ -114,7 +110,7 @@ public function prepare(string|Expression|SqlString $sql): SqlString // then $identifier = $sql->getIdentifier(); } - $context = new WriterContext($this->converter); + $context = new WriterContext($this->getConverter()); $rawSql = $this->format($sql, $context); return new SqlString( @@ -151,7 +147,7 @@ protected function guessTypeOf(Expression $expression): ?string } if ($expression instanceof Value) { - if ($type = $this->converter->guessInputType($expression->getValue())) { + if ($type = $this->getConverter()->guessInputType($expression->getValue())) { // Cache guessed type to avoid doing it twice when converting // values later at query time. $expression->setType($type); @@ -314,7 +310,7 @@ protected function parseExpression(Raw|RawQuery $expression, WriterContext $cont return $asString; } - $converter = $this->converter; + $converter = $this->getConverter(); // See https://stackoverflow.com/a/3735908 for the starting // sequence explaination, the rest should be comprehensible.