From 92e8bc008d7572d0197c68691e66c6ca15e72eaa Mon Sep 17 00:00:00 2001 From: Gunnar Velle Date: Fri, 26 Jan 2024 12:57:05 +0100 Subject: [PATCH] Remove orphans from node. --- .../java/no/ndla/taxonomy/rest/v1/Nodes.java | 6 +- .../rest/v1/commands/NodeSearchBody.java | 8 +-- .../DomainEntityHelperServiceImpl.java | 21 +++---- .../NodePublishingIntegrationTest.java | 62 +++++++++++++++++++ 4 files changed, 76 insertions(+), 21 deletions(-) diff --git a/src/main/java/no/ndla/taxonomy/rest/v1/Nodes.java b/src/main/java/no/ndla/taxonomy/rest/v1/Nodes.java index 08abf4fc..811444ea 100644 --- a/src/main/java/no/ndla/taxonomy/rest/v1/Nodes.java +++ b/src/main/java/no/ndla/taxonomy/rest/v1/Nodes.java @@ -143,8 +143,7 @@ public SearchResultDTO searchNodes( Optional includeContexts, @Parameter(description = "Filter out programme contexts") @RequestParam(value = "filterProgrammes", required = false, defaultValue = "false") - boolean filterProgrammes - ) { + boolean filterProgrammes) { return nodeService.searchByNodeType( query, ids, @@ -172,8 +171,7 @@ public SearchResultDTO searchNodes(@RequestBody NodeSearchBody searchBo searchBodyParams.pageSize, searchBodyParams.page, searchBodyParams.nodeType, - searchBodyParams.customFields - ); + searchBodyParams.customFields); } @GetMapping("/page") diff --git a/src/main/java/no/ndla/taxonomy/rest/v1/commands/NodeSearchBody.java b/src/main/java/no/ndla/taxonomy/rest/v1/commands/NodeSearchBody.java index 7d374d34..3ea95fb5 100644 --- a/src/main/java/no/ndla/taxonomy/rest/v1/commands/NodeSearchBody.java +++ b/src/main/java/no/ndla/taxonomy/rest/v1/commands/NodeSearchBody.java @@ -9,12 +9,11 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; -import no.ndla.taxonomy.config.Constants; -import no.ndla.taxonomy.domain.NodeType; - import java.util.List; import java.util.Map; import java.util.Optional; +import no.ndla.taxonomy.config.Constants; +import no.ndla.taxonomy.domain.NodeType; public class NodeSearchBody { @JsonProperty @@ -23,12 +22,10 @@ public class NodeSearchBody { "If specified, the search result will be filtered by whether they include the key,value combination provided. If more than one provided only one will be required (OR)") public Optional> customFields = Optional.empty(); - @Schema(description = "ISO-639-1 language code", example = "nb") @JsonProperty public Optional language = Optional.of(Constants.DefaultLanguage); - @Schema(description = "How many results to return per page") @JsonProperty public int pageSize = 10; @@ -64,5 +61,4 @@ public class NodeSearchBody { public Optional> getCustomFields() { return customFields; } - } diff --git a/src/main/java/no/ndla/taxonomy/service/DomainEntityHelperServiceImpl.java b/src/main/java/no/ndla/taxonomy/service/DomainEntityHelperServiceImpl.java index e6c7f111..37e158bb 100644 --- a/src/main/java/no/ndla/taxonomy/service/DomainEntityHelperServiceImpl.java +++ b/src/main/java/no/ndla/taxonomy/service/DomainEntityHelperServiceImpl.java @@ -203,18 +203,17 @@ private Optional updateNode(Node node, boolean cleanUp) { } result = nodeRepository.save(existing); - - // delete orphans - List childIds = node.getChildConnections().stream() - .map(DomainEntity::getPublicId) - .toList(); - result.getChildConnections().forEach(nodeConnection -> { - if (!childIds.contains(nodeConnection.getPublicId())) { - // Connection deleted - deleteEntityByPublicId(nodeConnection.getPublicId()); - } - }); } + // delete any orphans + List childIds = node.getChildConnections().stream() + .map(DomainEntity::getPublicId) + .toList(); + result.getChildConnections().forEach(nodeConnection -> { + if (!childIds.contains(nodeConnection.getPublicId())) { + // Connection deleted + deleteEntityByPublicId(nodeConnection.getPublicId()); + } + }); if (cleanUp) { buildPathsForEntity(result.getPublicId()); } diff --git a/src/test/java/no/ndla/taxonomy/service/NodePublishingIntegrationTest.java b/src/test/java/no/ndla/taxonomy/service/NodePublishingIntegrationTest.java index 4c135328..eb43280e 100644 --- a/src/test/java/no/ndla/taxonomy/service/NodePublishingIntegrationTest.java +++ b/src/test/java/no/ndla/taxonomy/service/NodePublishingIntegrationTest.java @@ -48,6 +48,9 @@ public class NodePublishingIntegrationTest extends AbstractIntegrationTest { @Autowired NodeService nodeService; + @Autowired + NodeConnectionService nodeConnectionService; + @Autowired VersionService versionService; @@ -655,4 +658,63 @@ void can_publish_node_tree_to_schema_async() throws Exception { assertEquals(1, customfields.size()); assertAnyTrue(customfields, customfield -> customfield.equals("to be kept")); } + + @Test + @Transactional(propagation = Propagation.REQUIRES_NEW) + void can_publish_node_tree_with_moved_resource_to_schema() throws Exception { + final var command = new VersionPostPut() { + { + name = "Beta"; + } + }; + Version target = versionService.createNewVersion(Optional.empty(), command); + assertTrue(checkSchemaExists(versionService.schemaFromHash(target.getHash()))); + executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); + + // a node to make sure testnode is not the first + builder.node(n -> n.publicId("urn:node:first").resource(r -> r.publicId("urn:resource:first"))); + Node resource = builder.node(NodeType.RESOURCE, r -> r.publicId("urn:resource:1")); + Node topic1 = + builder.node(NodeType.TOPIC, t -> t.publicId("urn:topic:1").resource(resource)); + Node topic2 = builder.node(NodeType.TOPIC, t -> t.publicId("urn:topic:2")); + Node node = builder.node( + NodeType.SUBJECT, + s -> s.isContext(true).publicId("urn:subject:1").child(topic1).child(topic2)); + + TestTransaction.flagForCommit(); + TestTransaction.end(); + + nodeService.publishNode(node.getPublicId(), Optional.empty(), target.getPublicId(), true, false); + + while (!changelogRepository.findAll().isEmpty()) { + executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); + } + + TestTransaction.start(); + TestTransaction.flagForCommit(); + // Move resource to another node + nodeConnectionService.disconnectParentChild(topic1, resource); + nodeConnectionService.connectParentChild(topic2, resource, builder.core(), null, Optional.empty()); + TestTransaction.end(); + + nodeService.publishNode(node.getPublicId(), Optional.empty(), target.getPublicId(), true, false); + + while (!changelogRepository.findAll().isEmpty()) { + executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); + } + + VersionContext.setCurrentVersion(versionService.schemaFromHash(target.getHash())); + Node updated = (Node) domainEntityHelperService + .getProcessedEntityByPublicId(URI.create("urn:resource:1"), false, false) + .get(); + VersionContext.setCurrentVersion(versionService.schemaFromHash(null)); + + assertNotNull(updated); + assertNotNull(updated.getContexts()); + assertEquals(1, updated.getParentConnections().size()); + assertAnyTrue( + updated.getParentConnections(), + nodeResource -> nodeResource.getParent().get().getPublicId().equals(URI.create("urn:topic:2"))); + assertAnyTrue(updated.getAllPaths(), path -> path.equals("/subject:1/topic:2/resource:1")); + } }