From 30eac25eb030243810cfddbb25050ba308534809 Mon Sep 17 00:00:00 2001 From: Richard Richter Date: Thu, 29 Apr 2021 15:08:23 +0200 Subject: [PATCH] repo-sqale: implemented deletion of container by value + test Solution is different then in old repo but very simple, new method RootUpdateContext#resolveContainerIdsForDeletedValues adds the IDs so the DB related code handles only "by CID" case. --- .../update/ContainerTableUpdateContext.java | 7 +-- .../update/NestedContainerUpdateContext.java | 2 +- .../repo/sqale/update/RootUpdateContext.java | 27 ++++++++- .../sqale/func/SqaleRepoModifyObjectTest.java | 59 +++++++++++++++---- 4 files changed, 76 insertions(+), 19 deletions(-) diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/ContainerTableUpdateContext.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/ContainerTableUpdateContext.java index e65089b48cd..4162e18a188 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/ContainerTableUpdateContext.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/ContainerTableUpdateContext.java @@ -16,13 +16,10 @@ import com.evolveum.midpoint.repo.sqale.qmodel.common.QContainerMapping; /** - * Update context for owned containers stored in tables. + * Update context for multi-value containers stored in separate table. * This can be owned by the root object or another container. - * TODO - this is theory, before implementation: - * Updates are collected as the modifications are processed and then executed by the root context. - * Inserts are executed immediately to allow nested inserts (e.g. container inside the container). * - * @param schema type of the object stored in the owned (child) table + * @param schema type of the container stored in the owned table * @param type of entity path for the owned (child) table * @param row type related to the {@link Q} * @param owner row type diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/NestedContainerUpdateContext.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/NestedContainerUpdateContext.java index dac0ac2f7b9..cfed67e7bf7 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/NestedContainerUpdateContext.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/NestedContainerUpdateContext.java @@ -16,7 +16,7 @@ /** * Update context for nested containers stored in the same table used by the parent context. * - * @param schema type of the object mapped by nested mapping + * @param schema type of the container mapped by the nested mapping * @param entity query type that holds the data for the mapped attributes * @param row type related to the {@link Q} */ diff --git a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/RootUpdateContext.java b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/RootUpdateContext.java index b2df16978a3..2e801abf9b8 100644 --- a/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/RootUpdateContext.java +++ b/repo/repo-sqale/src/main/java/com/evolveum/midpoint/repo/sqale/update/RootUpdateContext.java @@ -14,7 +14,7 @@ import com.querydsl.core.types.Path; import com.querydsl.sql.dml.SQLUpdateClause; -import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.equivalence.EquivalenceStrategy; import com.evolveum.midpoint.repo.sqale.ContainerValueIdGenerator; @@ -32,8 +32,7 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; /** - * TODO - * Adds execute that processes the modifications and finalizes the update of root entity. + * Root context of the update context tree, see {@link SqaleUpdateContext} for more information. * * @param schema type * @param type of entity path @@ -111,11 +110,33 @@ public QueryTableMapping mapping() { private void processModification(ItemDelta modification) throws RepositoryException, SchemaException { cidGenerator.processModification(modification); + resolveContainerIdsForDeletedValues(modification); modification.applyTo(getPrismObject()); new DelegatingItemDeltaProcessor(this).process(modification); } + private void resolveContainerIdsForDeletedValues(ItemDelta modification) { + if (!modification.isDelete()) { + return; + } + + PrismContainer container = + getPrismObject().findContainer(modification.getPath()); + if (container != null) { + for (PrismValue value : modification.getValuesToDelete()) { + //noinspection unchecked + PrismContainerValue pcv = (PrismContainerValue) value; + if (pcv.getId() == null) { + PrismContainerValue existingValue = container.findValue( + pcv, EquivalenceStrategy.REAL_VALUE_CONSIDER_DIFFERENT_IDS); + // We will set CID and use that for DB updates. + pcv.setId(existingValue.getId()); + } + } + } + } + /** * Executes all necessary SQL updates (including sub-entity inserts/deletes) * for the enclosed {@link #object}. diff --git a/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoModifyObjectTest.java b/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoModifyObjectTest.java index 84b41cb7ae5..7253b01ba32 100644 --- a/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoModifyObjectTest.java +++ b/repo/repo-sqale/src/test/java/com/evolveum/midpoint/repo/sqale/func/SqaleRepoModifyObjectTest.java @@ -1881,7 +1881,46 @@ public void test304MultipleModificationsOfExistingAssignment() } @Test - public void test305AddingAssignmentWithNewPrefilledCid() + public void test305DeleteAssignmentByContent() + throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException { + OperationResult result = createOperationResult(); + MUser originalRow = selectObjectByOid(QUser.class, user1Oid); + + given("delta deleting assignments without CID by equality for user 1"); + ObjectDelta delta = prismContext.deltaFor(UserType.class) + .item(UserType.F_ASSIGNMENT) + .delete(new AssignmentType(prismContext).order(50)) + .asObjectDelta(user1Oid); + + when("modifyObject is called"); + repositoryService.modifyObject(UserType.class, user1Oid, delta.getModifications(), result); + + then("operation is successful"); + assertThatOperationResult(result).isSuccess(); + + and("serialized form (fullObject) is updated and assignments with only order 50"); + UserType userObject = repositoryService.getObject(UserType.class, user1Oid, null, result) + .asObjectable(); + assertThat(userObject.getVersion()).isEqualTo(String.valueOf(originalRow.version + 1)); + List assignments = userObject.getAssignment(); + assertThat(assignments).hasSize(2) + .anyMatch(a -> a.getOrder().equals(47)) + // this one had order AND target ref, so it's no match + .anyMatch(ass -> ass.getOrder() == 50 && ass.getTargetRef() != null); + + and("corresponding assignment row is deleted"); + MUser row = selectObjectByOid(QUser.class, user1Oid); + assertThat(row.version).isEqualTo(originalRow.version + 1); + + QAssignment a = QAssignmentMapping.INSTANCE.defaultAlias(); + List aRows = select(a, a.ownerOid.eq(UUID.fromString(user1Oid))); + assertThat(aRows).hasSize(2) + .anyMatch(aRow -> aRow.orderValue.equals(47)) + .anyMatch(ass -> ass.orderValue == 50 && ass.targetRefTargetOid != null); + } + + @Test + public void test310AddingAssignmentWithNewPrefilledCid() throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException { OperationResult result = createOperationResult(); MUser originalRow = selectObjectByOid(QUser.class, user1Oid); @@ -1905,7 +1944,7 @@ public void test305AddingAssignmentWithNewPrefilledCid() .asObjectable(); assertThat(userObject.getVersion()).isEqualTo(String.valueOf(originalRow.version + 1)); List assignments = userObject.getAssignment(); - assertThat(assignments).hasSize(4) + assertThat(assignments).hasSize(3) .anyMatch(a -> a.getId().equals(originalRow.containerIdSeq)); and("new assignment row is created"); @@ -1915,13 +1954,13 @@ public void test305AddingAssignmentWithNewPrefilledCid() QAssignment a = QAssignmentMapping.INSTANCE.defaultAlias(); List aRows = select(a, a.ownerOid.eq(UUID.fromString(user1Oid))); - assertThat(aRows).hasSize(4) + assertThat(aRows).hasSize(3) .anyMatch(aRow -> aRow.cid.equals(originalRow.containerIdSeq) && aRow.orderValue == 1); } @Test - public void test306DeleteAssignmentByCid() + public void test311DeleteAssignmentByCid() throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException { OperationResult result = createOperationResult(); MUser originalRow = selectObjectByOid(QUser.class, user1Oid); @@ -1944,7 +1983,7 @@ public void test306DeleteAssignmentByCid() .asObjectable(); assertThat(userObject.getVersion()).isEqualTo(String.valueOf(originalRow.version + 1)); List assignments = userObject.getAssignment(); - assertThat(assignments).hasSize(3) + assertThat(assignments).hasSize(2) .noneMatch(a -> a.getId().equals(originalRow.containerIdSeq - 1)); and("new assignment row is created"); @@ -1954,12 +1993,12 @@ public void test306DeleteAssignmentByCid() QAssignment a = QAssignmentMapping.INSTANCE.defaultAlias(); List aRows = select(a, a.ownerOid.eq(UUID.fromString(user1Oid))); - assertThat(aRows).hasSize(3) + assertThat(aRows).hasSize(2) .noneMatch(aRow -> aRow.cid.equals(originalRow.containerIdSeq - 1)); } @Test - public void test307AddingAssignmentWithUsedBytFreeCid() + public void test312AddingAssignmentWithUsedBytFreeCid() throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException { OperationResult result = createOperationResult(); MUser originalRow = selectObjectByOid(QUser.class, user1Oid); @@ -1984,7 +2023,7 @@ public void test307AddingAssignmentWithUsedBytFreeCid() .asObjectable(); assertThat(userObject.getVersion()).isEqualTo(String.valueOf(originalRow.version + 1)); List assignments = userObject.getAssignment(); - assertThat(assignments).hasSize(4) + assertThat(assignments).hasSize(3) .anyMatch(a -> a.getId().equals(originalRow.containerIdSeq - 1)); and("new assignment row is created"); @@ -1994,7 +2033,7 @@ public void test307AddingAssignmentWithUsedBytFreeCid() QAssignment a = QAssignmentMapping.INSTANCE.defaultAlias(); List aRows = select(a, a.ownerOid.eq(UUID.fromString(user1Oid))); - assertThat(aRows).hasSize(4) + assertThat(aRows).hasSize(3) .anyMatch(aRow -> aRow.cid.equals(originalRow.containerIdSeq - 1) && aRow.orderValue == 1); } @@ -2002,7 +2041,7 @@ public void test307AddingAssignmentWithUsedBytFreeCid() // TODO delete by pattern - as per ItemImpl.remove(V, EquivalenceStrategy) @Test - public void test309DeleteAllAssignments() + public void test319DeleteAllAssignments() throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException { OperationResult result = createOperationResult(); MUser originalRow = selectObjectByOid(QUser.class, user1Oid);