Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TASK: Core and neos schemas for pgsql and mysql #5398

Merged
merged 5 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -729,8 +729,7 @@ private function whenWorkspaceWasRemoved(WorkspaceWasRemoved $event): void
*/
private function determineRequiredSqlStatements(): array
{
$schemaManager = $this->dbal->createSchemaManager();
$schema = (new DoctrineDbalContentGraphSchemaBuilder($this->tableNames))->buildSchema($schemaManager);
$schema = (new DoctrineDbalContentGraphSchemaBuilder($this->tableNames))->buildSchema($this->dbal);
return DbalSchemaDiff::determineRequiredSqlStatements($this->dbal, $schema);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Neos\ContentGraph\DoctrineDbalAdapter;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Exception as DBALException;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
Expand All @@ -19,38 +20,32 @@
*/
class DoctrineDbalContentGraphSchemaBuilder
{
private const DEFAULT_TEXT_COLLATION = 'utf8mb4_unicode_520_ci';

public function __construct(
private readonly ContentGraphTableNames $tableNames
) {
}

/**
* @param AbstractSchemaManager<AbstractPlatform> $schemaManager
* @return Schema
*/
public function buildSchema(AbstractSchemaManager $schemaManager): Schema
public function buildSchema(Connection $connection): Schema
{
return DbalSchemaFactory::createSchemaWithTables($schemaManager, [
$this->createNodeTable(),
$this->createHierarchyRelationTable(),
$this->createReferenceRelationTable(),
$this->createDimensionSpacePointsTable(),
$this->createWorkspaceTable(),
$this->createContentStreamTable(),
return DbalSchemaFactory::createSchemaWithTables($connection, [
$this->createNodeTable($connection->getDatabasePlatform()),
$this->createHierarchyRelationTable($connection->getDatabasePlatform()),
$this->createReferenceRelationTable($connection->getDatabasePlatform()),
$this->createDimensionSpacePointsTable($connection->getDatabasePlatform()),
$this->createWorkspaceTable($connection->getDatabasePlatform()),
$this->createContentStreamTable($connection->getDatabasePlatform()),
]);
}

private function createNodeTable(): Table
private function createNodeTable(AbstractPlatform $platform): Table
{
$table = self::createTable($this->tableNames->node(), [
DbalSchemaFactory::columnForNodeAnchorPoint('relationanchorpoint')->setAutoincrement(true),
DbalSchemaFactory::columnForNodeAggregateId('nodeaggregateid')->setNotnull(false),
DbalSchemaFactory::columnForDimensionSpacePointHash('origindimensionspacepointhash')->setNotnull(false),
DbalSchemaFactory::columnForNodeTypeName('nodetypename'),
(new Column('name', self::type(Types::STRING)))->setLength(255)->setNotnull(false)->setPlatformOption('charset', 'ascii')->setPlatformOption('collation', 'ascii_general_ci'),
(new Column('properties', self::type(Types::TEXT)))->setNotnull(true)->setPlatformOption('collation', self::DEFAULT_TEXT_COLLATION),
DbalSchemaFactory::columnForNodeAnchorPoint('relationanchorpoint', $platform)->setAutoincrement(true),
DbalSchemaFactory::columnForNodeAggregateId('nodeaggregateid', $platform)->setNotnull(false),
DbalSchemaFactory::columnForDimensionSpacePointHash('origindimensionspacepointhash', $platform)->setNotnull(false),
DbalSchemaFactory::columnForNodeTypeName('nodetypename', $platform),
(new Column('name', self::type(Types::STRING)))->setLength(255)->setNotnull(false),
DbalSchemaFactory::columnForProperties('properties', $platform)->setNotnull(true),
(new Column('classification', self::type(Types::BINARY)))->setLength(20)->setNotnull(true),
(new Column('created', self::type(Types::DATETIME_IMMUTABLE)))->setDefault('CURRENT_TIMESTAMP')->setNotnull(true),
(new Column('originalcreated', self::type(Types::DATETIME_IMMUTABLE)))->setDefault('CURRENT_TIMESTAMP')->setNotnull(true),
Expand All @@ -64,14 +59,14 @@ private function createNodeTable(): Table
->addIndex(['nodetypename']);
}

private function createHierarchyRelationTable(): Table
private function createHierarchyRelationTable(AbstractPlatform $platform): Table
{
$table = self::createTable($this->tableNames->hierarchyRelation(), [
(new Column('position', self::type(Types::INTEGER)))->setNotnull(true),
DbalSchemaFactory::columnForContentStreamId('contentstreamid')->setNotnull(true),
DbalSchemaFactory::columnForDimensionSpacePointHash('dimensionspacepointhash')->setNotnull(true),
DbalSchemaFactory::columnForNodeAnchorPoint('parentnodeanchor'),
DbalSchemaFactory::columnForNodeAnchorPoint('childnodeanchor'),
DbalSchemaFactory::columnForContentStreamId('contentstreamid', $platform)->setNotnull(true),
DbalSchemaFactory::columnForDimensionSpacePointHash('dimensionspacepointhash', $platform)->setNotnull(true),
DbalSchemaFactory::columnForNodeAnchorPoint('parentnodeanchor', $platform),
DbalSchemaFactory::columnForNodeAnchorPoint('childnodeanchor', $platform),
(new Column('subtreetags', self::type(Types::JSON))),
]);

Expand All @@ -84,50 +79,50 @@ private function createHierarchyRelationTable(): Table
->addIndex(['contentstreamid', 'dimensionspacepointhash']);
}

private function createDimensionSpacePointsTable(): Table
private function createDimensionSpacePointsTable(AbstractPlatform $platform): Table
{
$table = self::createTable($this->tableNames->dimensionSpacePoints(), [
DbalSchemaFactory::columnForDimensionSpacePointHash('hash')->setNotnull(true),
DbalSchemaFactory::columnForDimensionSpacePoint('dimensionspacepoint')->setNotnull(true)
DbalSchemaFactory::columnForDimensionSpacePointHash('hash', $platform)->setNotnull(true),
DbalSchemaFactory::columnForDimensionSpacePoint('dimensionspacepoint', $platform)->setNotnull(true)
]);

return $table
->setPrimaryKey(['hash']);
}

private function createReferenceRelationTable(): Table
private function createReferenceRelationTable(AbstractPlatform $platform): Table
{
$table = self::createTable($this->tableNames->referenceRelation(), [
(new Column('name', self::type(Types::STRING)))->setLength(255)->setNotnull(true)->setPlatformOption('charset', 'ascii')->setPlatformOption('collation', 'ascii_general_ci'),
(new Column('name', self::type(Types::STRING)))->setLength(255)->setNotnull(true),
(new Column('position', self::type(Types::INTEGER)))->setNotnull(true),
DbalSchemaFactory::columnForNodeAnchorPoint('nodeanchorpoint'),
(new Column('properties', self::type(Types::TEXT)))->setNotnull(false)->setPlatformOption('collation', self::DEFAULT_TEXT_COLLATION),
DbalSchemaFactory::columnForNodeAggregateId('destinationnodeaggregateid')->setNotnull(true)
DbalSchemaFactory::columnForNodeAnchorPoint('nodeanchorpoint', $platform),
DbalSchemaFactory::columnForProperties('properties', $platform)->setNotnull(false),
DbalSchemaFactory::columnForNodeAggregateId('destinationnodeaggregateid', $platform)->setNotnull(true)
]);

return $table
->setPrimaryKey(['name', 'position', 'nodeanchorpoint']);
}

private function createWorkspaceTable(): Table
private function createWorkspaceTable(AbstractPlatform $platform): Table
{
$workspaceTable = self::createTable($this->tableNames->workspace(), [
DbalSchemaFactory::columnForWorkspaceName('name')->setNotnull(true),
DbalSchemaFactory::columnForWorkspaceName('baseWorkspaceName')->setNotnull(false),
DbalSchemaFactory::columnForContentStreamId('currentContentStreamId')->setNotNull(true),
DbalSchemaFactory::columnForWorkspaceName('name', $platform)->setNotnull(true),
DbalSchemaFactory::columnForWorkspaceName('baseWorkspaceName', $platform)->setNotnull(false),
DbalSchemaFactory::columnForContentStreamId('currentContentStreamId', $platform)->setNotNull(true),
]);

$workspaceTable->addUniqueIndex(['currentContentStreamId']);

return $workspaceTable->setPrimaryKey(['name']);
}

private function createContentStreamTable(): Table
private function createContentStreamTable(AbstractPlatform $platform): Table
{
$contentStreamTable = self::createTable($this->tableNames->contentStream(), [
DbalSchemaFactory::columnForContentStreamId('id')->setNotnull(true),
DbalSchemaFactory::columnForContentStreamId('id', $platform)->setNotnull(true),
(new Column('version', Type::getType(Types::INTEGER)))->setNotnull(true),
DbalSchemaFactory::columnForContentStreamId('sourceContentStreamId')->setNotnull(false),
DbalSchemaFactory::columnForContentStreamId('sourceContentStreamId', $platform)->setNotnull(false),
(new Column('sourceContentStreamVersion', Type::getType(Types::INTEGER)))->setNotnull(false),
(new Column('closed', Type::getType(Types::BOOLEAN)))->setNotnull(true),
(new Column('hasChanges', Type::getType(Types::BOOLEAN)))->setNotnull(true),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ private function determineRequiredSqlStatements(): array
'sequencenumber'
]);

$schema = DbalSchemaFactory::createSchemaWithTables($schemaManager, [$table]);
$schema = DbalSchemaFactory::createSchemaWithTables($this->dbal, [$table]);
$statements = DbalSchemaDiff::determineRequiredSqlStatements($this->dbal, $schema);

return $statements;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

namespace Neos\ContentRepository\Core\Infrastructure;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Platforms\AbstractMySQLPlatform;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\Column;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Schema\SchemaException;
Expand All @@ -23,11 +24,11 @@
* Provide doctrine DBAL column schema definitions for common types in the content repository to
* produce consistent columns across projections.
*
* @internal Because we might need to check for platform later on and generally change the input and output format of functions within.
* @internal Because platform checks are limited for now and the input and output format of functions might change.
*/
final class DbalSchemaFactory
{
private const DEFAULT_TEXT_COLLATION = 'utf8mb4_unicode_520_ci';
private const DEFAULT_MYSQL_COLLATION = 'utf8mb4_unicode_520_ci';

// This class only contains static members and should not be constructed
private function __construct()
Expand All @@ -39,12 +40,18 @@ private function __construct()
*
* @see NodeAggregateId
*/
public static function columnForNodeAggregateId(string $columnName): Column
public static function columnForNodeAggregateId(string $columnName, AbstractPlatform $platform): Column
{
return (new Column($columnName, Type::getType(Types::STRING)))
->setLength(64)
->setPlatformOption('charset', 'ascii')
->setPlatformOption('collation', 'ascii_general_ci');
$column = (new Column($columnName, Type::getType(Types::STRING)))
->setLength(64);

if ($platform instanceof AbstractMySQLPlatform) {
$column = $column
->setPlatformOption('charset', 'ascii')
->setPlatformOption('collation', 'ascii_general_ci');
}

return $column;
}

/**
Expand All @@ -57,7 +64,7 @@ public static function columnForNodeAggregateId(string $columnName): Column
*
* @see ContentStreamId
*/
public static function columnForContentStreamId(string $columnName): Column
public static function columnForContentStreamId(string $columnName, AbstractPlatform $platform): Column
{
return (new Column($columnName, Type::getType(Types::BINARY)))
->setLength(36);
Expand All @@ -71,7 +78,7 @@ public static function columnForContentStreamId(string $columnName): Column
* A simpler and faster format would be preferable though, int or a shorter binary format if possible. Fortunately
* this is a pure projection information and therefore could change by replay.
*/
public static function columnForNodeAnchorPoint(string $columnName): Column
public static function columnForNodeAnchorPoint(string $columnName, AbstractPlatform $platform): Column
{
return (new Column($columnName, Type::getType(Types::BIGINT)))
->setNotnull(true);
Expand All @@ -85,11 +92,10 @@ public static function columnForNodeAnchorPoint(string $columnName): Column
*
* @see DimensionSpacePoint
*/
public static function columnForDimensionSpacePoint(string $columnName): Column
public static function columnForDimensionSpacePoint(string $columnName, AbstractPlatform $platform): Column
{
return (new Column($columnName, Type::getType(Types::TEXT)))
->setDefault('{}')
->setPlatformOption('collation', self::DEFAULT_TEXT_COLLATION);
return (new Column($columnName, Type::getType(Types::JSON)))
->setDefault('{}');
}

/**
Expand All @@ -100,7 +106,7 @@ public static function columnForDimensionSpacePoint(string $columnName): Column
*
* @see DimensionSpacePoint
*/
public static function columnForDimensionSpacePointHash(string $columnName): Column
public static function columnForDimensionSpacePointHash(string $columnName, AbstractPlatform $platform): Column
{
return (new Column($columnName, Type::getType(Types::BINARY)))
->setLength(32)
Expand All @@ -112,39 +118,89 @@ public static function columnForDimensionSpacePointHash(string $columnName): Col
*
* @see NodeTypeName
*/
public static function columnForNodeTypeName(string $columnName): Column
public static function columnForNodeTypeName(string $columnName, AbstractPlatform $platform): Column
{
return (new Column($columnName, Type::getType(Types::STRING)))
$column = (new Column($columnName, Type::getType(Types::STRING)))
->setLength(255)
->setNotnull(true)
->setPlatformOption('charset', 'ascii')
->setPlatformOption('collation', 'ascii_general_ci');
->setNotnull(true);

if ($platform instanceof AbstractMySQLPlatform) {
$column = $column
->setPlatformOption('charset', 'ascii')
->setPlatformOption('collation', 'ascii_general_ci');
}

return $column;
}

/**
* @see WorkspaceName
*/
public static function columnForWorkspaceName(string $columnName): Column
public static function columnForWorkspaceName(string $columnName, AbstractPlatform $platform): Column
{
return (new Column($columnName, Type::getType(Types::STRING)))
$column = (new Column($columnName, Type::getType(Types::STRING)))
->setLength(WorkspaceName::MAX_LENGTH)
->setNotnull(true)
->setPlatformOption('collation', self::DEFAULT_TEXT_COLLATION);
->setNotnull(true);

if ($platform instanceof AbstractMySQLPlatform) {
$column = $column
->setPlatformOption('charset', 'ascii')
->setPlatformOption('collation', 'ascii_general_ci');
}

return $column;
}

public static function columnForProperties(string $columnName, AbstractPlatform $platform): Column
{
$column = (new Column($columnName, Type::getType(Types::JSON)));

if ($platform instanceof AbstractMySQLPlatform) {
$column = (new Column($columnName, Type::getType(Types::TEXT)))
->setPlatformOption('collation', self::DEFAULT_MYSQL_COLLATION);
}

return $column;
}

public static function columnForGenericString(string $columnName, AbstractPlatform $platform): Column
{
$column = (new Column($columnName, Type::getType(Types::STRING)));

if ($platform instanceof AbstractMySQLPlatform) {
$column = $column->setPlatformOption('collation', self::DEFAULT_MYSQL_COLLATION);
}

return $column;
}

public static function columnForGenericText(string $columnName, AbstractPlatform $platform): Column
{
$column = (new Column($columnName, Type::getType(Types::TEXT)));
if ($platform instanceof AbstractMySQLPlatform) {
$column = $column->setPlatformOption('collation', self::DEFAULT_MYSQL_COLLATION);
}

return $column;
}

/**
* @param AbstractSchemaManager<AbstractPlatform> $schemaManager
* @param Connection $dbal
* @param Table[] $tables
* @return Schema
* @throws Exception
* @throws SchemaException
*/
public static function createSchemaWithTables(AbstractSchemaManager $schemaManager, array $tables): Schema
public static function createSchemaWithTables(Connection $dbal, array $tables): Schema
{
$schemaManager = $dbal->createSchemaManager();
$schemaConfig = $schemaManager->createSchemaConfig();
$schemaConfig->setDefaultTableOptions([
'charset' => 'utf8mb4'
]);

if ($dbal->getDatabasePlatform() instanceof AbstractMySQLPlatform) {
$schemaConfig->setDefaultTableOptions([
'charset' => 'utf8mb4'
]);
}

return new Schema($tables, [], $schemaConfig);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ public function status(): ProjectionStatus
*/
private function determineRequiredSqlStatements(): array
{
$schemaManager = $this->dbal->createSchemaManager();
$schema = (new DocumentUriPathSchemaBuilder($this->tableNamePrefix))->buildSchema($schemaManager);
$schema = (new DocumentUriPathSchemaBuilder($this->tableNamePrefix))->buildSchema($this->dbal);
$statements = DbalSchemaDiff::determineRequiredSqlStatements($this->dbal, $schema);

return $statements;
Expand Down
Loading
Loading