Skip to content

Commit 3a16951

Browse files
authored
Use DateTimeColumn (#355)
1 parent ac7b5f8 commit 3a16951

File tree

7 files changed

+86
-54
lines changed

7 files changed

+86
-54
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
- Enh #350, #351: Use `DbArrayHelper::arrange()` instead of `DbArrayHelper::index()` method (@Tigrov)
3838
- New #348: Realize `Schema::loadResultColumn()` method (@Tigrov)
3939
- New #354: Add `FOR` clause to query (@vjik)
40+
- New #355: Use `DateTimeColumn` class for datetime column types (@Tigrov)
4041

4142
## 1.2.0 March 21, 2024
4243

src/Column/ColumnDefinitionBuilder.php

+8-4
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,11 @@ final class ColumnDefinitionBuilder extends AbstractColumnDefinitionBuilder
2929
'varchar',
3030
'text',
3131
'blob',
32-
'time',
33-
'datetime',
3432
'timestamp',
33+
'datetime',
34+
'datetimetz',
35+
'time',
36+
'timetz',
3537
];
3638

3739
protected const TYPES_WITH_SCALE = [
@@ -87,10 +89,12 @@ protected function getDbType(ColumnInterface $column): string
8789
ColumnType::TEXT => 'text',
8890
ColumnType::BINARY => 'blob',
8991
ColumnType::UUID => 'blob(16)',
90-
ColumnType::DATETIME => 'datetime',
9192
ColumnType::TIMESTAMP => 'timestamp',
92-
ColumnType::DATE => 'date',
93+
ColumnType::DATETIME => 'datetime',
94+
ColumnType::DATETIMETZ => 'datetimetz',
9395
ColumnType::TIME => 'time',
96+
ColumnType::TIMETZ => 'timetz',
97+
ColumnType::DATE => 'date',
9498
ColumnType::ARRAY => 'json',
9599
ColumnType::STRUCTURED => 'json',
96100
ColumnType::JSON => 'json',

src/Column/ColumnFactory.php

+9-1
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,12 @@ final class ColumnFactory extends AbstractColumnFactory
4242
'longtext' => ColumnType::TEXT,
4343
'text' => ColumnType::TEXT,
4444
'blob' => ColumnType::BINARY,
45-
'year' => ColumnType::DATE,
45+
'year' => ColumnType::SMALLINT,
4646
'date' => ColumnType::DATE,
4747
'time' => ColumnType::TIME,
48+
'timetz' => ColumnType::TIMETZ,
4849
'datetime' => ColumnType::DATETIME,
50+
'datetimetz' => ColumnType::DATETIMETZ,
4951
'timestamp' => ColumnType::TIMESTAMP,
5052
'json' => ColumnType::JSON,
5153
];
@@ -56,6 +58,12 @@ protected function getType(string $dbType, array $info = []): string
5658
'bit', 'tinyint' => isset($info['size']) && $info['size'] === 1
5759
? ColumnType::BOOLEAN
5860
: parent::getType($dbType, $info),
61+
'text' => match ($info['defaultValueRaw'] ?? null) {
62+
'CURRENT_TIMESTAMP' => ColumnType::DATETIMETZ,
63+
'CURRENT_DATE' => ColumnType::DATE,
64+
'CURRENT_TIME' => ColumnType::TIMETZ,
65+
default => parent::getType($dbType, $info),
66+
},
5967
default => parent::getType($dbType, $info),
6068
};
6169
}

tests/ColumnTest.php

+29-31
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace Yiisoft\Db\Sqlite\Tests;
66

7+
use DateTimeImmutable;
8+
use DateTimeZone;
79
use PDO;
810
use Yiisoft\Db\Command\Param;
911
use Yiisoft\Db\Schema\Column\BinaryColumn;
@@ -12,20 +14,23 @@
1214
use Yiisoft\Db\Schema\Column\IntegerColumn;
1315
use Yiisoft\Db\Schema\Column\JsonColumn;
1416
use Yiisoft\Db\Schema\Column\StringColumn;
17+
use Yiisoft\Db\Sqlite\Column\ColumnBuilder;
1518
use Yiisoft\Db\Sqlite\Connection;
1619
use Yiisoft\Db\Sqlite\Tests\Support\TestTrait;
1720
use Yiisoft\Db\Query\Query;
18-
use Yiisoft\Db\Tests\AbstractColumnTest;
21+
use Yiisoft\Db\Tests\Common\CommonColumnTest;
1922

