Skip to content

Commit f14e331

Browse files
authored
Merge pull request #4124 from neos/feature/4075-content-subgraph-count-queries
FEATURE: Add count* queries to Content Subgraph
2 parents d51cd12 + 6e68e28 commit f14e331

File tree

15 files changed

+1037
-88
lines changed

15 files changed

+1037
-88
lines changed

Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ContentSubgraph.php

Lines changed: 140 additions & 86 deletions
Large diffs are not rendered by default.

Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Repository/ContentSubhypergraph.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint;
2727
use Neos\ContentRepository\Core\NodeType\NodeTypeManager;
2828
use Neos\ContentRepository\Core\Projection\ContentGraph\ContentSubgraphInterface;
29+
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter;
2930
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindChildNodesFilter;
3031
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindDescendantNodesFilter;
3132
use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindPrecedingSiblingNodesFilter;
@@ -127,6 +128,12 @@ public function findChildNodes(
127128
);
128129
}
129130

131+
public function countChildNodes(NodeAggregateId $parentNodeAggregateId, Filter\CountChildNodesFilter $filter): int
132+
{
133+
// TODO: Implement countChildNodes() method.
134+
return 0;
135+
}
136+
130137
public function findReferences(
131138
NodeAggregateId $nodeAggregateId,
132139
FindReferencesFilter $filter
@@ -158,6 +165,12 @@ public function findReferences(
158165
);
159166
}
160167

168+
public function countReferences(NodeAggregateId $nodeAggregateId, Filter\CountReferencesFilter $filter): int
169+
{
170+
// TODO: Implement countReferences() method.
171+
return 0;
172+
}
173+
161174
public function findBackReferences(
162175
NodeAggregateId $nodeAggregateId,
163176
FindBackReferencesFilter $filter
@@ -190,6 +203,12 @@ public function findBackReferences(
190203
);
191204
}
192205

