Search in sources :

Example 1 with Patch

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);
}
Also used : DataComplexProcessor(com.linkedin.data.transform.DataComplexProcessor) Patch(com.linkedin.data.transform.patch.Patch)

Example 2 with Patch

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()));
}
Also used : Message(com.linkedin.data.message.Message) PatchRequest(com.linkedin.restli.common.PatchRequest) DataComplexProcessor(com.linkedin.data.transform.DataComplexProcessor) ValidationResult(com.linkedin.data.schema.validation.ValidationResult) ValidationOptions(com.linkedin.data.schema.validation.ValidationOptions) DataProcessingException(com.linkedin.data.transform.DataProcessingException) RecordTemplate(com.linkedin.data.template.RecordTemplate) SimpleDataElement(com.linkedin.data.element.SimpleDataElement) Patch(com.linkedin.data.transform.patch.Patch)

Example 3 with Patch

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);
}
Also used : Group(com.linkedin.restli.examples.groups.api.Group) DataList(com.linkedin.data.DataList) DataComplexProcessor(com.linkedin.data.transform.DataComplexProcessor) Patch(com.linkedin.data.transform.patch.Patch) PatchTree(com.linkedin.data.transform.patch.request.PatchTree) DataMap(com.linkedin.data.DataMap) Test(org.testng.annotations.Test)

Example 4 with Patch

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);
}
Also used : Group(com.linkedin.restli.examples.groups.api.Group) DataComplexProcessor(com.linkedin.data.transform.DataComplexProcessor) Patch(com.linkedin.data.transform.patch.Patch) PatchTree(com.linkedin.data.transform.patch.request.PatchTree) DataMap(com.linkedin.data.DataMap) Test(org.testng.annotations.Test)

Example 5 with Patch

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);
}
Also used : Group(com.linkedin.restli.examples.groups.api.Group) DataComplexProcessor(com.linkedin.data.transform.DataComplexProcessor) Patch(com.linkedin.data.transform.patch.Patch) PatchTree(com.linkedin.data.transform.patch.request.PatchTree) DataMap(com.linkedin.data.DataMap) Test(org.testng.annotations.Test)

Aggregations

DataComplexProcessor (com.linkedin.data.transform.DataComplexProcessor)6 Patch (com.linkedin.data.transform.patch.Patch)6 DataMap (com.linkedin.data.DataMap)4 PatchTree (com.linkedin.data.transform.patch.request.PatchTree)4 Group (com.linkedin.restli.examples.groups.api.Group)4 Test (org.testng.annotations.Test)4 DataList (com.linkedin.data.DataList)1 SimpleDataElement (com.linkedin.data.element.SimpleDataElement)1 Message (com.linkedin.data.message.Message)1 ValidationOptions (com.linkedin.data.schema.validation.ValidationOptions)1 ValidationResult (com.linkedin.data.schema.validation.ValidationResult)1 RecordTemplate (com.linkedin.data.template.RecordTemplate)1 DataProcessingException (com.linkedin.data.transform.DataProcessingException)1 PatchRequest (com.linkedin.restli.common.PatchRequest)1