Skip to content

Commit ae45569

Browse files
authored
Use DateTimeColumn (#407)
1 parent bca4187 commit ae45569

File tree

10 files changed

+122
-81
lines changed

10 files changed

+122
-81
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
- Enh #396: Remove `getCacheKey()` and `getCacheTag()` methods from `Schema` class (@Tigrov)
4040
- Enh #403, #404: Use `DbArrayHelper::arrange()` instead of `DbArrayHelper::index()` method (@Tigrov)
4141
- New #397: Realize `Schema::loadResultColumn()` method (@Tigrov)
42+
- New #407: Use `DateTimeColumn` class for datetime column types (@Tigrov)
4243

4344
## 1.3.0 March 21, 2024
4445

src/Column/ColumnDefinitionBuilder.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ final class ColumnDefinitionBuilder extends AbstractColumnDefinitionBuilder
2525
'bpchar',
2626
'character varying',
2727
'varchar',
28-
'time',
29-
'timetz',
3028
'timestamp',
3129
'timestamptz',
30+
'time',
31+
'timetz',
3232
'interval',
3333
];
3434

@@ -97,10 +97,12 @@ protected function getDbType(ColumnInterface $column): string
9797
ColumnType::TEXT => 'text',
9898
ColumnType::BINARY => 'bytea',
9999
ColumnType::UUID => 'uuid',
100-
ColumnType::DATETIME => 'timestamp',
101100
ColumnType::TIMESTAMP => 'timestamp',
102-
ColumnType::DATE => 'date',
101+
ColumnType::DATETIME => 'timestamp',
102+
ColumnType::DATETIMETZ => 'timestamptz',
103103
ColumnType::TIME => 'time',
104+
ColumnType::TIMETZ => 'timetz',
105+
ColumnType::DATE => 'date',
104106
ColumnType::STRUCTURED => 'jsonb',
105107
ColumnType::JSON => 'jsonb',
106108
default => 'varchar',

src/Column/ColumnFactory.php

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
* columns?: array<string, ColumnInterface>,
2525
* comment?: string|null,
2626
* computed?: bool|string,
27+
* dbTimezone?: string,
2728
* db_type?: string|null,
2829
* default_value?: mixed,
2930
* dimension?: int|string,
@@ -88,16 +89,16 @@ final class ColumnFactory extends AbstractColumnFactory
8889
'varchar' => ColumnType::STRING,
8990
'text' => ColumnType::TEXT,
9091
'bytea' => ColumnType::BINARY,
91-
'date' => ColumnType::DATE,
92+
'abstime' => ColumnType::DATETIME,
93+
'timestamp' => ColumnType::DATETIME,
94+
'timestamp without time zone' => ColumnType::DATETIME,
95+
'timestamp with time zone' => ColumnType::DATETIMETZ,
96+
'timestamptz' => ColumnType::DATETIMETZ,
9297
'time' => ColumnType::TIME,
9398
'time without time zone' => ColumnType::TIME,
94-
'time with time zone' => ColumnType::TIME,
95-
'timetz' => ColumnType::TIME,
96-
'timestamp' => ColumnType::TIMESTAMP,
97-
'timestamp without time zone' => ColumnType::TIMESTAMP,
98-
'timestamp with time zone' => ColumnType::TIMESTAMP,
99-
'timestamptz' => ColumnType::TIMESTAMP,
100-
'abstime' => ColumnType::TIMESTAMP,
99+
'time with time zone' => ColumnType::TIMETZ,
100+
'timetz' => ColumnType::TIMETZ,
101+
'date' => ColumnType::DATE,
101102
'interval' => ColumnType::STRING,
102103
'box' => ColumnType::STRING,
103104
'circle' => ColumnType::STRING,

tests/ColumnTest.php

Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
namespace Yiisoft\Db\Pgsql\Tests;
66