2023
use function str_repeat;
2124

2225
/**
2326
* @group sqlite
2427
*/
25-
final class ColumnTest extends AbstractColumnTest
28+
final class ColumnTest extends CommonColumnTest
2629
{
2730
use TestTrait;
2831

32+
protected const COLUMN_BUILDER = ColumnBuilder::class;
33+
2934
private function insertTypeValues(Connection $db): void
3035
{
3136
$command = $db->createCommand();
@@ -39,6 +44,7 @@ private function insertTypeValues(Connection $db): void
3944
'float_col' => 1.234,
4045
'blob_col' => "\x10\x11\x12",
4146
'timestamp_col' => '2023-07-11 14:50:23',
47+
'timestamp_default' => new DateTimeImmutable('2023-07-11 14:50:23'),
4248
'bool_col' => false,
4349
'bit_col' => 0b0110_0110, // 102
4450
'json_col' => [['a' => 1, 'b' => null, 'c' => [1, 3, 5]]],
@@ -48,18 +54,24 @@ private function insertTypeValues(Connection $db): void
4854
$command->execute();
4955
}
5056

51-
private function assertResultValues(array $result): void
57+
private function assertTypecastedValues(array $result, bool $allTypecasted = false): void
5258
{
5359
$this->assertSame(1, $result['int_col']);
5460
$this->assertSame(str_repeat('x', 100), $result['char_col']);
5561
$this->assertNull($result['char_col3']);
5662
$this->assertSame(1.234, $result['float_col']);
5763
$this->assertSame("\x10\x11\x12", $result['blob_col']);
58-
$this->assertSame('2023-07-11 14:50:23', $result['timestamp_col']);
64+
$this->assertEquals(new DateTimeImmutable('2023-07-11 14:50:23', new DateTimeZone('UTC')), $result['timestamp_col']);
65+
$this->assertEquals(new DateTimeImmutable('2023-07-11 14:50:23'), $result['timestamp_default']);
5966
$this->assertFalse($result['bool_col']);
6067
$this->assertSame(0b0110_0110, $result['bit_col']);
6168
$this->assertSame([['a' => 1, 'b' => null, 'c' => [1, 3, 5]]], $result['json_col']);
62-
$this->assertSame('[1,2,3,"string",null]', $result['json_text_col']);
69+
70+
if ($allTypecasted) {
71+
$this->assertSame([1, 2, 3, 'string', null], $result['json_text_col']);
72+
} else {
73+
$this->assertSame('[1,2,3,"string",null]', $result['json_text_col']);
74+
}
6375
}
6476

6577
public function testQueryWithTypecasting(): void
@@ -72,11 +84,11 @@ public function testQueryWithTypecasting(): void
7284

7385
$result = $query->one();
7486

75-
$this->assertResultValues($result);
87+
$this->assertTypecastedValues($result);
7688

7789
$result = $query->all();
7890

79-
$this->assertResultValues($result[0]);
91+
$this->assertTypecastedValues($result[0]);
8092

8193
$db->close();
8294
}
@@ -91,11 +103,11 @@ public function testCommandWithPhpTypecasting(): void
91103

92104
$result = $command->queryOne();
93105

94-
$this->assertResultValues($result);
106+
$this->assertTypecastedValues($result);
95107

96108
$result = $command->queryAll();
97109

98-
$this->assertResultValues($result[0]);
110+
$this->assertTypecastedValues($result[0]);
99111

