Skip to content

Commit 402c726

Browse files
authored
Refactor ColumnFactory (#288)
1 parent d992d1a commit 402c726

File tree

6 files changed

+81
-76
lines changed

6 files changed

+81
-76
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@
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-
- New #276: Implement `ColumnFactory` class (@Tigrov)
14+
- New #276, #288: Implement `ColumnFactory` class (@Tigrov)
1515
- Enh #279: Separate column type constants (@Tigrov)
1616
- New #280: Realize `ColumnBuilder` class (@Tigrov)
1717
- Enh #281: Update according changes in `ColumnSchemaInterface` (@Tigrov)
1818
- New #282: Add `ColumnDefinitionBuilder` class (@Tigrov)
1919
- Bug #285: Fix `DMLQueryBuilder::insertBatch()` method (@Tigrov)
2020
- Enh #283: Refactor `Dsn` class (@Tigrov)
2121
- Enh #286: Use constructor to create columns and initialize properties (@Tigrov)
22+
- Enh #288: Refactor `Schema::findColumns()` method (@Tigrov)
2223

2324
## 1.3.0 March 21, 2024
2425

src/Column/ColumnFactory.php

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
use Yiisoft\Db\Constant\ColumnType;
88
use Yiisoft\Db\Schema\Column\AbstractColumnFactory;
9-
use Yiisoft\Db\Schema\Column\ColumnSchemaInterface;
109

1110
use function preg_replace;
1211
use function strtolower;
@@ -19,10 +18,9 @@ final class ColumnFactory extends AbstractColumnFactory
1918
* @link https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/Data-Types.html
2019
*
2120
* @var string[]
22-
*
23-
* @psalm-suppress MissingClassConstType
21+
* @psalm-var array<string, ColumnType::*>
2422
*/
25-
private const TYPE_MAP = [
23+
protected const TYPE_MAP = [
2624
'char' => ColumnType::CHAR,
2725
'nchar' => ColumnType::CHAR,
2826
'varchar2' => ColumnType::STRING,
@@ -65,21 +63,15 @@ protected function getType(string $dbType, array $info = []): string
6563
return ColumnType::STRING;
6664
}
6765

68-
return self::TYPE_MAP[$dbType] ?? ColumnType::STRING;
66+
return parent::getType($dbType, $info);
6967
}
7068

71-
public function fromType(string $type, array $info = []): ColumnSchemaInterface
69+
protected function getColumnClass(string $type, array $info = []): string
7270
{
7371
if ($type === ColumnType::BINARY) {
74-
unset($info['type']);
75-
return new BinaryColumnSchema($type, ...$info);
72+
return BinaryColumnSchema::class;
7673
}
7774

78-
return parent::fromType($type, $info);
79-
}
80-
81-
protected function isDbType(string $dbType): bool
82-
{
83-
return isset(self::TYPE_MAP[$dbType]);
75+
return parent::getColumnClass($type, $info);
8476
}
8577
}

src/Schema.php

