Skip to content

Commit 226d840

Browse files
authored
Add ColumnDefinitionBuilder (#282)
1 parent 55bbd32 commit 226d840

12 files changed

+273
-27
lines changed

CHANGELOG.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@
66
from `$table, $columns, $rows` to `$table, $rows, $columns = []` (@Tigrov)
77
- Enh #260: Support `Traversable` values for `DMLQueryBuilder::batchInsert()` method with empty columns (@Tigrov)
88
- Enh #255: Implement `SqlParser` and `ExpressionBuilder` driver classes (@Tigrov)
9-
- Enh #236: Implement `ColumnSchemaInterface` classes according to the data type of database table columns
9+
- New #236: Implement `ColumnSchemaInterface` classes according to the data type of database table columns
1010
for type casting performance. Related with yiisoft/db#752 (@Tigrov)
1111
- Chg #272: Replace call of `SchemaInterface::getRawTableName()` to `QuoterInterface::getRawTableName()` (@Tigrov)
1212
- Enh #275: Refactor PHP type of `ColumnSchemaInterface` instances (@Tigrov)
1313
- Enh #277: Raise minimum PHP version to `^8.1` with minor refactoring (@Tigrov)
14-
- Enh #276: Implement `ColumnFactory` class (@Tigrov)
14+
- New #276: Implement `ColumnFactory` class (@Tigrov)
1515
- Enh #279: Separate column type constants (@Tigrov)
16-
- Enh #280: Realize `ColumnBuilder` class (@Tigrov)
16+
- New #280: Realize `ColumnBuilder` class (@Tigrov)
1717
- Enh #281: Update according changes in `ColumnSchemaInterface` (@Tigrov)
18+
- New #282: Add `ColumnDefinitionBuilder` class (@Tigrov)
1819

1920
## 1.3.0 March 21, 2024
2021

src/Column/ColumnBuilder.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,26 @@
99

1010
final class ColumnBuilder extends \Yiisoft\Db\Schema\Column\ColumnBuilder
1111
{
12+
public static function tinyint(int|null $size = 3): ColumnSchemaInterface
13+
{
14+
return parent::tinyint($size);
15+
}
16+
17+
public static function smallint(int|null $size = 5): ColumnSchemaInterface
18+
{
19+
return parent::smallint($size);
20+
}
21+
22+
public static function integer(int|null $size = 10): ColumnSchemaInterface
23+
{
24+
return parent::integer($size);
25+
}
26+
27+
public static function bigint(int|null $size = 20): ColumnSchemaInterface
28+
{
29+
return parent::bigint($size);
30+
}
31+
1232
public static function binary(int|null $size = null): ColumnSchemaInterface
1333
{
1434
return (new BinaryColumnSchema(ColumnType::BINARY))
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yiisoft\Db\Oracle\Column;
6+
7+
use Yiisoft\Db\Constant\ColumnType;
8+
use Yiisoft\Db\QueryBuilder\AbstractColumnDefinitionBuilder;
9+
use Yiisoft\Db\Schema\Column\ColumnSchemaInterface;
10+
11+
use function ceil;
12+
use function log10;
13+
use function strtoupper;
14+
15+
final class ColumnDefinitionBuilder extends AbstractColumnDefinitionBuilder
16+
{
17+
protected const AUTO_INCREMENT_KEYWORD = 'GENERATED BY DEFAULT AS IDENTITY';
18+
19+
protected const GENERATE_UUID_EXPRESSION = 'sys_guid()';
20+
21+
protected const TYPES_WITH_SIZE = [
22+
'varchar2',
23+
'nvarchar2',
24+
'number',
25+
'float',
26+
'timestamp',
27+
'interval day(0) to second',
28+
'raw',
29+
'urowid',
30+
'char',
31+
'nchar',
32+
];
33+
34+
protected const TYPES_WITH_SCALE = [
35+
'number',
36+
];
37+
38+
public function build(ColumnSchemaInterface $column): string
39+
{
40+
return $this->buildType($column)
41+
. $this->buildAutoIncrement($column)
42+
. $this->buildDefault($column)
43+
. $this->buildPrimaryKey($column)
44+
. $this->buildUnique($column)
45+
. $this->buildNotNull($column)
46+
. $this->buildCheck($column)
47+
. $this->buildReferences($column)
48+
. $this->buildExtra($column);
49+
}
50+
51+
protected function buildOnDelete(string $onDelete): string
52+
{
53+
return match ($onDelete = strtoupper($onDelete)) {
54+
'CASCADE',
55+
'SET NULL' => " ON DELETE $onDelete",
56+
default => '',
57+
};
58+
}
59+
60+
protected function buildOnUpdate(string $onUpdate): string
61+
{
62+
return '';
63+
}
64+
65+
protected function getDbType(ColumnSchemaInterface $column): string
66+
{
67+
$size = $column->getSize();
68+
69+
/** @psalm-suppress DocblockTypeContradiction */
70+
return match ($column->getType()) {
71+
ColumnType::BOOLEAN => 'number(1)',
72+
ColumnType::BIT => match (true) {
73+
$size === null => 'number(38)',
74+
$size <= 126 => 'number(' . ceil(log10(2 ** $size)) . ')',
75+
default => 'raw(' . ceil($size / 8) . ')',
76+
},
77+
ColumnType::TINYINT => 'number(' . ($size ?? 3) . ')',
78+
ColumnType::SMALLINT => 'number(' . ($size ?? 5) . ')',
79+
ColumnType::INTEGER => 'number(' . ($size ?? 10) . ')',
80+
ColumnType::BIGINT => 'number(' . ($size ?? 20) . ')',
81+
ColumnType::FLOAT => 'binary_float',
82+
ColumnType::DOUBLE => 'binary_double',
83+
ColumnType::DECIMAL => 'number(' . ($size ?? 10) . ',' . ($column->getScale() ?? 0) . ')',
84+
ColumnType::MONEY => 'number(' . ($size ?? 19) . ',' . ($column->getScale() ?? 4) . ')',
85+
ColumnType::CHAR => 'char',
86+
ColumnType::STRING => 'varchar2',
87+
ColumnType::TEXT => 'clob',
88+
ColumnType::BINARY => 'blob',
89+
ColumnType::UUID => 'raw(16)',
90+
ColumnType::DATETIME => 'timestamp',
91+
ColumnType::TIMESTAMP => 'timestamp',
92+
ColumnType::DATE => 'date',
93+
ColumnType::TIME => 'interval day(0) to second',
94+
ColumnType::ARRAY => 'json',
95+
ColumnType::STRUCTURED => 'json',
96+
ColumnType::JSON => 'json',
97+
default => 'varchar2',
98+
};
99+
}
100+
}

src/Connection.php

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@
1111
use Yiisoft\Db\Exception\InvalidArgumentException;
1212
use Yiisoft\Db\Exception\InvalidCallException;
1313
use Yiisoft\Db\Exception\InvalidConfigException;
14-
use Yiisoft\Db\Oracle\Column\ColumnFactory;
1514
use Yiisoft\Db\QueryBuilder\QueryBuilderInterface;
16-
use Yiisoft\Db\Schema\Column\ColumnFactoryInterface;
1715
use Yiisoft\Db\Schema\QuoterInterface;
1816
use Yiisoft\Db\Schema\SchemaInterface;
1917
use Yiisoft\Db\Transaction\TransactionInterface;
@@ -49,11 +47,6 @@ public function createTransaction(): TransactionInterface
4947
return new Transaction($this);
5048
}
5149

52-
public function getColumnFactory(): ColumnFactoryInterface
53-
{
54-
return new ColumnFactory();
55-
}
56-
5750
/**
5851
* Override base behaviour to support Oracle sequences.
5952
*

src/DDLQueryBuilder.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public function addForeignKey(
4747

4848
public function alterColumn(string $table, string $column, ColumnInterface|string $type): string
4949
{
50+
/** @psalm-suppress DeprecatedMethod */
5051
return 'ALTER TABLE '
5152
. $this->quoter->quoteTableName($table)
5253
. ' MODIFY '

src/QueryBuilder.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Yiisoft\Db\Constant\ColumnType;
88
use Yiisoft\Db\Constant\PseudoType;
9+
use Yiisoft\Db\Oracle\Column\ColumnDefinitionBuilder;
910
use Yiisoft\Db\QueryBuilder\AbstractQueryBuilder;
1011
use Yiisoft\Db\Schema\QuoterInterface;
1112
use Yiisoft\Db\Schema\SchemaInterface;
@@ -49,6 +50,8 @@ public function __construct(QuoterInterface $quoter, SchemaInterface $schema)
4950
$ddlBuilder = new DDLQueryBuilder($this, $quoter, $schema);
5051
$dmlBuilder = new DMLQueryBuilder($this, $quoter, $schema);
5152
$dqlBuilder = new DQLQueryBuilder($this, $quoter);
52-
parent::__construct($quoter, $schema, $ddlBuilder, $dmlBuilder, $dqlBuilder);
53+
$columnDefinitionBuilder = new ColumnDefinitionBuilder($this);
54+
55+
parent::__construct($quoter, $schema, $ddlBuilder, $dmlBuilder, $dqlBuilder, $columnDefinitionBuilder);
5356
}
5457
}

