Add tests and fixes for PATCH scenarios
diff --git a/scim-core/src/main/java/org/apache/directory/scim/core/repository/PatchHandlerImpl.java b/scim-core/src/main/java/org/apache/directory/scim/core/repository/PatchHandlerImpl.java
index aa10e27..80b7c32 100644
--- a/scim-core/src/main/java/org/apache/directory/scim/core/repository/PatchHandlerImpl.java
+++ b/scim-core/src/main/java/org/apache/directory/scim/core/repository/PatchHandlerImpl.java
@@ -32,6 +32,7 @@
import java.util.*;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
@SuppressWarnings("unchecked")
@Slf4j
@@ -84,25 +85,43 @@
Schema baseSchema = this.schemaRegistry.getSchema(source.getBaseUrn());
Attribute attribute = baseSchema.getAttribute(attributeReference.getAttributeName());
- Object attributeObject = attribute.getAccessor().get(source);
- if (attributeObject == null && patchOperation.getOperation().equals(PatchOperation.Type.REPLACE)) {
+ Schema.AttributeAccessor attributeAccessor = attribute.getAccessor();
+ Object attributeObject = attributeAccessor.get(source);
+ if (attributeObject == null && PatchOperation.Type.REPLACE.equals(patchOperation.getOperation())) {
throw new IllegalArgumentException("Cannot apply patch replace on missing property: " + attribute.getName());
}
- if (valuePathExpression.getAttributeExpression() != null && attributeObject instanceof Collection<?>) {
- // apply expression filter
+ // Add item to list
+ if (PatchOperation.Type.ADD.equals(patchOperation.getOperation()) && attributeObject instanceof List<?>) {
+ List<Object> newItems = new ArrayList<>((Collection<Object>) attributeObject);
+ newItems.add(patchOperation.getValue());
+ attributeAccessor.set(source, newItems);
+ } else if (valuePathExpression.getAttributeExpression() != null && attributeObject instanceof List<?>) {
+ // change list
+ Predicate<Object> pred = FilterExpressions.inMemory(valuePathExpression.getAttributeExpression(), baseSchema);
+ String subAttributeName = valuePathExpression.getAttributePath().getSubAttributeName();
+
Collection<Object> items = (Collection<Object>) attributeObject;
- items.forEach(item -> {
- Predicate<Object> pred = FilterExpressions.inMemory(valuePathExpression.getAttributeExpression(), baseSchema);
- if (pred.test(item)) {
- String subAttributeName = valuePathExpression.getAttributePath().getSubAttributeName();
- Schema.AttributeAccessor subAttributeAccessor = attribute.getAttribute(subAttributeName).getAccessor();
- subAttributeAccessor.set(item, patchOperation.getValue());
- }
- });
+
+ // remove item from list
+ if (PatchOperation.Type.REMOVE.equals(patchOperation.getOperation()) && subAttributeName == null) {
+ Object newItems = items.stream()
+ .filter(item -> !pred.test(item))
+ .collect(Collectors.toList());
+ attributeAccessor.set(source, newItems);
+ } else {
+ // update item in list
+ items.stream()
+ .filter(pred)
+ .findFirst()
+ .ifPresent(item -> {
+ Schema.AttributeAccessor subAttributeAccessor = attribute.getAttribute(subAttributeName).getAccessor();
+ subAttributeAccessor.set(item, patchOperation.getValue());
+ });
+ }
} else {
- // no filter expression, just set the value
- attribute.getAccessor().set(source, patchOperation.getValue());
+ // just set the value
+ attributeAccessor.set(source, patchOperation.getValue());
}
return source;
}
diff --git a/scim-core/src/test/java/org/apache/directory/scim/core/repository/PatchHandlerTest.java b/scim-core/src/test/java/org/apache/directory/scim/core/repository/PatchHandlerTest.java
index 4d8d8d6..7de8b8c 100644
--- a/scim-core/src/test/java/org/apache/directory/scim/core/repository/PatchHandlerTest.java
+++ b/scim-core/src/test/java/org/apache/directory/scim/core/repository/PatchHandlerTest.java
@@ -78,6 +78,46 @@
));
}
+ @Test
+ public void deleteItemWithFilter() throws FilterParseException {
+ PatchOperation op = new PatchOperation();
+ op.setOperation(PatchOperation.Type.REMOVE);
+ op.setPath(new PatchOperationPath("emails[type EQ \"home\"]"));
+ ScimUser updatedUser = performPatch(op);
+ List<Email> emails = updatedUser.getEmails();
+ assertThat(emails).isEqualTo(List.of(
+ new Email()
+ .setPrimary(true)
+ .setType("work")
+ .setValue("work@example.com")
+ ));
+ }
+
+ @Test
+ public void addItem() throws FilterParseException {
+ PatchOperation op = new PatchOperation();
+ op.setOperation(PatchOperation.Type.ADD);
+ op.setPath(new PatchOperationPath("emails"));
+ op.setValue(new Email()
+ .setType("other")
+ .setValue("other@example.com"));
+
+ ScimUser updatedUser = performPatch(op);
+ List<Email> emails = updatedUser.getEmails();
+ assertThat(emails).isEqualTo(List.of(
+ new Email()
+ .setPrimary(true)
+ .setType("work")
+ .setValue("work@example.com"),
+ new Email()
+ .setType("home")
+ .setValue("home@example.com"),
+ new Email()
+ .setType("other")
+ .setValue("other@example.com")
+ ));
+ }
+
private ScimUser performPatch(PatchOperation op) {
when(mockSchemaRegistry.getSchema(ScimUser.SCHEMA_URI)).thenReturn(Schemas.schemaFor(ScimUser.class));
PatchHandler patchHandler = new PatchHandlerImpl(mockSchemaRegistry);