Lines changed: 57 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,18 @@
3838
/**
3939
* Implements the Oracle Server specific schema, supporting Oracle Server 11C and above.
4040
*
41-
* @psalm-type ColumnInfoArray = array{
41+
* @psalm-type ColumnArray = array{
4242
* column_name: string,
4343
* data_type: string,
4444
* data_scale: string|null,
45+
* identity_column: string,
4546
* size: string|null,
4647
* nullable: string,
4748
* data_default: string|null,
48-
* is_pk: string|null,
49-
* identity_column: string,
50-
* column_comment: string|null
49+
* constraint_type: string|null,
50+
* column_comment: string|null,
51+
* schema: string,
52+
* table: string
5153
* }
5254
*
5355
* @psalm-type ConstraintArray = array<
@@ -334,6 +336,9 @@ protected function loadTableDefaultValues(string $tableName): array
334336
*/
335337
protected function findColumns(TableSchemaInterface $table): bool
336338
{
339+
$schemaName = $table->getSchemaName();
340+
$tableName = $table->getName();
341+
337342
$sql = <<<SQL
338343
SELECT
339344
A.COLUMN_NAME,
@@ -343,30 +348,45 @@ protected function findColumns(TableSchemaInterface $table): bool
343348
(CASE WHEN A.CHAR_LENGTH > 0 THEN A.CHAR_LENGTH ELSE A.DATA_PRECISION END) AS "size",
344349
A.NULLABLE,
345350
A.DATA_DEFAULT,
346-
(
347-
SELECT COUNT(*)
348-
FROM ALL_CONSTRAINTS AC
349-
INNER JOIN ALL_CONS_COLUMNS ACC ON ACC.CONSTRAINT_NAME=AC.CONSTRAINT_NAME
350-
WHERE
351-
AC.OWNER = A.OWNER
352-
AND AC.TABLE_NAME = B.OBJECT_NAME
353-
AND ACC.COLUMN_NAME = A.COLUMN_NAME
354-
AND AC.CONSTRAINT_TYPE = 'P'
355-
) AS IS_PK,
351+
AC.CONSTRAINT_TYPE,
356352
COM.COMMENTS AS COLUMN_COMMENT
357353
FROM ALL_TAB_COLUMNS A
358-
INNER JOIN ALL_OBJECTS B ON B.OWNER = A.OWNER AND LTRIM(B.OBJECT_NAME) = LTRIM(A.TABLE_NAME)
359-
LEFT JOIN ALL_COL_COMMENTS COM ON (A.OWNER = COM.OWNER AND A.TABLE_NAME = COM.TABLE_NAME AND A.COLUMN_NAME = COM.COLUMN_NAME)
360-
WHERE
361-
A.OWNER = :schemaName
354+
INNER JOIN ALL_OBJECTS B
355+
ON B.OWNER = A.OWNER
356+
AND B.OBJECT_NAME = A.TABLE_NAME
357+
LEFT JOIN ALL_COL_COMMENTS COM
358+
ON COM.OWNER = A.OWNER
359+
AND COM.TABLE_NAME = A.TABLE_NAME
360+
AND COM.COLUMN_NAME = A.COLUMN_NAME
361+
LEFT JOIN ALL_CONSTRAINTS AC
362+
ON AC.OWNER = A.OWNER
363+
AND AC.TABLE_NAME = A.TABLE_NAME
364+
AND (AC.CONSTRAINT_TYPE = 'P'
365+
OR AC.CONSTRAINT_TYPE = 'U'
366+
AND (
367+
SELECT COUNT(*)
368+
FROM ALL_CONS_COLUMNS UCC
369+
WHERE UCC.CONSTRAINT_NAME = AC.CONSTRAINT_NAME
370+
AND UCC.TABLE_NAME = AC.TABLE_NAME
371+
AND UCC.OWNER = AC.OWNER
372+
) = 1
373+
)
374+
AND AC.CONSTRAINT_NAME IN (
375+
SELECT ACC.CONSTRAINT_NAME
376+
FROM ALL_CONS_COLUMNS ACC
377+
WHERE ACC.OWNER = A.OWNER
378+
AND ACC.TABLE_NAME = A.TABLE_NAME
379+
AND ACC.COLUMN_NAME = A.COLUMN_NAME
380+
)
381+
WHERE A.OWNER = :schemaName
382+
AND A.TABLE_NAME = :tableName
362383
AND B.OBJECT_TYPE IN ('TABLE', 'VIEW', 'MATERIALIZED VIEW')
363-
AND B.OBJECT_NAME = :tableName
364384
ORDER BY A.COLUMN_ID
365385
SQL;
366386

367387
$columns = $this->db->createCommand($sql, [
368-
':tableName' => $table->getName(),
369-
':schemaName' => $table->getSchemaName(),
388+
':schemaName' => $schemaName,
389+
':tableName' => $tableName,
370390
])->queryAll();
371391

372392
if ($columns === []) {
@@ -375,9 +395,12 @@ protected function findColumns(TableSchemaInterface $table): bool
375395

376396
/** @psalm-var string[][] $info */
377397
foreach ($columns as $info) {
378-
/** @psalm-var ColumnInfoArray $info */
379398
$info = array_change_key_case($info);
380399

400+
$info['schema'] = $schemaName;
401+
$info['table'] = $tableName;
402+
403+
/** @psalm-var ColumnArray $info */
381404
$column = $this->loadColumnSchema($info);
382405

383406
$table->column($info['column_name'], $column);
@@ -422,26 +445,24 @@ protected function getTableSequenceName(string $tableName): string|null
422445
*
423446
* @return ColumnSchemaInterface The column schema object.
424447
*
425-
* @psalm-param ColumnInfoArray $info The column information.
448+
* @psalm-param ColumnArray $info The column information.
426449
*/
427450
private function loadColumnSchema(array $info): ColumnSchemaInterface
428451
{
429-
$columnFactory = $this->db->getSchema()->getColumnFactory();
430-
431-
$dbType = $info['data_type'];
432-
$column = $columnFactory->fromDbType($dbType, [
452+
$column = $this->getColumnFactory()->fromDbType($info['data_type'], [
453+
'autoIncrement' => $info['identity_column'] === 'YES',
454+
'comment' => $info['column_comment'],
455+
'name' => $info['column_name'],
456+
'notNull' => $info['nullable'] !== 'Y',
457+
'primaryKey' => $info['constraint_type'] === 'P',
433458
'scale' => $info['data_scale'] !== null ? (int) $info['data_scale'] : null,
459+
'schema' => $info['schema'],
434460
'size' => $info['size'] !== null ? (int) $info['size'] : null,
461+
'table' => $info['table'],
462+
'unique' => $info['constraint_type'] === 'U',
435463
]);
436-
/** @psalm-suppress DeprecatedMethod */
437-
$column->name($info['column_name']);
438-
$column->notNull($info['nullable'] !== 'Y');
439-
$column->comment($info['column_comment']);
440-
$column->primaryKey((bool) $info['is_pk']);
441-
$column->autoIncrement($info['identity_column'] === 'YES');
442-
$column->defaultValue($this->normalizeDefaultValue($info['data_default'], $column));
443-
444-
return $column;
464+
465+
return $column->defaultValue($this->normalizeDefaultValue($info['data_default'], $column));
445466
}
446467

447468
/**

tests/ColumnSchemaTest.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public function testPhpTypeCast(): void
6969
$db->close();
7070
}
7171

72-
public function testColumnSchemaInstance()
72+
public function testColumnSchemaInstance(): void
7373
{
7474
$db = $this->getConnection(true);
7575
$schema = $db->getSchema();
@@ -82,18 +82,18 @@ public function testColumnSchemaInstance()
8282
}
8383

8484
/** @dataProvider \Yiisoft\Db\Oracle\Tests\Provider\ColumnSchemaProvider::predefinedTypes */
85-
public function testPredefinedType(string $className, string $type, string $phpType)
85+
public function testPredefinedType(string $className, string $type, string $phpType): void
8686
{
8787
parent::testPredefinedType($className, $type, $phpType);
8888
}
8989

9090
/** @dataProvider \Yiisoft\Db\Oracle\Tests\Provider\ColumnSchemaProvider::dbTypecastColumns */
91-
public function testDbTypecastColumns(string $className, array $values)
91+
public function testDbTypecastColumns(string $className, array $values): void
9292
{
9393
parent::testDbTypecastColumns($className, $values);
9494
}
9595

96-
public function testBinaryColumnSchema()
96+
public function testBinaryColumnSchema(): void
9797
{
9898
$binaryCol = new BinaryColumnSchema();
9999
$binaryCol->dbType('BLOB');
@@ -104,4 +104,16 @@ public function testBinaryColumnSchema()
104104
$binaryCol->dbTypecast(new Param("\x10\x11\x12", PDO::PARAM_LOB)),
105105
);
106106
}
107+
108+
public function testUniqueColumn(): void
109+
{
110+
$db = $this->getConnection(true);
111+
$schema = $db->getSchema();
112+
113+
$this->assertTrue($schema->getTableSchema('T_constraints_1')?->getColumn('C_unique')->isUnique());
114+
$this->assertFalse($schema->getTableSchema('T_constraints_2')?->getColumn('C_index_2_1')->isUnique());
115+
$this->assertFalse($schema->getTableSchema('T_constraints_2')?->getColumn('C_index_2_2')->isUnique());
116+
$this->assertTrue($schema->getTableSchema('T_upsert')?->getColumn('email')->isUnique());
117+
$this->assertFalse($schema->getTableSchema('T_upsert')?->getColumn('recovery_email')->isUnique());
118+
}
107119
}

tests/Provider/SchemaProvider.php

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -278,15 +278,6 @@ public static function columns(): array
278278
];
279279
}
280280

281-
public static function columnsTypeChar(): array
282-
{
283-
return [
284-
['char_col', 'char', 100, 'CHAR'],
285-
['char_col2', 'string', 100, 'VARCHAR2'],
286-
['char_col3', 'string', 4000, 'VARCHAR2'],
287-
];
288-
}
289-
290281
public static function constraints(): array
291282
{
292283
$constraints = parent::constraints();

tests/SchemaTest.php

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -81,18 +81,6 @@ public function testGetSchemaDefaultValues(): void
8181
parent::testGetSchemaDefaultValues();
8282
}
8383

84-
/**
85-
* @dataProvider \Yiisoft\Db\Oracle\Tests\Provider\SchemaProvider::columnsTypeChar
86-
*/
87-
public function testGetStringFieldsSize(
88-
string $columnName,
89-
string $columnType,
90-
int|null $columnSize,
91-
string $columnDbType
92-
): void {
93-
parent::testGetStringFieldsSize($columnName, $columnType, $columnSize, $columnDbType);
94-
}
95-
9684
/**
9785
* @throws Exception
9886
* @throws InvalidConfigException

0 commit comments

Comments
 (0)