Skip to content

Commit

Permalink
fix: introspect of the view in the schema
Browse files Browse the repository at this point in the history
  • Loading branch information
nikophil committed Dec 18, 2024
1 parent ad2a79f commit 0a07800
Show file tree
Hide file tree
Showing 7 changed files with 220 additions and 1 deletion.
18 changes: 18 additions & 0 deletions src/SQL/Builder/DropSchemaObjectsSQLBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Schema\Sequence;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\View;

use function array_merge;

Expand All @@ -24,6 +25,7 @@ public function buildSQL(Schema $schema): array
$this->buildSequenceStatements($schema->getSequences()),
$this->buildTableStatements($schema->getTables()),
$this->buildNamespaceStatements($schema->getNamespaces()),
$this->buildViewStatements($schema->getViews()),
);
}

Expand Down Expand Up @@ -72,4 +74,20 @@ private function buildNamespaceStatements(array $namespaces): array

return $statements;
}

/**
* @param list<View> $views
*
* @return list<string>
*/
private function buildViewStatements(array $views): array
{
$statements = [];

foreach ($views as $view) {
$statements[] = $this->platform->getDropViewSQL($view->getQuotedName($this->platform));
}

return $statements;
}
}
4 changes: 3 additions & 1 deletion src/Schema/AbstractSchemaManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,9 @@ public function introspectSchema(): Schema

$tables = $this->listTables();

return new Schema($tables, $sequences, $this->createSchemaConfig(), $schemaNames);
$views = $this->listViews();

return new Schema($tables, $sequences, $this->createSchemaConfig(), $schemaNames, $views);
}

/**
Expand Down
19 changes: 19 additions & 0 deletions src/Schema/Exception/ViewAlreadyExists.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Doctrine\DBAL\Schema\Exception;

use Doctrine\DBAL\Schema\SchemaException;
use LogicException;

use function sprintf;

/** @psalm-immutable */
final class ViewAlreadyExists extends LogicException implements SchemaException
{
public static function new(string $viewName): self
{
return new self(sprintf('The view "%s" already exists.', $viewName));
}
}
19 changes: 19 additions & 0 deletions src/Schema/Exception/ViewDoesNotExist.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Doctrine\DBAL\Schema\Exception;

use Doctrine\DBAL\Schema\SchemaException;
use LogicException;

use function sprintf;

/** @psalm-immutable */
final class ViewDoesNotExist extends LogicException implements SchemaException
{
public static function new(string $viewName): self
{
return new self(sprintf('There exists no view with the name "%s".', $viewName));
}
}
74 changes: 74 additions & 0 deletions src/Schema/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
use Doctrine\DBAL\Schema\Exception\SequenceDoesNotExist;
use Doctrine\DBAL\Schema\Exception\TableAlreadyExists;
use Doctrine\DBAL\Schema\Exception\TableDoesNotExist;
use Doctrine\DBAL\Schema\Exception\ViewAlreadyExists;
use Doctrine\DBAL\Schema\Exception\ViewDoesNotExist;
use Doctrine\DBAL\SQL\Builder\CreateSchemaObjectsSQLBuilder;
use Doctrine\DBAL\SQL\Builder\DropSchemaObjectsSQLBuilder;

Expand Down Expand Up @@ -57,18 +59,23 @@ class Schema extends AbstractAsset
/** @var array<string, Sequence> */
protected array $_sequences = [];

/** @var array<string, View> */
protected array $_views = [];

protected SchemaConfig $_schemaConfig;

/**
* @param array<Table> $tables
* @param array<Sequence> $sequences
* @param array<string> $namespaces
* @param array<View> $views
*/
public function __construct(
array $tables = [],
array $sequences = [],
?SchemaConfig $schemaConfig = null,
array $namespaces = [],
array $views = [],
) {
$schemaConfig ??= new SchemaConfig();

Expand All @@ -91,6 +98,10 @@ public function __construct(
foreach ($sequences as $sequence) {
$this->_addSequence($sequence);
}

foreach ($views as $view) {
$this->_addView($view);
}
}

protected function _addTable(Table $table): void
Expand Down Expand Up @@ -134,6 +145,26 @@ protected function _addSequence(Sequence $sequence): void
$this->_sequences[$seqName] = $sequence;
}

protected function _addView(View $view): void
{
$namespaceName = $view->getNamespaceName();
$viewName = $this->normalizeName($view);

if (isset($this->_views[$viewName])) {
throw ViewAlreadyExists::new($viewName);
}

if (
$namespaceName !== null
&& ! $view->isInDefaultNamespace($this->getName())
&& ! $this->hasNamespace($namespaceName)
) {
$this->createNamespace($namespaceName);
}

$this->_views[$viewName] = $view;
}

