Skip to content

Commit

Permalink
Add ColumnDefinitionBuilder (#322)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tigrov authored Oct 15, 2024
1 parent a87695b commit d43b696
Show file tree
Hide file tree
Showing 10 changed files with 167 additions and 22 deletions.
9 changes: 5 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@
## 2.0.0 under development

- Enh #289: Implement `SqlParser` and `ExpressionBuilder` driver classes (@Tigrov)
- Enh #273: Implement `ColumnSchemaInterface` classes according to the data type of database table columns
- New #273: Implement `ColumnSchemaInterface` classes according to the data type of database table columns
for type casting performance. Related with yiisoft/db#752 (@Tigrov)
- Chg #307: Replace call of `SchemaInterface::getRawTableName()` to `QuoterInterface::getRawTableName()` (@Tigrov)
- Enh #310: Add JSON overlaps condition builder (@Tigrov)
- New #310: Add JSON overlaps condition builder (@Tigrov)
- Enh #312: Update `bit` type according to main PR yiisoft/db#860 (@Tigrov)
- Enh #315: Raise minimum PHP version to `^8.1` with minor refactoring (@Tigrov)
- Enh #314: Implement `ColumnFactory` class (@Tigrov)
- New #314: Implement `ColumnFactory` class (@Tigrov)
- Enh #317: Separate column type constants (@Tigrov)
- Enh #318: Realize `ColumnBuilder` class (@Tigrov)
- New #318: Realize `ColumnBuilder` class (@Tigrov)
- Enh #320: Update according changes in `ColumnSchemaInterface` (@Tigrov)
- New #322: Add `ColumnDefinitionBuilder` class (@Tigrov)

## 1.2.0 March 21, 2024

Expand Down
100 changes: 100 additions & 0 deletions src/Column/ColumnDefinitionBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Db\Sqlite\Column;

use Yiisoft\Db\Constant\ColumnType;
use Yiisoft\Db\QueryBuilder\AbstractColumnDefinitionBuilder;
use Yiisoft\Db\Schema\Column\ColumnSchemaInterface;

final class ColumnDefinitionBuilder extends AbstractColumnDefinitionBuilder
{
protected const AUTO_INCREMENT_KEYWORD = 'AUTOINCREMENT';

protected const TYPES_WITH_SIZE = [
'bit',
'tinyint',
'smallint',
'mediumint',
'int',
'integer',
'bigint',
'float',
'real',
'double',
'decimal',
'numeric',
'char',
'varchar',
'text',
'blob',
'time',
'datetime',
'timestamp',
];

protected const TYPES_WITH_SCALE = [
'float',
'real',
'double',
'decimal',
'numeric',
];

public function build(ColumnSchemaInterface $column): string
{
return $this->buildType($column)
. $this->buildPrimaryKey($column)
. $this->buildAutoIncrement($column)
. $this->buildUnique($column)
. $this->buildNotNull($column)
. $this->buildDefault($column)
. $this->buildCheck($column)
. $this->buildReferences($column)
. $this->buildExtra($column)
. $this->buildComment($column);
}

protected function buildComment(ColumnSchemaInterface $column): string
{
$comment = $column->getComment();

return $comment === null || $comment === '' ? '' : ' /* ' . str_replace('*/', '*\/', $comment) . ' */';
}

protected function buildNotNull(ColumnSchemaInterface $column): string
{
return $column->isPrimaryKey() ? ' NOT NULL' : parent::buildNotNull($column);
}

protected function getDbType(ColumnSchemaInterface $column): string
{
/** @psalm-suppress DocblockTypeContradiction */
return match ($column->getType()) {
ColumnType::BOOLEAN => 'boolean',
ColumnType::BIT => 'bit',
ColumnType::TINYINT => $column->isAutoIncrement() ? 'integer' : 'tinyint',
ColumnType::SMALLINT => $column->isAutoIncrement() ? 'integer' : 'smallint',
ColumnType::INTEGER => 'integer',
ColumnType::BIGINT => $column->isAutoIncrement() ? 'integer' : 'bigint',
ColumnType::FLOAT => 'float',
ColumnType::DOUBLE => 'double',
ColumnType::DECIMAL => 'decimal',
ColumnType::MONEY => 'decimal',
ColumnType::CHAR => 'char',
ColumnType::STRING => 'varchar',
ColumnType::TEXT => 'text',
ColumnType::BINARY => 'blob',
ColumnType::UUID => 'blob(16)',
ColumnType::DATETIME => 'datetime',
ColumnType::TIMESTAMP => 'timestamp',
ColumnType::DATE => 'date',
ColumnType::TIME => 'time',
ColumnType::ARRAY => 'json',
ColumnType::STRUCTURED => 'json',
ColumnType::JSON => 'json',
default => 'varchar',
};
}
}
1 change: 0 additions & 1 deletion src/Column/ColumnFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ final class ColumnFactory extends AbstractColumnFactory
'numeric' => ColumnType::DECIMAL,
'char' => ColumnType::CHAR,
'varchar' => ColumnType::STRING,
'string' => ColumnType::STRING,
'enum' => ColumnType::STRING,
'tinytext' => ColumnType::TEXT,
'mediumtext' => ColumnType::TEXT,
Expand Down
7 changes: 0 additions & 7 deletions src/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@
use Yiisoft\Db\Driver\Pdo\AbstractPdoConnection;
use Yiisoft\Db\Driver\Pdo\PdoCommandInterface;
use Yiisoft\Db\QueryBuilder\QueryBuilderInterface;
use Yiisoft\Db\Schema\Column\ColumnFactoryInterface;
use Yiisoft\Db\Schema\Quoter;
use Yiisoft\Db\Schema\QuoterInterface;
use Yiisoft\Db\Schema\SchemaInterface;
use Yiisoft\Db\Sqlite\Column\ColumnFactory;
use Yiisoft\Db\Transaction\TransactionInterface;

use function str_starts_with;
Expand Down Expand Up @@ -72,11 +70,6 @@ public function getQueryBuilder(): QueryBuilderInterface
return $this->queryBuilder;
}

