Skip to content

Commit

Permalink
Merge pull request #5025 from neos/4993-fixMoveSubtreeTags
Browse files Browse the repository at this point in the history
Introduce test assertions for subtree tags on NodeMove
  • Loading branch information
nezaniel authored May 6, 2024
2 parents 5d8bdf5 + 1454588 commit 95cda1e
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 107 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ private function whenNodeAggregateWasMoved(NodeAggregateWasMoved $event): void
);
$this->moveSubtreeTags(
$event->contentStreamId,
$event->nodeAggregateId,
$event->newParentNodeAggregateId,
$succeedingSiblingForCoverage->dimensionSpacePoint
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,81 +134,62 @@ private function whenSubtreeWasUntagged(SubtreeWasUntagged $event): void
]);
}

private function moveSubtreeTags(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, NodeAggregateId $newParentNodeAggregateId, DimensionSpacePoint $coveredDimensionSpacePoint): void
{
$nodeTags = $this->nodeTagsForNode($nodeAggregateId, $contentStreamId, $coveredDimensionSpacePoint);
$newParentSubtreeTags = $this->nodeTagsForNode($newParentNodeAggregateId, $contentStreamId, $coveredDimensionSpacePoint);
$newSubtreeTags = [];
foreach ($nodeTags->withoutInherited() as $tag) {
$newSubtreeTags[$tag->value] = true;
}
foreach ($newParentSubtreeTags as $tag) {
$newSubtreeTags[$tag->value] = null;
}
if ($newSubtreeTags === [] && $nodeTags->isEmpty()) {
return;
}
private function moveSubtreeTags(
ContentStreamId $contentStreamId,
NodeAggregateId $newParentNodeAggregateId,
DimensionSpacePoint $coveredDimensionSpacePoint
): void {
$this->getDatabaseConnection()->executeStatement('
UPDATE ' . $this->getTableNamePrefix() . '_hierarchyrelation h
SET h.subtreetags = JSON_MERGE_PATCH(:newParentTags, JSON_MERGE_PATCH(\'{}\', h.subtreetags))
WHERE h.childnodeanchor IN (
WITH RECURSIVE cte (id) AS (
SELECT ch.childnodeanchor
FROM ' . $this->getTableNamePrefix() . '_hierarchyrelation ch
INNER JOIN ' . $this->getTableNamePrefix() . '_node n ON n.relationanchorpoint = ch.parentnodeanchor
UPDATE ' . $this->getTableNamePrefix() . '_hierarchyrelation h,
(
WITH RECURSIVE cte AS (
SELECT
JSON_KEYS(th.subtreetags) subtreeTagsToInherit, th.childnodeanchor
FROM
' . $this->getTableNamePrefix() . '_hierarchyrelation th
INNER JOIN ' . $this->getTableNamePrefix() . '_node tn ON tn.relationanchorpoint = th.childnodeanchor
WHERE
n.nodeaggregateid = :nodeAggregateId
AND ch.contentstreamid = :contentStreamId
AND ch.dimensionspacepointhash = :dimensionSpacePointHash
UNION ALL
tn.nodeaggregateid = :newParentNodeAggregateId
AND th.contentstreamid = :contentStreamId
AND th.dimensionspacepointhash = :dimensionSpacePointHash
UNION
SELECT
dh.childnodeanchor
JSON_MERGE_PRESERVE(
cte.subtreeTagsToInherit,
JSON_KEYS(JSON_MERGE_PATCH(
\'{}\',
dh.subtreetags
))
) subtreeTagsToInherit,
dh.childnodeanchor
FROM
cte
JOIN ' . $this->getTableNamePrefix() . '_hierarchyrelation dh ON dh.parentnodeanchor = cte.id
JOIN ' . $this->getTableNamePrefix() . '_hierarchyrelation dh
ON
dh.parentnodeanchor = cte.childnodeanchor
AND dh.contentstreamid = :contentStreamId
AND dh.dimensionspacepointhash = :dimensionSpacePointHash
)
SELECT id FROM cte
SELECT * FROM cte
) AS r
SET h.subtreetags = (
SELECT
JSON_MERGE_PATCH(
IFNULL(JSON_OBJECTAGG(htk.k, null), \'{}\'),
JSON_MERGE_PATCH(\'{}\', h.subtreetags)
)
FROM
JSON_TABLE(r.subtreeTagsToInherit, \'$[*]\' COLUMNS (k VARCHAR(36) PATH \'$\')) htk
)
', [
'contentStreamId' => $contentStreamId->value,
'nodeAggregateId' => $nodeAggregateId->value,
'dimensionSpacePointHash' => $coveredDimensionSpacePoint->hash,
'newParentTags' => json_encode($newSubtreeTags, JSON_THROW_ON_ERROR | JSON_FORCE_OBJECT),
]);
$this->getDatabaseConnection()->executeStatement('
UPDATE ' . $this->getTableNamePrefix() . '_hierarchyrelation h
INNER JOIN ' . $this->getTableNamePrefix() . '_node n ON n.relationanchorpoint = h.childnodeanchor
SET h.subtreetags = :newParentTags
WHERE
n.nodeaggregateid = :nodeAggregateId
h.childnodeanchor = r.childnodeanchor
AND h.contentstreamid = :contentStreamId
AND h.dimensionspacepointhash = :dimensionSpacePointHash
', [
'contentStreamId' => $contentStreamId->value,
'nodeAggregateId' => $nodeAggregateId->value,
'dimensionSpacePointHash' => $coveredDimensionSpacePoint->hash,
'newParentTags' => json_encode($newSubtreeTags, JSON_THROW_ON_ERROR | JSON_FORCE_OBJECT),
]);
}

private function nodeTagsForNode(NodeAggregateId $nodeAggregateId, ContentStreamId $contentStreamId, DimensionSpacePoint $dimensionSpacePoint): NodeTags
{
$subtreeTagsJson = $this->getDatabaseConnection()->fetchOne('
SELECT h.subtreetags FROM ' . $this->getTableNamePrefix() . '_hierarchyrelation h
INNER JOIN ' . $this->getTableNamePrefix() . '_node n ON n.relationanchorpoint = h.childnodeanchor
WHERE
n.nodeaggregateid = :nodeAggregateId
AND h.contentstreamid = :contentStreamId
AND h.dimensionspacepointhash = :dimensionSpacePointHash
', [
'nodeAggregateId' => $nodeAggregateId->value,
'contentStreamId' => $contentStreamId->value,
'dimensionSpacePointHash' => $dimensionSpacePoint->hash,
'newParentNodeAggregateId' => $newParentNodeAggregateId->value,
'dimensionSpacePointHash' => $coveredDimensionSpacePoint->hash,
]);
if (!is_string($subtreeTagsJson)) {
throw new \RuntimeException(sprintf('Failed to fetch SubtreeTags for node "%s" in content subgraph "%s@%s"', $nodeAggregateId->value, $dimensionSpacePoint->toJson(), $contentStreamId->value), 1698838865);
}
return NodeFactory::extractNodeTagsFromJson($subtreeTagsJson);
}

private function subtreeTagsForHierarchyRelation(ContentStreamId $contentStreamId, NodeRelationAnchorPoint $parentNodeAnchorPoint, DimensionSpacePoint $dimensionSpacePoint): NodeTags
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ Feature: Move a node aggregate into and out of a tagged parent
Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"}
And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"}
And I expect this node to be exactly explicitly tagged "tag1"
And I expect this node to exactly inherit the tags "tag1"
And I expect this node to exactly inherit the tags ""

And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"}
And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"}
Expand All @@ -469,7 +469,7 @@ Feature: Move a node aggregate into and out of a tagged parent
Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"}
And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"}
And I expect this node to be exactly explicitly tagged "tag1"
And I expect this node to exactly inherit the tags "tag1"
And I expect this node to exactly inherit the tags ""

And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"}
And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"}
Expand Down Expand Up @@ -539,7 +539,7 @@ Feature: Move a node aggregate into and out of a tagged parent
Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"}
And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"}
And I expect this node to be exactly explicitly tagged "tag1"
And I expect this node to exactly inherit the tags "tag1"
And I expect this node to exactly inherit the tags ""

And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"}
And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"}
Expand Down Expand Up @@ -609,7 +609,7 @@ Feature: Move a node aggregate into and out of a tagged parent
Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"}
And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"}
And I expect this node to be exactly explicitly tagged "tag1"
And I expect this node to exactly inherit the tags "tag1"
And I expect this node to exactly inherit the tags ""

And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"}
And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"}
Expand Down Expand Up @@ -679,7 +679,7 @@ Feature: Move a node aggregate into and out of a tagged parent
Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"}
And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"}
And I expect this node to be exactly explicitly tagged "tag1"
And I expect this node to exactly inherit the tags "tag1"
And I expect this node to exactly inherit the tags ""

And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"}
And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"}
Expand Down Expand Up @@ -1020,7 +1020,7 @@ Feature: Move a node aggregate into and out of a tagged parent
Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"}
And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"}
And I expect this node to be exactly explicitly tagged "tag1"
And I expect this node to exactly inherit the tags "tag1"
And I expect this node to exactly inherit the tags ""

And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"}
And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"}
Expand All @@ -1031,7 +1031,7 @@ Feature: Move a node aggregate into and out of a tagged parent
Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"}
And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"}
And I expect this node to be exactly explicitly tagged "tag1"
And I expect this node to exactly inherit the tags "tag1"
And I expect this node to exactly inherit the tags ""

And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"}
And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"}
Expand Down Expand Up @@ -1101,7 +1101,7 @@ Feature: Move a node aggregate into and out of a tagged parent
Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"}
And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"}
And I expect this node to be exactly explicitly tagged "tag1"
And I expect this node to exactly inherit the tags "tag1"
And I expect this node to exactly inherit the tags ""

And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"}
And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"}
Expand Down Expand Up @@ -1171,7 +1171,7 @@ Feature: Move a node aggregate into and out of a tagged parent
Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"}
And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"}
And I expect this node to be exactly explicitly tagged "tag1"
And I expect this node to exactly inherit the tags "tag1"
And I expect this node to exactly inherit the tags ""

And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"}
And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"}
Expand Down Expand Up @@ -1241,7 +1241,7 @@ Feature: Move a node aggregate into and out of a tagged parent
Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"}
And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"}
And I expect this node to be exactly explicitly tagged "tag1"
And I expect this node to exactly inherit the tags "tag1"
And I expect this node to exactly inherit the tags ""

And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"}
And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"}
Expand Down Expand Up @@ -1788,7 +1788,7 @@ Feature: Move a node aggregate into and out of a tagged parent
When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"}
Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"}
And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"}
And I expect this node to be exactly explicitly tagged "tag1"
And I expect this node to be exactly explicitly tagged ""
And I expect this node to exactly inherit the tags "tag1"

And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"}
Expand All @@ -1811,7 +1811,7 @@ Feature: Move a node aggregate into and out of a tagged parent

Given the command TagSubtree is executed with payload:
| Key | Value |
| nodeAggregateId | "nody-mc-nodeface" |
| nodeAggregateId | "sir-david-nodenborough" |
| coveredDimensionSpacePoint | {"example": "spec"} |
| nodeVariantSelectionStrategy | "allSpecializations" |
| tag | "tag1" |
Expand Down Expand Up @@ -1881,7 +1881,7 @@ Feature: Move a node aggregate into and out of a tagged parent

Given the command TagSubtree is executed with payload:
| Key | Value |
| nodeAggregateId | "nody-mc-nodeface" |
| nodeAggregateId | "sir-david-nodenborough" |
| coveredDimensionSpacePoint | {"example": "spec"} |
| nodeVariantSelectionStrategy | "allSpecializations" |
| tag | "tag1" |
Expand Down Expand Up @@ -1951,7 +1951,7 @@ Feature: Move a node aggregate into and out of a tagged parent

Given the command TagSubtree is executed with payload:
| Key | Value |
| nodeAggregateId | "nody-mc-nodeface" |
| nodeAggregateId | "sir-david-nodenborough" |
| coveredDimensionSpacePoint | {"example": "source"} |
| nodeVariantSelectionStrategy | "allSpecializations" |
| tag | "tag1" |
Expand Down Expand Up @@ -2021,7 +2021,7 @@ Feature: Move a node aggregate into and out of a tagged parent

Given the command TagSubtree is executed with payload:
| Key | Value |
| nodeAggregateId | "nody-mc-nodeface" |
| nodeAggregateId | "sir-david-nodenborough" |
| coveredDimensionSpacePoint | {"example": "source"} |
| nodeVariantSelectionStrategy | "allSpecializations" |
| tag | "tag1" |
Expand Down Expand Up @@ -2091,7 +2091,7 @@ Feature: Move a node aggregate into and out of a tagged parent

Given the command TagSubtree is executed with payload:
| Key | Value |
| nodeAggregateId | "nody-mc-nodeface" |
| nodeAggregateId | "sir-david-nodenborough" |
| coveredDimensionSpacePoint | {"example": "spec"} |
| nodeVariantSelectionStrategy | "allSpecializations" |
| tag | "tag1" |
Expand Down Expand Up @@ -2161,7 +2161,7 @@ Feature: Move a node aggregate into and out of a tagged parent

Given the command TagSubtree is executed with payload:
| Key | Value |
| nodeAggregateId | "nody-mc-nodeface" |
| nodeAggregateId | "sir-david-nodenborough" |
| coveredDimensionSpacePoint | {"example": "spec"} |
| nodeVariantSelectionStrategy | "allSpecializations" |
| tag | "tag1" |
Expand Down
Loading

0 comments on commit 95cda1e

Please sign in to comment.