7+
use DateTimeImmutable;
8+
use DateTimeZone;
9+
use PHPUnit\Framework\Attributes\DataProviderExternal;
710
use Throwable;
811
use Yiisoft\Db\Constant\ColumnType;
912
use Yiisoft\Db\Exception\Exception;
@@ -20,25 +23,30 @@
2023
use Yiisoft\Db\Pgsql\Column\IntegerColumn;
2124
use Yiisoft\Db\Pgsql\Column\StructuredColumn;
2225
use Yiisoft\Db\Pgsql\Connection;
26+
use Yiisoft\Db\Pgsql\Tests\Provider\ColumnProvider;
2327
use Yiisoft\Db\Pgsql\Tests\Support\TestTrait;
2428
use Yiisoft\Db\Query\Query;
2529
use Yiisoft\Db\Schema\Column\ColumnInterface;
2630
use Yiisoft\Db\Schema\Column\DoubleColumn;
2731
use Yiisoft\Db\Schema\Column\JsonColumn;
2832
use Yiisoft\Db\Schema\Column\StringColumn;
29-
use Yiisoft\Db\Tests\AbstractColumnTest;
33+
use Yiisoft\Db\Tests\Common\CommonColumnTest;
34+
use Yiisoft\Db\Tests\Support\Assert;
3035

36+
use function str_repeat;
3137
use function stream_get_contents;
3238