100112
$db->close();
101113
}
@@ -130,33 +142,19 @@ public function testPhpTypeCast(): void
130142
{
131143
$db = $this->getConnection(true);
132144
$schema = $db->getSchema();
133-
$tableSchema = $schema->getTableSchema('type');
145+
$columns = $schema->getTableSchema('type')->getColumns();
134146

135147
$this->insertTypeValues($db);
136148

137149
$query = (new Query($db))->from('type')->one();
138150

139-
$intColPhpType = $tableSchema->getColumn('int_col')?->phpTypecast($query['int_col']);
140-
$charColPhpType = $tableSchema->getColumn('char_col')?->phpTypecast($query['char_col']);
141-
$charCol3PhpType = $tableSchema->getColumn('char_col3')?->phpTypecast($query['char_col3']);
142-
$floatColPhpType = $tableSchema->getColumn('float_col')?->phpTypecast($query['float_col']);
143-
$blobColPhpType = $tableSchema->getColumn('blob_col')?->phpTypecast($query['blob_col']);
144-
$timestampColPhpType = $tableSchema->getColumn('timestamp_col')?->phpTypecast($query['timestamp_col']);
145-
$boolColPhpType = $tableSchema->getColumn('bool_col')?->phpTypecast($query['bool_col']);
146-
$bitColPhpType = $tableSchema->getColumn('bit_col')?->phpTypecast($query['bit_col']);
147-
$jsonColPhpType = $tableSchema->getColumn('json_col')?->phpTypecast($query['json_col']);
148-
$jsonTextColPhpType = $tableSchema->getColumn('json_text_col')?->phpTypecast($query['json_text_col']);
149-
150-
$this->assertSame(1, $intColPhpType);
151-
$this->assertSame(str_repeat('x', 100), $charColPhpType);
152-
$this->assertNull($charCol3PhpType);
153-
$this->assertSame(1.234, $floatColPhpType);
154-
$this->assertSame("\x10\x11\x12", $blobColPhpType);
155-
$this->assertSame('2023-07-11 14:50:23', $timestampColPhpType);
156-
$this->assertFalse($boolColPhpType);
157-
$this->assertSame(0b0110_0110, $bitColPhpType);
158-
$this->assertSame([['a' => 1, 'b' => null, 'c' => [1, 3, 5]]], $jsonColPhpType);
159-
$this->assertSame([1, 2, 3, 'string', null], $jsonTextColPhpType);
151+
$result = [];
152+
153+
foreach ($columns as $columnName => $column) {
154+
$result[$columnName] = $column->phpTypecast($query[$columnName]);
155+
}
156+
157+
$this->assertTypecastedValues($result, true);
160158

161159
$db->close();
162160
}

tests/Provider/ColumnFactoryProvider.php

+8-5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Yiisoft\Db\Schema\Column\BinaryColumn;
99
use Yiisoft\Db\Schema\Column\BitColumn;
1010
use Yiisoft\Db\Schema\Column\BooleanColumn;
11+
use Yiisoft\Db\Schema\Column\DatetimeColumn;
1112
use Yiisoft\Db\Schema\Column\DoubleColumn;
1213
use Yiisoft\Db\Schema\Column\IntegerColumn;
1314
use Yiisoft\Db\Schema\Column\JsonColumn;
@@ -42,11 +43,13 @@ public static function dbTypes(): array
4243
['longtext', ColumnType::TEXT, StringColumn::class],
4344
['text', ColumnType::TEXT, StringColumn::class],
4445
['blob', ColumnType::BINARY, BinaryColumn::class],
45-
['year', ColumnType::DATE, StringColumn::class],
46-
['date', ColumnType::DATE, StringColumn::class],
47-
['time', ColumnType::TIME, StringColumn::class],
48-
['datetime', ColumnType::DATETIME, StringColumn::class],
49-
['timestamp', ColumnType::TIMESTAMP, StringColumn::class],
46+
['year', ColumnType::SMALLINT, IntegerColumn::class],
47+
['date', ColumnType::DATE, DatetimeColumn::class],
48+
['time', ColumnType::TIME, DatetimeColumn::class],
49+
['timetz', ColumnType::TIMETZ, DatetimeColumn::class],
50+
['datetime', ColumnType::DATETIME, DatetimeColumn::class],
51+
['datetimetz', ColumnType::DATETIMETZ, DatetimeColumn::class],
52+
['timestamp', ColumnType::TIMESTAMP, DatetimeColumn::class],
5053
['json', ColumnType::JSON, JsonColumn::class],
5154
];
5255
}

tests/Provider/SchemaProvider.php

+27-11
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44

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

