use of com.linkedin.data.transform.patch.Patch in project rest.li by linkedin.
the class PatchApplier method applyPatch.
public static <T extends RecordTemplate> void applyPatch(T original, PatchRequest<T> patch) throws DataProcessingException {
DataComplexProcessor processor = new DataComplexProcessor(new Patch(), patch.getPatchDocument(), original.data());
processor.run(false);
}
use of com.linkedin.data.transform.patch.Patch in project rest.li by linkedin.
the class RestLiDataValidator method validatePatch.
/**
* Checks that if the patch is applied to a valid entity, the modified entity will also be valid.
* This method
* (1) Checks that required/ReadOnly/CreateOnly fields are not deleted.
* (2) Checks that new values for record templates contain all required fields.
* (3) Applies the patch to an empty entity and validates the entity for custom validation rules
* and Rest.li annotations (Allows required fields to be absent by using {@link RequiredMode#IGNORE},
* because a patch does not necessarily contain all fields).
*
* NOTE: Updating a part of an array is not supported. So if the array contains a required field that is
* readonly or createonly, the field cannot be present (no partial updates on readonly/createonly)
* but cannot be absent either (no missing required fields). This means the array cannot be changed by a
* partial update request. This is something that should be fixed.
*
* @param patchRequest the patch
* @return the final validation result
*/
private ValidationResult validatePatch(PatchRequest<?> patchRequest) {
// Instantiate an empty entity.
RecordTemplate entity;
try {
entity = _valueClass.newInstance();
} catch (InstantiationException e) {
return validationResultWithErrorMessage(INSTANTIATION_ERROR);
} catch (IllegalAccessException e) {
return validationResultWithErrorMessage(ILLEGAL_ACCESS_ERROR);
}
// Apply the patch to the entity and get paths that $set and $delete operations were performed on.
@SuppressWarnings("unchecked") PatchRequest<RecordTemplate> patch = (PatchRequest<RecordTemplate>) patchRequest;
DataComplexProcessor processor = new DataComplexProcessor(new Patch(true), patch.getPatchDocument(), entity.data());
MessageList<Message> messages;
try {
messages = processor.runDataProcessing(false);
} catch (DataProcessingException e) {
return validationResultWithErrorMessage("Error while applying patch: " + e.getMessage());
}
ValidationErrorResult checkDeleteResult = new ValidationErrorResult();
checkDeletesAreValid(entity.schema(), messages, checkDeleteResult);
if (!checkDeleteResult.isValid()) {
return checkDeleteResult;
}
ValidationResult checkSetResult = checkNewRecordsAreNotMissingFields(entity, messages);
if (checkSetResult != null) {
return checkSetResult;
}
// It's okay if required fields are absent in a partial update request, so use ignore mode.
return ValidateDataAgainstSchema.validate(new SimpleDataElement(entity.data(), entity.schema()), new ValidationOptions(RequiredMode.IGNORE), new DataValidator(entity.schema()));
}
use of com.linkedin.data.transform.patch.Patch in project rest.li by linkedin.
the class TestPatchGeneration method testRoundtripDeleteField.
@Test
void testRoundtripDeleteField() throws Exception {
Group g1 = new Group();
g1.setId(17);
g1.setDescription("Some description");
Group g2 = new Group(g1.data().copy());
g2.removeDescription();
PatchTree update = PatchCreator.diff(g1, g2);
//"{$delete=[description]}"
final DataMap deleteMap = new DataMap();
final DataList descriptionList = new DataList();
descriptionList.add("description");
deleteMap.put(PatchConstants.DELETE_COMMAND, descriptionList);
assertEquals(update.getDataMap(), deleteMap, "PatchTree DataMap should be correct");
assertFalse(g1.equals(g2));
DataComplexProcessor processor = new DataComplexProcessor(new Patch(), update.getDataMap(), g1.data());
processor.run(false);
assertEquals(g1, g2);
}
use of com.linkedin.data.transform.patch.Patch in project rest.li by linkedin.
the class TestPatchGeneration method testRoundtripModifyEscapedField.
@Test(groups = { TestConstants.TESTNG_GROUP_KNOWN_ISSUE })
void testRoundtripModifyEscapedField() throws Exception {
Group g1 = new Group();
g1.data().put("$foo", new DataMap());
Group g2 = new Group(g1.data().copy());
((DataMap) g2.data().get("$foo")).put("bar", 42);
PatchTree update = PatchCreator.diff(g1, g2);
//"{$$foo={$set={bar=42}}}"
final DataMap setMap = new DataMap();
final DataMap barMap = new DataMap();
barMap.put("bar", 42);
setMap.put(PatchConstants.SET_COMMAND, barMap);
final DataMap fooMap = new DataMap();
fooMap.put("$$foo", setMap);
assertEquals(update.getDataMap(), fooMap, "PatchTree DataMap must be correct");
assertFalse(g1.equals(g2));
DataComplexProcessor processor = new DataComplexProcessor(new Patch(), update.getDataMap(), g1.data());
processor.run(false);
assertEquals(g1, g2);
}
use of com.linkedin.data.transform.patch.Patch in project rest.li by linkedin.
the class TestPatchGeneration method testRoundtripAddFields.
@Test
void testRoundtripAddFields() throws Exception {
Group g1 = new Group();
g1.setId(17);
g1.setDescription("Some description");
Group g2 = new Group(g1.data().copy());
g2.setId(42);
g2.setName("Some Group");
PatchTree update = PatchCreator.diff(g1, g2);
//"{$set={id=42, name=Some Group}}"
final DataMap setMap = new DataMap();
final DataMap idNameMap = new DataMap();
idNameMap.put("id", 42);
idNameMap.put("name", "Some Group");
setMap.put(PatchConstants.SET_COMMAND, idNameMap);
assertEquals(update.getDataMap(), setMap, "PatchTree DataMap should be correct");
assertFalse(g1.equals(g2));
DataComplexProcessor processor = new DataComplexProcessor(new Patch(), update.getDataMap(), g1.data());
processor.run(false);
assertEquals(g1, g2);
}
Aggregations