3339
/**
3440
* @group pgsql
3541
*
3642
* @psalm-suppress PropertyNotSetInConstructor
3743
*/
38-
final class ColumnTest extends AbstractColumnTest
44+
final class ColumnTest extends CommonColumnTest
3945
{
4046
use TestTrait;
4147

48+
protected const COLUMN_BUILDER = ColumnBuilder::class;
49+
4250
private function insertTypeValues(Connection $db): void
4351
{
4452
$db->createCommand()->insert(
@@ -49,6 +57,8 @@ private function insertTypeValues(Connection $db): void
4957
'char_col3' => null,
5058
'float_col' => 1.234,
5159
'blob_col' => "\x10\x11\x12",
60+
'timestamp_col' => '2023-07-11 14:50:23',
61+
'timestamp_default' => new DateTimeImmutable('2023-07-11 14:50:23'),
5262
'bool_col' => false,
5363
'bit_col' => 0b0110_0100, // 100
5464
'varbit_col' => 0b1_1100_1000, // 456
@@ -64,12 +74,14 @@ private function insertTypeValues(Connection $db): void
6474
)->execute();
6575
}
6676

67-
private function assertResultValues(array $result): void
77+
private function assertTypecastedValues(array $result): void
6878
{
6979
$this->assertSame(1, $result['int_col']);
7080
$this->assertSame(str_repeat('x', 100), $result['char_col']);
7181
$this->assertSame(1.234, $result['float_col']);
7282
$this->assertSame("\x10\x11\x12", stream_get_contents($result['blob_col']));
83+
$this->assertEquals(new DateTimeImmutable('2023-07-11 14:50:23', new DateTimeZone('UTC')), $result['timestamp_col']);
84+
$this->assertEquals(new DateTimeImmutable('2023-07-11 14:50:23'), $result['timestamp_default']);
7385
$this->assertFalse($result['bool_col']);
7486
$this->assertSame(0b0110_0100, $result['bit_col']);
7587
$this->assertSame(0b1_1100_1000, $result['varbit_col']);
@@ -93,11 +105,11 @@ public function testQueryWithTypecasting(): void
93105

94106
$result = $query->one();
95107

96-
$this->assertResultValues($result);
108+
$this->assertTypecastedValues($result);
97109

98110
$result = $query->all();
99111

100-
$this->assertResultValues($result[0]);
112+
$this->assertTypecastedValues($result[0]);
101113

102114
$db->close();
103115
}
@@ -112,11 +124,11 @@ public function testCommandWithPhpTypecasting(): void
112124

113125
$result = $command->queryOne();
114126

115-
$this->assertResultValues($result);
127+
$this->assertTypecastedValues($result);
116128

117129
$result = $command->queryAll();
118130

119-
$this->assertResultValues($result[0]);
131+
$this->assertTypecastedValues($result[0]);
120132

121133
$db->close();
122134
}
@@ -190,43 +202,19 @@ public function testPhpTypeCast(): void
190202
{
191203
$db = $this->getConnection(true);
192204
$schema = $db->getSchema();
193-
$tableSchema = $schema->getTableSchema('type');
205+
$columns = $schema->getTableSchema('type')->getColumns();
194206

195207
$this->insertTypeValues($db);
196208

197209
$query = (new Query($db))->from('type')->one();
198210

199-
$intColPhpTypeCast = $tableSchema->getColumn('int_col')?->phpTypecast($query['int_col']);
200-
$charColPhpTypeCast = $tableSchema->getColumn('char_col')?->phpTypecast($query['char_col']);
201-
$floatColPhpTypeCast = $tableSchema->getColumn('float_col')?->phpTypecast($query['float_col']);
202-
$blobColPhpTypeCast = $tableSchema->getColumn('blob_col')?->phpTypecast($query['blob_col']);
203-
$boolColPhpTypeCast = $tableSchema->getColumn('bool_col')?->phpTypecast($query['bool_col']);
204-
$bitColPhpTypeCast = $tableSchema->getColumn('bit_col')?->phpTypecast($query['bit_col']);
205-
$varbitColPhpTypeCast = $tableSchema->getColumn('varbit_col')?->phpTypecast($query['varbit_col']);
206-
$numericColPhpTypeCast = $tableSchema->getColumn('numeric_col')?->phpTypecast($query['numeric_col']);
207-
$intArrayColPhpType = $tableSchema->getColumn('intarray_col')?->phpTypecast($query['intarray_col']);
208-
$numericArrayColPhpTypeCast = $tableSchema->getColumn('numericarray_col')?->phpTypecast($query['numericarray_col']);
209-
$varcharArrayColPhpTypeCast = $tableSchema->getColumn('varchararray_col')?->phpTypecast($query['varchararray_col']);
210-
$textArray2ColPhpType = $tableSchema->getColumn('textarray2_col')?->phpTypecast($query['textarray2_col']);
211-
$jsonColPhpType = $tableSchema->getColumn('json_col')?->phpTypecast($query['json_col']);
212-
$jsonBColPhpType = $tableSchema->getColumn('jsonb_col')?->phpTypecast($query['jsonb_col']);
213-
$jsonArrayColPhpType = $tableSchema->getColumn('jsonarray_col')?->phpTypecast($query['jsonarray_col']);
214-
215-
$this->assertSame(1, $intColPhpTypeCast);
216-
$this->assertSame(str_repeat('x', 100), $charColPhpTypeCast);
217-
$this->assertSame(1.234, $floatColPhpTypeCast);
218-
$this->assertSame("\x10\x11\x12", stream_get_contents($blobColPhpTypeCast));
219-
$this->assertFalse($boolColPhpTypeCast);
220-
$this->assertSame(0b0110_0100, $bitColPhpTypeCast);
221-
$this->assertSame(0b1_1100_1000, $varbitColPhpTypeCast);
222-
$this->assertSame(33.22, $numericColPhpTypeCast);
223-
$this->assertSame([1, -2, null, 42], $intArrayColPhpType);
224-
$this->assertSame([null, 1.2, -2.2, null, null], $numericArrayColPhpTypeCast);
225-
$this->assertSame(['', 'some text', '""', '\\\\', '[",","null",true,"false","f"]', null], $varcharArrayColPhpTypeCast);
226-
$this->assertNull($textArray2ColPhpType);
227-
$this->assertSame([['a' => 1, 'b' => null, 'c' => [1, 3, 5]]], $jsonColPhpType);
228-
$this->assertSame(['1', '2', '3'], $jsonBColPhpType);
229-
$this->assertSame([[[',', 'null', true, 'false', 'f']]], $jsonArrayColPhpType);
211+
$result = [];
212+
213+
foreach ($columns as $columnName => $column) {
214+
$result[$columnName] = $column->phpTypecast($query[$columnName]);
215+
}
216+
217+
$this->assertTypecastedValues($result);
230218

231219
$db->close();
232220
}
@@ -430,32 +418,48 @@ public function testColumnInstance()
430418
$db->close();
431419
}
432420

