Skip to content

Commit 8fe50f9

Browse files
committed
Result::getColumnTypes() redesigned, uses TypeConverter
1 parent fd3ac1c commit 8fe50f9

17 files changed

Lines changed: 198 additions & 158 deletions

src/Database/Connection.php

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
use JetBrains\PhpStorm\Language;
1313
use Nette\Utils\Arrays;
14-
use Nette\Utils\DateTime;
1514
use PDOException;
1615

1716

@@ -29,6 +28,7 @@ class Connection
2928
private ?Drivers\Connection $connection = null;
3029
private ?Drivers\Engine $engine;
3130
private ?SqlPreprocessor $preprocessor;
31+
private TypeConverter $typeConverter;
3232

3333
/** @var callable(array, Result): array */
3434
private $rowNormalizer = [Helpers::class, 'normalizeRow'];
@@ -43,13 +43,12 @@ public function __construct(
4343
?string $password = null,
4444
array $options = [],
4545
) {
46-
if (($options['newDateTime'] ?? null) === false) {
47-
$this->rowNormalizer = fn($row, $resultSet) => Helpers::normalizeRow($row, $resultSet, DateTime::class);
48-
}
4946
$lazy = $options['lazy'] ?? false;
50-
unset($options['newDateTime'], $options['lazy']);
47+
unset($options['lazy']);
5148

52-
$this->driver = (new Factory)->createDriverFromDsn($dsn, $user, $password, $options);
49+
$factory = new Factory;
50+
$this->typeConverter = $factory->createTypeConverter($options);
51+
$this->driver = $factory->createDriverFromDsn($dsn, $user, $password, $options);
5352
if (!$lazy) {
5453
$this->connect();
5554
}
@@ -134,6 +133,12 @@ public function getReflection(): Reflection
134133
}
135134

136135

