Skip to content
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

ColumnSchema classes for performance of typecasting #752

Merged
merged 31 commits into from
May 30, 2024
Merged
Changes from 11 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
a57729b
Column type classes
Tigrov Sep 1, 2023
a458258
Remove extra tests
Tigrov Sep 1, 2023
0ef31a1
Remove final
Tigrov Sep 1, 2023
eea7d04
Refactor tests
Tigrov Sep 1, 2023
3928a3e
Apply StyleCI fixes
Tigrov Sep 1, 2023
d029f8d
Merge branch 'master' into column_type_classes2
Tigrov Sep 1, 2023
83c6241
Improve params of `createColumnSchema()`
Tigrov Sep 3, 2023
f52b96f
Merge branch 'master' into column_type_classes2
Tigrov Sep 3, 2023
7b91caf
Remove a duplicate test
Tigrov Sep 5, 2023
4cca03b
Add line to CHANGELOG.md
Tigrov Sep 5, 2023
4231047
Merge remote-tracking branch 'origin/master' into column_type_classes2
Tigrov Oct 7, 2023
c46c519
Merge branch 'refs/heads/master' into column_type_classes2
Tigrov Apr 25, 2024
cd27589
Refactor `ColumnSchemaInterface` and typecasting
Tigrov Apr 25, 2024
969714b
Update
Tigrov Apr 27, 2024
ff22127
Merge branch 'refs/heads/master' into column_type_classes2
Tigrov May 4, 2024
56d2848
Improve
Tigrov May 5, 2024
2f705e7
Apply fixes from StyleCI
StyleCIBot May 5, 2024
4bb7de3
Merge branch 'refs/heads/master' into column_type_classes2
Tigrov May 5, 2024
f794df6
Merge branch 'master' into column_type_classes2
vjik May 5, 2024
c882726
Merge branch 'refs/heads/master' into column_type_classes2
Tigrov May 5, 2024
c627ce5
Merge branch 'yiisoft:column_type_classes2' into column_type_classes2
Tigrov May 5, 2024
6041faa
Update UPGRADE.md [skip ci]
Tigrov May 6, 2024
78806d7
Merge branch 'yiisoft:column_type_classes2' into column_type_classes2
Tigrov May 6, 2024
cb0a28b
Improve bigint typecasting
Tigrov May 6, 2024
ece7157
Merge branch 'yiisoft:column_type_classes2' into column_type_classes2
Tigrov May 6, 2024
a26176b
Merge branch 'refs/heads/master' into column_type_classes2
Tigrov May 24, 2024
a7690fe
Merge branch 'yiisoft:column_type_classes2' into column_type_classes2
Tigrov May 24, 2024
d2846c7
Merge branch 'refs/heads/master' into column_type_classes2
Tigrov May 24, 2024
d1e072b
Merge branch 'yiisoft:column_type_classes2' into column_type_classes2
Tigrov May 24, 2024
d36dc53
Update doc [skip ci]
Tigrov May 30, 2024
9400b1d
Merge branch 'yiisoft:column_type_classes2' into column_type_classes2
Tigrov May 30, 2024
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -3,6 +3,8 @@
## 1.1.2 under development

- Bug #751: Fix collected debug actions (@xepozz)
- Enh #752: Implement `ColumnSchemaInterface` classes according to the data type of database table columns
for type casting performance (@Tigrov)
- Chg #755: Deprecate `TableSchemaInterface::compositeForeignKey()` (@Tigrov)
- Enh #756: Refactor `Quoter` (@Tigrov)
- Bug #756: Fix `Quoter::quoteSql()` for SQL containing table with prefix (@Tigrov)
2 changes: 1 addition & 1 deletion src/QueryBuilder/AbstractDMLQueryBuilder.php
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@
use Yiisoft\Db\Exception\NotSupportedException;
use Yiisoft\Db\Expression\ExpressionInterface;
use Yiisoft\Db\Query\QueryInterface;
use Yiisoft\Db\Schema\ColumnSchemaInterface;
use Yiisoft\Db\Schema\Column\ColumnSchemaInterface;
use Yiisoft\Db\Schema\QuoterInterface;
use Yiisoft\Db\Schema\SchemaInterface;

4 changes: 4 additions & 0 deletions src/Schema/AbstractColumnSchema.php
Original file line number Diff line number Diff line change
@@ -14,6 +14,8 @@
use function is_resource;