433-
/** @dataProvider \Yiisoft\Db\Pgsql\Tests\Provider\ColumnProvider::predefinedTypes */
421+
#[DataProviderExternal(ColumnProvider::class, 'predefinedTypes')]
434422
public function testPredefinedType(string $className, string $type, string $phpType)
435423
{
436424
parent::testPredefinedType($className, $type, $phpType);
437425
}
438426

439-
/** @dataProvider \Yiisoft\Db\Pgsql\Tests\Provider\ColumnProvider::dbTypecastColumns */
427+
#[DataProviderExternal(ColumnProvider::class, 'dbTypecastColumns')]
440428
public function testDbTypecastColumns(ColumnInterface $column, array $values)
441429
{
442430
parent::testDbTypecastColumns($column, $values);
443431
}
444432

445-
/** @dataProvider \Yiisoft\Db\Pgsql\Tests\Provider\ColumnProvider::phpTypecastColumns */
433+
#[DataProviderExternal(ColumnProvider::class, 'phpTypecastColumns')]
446434
public function testPhpTypecastColumns(ColumnInterface $column, array $values)
447435
{
448436
parent::testPhpTypecastColumns($column, $values);
449437
}
450438

451-
/** @dataProvider \Yiisoft\Db\Pgsql\Tests\Provider\ColumnProvider::phpTypecastArrayColumns */
439+
#[DataProviderExternal(ColumnProvider::class, 'dbTypecastArrayColumns')]
440+
public function testArrayColumnDbTypecast(ColumnInterface $column, array $values): void
441+
{
442+
$arrayCol = (new ArrayColumn())->column($column);
443+
444+
foreach ($values as [$dimension, $expected, $value]) {
445+
$arrayCol->dimension($dimension);
446+
$dbValue = $arrayCol->dbTypecast($value);
447+
448+
$this->assertInstanceOf(ArrayExpression::class, $dbValue);
449+
$this->assertSame($arrayCol, $dbValue->getType());
450+
$this->assertEquals($value, $dbValue->getValue());
451+
}
452+
}
453+
454+
#[DataProviderExternal(ColumnProvider::class, 'phpTypecastArrayColumns')]
452455
public function testPhpTypecastArrayColumn(ColumnInterface $column, array $values): void
453456
{
454457
$arrayCol = ColumnBuilder::array($column);
455458

456459
foreach ($values as [$dimension, $expected, $value]) {
457460
$arrayCol->dimension($dimension);
458-
$this->assertSame($expected, $arrayCol->phpTypecast($value));
461+
462+
Assert::arraysEquals($expected, $arrayCol->phpTypecast($value));
459463
}
460464
}
461465

tests/Provider/ColumnFactoryProvider.php

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Yiisoft\Db\Pgsql\Column\BooleanColumn;
1313
use Yiisoft\Db\Pgsql\Column\IntegerColumn;
1414
use Yiisoft\Db\Pgsql\Column\StructuredColumn;
15+
use Yiisoft\Db\Schema\Column\DateTimeColumn;
1516
use Yiisoft\Db\Schema\Column\DoubleColumn;
1617
use Yiisoft\Db\Schema\Column\JsonColumn;
1718
use Yiisoft\Db\Schema\Column\StringColumn;
@@ -55,16 +56,16 @@ public static function dbTypes(): array
5556
['varchar', ColumnType::STRING, StringColumn::class],
5657
['text', ColumnType::TEXT, StringColumn::class],
5758
['bytea', ColumnType::BINARY, BinaryColumn::class],
58-
['date', ColumnType::DATE, StringColumn::class],
59-
['time', ColumnType::TIME, StringColumn::class],
60-
['time without time zone', ColumnType::TIME, StringColumn::class],
61-
['time with time zone', ColumnType::TIME, StringColumn::class],
62-
['timetz', ColumnType::TIME, StringColumn::class],
63-
['timestamp', ColumnType::TIMESTAMP, StringColumn::class],
64-
['timestamp without time zone', ColumnType::TIMESTAMP, StringColumn::class],
65-
['timestamp with time zone', ColumnType::TIMESTAMP, StringColumn::class],
66-
['timestamptz', ColumnType::TIMESTAMP, StringColumn::class],
67-
['abstime', ColumnType::TIMESTAMP, StringColumn::class],
59+
['abstime', ColumnType::DATETIME, DateTimeColumn::class],
60+
['timestamp', ColumnType::DATETIME, DateTimeColumn::class],
61+
['timestamp without time zone', ColumnType::DATETIME, DateTimeColumn::class],
62+
['timestamp with time zone', ColumnType::DATETIMETZ, DateTimeColumn::class],
63+
['timestamptz', ColumnType::DATETIMETZ, DateTimeColumn::class],
64+
['time', ColumnType::TIME, DateTimeColumn::class],
65+
['time without time zone', ColumnType::TIME, DateTimeColumn::class],
66+
['time with time zone', ColumnType::TIMETZ, DateTimeColumn::class],
67+
['timetz', ColumnType::TIMETZ, DateTimeColumn::class],
68+
['date', ColumnType::DATE, DateTimeColumn::class],
6869
['interval', ColumnType::STRING, StringColumn::class],
6970
['box', ColumnType::STRING, StringColumn::class],
7071
['circle', ColumnType::STRING, StringColumn::class],

