-
Notifications
You must be signed in to change notification settings - Fork 2
Use a sql recursive query for node tree invalidation and dto tree building #791
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
Changes from all commits
7547737
520bd8e
ad66f8f
a4a4709
855145e
d62860d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,21 +29,32 @@ public interface NodeRepository extends JpaRepository<NodeEntity, UUID> { | |
List<NodeEntity> findAllByStudyIdAndTypeAndStashed(UUID id, NodeType type, boolean stashed); | ||
|
||
@Query(nativeQuery = true, value = | ||
"WITH RECURSIVE NodeHierarchy (id_node, depth) AS ( " + | ||
" SELECT n0.id_node, 0 AS depth" + | ||
"WITH RECURSIVE NodeHierarchy (id_node) AS ( " + | ||
" SELECT n0.id_node" + | ||
" FROM NODE n0 " + | ||
" WHERE id_node = :nodeUuid " + | ||
" UNION ALL " + | ||
" SELECT n.id_node, nh.depth + 1 as depth" + | ||
" SELECT n.id_node" + | ||
" FROM NODE n " + | ||
" INNER JOIN NodeHierarchy nh ON n.parent_node = nh.id_node " + | ||
") " + | ||
"SELECT nh.id_node::text " + | ||
"FROM NodeHierarchy nh " + | ||
"ORDER BY nh.depth DESC") | ||
List<String> findAllDescendants(UUID nodeUuid); | ||
"SELECT cast(nh.id_node AS VARCHAR) " + | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is "cast()" needed here ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes otherwise the result is of type string and not uuid There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does it work without casting neither in postgres nor H2? or not working only in H2? |
||
"FROM NodeHierarchy nh where nh.id_node != :nodeUuid ") | ||
List<UUID> findAllChildrenUuids(UUID nodeUuid); | ||
|
||
List<NodeEntity> findAllByIdNodeIn(List<UUID> uuids); | ||
@Query(nativeQuery = true, value = | ||
"WITH RECURSIVE NodeHierarchy (id_node) AS ( " + | ||
" SELECT n0.id_node" + | ||
" FROM NODE n0 " + | ||
" WHERE id_node = :nodeUuid " + | ||
" UNION ALL " + | ||
" SELECT n.id_node" + | ||
" FROM NODE n " + | ||
" INNER JOIN NodeHierarchy nh ON n.parent_node = nh.id_node " + | ||
") " + | ||
"SELECT * FROM NODE n " + | ||
"WHERE n.id_node IN (SELECT nh.id_node FROM NodeHierarchy nh) AND n.id_node != :nodeUuid") | ||
List<NodeEntity> findAllChildren(UUID nodeUuid); | ||
|
||
List<NodeEntity> findAllByStudyIdAndStashedAndParentNodeIdNodeOrderByStashDateDesc(UUID id, boolean stashed, UUID parentNode); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -128,7 +128,7 @@ private NetworkModificationNode createAndInsertNode(StudyEntity study, UUID node | |
if (insertMode.equals(InsertMode.BEFORE)) { | ||
reference.setParentNode(node); | ||
} else if (insertMode.equals(InsertMode.AFTER)) { | ||
nodesRepository.findAllByParentNodeIdNode(nodeId).stream() | ||
getChildren(nodeId).stream() | ||
.filter(n -> !n.getIdNode().equals(node.getIdNode())) | ||
.forEach(child -> child.setParentNode(node)); | ||
} | ||
|
@@ -238,7 +238,7 @@ public void moveStudyNode(UUID nodeToMoveUuid, UUID anchorNodeUuid, InsertMode i | |
private UUID moveNode(UUID nodeToMoveUuid, UUID anchorNodeUuid, InsertMode insertMode) { | ||
NodeEntity nodeToMoveEntity = getNodeEntity(nodeToMoveUuid); | ||
|
||
nodesRepository.findAllByParentNodeIdNode(nodeToMoveUuid) | ||
getChildren(nodeToMoveUuid) | ||
.forEach(child -> child.setParentNode(nodeToMoveEntity.getParentNode())); | ||
|
||
NodeEntity anchorNodeEntity = getNodeEntity(anchorNodeUuid); | ||
|
@@ -253,7 +253,7 @@ private UUID moveNode(UUID nodeToMoveUuid, UUID anchorNodeUuid, InsertMode inser | |
if (insertMode.equals(InsertMode.BEFORE)) { | ||
anchorNodeEntity.setParentNode(nodeToMoveEntity); | ||
} else if (insertMode.equals(InsertMode.AFTER)) { | ||
nodesRepository.findAllByParentNodeIdNode(anchorNodeUuid).stream() | ||
getChildren(anchorNodeUuid).stream() | ||
.filter(n -> !n.getIdNode().equals(nodeToMoveEntity.getIdNode())) | ||
.forEach(child -> child.setParentNode(nodeToMoveEntity)); | ||
} | ||
|
@@ -264,7 +264,7 @@ private UUID moveNode(UUID nodeToMoveUuid, UUID anchorNodeUuid, InsertMode inser | |
|
||
@Transactional | ||
public void moveStudySubtree(UUID parentNodeToMoveUuid, UUID anchorNodeUuid) { | ||
List<NodeEntity> children = getChildrenByParentUuid(parentNodeToMoveUuid); | ||
List<NodeEntity> children = getChildren(parentNodeToMoveUuid); | ||
moveNode(parentNodeToMoveUuid, anchorNodeUuid, InsertMode.CHILD); | ||
children.forEach(child -> self.moveStudySubtree(child.getIdNode(), parentNodeToMoveUuid)); | ||
} | ||
|
@@ -299,9 +299,9 @@ private void stashNodes(UUID id, boolean stashChildren, List<UUID> stashedNodes, | |
UUID modificationGroupUuid = self.getModificationGroupUuid(nodeToStash.getIdNode()); | ||
networkModificationService.deleteStashedModifications(modificationGroupUuid); | ||
if (!stashChildren) { | ||
nodesRepository.findAllByParentNodeIdNode(id).forEach(node -> node.setParentNode(nodeToStash.getParentNode())); | ||
getChildren(id).forEach(node -> node.setParentNode(nodeToStash.getParentNode())); | ||
} else { | ||
nodesRepository.findAllByParentNodeIdNode(id) | ||
getChildren(id) | ||
.forEach(child -> stashNodes(child.getIdNode(), true, stashedNodes, false)); | ||
} | ||
stashedNodes.add(id); | ||
|
@@ -329,9 +329,9 @@ private void deleteNodes(UUID id, boolean deleteChildren, boolean allowDeleteRoo | |
rootNetworkNodeInfoService.fillDeleteNodeInfo(id, deleteNodeInfos); | ||
|
||
if (!deleteChildren) { | ||
nodesRepository.findAllByParentNodeIdNode(id).forEach(node -> node.setParentNode(nodeToDelete.getParentNode())); | ||
getChildren(id).forEach(node -> node.setParentNode(nodeToDelete.getParentNode())); | ||
} else { | ||
nodesRepository.findAllByParentNodeIdNode(id) | ||
getChildren(id) | ||
.forEach(child -> deleteNodes(child.getIdNode(), true, false, removedNodes, deleteNodeInfos)); | ||
} | ||
removedNodes.add(id); | ||
|
@@ -344,12 +344,28 @@ private void deleteNodes(UUID id, boolean deleteChildren, boolean allowDeleteRoo | |
}); | ||
} | ||
|
||
public List<NodeEntity> getChildrenByParentUuid(UUID parentUuid) { | ||
public List<NodeEntity> getChildren(UUID parentUuid) { | ||
return nodesRepository.findAllByParentNodeIdNode(parentUuid); | ||
} | ||
|
||
public List<String> getAllChildrenFromParentUuid(UUID parentUuid) { | ||
return nodesRepository.findAllDescendants(parentUuid); | ||
public List<UUID> getAllChildrenUuids(UUID parentUuid) { | ||
return nodesRepository.findAllChildrenUuids(parentUuid); | ||
} | ||
|
||
// TODO Remove this method and use getAllChildrenUuids | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since we've already changed some "getChildren" to "getChildrenUuids" here, why don't we make this change right now by renaming all occurences ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method is used in many places and you have to test a lot of things |
||
public List<UUID> getChildrenUuids(UUID parentUuid) { | ||
List<UUID> children = new ArrayList<>(); | ||
doGetChildrenUuids(parentUuid, children); | ||
return children; | ||
} | ||
|
||
private void doGetChildrenUuids(UUID parentUuid, List<UUID> children) { | ||
Optional<NodeEntity> optNode = nodesRepository.findById(parentUuid); | ||
optNode.ifPresent(node -> getChildren(parentUuid) | ||
.forEach(child -> { | ||
children.add(child.getIdNode()); | ||
doGetChildrenUuids(child.getIdNode(), children); | ||
})); | ||
} | ||
|
||
@Transactional | ||
|
@@ -411,10 +427,7 @@ private void completeNodeInfos(List<AbstractNode> nodes, UUID rootNetworkUuid) { | |
|
||
@Transactional | ||
public AbstractNode getStudySubtree(UUID studyId, UUID parentNodeUuid, UUID rootNetworkUuid) { | ||
// TODO: not working because of proxy appearing in tests TOFIX later | ||
// List<UUID> nodeUuids = nodesRepository.findAllDescendants(parentNodeUuid).stream().map(UUID::fromString).toList(); | ||
// List<NodeEntity> nodes = nodesRepository.findAllById(nodeUuids); | ||
List<NodeEntity> nodes = nodesRepository.findAllByStudyId(studyId); | ||
List<NodeEntity> nodes = nodesRepository.findAllChildren(parentNodeUuid); | ||
|
||
List<AbstractNode> allNodeInfos = new ArrayList<>(); | ||
allNodeInfos.addAll(rootNodeInfoRepository.findAllByNodeStudyId(studyId).stream().map(RootNodeInfoEntity::toDto).toList()); | ||
|
@@ -561,7 +574,7 @@ private AbstractNode getSimpleNode(UUID nodeId) { | |
@Transactional | ||
public AbstractNode getNode(UUID nodeId, UUID rootNetworkUuid) { | ||
AbstractNode node = getSimpleNode(nodeId); | ||
nodesRepository.findAllByParentNodeIdNode(node.getId()).stream().map(NodeEntity::getIdNode).forEach(node.getChildrenIds()::add); | ||
getChildren(node.getId()).stream().map(NodeEntity::getIdNode).forEach(node.getChildrenIds()::add); | ||
if (rootNetworkUuid != null) { | ||
completeNodeInfos(List.of(node), rootNetworkUuid); | ||
} | ||
|
@@ -691,7 +704,7 @@ public List<Pair<AbstractNode, Integer>> getStashedNodes(UUID studyUuid) { | |
nodes.stream().map(node -> networkModificationNodeInfos.get(node.getIdNode())) | ||
.forEach(abstractNode -> { | ||
ArrayList<UUID> children = new ArrayList<>(); | ||
doGetChildren(abstractNode.getId(), children); | ||
doGetChildrenUuids(abstractNode.getId(), children); | ||
result.add(Pair.of(abstractNode, children.size())); | ||
}); | ||
return result; | ||
|
@@ -746,7 +759,7 @@ public Map<UUID, UUID> getModificationReports(UUID nodeUuid, UUID rootNetworkUui | |
} | ||
|
||
private void restoreNodeChildren(UUID studyId, UUID parentNodeId) { | ||
nodesRepository.findAllByParentNodeIdNode(parentNodeId).forEach(nodeEntity -> { | ||
getChildren(parentNodeId).forEach(nodeEntity -> { | ||
NetworkModificationNodeInfoEntity modificationNodeToRestore = networkModificationNodeInfoRepository.findById(nodeEntity.getIdNode()).orElseThrow(() -> new StudyException(NODE_NOT_FOUND)); | ||
if (self.isNodeNameExists(studyId, modificationNodeToRestore.getName())) { | ||
String newName = getSuffixedNodeName(studyId, modificationNodeToRestore.getName()); | ||
|
@@ -883,7 +896,7 @@ private boolean hasAnyBuiltChildren(NodeEntity node, UUID rootNetworkUuid, Set<N | |
} | ||
checkedChildren.add(node); | ||
|
||
for (NodeEntity child : getChildrenByParentUuid(node.getIdNode())) { | ||
for (NodeEntity child : getChildren(node.getIdNode())) { | ||
if (!checkedChildren.contains(child) | ||
&& hasAnyBuiltChildren(child, rootNetworkUuid, checkedChildren)) { | ||
return true; | ||
|
@@ -919,11 +932,12 @@ private void fillIndexedNodeTreeInfosToInvalidate(NodeEntity nodeEntity, UUID ro | |
|
||
private InvalidateNodeInfos invalidateChildrenNodes(UUID nodeUuid, UUID rootNetworkUuid) { | ||
InvalidateNodeInfos invalidateNodeInfos = new InvalidateNodeInfos(); | ||
nodesRepository.findAllByParentNodeIdNode(nodeUuid) | ||
.forEach(child -> { | ||
invalidateNodeInfos.add(rootNetworkNodeInfoService.invalidateRootNetworkNode(child.getIdNode(), rootNetworkUuid, InvalidateNodeTreeParameters.ALL)); | ||
invalidateNodeInfos.add(invalidateChildrenNodes(child.getIdNode(), rootNetworkUuid)); | ||
}); | ||
List<RootNetworkNodeInfoEntity> rootNetworkNodeInfoEntities = rootNetworkNodeInfoService.getRootNetworkNodes(rootNetworkUuid, getAllChildrenUuids(nodeUuid)); | ||
|
||
rootNetworkNodeInfoEntities.forEach(child -> | ||
invalidateNodeInfos.add(rootNetworkNodeInfoService.invalidateRootNetworkNode(child, InvalidateNodeTreeParameters.ALL)) | ||
); | ||
|
||
return invalidateNodeInfos; | ||
} | ||
|
||
|
@@ -1010,21 +1024,6 @@ public Boolean isReadOnly(UUID nodeUuid) { | |
return getNodeInfoEntity(nodeUuid).getReadOnly(); | ||
} | ||
|
||
public List<UUID> getChildren(UUID id) { | ||
List<UUID> children = new ArrayList<>(); | ||
doGetChildren(id, children); | ||
return children; | ||
} | ||
|
||
private void doGetChildren(UUID id, List<UUID> children) { | ||
Optional<NodeEntity> optNode = nodesRepository.findById(id); | ||
optNode.ifPresent(node -> nodesRepository.findAllByParentNodeIdNode(id) | ||
.forEach(child -> { | ||
children.add(child.getIdNode()); | ||
doGetChildren(child.getIdNode(), children); | ||
})); | ||
} | ||
|
||
// only used for tests | ||
@Transactional | ||
public UUID getParentNode(UUID nodeUuid, NodeType nodeType) { | ||
|
@@ -1060,7 +1059,7 @@ private void fillIndexedNodeInfosToInvalidate(UUID parentNodeUuid, boolean inclu | |
if (includeParentNode) { | ||
nodesToInvalidate.add(parentNodeUuid); | ||
} | ||
nodesToInvalidate.addAll(getChildren(parentNodeUuid)); | ||
nodesToInvalidate.addAll(getAllChildrenUuids(parentNodeUuid)); | ||
invalidateNodeInfos.addGroupUuids( | ||
networkModificationNodeInfoRepository.findAllById(nodesToInvalidate).stream() | ||
.map(NetworkModificationNodeInfoEntity::getModificationGroupUuid).toList() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we sure that ordering by depth was not necessary anywhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes