package com.redhat.lightblue.client;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ContainerNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.redhat.lightblue.client.util.JSON;
/**
* Update expression
*
* Usage:
* <pre>
* Update.set("x",1).more("y","value").more("x",Literal.value(new Date())).more(Literal.emptyObject());
* Update.unset("x").more("y").more("z");
* Update.addValue("x",Literal.value(1)).more("y",Literal.value(-1)).more("z",new ValueOf("w"));
* Update.append("array",Literal.emptyObject());
* Update.insert("array",Literal.emptyArray());
* Update.forEach("array",Query..., Update.set(...) )
* Update.forEach("array",Update.ALL, Update.set(...) )
* Update.forEach("array",Query..., Update.REMOVE)
* Update.update(Update.set("x",1),Update.unset("y"), Update.addValue("z",Literal.value(1)));
* </pre>
*/
public class Update extends Expression implements ForEachUpdate {
public interface AddLiteral extends JsonObj {
}
public interface AppendInsertLiteral extends JsonObj {
}
public interface SetLiteral extends JsonObj {
}
public interface UpdateQuery extends JsonObj {
}
public static final UpdateQuery ALL = new All();
public static final ForEachUpdate REMOVE = new Remove();
public static class All extends ExpressionPart implements UpdateQuery {
public All() {
super(JsonNodeFactory.instance.textNode("$all"));
}
}
public static class Remove extends ExpressionPart implements ForEachUpdate {
public Remove() {
super(JsonNodeFactory.instance.textNode("$remove"));
}
}
/**
* Represents a $set expression
*/
public static class Set extends Update {
public Set() {
super(JsonNodeFactory.instance.objectNode());
}
public Set(ObjectNode node) {
super(node);
}
/**
* Add a new field/value to $set
*/
public Set more(String field, JsonNode value) {
JsonNode x = ((ObjectNode) node).get("$set");
if (x == null) {
x = JsonNodeFactory.instance.objectNode();
((ObjectNode) node).set("$set", x);
}
((ObjectNode) x).set(field, value);
return this;
}
/**
* Add a new field/value to $set
*/
public Set more(String field, SetLiteral value) {
return more(field, value.toJson());
}
public Set more(String field, int i) {
return more(field, Literal.value(i));
}
public Set more(String field, long i) {
return more(field, Literal.value(i));
}
public Set more(String field, String i) {
return more(field, Literal.value(i));
}
public Set more(String field, boolean i) {
return more(field, Literal.value(i));
}
public Set more(String field, Date date) {
return more(field, Literal.value(date));
}
}
/**
* Represents an $add expression
*/
public static class Add extends Update {
public Add() {
super(JsonNodeFactory.instance.objectNode());
}
public Add(ObjectNode node) {
super(node);
}
/**
* Adds a new field/value to add
*/
public Add more(String field, JsonNode value) {
JsonNode x = ((ObjectNode) node).get("$add");
if (x == null) {
x = JsonNodeFactory.instance.objectNode();
((ObjectNode) node).set("$add", x);
}
((ObjectNode) x).set(field, value);
return this;
}
/**
* Adds a new field/value to add
*/
public Add more(String field, AddLiteral value) {
return more(field, value.toJson());
}
}
/**
* Represents an $append or $insert expression
*/
public static class AppendInsert extends Update {
public AppendInsert(String op, String field) {
super(JsonNodeFactory.instance.objectNode());
ObjectNode x = JsonNodeFactory.instance.objectNode();
x.set(field, JsonNodeFactory.instance.arrayNode());
((ObjectNode) node).set(op, x);
}
/**
* Adds a new value to append/insert
*/
public AppendInsert more(JsonNode value) {
((ArrayNode) ((ObjectNode) ((ObjectNode) node).elements().next()).elements().next()).add(value);
return this;
}
/**
* Adds a new value to append/insert
*/
public AppendInsert more(AppendInsertLiteral value) {
return more(value.toJson());
}
}
/**
* Represents an $unset expression
*/
public static class Unset extends Update {
public Unset() {
super(JsonNodeFactory.instance.objectNode());
}
public Unset(ObjectNode node) {
super(node);
}
/**
* Adds a new field to unset
*/
public Unset more(String field) {
JsonNode x = ((ObjectNode) node).get("$unset");
if (x == null) {
x = JsonNodeFactory.instance.textNode(field);
((ObjectNode) node).set("$unset", x);
} else {
ArrayNode arr;
if (!(x instanceof ArrayNode)) {
arr = JsonNodeFactory.instance.arrayNode();
arr.add(x);
((ObjectNode) node).set("$unset", arr);
} else {
arr = (ArrayNode) x;
}
arr.add(JsonNodeFactory.instance.textNode(field));
}
return this;
}
}
/**
* Creates an update node with the given array or object node
*/
public Update(ContainerNode node) {
super(node);
}
private Update(boolean arrayNode) {
super(arrayNode);
}
public static Update update(ContainerNode node) {
return new Update(node);
}
/**
* Creates an update like so: $set: toJson(pojo)
*
* @param pojo
* @return
*/
public static Update updatePojo(Object pojo) {
Objects.requireNonNull(pojo, "Pojo cannot be null");
ObjectNode set = JsonNodeFactory.instance.objectNode();
JsonNode pojoAsJson = JSON.toJsonNode(pojo);
if (!(pojoAsJson instanceof ObjectNode)) {
throw new IllegalArgumentException(pojo+" is not a pojo!");
}
set.set("$set", pojoAsJson);
return new Update(set);
}
/**
* <pre>
* [ update,... ]
* </pre>
*/
public static Update update(Update... update) {
if (update.length == 1) {
return update[0];
} else {
Update x = new Update(true);
for (Update u : update) {
((ArrayNode) x.node).add(u.toJson());
}
return x;
}
}
public static Update update(List<? extends Update> update) {
if (update.size() == 1) {
return update.get(0);
} else {
Update x = new Update(true);
for (Update u : update) {
((ArrayNode) x.node).add(u.toJson());
}
return x;
}
}
/**
* <pre>
* { $set : { field: l } }
* </pre>
*/
public static Set set(String field, SetLiteral l) {
return new Set().more(field, l);
}
public static Set set(String field, int i) {
return new Set().more(field, Literal.value(i));
}
public static Set set(String field, long i) {
return new Set().more(field, Literal.value(i));
}
public static Set set(String field, String i) {
return new Set().more(field, Literal.value(i));
}
public static Set set(String field, boolean i) {
return new Set().more(field, Literal.value(i));
}
public static Set set(String field, Date date) {
return new Set().more(field, Literal.value(date));
}
/**
* <pre>
* { $unset : [ fields... ]
* </pre>
*/
public static Unset unset(String... fields) {
Unset x = new Unset();
for (String f : fields) {
x.more(f);
}
return x;
}
/**
* <pre>
* { $add : { field: literal } }
* </pre>
*/
public static Add addValue(String field, AddLiteral literal) {
return new Add().more(field, literal);
}
/**
* <pre>
* { $append : { path: value } }
* </pre>
*/
public static AppendInsert append(String field, AppendInsertLiteral value) {
return new AppendInsert("$append", field).more(value);
}
/**
* <pre>
* { $insert : { path: value } }
* </pre>
*/
public static AppendInsert insert(String field, AppendInsertLiteral value) {
return new AppendInsert("$insert", field).more(value);
}
/**
* <pre>
* { $foreach : { field: { q }, $update: u } }
* </pre>
*/
public static Update forEach(String field,
UpdateQuery q,
ForEachUpdate u) {
Update x = new Update(false);
ObjectNode fe = JsonNodeFactory.instance.objectNode();
fe.set(field, q.toJson());
fe.set("$update", u.toJson());
((ObjectNode) x.node).set("$foreach", fe);
return x;
}
}