/**
* @deprecated Use Yiisoft\Db\Schema\Column\AbstractColumnSchema instead
*
* Represents the metadata of a column in a database table.
*
* It provides information about the column's name, type, size, precision, and other details.
@@ -38,6 +40,8 @@
* $column->autoIncrement(true);
* $column->primaryKey(true);
* ``
*
* @psalm-suppress DeprecatedInterface
*/
abstract class AbstractColumnSchema implements ColumnSchemaInterface
{
69 changes: 59 additions & 10 deletions src/Schema/AbstractSchema.php
Original file line number Diff line number Diff line change
@@ -11,6 +11,14 @@
use Yiisoft\Db\Connection\ConnectionInterface;
use Yiisoft\Db\Constraint\Constraint;
use Yiisoft\Db\Exception\NotSupportedException;
use Yiisoft\Db\Schema\Column\BinaryColumnSchema;
use Yiisoft\Db\Schema\Column\BooleanColumnSchema;
use Yiisoft\Db\Schema\Column\ColumnSchemaInterface;
use Yiisoft\Db\Schema\Column\DoubleColumnSchema;
use Yiisoft\Db\Schema\Column\IntegerColumnSchema;
use Yiisoft\Db\Schema\Column\JsonColumnSchema;
use Yiisoft\Db\Schema\Column\StringColumnSchema;
use Yiisoft\Db\Schema\Column\BigIntColumnSchema;

use function array_change_key_case;
use function array_map;
@@ -394,24 +402,53 @@ protected function findTableNames(string $schema): array
}

/**
* Extracts the PHP type from an abstract DB type.
* Creates a column schema for the database.
*
* @param ColumnSchemaInterface $column The column schema information.
* This method may be overridden by child classes to create a DBMS-specific column schema.
*
* @param string $type The abstract data type.
* @param string $name The column name.
* @param mixed ...$info The column information.
* @psalm-param array{unsigned?: bool} $info The set of parameters may be different for a specific DBMS.
*
* @return ColumnSchemaInterface
*/
protected function createColumnSchema(string $type, string $name, mixed ...$info): ColumnSchemaInterface
{
$phpType = $this->getColumnPhpType($type);
$isUnsigned = !empty($info['unsigned']);

if (
$isUnsigned && PHP_INT_SIZE === 4 && $type === SchemaInterface::TYPE_INTEGER
|| ($isUnsigned || PHP_INT_SIZE !== 8) && $type === SchemaInterface::TYPE_BIGINT
) {
$column = new BigIntColumnSchema($name);
} else {
$column = $this->createPhpTypeColumnSchema($phpType, $name);
Tigrov marked this conversation as resolved.
Show resolved Hide resolved
}

$column->type($type);
$column->phpType($phpType);
$column->unsigned($isUnsigned);

return $column;
}