public function getColumnFactory(): ColumnFactoryInterface
{
return new ColumnFactory();
}

public function getQuoter(): QuoterInterface
{
if ($this->quoter === null) {
Expand Down
5 changes: 4 additions & 1 deletion src/QueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Yiisoft\Db\QueryBuilder\AbstractQueryBuilder;
use Yiisoft\Db\Schema\QuoterInterface;
use Yiisoft\Db\Schema\SchemaInterface;
use Yiisoft\Db\Sqlite\Column\ColumnDefinitionBuilder;

/**
* Implements the SQLite Server specific query builder.
Expand Down Expand Up @@ -50,6 +51,8 @@ public function __construct(QuoterInterface $quoter, SchemaInterface $schema)
$ddlBuilder = new DDLQueryBuilder($this, $quoter, $schema);
$dmlBuilder = new DMLQueryBuilder($this, $quoter, $schema);
$dqlBuilder = new DQLQueryBuilder($this, $quoter);
parent::__construct($quoter, $schema, $ddlBuilder, $dmlBuilder, $dqlBuilder);
$columnDefinitionBuilder = new ColumnDefinitionBuilder($this);

parent::__construct($quoter, $schema, $ddlBuilder, $dmlBuilder, $dqlBuilder, $columnDefinitionBuilder);
}
}
11 changes: 10 additions & 1 deletion src/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@
use Yiisoft\Db\Expression\Expression;
use Yiisoft\Db\Helper\DbArrayHelper;
use Yiisoft\Db\Schema\Builder\ColumnInterface;
use Yiisoft\Db\Schema\Column\ColumnFactoryInterface;
use Yiisoft\Db\Schema\Column\ColumnSchemaInterface;
use Yiisoft\Db\Schema\TableSchemaInterface;
use Yiisoft\Db\Sqlite\Column\ColumnBuilder;
use Yiisoft\Db\Sqlite\Column\ColumnFactory;

use function array_change_key_case;
use function array_column;
Expand Down Expand Up @@ -73,11 +76,17 @@
*/
final class Schema extends AbstractPdoSchema
{
/** @deprecated Use {@see ColumnBuilder} instead. Will be removed in 2.0. */
public function createColumn(string $type, array|int|string $length = null): ColumnInterface
{
return new Column($type, $length);
}

public function getColumnFactory(): ColumnFactoryInterface
{
return new ColumnFactory();
}

/**
* Returns all table names in the database.
*
Expand Down Expand Up @@ -437,7 +446,7 @@ public function getSchemaDefaultValues(string $schema = '', bool $refresh = fals
*/
private function loadColumnSchema(array $info): ColumnSchemaInterface
{
$columnFactory = $this->db->getColumnFactory();
$columnFactory = $this->getColumnFactory();

$dbType = strtolower($info['type']);
$column = $columnFactory->fromDefinition($dbType, ['name' => $info['name']]);
Expand Down
8 changes: 0 additions & 8 deletions tests/ConnectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
use Yiisoft\Db\Exception\InvalidConfigException;
use Yiisoft\Db\Exception\NotSupportedException;
use Yiisoft\Db\Profiler\ProfilerInterface;
use Yiisoft\Db\Sqlite\Column\ColumnFactory;
use Yiisoft\Db\Sqlite\Tests\Support\TestTrait;
use Yiisoft\Db\Tests\Common\CommonConnectionTest;
use Yiisoft\Db\Transaction\TransactionInterface;
Expand Down Expand Up @@ -182,13 +181,6 @@ private function runExceptionTest(ConnectionInterface $db): void
$this->assertTrue($thrown, 'An exception should have been thrown by the command.');
}

public function testGetColumnFactory(): void
{
$db = $this->getConnection();

$this->assertInstanceOf(ColumnFactory::class, $db->getColumnFactory());
}

private function createProfiler(): ProfilerInterface
{
return $this->createMock(ProfilerInterface::class);
Expand Down
33 changes: 33 additions & 0 deletions tests/Provider/QueryBuilderProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Yiisoft\Db\Sqlite\Tests\Provider;

use Yiisoft\Db\Constant\PseudoType;
use Yiisoft\Db\Expression\Expression;
use Yiisoft\Db\Expression\JsonExpression;
use Yiisoft\Db\Query\Query;
Expand Down Expand Up @@ -257,4 +258,36 @@ public static function upsert(): array

return $upsert;
}

public static function buildColumnDefinition(): array
{
$values = parent::buildColumnDefinition();

$values[PseudoType::PK][0] = 'integer PRIMARY KEY AUTOINCREMENT NOT NULL';
$values[PseudoType::UPK][0] = 'integer PRIMARY KEY AUTOINCREMENT NOT NULL';
$values[PseudoType::BIGPK][0] = 'integer PRIMARY KEY AUTOINCREMENT NOT NULL';
$values[PseudoType::UBIGPK][0] = 'integer PRIMARY KEY AUTOINCREMENT NOT NULL';
$values[PseudoType::UUID_PK][0] = 'blob(16) PRIMARY KEY NOT NULL';
$values[PseudoType::UUID_PK_SEQ][0] = 'blob(16) PRIMARY KEY NOT NULL';
$values['primaryKey()'][0] = 'integer PRIMARY KEY AUTOINCREMENT NOT NULL';
$values['primaryKey(false)'][0] = 'integer PRIMARY KEY NOT NULL';
$values['smallPrimaryKey()'][0] = 'integer PRIMARY KEY AUTOINCREMENT NOT NULL';
$values['smallPrimaryKey(false)'][0] = 'smallint PRIMARY KEY NOT NULL';
$values['bigPrimaryKey()'][0] = 'integer PRIMARY KEY AUTOINCREMENT NOT NULL';
$values['bigPrimaryKey(false)'][0] = 'bigint PRIMARY KEY NOT NULL';
$values['uuidPrimaryKey()'][0] = 'blob(16) PRIMARY KEY NOT NULL';
$values['uuidPrimaryKey(false)'][0] = 'blob(16) PRIMARY KEY NOT NULL';
$values['money()'][0] = 'decimal(19,4)';
$values['money(10)'][0] = 'decimal(10,4)';
$values['money(10,2)'][0] = 'decimal(10,2)';
$values['money(null)'][0] = 'decimal';
$values['binary()'][0] = 'blob';
$values['binary(1000)'][0] = 'blob(1000)';
$values['uuid()'][0] = 'blob(16)';
$values["comment('comment')"][0] = 'varchar(255) /* comment */';
$values['integer()->primaryKey()'][0] = 'integer PRIMARY KEY NOT NULL';
$values['unsigned()'][0] = 'integer';

return $values;
}
}
7 changes: 7 additions & 0 deletions tests/QueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Yiisoft\Db\Query\Query;
use Yiisoft\Db\Query\QueryInterface;
use Yiisoft\Db\QueryBuilder\Condition\JsonOverlapsCondition;
use Yiisoft\Db\Schema\Column\ColumnSchemaInterface;
use Yiisoft\Db\Sqlite\Column;
use Yiisoft\Db\Sqlite\Tests\Support\TestTrait;
use Yiisoft\Db\Tests\Common\CommonQueryBuilderTest;
Expand Down Expand Up @@ -835,4 +836,10 @@ public function testJsonOverlapsConditionOperator(iterable|ExpressionInterface $

$db->close();
}

/** @dataProvider \Yiisoft\Db\Sqlite\Tests\Provider\QueryBuilderProvider::buildColumnDefinition() */
public function testBuildColumnDefinition(string $expected, ColumnSchemaInterface|string $column): void
{
parent::testBuildColumnDefinition($expected, $column);
}
}
8 changes: 8 additions & 0 deletions tests/SchemaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Yiisoft\Db\Exception\Exception;
use Yiisoft\Db\Exception\InvalidConfigException;
use Yiisoft\Db\Exception\NotSupportedException;
use Yiisoft\Db\Sqlite\Column\ColumnFactory;
use Yiisoft\Db\Sqlite\Schema;
use Yiisoft\Db\Sqlite\Tests\Support\TestTrait;
use Yiisoft\Db\Tests\Common\CommonSchemaTest;
Expand Down Expand Up @@ -359,4 +360,11 @@ public function testNotConnectionPDO(): void

$schema->refresh();
}

public function testGetColumnFactory(): void
{
$db = $this->getConnection();

$this->assertInstanceOf(ColumnFactory::class, $db->getSchema()->getColumnFactory());
}
}

0 comments on commit d43b696

Please sign in to comment.