Enable deleting resources by lastN occurrences 57/130157/1
authorJozsef Csongvai <jozsef.csongvai@bell.ca>
Mon, 16 May 2022 15:09:06 +0000 (11:09 -0400)
committerkuldipr <kuldip.rai@amdocs.com>
Wed, 3 Aug 2022 19:29:55 +0000 (15:29 -0400)
Also enable deletion using resource-type and resource-id.

Issue-ID: CCSDK-3735
Signed-off-by: Jozsef Csongvai <jozsef.csongvai@bell.ca>
Signed-off-by: kuldipr <kuldip.rai@amdocs.com>
Change-Id: Id1b487fce97f582bd3781dfd5bcff61a8df08c5c

ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionDBService.kt
ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionRepository.kt
ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionDBServiceTest.kt
ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resource/api/DeleteResponse.kt [new file with mode: 0644]
ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resource/api/ResourceController.kt

index ed9e6d1..3041fa7 100644 (file)
@@ -26,6 +26,7 @@ import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment
 import org.slf4j.LoggerFactory
 import org.springframework.dao.EmptyResultDataAccessException
 import org.springframework.stereotype.Service
+import java.lang.IllegalArgumentException
 import java.util.UUID
 
 @Service
@@ -281,27 +282,80 @@ class ResourceResolutionDBService(private val resourceResolutionRepository: Reso
     }
 
     /**
-     * This is a deleteByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKey method to delete resources
-     * associated to a specific resolution-key
+     * This method to deletes resources associated to a specific resolution-key
      *
      * @param blueprintName name of the CBA
      * @param blueprintVersion version of the CBA
      * @param artifactName name of the artifact
      * @param resolutionKey value of the resolution-key
+     * @param lastNOccurrences number of occurrences to delete starting from the last,
+     * all occurrences will be deleted when null
+     *
+     * @return number of deleted rows
      */