136+
public function getTypeConverter(): TypeConverter
137+
{
138+
return $this->typeConverter;
139+
}
140+
141+
137142
public function setRowNormalizer(?callable $normalizer): static
138143
{
139144
$this->rowNormalizer = $normalizer;

src/Database/Drivers/Engine.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
namespace Nette\Database\Drivers;
1111

1212
use Nette\Database;
13+
use Nette\Database\TypeConverter;
1314

1415

1516
/**
@@ -69,11 +70,7 @@ function getIndexes(string $table): array;
6970
/** @return list<array{name: string, local: string, table: string, foreign: string}> */
7071
function getForeignKeys(string $table): array;
7172

72-
/**
73-
* Returns associative array of detected types (IStructure::FIELD_*) in result set.
74-
* @return array<string, string>
75-
*/
76-
function getColumnTypes(\PDOStatement $statement): array;
73+
function resolveColumnConverter(array $meta, TypeConverter $converter): ?\Closure;
7774

7875
/**
7976
* Cheks if driver supports specific property

src/Database/Drivers/Engines/MSSQLEngine.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Nette;
1313
use Nette\Database\Drivers\Connection;
1414
use Nette\Database\Drivers\Engine;
15+
use Nette\Database\TypeConverter;
1516

1617

1718
/**
@@ -213,9 +214,9 @@ public function getForeignKeys(string $table): array
213214
}
214215

215216

216-
public function getColumnTypes(\PDOStatement $statement): array
217+
public function resolveColumnConverter(array $meta, TypeConverter $converter): ?\Closure
217218
{
218-
return Nette\Database\Helpers::detectTypes($statement);
219+
return $converter->resolve($meta['nativeType']);
219220
}
220221

221222

src/Database/Drivers/Engines/MySQLEngine.php

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@
2020
*/
2121
class MySQLEngine implements Engine
2222
{
23-
public bool $convertBoolean = true;
24-
25-
2623
public function __construct(
2724
private readonly Connection $connection,
2825
) {
@@ -176,23 +173,21 @@ public function getForeignKeys(string $table): array
176173
}
177174

178175

179-
public function getColumnTypes(\PDOStatement $statement): array
176+
public function resolveColumnConverter(array $meta, TypeConverter $converter): ?\Closure
180177
{
181-
$types = [];
182-
$count = $statement->columnCount();
183-
for ($col = 0; $col < $count; $col++) {
184-
$meta = $statement->getColumnMeta($col);
185-
if (isset($meta['native_type'])) {
186-
$types[$meta['name']] = match (true) {
187-
$meta['native_type'] === 'NEWDECIMAL' && $meta['precision'] === 0 => Nette\Database\IStructure::FIELD_INTEGER,
188-
$meta['native_type'] === 'TINY' && $meta['len'] === 1 && $this->convertBoolean => Nette\Database\IStructure::FIELD_BOOL,
189-
$meta['native_type'] === 'TIME' => Nette\Database\IStructure::FIELD_TIME_INTERVAL,
190-
default => TypeConverter::detectType($meta['native_type']),
191-
};
192-
}
193-
}
194-
195-
return $types;
178+
return match ($meta['nativeType']) {
179+
'NEWDECIMAL' => $meta['precision'] === 0
180+
? $converter->toInt(...)
181+
: $converter->toFloat(...), // precision in PDOStatement::getColumnMeta() means scale
182+
'TINY' => $meta['length'] === 1 && $converter->convertBoolean
183+
? $converter->toBool(...)
184+
: $converter->toInt(...),
185+
'TIME' => $converter->toInterval(...),
186+
'DATE', 'DATETIME', 'TIMESTAMP' => fn($value): ?\DateTimeInterface => str_starts_with($value, '0000-00')
187+
? null
188+
: $converter->toDateTime($value),
189+
default => $converter->resolve($meta['nativeType']),
190+
};
196191
}
197192

198193

src/Database/Drivers/Engines/ODBCEngine.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
use Nette;
1313
use Nette\Database\Drivers\Engine;
14+
use Nette\Database\TypeConverter;
1415

1516

1617
/**
@@ -96,9 +97,9 @@ public function getForeignKeys(string $table): array
9697
}
9798

9899

99-
public function getColumnTypes(\PDOStatement $statement): array
100+
public function resolveColumnConverter(array $meta, TypeConverter $converter): ?\Closure
100101
{
101-
return [];
102+
return $converter->resolve($meta['nativeType']);
102103
}
103104

104105

src/Database/Drivers/Engines/OracleEngine.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Nette;
1313
use Nette\Database\Drivers\Connection;
1414
use Nette\Database\Drivers\Engine;
15+
use Nette\Database\TypeConverter;
1516

1617

1718
/**
@@ -130,9 +131,9 @@ public function getForeignKeys(string $table): array
130131
}
131132

132133

133-
public function getColumnTypes(\PDOStatement $statement): array
134+
public function resolveColumnConverter(array $meta, TypeConverter $converter): ?\Closure
134135
{
135-
return [];
136+
return $converter->resolve($meta['nativeType']);
136137
}
137138

138139

src/Database/Drivers/Engines/PostgreSQLEngine.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Nette;
1313
use Nette\Database\Drivers\Connection;
1414
use Nette\Database\Drivers\Engine;
15+
use Nette\Database\TypeConverter;
1516

1617

1718
/**
@@ -238,12 +239,11 @@ public function getForeignKeys(string $table): array
238239
}
239240

240241

241-
public function getColumnTypes(\PDOStatement $statement): array
242+
public function resolveColumnConverter(array $meta, TypeConverter $converter): ?\Closure
242243
{
243-
static $cache;
244-
$item = &$cache[$statement->queryString];
245-
$item ??= Nette\Database\Helpers::detectTypes($statement);
246-
return $item;
244+
return $meta['nativeType'] === 'bool'
245+
? fn($value): bool => ($value && $value !== 'f' && $value !== 'F')
246+
: $converter->resolve($meta['nativeType']);
247247
}
248248

249249

src/Database/Drivers/Engines/SQLServerEngine.php

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -218,23 +218,14 @@ public function getForeignKeys(string $table): array
218218
}
219219

220220

221-
public function getColumnTypes(\PDOStatement $statement): array
221+
public function resolveColumnConverter(array $meta, TypeConverter $converter): ?\Closure
222222
{
223-
$types = [];
224-
$count = $statement->columnCount();
225-
for ($col = 0; $col < $count; $col++) {
226-
$meta = $statement->getColumnMeta($col);
227-
if (
228-
isset($meta['sqlsrv:decl_type'])
229-
&& $meta['sqlsrv:decl_type'] !== 'timestamp'
230-
) { // timestamp does not mean time in sqlsrv
231-
$types[$meta['name']] = TypeConverter::detectType($meta['sqlsrv:decl_type']);
232-
} elseif (isset($meta['native_type'])) {
233-
$types[$meta['name']] = TypeConverter::detectType($meta['native_type']);
234-
}
235-
}
236-
237-
return $types;
223+
return match ($meta['nativeType']) {
224+
'timestamp' => null, // timestamp does not mean time in sqlsrv
225+
'decimal', 'numeric',
226+
'double', 'double precision', 'float', 'real', 'money', 'smallmoney' => fn($value): float => (float) (is_string($value) && str_starts_with($value, '.') ? '0' . $value : $value),
227+
default => $converter->resolve($meta['nativeType']),
228+
};
238229
}
239230

240231

src/Database/Drivers/Engines/SQLiteEngine.php

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
namespace Nette\Database\Drivers\Engines;
1111

1212
use Nette;
13+
use Nette\Database\DateTime;
1314
use Nette\Database\Drivers\Connection;
1415
use Nette\Database\Drivers\Engine;
1516
use Nette\Database\TypeConverter;
@@ -228,22 +229,11 @@ public function getForeignKeys(string $table): array
228229
}
229230

230231

231-
public function getColumnTypes(\PDOStatement $statement): array
232+
public function resolveColumnConverter(array $meta, TypeConverter $converter): ?\Closure
232233
{
233-
$types = [];
234-
$count = $statement->columnCount();
235-
for ($col = 0; $col < $count; $col++) {
236-
$meta = $statement->getColumnMeta($col);
237-
if (isset($meta['sqlite:decl_type'])) {
238-
$types[$meta['name']] = $this->formatDateTime === 'U' && in_array($meta['sqlite:decl_type'], ['DATE', 'DATETIME'], strict: true)
239-
? Nette\Database\IStructure::FIELD_UNIX_TIMESTAMP
240-
: TypeConverter::detectType($meta['sqlite:decl_type']);
241-
} elseif (isset($meta['native_type'])) {
242-
$types[$meta['name']] = TypeConverter::detectType($meta['native_type']);
243-
}
244-
}
245-
246-
return $types;
234+
return in_array($meta['nativeType'], ['DATE', 'DATETIME'], true)
235+
? (fn($value): \DateTimeInterface => is_int($value) ? (new DateTime)->setTimestamp($value) : new DateTime($value))
236+
: $converter->resolve($meta['nativeType']);
247237
}
248238

249239

src/Database/Drivers/PDO/Connection.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515

1616
class Connection implements Drivers\Connection
1717
{
18-
protected readonly PDO $pdo;
18+
public readonly PDO $pdo;
19+
public string $metaTypeKey = 'native_type';
1920

2021

2122
public function __construct(

0 commit comments

Comments
 (0)