tests/Provider/ColumnProvider.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace Yiisoft\Db\Pgsql\Tests\Provider;
66

7+
use DateTimeImmutable;
8+
use DateTimeZone;
79
use Yiisoft\Db\Expression\Expression;
810
use Yiisoft\Db\Pgsql\Column\ArrayColumn;
911
use Yiisoft\Db\Pgsql\Column\ArrayLazyColumn;
@@ -16,6 +18,7 @@
1618
use Yiisoft\Db\Pgsql\Column\StructuredLazyColumn;
1719
use Yiisoft\Db\Pgsql\Data\LazyArray;
1820
use Yiisoft\Db\Pgsql\Data\StructuredLazyArray;
21+
use Yiisoft\Db\Schema\Column\DateTimeColumn;
1922
use Yiisoft\Db\Schema\Column\DoubleColumn;
2023
use Yiisoft\Db\Schema\Column\JsonColumn;
2124
use Yiisoft\Db\Schema\Column\StringColumn;
@@ -125,6 +128,8 @@ public static function phpTypecastColumns(): array
125128

126129
public static function phpTypecastArrayColumns()
127130
{
131+
$utcTimezone = new DateTimeZone('UTC');
132+
128133
return [
129134
// [column, values]
130135
[
@@ -170,6 +175,28 @@ public static function phpTypecastArrayColumns()
170175
[2, [["\x10\x11"], ['', null]], '{{\x1011},{"",}}'],
171176
],
172177
],
178+
[
179+
new DateTimeColumn(),
180+
[
181+
[
182+
1,
183+
[
184+
new DateTimeImmutable('2025-04-19 14:11:35', $utcTimezone),
185+
new DateTimeImmutable('2025-04-19 00:00:00', $utcTimezone),
186+
null,
187+
],
188+
'{2025-04-19 14:11:35,2025-04-19 00:00:00,}',
189+
],
190+
[
191+
2,
192+
[
193+
[new DateTimeImmutable('2025-04-19 14:11:35', $utcTimezone)],
194+
[new DateTimeImmutable('2025-04-19 00:00:00', $utcTimezone), null],
195+
],
196+
'{{2025-04-19 14:11:35},{2025-04-19 00:00:00,}}',
197+
],
198+
],
199+
],
173200
[
174201
new JsonColumn(),
175202
[

tests/Provider/QueryBuilderProvider.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,9 @@ public static function buildColumnDefinition(): array
374374
$values['datetime()'][0] = 'timestamp(0)';
375375
$values['datetime(6)'][0] = 'timestamp(6)';
376376
$values['datetime(null)'][0] = 'timestamp';
377+
$values['datetimeWithTimezone()'][0] = 'timestamptz(0)';
378+
$values['datetimeWithTimezone(6)'][0] = 'timestamptz(6)';
379+
$values['datetimeWithTimezone(null)'][0] = 'timestamptz';
377380
$values['array()'][0] = 'varchar[]';
378381
$values['structured()'][0] = 'jsonb';
379382
$values['json()'][0] = 'jsonb';

0 commit comments

Comments
 (0)