-    suspend fun deleteByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKey(
+    fun deleteResources(
         blueprintName: String,
         blueprintVersion: String,
         artifactName: String,
-        resolutionKey: String
-    ) {
-        resourceResolutionRepository.deleteByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKey(
+        resolutionKey: String,
+        lastNOccurrences: Int?
+    ): Int = lastNOccurrences?.let {
+        if (lastNOccurrences < 0) {
+            throw IllegalArgumentException("last N occurrences must be a positive integer")
+        }
+        resourceResolutionRepository.deleteLastNOccurences(
             blueprintName,
             blueprintVersion,
             artifactName,
-            resolutionKey
+            resolutionKey,
+            it
         )
-    }
+    } ?: resourceResolutionRepository.deleteByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKey(
+        blueprintName,
+        blueprintVersion,
+        artifactName,
+        resolutionKey
+    )
+
+    /**
+     * This method to deletes resources associated to a specific resourceType and resourceId
+     *
+     * @param blueprintName name of the CBA
+     * @param blueprintVersion version of the CBA
+     * @param artifactName name of the artifact
+     * @param resourceType value of the resourceType
+     * @param resourceId value of the resourceId
+     * @param lastNOccurrences number of occurrences to delete starting from the last,
+     * all occurrences will be deleted when null
+     *
+     * @return number of deleted rows
+     */
+    fun deleteResources(
+        blueprintName: String,
+        blueprintVersion: String,
+        artifactName: String,
+        resourceType: String,
+        resourceId: String,
+        lastNOccurrences: Int?
+    ): Int = lastNOccurrences?.let {
+        if (lastNOccurrences < 0) {
+            throw IllegalArgumentException("last N occurrences must be a positive integer")
+        }
+        resourceResolutionRepository.deleteLastNOccurences(
+            blueprintName,
+            blueprintVersion,
+            artifactName,
+            resourceType,
+            resourceId,
+            it
+        )
+    } ?: resourceResolutionRepository.deleteByBlueprintNameAndBlueprintVersionAndArtifactNameAndResourceTypeAndResourceId(
+        blueprintName,
+        blueprintVersion,
+        artifactName,
+        resourceType,
+        resourceId
+    )
 
     suspend fun deleteResourceResolutionList(listResourceResolution: List<ResourceResolution>) = withContext(Dispatchers.IO) {
         try {
index 4b707b0..30969f1 100644 (file)
@@ -16,6 +16,7 @@
 package org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db
 
 import org.springframework.data.jpa.repository.JpaRepository
+import org.springframework.data.jpa.repository.Modifying
 import org.springframework.data.jpa.repository.Query
 import org.springframework.data.repository.query.Param
 import org.springframework.stereotype.Repository
@@ -155,9 +156,65 @@ interface ResourceResolutionRepository : JpaRepository<ResourceResolution, Strin
 
     @Transactional
     fun deleteByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKey(
-        blueprintName: String?,
-        blueprintVersion: String?,
+        blueprintName: String,
+        blueprintVersion: String,
         artifactName: String,
         resolutionKey: String
+    ): Int
+
+    @Transactional
+    fun deleteByBlueprintNameAndBlueprintVersionAndArtifactNameAndResourceTypeAndResourceId(
+        blueprintName: String,
+        blueprintVersion: String,
+        artifactName: String,
+        resourceType: String,
+        resourceId: String
+    ): Int
+
+    @Transactional
+    @Modifying
+    @Query(
+        value = """
+        DELETE FROM RESOURCE_RESOLUTION
+        WHERE resolution_key = :resolutionKey AND blueprint_name = :blueprintName
+            AND blueprint_version = :blueprintVersion AND artifact_name = :artifactName
+            AND occurrence > (
+                SELECT max(occurrence) - :lastN FROM RESOURCE_RESOLUTION
+                WHERE resolution_key = :resolutionKey AND blueprint_name = :blueprintName
+                    AND blueprint_version = :blueprintVersion AND artifact_name = :artifactName)
+    """,
+        nativeQuery = true
+    )
+    fun deleteLastNOccurences(
+        @Param("blueprintName") blueprintName: String,
+        @Param("blueprintVersion") blueprintVersion: String,
+        @Param("artifactName") artifactName: String,
+        @Param("resolutionKey") resolutionKey: String,
+        @Param("lastN") lastN: Int
+    ): Int
+
+    @Transactional
+    @Modifying
+    @Query(
+        value = """
+        DELETE FROM RESOURCE_RESOLUTION
+        WHERE resource_type = :resourceType AND resource_id = :resourceId
+            AND blueprint_name = :blueprintName
+            AND blueprint_version = :blueprintVersion AND artifact_name = :artifactName
+            AND occurrence > (
+                SELECT max(occurrence) - :lastN FROM RESOURCE_RESOLUTION
+                WHERE resource_type = :resourceType AND resource_id = :resourceId
+                    AND blueprint_name = :blueprintName
+                    AND blueprint_version = :blueprintVersion AND artifact_name = :artifactName)
+    """,
+        nativeQuery = true
     )
+    fun deleteLastNOccurences(
+        @Param("blueprintName") blueprintName: String,
+        @Param("blueprintVersion") blueprintVersion: String,
+        @Param("artifactName") artifactName: String,
+        @Param("resourceType") resourceType: String,
+        @Param("resourceId") resourceId: String,
+        @Param("lastN") lastN: Int
+    ): Int
 }
index 8d4109f..69e7a64 100644 (file)
@@ -321,15 +321,54 @@ open class ResourceResolutionDBServiceTest {
     }
 
     @Test
-    fun deleteByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKeyTest() {
+    fun deleteResourcesResolutionKeyAll() {
         every {
-            resourceResolutionRepository.deleteByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKey(any(), any(), any(), any())
-        } returns Unit
+            resourceResolutionRepository.deleteByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKey(blueprintName, blueprintVersion, artifactPrefix, resolutionKey)
+        } returns 3
         runBlocking {
-            val res = resourceResolutionDBService.deleteByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKey(
-                blueprintName, blueprintVersion, artifactPrefix, resolutionKey
+            val res = resourceResolutionDBService.deleteResources(
+                blueprintName, blueprintVersion, artifactPrefix, resolutionKey, null
             )
-            assertEquals(Unit, res)
+            assertEquals(3, res)
+        }
+    }
+
+    @Test
+    fun deleteResourcesResolutionKeyLastN() {
+        every {
+            resourceResolutionRepository.deleteLastNOccurences(blueprintName, blueprintVersion, artifactPrefix, resolutionKey, 1)
+        } returns 4
+        runBlocking {
+            val res = resourceResolutionDBService.deleteResources(
+                blueprintName, blueprintVersion, artifactPrefix, resolutionKey, 1
+            )
+            assertEquals(4, res)
+        }
+    }
+
+    @Test
+    fun deleteResourcesResourceIdAndTypeAll() {
+        every {
+            resourceResolutionRepository.deleteByBlueprintNameAndBlueprintVersionAndArtifactNameAndResourceTypeAndResourceId(blueprintName, blueprintVersion, artifactPrefix, resourceType, resourceId)
+        } returns 3
+        runBlocking {
+            val res = resourceResolutionDBService.deleteResources(
+                blueprintName, blueprintVersion, artifactPrefix, resourceType, resourceId, null
+            )
+            assertEquals(3, res)
+        }
+    }
+
+    @Test
+    fun deleteResourcesResourceIdAndTypeLastN() {
+        every {
+            resourceResolutionRepository.deleteLastNOccurences(blueprintName, blueprintVersion, artifactPrefix, resourceType, resourceId, 2)
+        } returns 6
+        runBlocking {
+            val res = resourceResolutionDBService.deleteResources(
+                blueprintName, blueprintVersion, artifactPrefix, resourceType, resourceId, 2
+            )
+            assertEquals(6, res)
         }
     }
 }
diff --git a/ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resource/api/DeleteResponse.kt b/ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resource/api/DeleteResponse.kt
new file mode 100644 (file)
index 0000000..0ad5b5e
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright © 2022 Bell Canada
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onap.ccsdk.cds.blueprintsprocessor.resource.api
+
+data class DeleteResponse(val deletedEntries: Int)
index d2b7ac3..dbfc697 100644 (file)
@@ -173,25 +173,45 @@ open class ResourceController(private var resourceResolutionDBService: ResourceR
         notes = "Delete all the resources associated to a resolution-key using blueprint metadata, artifact name and the resolution-key."
     )
     @PreAuthorize("hasRole('USER')")
-    fun deleteByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKey(
+    suspend fun deleteResolutions(
         @ApiParam(value = "Name of the CBA", required = true)
         @RequestParam(value = "bpName", required = true) bpName: String,
         @ApiParam(value = "Version of the CBA", required = true)
         @RequestParam(value = "bpVersion", required = true) bpVersion: String,
         @ApiParam(value = "Artifact name for which to retrieve a resolved resource", required = true)
-        @RequestParam(value = "artifactName", required = false, defaultValue = "") artifactName: String,
-        @ApiParam(value = "Resolution Key associated with the resolution", required = true)
-        @RequestParam(value = "resolutionKey", required = true) resolutionKey: String
+        @RequestParam(value = "artifactName", required = true, defaultValue = "") artifactName: String,
+        @ApiParam(value = "Resolution Key associated with the resolution", required = false)
+        @RequestParam(value = "resolutionKey", required = false) resolutionKey: String?,
+        @ApiParam(value = "resourceType associated with the resolution, must be used with resourceId", required = false)
+        @RequestParam(value = "resourceType", required = false) resourceType: String?,
+        @ApiParam(value = "Resolution Key associated with the resolution, must be used with resourceType", required = false)
+        @RequestParam(value = "resourceId", required = false) resourceId: String?,
+        @ApiParam(value = "Only delete last N occurrences", required = false)
+        @RequestParam(value = "lastN", required = false) lastN: Int?
     ) = runBlocking {
-        ResponseEntity.ok()
-            .body(
-                resourceResolutionDBService.deleteByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKey(
+        when {
+            resolutionKey?.isNotEmpty() == true -> resourceResolutionDBService.deleteResources(
+                bpName,
+                bpVersion,
+                artifactName,
+                resolutionKey,
+                lastN
+            )
+            resourceId?.isNotEmpty() == true && resourceType?.isNotEmpty() == true ->
+                resourceResolutionDBService.deleteResources(
                     bpName,
                     bpVersion,
                     artifactName,
-                    resolutionKey
+                    resourceType,
+                    resourceId,
+                    lastN
                 )
+            else -> throw httpProcessorException(
+                ErrorCatalogCodes.REQUEST_NOT_FOUND,
+                ResourceApiDomains.RESOURCE_API,
+                "Either use resolutionKey or resourceType + resourceId. Values cannot be blank"
             )
+        }.let { ResponseEntity.ok().body(DeleteResponse(it)) }
     }
 
     @RequestMapping(