7+
use DateTimeImmutable;
78
use Yiisoft\Db\Constant\ColumnType;
89
use Yiisoft\Db\Expression\Expression;
910
use Yiisoft\Db\Schema\Column\ArrayColumn;
1011
use Yiisoft\Db\Schema\Column\BinaryColumn;
1112
use Yiisoft\Db\Schema\Column\BitColumn;
1213
use Yiisoft\Db\Schema\Column\BooleanColumn;
14+
use Yiisoft\Db\Schema\Column\DatetimeColumn;
1315
use Yiisoft\Db\Schema\Column\DoubleColumn;
1416
use Yiisoft\Db\Schema\Column\IntegerColumn;
1517
use Yiisoft\Db\Schema\Column\JsonColumn;
@@ -78,11 +80,19 @@ public static function columns(): array
7880
scale: 2,
7981
defaultValue: 33.22,
8082
),
81-
'timestamp_col' => new StringColumn(
83+
'timestamp_col' => new DatetimeColumn(
8284
ColumnType::TIMESTAMP,
8385
dbType: 'timestamp',
8486
notNull: true,
85-
defaultValue: '2002-01-01 00:00:00',
87+
defaultValue: new DateTimeImmutable('2002-01-01 00:00:00'),
88+
hasTimezone: false,
89+
shouldConvertTimezone: true,
90+
),
91+
'timestamp_default' => new DatetimeColumn(
92+
ColumnType::TIMESTAMP,
93+
dbType: 'timestamp',
94+
notNull: true,
95+
defaultValue: new Expression('CURRENT_TIMESTAMP'),
8696
),
8797
'bool_col' => new BooleanColumn(
8898
dbType: 'tinyint',
@@ -94,12 +104,6 @@ public static function columns(): array
94104
size: 1,
95105
defaultValue: true,
96106
),
97-
'ts_default' => new StringColumn(
98-
ColumnType::TIMESTAMP,
99-
dbType: 'timestamp',
100-
notNull: true,
101-
defaultValue: new Expression('CURRENT_TIMESTAMP'),
102-
),
103107
'bit_col' => new BitColumn(
104108
dbType: 'bit',
105109
notNull: true,
@@ -146,12 +150,24 @@ public static function columns(): array
146150
notNull: true,
147151
defaultValue: 'CURRENT_TIMESTAMP',
148152
),
149-
'timestamp_text' => new StringColumn(
150-
ColumnType::TEXT,
153+
'timestamp_text' => new DatetimeColumn(
154+
ColumnType::DATETIMETZ,
151155
dbType: 'text',
152156
notNull: true,
153157
defaultValue: new Expression('CURRENT_TIMESTAMP'),
154158
),
159+
'time_text' => new DatetimeColumn(
160+
ColumnType::TIMETZ,
161+
dbType: 'text',
162+
notNull: true,
163+
defaultValue: new Expression('CURRENT_TIME'),
164+
),
165+
'date_text' => new DatetimeColumn(
166+
ColumnType::DATE,
167+
dbType: 'text',
168+
notNull: true,
169+
defaultValue: new Expression('CURRENT_DATE'),
170+
),
155171
],
156172
'timestamp_default',
157173
],
@@ -266,7 +282,7 @@ public static function resultColumns(): array
266282
'len' => -1,
267283
'precision' => 0,
268284
]],
269-
[new StringColumn(ColumnType::TIMESTAMP, dbType: 'timestamp', name: 'timestamp_col'), [
285+
[new DatetimeColumn(ColumnType::TIMESTAMP, dbType: 'timestamp', name: 'timestamp_col'), [
270286
'native_type' => 'null',
271287
'pdo_type' => 0,
272288
'sqlite:decl_type' => 'timestamp',

tests/Support/Fixture/sqlite.sql

+4-2
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,9 @@ CREATE TABLE "type" (
134134
blob_col blob,
135135
numeric_col decimal(5,2) DEFAULT '33.22',
136136
timestamp_col timestamp NOT NULL DEFAULT '2002-01-01 00:00:00',
137+
timestamp_default TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
137138
bool_col tinyint(1) NOT NULL,
138139
bool_col2 tinyint(1) DEFAULT '1',
139-
ts_default TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
140140
bit_col BIT(8) NOT NULL DEFAULT 130, -- 0b1000_0010
141141
json_col json NOT NULL DEFAULT '{"number":10}',
142142
json_text_col text CHECK(json_text_col IS NULL OR json_valid(json_text_col)) -- for STRICT table
@@ -173,7 +173,9 @@ CREATE TABLE "notauto_pk" (
173173
CREATE TABLE "timestamp_default" (
174174
id INTEGER PRIMARY KEY,
175175
text_col TEXT NOT NULL DEFAULT 'CURRENT_TIMESTAMP',
176-
timestamp_text TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
176+
timestamp_text TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
177+
time_text TEXT NOT NULL DEFAULT CURRENT_TIME,
178+
date_text TEXT NOT NULL DEFAULT CURRENT_DATE
177179
); -- STRICT
178180

179181
CREATE TABLE "json_type" (

0 commit comments

Comments
 (0)