src/Schema.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
use Yiisoft\Db\Exception\NotSupportedException;
1919
use Yiisoft\Db\Expression\Expression;
2020
use Yiisoft\Db\Helper\DbArrayHelper;
21+
use Yiisoft\Db\Oracle\Column\ColumnFactory;
2122
use Yiisoft\Db\Schema\Builder\ColumnInterface;
23+
use Yiisoft\Db\Schema\Column\ColumnFactoryInterface;
2224
use Yiisoft\Db\Schema\Column\ColumnSchemaInterface;
2325
use Yiisoft\Db\Schema\TableSchemaInterface;
2426

@@ -71,11 +73,17 @@ public function __construct(protected ConnectionInterface $db, SchemaCache $sche
7173
parent::__construct($db, $schemaCache);
7274
}
7375

76+
/** @deprecated Use {@see ColumnBuilder} instead. Will be removed in 2.0. */
7477
public function createColumn(string $type, array|int|string $length = null): ColumnInterface
7578
{
7679
return new Column($type, $length);
7780
}
7881

82+
public function getColumnFactory(): ColumnFactoryInterface
83+
{
84+
return new ColumnFactory();
85+
}
86+
7987
protected function resolveTableName(string $name): TableSchemaInterface
8088
{
8189
$resolvedName = new TableSchema();
@@ -418,7 +426,7 @@ protected function getTableSequenceName(string $tableName): string|null
418426
*/
419427
private function loadColumnSchema(array $info): ColumnSchemaInterface
420428
{
421-
$columnFactory = $this->db->getColumnFactory();
429+
$columnFactory = $this->db->getSchema()->getColumnFactory();
422430

423431
$dbType = $info['data_type'];
424432
$column = $columnFactory->fromDbType($dbType, [

tests/ConnectionTest.php

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
use Yiisoft\Db\Exception\Exception;
1212
use Yiisoft\Db\Exception\InvalidConfigException;
1313
use Yiisoft\Db\Exception\NotSupportedException;
14-
use Yiisoft\Db\Oracle\Column\ColumnFactory;
1514
use Yiisoft\Db\Oracle\Tests\Support\TestTrait;
1615
use Yiisoft\Db\Tests\Common\CommonConnectionTest;
1716
use Yiisoft\Db\Transaction\TransactionInterface;
@@ -131,11 +130,4 @@ public function testSerialized(): void
131130
$this->assertEquals(123, $unserialized->createCommand('SELECT 123 FROM DUAL')->queryScalar());
132131
$this->assertNotNull($connection->getPDO());
133132
}
134-
135-
public function testGetColumnFactory(): void
136-
{
137-
$db = $this->getConnection();
138-
139-
$this->assertInstanceOf(ColumnFactory::class, $db->getColumnFactory());
140-
}
141133
}

tests/Provider/ColumnBuilderProvider.php

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,27 @@
44

55
namespace Yiisoft\Db\Oracle\Tests\Provider;
66

7-
use Yiisoft\Db\Constant\ColumnType;
87
use Yiisoft\Db\Oracle\Column\BinaryColumnSchema;
98

109
class ColumnBuilderProvider extends \Yiisoft\Db\Tests\Provider\ColumnBuilderProvider
1110
{
1211
public static function buildingMethods(): array
1312
{
14-
return [
15-
// building method, args, expected instance of, expected type, expected column method results
16-
...parent::buildingMethods(),
17-
['binary', [], BinaryColumnSchema::class, ColumnType::BINARY],
18-
['binary', [8], BinaryColumnSchema::class, ColumnType::BINARY, ['getSize' => 8]],
19-
];
13+
$values = parent::buildingMethods();
14+
15+
$values['primaryKey()'][4]['getSize'] = 10;
16+
$values['primaryKey(false)'][4]['getSize'] = 10;
17+
$values['smallPrimaryKey()'][4]['getSize'] = 5;
18+
$values['smallPrimaryKey(false)'][4]['getSize'] = 5;
19+
$values['bigPrimaryKey()'][4]['getSize'] = 20;
20+
$values['bigPrimaryKey(false)'][4]['getSize'] = 20;
21+
$values['tinyint()'][4]['getSize'] = 3;
22+
$values['smallint()'][4]['getSize'] = 5;
23+
$values['integer()'][4]['getSize'] = 10;
24+
$values['bigint()'][4]['getSize'] = 20;
25+
$values['binary()'][2] = BinaryColumnSchema::class;
26+
$values['binary(8)'][2] = BinaryColumnSchema::class;
27+
28+
return $values;
2029
}
2130
}

0 commit comments

Comments
 (0)