Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.azure.cosmos.models;
import com.azure.cosmos.implementation.ImplementationBridgeHelpers;
import com.azure.cosmos.implementation.apachecommons.lang.StringUtils;
import com.azure.cosmos.implementation.patch.PatchOperation;
import com.azure.cosmos.implementation.patch.PatchOperationCore;
import com.azure.cosmos.implementation.patch.PatchOperationType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkArgument;
/**
* Grammar is a super set of this RFC: https://tools.ietf.org/html/rfc6902#section-4.1
*
* Contains a list of Patch operations to be applied on an item. It is applied in an atomic manner and we support all
* the operation in above RFC and more.
*
* This can be executed in 3 ways:
* 1. Passing this to container in container.patchItem() which requires the id of the item to be patched, partition
* key, the CosmosPatchOperations instance, any CosmosItemRequestOptions and the class type for which response will be parsed.
* 2. Add CosmosPatchOperations instance in TransactionalBatch using batch.patchItemOperation() which requires the id of the item
* to be patched, cosmos patch instance and TransactionalBatchItemRequestOptions(if-any) and follow remaining
* steps for batch for it's execution.
* 3. Create a bulk item using {@link CosmosBulkOperations#getPatchItemOperation(String, PartitionKey, CosmosPatchOperations)} which requires the id of the item to be patched,
* cosmos patch instance, partition key and {@link CosmosBulkItemRequestOptions}(if-any) and follow remaining steps to
* execute bulk operations.
*
* Let's assume this is the JSON for which we want to run patch operation.
*
* {
* a : "xyz"
* b : {
* c : "efg:
* d : 4
* e : [0, 1, 2 , 3]
* }
* }
*
*
*/
public final class CosmosPatchOperations {
private final List patchOperations;
private CosmosPatchOperations() {
this.patchOperations = Collections.synchronizedList(new ArrayList<>());
}
/**
* Initializes a new instance of {@link CosmosPatchOperations} that will contain operations to be performed on a item atomically.
*
* @return A new instance of {@link CosmosPatchOperations}.
*/
public static CosmosPatchOperations create() {
return new CosmosPatchOperations();
}
/**
* This performs one of the following functions, depending upon what the target location references:
* 1. Target location specifies an array index, a new value is inserted into the array at the specified index.
* 2. Target location specifies an object member that does not already exist, a new member is added to the object.
* 3. Target location specifies an object member that does exist, that member's value is replaced.
*
* For the above JSON, we can have something like this:
*
* CosmosPatchOperations cosmosPatch = CosmosPatchOperations.create();
* cosmosPatch.add("/b/e", 15); // will add a value to the array, so /b/e array will become [0, 1, 2, 3, 15]
* cosmosPatch.add("/a", "new value"); // will replace the value
* cosmosPatch.add("/b/e/1", 10); // will change value of the /b/e array to [0, 10, 2, 3]
*
*
* This operation is not idempotent for scenario 1 and 2. For 3rd it is as the final value will be the value
* provided here.
*
* @param The type of item to be added.
*
* @param path the operation path.
* @param value the value which will be added.
*
* @return same instance of {@link CosmosPatchOperations}
*/
public CosmosPatchOperations add(String path, T value) {
checkArgument(StringUtils.isNotEmpty(path), "path empty %s", path);
this.patchOperations.add(
new PatchOperationCore<>(
PatchOperationType.ADD,
path,
value));
return this;
}
/**
* This removes the value at the target location.
*
* For the above JSON, we can have something like this:
*
* CosmosPatchOperations cosmosPatch = CosmosPatchOperations.create();
* cosmosPatch.remove("/a");
* cosmosPatch.remove("/b/e/3"); // will remove 4th element of /b/e array
*
*
* This operation is not idempotent. Since once applied, next time it will return bad request due to path not found.
*
* @param path the operation path.
*
* @return same instance of {@link CosmosPatchOperations}
*/
public CosmosPatchOperations remove(String path) {
checkArgument(StringUtils.isNotEmpty(path), "path empty %s", path);
this.patchOperations.add(
new PatchOperationCore<>(
PatchOperationType.REMOVE,
path,
null));
return this;
}
/**
* This replaces the value at the target location with a new value.
*
* For the above JSON, we can have something like this:
*
* CosmosPatchOperations cosmosPatch = CosmosPatchOperations.create();
* cosmosPatch.replace("/a", "new value"); // will replace "xyz" to "new value"
* cosmosPatch.replace("/b/e/1", 2); // will replace 2nd element of /b/e array to 2
*
*
* This operation is idempotent as multiple call execution replace to the same value.
*
* @param The type of item to be replaced.
*
* @param path the operation path.
* @param value the value which will be replaced.
*
* @return same instance of {@link CosmosPatchOperations}
*/
public CosmosPatchOperations replace(String path, T value) {
checkArgument(StringUtils.isNotEmpty(path), "path empty %s", path);
this.patchOperations.add(
new PatchOperationCore<>(
PatchOperationType.REPLACE,
path,
value));
return this;
}
/**
* This moves the value of an object from the source to a destination.
*
* This performs the following based on different cases:
* 1. Source location points to an object as value, moves the entire object to the target location.
* 2. Target location specifies an object member that does not already exist, a new member is added to the object.
* Its value is set to the value of the source location.
*
* For the above JSON, we can have something like this:
*
* CosmosPatchOperations cosmosPatch = CosmosPatchOperations.create();
* cosmosPatch.move("/a", "/c/d"); // will move the value of "/a" to "/c/d"
* cosmosPatch.move("/b/e/1", "/d"); // will move the object at the 2nd element of the array and set it as the
* value of "/d".
* cosmosPatch.move("/b", "/c"); //It can also be used as a rename operation since now all values of "/b" will
* set as values of "/c".
*
*
* @param fromPath the source path for the operation.
* @param toPath the destination path for the operation.
*
* @return same instance of {@link CosmosPatchOperations}
*/
public CosmosPatchOperations move(String fromPath, String toPath) {
checkArgument(StringUtils.isNotEmpty(fromPath), "Source path empty %s", fromPath);
checkArgument(StringUtils.isNotEmpty(toPath), "Destination path empty %s", toPath);
this.patchOperations.add(
new PatchOperationCore<>(
PatchOperationType.MOVE,
toPath,
fromPath));
return this;
}
/**
* This sets the value at the target location with a new value.
*
* For the above JSON, we can have something like this:
*
* CosmosPatchOperations cosmosPatch = CosmosPatchOperations.create();
* cosmosPatch.set("/f", "new value"); // will add a new path "/f" and set it's value as "new value".
* cosmosPatch.set("/b/e", "bar"); // will set "/b/e" path to be "bar".
*
*
* This operation is idempotent as multiple execution will set the same value. If a new path is added, next time
* same value will be set.
*
* @param The type of item to be set.
*
* @param path the operation path.
* @param value the value which will be set.
*
* @return same instance of {@link CosmosPatchOperations}
*/
public CosmosPatchOperations set(String path, T value) {
checkArgument(StringUtils.isNotEmpty(path), "path empty %s", path);
this.patchOperations.add(
new PatchOperationCore<>(
PatchOperationType.SET,
path,
value));
return this;
}
/**
* This increment the value at the target location. It's a CRDT operator and won't cause any conflict.
*
* For the above JSON, we can have something like this:
*
* CosmosPatchOperations cosmosPatch = CosmosPatchOperations.create();
* cosmosPatch.increment("/b/d", 1); // will add 1 to "/b/d" resulting in 5.
*
*
* This is not idempotent as multiple execution will increase the value by the given increment. For multi-region
* we do support concurrent increment on different regions and the final value is a merged value combining
* all increments value.
* However if multiple increments are on the same region, it can lead to concurrency issue which can be retried.
*
* @param path the operation path.
* @param value the value which will be incremented.
*
* @return same instance of {@link CosmosPatchOperations}
*/
public CosmosPatchOperations increment(String path, long value) {
checkArgument(StringUtils.isNotEmpty(path), "path empty %s", path);
this.patchOperations.add(
new PatchOperationCore<>(
PatchOperationType.INCREMENT,
path,
value));
return this;
}
/**
* This increment the value at the target location.
*
* For the above JSON, we can have something like this:
*
* CosmosPatchOperations cosmosPatch = CosmosPatchOperations.create();
* cosmosPatch.increment("/b/d", 3.5); // will add 3.5 to "/b/d" resulting in 7.5.
*
*
* This is not idempotent as multiple execution will increase the value by the given increment. For multi-region
* we do support concurrent increment on different regions and the final value is a merged value combining
* all increments values.
* However if multiple increments are on the same region, it can lead to concurrency issue which can be retried.
*
* @param path the operation path.
* @param value the value which will be incremented.
*
* @return same instance of {@link CosmosPatchOperations}
*/
public CosmosPatchOperations increment(String path, double value) {
checkArgument(StringUtils.isNotEmpty(path), "path empty %s", path);
this.patchOperations.add(
new PatchOperationCore<>(
PatchOperationType.INCREMENT,
path,
value));
return this;
}
// NOTE returning this patchOperations means any
// modifications - like adding new entries is still
// thread-safe - but enumerating over the collection is not
// unless synchronized
List getPatchOperations() {
return this.patchOperations;
}
///////////////////////////////////////////////////////////////////////////////////////////
// the following helper/accessor only helps to access this class outside of this package.//
///////////////////////////////////////////////////////////////////////////////////////////
static void initialize() {
ImplementationBridgeHelpers.CosmosPatchOperationsHelper.setCosmosPatchOperationsAccessor(
cosmosPatchOperations -> cosmosPatchOperations.getPatchOperations()
);
}
static { initialize(); }
}