/**
* Returns the namespaces of this schema.
*
Expand Down Expand Up @@ -249,6 +280,29 @@ public function getSequences(): array
return array_values($this->_sequences);
}

public function hasView(string $name): bool
{
$name = $this->getFullQualifiedAssetName($name);

return isset($this->_views[$name]);
}

public function getView(string $name): View
{
$name = $this->getFullQualifiedAssetName($name);
if (! $this->hasView($name)) {
throw ViewDoesNotExist::new($name);
}

return $this->_views[$name];
}

/** @return list<View> */
public function getViews(): array
{
return array_values($this->_views);
}

/**
* Creates a new namespace.
*
Expand Down Expand Up @@ -332,6 +386,26 @@ public function dropSequence(string $name): self
return $this;
}

/**
* Creates a new view.
*/
public function createView(string $name, string $sql): View
{
$view = new View($name, $sql);
$this->_addView($view);

return $view;
}

/** @return $this */
public function dropView(string $name): self
{
$name = $this->getFullQualifiedAssetName($name);
unset($this->_views[$name]);

return $this;
}

/**
* Returns an array of necessary SQL queries to create the schema on the given platform.
*
Expand Down
19 changes: 19 additions & 0 deletions tests/Functional/Schema/SchemaManagerFunctionalTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,25 @@ public function testCreateAndListViews(): void
self::assertStringContainsString('view_test_table', $filtered[0]->getSql());
}

public function testIntrospectSchemaWithView(): void
{
$this->createTestTable('view_test_table');

$name = 'doctrine_test_view';
$sql = 'SELECT * FROM view_test_table';

$view = new View($name, $sql);

$this->schemaManager->createView($view);

$schema = $this->schemaManager->introspectSchema();

$filtered = array_values($this->filterElementsByName($schema->getViews(), $name));
self::assertCount(1, $filtered);

self::assertStringContainsString('view_test_table', $filtered[0]->getSql());
}

public function testAutoincrementDetection(): void
{
if (! $this->connection->getDatabasePlatform()->supportsIdentityColumns()) {
Expand Down
68 changes: 68 additions & 0 deletions tests/Schema/SchemaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Doctrine\DBAL\Schema\SchemaException;
use Doctrine\DBAL\Schema\Sequence;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\View;
use Doctrine\DBAL\Types\Types;
use PHPUnit\Framework\TestCase;

Expand Down Expand Up @@ -169,6 +170,73 @@ public function testAddSequenceTwiceThrowsException(): void
new Schema([], [$sequence, $sequence]);
}

public function testAddViews(): void
{
$view = new View('a_view', 'SELECT 1');

$schema = new Schema([], [], null, [], [$view]);

self::assertTrue($schema->hasView('a_view'));
self::assertSame('a_view', $schema->getView('a_view')->getName());

self::assertEquals([$view], $schema->getViews());
}

public function testViewAccessCaseInsensitive(): void
{
$view = new View('a_View', 'SELECT 1');

$schema = new Schema([], [], null, [], [$view]);
self::assertTrue($schema->hasView('a_view'));
self::assertTrue($schema->hasView('a_View'));
self::assertTrue($schema->hasView('A_VIEW'));

self::assertEquals($view, $schema->getView('a_view'));
self::assertEquals($view, $schema->getView('a_View'));
self::assertEquals($view, $schema->getView('A_VIEW'));
}

public function testGetUnknownViewThrowsException(): void
{
$this->expectException(SchemaException::class);

$schema = new Schema();
$schema->getView('unknown');
}

public function testCreateView(): void
{
$schema = new Schema();
$view = $schema->createView('a_view', 'SELECT 1');

self::assertEquals('a_view', $view->getName());
self::assertEquals('SELECT 1', $view->getSql());

self::assertTrue($schema->hasView('a_view'));
self::assertSame('a_view', $schema->getView('a_view')->getName());

self::assertEquals([$view], $schema->getViews());
}

public function testDropView(): void
{
$view = new View('a_View', 'SELECT 1');

$schema = new Schema([], [], null, [], [$view]);

$schema->dropView('a_view');
self::assertFalse($schema->hasView('a_view'));
}

public function testAddViewTwiceThrowsException(): void
{
$this->expectException(SchemaException::class);

$view = new View('a_View', 'SELECT 1');

new Schema([], [], null, [], [$view, $view]);
}

public function testConfigMaxIdentifierLength(): void
{
$schemaConfig = new SchemaConfig();
Expand Down

0 comments on commit 0a07800

Please sign in to comment.