Skip to content

Commit

Permalink
Rename composite type to structured type (#338)
Browse files Browse the repository at this point in the history
* Rename composite type to structured type

* Remove `Structured` folder, add FQN

* Fix test issues

* Add line to CHANGELOG.md [skip ci]

* fix changelog

---------

Co-authored-by: Sergei Predvoditelev <[email protected]>
  • Loading branch information
Tigrov and vjik authored Feb 25, 2024
1 parent a023a09 commit 0c5ad2e
Show file tree
Hide file tree
Showing 16 changed files with 173 additions and 167 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

- Bug #316, #6: Support table view constraints (@Tigrov)
- Enh #324: Change property `Schema::$typeMap` to constant `Schema::TYPE_MAP` (@Tigrov)
- Enh #303: Support composite types (@Tigrov)
- Enh #303, #338: Support structured type (@Tigrov)
- Enh #330: Create instance of `ArrayParser` directly (@Tigrov)
- Bug #331: Exclude from index column names fields specified in `INCLUDE` clause (@Tigrov)
- Enh #334: Minor `DDLQueryBuilder` refactoring (@Tigrov)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@
use Yiisoft\Db\Exception\NotSupportedException;
use Yiisoft\Db\Expression\ExpressionBuilderInterface;
use Yiisoft\Db\Expression\ExpressionInterface;
use Yiisoft\Db\Pgsql\Composite\CompositeExpression;
use Yiisoft\Db\Pgsql\StructuredExpression;
use Yiisoft\Db\Query\QueryInterface;
use Yiisoft\Db\QueryBuilder\QueryBuilderInterface;

use function implode;

/**
* Builds expressions for {@see CompositeExpression} for PostgreSQL Server.
* Builds expressions for {@see StructuredExpression} for PostgreSQL Server.
*/
final class CompositeExpressionBuilder implements ExpressionBuilderInterface
final class StructuredExpressionBuilder implements ExpressionBuilderInterface
{
public function __construct(private QueryBuilderInterface $queryBuilder)
{
Expand All @@ -28,7 +28,7 @@ public function __construct(private QueryBuilderInterface $queryBuilder)
/**
* The method builds the raw SQL from the expression that won't be additionally escaped or quoted.
*
* @param CompositeExpression $expression The expression build.
* @param StructuredExpression $expression The expression build.
* @param array $params The binding parameters.
*
* @throws Exception
Expand Down Expand Up @@ -71,7 +71,7 @@ public function build(ExpressionInterface $expression, array &$params = []): str
* @throws InvalidConfigException
* @throws NotSupportedException
*/
private function buildPlaceholders(CompositeExpression $expression, array &$params): array
private function buildPlaceholders(StructuredExpression $expression, array &$params): array
{
$value = $expression->getNormalizedValue();

Expand Down Expand Up @@ -101,7 +101,7 @@ private function buildPlaceholders(CompositeExpression $expression, array &$para
/**
* @return string The typecast expression based on {@see type}.
*/
private function getTypeHint(CompositeExpression $expression): string
private function getTypeHint(StructuredExpression $expression): string
{
$type = $expression->getType();

Expand Down
22 changes: 10 additions & 12 deletions src/ColumnSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
use Yiisoft\Db\Expression\ArrayExpression;
use Yiisoft\Db\Expression\ExpressionInterface;
use Yiisoft\Db\Expression\JsonExpression;
use Yiisoft\Db\Pgsql\Composite\CompositeExpression;
use Yiisoft\Db\Pgsql\Composite\CompositeParser;
use Yiisoft\Db\Schema\AbstractColumnSchema;
use Yiisoft\Db\Schema\ColumnSchemaInterface;
use Yiisoft\Db\Schema\SchemaInterface;
Expand Down Expand Up @@ -62,7 +60,7 @@ final class ColumnSchema extends AbstractColumnSchema
private string|null $sequenceName = null;

/**
* @var ColumnSchemaInterface[] Columns metadata of the composite type.
* @var ColumnSchemaInterface[] Columns metadata of the structured type.
* @psalm-var array<string, ColumnSchemaInterface>
*/
private array $columns = [];
Expand All @@ -83,7 +81,7 @@ public function dbTypecast(mixed $value): mixed
return $value;
}

if ($this->getType() === Schema::TYPE_COMPOSITE) {
if ($this->getType() === Schema::TYPE_STRUCTURED) {
$value = $this->dbTypecastArray($value, $this->dimension);
}

Expand Down Expand Up @@ -146,7 +144,7 @@ private function dbTypecastValue(mixed $value): mixed
? str_pad(decbin($value), (int) $this->getSize(), '0', STR_PAD_LEFT)
: (string) $value,

Schema::TYPE_COMPOSITE => new CompositeExpression($value, $this->getDbType(), $this->columns),
Schema::TYPE_STRUCTURED => new StructuredExpression($value, $this->getDbType(), $this->columns),

default => $this->typecast($value),
};
Expand Down Expand Up @@ -203,19 +201,19 @@ private function phpTypecastValue(mixed $value): mixed
SchemaInterface::TYPE_JSON
=> json_decode((string) $value, true, 512, JSON_THROW_ON_ERROR),

Schema::TYPE_COMPOSITE => $this->phpTypecastComposite($value),
Schema::TYPE_STRUCTURED => $this->phpTypecastStructured($value),

default => parent::phpTypecast($value),
};
}

/**
* Converts the input value according to the composite type after retrieval from the database.
* Converts the input value according to the structured type after retrieval from the database.
*/
private function phpTypecastComposite(mixed $value): array|null
private function phpTypecastStructured(mixed $value): array|null
{
if (is_string($value)) {
$value = (new CompositeParser())->parse($value);
$value = (new StructuredParser())->parse($value);
}

if (!is_iterable($value)) {
Expand Down Expand Up @@ -276,9 +274,9 @@ public function sequenceName(string|null $sequenceName): void
}

/**
* Set columns of the composite type.
* Set columns of the structured type.
*
* @param ColumnSchemaInterface[] $columns The metadata of the composite type columns.
* @param ColumnSchemaInterface[] $columns The metadata of the structured type columns.
* @psalm-param array<string, ColumnSchemaInterface> $columns
*/
public function columns(array $columns): void
Expand All @@ -287,7 +285,7 @@ public function columns(array $columns): void
}

/**
* Get the metadata of the composite type columns.
* Get the metadata of the structured type columns.
*
* @return ColumnSchemaInterface[]
*/
Expand Down
5 changes: 2 additions & 3 deletions src/DQLQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@
use Yiisoft\Db\Expression\ExpressionBuilderInterface;
use Yiisoft\Db\Expression\JsonExpression;
use Yiisoft\Db\Pgsql\Builder\ArrayExpressionBuilder;
use Yiisoft\Db\Pgsql\Builder\CompositeExpressionBuilder;
use Yiisoft\Db\Pgsql\Builder\StructuredExpressionBuilder;
use Yiisoft\Db\Pgsql\Builder\JsonExpressionBuilder;
use Yiisoft\Db\Pgsql\Composite\CompositeExpression;
use Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder;
use Yiisoft\Db\QueryBuilder\Condition\LikeCondition;

Expand Down Expand Up @@ -52,7 +51,7 @@ protected function defaultExpressionBuilders(): array
return array_merge(parent::defaultExpressionBuilders(), [
ArrayExpression::class => ArrayExpressionBuilder::class,
JsonExpression::class => JsonExpressionBuilder::class,
CompositeExpression::class => CompositeExpressionBuilder::class,
StructuredExpression::class => StructuredExpressionBuilder::class,
]);
}
}
20 changes: 10 additions & 10 deletions src/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ final class Schema extends AbstractPdoSchema
*/
public const TYPE_BIT = 'bit';
/**
* Define the abstract column type as `composite`.
* Define the abstract column type as `structured`.
*/
public const TYPE_COMPOSITE = 'composite';
public const TYPE_STRUCTURED = 'structured';

/**
* The mapping from physical column types (keys) to abstract column types (values).
Expand Down Expand Up @@ -826,11 +826,11 @@ protected function loadColumnSchema(array $info): ColumnSchemaInterface
}

if ($info['type_type'] === 'c') {
$column->type(self::TYPE_COMPOSITE);
$composite = $this->resolveTableName((string) $column->getDbType());
$column->type(self::TYPE_STRUCTURED);
$structured = $this->resolveTableName((string) $column->getDbType());

if ($this->findColumns($composite)) {
$column->columns($composite->getColumns());
if ($this->findColumns($structured)) {
$column->columns($structured->getColumns());
}
} else {
$column->type(self::TYPE_MAP[(string) $column->getDbType()] ?? self::TYPE_STRING);
Expand All @@ -839,12 +839,12 @@ protected function loadColumnSchema(array $info): ColumnSchemaInterface
$column->phpType($this->getColumnPhpType($column));
$column->defaultValue($this->normalizeDefaultValue($defaultValue, $column));

if ($column->getType() === self::TYPE_COMPOSITE && $column->getDimension() === 0) {
if ($column->getType() === self::TYPE_STRUCTURED && $column->getDimension() === 0) {
/** @psalm-var array|null $defaultValue */
$defaultValue = $column->getDefaultValue();
if (is_array($defaultValue)) {
foreach ($column->getColumns() as $compositeColumnName => $compositeColumn) {
$compositeColumn->defaultValue($defaultValue[$compositeColumnName] ?? null);
foreach ($column->getColumns() as $structuredColumnName => $structuredColumn) {
$structuredColumn->defaultValue($defaultValue[$structuredColumnName] ?? null);
}
}
}
Expand All @@ -863,7 +863,7 @@ protected function getColumnPhpType(ColumnSchemaInterface $column): string
{
return match ($column->getType()) {
self::TYPE_BIT => self::PHP_TYPE_INTEGER,
self::TYPE_COMPOSITE => self::PHP_TYPE_ARRAY,
self::TYPE_STRUCTURED => self::PHP_TYPE_ARRAY,
default => parent::getColumnPhpType($column),
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,31 @@

declare(strict_types=1);

namespace Yiisoft\Db\Pgsql\Composite;
namespace Yiisoft\Db\Pgsql;

use Traversable;
use Yiisoft\Db\Expression\ExpressionInterface;
use Yiisoft\Db\Schema\ColumnSchemaInterface;

use function array_key_exists;
use function array_keys;
use function is_iterable;
use function iterator_to_array;

/**
* Represents a composite type SQL expression.
* Represents a structured type SQL expression.
*
* @see https://en.wikipedia.org/wiki/Structured_type
*
* For example:
*
* ```php
* new CompositeExpression(['price' => 10, 'currency_code' => 'USD']);
* new StructuredExpression(['price' => 10, 'currency_code' => 'USD']);
* ```
*
* Will be encoded to `ROW(10, USD)`
*/
class CompositeExpression implements ExpressionInterface
class StructuredExpression implements ExpressionInterface
{
/**
* @param ColumnSchemaInterface[] $columns
Expand All @@ -33,7 +40,7 @@ public function __construct(
}

/**
* The composite type name.
* The structured type name.
*
* Defaults to `null` which means the type is not explicitly specified.
*
Expand All @@ -46,7 +53,7 @@ public function getType(): string|null
}

/**
* The composite type columns that are used for value normalization and type casting.
* The structured type columns that are used for value normalization and type casting.
*
* @return ColumnSchemaInterface[]
*/
Expand All @@ -56,7 +63,7 @@ public function getColumns(): array
}

/**
* The content of the composite type. It can be represented as an associative array of composite type column names
* The content of the structured type. It can be represented as an associative array of structured type column names
* and values.
*/
public function getValue(): mixed
Expand All @@ -65,7 +72,7 @@ public function getValue(): mixed
}

/**
* Sorted values according to the order of composite type columns,
* Sorted values according to the order of structured type columns,
* indexed keys are replaced with column names,
* missing elements are filled in with default values,
* excessive elements are removed.
Expand Down
10 changes: 6 additions & 4 deletions src/Composite/CompositeParser.php → src/StructuredParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@

declare(strict_types=1);

namespace Yiisoft\Db\Pgsql\Composite;
namespace Yiisoft\Db\Pgsql;

use function in_array;

/**
* Composite type representation to PHP array parser for PostgreSQL Server.
* Structured type representation to PHP array parser for PostgreSQL Server.
*/
final class CompositeParser
final class StructuredParser
{
/**
* Converts composite type value from PostgreSQL to PHP array
* Converts structured (composite) type value from PostgreSQL to PHP array
*
* @param string $value String to convert.
*/
Expand Down
12 changes: 6 additions & 6 deletions tests/ColumnSchemaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -212,14 +212,14 @@ public function testPrimaryKeyOfView()
$this->assertFalse($tableSchema->getColumn('C_index_2_2')->isPrimaryKey());
}

public function testCompositeType(): void
public function testStructuredType(): void
{
$db = $this->getConnection(true);
$command = $db->createCommand();
$schema = $db->getSchema();
$tableSchema = $schema->getTableSchema('test_composite_type');
$tableSchema = $schema->getTableSchema('test_structured_type');

$command->insert('test_composite_type', [
$command->insert('test_structured_type', [
'price_col' => ['value' => 10.0, 'currency_code' => 'USD'],
'price_array' => [
null,
Expand All @@ -235,7 +235,7 @@ public function testCompositeType(): void
],
])->execute();

$query = (new Query($db))->from('test_composite_type')->one();
$query = (new Query($db))->from('test_structured_type')->one();

$priceColPhpType = $tableSchema->getColumn('price_col')->phpTypecast($query['price_col']);
$priceDefaultPhpType = $tableSchema->getColumn('price_default')->phpTypecast($query['price_default']);
Expand Down Expand Up @@ -275,14 +275,14 @@ public function testCompositeType(): void

$priceArray = $tableSchema->getColumn('price_array');
$this->assertEquals(
new ArrayExpression([], 'currency_money_composite', 1),
new ArrayExpression([], 'currency_money_structured', 1),
$priceArray->dbTypecast(1),
'For scalar value returns empty array'
);

$priceArray2 = $tableSchema->getColumn('price_array2');
$this->assertEquals(
new ArrayExpression([null, null], 'currency_money_composite', 2),
new ArrayExpression([null, null], 'currency_money_structured', 2),
$priceArray2->dbTypecast([null, null]),
'Double array of null values'
);
Expand Down
24 changes: 0 additions & 24 deletions tests/CompositeExpressionTest.php

This file was deleted.

Loading

0 comments on commit 0c5ad2e

Please sign in to comment.