Skip to content

Commit

Permalink
Query deduplication part 2
Browse files Browse the repository at this point in the history
  • Loading branch information
kitsunet committed Apr 14, 2024
1 parent dd30d55 commit 027cb02
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 115 deletions.
61 changes: 28 additions & 33 deletions Neos.ContentGraph.DoctrineDbalAdapter/src/ContentGraphAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,22 @@
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\CountChildNodesFilter;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindChildNodesFilter;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindPrecedingSiblingNodesFilter;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindRootNodeAggregatesFilter;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindSucceedingSiblingNodesFilter;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\NodeType\ExpandedNodeTypeCriteria;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\NodeType\NodeTypeCriteria;
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\Pagination\Pagination;
use Neos\ContentRepository\Core\Projection\ContentGraph\Node;
use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate;
use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregates;
use Neos\ContentRepository\Core\Projection\ContentGraph\NodePath;
use Neos\ContentRepository\Core\Projection\ContentGraph\Nodes;
use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints;
use Neos\ContentRepository\Core\Projection\Workspace\Workspace;
use Neos\ContentRepository\Core\Projection\Workspace\WorkspaceStatus;
use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId;
use Neos\ContentRepository\Core\SharedModel\Exception\ContentStreamDoesNotExistYet;
use Neos\ContentRepository\Core\SharedModel\Exception\RootNodeAggregateDoesNotExist;
use Neos\ContentRepository\Core\SharedModel\Exception\WorkspaceDoesNotExist;
use Neos\ContentRepository\Core\SharedModel\Id\UuidFactory;
use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateClassification;
use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId;
use Neos\ContentRepository\Core\SharedModel\Node\NodeName;
Expand Down Expand Up @@ -72,29 +73,34 @@ public function __construct(

public function rootNodeAggregateWithTypeExists(NodeTypeName $nodeTypeName): bool
{
$rootNodeAggregate = $this->findRootNodeAggregateByType($nodeTypeName);
return (bool)$rootNodeAggregate;
try {
return (bool)$this->findRootNodeAggregateByType($nodeTypeName);
} catch(\Exception $_) {
}

return false;
}

public function findRootNodeAggregateByType(NodeTypeName $nodeTypeName): ?NodeAggregate
{
$queryBuilder = $this->nodeQueryBuilder->buildBasicNodeAggregateQuery()
->where('h.contentstreamid = :contentStreamId')
->andWhere('h.parentnodeanchor = :rootEdgeParentAnchorId')
->setParameters([
'contentStreamId' => $this->getContentStreamId()->value,
'rootEdgeParentAnchorId' => NodeRelationAnchorPoint::forRootEdge()->value,
]);

$queryBuilder
->andWhere('n.nodetypename = :nodeTypeName')
->setParameter('nodeTypeName', $nodeTypeName->value);
$rootNodeAggregateQueryBuilder = $this->nodeQueryBuilder->buildFindRootNodeAggregatesQuery($this->getContentStreamId(), FindRootNodeAggregatesFilter::create(nodeTypeName: $nodeTypeName));
$rootNodeAggregates = NodeAggregates::fromArray(iterator_to_array($this->mapQueryBuilderToNodeAggregates($rootNodeAggregateQueryBuilder)));
if ($rootNodeAggregates->count() < 1) {
throw RootNodeAggregateDoesNotExist::butWasExpectedTo($nodeTypeName);
}
if ($rootNodeAggregates->count() > 1) {
$ids = [];
foreach ($rootNodeAggregates as $rootNodeAggregate) {
$ids[] = $rootNodeAggregate->nodeAggregateId->value;
}
throw new \RuntimeException(sprintf(
'More than one root node aggregate of type "%s" found (IDs: %s).',
$nodeTypeName->value,
implode(', ', $ids)
));
}

return $this->nodeFactory->mapNodeRowsToNodeAggregate(
$this->fetchRows($queryBuilder),
$this->getContentStreamId(),
VisibilityConstraints::withoutRestrictions()
);
return $rootNodeAggregates->first();
}

public function findParentNodeAggregates(NodeAggregateId $childNodeAggregateId): iterable
Expand Down Expand Up @@ -349,7 +355,7 @@ private function buildChildNodesQuery(NodeAggregateId $parentNodeAggregateId, Di
{
$queryBuilder = $this->nodeQueryBuilder->buildBasicChildNodesQuery($parentNodeAggregateId, $this->getContentStreamId(), $dimensionSpacePoint);
if ($filter->nodeTypes !== null) {
$this->addNodeTypeCriteria($queryBuilder, $filter->nodeTypes);
$this->nodeQueryBuilder->addNodeTypeCriteria($queryBuilder, ExpandedNodeTypeCriteria::create($filter->nodeTypes, $this->nodeTypeManager));
}
if ($filter->searchTerm !== null) {
$this->nodeQueryBuilder->addSearchTermConstraints($queryBuilder, $filter->searchTerm);
Expand Down Expand Up @@ -431,7 +437,7 @@ private function buildSiblingsQuery(bool $preceding, NodeAggregateId $siblingNod
$queryBuilder = $this->nodeQueryBuilder->buildBasicNodeSiblingsQuery($preceding, $siblingNodeAggregateId, $this->getContentStreamId(), $dimensionSpacePoint);

if ($filter->nodeTypes !== null) {
$this->addNodeTypeCriteria($queryBuilder, $filter->nodeTypes);
$this->nodeQueryBuilder->addNodeTypeCriteria($queryBuilder, ExpandedNodeTypeCriteria::create($filter->nodeTypes, $this->nodeTypeManager));
}
if ($filter->searchTerm !== null) {
$this->nodeQueryBuilder->addSearchTermConstraints($queryBuilder, $filter->searchTerm);
Expand All @@ -446,12 +452,6 @@ private function buildSiblingsQuery(bool $preceding, NodeAggregateId $siblingNod
return $queryBuilder;
}

private function addNodeTypeCriteria(QueryBuilder $queryBuilder, NodeTypeCriteria $nodeTypeCriteria, string $nodeTableAlias = 'n'): void
{
$constraintsWithSubNodeTypes = ExpandedNodeTypeCriteria::create($nodeTypeCriteria, $this->nodeTypeManager);
$this->nodeQueryBuilder->addNodeTypeCriteria($queryBuilder, $constraintsWithSubNodeTypes, $nodeTableAlias);
}

private function applyPagination(QueryBuilder $queryBuilder, Pagination $pagination): void
{
$queryBuilder
Expand Down Expand Up @@ -489,11 +489,6 @@ private function fetchNodes(QueryBuilder $queryBuilder, DimensionSpacePoint $dim
return $this->nodeFactory->mapNodeRowsToNodes($nodeRows, $this->getContentStreamId(), $dimensionSpacePoint, VisibilityConstraints::withoutRestrictions());
}

private function createUniqueParameterName(): string
{
return 'param_' . UuidFactory::create();
}

public function getWorkspaceName(): WorkspaceName
{
if ($this->workspaceName !== null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
use Doctrine\DBAL\Result;
use Neos\ContentGraph\DoctrineDbalAdapter\ContentGraphAdapter;
use Neos\ContentGraph\DoctrineDbalAdapter\DoctrineDbalContentGraphProjection;
use Neos\ContentGraph\DoctrineDbalAdapter\Domain\Projection\NodeRelationAnchorPoint;
use Neos\ContentGraph\DoctrineDbalAdapter\NodeQueryBuilder;
use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint;
use Neos\ContentRepository\Core\Infrastructure\DbalClientInterface;
Expand Down Expand Up @@ -79,7 +78,7 @@ public function __construct(
$this->nodeQueryBuilder = new NodeQueryBuilder($this->client->getConnection(), $this->tableNamePrefix);
}

final public function getSubgraph(
public function getSubgraph(
ContentStreamId $contentStreamId,
DimensionSpacePoint $dimensionSpacePoint,
VisibilityConstraints $visibilityConstraints
Expand Down Expand Up @@ -115,6 +114,9 @@ public function findRootNodeAggregateByType(
FindRootNodeAggregatesFilter::create(nodeTypeName: $nodeTypeName)
);

if ($rootNodeAggregates->count() < 1) {
throw RootNodeAggregateDoesNotExist::butWasExpectedTo($nodeTypeName);
}
if ($rootNodeAggregates->count() > 1) {
$ids = [];
foreach ($rootNodeAggregates as $rootNodeAggregate) {
Expand All @@ -127,33 +129,15 @@ public function findRootNodeAggregateByType(
));
}

$rootNodeAggregate = $rootNodeAggregates->first();

if ($rootNodeAggregate === null) {
throw RootNodeAggregateDoesNotExist::butWasExpectedTo($nodeTypeName);
}

return $rootNodeAggregate;
return $rootNodeAggregates->first();
}

public function findRootNodeAggregates(
ContentStreamId $contentStreamId,
FindRootNodeAggregatesFilter $filter,
): NodeAggregates {
$queryBuilder = $this->nodeQueryBuilder->buildBasicNodeAggregateQuery();
$queryBuilder
->andWhere('h.parentnodeanchor = :rootEdgeParentAnchorId')
->setParameters([
'contentStreamId' => $contentStreamId->value,
'rootEdgeParentAnchorId' => NodeRelationAnchorPoint::forRootEdge()->value,
]);

if ($filter->nodeTypeName !== null) {
$queryBuilder
->andWhere('n.nodetypename = :nodeTypeName')
->setParameter('nodeTypeName', $filter->nodeTypeName->value);
}
return NodeAggregates::fromArray(iterator_to_array($this->mapQueryBuilderToNodeAggregates($queryBuilder, $contentStreamId)));
$rootNodeAggregateQueryBuilder = $this->nodeQueryBuilder->buildFindRootNodeAggregatesQuery($contentStreamId, $filter);
return NodeAggregates::fromArray(iterator_to_array($this->mapQueryBuilderToNodeAggregates($rootNodeAggregateQueryBuilder, $contentStreamId)));
}

public function findNodeAggregatesByType(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,15 +162,9 @@ public function findNodeById(NodeAggregateId $nodeAggregateId): ?Node

public function findRootNodeByType(NodeTypeName $nodeTypeName): ?Node
{
$queryBuilder = $this->createQueryBuilder()
->select('n.*, h.name, h.subtreetags')
->from($this->nodeQueryBuilder->getTablenameForNode(), 'n')
->innerJoin('n', $this->nodeQueryBuilder->getTablenameForHierachyRelation(), 'h', 'h.childnodeanchor = n.relationanchorpoint')
->where('n.nodetypename = :nodeTypeName')->setParameter('nodeTypeName', $nodeTypeName->value)
->andWhere('h.contentstreamid = :contentStreamId')->setParameter('contentStreamId', $this->contentStreamId->value)
->andWhere('h.dimensionspacepointhash = :dimensionSpacePointHash')->setParameter('dimensionSpacePointHash', $this->dimensionSpacePoint->hash)
->andWhere('n.classification = :nodeAggregateClassification')
->setParameter('nodeAggregateClassification', NodeAggregateClassification::CLASSIFICATION_ROOT->value);
$queryBuilder = $this->nodeQueryBuilder->buildBasicNodeQuery($this->contentStreamId, $this->dimensionSpacePoint)
->andWhere('n.nodetypename = :nodeTypeName')->setParameter('nodeTypeName', $nodeTypeName->value)
->andWhere('n.classification = :nodeAggregateClassification')->setParameter('nodeAggregateClassification', NodeAggregateClassification::CLASSIFICATION_ROOT->value);
$this->addSubtreeTagConstraints($queryBuilder);
return $this->fetchNode($queryBuilder);
}
Expand Down Expand Up @@ -273,7 +267,7 @@ public function findSubtree(NodeAggregateId $entryNodeAggregateId, FindSubtreeFi
$queryBuilderRecursive->andWhere('p.level < :maximumLevels')->setParameter('maximumLevels', $filter->maximumLevels);
}
if ($filter->nodeTypes !== null) {
$this->addNodeTypeCriteria($queryBuilderRecursive, $filter->nodeTypes, 'c');
$this->nodeQueryBuilder->addNodeTypeCriteria($queryBuilderRecursive, ExpandedNodeTypeCriteria::create($filter->nodeTypes, $this->nodeTypeManager), 'c');
}
$this->addSubtreeTagConstraints($queryBuilderRecursive);

Expand Down Expand Up @@ -366,7 +360,7 @@ public function findClosestNode(NodeAggregateId $entryNodeAggregateId, FindClose

$queryBuilderCte = $this->nodeQueryBuilder->buildBasicNodesCteQuery($entryNodeAggregateId, $this->contentStreamId, $this->dimensionSpacePoint);
if ($filter->nodeTypes !== null) {
$this->addNodeTypeCriteria($queryBuilderCte, $filter->nodeTypes, 'pn');
$this->nodeQueryBuilder->addNodeTypeCriteria($queryBuilderCte, ExpandedNodeTypeCriteria::create($filter->nodeTypes, $this->nodeTypeManager), 'pn');
}
$nodeRows = $this->fetchCteResults(
$queryBuilderInitial,
Expand Down Expand Up @@ -404,21 +398,18 @@ public function countDescendantNodes(NodeAggregateId $entryNodeAggregateId, Coun

public function countNodes(): int
{
$queryBuilder = $this->createQueryBuilder()
->select('COUNT(*)')
->from($this->nodeQueryBuilder->getTablenameForNode(), 'n')
->innerJoin('n', $this->nodeQueryBuilder->getTablenameForHierachyRelation(), 'h', 'h.childnodeanchor = n.relationanchorpoint')
->where('h.contentstreamid = :contentStreamId')->setParameter('contentStreamId', $this->contentStreamId->value)
->andWhere('h.dimensionspacepointhash = :dimensionSpacePointHash')->setParameter('dimensionSpacePointHash', $this->dimensionSpacePoint->hash);
$queryBuilder = $this->nodeQueryBuilder->buildBasicNodeQuery($this->contentStreamId, $this->dimensionSpacePoint, 'n', 'COUNT(*)');
try {
$result = $this->executeQuery($queryBuilder)->fetchOne();
if (!is_int($result)) {
throw new \RuntimeException(sprintf('Expected result to be of type integer but got: %s', get_debug_type($result)), 1678366902);
}
return $result;
} catch (DbalDriverException | DbalException $e) {
throw new \RuntimeException(sprintf('Failed to count all nodes: %s', $e->getMessage()), 1678364741, $e);
}

if (!is_int($result)) {
throw new \RuntimeException(sprintf('Expected result to be of type integer but got: %s', get_debug_type($result)), 1678366902);
}

return $result;
}

public function jsonSerialize(): ContentSubgraphIdentity
Expand Down Expand Up @@ -456,17 +447,11 @@ private function addSubtreeTagConstraints(QueryBuilder $queryBuilder, string $hi
}
}

private function addNodeTypeCriteria(QueryBuilder $queryBuilder, NodeTypeCriteria $nodeTypeCriteria, string $nodeTableAlias = 'n'): void
{
$constraintsWithSubNodeTypes = ExpandedNodeTypeCriteria::create($nodeTypeCriteria, $this->nodeTypeManager);
$this->nodeQueryBuilder->addNodeTypeCriteria($queryBuilder, $constraintsWithSubNodeTypes, $nodeTableAlias);
}

private function buildChildNodesQuery(NodeAggregateId $parentNodeAggregateId, FindChildNodesFilter|CountChildNodesFilter $filter): QueryBuilder
{
$queryBuilder = $this->nodeQueryBuilder->buildBasicChildNodesQuery($parentNodeAggregateId, $this->contentStreamId, $this->dimensionSpacePoint);
if ($filter->nodeTypes !== null) {
$this->addNodeTypeCriteria($queryBuilder, $filter->nodeTypes);
$this->nodeQueryBuilder->addNodeTypeCriteria($queryBuilder, ExpandedNodeTypeCriteria::create($filter->nodeTypes, $this->nodeTypeManager));
}
if ($filter->searchTerm !== null) {
$this->nodeQueryBuilder->addSearchTermConstraints($queryBuilder, $filter->searchTerm);
Expand Down Expand Up @@ -497,7 +482,7 @@ private function buildReferencesQuery(bool $backReferences, NodeAggregateId $nod
$this->addSubtreeTagConstraints($queryBuilder, 'dh');
$this->addSubtreeTagConstraints($queryBuilder, 'sh');
if ($filter->nodeTypes !== null) {
$this->addNodeTypeCriteria($queryBuilder, $filter->nodeTypes, "{$destinationTablePrefix}n");
$this->nodeQueryBuilder->addNodeTypeCriteria($queryBuilder, ExpandedNodeTypeCriteria::create($filter->nodeTypes, $this->nodeTypeManager), "{$destinationTablePrefix}n");
}
if ($filter->nodeSearchTerm !== null) {
$this->nodeQueryBuilder->addSearchTermConstraints($queryBuilder, $filter->nodeSearchTerm, "{$destinationTablePrefix}n");
Expand All @@ -511,9 +496,6 @@ private function buildReferencesQuery(bool $backReferences, NodeAggregateId $nod
if ($filter->referencePropertyValue !== null) {
$this->nodeQueryBuilder->addPropertyValueConstraints($queryBuilder, $filter->referencePropertyValue, 'r');
}
if ($filter->nodePropertyValue !== null) {
$this->nodeQueryBuilder->addPropertyValueConstraints($queryBuilder, $filter->nodePropertyValue, "{$destinationTablePrefix}n");
}
if ($filter->referenceName !== null) {
$queryBuilder->andWhere('r.name = :referenceName')->setParameter('referenceName', $filter->referenceName->value);
}
Expand All @@ -538,7 +520,7 @@ private function buildSiblingsQuery(bool $preceding, NodeAggregateId $siblingNod

$this->addSubtreeTagConstraints($queryBuilder);
if ($filter->nodeTypes !== null) {
$this->addNodeTypeCriteria($queryBuilder, $filter->nodeTypes);
$this->nodeQueryBuilder->addNodeTypeCriteria($queryBuilder, ExpandedNodeTypeCriteria::create($filter->nodeTypes, $this->nodeTypeManager));
}
if ($filter->searchTerm !== null) {
$this->nodeQueryBuilder->addSearchTermConstraints($queryBuilder, $filter->searchTerm);
Expand Down Expand Up @@ -583,7 +565,7 @@ private function buildAncestorNodesQueries(NodeAggregateId $entryNodeAggregateId

$queryBuilderCte = $this->nodeQueryBuilder->buildBasicNodesCteQuery($entryNodeAggregateId, $this->contentStreamId, $this->dimensionSpacePoint);
if ($filter->nodeTypes !== null) {
$this->addNodeTypeCriteria($queryBuilderCte, $filter->nodeTypes, 'pn');
$this->nodeQueryBuilder->addNodeTypeCriteria($queryBuilderCte, ExpandedNodeTypeCriteria::create($filter->nodeTypes, $this->nodeTypeManager), 'pn');
}
return compact('queryBuilderInitial', 'queryBuilderRecursive', 'queryBuilderCte');
}
Expand Down Expand Up @@ -619,7 +601,7 @@ private function buildDescendantNodesQueries(NodeAggregateId $entryNodeAggregate

$queryBuilderCte = $this->nodeQueryBuilder->buildBasicNodesCteQuery($entryNodeAggregateId, $this->contentStreamId, $this->dimensionSpacePoint, 'tree', 'n');
if ($filter->nodeTypes !== null) {
$this->addNodeTypeCriteria($queryBuilderCte, $filter->nodeTypes);
$this->nodeQueryBuilder->addNodeTypeCriteria($queryBuilderCte, ExpandedNodeTypeCriteria::create($filter->nodeTypes, $this->nodeTypeManager));
}
if ($filter->searchTerm !== null) {
$this->nodeQueryBuilder->addSearchTermConstraints($queryBuilderCte, $filter->searchTerm);
Expand Down
Loading

0 comments on commit 027cb02

Please sign in to comment.