206+
public function countBackReferences(NodeAggregateId $nodeAggregateId, Filter\CountBackReferencesFilter $filter): int
207+
{
208+
// TODO: Implement countBackReferences() method.
209+
return 0;
210+
}
211+
193212
public function findParentNode(NodeAggregateId $childNodeAggregateId): ?Node
194213
{
195214
$query = HypergraphParentQuery::create($this->contentStreamIdentifier, $this->tableNamePrefix);
@@ -408,6 +427,13 @@ public function findDescendantNodes(
408427
return Nodes::createEmpty();
409428
}
410429

430+
431+
public function countDescendantNodes(NodeAggregateId $entryNodeAggregateId, Filter\CountDescendantNodesFilter $filter): int
432+
{
433+
// TODO: Implement countDescendantNodes() method.
434+
return 0;
435+
}
436+
411437
/**
412438
* @throws \Doctrine\DBAL\Driver\Exception
413439
* @throws \Doctrine\DBAL\Exception
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
@contentrepository @adapters=DoctrineDBAL
2+
# TODO implement for Postgres
3+
Feature: Count nodes using the countBackReferences query
4+
5+
Background:
6+
Given I have the following content dimensions:
7+
| Identifier | Values | Generalizations |
8+
| language | mul, de, en, ch | ch->de->mul, en->mul |
9+
And I have the following NodeTypes configuration:
10+
"""
11+
'Neos.ContentRepository:Root': []
12+
'Neos.ContentRepository.Testing:AbstractPage':
13+
abstract: true
14+
properties:
15+
text:
16+
type: string
17+
refs:
18+
type: references
19+
properties:
20+
foo:
21+
type: string
22+
ref:
23+
type: reference
24+
properties:
25+
foo:
26+
type: string
27+
'Neos.ContentRepository.Testing:SomeMixin':
28+
abstract: true
29+
'Neos.ContentRepository.Testing:Homepage':
30+
superTypes:
31+
'Neos.ContentRepository.Testing:AbstractPage': true
32+
childNodes:
33+
terms:
34+
type: 'Neos.ContentRepository.Testing:Terms'
35+
contact:
36+
type: 'Neos.ContentRepository.Testing:Contact'
37+
38+
'Neos.ContentRepository.Testing:Terms':
39+
superTypes:
40+
'Neos.ContentRepository.Testing:AbstractPage': true
41+
properties:
42+
text:
43+
defaultValue: 'Terms default'
44+
'Neos.ContentRepository.Testing:Contact':
45+
superTypes:
46+
'Neos.ContentRepository.Testing:AbstractPage': true
47+
'Neos.ContentRepository.Testing:SomeMixin': true
48+
properties:
49+
text:
50+
defaultValue: 'Contact default'
51+
'Neos.ContentRepository.Testing:Page':
52+
superTypes:
53+
'Neos.ContentRepository.Testing:AbstractPage': true
54+
'Neos.ContentRepository.Testing:SpecialPage':
55+
superTypes:
56+
'Neos.ContentRepository.Testing:AbstractPage': true
57+
"""
58+
And I am user identified by "initiating-user-identifier"
59+
And the command CreateRootWorkspace is executed with payload:
60+
| Key | Value |
61+
| workspaceName | "live" |
62+
| workspaceTitle | "Live" |
63+
| workspaceDescription | "The live workspace" |
64+
| newContentStreamId | "cs-identifier" |
65+
And the graph projection is fully up to date
66+
And I am in content stream "cs-identifier" and dimension space point {"language":"de"}
67+
And the command CreateRootNodeAggregateWithNode is executed with payload:
68+
| Key | Value |
69+
| nodeAggregateId | "lady-eleonode-rootford" |
70+
| nodeTypeName | "Neos.ContentRepository:Root" |
71+
And the graph projection is fully up to date
72+
And the following CreateNodeAggregateWithNode commands are executed:
73+
| nodeAggregateId | nodeName | nodeTypeName | parentNodeAggregateId | initialPropertyValues | tetheredDescendantNodeAggregateIds |
74+
| home | home | Neos.ContentRepository.Testing:Homepage | lady-eleonode-rootford | {} | {"terms": "terms", "contact": "contact"} |
75+
| c | c | Neos.ContentRepository.Testing:Page | home | {"text": "c"} | {} |
76+
| a | a | Neos.ContentRepository.Testing:Page | home | {"text": "a"} | {} |
77+
| a1 | a1 | Neos.ContentRepository.Testing:Page | a | {"text": "a1"} | {} |
78+
| a2 | a2 | Neos.ContentRepository.Testing:Page | a | {"text": "a2"} | {} |
79+
| a2a | a2a | Neos.ContentRepository.Testing:SpecialPage | a2 | {"text": "a2a"} | {} |
80+
| a2a1 | a2a1 | Neos.ContentRepository.Testing:Page | a2a | {"text": "a2a1"} | {} |
81+
| a2a2 | a2a2 | Neos.ContentRepository.Testing:Page | a2a | {"text": "a2a2"} | {} |
82+
| a2a3 | a2a3 | Neos.ContentRepository.Testing:Page | a2a | {"text": "a2a3"} | {} |
83+
| a3 | a3 | Neos.ContentRepository.Testing:Page | a | {"text": "a3"} | {} |
84+
| b | b | Neos.ContentRepository.Testing:Page | home | {"text": "b"} | {} |
85+
| b1 | b1 | Neos.ContentRepository.Testing:Page | b | {"text": "b1"} | {} |
86+
And the command SetNodeReferences is executed with payload:
87+
| Key | Value |
88+
| sourceNodeAggregateId | "c" |
89+
| referenceName | "refs" |
90+
| references | [{"target":"b1", "properties": {"foo": "foos"}}] |
91+
And the command SetNodeReferences is executed with payload:
92+
| Key | Value |
93+
| sourceNodeAggregateId | "a" |
94+
| referenceName | "refs" |
95+
| references | [{"target":"b1"}, {"target":"a2a2"}] |
96+
And the command SetNodeReferences is executed with payload:
97+
| Key | Value |
98+
| sourceNodeAggregateId | "b1" |
99+
| referenceName | "ref" |
100+
| references | [{"target":"a"}] |
101+
And the command SetNodeReferences is executed with payload:
102+
| Key | Value |
103+
| sourceNodeAggregateId | "b" |
104+
| referenceName | "refs" |
105+
| references | [{"target":"a3", "properties": {"foo": "bar"}}, {"target":"a2a1", "properties": {"foo": "baz"}}] |
106+
And the command SetNodeReferences is executed with payload:
107+
| Key | Value |
108+
| sourceNodeAggregateId | "a" |
109+
| referenceName | "refs" |
110+
| references | [{"target":"b1", "properties": {"foo": "bar"}}, {"target": "b"}] |
111+
And the command SetNodeReferences is executed with payload:
112+
| Key | Value |
113+
| sourceNodeAggregateId | "a2" |
114+
| referenceName | "ref" |
115+
| references | [{"target":"a2a3"}] |
116+
And the command SetNodeReferences is executed with payload:
117+
| Key | Value |
118+
| sourceNodeAggregateId | "a2a3" |
119+
| referenceName | "ref" |
120+
| references | [{"target":"a2"}] |
121+
And the command DisableNodeAggregate is executed with payload:
122+
| Key | Value |
123+
| nodeAggregateId | "a2a3" |
124+
| nodeVariantSelectionStrategy | "allVariants" |
125+
And the graph projection is fully up to date
126+
127+
Scenario: countBackReferences queries with empty results
128+
When I execute the countBackReferences query for node aggregate id "non-existing" I expect the result 0
129+
When I execute the countBackReferences query for node aggregate id "home" I expect the result 0
130+
# "a2" is references node "a2a3" but "a2a3" is disabled so this reference should be ignored
131+
When I execute the countBackReferences query for node aggregate id "a2" I expect the result 0
132+
# "a2a3" is references node "a2" but "a2a3" is disabled so this reference should be ignored
133+
When I execute the countBackReferences query for node aggregate id "a2a3" I expect the result 0
134+
When I execute the countBackReferences query for node aggregate id "a" and filter '{"referenceName": "non-existing"}' I expect the result 0
135+
136+
Scenario: countBackReferences queries with results
137+
When I execute the countBackReferences query for node aggregate id "a" I expect the result 1
138+
When I execute the countBackReferences query for node aggregate id "a3" and filter '{"referenceName": "refs"}' I expect the result 1
139+
When I execute the countBackReferences query for node aggregate id "b1" I expect the result 2
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
@contentrepository @adapters=DoctrineDBAL
2+
# TODO implement for Postgres
3+
Feature: Count nodes using the countChildNodes query
4+
5+
Background:
6+
Given I have the following content dimensions:
7+
| Identifier | Values | Generalizations |
8+
| language | mul, de, en, ch | ch->de->mul, en->mul |
9+
And I have the following NodeTypes configuration:
10+
"""
11+
'Neos.ContentRepository:Root': []
12+
'Neos.ContentRepository.Testing:AbstractPage':
13+
abstract: true
14+
properties:
15+
text:
16+
type: string
17+
'Neos.ContentRepository.Testing:SomeMixin':
18+
abstract: true
19+
'Neos.ContentRepository.Testing:Homepage':
20+
superTypes:
21+
'Neos.ContentRepository.Testing:AbstractPage': true
22+
childNodes:
23+
terms:
24+
type: 'Neos.ContentRepository.Testing:Terms'
25+
contact:
26+
type: 'Neos.ContentRepository.Testing:Contact'
27+
28+
'Neos.ContentRepository.Testing:Terms':
29+
superTypes:
30+
'Neos.ContentRepository.Testing:AbstractPage': true
31+
properties:
32+
text:
33+
defaultValue: 'Terms default'
34+
'Neos.ContentRepository.Testing:Contact':
35+
superTypes:
36+
'Neos.ContentRepository.Testing:AbstractPage': true
37+
'Neos.ContentRepository.Testing:SomeMixin': true
38+
properties:
39+
text:
40+
defaultValue: 'Contact default'
41+
'Neos.ContentRepository.Testing:Page':
42+
superTypes:
43+
'Neos.ContentRepository.Testing:AbstractPage': true
44+
'Neos.ContentRepository.Testing:SpecialPage':
45+
superTypes:
46+
'Neos.ContentRepository.Testing:AbstractPage': true
47+
"""
48+
And I am user identified by "initiating-user-identifier"
49+
And the command CreateRootWorkspace is executed with payload:
50+
| Key | Value |
51+
| workspaceName | "live" |
52+
| workspaceTitle | "Live" |
53+
| workspaceDescription | "The live workspace" |
54+
| newContentStreamId | "cs-identifier" |
55+
And the graph projection is fully up to date
56+
And I am in content stream "cs-identifier" and dimension space point {"language":"de"}
57+
And the command CreateRootNodeAggregateWithNode is executed with payload:
58+
| Key | Value |
59+
| nodeAggregateId | "lady-eleonode-rootford" |
60+
| nodeTypeName | "Neos.ContentRepository:Root" |
61+
And the graph projection is fully up to date
62+
And the following CreateNodeAggregateWithNode commands are executed:
63+
| nodeAggregateId | nodeTypeName | parentNodeAggregateId | initialPropertyValues | tetheredDescendantNodeAggregateIds |
64+
| home | Neos.ContentRepository.Testing:Homepage | lady-eleonode-rootford | {} | {"terms": "terms", "contact": "contact"} |
65+
| a | Neos.ContentRepository.Testing:Page | home | {"text": "a"} | {} |
66+
| a1 | Neos.ContentRepository.Testing:Page | a | {"text": "a1"} | {} |
67+
| a2 | Neos.ContentRepository.Testing:Page | a | {"text": "a2"} | {} |
68+
| a2a | Neos.ContentRepository.Testing:SpecialPage | a2 | {"text": "a2a"} | {} |
69+
| a2a1 | Neos.ContentRepository.Testing:Page | a2a | {"text": "a2a1"} | {} |
70+
| a2a2 | Neos.ContentRepository.Testing:Page | a2a | {"text": "a2a2"} | {} |
71+
| a2a3 | Neos.ContentRepository.Testing:Page | a2a | {"text": "a2a3"} | {} |
72+
| b | Neos.ContentRepository.Testing:Page | home | {"text": "b"} | {} |
73+
| b1 | Neos.ContentRepository.Testing:Page | b | {"text": "b1"} | {} |
74+
And the command DisableNodeAggregate is executed with payload:
75+
| Key | Value |
76+
| nodeAggregateId | "a2a3" |
77+
| nodeVariantSelectionStrategy | "allVariants" |
78+
And the graph projection is fully up to date
79+
80+
Scenario: Child nodes without filter
81+
When I execute the countChildNodes query for parent node aggregate id "home" I expect the result 4
82+
When I execute the countChildNodes query for parent node aggregate id "a" I expect the result 2
83+
When I execute the countChildNodes query for parent node aggregate id "a1" I expect the result 0
84+
When I execute the countChildNodes query for parent node aggregate id "a2a" I expect the result 2
85+
86+
Scenario: Child nodes filtered by node type
87+
When I execute the countChildNodes query for parent node aggregate id "home" and filter '{"nodeTypeConstraints": "Neos.ContentRepository.Testing:AbstractPage"}' I expect the result 4
88+
When I execute the countChildNodes query for parent node aggregate id "home" and filter '{"nodeTypeConstraints": "Neos.ContentRepository.Testing:SomeMixin"}' I expect the result 1
89+
When I execute the countChildNodes query for parent node aggregate id "home" and filter '{"nodeTypeConstraints": "Neos.ContentRepository.Testing:SomeMixin"}' I expect the result 1
90+
When I execute the countChildNodes query for parent node aggregate id "home" and filter '{"nodeTypeConstraints": "Neos.ContentRepository.Testing:AbstractPage,!Neos.ContentRepository.Testing:SomeMixin"}' I expect the result 3
91+
When I execute the countChildNodes query for parent node aggregate id "home" and filter '{"nodeTypeConstraints": "Neos.ContentRepository.Testing:NonExistingNodeType"}' I expect the result 0

0 commit comments

Comments
 (0)