Skip to content

Commit

Permalink
feat(Model): getColumns 方法增加返回 typeunsignedlengthscale
Browse files Browse the repository at this point in the history
  • Loading branch information
twinh committed Nov 30, 2022
1 parent 3ead9b6 commit 53a5992
Show file tree
Hide file tree
Showing 2 changed files with 297 additions and 14 deletions.
166 changes: 152 additions & 14 deletions lib/Db/Mysql.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,19 @@ class Mysql extends BaseDriver

protected $sqlParts = [];

/**
* @var string[]
* @internal
*/
protected $typeMap = [
'smallint' => 'smallInt',
'mediumint' => 'mediumInt',
'int' => 'int',
'text' => 'text',
'mediumtext' => 'mediumText',
'longtext' => 'longText',
];

public function getSql($type, $sqlParts, $identifierConverter = null)
{
$this->aliases = [];
Expand Down Expand Up @@ -73,20 +86,7 @@ public function getColumns(string $table, callable $phpKeyConverter = null): arr
$dbColumns = $this->db->fetchAll("SHOW COLUMNS FROM $table");

foreach ($dbColumns as $dbColumn) {
$column = [];

$column['cast'] = $this->getCastType($dbColumn['Type']);

// Auto increment column cant have default value, so it's allow to be null
if ('YES' === $dbColumn['Null'] || false !== strpos($dbColumn['Extra'], 'auto_increment')) {
$column['nullable'] = true;
}

[$default, $isCustom] = $this->getCustomDefault($dbColumn);
if ($isCustom) {
$column['default'] = $default;
}

$column = $this->parseColumn($dbColumn);
$name = $phpKeyConverter ? $phpKeyConverter($dbColumn['Field']) : $dbColumn['Field'];
$columns[$name] = $column;
}
Expand Down Expand Up @@ -393,6 +393,144 @@ protected function generateLockSql()
}
}

/**
* Parse column metadata from database column information
*
* @param array $dbColumn
* @return array
*/
protected function parseColumn(array $dbColumn): array
{
$column = $this->parseColumnType($dbColumn['Type']);

// Auto increment column cant have default value, so it's allow to be null
if ('YES' === $dbColumn['Null'] || false !== strpos($dbColumn['Extra'], 'auto_increment')) {
$column['nullable'] = true;
}

[$default, $isCustom] = $this->getCustomDefault($dbColumn);
if ($isCustom) {
$column['default'] = $default;
}

return $column;
}

/**
* Parse column metadata from database column type
*
* $columnType examples:
*
* bigint(20) unsigned
* decimal(16,2) unsigned
* timestamp
*
* @param string $columnType
* @return array
* @internal
*/
protected function parseColumnType(string $columnType): array
{
[$type, $left] = explode('(', $columnType) + [1 => 0];
$length = (int) $left;

switch ($type) {
case 'tinyint':
return 1 === $length ? [
'type' => 'bool',
'cast' => 'bool',
] : [
'type' => 'tinyInt',
'cast' => 'int',
'unsigned' => $this->isTypeUnsigned($columnType),
];

case 'smallint':
case 'mediumint':
case 'int':
return [
'type' => $this->typeMap[$type],
'cast' => 'int',
'unsigned' => $this->isTypeUnsigned($columnType),
];

case 'bigint':
return [
'type' => 'bigInt',
'cast' => 'intString',
'unsigned' => $this->isTypeUnsigned($columnType),
];

case 'timestamp':
case 'datetime':
return [
'type' => $type,
'cast' => 'datetime',
];

case 'date':
return [
'type' => 'date',
'cast' => 'date',
];

case 'decimal':
// $left = 16,2) unsigned
$scale = (int) explode(',', $left)[1];
return [
'type' => 'decimal',
'cast' => 'decimal',
'unsigned' => $this->isTypeUnsigned($columnType),
'length' => $length,
'scale' => $scale,
];

case 'json':
return [
'type' => 'json',
'cast' => 'json',
'length' => 1024 ** 3, // 1GB
];

case 'char':
case 'varchar':
return [
'type' => 'string',
'cast' => 'string',
'length' => $length,
];

case 'text':
case 'mediumtext':
case 'longtext':
return [
'type' => $this->typeMap[$type],
'cast' => 'string',
];

default:
return [
'type' => 'string',
'cast' => 'string',
];
}
}

