Skip to content

Commit

Permalink
Merge pull request #375 from kburton-dev/improve-inferring-model-prop…
Browse files Browse the repository at this point in the history
…erty-types

Improve inferring model property types, based on DB driver
  • Loading branch information
romalytvynenko authored May 17, 2024
2 parents 16ea85a + fa3890c commit 001a37b
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 15 deletions.
43 changes: 28 additions & 15 deletions src/Support/InferExtensions/ModelExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ public function getPropertyType(PropertyFetchEvent $event): ?Type

if ($attribute = $info->get('attributes')->get($event->getName())) {
$baseType = $this->getAttributeTypeFromEloquentCasts($attribute['cast'] ?? '')
?? $this->getAttributeTypeFromDbColumnType($attribute['type'] ?? '');
?? $this->getAttributeTypeFromDbColumnType($attribute['type'], $attribute['driver'])
?? new UnknownType("Virtual attribute ({$attribute['name']}) type inference not supported.");

if ($attribute['nullable']) {
return Union::wrap([$baseType, new NullType()]);
Expand All @@ -72,22 +73,34 @@ public function getPropertyType(PropertyFetchEvent $event): ?Type
throw new \LogicException('Should not happen');
}

private function getAttributeTypeFromDbColumnType(string $columnType): AbstractType
/**
* MySQL/MariaDB decimal is mapped to a string by PDO.
* Floating point numbers and decimals are all mapped to strings when using the pgsql driver.
*/
private function getAttributeTypeFromDbColumnType(?string $columnType, ?string $dbDriverName): ?AbstractType
{
$type = Str::before($columnType, ' ');
$typeName = Str::before($type, '(');

// @todo Fix to native types
$attributeType = match ($typeName) {
'int', 'integer', 'bigint' => new IntegerType(),
'float', 'double', 'decimal' => new FloatType(),
'varchar', 'string', 'text', 'datetime' => new StringType(), // string, text - needed?
'tinyint', 'bool', 'boolean' => new BooleanType(), // bool, boolean - needed?
'json', 'array' => new ArrayType(),
default => new UnknownType("unimplemented DB column type [$type]"),
};
if ($columnType === null) {
return null;
}

$typeName = str($columnType)
->before(' ') // strip modifiers from a type name such as `bigint unsigned`
->before('(') // strip the length from a type name such as `tinyint(4)`
->toString();

if (in_array($typeName, ['int', 'integer', 'tinyint', 'smallint', 'mediumint', 'bigint'])) {
return new IntegerType();
}

if ($dbDriverName === 'sqlite' && in_array($typeName, ['float', 'double', 'decimal'])) {
return new FloatType();
}

if (in_array($dbDriverName, ['mysql', 'mariadb']) && in_array($typeName, ['float', 'double'])) {
return new FloatType();
}

return $attributeType;
return new StringType();
}

/**
Expand Down
2 changes: 2 additions & 0 deletions src/Support/ResponseExtractor/ModelInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ protected function getAttributes($model)
return collect($columns)
->values()
->map(fn ($column) => [
'driver' => $connection->getDriverName(),
'name' => $column['name'],
'type' => $column['type'],
'increments' => $column['auto_increment'],
Expand Down Expand Up @@ -226,6 +227,7 @@ protected function getVirtualAttributes($model, $columns)
})
->reject(fn ($cast, $name) => $keyedColumns->has($name))
->map(fn ($cast, $name) => [
'driver' => null,
'name' => $name,
'type' => null,
'increments' => false,
Expand Down

0 comments on commit 001a37b

Please sign in to comment.