Skip to content

Support DateTime instances #269

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/ColumnSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

use Yiisoft\Db\Schema\AbstractColumnSchema;

use function str_contains;

/**
* Represents the metadata of a column in a database table for SQLite Server.
*
Expand All @@ -32,4 +34,8 @@
*/
final class ColumnSchema extends AbstractColumnSchema
{
public function hasTimezone(): bool
{
return str_contains((string) $this->getDbType(), 'tz');
}
}
68 changes: 37 additions & 31 deletions src/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,12 @@ final class Schema extends AbstractPdoSchema
'char' => self::TYPE_CHAR,
'blob' => self::TYPE_BINARY,
'datetime' => self::TYPE_DATETIME,
'year' => self::TYPE_DATE,
'year' => self::TYPE_SMALLINT,
'date' => self::TYPE_DATE,
'time' => self::TYPE_TIME,
'timetz' => self::TYPE_TIME,
'timestamp' => self::TYPE_TIMESTAMP,
'timestamptz' => self::TYPE_TIMESTAMP,
'enum' => self::TYPE_STRING,
];

Expand Down Expand Up @@ -457,42 +459,46 @@ public function getSchemaDefaultValues(string $schema = '', bool $refresh = fals
*/
protected function loadColumnSchema(array $info): ColumnSchemaInterface
{
$dbType = strtolower($info['type']);

$column = $this->createColumnSchema($info['name']);
$column->allowNull(!$info['notnull']);
$column->primaryKey($info['pk'] != '0');
$column->dbType(strtolower($info['type']));
$column->unsigned(str_contains($column->getDbType() ?? '', 'unsigned'));
$column->type(self::TYPE_STRING);

if (preg_match('/^(\w+)(?:\(([^)]+)\))?/', $column->getDbType() ?? '', $matches)) {
$type = strtolower($matches[1]);

if (isset($this->typeMap[$type])) {
$column->type($this->typeMap[$type]);
$column->dbType($dbType);
$column->unsigned(str_contains($dbType, 'unsigned'));

preg_match('/^(\w*)(?:\(([^)]+)\))?/', $dbType, $matches);
$type = $matches[1];

$column->type(match ($info['dflt_value']) {
'CURRENT_TIMESTAMP' => self::TYPE_TIMESTAMP,
'CURRENT_DATE' => self::TYPE_DATE,
'CURRENT_TIME' => self::TYPE_TIME,
default => $this->typeMap[$type] ?? self::TYPE_STRING,
});

if (!empty($matches[2])) {
$values = explode(',', $matches[2]);
$column->precision((int) $values[0]);
$column->size((int) $values[0]);

if (isset($values[1])) {
$column->scale((int) $values[1]);
}

if (!empty($matches[2])) {
$values = explode(',', $matches[2]);
$column->precision((int) $values[0]);
$column->size((int) $values[0]);

if (isset($values[1])) {
$column->scale((int) $values[1]);
}

if (($type === 'tinyint' || $type === 'bit') && $column->getSize() === 1) {
$column->type(self::TYPE_BOOLEAN);
} elseif ($type === 'bit') {
if ($column->getSize() > 32) {
$column->type(self::TYPE_BIGINT);
} elseif ($column->getSize() === 32) {
$column->type(self::TYPE_INTEGER);
}
if (($type === 'tinyint' || $type === 'bit') && $column->getSize() === 1) {
$column->type(self::TYPE_BOOLEAN);
} elseif ($type === 'bit') {
if ($column->getSize() > 32) {
$column->type(self::TYPE_BIGINT);
} elseif ($column->getSize() === 32) {
$column->type(self::TYPE_INTEGER);
}
}
}

$column->phpType($this->getColumnPhpType($column));
$column->dateTimeFormat($this->getDateTimeFormat($column));
$column->defaultValue($this->normalizeDefaultValue($info['dflt_value'], $column));

return $column;
Expand All @@ -512,11 +518,11 @@ private function normalizeDefaultValue(string|null $defaultValue, ColumnSchemaIn
return null;
}

if (in_array($defaultValue, ['CURRENT_TIMESTAMP', 'CURRENT_DATE', 'CURRENT_TIME'], true)) {
return new Expression($defaultValue);
}
$value = preg_replace('/^([\'"])(.*)\1$/s', '$2', $defaultValue, 1);

$value = preg_replace('/^([\'"])(.*)\1$/s', '$2', $defaultValue);
if ($column->getDateTimeFormat() !== null) {
return date_create_immutable($value) ?: new Expression($defaultValue);
}

return $column->phpTypecast($value);
}
Expand Down
17 changes: 16 additions & 1 deletion tests/ColumnSchemaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Yiisoft\Db\Sqlite\Tests;

use DateTimeImmutable;
use PHPUnit\Framework\TestCase;
use Yiisoft\Db\Sqlite\Tests\Support\TestTrait;
use Yiisoft\Db\Query\Query;
Expand Down Expand Up @@ -34,6 +35,10 @@ public function testPhpTypeCast(): void
'float_col' => 1.234,
'blob_col' => "\x10\x11\x12",
'timestamp_col' => '2023-07-11 14:50:23',
'datetime_col' => new DateTimeImmutable('2023-07-11 14:50:23.123 +02:00'),
'timestamptz_col' => new DateTimeImmutable('2023-07-11 14:50:23.12 -2:30'),
'date_col' => new DateTimeImmutable('2023-07-11'),
'time_col' => new DateTimeImmutable('14:50:23'),
'bool_col' => false,
]
);
Expand All @@ -48,14 +53,24 @@ public function testPhpTypeCast(): void
$floatColPhpType = $tableSchema->getColumn('float_col')?->phpTypecast($query['float_col']);
$blobColPhpType = $tableSchema->getColumn('blob_col')?->phpTypecast($query['blob_col']);
$timestampColPhpType = $tableSchema->getColumn('timestamp_col')?->phpTypecast($query['timestamp_col']);
$datetimeColPhpType = $tableSchema->getColumn('datetime_col')?->phpTypecast($query['datetime_col']);
$timestamptzColPhpType = $tableSchema->getColumn('timestamptz_col')?->phpTypecast($query['timestamptz_col']);
$dateColPhpType = $tableSchema->getColumn('date_col')?->phpTypecast($query['date_col']);
$timeColPhpType = $tableSchema->getColumn('time_col')?->phpTypecast($query['time_col']);
$tsDefaultPhpType = $tableSchema->getColumn('ts_default')?->phpTypecast($query['ts_default']);
$boolColPhpType = $tableSchema->getColumn('bool_col')?->phpTypecast($query['bool_col']);

$this->assertSame(1, $intColPhpType);
$this->assertSame(str_repeat('x', 100), $charColPhpType);
$this->assertNull($charCol3PhpType);
$this->assertSame(1.234, $floatColPhpType);
$this->assertSame("\x10\x11\x12", $blobColPhpType);
$this->assertSame('2023-07-11 14:50:23', $timestampColPhpType);
$this->assertEquals(new DateTimeImmutable('2023-07-11 14:50:23'), $timestampColPhpType);
$this->assertEquals(new DateTimeImmutable('2023-07-11 14:50:23.123 +02:00'), $datetimeColPhpType);
$this->assertEquals(new DateTimeImmutable('2023-07-11 14:50:23.12 -2:30'), $timestamptzColPhpType);
$this->assertEquals(new DateTimeImmutable('2023-07-11'), $dateColPhpType);
$this->assertEquals(new DateTimeImmutable('14:50:23'), $timeColPhpType);
$this->assertInstanceOf(DateTimeImmutable::class, $tsDefaultPhpType);
$this->assertFalse($boolColPhpType);

$db->close();
Expand Down
82 changes: 77 additions & 5 deletions tests/Provider/SchemaProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Yiisoft\Db\Sqlite\Tests\Provider;

use DateTimeImmutable;
use Yiisoft\Db\Expression\Expression;
use Yiisoft\Db\Tests\Support\AnyValue;

Expand Down Expand Up @@ -160,15 +161,86 @@ public static function columns(): array
'timestamp_col' => [
'type' => 'timestamp',
'dbType' => 'timestamp',
'phpType' => 'string',
'phpType' => 'DateTimeInterface',
'primaryKey' => false,
'allowNull' => false,
'autoIncrement' => false,
'enumValues' => null,
'size' => null,
'precision' => null,
'scale' => null,
'defaultValue' => new DateTimeImmutable('2002-01-01 00:00:00'),
'dateTimeFormat' => 'Y-m-d H:i:s',
],
'datetime_col' => [
'type' => 'datetime',
'dbType' => 'datetime(3)',
'phpType' => 'DateTimeInterface',
'primaryKey' => false,
'allowNull' => false,
'autoIncrement' => false,
'enumValues' => null,
'size' => 3,
'precision' => 3,
'scale' => null,
'defaultValue' => new DateTimeImmutable('2023-06-11 15:24:11.123'),
'dateTimeFormat' => 'Y-m-d H:i:s.v',
],
'timestamptz_col' => [
'type' => 'timestamp',
'dbType' => 'timestamptz(2)',
'phpType' => 'DateTimeInterface',
'primaryKey' => false,
'allowNull' => false,
'autoIncrement' => false,
'enumValues' => null,
'size' => 2,
'precision' => 2,
'scale' => null,
'defaultValue' => new DateTimeImmutable('2023-06-11 15:24:11.12+0200'),
'dateTimeFormat' => 'Y-m-d H:i:s.vP',
],
'date_col' => [
'type' => 'date',
'dbType' => 'date',
'phpType' => 'DateTimeInterface',
'primaryKey' => false,
'allowNull' => false,
'autoIncrement' => false,
'enumValues' => null,
'size' => null,
'precision' => null,
'scale' => null,
'defaultValue' => '2002-01-01 00:00:00',
'defaultValue' => new DateTimeImmutable('2023-06-11'),
'dateTimeFormat' => 'Y-m-d',
],
'time_col' => [
'type' => 'time',
'dbType' => 'time(6)',
'phpType' => 'DateTimeInterface',
'primaryKey' => false,
'allowNull' => false,
'autoIncrement' => false,
'enumValues' => null,
'size' => 6,
'precision' => 6,
'scale' => null,
'defaultValue' => new DateTimeImmutable('15:24:11.123456'),
'dateTimeFormat' => 'H:i:s.u',
],
'timetz_col' => [
'type' => 'time',
'dbType' => 'timetz',
'phpType' => 'DateTimeInterface',
'primaryKey' => false,
'allowNull' => false,
'autoIncrement' => false,
'enumValues' => null,
'size' => null,
'precision' => null,
'scale' => null,
'defaultValue' => new DateTimeImmutable('15:24:11'),
'dateTimeFormat' => 'H:i:sP',
],
'bool_col' => [
'type' => 'boolean',
Expand Down Expand Up @@ -199,7 +271,7 @@ public static function columns(): array
'ts_default' => [
'type' => 'timestamp',
'dbType' => 'timestamp',
'phpType' => 'string',
'phpType' => 'DateTimeInterface',
'primaryKey' => false,
'allowNull' => false,
'autoIncrement' => false,
Expand Down Expand Up @@ -272,9 +344,9 @@ public static function columns(): array
'defaultValue' => 'CURRENT_TIMESTAMP',
],
'timestamp_text' => [
'type' => 'text',
'type' => 'timestamp',
'dbType' => 'text',
'phpType' => 'string',
'phpType' => 'DateTimeInterface',
'primaryKey' => false,
'allowNull' => false,
'autoIncrement' => false,
Expand Down
5 changes: 5 additions & 0 deletions tests/Support/Fixture/sqlite.sql
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ CREATE TABLE "type" (
blob_col blob,
numeric_col decimal(5,2) DEFAULT '33.22',
timestamp_col timestamp NOT NULL DEFAULT '2002-01-01 00:00:00',
datetime_col datetime(3) NOT NULL DEFAULT '2023-06-11 15:24:11.123',
timestamptz_col timestamptz(2) NOT NULL DEFAULT '2023-06-11 15:24:11.12+0200',
date_col date NOT NULL DEFAULT '2023-06-11',
time_col time(6) NOT NULL DEFAULT '15:24:11.123456',
timetz_col timetz NOT NULL DEFAULT '15:24:11',
bool_col tinyint(1) NOT NULL,
bool_col2 tinyint(1) DEFAULT '1',
ts_default TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
Expand Down