From 41f27497ccafe0e76925a209d97a3ba5098d5da4 Mon Sep 17 00:00:00 2001 From: Tigrov Date: Sat, 5 Aug 2023 11:57:46 +0700 Subject: [PATCH] Support DateTime instances --- src/ColumnSchema.php | 6 ++ src/Schema.php | 36 +++++++- tests/ColumnSchemaTest.php | 22 ++++- tests/Function/CastTest.php | 17 +++- tests/Function/ConvertTest.php | 17 +++- tests/Function/DateTimeTest.php | 17 +++- tests/Function/TryCastTest.php | 17 +++- tests/Function/TryConvertTest.php | 17 +++- .../Provider/Function/ConvertionProvider.php | 10 +- tests/Provider/Function/DateTimeProvider.php | 14 +-- tests/Provider/QueryBuilderProvider.php | 2 +- tests/Provider/SchemaProvider.php | 91 ++++++++++++++++++- tests/Provider/Type/DateProvider.php | 12 ++- tests/QueryBuilderTest.php | 2 +- tests/Support/Fixture/mssql.sql | 8 +- tests/Type/DateTest.php | 21 +++-- tests/Type/RowversionTest.php | 2 +- 17 files changed, 259 insertions(+), 52 deletions(-) diff --git a/src/ColumnSchema.php b/src/ColumnSchema.php index 97e21993d..f9e73db4d 100644 --- a/src/ColumnSchema.php +++ b/src/ColumnSchema.php @@ -11,6 +11,7 @@ use function bin2hex; use function is_string; +use function str_starts_with; /** * Represents the metadata of a column in a database table for MSSQL Server. @@ -51,4 +52,9 @@ public function dbTypecast(mixed $value): mixed return parent::dbTypecast($value); } + + public function hasTimezone(): bool + { + return str_starts_with((string) $this->getDbType(), 'datetimeoffset'); + } } diff --git a/src/Schema.php b/src/Schema.php index f1fb7caa7..60b9a65d6 100644 --- a/src/Schema.php +++ b/src/Schema.php @@ -13,6 +13,7 @@ use Yiisoft\Db\Driver\Pdo\AbstractPdoSchema; use Yiisoft\Db\Exception\Exception; use Yiisoft\Db\Exception\InvalidConfigException; +use Yiisoft\Db\Expression\Expression; use Yiisoft\Db\Helper\DbArrayHelper; use Yiisoft\Db\Schema\Builder\ColumnInterface; use Yiisoft\Db\Schema\ColumnSchemaInterface; @@ -108,9 +109,16 @@ final class Schema extends AbstractPdoSchema 'image' => self::TYPE_BINARY, /** - * Other data types 'cursor' type can't be used with tables + * The Transact-SQL rowversion data type is not a date or time data type. + * timestamp is a deprecated synonym for rowversion. + * rowversion column is semantically equivalent to a binary(8)/varbinary(8) column. + * + * @link https://learn.microsoft.com/en-us/sql/t-sql/functions/date-and-time-data-types-and-functions-transact-sql + * @link https://learn.microsoft.com/en-us/sql/t-sql/data-types/rowversion-transact-sql?view=sql-server-ver16 */ - 'timestamp' => self::TYPE_TIMESTAMP, + 'timestamp' => self::TYPE_BINARY, + + /** Other data types 'cursor' type can't be used with tables */ 'hierarchyid' => self::TYPE_STRING, 'uniqueidentifier' => self::TYPE_STRING, 'sql_variant' => self::TYPE_STRING, @@ -466,6 +474,7 @@ protected function loadColumnSchema(array $info): ColumnSchemaInterface } $column->phpType($this->getColumnPhpType($column)); + $column->dateTimeFormat($this->getDateTimeFormat($column)); $column->defaultValue($this->normalizeDefaultValue($info['column_default'], $column)); return $column; @@ -479,7 +488,7 @@ protected function loadColumnSchema(array $info): ColumnSchemaInterface * * @return mixed The normalized default value. */ - private function normalizeDefaultValue(?string $defaultValue, ColumnSchemaInterface $column): mixed + private function normalizeDefaultValue(string|null $defaultValue, ColumnSchemaInterface $column): mixed { if ( $defaultValue === null @@ -492,6 +501,10 @@ private function normalizeDefaultValue(?string $defaultValue, ColumnSchemaInterf $value = $this->parseDefaultValue($defaultValue); + if ($column->getDateTimeFormat() !== null) { + return date_create_immutable($value) ?: new Expression($value); + } + return is_numeric($value) ? $column->phpTypeCast($value) : $value; @@ -541,6 +554,12 @@ protected function findColumns(TableSchemaInterface $table): bool ELSE [t1].[data_type] + '(' + LTRIM(RTRIM(CONVERT(CHAR,[t1].[numeric_precision]))) + ',' + LTRIM(RTRIM(CONVERT(CHAR,[t1].[numeric_scale]))) + ')' END + WHEN [t1].[data_type] IN ('datetime2','datetimeoffset','time') THEN + CASE WHEN [t1].[datetime_precision] = NULL OR [t1].[datetime_precision] = -1 THEN + [t1].[data_type] + ELSE + [t1].[data_type] + '(' + LTRIM(RTRIM(CONVERT(CHAR,[t1].[datetime_precision]))) + ')' + END ELSE [t1].[data_type] END AS 'data_type', @@ -937,4 +956,15 @@ private function parseDefaultValue(string $value): string return $value; } + + protected function getMillisecondsFormat(ColumnSchemaInterface $column): string + { + $dbType = explode('(', (string) $column->getDbType(), 2)[0]; + + return match ($dbType) { + 'date', 'smalldatetime' => '', + 'datetime' => '.v', + default => parent::getMillisecondsFormat($column), + }; + } } diff --git a/tests/ColumnSchemaTest.php b/tests/ColumnSchemaTest.php index f7ef59a68..399582ab4 100644 --- a/tests/ColumnSchemaTest.php +++ b/tests/ColumnSchemaTest.php @@ -4,6 +4,7 @@ namespace Yiisoft\Db\Mssql\Tests; +use DateTimeImmutable; use PHPUnit\Framework\TestCase; use Yiisoft\Db\Mssql\Tests\Support\TestTrait; use Yiisoft\Db\Query\Query; @@ -33,7 +34,12 @@ public function testPhpTypeCast(): void 'char_col3' => null, 'float_col' => 1.234, 'blob_col' => "\x10\x11\x12", - 'datetime_col' => '2023-07-11 14:50:00.123', + 'smalldatetime_col' => '2023-08-05 12:05:00', + 'datetime_col' => '2023-07-11 14:50:12.123', + 'datetime2_col' => new DateTimeImmutable('2023-07-11 14:50:23.12 +02:00'), + 'datetimeoffset_col' => new DateTimeImmutable('2023-07-11 14:50:23.1234567 -2:30'), + 'date_col' => new DateTimeImmutable('2023-07-11'), + 'time_col' => new DateTimeImmutable('14:50:23.123456'), 'bool_col' => false, ] ); @@ -47,7 +53,13 @@ public function testPhpTypeCast(): void $charCol3PhpType = $tableSchema->getColumn('char_col3')?->phpTypecast($query['char_col3']); $floatColPhpType = $tableSchema->getColumn('float_col')?->phpTypecast($query['float_col']); $blobColPhpType = $tableSchema->getColumn('blob_col')?->phpTypecast($query['blob_col']); + $smalldatetimeColPhpType = $tableSchema->getColumn('smalldatetime_col')?->phpTypecast($query['smalldatetime_col']); $datetimeColPhpType = $tableSchema->getColumn('datetime_col')?->phpTypecast($query['datetime_col']); + $datetime2ColPhpType = $tableSchema->getColumn('datetime2_col')?->phpTypecast($query['datetime2_col']); + $datetimeoffsetColPhpType = $tableSchema->getColumn('datetimeoffset_col')?->phpTypecast($query['datetimeoffset_col']); + $dateColPhpType = $tableSchema->getColumn('date_col')?->phpTypecast($query['date_col']); + $timeColPhpType = $tableSchema->getColumn('time_col')?->phpTypecast($query['time_col']); + $datetime2DefaultPhpType = $tableSchema->getColumn('datetime2_default')?->phpTypecast($query['datetime2_default']); $boolColPhpType = $tableSchema->getColumn('bool_col')?->phpTypecast($query['bool_col']); $this->assertSame(1, $intColPhpType); @@ -55,7 +67,13 @@ public function testPhpTypeCast(): void $this->assertNull($charCol3PhpType); $this->assertSame(1.234, $floatColPhpType); $this->assertSame("\x10\x11\x12", $blobColPhpType); - $this->assertSame('2023-07-11 14:50:00.123', $datetimeColPhpType); + $this->assertEquals(new DateTimeImmutable('2023-08-05 12:05:00'), $smalldatetimeColPhpType); + $this->assertEquals(new DateTimeImmutable('2023-07-11 14:50:12.123'), $datetimeColPhpType); + $this->assertEquals(new DateTimeImmutable('2023-07-11 14:50:23.12 +02:00'), $datetime2ColPhpType); + $this->assertEquals(new DateTimeImmutable('2023-07-11 14:50:23.1234567 -2:30'), $datetimeoffsetColPhpType); + $this->assertEquals(new DateTimeImmutable('2023-07-11'), $dateColPhpType); + $this->assertEquals(new DateTimeImmutable('14:50:23.123456'), $timeColPhpType); + $this->assertInstanceOf(DateTimeImmutable::class, $datetime2DefaultPhpType); $this->assertEquals(false, $boolColPhpType); $db->close(); diff --git a/tests/Function/CastTest.php b/tests/Function/CastTest.php index 1f2c29922..3a7e68a96 100644 --- a/tests/Function/CastTest.php +++ b/tests/Function/CastTest.php @@ -11,6 +11,7 @@ use Yiisoft\Db\Exception\InvalidArgumentException; use Yiisoft\Db\Exception\InvalidConfigException; use Yiisoft\Db\Exception\NotSupportedException; +use Yiisoft\Db\Expression\ExpressionInterface; use Yiisoft\Db\Mssql\Tests\Support\TestTrait; /** @@ -37,7 +38,7 @@ public function testCreateTableWithDefaultValue( string $column, string $dbType, string $phpType, - string $defaultValue + string|ExpressionInterface $defaultValue ): void { $db = $this->buildTable(); @@ -45,7 +46,11 @@ public function testCreateTableWithDefaultValue( $this->assertSame($dbType, $tableSchema?->getColumn($column)->getDbType()); $this->assertSame($phpType, $tableSchema?->getColumn($column)->getPhpType()); - $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + if ($defaultValue instanceof ExpressionInterface) { + $this->assertEquals($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } else { + $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } $db->createCommand()->dropTable('cast')->execute(); } @@ -89,7 +94,7 @@ public function testDefaultValue( string $column, string $dbType, string $phpType, - string $defaultValue + string|ExpressionInterface $defaultValue ): void { $this->setFixture('Function/convertion.sql'); @@ -98,7 +103,11 @@ public function testDefaultValue( $this->assertSame($dbType, $tableSchema?->getColumn($column)->getDbType()); $this->assertSame($phpType, $tableSchema?->getColumn($column)->getPhpType()); - $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + if ($defaultValue instanceof ExpressionInterface) { + $this->assertEquals($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } else { + $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } $db->createCommand()->dropTable('cast')->execute(); } diff --git a/tests/Function/ConvertTest.php b/tests/Function/ConvertTest.php index 1d129dc95..6afedfbca 100644 --- a/tests/Function/ConvertTest.php +++ b/tests/Function/ConvertTest.php @@ -11,6 +11,7 @@ use Yiisoft\Db\Exception\InvalidArgumentException; use Yiisoft\Db\Exception\InvalidConfigException; use Yiisoft\Db\Exception\NotSupportedException; +use Yiisoft\Db\Expression\ExpressionInterface; use Yiisoft\Db\Mssql\Tests\Support\TestTrait; /** @@ -37,7 +38,7 @@ public function testCreateTableWithDefaultValue( string $column, string $dbType, string $phpType, - string $defaultValue + string|ExpressionInterface $defaultValue ): void { $db = $this->buildTable(); @@ -45,7 +46,11 @@ public function testCreateTableWithDefaultValue( $this->assertSame($dbType, $tableSchema?->getColumn($column)->getDbType()); $this->assertSame($phpType, $tableSchema?->getColumn($column)->getPhpType()); - $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + if ($defaultValue instanceof ExpressionInterface) { + $this->assertEquals($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } else { + $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } $db->createCommand()->dropTable('convert')->execute(); } @@ -89,7 +94,7 @@ public function testDefaultValue( string $column, string $dbType, string $phpType, - string $defaultValue + string|ExpressionInterface $defaultValue ): void { $this->setFixture('Function/convertion.sql'); @@ -98,7 +103,11 @@ public function testDefaultValue( $this->assertSame($dbType, $tableSchema?->getColumn($column)->getDbType()); $this->assertSame($phpType, $tableSchema?->getColumn($column)->getPhpType()); - $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + if ($defaultValue instanceof ExpressionInterface) { + $this->assertEquals($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } else { + $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } $db->createCommand()->dropTable('convert')->execute(); } diff --git a/tests/Function/DateTimeTest.php b/tests/Function/DateTimeTest.php index 11cfab86e..a146aa75e 100644 --- a/tests/Function/DateTimeTest.php +++ b/tests/Function/DateTimeTest.php @@ -12,6 +12,7 @@ use Yiisoft\Db\Exception\InvalidArgumentException; use Yiisoft\Db\Exception\InvalidConfigException; use Yiisoft\Db\Exception\NotSupportedException; +use Yiisoft\Db\Expression\ExpressionInterface; use Yiisoft\Db\Mssql\Tests\Support\TestTrait; /** @@ -36,7 +37,7 @@ public function testCreateTableWithDefaultValue( string $column, string $dbType, string $phpType, - string $defaultValue + string|ExpressionInterface $defaultValue ): void { $db = $this->buildTable(); @@ -44,7 +45,11 @@ public function testCreateTableWithDefaultValue( $this->assertSame($dbType, $tableSchema?->getColumn($column)->getDbType()); $this->assertSame($phpType, $tableSchema?->getColumn($column)->getPhpType()); - $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + if ($defaultValue instanceof ExpressionInterface) { + $this->assertEquals($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } else { + $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } $db->createCommand()->dropTable('datetime')->execute(); } @@ -136,7 +141,7 @@ public function testDefaultValue( string $column, string $dbType, string $phpType, - string $defaultValue + string|ExpressionInterface $defaultValue ): void { $this->setFixture('Function/datetime.sql'); @@ -145,7 +150,11 @@ public function testDefaultValue( $this->assertSame($dbType, $tableSchema?->getColumn($column)->getDbType()); $this->assertSame($phpType, $tableSchema?->getColumn($column)->getPhpType()); - $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + if ($defaultValue instanceof ExpressionInterface) { + $this->assertEquals($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } else { + $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } $db->createCommand()->dropTable('datetime')->execute(); } diff --git a/tests/Function/TryCastTest.php b/tests/Function/TryCastTest.php index beb81fa83..a24a7c400 100644 --- a/tests/Function/TryCastTest.php +++ b/tests/Function/TryCastTest.php @@ -11,6 +11,7 @@ use Yiisoft\Db\Exception\InvalidArgumentException; use Yiisoft\Db\Exception\InvalidConfigException; use Yiisoft\Db\Exception\NotSupportedException; +use Yiisoft\Db\Expression\ExpressionInterface; use Yiisoft\Db\Mssql\Tests\Support\TestTrait; /** @@ -37,7 +38,7 @@ public function testCreateTableWithDefaultValue( string $column, string $dbType, string $phpType, - string $defaultValue + string|ExpressionInterface $defaultValue ): void { $db = $this->buildTable(); @@ -45,7 +46,11 @@ public function testCreateTableWithDefaultValue( $this->assertSame($dbType, $tableSchema?->getColumn($column)->getDbType()); $this->assertSame($phpType, $tableSchema?->getColumn($column)->getPhpType()); - $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + if ($defaultValue instanceof ExpressionInterface) { + $this->assertEquals($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } else { + $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } $db->createCommand()->dropTable('trycast')->execute(); } @@ -89,7 +94,7 @@ public function testDefaultValue( string $column, string $dbType, string $phpType, - string $defaultValue + string|ExpressionInterface $defaultValue ): void { $this->setFixture('Function/convertion.sql'); @@ -98,7 +103,11 @@ public function testDefaultValue( $this->assertSame($dbType, $tableSchema?->getColumn($column)->getDbType()); $this->assertSame($phpType, $tableSchema?->getColumn($column)->getPhpType()); - $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + if ($defaultValue instanceof ExpressionInterface) { + $this->assertEquals($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } else { + $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } $db->createCommand()->dropTable('trycast')->execute(); } diff --git a/tests/Function/TryConvertTest.php b/tests/Function/TryConvertTest.php index 63162a44e..c4419178e 100644 --- a/tests/Function/TryConvertTest.php +++ b/tests/Function/TryConvertTest.php @@ -11,6 +11,7 @@ use Yiisoft\Db\Exception\InvalidArgumentException; use Yiisoft\Db\Exception\InvalidConfigException; use Yiisoft\Db\Exception\NotSupportedException; +use Yiisoft\Db\Expression\ExpressionInterface; use Yiisoft\Db\Mssql\Tests\Support\TestTrait; /** @@ -37,7 +38,7 @@ public function testCreateTableWithDefaultValue( string $column, string $dbType, string $phpType, - string $defaultValue + string|ExpressionInterface $defaultValue ): void { $db = $this->buildTable(); @@ -45,7 +46,11 @@ public function testCreateTableWithDefaultValue( $this->assertSame($dbType, $tableSchema?->getColumn($column)->getDbType()); $this->assertSame($phpType, $tableSchema?->getColumn($column)->getPhpType()); - $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + if ($defaultValue instanceof ExpressionInterface) { + $this->assertEquals($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } else { + $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } $db->createCommand()->dropTable('tryconvert')->execute(); } @@ -89,7 +94,7 @@ public function testDefaultValue( string $column, string $dbType, string $phpType, - string $defaultValue + string|ExpressionInterface $defaultValue ): void { $this->setFixture('Function/convertion.sql'); @@ -98,7 +103,11 @@ public function testDefaultValue( $this->assertSame($dbType, $tableSchema?->getColumn($column)->getDbType()); $this->assertSame($phpType, $tableSchema?->getColumn($column)->getPhpType()); - $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + if ($defaultValue instanceof ExpressionInterface) { + $this->assertEquals($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } else { + $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } $db->createCommand()->dropTable('tryconvert')->execute(); } diff --git a/tests/Provider/Function/ConvertionProvider.php b/tests/Provider/Function/ConvertionProvider.php index c5bf656ac..b949d5139 100644 --- a/tests/Provider/Function/ConvertionProvider.php +++ b/tests/Provider/Function/ConvertionProvider.php @@ -4,6 +4,8 @@ namespace Yiisoft\Db\Mssql\Tests\Provider\Function; +use Yiisoft\Db\Expression\Expression; + final class ConvertionProvider { public static function castColumns(): array @@ -13,7 +15,7 @@ public static function castColumns(): array ['Mycast2', 'int', 'integer', 'CONVERT([int],(14.85))'], ['Mycast3', 'float', 'double', 'CONVERT([float],\'14.85\')'], ['Mycast4', 'varchar(4)', 'string', 'CONVERT([varchar](4),(15.6))'], - ['Mycast5', 'datetime', 'string', 'CONVERT([datetime],\'2023-02-21\')'], + ['Mycast5', 'datetime', 'DateTimeInterface', new Expression('CONVERT([datetime],\'2023-02-21\')')], ['Mycast6', 'binary(10)', 'resource', 'CONVERT([binary](10),\'testme\')'], ]; } @@ -25,7 +27,7 @@ public static function convertColumns(): array ['Myconvert2', 'int', 'integer', 'CONVERT([int],(14.85))'], ['Myconvert3', 'float', 'double', 'CONVERT([float],\'14.85\')'], ['Myconvert4', 'varchar(4)', 'string', 'CONVERT([varchar](4),(15.6))'], - ['Myconvert5', 'datetime', 'string', 'CONVERT([datetime],\'2023-02-21\')'], + ['Myconvert5', 'datetime', 'DateTimeInterface', new Expression('CONVERT([datetime],\'2023-02-21\')')], ['Myconvert6', 'binary(10)', 'resource', 'CONVERT([binary](10),\'testme\')'], ]; } @@ -37,7 +39,7 @@ public static function tryCastColumns(): array ['Mytrycast2', 'int', 'integer', 'TRY_CAST((14.85) AS [int])'], ['Mytrycast3', 'float', 'double', 'TRY_CAST(\'14.85\' AS [float])'], ['Mytrycast4', 'varchar(4)', 'string', 'TRY_CAST((15.6) AS [varchar](4))'], - ['Mytrycast5', 'datetime', 'string', 'TRY_CAST(\'2023-02-21\' AS [datetime])'], + ['Mytrycast5', 'datetime', 'DateTimeInterface', new Expression('TRY_CAST(\'2023-02-21\' AS [datetime])')], ['Mytrycast6', 'binary(10)', 'resource', 'TRY_CAST(\'testme\' AS [binary](10))'], ]; } @@ -49,7 +51,7 @@ public static function tryConvertColumns(): array ['Mytryconvert2', 'int', 'integer', 'TRY_CAST((14.85) AS [int])'], ['Mytryconvert3', 'float', 'double', 'TRY_CAST(\'14.85\' AS [float])'], ['Mytryconvert4', 'varchar(4)', 'string', 'TRY_CAST((15.6) AS [varchar](4))'], - ['Mytryconvert5', 'datetime', 'string', 'TRY_CAST(\'2023-02-21\' AS [datetime])'], + ['Mytryconvert5', 'datetime', 'DateTimeInterface', new Expression('TRY_CAST(\'2023-02-21\' AS [datetime])')], ['Mytryconvert6', 'binary(10)', 'resource', 'TRY_CAST(\'testme\' AS [binary](10))'], ]; } diff --git a/tests/Provider/Function/DateTimeProvider.php b/tests/Provider/Function/DateTimeProvider.php index 6cbb4101c..636be89c9 100644 --- a/tests/Provider/Function/DateTimeProvider.php +++ b/tests/Provider/Function/DateTimeProvider.php @@ -4,19 +4,21 @@ namespace Yiisoft\Db\Mssql\Tests\Provider\Function; +use Yiisoft\Db\Expression\Expression; + final class DateTimeProvider { public static function columns(): array { return [ /** @link https://docs.microsoft.com/en-us/sql/t-sql/functions/getutcdate-transact-sql?view=sql-server-ver16 */ - ['Mydate1', 'date', 'string', 'getutcdate()'], + ['Mydate1', 'date', 'DateTimeInterface', new Expression('getutcdate()')], /** @link https://docs.microsoft.com/en-us/sql/t-sql/functions/getdate-transact-sql?view=sql-server-ver16 */ - ['Mydate2', 'date', 'string', 'getdate()'], + ['Mydate2', 'date', 'DateTimeInterface', new Expression('getdate()')], /** @link https://docs.microsoft.com/en-us/sql/t-sql/functions/dateadd-transact-sql?view=sql-server-ver16 */ - ['Mydate3', 'date', 'string', 'dateadd(month,(1),\'2006-08-31\')'], + ['Mydate3', 'date', 'DateTimeInterface', new Expression('dateadd(month,(1),\'2006-08-31\')')], /** @link https://learn.microsoft.com/en-us/sql/t-sql/functions/datediff-transact-sql?view=sql-server-ver16 */ [ @@ -42,13 +44,13 @@ public static function columns(): array ['Mydatetime6', 'int', 'integer', 'datepart(year,\'2023-02-21\')'], /** @link https://docs.microsoft.com/en-us/sql/t-sql/functions/sysdatetime-transact-sql?view=sql-server-ver16 */ - ['Mydatetime7', 'datetime', 'string', 'sysdatetime()'], + ['Mydatetime7', 'datetime', 'DateTimeInterface', new Expression('sysdatetime()')], /** @link https://docs.microsoft.com/en-us/sql/t-sql/functions/sysdatetimeoffset-transact-sql?view=sql-server-ver16 */ - ['Mydatetimeoffset1', 'datetimeoffset', 'string', 'sysdatetimeoffset()'], + ['Mydatetimeoffset1', 'datetimeoffset(7)', 'DateTimeInterface', new Expression('sysdatetimeoffset()')], /** https://docs.microsoft.com/en-us/sql/t-sql/functions/sysutcdatetime-transact-sql?view=sql-server-ver16 */ - ['Mydatetimeoffset2', 'datetimeoffset', 'string', 'sysutcdatetime()'], + ['Mydatetimeoffset2', 'datetimeoffset(7)', 'DateTimeInterface', new Expression('sysutcdatetime()')], ]; } } diff --git a/tests/Provider/QueryBuilderProvider.php b/tests/Provider/QueryBuilderProvider.php index aea94267a..e4b146549 100644 --- a/tests/Provider/QueryBuilderProvider.php +++ b/tests/Provider/QueryBuilderProvider.php @@ -128,7 +128,7 @@ public static function insertWithReturningPks(): array ['{{%type}}.[[related_id]]' => null, '[[time]]' => new Expression('now()')], [], << null], ], diff --git a/tests/Provider/SchemaProvider.php b/tests/Provider/SchemaProvider.php index 039aa5c17..0dc41b587 100644 --- a/tests/Provider/SchemaProvider.php +++ b/tests/Provider/SchemaProvider.php @@ -4,7 +4,9 @@ namespace Yiisoft\Db\Mssql\Tests\Provider; +use DateTimeImmutable; use Yiisoft\Db\Constraint\DefaultValueConstraint; +use Yiisoft\Db\Expression\Expression; use Yiisoft\Db\Tests\Support\AnyValue; final class SchemaProvider extends \Yiisoft\Db\Tests\Provider\SchemaProvider @@ -157,10 +159,24 @@ public static function columns(): array 'scale' => 2, 'defaultValue' => 33.22, ], + 'smalldatetime_col' => [ + 'type' => 'datetime', + 'dbType' => 'smalldatetime', + 'phpType' => 'DateTimeInterface', + 'primaryKey' => false, + 'allowNull' => false, + 'autoIncrement' => false, + 'enumValues' => [], + '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', - 'phpType' => 'string', + 'phpType' => 'DateTimeInterface', 'primaryKey' => false, 'allowNull' => false, 'autoIncrement' => false, @@ -168,7 +184,78 @@ public static function columns(): array 'size' => null, 'precision' => null, 'scale' => null, - 'defaultValue' => '2002-01-01 00:00:00', + 'defaultValue' => new DateTimeImmutable('2023-06-11 15:24:11.123'), + 'dateTimeFormat' => 'Y-m-d H:i:s.v', + ], + 'datetime2_col' => [ + 'type' => 'datetime', + 'dbType' => 'datetime2(2)', + 'phpType' => 'DateTimeInterface', + 'primaryKey' => false, + 'allowNull' => false, + 'autoIncrement' => false, + 'enumValues' => [], + 'size' => 2, + 'precision' => 2, + 'scale' => null, + 'defaultValue' => new DateTimeImmutable('2023-06-11 15:24:11.12'), + 'dateTimeFormat' => 'Y-m-d H:i:s.v', + ], + 'datetime2_default' => [ + 'type' => 'datetime', + 'dbType' => 'datetime2(7)', + 'phpType' => 'DateTimeInterface', + 'primaryKey' => false, + 'allowNull' => false, + 'autoIncrement' => false, + 'enumValues' => [], + 'size' => 7, + 'precision' => 7, + 'scale' => null, + 'defaultValue' => new Expression('sysdatetime()'), + 'dateTimeFormat' => 'Y-m-d H:i:s.u', + ], + 'datetimeoffset_col' => [ + 'type' => 'datetime', + 'dbType' => 'datetimeoffset(7)', + 'phpType' => 'DateTimeInterface', + 'primaryKey' => false, + 'allowNull' => false, + 'autoIncrement' => false, + 'enumValues' => [], + 'size' => 7, + 'precision' => 7, + 'scale' => null, + 'defaultValue' => new DateTimeImmutable('2023-06-11 15:24:11.1234567 +02:00'), + 'dateTimeFormat' => 'Y-m-d H:i:s.uP', + ], + 'date_col' => [ + 'type' => 'date', + 'dbType' => 'date', + 'phpType' => 'DateTimeInterface', + 'primaryKey' => false, + 'allowNull' => false, + 'autoIncrement' => false, + 'enumValues' => [], + 'size' => null, + 'precision' => null, + 'scale' => null, + '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' => [], + 'size' => 6, + 'precision' => 6, + 'scale' => null, + 'defaultValue' => new DateTimeImmutable('15:24:11.123456'), + 'dateTimeFormat' => 'H:i:s.u', ], 'bool_col' => [ 'type' => 'tinyint', diff --git a/tests/Provider/Type/DateProvider.php b/tests/Provider/Type/DateProvider.php index 0774252b5..8df431c08 100644 --- a/tests/Provider/Type/DateProvider.php +++ b/tests/Provider/Type/DateProvider.php @@ -4,16 +4,18 @@ namespace Yiisoft\Db\Mssql\Tests\Provider\Type; +use DateTimeImmutable; + final class DateProvider { public static function columns(): array { return [ - ['Mydate', 'date', 'string', '2007-05-08'], - ['Mydatetime', 'datetime', 'string', '2007-05-08 12:35:29.123'], - ['Mydatetime2', 'datetime2', 'string', '2007-05-08 12:35:29.1234567'], - ['Mydatetimeoffset', 'datetimeoffset', 'string', '2007-05-08 12:35:29.1234567 +12:15'], - ['Mytime', 'time', 'string', '12:35:29.1234567'], + ['Mydate', 'date', 'DateTimeInterface', new DateTimeImmutable('2007-05-08')], + ['Mydatetime', 'datetime', 'DateTimeInterface', new DateTimeImmutable('2007-05-08 12:35:29.123')], + ['Mydatetime2', 'datetime2(7)', 'DateTimeInterface', new DateTimeImmutable('2007-05-08 12:35:29.1234567')], + ['Mydatetimeoffset', 'datetimeoffset(7)', 'DateTimeInterface', new DateTimeImmutable('2007-05-08 12:35:29.1234567 +12:15')], + ['Mytime', 'time(7)', 'DateTimeInterface', new DateTimeImmutable('12:35:29.1234567')], ]; } } diff --git a/tests/QueryBuilderTest.php b/tests/QueryBuilderTest.php index 1591f9c42..cd6ada34a 100644 --- a/tests/QueryBuilderTest.php +++ b/tests/QueryBuilderTest.php @@ -842,7 +842,7 @@ public function testAlterColumnOnDb(): void $db->createCommand($sql)->execute(); $schema = $db->getTableSchema('[foo1]', true); $this->assertSame(SchemaInterface::TYPE_DATETIME, $schema?->getColumn('bar')->getDbType()); - $this->assertSame('getdate()', $schema?->getColumn('bar')->getDefaultValue()); + $this->assertEquals(new Expression('getdate()'), $schema?->getColumn('bar')->getDefaultValue()); } /** diff --git a/tests/Support/Fixture/mssql.sql b/tests/Support/Fixture/mssql.sql index b50283531..67bdb8b89 100644 --- a/tests/Support/Fixture/mssql.sql +++ b/tests/Support/Fixture/mssql.sql @@ -155,7 +155,13 @@ CREATE TABLE [dbo].[type] ( [float_col2] [float] DEFAULT '1.23', [blob_col] [varbinary](MAX), [numeric_col] [decimal](5,2) DEFAULT '33.22', - [datetime_col] [datetime] NOT NULL DEFAULT '2002-01-01 00:00:00', + [smalldatetime_col] [smalldatetime] NOT NULL DEFAULT '2002-01-01 00:00:00', + [datetime_col] [datetime] NOT NULL DEFAULT '2023-06-11 15:24:11.123', + [datetime2_col] [datetime2](2) NOT NULL DEFAULT '2023-06-11 15:24:11.12', + [datetimeoffset_col] [datetimeoffset] NOT NULL DEFAULT '2023-06-11 15:24:11.1234567 +02:00', + [date_col] [date] NOT NULL DEFAULT '2023-06-11', + [time_col] [time](6) NOT NULL DEFAULT '15:24:11.123456', + [datetime2_default] [datetime2] NOT NULL DEFAULT sysdatetime(), [bool_col] [tinyint] NOT NULL, [bool_col2] [tinyint] DEFAULT '1' ); diff --git a/tests/Type/DateTest.php b/tests/Type/DateTest.php index 042745d31..ec6a914d4 100644 --- a/tests/Type/DateTest.php +++ b/tests/Type/DateTest.php @@ -4,6 +4,7 @@ namespace Yiisoft\Db\Mssql\Tests\Type; +use DateTimeInterface; use PHPUnit\Framework\TestCase; use Throwable; use Yiisoft\Db\Connection\ConnectionInterface; @@ -37,7 +38,7 @@ public function testCreateTableWithDefaultValue( string $column, string $dbType, string $phpType, - string $defaultValue + string|DateTimeInterface $defaultValue ): void { $db = $this->buildTable(); @@ -45,7 +46,11 @@ public function testCreateTableWithDefaultValue( $this->assertSame($dbType, $tableSchema?->getColumn($column)->getDbType()); $this->assertSame($phpType, $tableSchema?->getColumn($column)->getPhpType()); - $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + if ($defaultValue instanceof DateTimeInterface) { + $this->assertEquals($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } else { + $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } $db->createCommand()->insert('date_default', [])->execute(); } @@ -89,7 +94,7 @@ public function testDefaultValue( string $column, string $dbType, string $phpType, - string $defaultValue + string|DateTimeInterface $defaultValue ): void { $this->setFixture('Type/date.sql'); @@ -98,7 +103,11 @@ public function testDefaultValue( $this->assertSame($dbType, $tableSchema?->getColumn($column)->getDbType()); $this->assertSame($phpType, $tableSchema?->getColumn($column)->getPhpType()); - $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + if ($defaultValue instanceof DateTimeInterface) { + $this->assertEquals($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } else { + $this->assertSame($defaultValue, $tableSchema?->getColumn($column)->getDefaultValue()); + } $db->createCommand()->dropTable('date_default')->execute(); } @@ -150,7 +159,7 @@ public function testValue(): void 'Mydatetime2' => null, 'Mydatetimeoffset1' => '2007-05-08 12:35:29.1234567 +12:15', 'Mydatetimeoffset2' => null, - 'Mytime1' => '12:35:29.1234567', + 'Mytime1' => '12:35:29.1234560', 'Mytime2' => null, ])->execute(); @@ -163,7 +172,7 @@ public function testValue(): void 'Mydatetime2' => null, 'Mydatetimeoffset1' => '2007-05-08 12:35:29.1234567 +12:15', 'Mydatetimeoffset2' => null, - 'Mytime1' => '12:35:29.1234567', + 'Mytime1' => '12:35:29.1234560', 'Mytime2' => null, ], $command->setSql( diff --git a/tests/Type/RowversionTest.php b/tests/Type/RowversionTest.php index 97aaf0fc1..994fe6fd6 100644 --- a/tests/Type/RowversionTest.php +++ b/tests/Type/RowversionTest.php @@ -38,7 +38,7 @@ public function testValue(): void $tableSchema = $db->getTableSchema('rowversion'); $this->assertSame('timestamp', $tableSchema?->getColumn('Myrowversion')->getDbType()); - $this->assertSame('string', $tableSchema?->getColumn('Myrowversion')->getPhpType()); + $this->assertSame('resource', $tableSchema?->getColumn('Myrowversion')->getPhpType()); $this->assertNull($tableSchema?->getColumn('Myrowversion')->getDefaultValue()); $command = $db->createCommand();