/*
* Copyright 2011 VZ Netzwerke Ltd
* Copyright 2014 devbliss GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mongojack;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.mongojack.internal.update.ComplexUpdateOperationValue;
import org.mongojack.internal.update.MultiUpdateOperationValue;
import org.mongojack.internal.update.SingleUpdateOperationValue;
import org.mongojack.internal.update.UpdateOperationValue;
import org.mongojack.internal.util.SerializationUtils;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* A database update. This can be used to build queries using the MongoDB
* modifier operations. It also will do serialisation of values, however it
* won't honour any custom serialisers specified on the fields that those values
* are being set.
*
* @author James Roper
* @since 1.1
*/
public class DBUpdate {
/**
* Increment the given field atomically by one
*
* @param field
* The field to increment
* @return this object
*/
public static Builder inc(String field) {
return inc(field, 1);
}
/**
* Increment the given field atomically by the given value
*
* @param field
* The field to increment
* @param by
* The value to increment by
* @return this object
*/
public static Builder inc(String field, int by) {
return new Builder().inc(field, by);
}
/**
* Set the given field (can be multiple levels deep) to the given value
* atomically
*
* @param field
* The field to set
* @param value
* The value to set it to
* @return this object
*/
public static Builder set(String field, Object value) {
return new Builder().set(field, value);
}
/**
* Unset the given field atomically
*
* @param field
* The field to unset
* @return this object
*/
public static Builder unset(String field) {
return new Builder().unset(field);
}
/**
* Add the given value to the array value at the specified field atomically
*
* @param field
* The field to add the value to
* @param value
* The value to add
* @return this object
*/
public static Builder push(String field, Object value) {
return new Builder().push(field, value);
}
/**
* Add all of the given values to the array value at the specified field
* atomically
*
* @param field
* The field to add the values to
* @param values
* The values to add
* @return this object
*/
public static Builder pushAll(String field, Object... values) {
return new Builder().pushAll(field, values);
}
/**
* Add all of the given values to the array value at the specified field
* atomically
*
* @param field
* The field to add the values to
* @param values
* The values to add
* @return this object
*/
public static Builder pushAll(String field, List<?> values) {
return new Builder().pushAll(field, values);
}
/**
* Add the given value to the array value if it doesn't already exist in the
* specified field atomically
*
* @param field
* The field to add the value to
* @param value
* The value to add
* @return this object
*/
public static Builder addToSet(String field, Object value) {
return new Builder().addToSet(field, value);
}
/**
* Add the given values to the array value if they don't already exist in
* the specified field atomically
*
* @param field
* The field to add the values to
* @param values
* The values to add
* @return this object
*/
public static Builder addToSet(String field, Object... values) {
return new Builder().addToSet(field, values);
}
/**
* Add the given values to the array value if they don't already exist in
* the specified field atomically
*
* @param field
* The field to add the values to
* @param values
* The values to add
* @return this object
*/
public static Builder addToSet(String field, List<?> values) {
return new Builder().addToSet(field, values);
}
/**
* Remove the first value from the array specified by field atomically
*
* @param field
* The field to remove the value from
* @return this object
*/
public static Builder popFirst(String field) {
return new Builder().popFirst(field);
}
/**
* Remove the last value from the array specified by field atomically
*
* @param field
* The field to remove the value from
* @return this object
*/
public static Builder popLast(String field) {
return new Builder().popLast(field);
}
/**
* Remove all occurances of value from the array at field
*
* @param field
* The field to remove the value from
* @param value
* The value to remove. This may be another query.
* @return this object
*/
public static Builder pull(String field, Object value) {
return new Builder().pull(field, value);
}
/**
* Remove all occurances of the values from the array at field
*
* @param field
* The field to remove the values from
* @param values
* The values to remove
* @return this object
*/
public static Builder pullAll(String field, Object... values) {
return new Builder().pullAll(field, values);
}
/**
* Remove all occurances of the values from the array at field
*
* @param field
* The field to remove the values from
* @param values
* The values to remove
* @return this object
*/
public static Builder pullAll(String field, List<?> values) {
return new Builder().pullAll(field, values);
}
/**
* Rename the given field to the new field name
*
* @param oldFieldName
* The old field name
* @param newFieldName
* The new field name
* @return this object
*/
public static Builder rename(String oldFieldName, String newFieldName) {
return new Builder().rename(oldFieldName, newFieldName);
}
/**
* Perform a bit operation on the given field
*
* @param field
* The field to perform the operation on
* @param operation
* The operation to perform
* @param value
* The value
* @return this object
*/
public static Builder bit(String field, String operation, int value) {
return new Builder().bit(field, operation, value);
}
/**
* Perform two bit operations on the given field
*
* @param field
* The field to perform the operations on
* @param operation1
* The first operation to perform
* @param value1
* The first value
* @param operation2
* The second operation to perform
* @param value2
* The second value
* @return this object
*/
public static Builder bit(String field, String operation1, int value1,
String operation2, int value2) {
return new Builder().bit(field, operation1, value1, operation2, value2);
}
/**
* Perform a bitwise and on the given field
*
* @param field
* The field to perform the and on
* @param value
* The value
* @return this object
*/
public static Builder bitwiseAnd(String field, int value) {
return new Builder().bitwiseAnd(field, value);
}
/**
* Perform a bitwise or on the given field
*
* @param field
* The field to perform the or on
* @param value
* The value
* @return this object
*/
public static Builder bitwiseOr(String field, int value) {
return new Builder().bitwiseOr(field, value);
}
/**
* The builder
*/
public static class Builder {
private final Map<String, Map<String, UpdateOperationValue>> update = new HashMap<String, Map<String, UpdateOperationValue>>();
/**
* Increment the given field atomically by one
*
* @param field
* The field to increment
* @return this object
*/
public Builder inc(String field) {
return inc(field, 1);
}
/**
* Increment the given field atomically by the given value
*
* @param field
* The field to increment
* @param by
* The value to increment by
* @return this object
*/
public Builder inc(String field, int by) {
return addOperation("$inc", field, new SingleUpdateOperationValue(
false, false, by));
}
/**
* Set the given field (can be multiple levels deep) to the given value
* atomically
*
* @param field
* The field to set
* @param value
* The value to set it to
* @return this object
*/
public Builder set(String field, Object value) {
return addOperation("$set", field, new SingleUpdateOperationValue(
false, true, value));
}
/**
* Unset the given field atomically
*
* @param field
* The field to unset
* @return this object
*/
public Builder unset(String field) {
return addOperation("$unset", field,
new SingleUpdateOperationValue(false, false, 1));
}
/**
* Add the given value to the array value at the specified field
* atomically
*
* @param field
* The field to add the value to
* @param value
* The value to add
* @return this object
*/
public Builder push(String field, Object value) {
return addOperation("$push", field, new SingleUpdateOperationValue(
true, true, value));
}
/**
* Add all of the given values to the array value at the specified field
* atomically
*
* @param field
* The field to add the values to
* @param values
* The values to add
* @return this object
*/
public Builder pushAll(String field, Object... values) {
return addOperation("$pushAll", field,
new MultiUpdateOperationValue(true, true, values));
}
/**
* Add all of the given values to the array value at the specified field
* atomically
*
* @param field
* The field to add the values to
* @param values
* The values to add
* @return this object
*/
public Builder pushAll(String field, List<?> values) {
return addOperation("$pushAll", field,
new MultiUpdateOperationValue(true, true, values));
}
/**
* Add the given value to the array value if it doesn't already exist in
* the specified field atomically
*
* @param field
* The field to add the value to
* @param value
* The value to add
* @return this object
*/
public Builder addToSet(String field, Object value) {
return addOperation("$addToSet", field,
new SingleUpdateOperationValue(true, true, value));
}
/**
* Add the given values to the array value if they don't already exist
* in the specified field atomically
*
* @param field
* The field to add the values to
* @param values
* The values to add
* @return this object
*/
public Builder addToSet(String field, Object... values) {
return addOperation("$addToSet", field,
new MultiUpdateOperationValue(true, true, values));
}
/**
* Add the given values to the array value if they don't already exist
* in the specified field atomically
*
* @param field
* The field to add the values to
* @param values
* The values to add
* @return this object
*/
public Builder addToSet(String field, List<?> values) {
return addOperation("$addToSet", field,
new MultiUpdateOperationValue(true, true, values));
}
/**
* Remove the first value from the array specified by field atomically
*
* @param field
* The field to remove the value from
* @return this object
*/
public Builder popFirst(String field) {
return addOperation("$pop", field, new SingleUpdateOperationValue(
true, false, -1));
}
/**
* Remove the last value from the array specified by field atomically
*
* @param field
* The field to remove the value from
* @return this object
*/
public Builder popLast(String field) {
return addOperation("$pop", field, new SingleUpdateOperationValue(
true, false, 1));
}
/**
* Remove all occurances of value from the array at field
*
* @param field
* The field to remove the value from
* @param value
* The value to remove. This may be another query.
* @return this object
*/
public Builder pull(String field, Object value) {
return addOperation("$pull", field, new SingleUpdateOperationValue(
true, true, value));
}
/**
* Remove all occurances of the values from the array at field
*
* @param field
* The field to remove the values from
* @param values
* The values to remove
* @return this object
*/
public Builder pullAll(String field, Object... values) {
return addOperation("$pullAll", field,
new MultiUpdateOperationValue(true, true, values));
}
/**
* Remove all occurances of the values from the array at field
*
* @param field
* The field to remove the values from
* @param values
* The values to remove
* @return this object
*/
public Builder pullAll(String field, List<?> values) {
return addOperation("$pullAll", field,
new MultiUpdateOperationValue(true, true, values));
}
/**
* Rename the given field to the new field name
*
* @param oldFieldName
* The old field name
* @param newFieldName
* The new field name
* @return this object
*/
public Builder rename(String oldFieldName, String newFieldName) {
return addOperation("$rename", oldFieldName,
new SingleUpdateOperationValue(false, false, newFieldName));
}
/**
* Perform a bit operation on the given field
*
* @param field
* The field to perform the operation on
* @param operation
* The operation to perform
* @param value
* The value
* @return this object
*/
public Builder bit(String field, String operation, int value) {
return addOperation("$bit", field, new ComplexUpdateOperationValue(
new BasicDBObject(operation, value)));
}
/**
* Perform two bit operations on the given field
*
* @param field
* The field to perform the operations on
* @param operation1
* The first operation to perform
* @param value1
* The first value
* @param operation2
* The second operation to perform
* @param value2
* The second value
* @return this object
*/
public Builder bit(String field, String operation1, int value1,
String operation2, int value2) {
return addOperation("$bit", field,
new ComplexUpdateOperationValue(new BasicDBObject(
operation1, value1).append(operation2, value2)));
}
/**
* Perform a bitwise and on the given field
*
* @param field
* The field to perform the and on
* @param value
* The value
* @return this object
*/
public Builder bitwiseAnd(String field, int value) {
return bit(field, "and", value);
}
/**
* Perform a bitwise or on the given field
*
* @param field
* The field to perform the or on
* @param value
* The value
* @return this object
*/
public Builder bitwiseOr(String field, int value) {
return bit(field, "or", value);
}
/**
* Add a raw operation. This may be useful in case of MongoDB adding new
* features that aren't yet available through this interface, or if
* something has been left out. Note that no serialisation will be
* attempted of the values.
*
* @param op
* The operation
* @param field
* The field to set the value on
* @param value
* The value to set
* @return this object
*/
public Builder addRawOperation(String op, String field, Object value) {
return addOperation(op, field, new SingleUpdateOperationValue(
false, false, value));
}
/**
* Add an operation to the update
*
* @param modifier
* The modifier of the operation
* @param field
* The field to set
* @param value
* The value to modify it with.
* @return this object
*/
public Builder addOperation(String modifier, String field,
UpdateOperationValue value) {
if (update.containsKey(modifier)) {
Map<String, UpdateOperationValue> existing = update
.get(modifier);
existing.put(field, value);
} else {
Map<String, UpdateOperationValue> newMap = new HashMap<String, UpdateOperationValue>();
newMap.put(field, value);
update.put(modifier, newMap);
}
return this;
}
/**
* Serialise the values of the query and get them
*
* @param objectMapper
* The object mapper to use to serialise values
* @return The object
*/
public DBObject serialiseAndGet(ObjectMapper objectMapper,
JavaType javaType) {
return SerializationUtils.serializeDBUpdate(update, objectMapper,
javaType);
}
/**
* Checks if the update is empty
*
* @return true if the update is empty
*/
public boolean isEmpty() {
return update.isEmpty();
}
}
}