/**
* @param string $columnType
* @return bool
* @internal
*/
protected function isTypeUnsigned(string $columnType): bool
{
return 'unsigned' === substr($columnType, -8);
}

/**
* @param string $columnType
* @return string
* @deprecated
*/
protected function getCastType($columnType)
{
$parts = explode('(', $columnType);
Expand Down
145 changes: 145 additions & 0 deletions tests/unit/Model/CastTraitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -812,4 +812,149 @@ public function providerForTestSaveDecimal(): array
[false, '0', '0'],
];
}

public function testGetColumns()
{
$columns = TestCast::getColumns();
$this->assertSame([
'int_column' => [
'type' => 'int',
'cast' => 'int',
'unsigned' => true,
'nullable' => true,
],
'nullable_int_column' => [
'type' => 'int',
'cast' => 'int',
'unsigned' => false,
'nullable' => true,
],
'nullable_default_int_column' => [
'type' => 'int',
'cast' => 'int',
'unsigned' => false,
'nullable' => true,
'default' => 7,
],
'big_int_column' => [
'type' => 'bigInt',
'cast' => 'intString',
'unsigned' => false,
],
'nullable_big_int_column' => [
'type' => 'bigInt',
'cast' => 'intString',
'unsigned' => false,
'nullable' => true,
],
'bool_column' => [
'type' => 'bool',
'cast' => 'bool',
],
'nullable_bool_column' => [
'type' => 'bool',
'cast' => 'bool',
'nullable' => true,
],
'string_column' => [
'type' => 'string',
'cast' => 'string',
'length' => 255,
],
'nullable_string_column' => [
'type' => 'string',
'cast' => 'string',
'length' => 255,
'nullable' => true,
],
'datetime_column' => [
'type' => 'datetime',
'cast' => 'datetime',
'nullable' => true,
],
'nullable_datetime_column' => [
'type' => 'datetime',
'cast' => 'datetime',
'nullable' => true,
],
'date_column' => [
'type' => 'date',
'cast' => 'date',
'nullable' => true,
],
'nullable_date_column' => [
'type' => 'date',
'cast' => 'date',
'nullable' => true,
],
'json_column' => [
'type' => 'string',
'cast' => 'array',
'length' => 255,
'default' => [
],
],
'nullable_json_column' => [
'type' => 'string',
'cast' => 'string',
'length' => 255,
'nullable' => true,
],
'object_column' => [
'type' => 'string',
'cast' => 'object',
'length' => 255,
],
'nullable_object_column' => [
'type' => 'string',
'cast' => 'object',
'length' => 255,
'nullable' => true,
],
'default_object_column' => [
'type' => 'string',
'cast' => 'object',
'length' => 255,
'default' => '{"a":"c"}',
],
'list_column' => [
'type' => 'string',
'cast' => 'list',
'length' => 255,
'default' => [
],
],
'nullable_list_column' => [
'type' => 'string',
'cast' => 'string',
'length' => 255,
'nullable' => true,
],
'list2_column' => [
'type' => 'string',
'cast' => [
0 => 'list',
'type' => 'int',
'separator' => '|',
],
'length' => 255,
'default' => [],
],
'decimal_column' => [
'type' => 'decimal',
'cast' => 'decimal',
'unsigned' => false,
'length' => 10,
'scale' => 2,
],
'nullable_decimal_column' => [
'type' => 'decimal',
'cast' => 'decimal',
'unsigned' => false,
'length' => 10,
'scale' => 2,
'nullable' => true,
],
], $columns);
}
}

0 comments on commit 53a5992

Please sign in to comment.