/**
* Get the PHP type from an abstract database type.
*
* @param string $type The abstract database type.
*
* @return string The PHP type name.
*/
protected function getColumnPhpType(ColumnSchemaInterface $column): string
protected function getColumnPhpType(string $type): string
{
return match ($column->getType()) {
return match ($type) {
// abstract type => php type
SchemaInterface::TYPE_TINYINT => SchemaInterface::PHP_TYPE_INTEGER,
SchemaInterface::TYPE_SMALLINT => SchemaInterface::PHP_TYPE_INTEGER,
SchemaInterface::TYPE_INTEGER => PHP_INT_SIZE === 4 && $column->isUnsigned()
? SchemaInterface::PHP_TYPE_STRING
: SchemaInterface::PHP_TYPE_INTEGER,
SchemaInterface::TYPE_BIGINT => PHP_INT_SIZE === 8 && !$column->isUnsigned()
? SchemaInterface::PHP_TYPE_INTEGER
: SchemaInterface::PHP_TYPE_STRING,
SchemaInterface::TYPE_INTEGER => SchemaInterface::PHP_TYPE_INTEGER,
SchemaInterface::TYPE_BIGINT => SchemaInterface::PHP_TYPE_INTEGER,
SchemaInterface::TYPE_BOOLEAN => SchemaInterface::PHP_TYPE_BOOLEAN,
SchemaInterface::TYPE_DECIMAL => SchemaInterface::PHP_TYPE_DOUBLE,
SchemaInterface::TYPE_FLOAT => SchemaInterface::PHP_TYPE_DOUBLE,
@@ -422,6 +459,18 @@ protected function getColumnPhpType(ColumnSchemaInterface $column): string
};
}

protected function createPhpTypeColumnSchema(string $phpType, string $name): ColumnSchemaInterface
Tigrov marked this conversation as resolved.
Show resolved Hide resolved
{
return match ($phpType) {
SchemaInterface::PHP_TYPE_INTEGER => new IntegerColumnSchema($name),
SchemaInterface::PHP_TYPE_DOUBLE => new DoubleColumnSchema($name),
SchemaInterface::PHP_TYPE_BOOLEAN => new BooleanColumnSchema($name),
SchemaInterface::PHP_TYPE_RESOURCE => new BinaryColumnSchema($name),
SchemaInterface::PHP_TYPE_ARRAY => new JsonColumnSchema($name),
default => new StringColumnSchema($name),
};
}

/**
* Returns the metadata of the given type for all tables in the given schema.
*
1 change: 1 addition & 0 deletions src/Schema/AbstractTableSchema.php
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
namespace Yiisoft\Db\Schema;

use Yiisoft\Db\Exception\NotSupportedException;
use Yiisoft\Db\Schema\Column\ColumnSchemaInterface;

use function array_keys;

219 changes: 219 additions & 0 deletions src/Schema/Column/AbstractColumnSchema.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Db\Schema\Column;

/**
* Represents the metadata of a column in a database table.
*
* It provides information about the column's name, type, size, precision, and other details.
*
* The `ColumnSchema` class is used to store and retrieve metadata about a column in a database table.
*
* It's typically used in conjunction with the TableSchema class, which represents the metadata of a database table as a
* whole.
*
* Here is an example of how to use the `ColumnSchema` class:
*
* ```php
* use Yiisoft\Db\Schema\ColumnSchema;
*
* $column = new ColumnSchema();
* $column->name('id');
* $column->allowNull(false);
* $column->dbType('int(11)');
* $column->phpType('integer');
* $column->type('integer');
* $column->defaultValue(0);
* $column->autoIncrement(true);
* $column->primaryKey(true);
* ``
*/
abstract class AbstractColumnSchema implements ColumnSchemaInterface
{
private bool $allowNull = false;
private bool $autoIncrement = false;
private string|null $comment = null;
private bool $computed = false;
private string|null $dbType = null;
private mixed $defaultValue = null;
private array|null $enumValues = null;
private string|null $extra = null;
private bool $isPrimaryKey = false;
private string|null $phpType = null;
private int|null $precision = null;
private int|null $scale = null;
private int|null $size = null;
private string $type = '';
private bool $unsigned = false;

public function __construct(private string $name)
Tigrov marked this conversation as resolved.
Show resolved Hide resolved
{
}

public function allowNull(bool $value): void
{
$this->allowNull = $value;
}

public function autoIncrement(bool $value): void
{
$this->autoIncrement = $value;
}

public function comment(string|null $value): void
{
$this->comment = $value;
}

public function computed(bool $value): void

Check warning on line 70 in src/Schema/Column/AbstractColumnSchema.php

Codecov / codecov/patch

src/Schema/Column/AbstractColumnSchema.php#L70

Added line #L70 was not covered by tests
{
$this->computed = $value;

Check warning on line 72 in src/Schema/Column/AbstractColumnSchema.php

Codecov / codecov/patch

src/Schema/Column/AbstractColumnSchema.php#L72

Added line #L72 was not covered by tests
}

public function dbType(string|null $value): void
{
$this->dbType = $value;
}

public function dbTypecast(mixed $value): mixed
{
return $value;
}

public function defaultValue(mixed $value): void
{
$this->defaultValue = $value;
}

public function enumValues(array|null $value): void
{
$this->enumValues = $value;
}

public function extra(string|null $value): void
{
$this->extra = $value;
}

public function getComment(): string|null
{
return $this->comment;
}

public function getDbType(): string|null
{
return $this->dbType;
}

public function getDefaultValue(): mixed
{
return $this->defaultValue;
}

public function getEnumValues(): array|null
{
return $this->enumValues;
}

public function getExtra(): string|null
{
return $this->extra;
}

public function getName(): string
{
return $this->name;
}

public function getPrecision(): int|null
{
return $this->precision;
}

public function getPhpType(): string|null
{
return $this->phpType;
}

public function getScale(): int|null
{
return $this->scale;
}

public function getSize(): int|null
{
return $this->size;
}

public function getType(): string
{
return $this->type;
}

public function isAllowNull(): bool
{
return $this->allowNull;
}

public function isAutoIncrement(): bool
{
return $this->autoIncrement;
}

public function isComputed(): bool

Check warning on line 165 in src/Schema/Column/AbstractColumnSchema.php

Codecov / codecov/patch

src/Schema/Column/AbstractColumnSchema.php#L165

Added line #L165 was not covered by tests
{
return $this->computed;

Check warning on line 167 in src/Schema/Column/AbstractColumnSchema.php

Codecov / codecov/patch

src/Schema/Column/AbstractColumnSchema.php#L167

Added line #L167 was not covered by tests
}

public function isPrimaryKey(): bool
{
return $this->isPrimaryKey;
}

public function isUnsigned(): bool
{
return $this->unsigned;
}

public function phpType(string|null $value): void
{
$this->phpType = $value;
}

public function phpTypecast(mixed $value): mixed
{
return $value;
}

public function precision(int|null $value): void
{
$this->precision = $value;
}

public function primaryKey(bool $value): void
{
$this->isPrimaryKey = $value;
}

public function scale(int|null $value): void
{
$this->scale = $value;
}

public function size(int|null $value): void
{
$this->size = $value;
}

public function type(string $value): void
{
$this->type = $value;
}

public function unsigned(bool $value): void
{
$this->unsigned = $value;
}
}
Loading