com.avaje.ebeaninternal.server.querydefn.OrmUpdateProperties Maven / Gradle / Ivy
package com.avaje.ebeaninternal.server.querydefn;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.server.deploy.DeployParser;
import com.avaje.ebeaninternal.server.persist.Binder;
import com.avaje.ebeaninternal.server.type.DataBind;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
/**
* Set properties for a UpdateQuery.
*/
public class OrmUpdateProperties {
private static final NullValue NULL_VALUE = new NullValue();
private static final NoneValue NONE_VALUE = new NoneValue();
/**
* Bind value used in the set clause for update query.
* It may/may not have bind values etc.
*/
public static abstract class Value {
public void bind(Binder binder, DataBind dataBind) throws SQLException {
// default to no bind values
}
public String bindClause() {
return "";
}
public int getBindCount() {
return 0;
}
}
/**
* Set property to null.
*/
static class NullValue extends Value {
@Override
public String bindClause() {
return "=null";
}
}
/**
* Set property to a simple value.
*/
static class SimpleValue extends Value {
final Object value;
SimpleValue(Object value) {
this.value = value;
}
@Override
public int getBindCount() {
return 1;
}
@Override
public String bindClause() {
return "=?";
}
@Override
public void bind(Binder binder, DataBind dataBind) throws SQLException {
binder.bindObject(dataBind, value);
dataBind.append(value).append(",");
}
}
/**
* Set using an expression with no bind value.
*/
static class NoneValue extends Value {
@Override
public String bindClause() {
return "";
}
}
/**
* Set using an expression with many bind values.
*/
static class RawArrayValue extends Value {
final Object[] bindValues;
public RawArrayValue(Object[] bindValues) {
this.bindValues = bindValues;
}
@Override
public int getBindCount() {
return bindValues.length;
}
@Override
public void bind(Binder binder, DataBind dataBind) throws SQLException {
for (Object val : bindValues) {
binder.bindObject(dataBind, val);
dataBind.append(val).append(",");
}
}
}
/**
* The set properties/expressions and their bind values.
*/
private LinkedHashMap values = new LinkedHashMap();
/**
* Normal set property.
*/
public void set(String propertyName, Object value) {
if (value == null) {
values.put(propertyName, NULL_VALUE);
} else {
values.put(propertyName, new SimpleValue(value));
}
}
/**
* Set a raw expression with no bind values.
*/
public void setRaw(String propertyName) {
values.put(propertyName, NONE_VALUE);
}
/**
* Set a raw expression with many bind values.
*/
public void setRaw(String propertyExpression, Object... vals) {
if (vals.length == 0) {
setRaw(propertyExpression);
} else {
values.put(propertyExpression, new RawArrayValue(vals));
}
}
/**
* Return true if this update has the same logical set clause.
*/
public boolean isSameByPlan(OrmUpdateProperties that) {
return that.values.size() == values.size()
&& logicalSetClause().equals(that.logicalSetClause());
}
/**
* Build the hash for the query plan caching.
*/
public void buildQueryPlanHash(HashQueryPlanBuilder builder) {
builder.add(OrmUpdateProperties.class);
Set> entries = values.entrySet();
for (Map.Entry entry : entries) {
builder.add(entry.getKey());
builder.bind(entry.getValue().getBindCount());
}
}
/**
* Bind all the bind values for the update set clause.
*/
public void bind(Binder binder, DataBind dataBind) throws SQLException {
for (Value bindValue : values.values()) {
bindValue.bind(binder, dataBind);
}
}
/**
* Build the actual set clause converting logical property names to db columns etc.
*/
public String buildSetClause(DeployParser deployParser) {
int setCount = 0;
StringBuilder sb = new StringBuilder();
for (Map.Entry entry : values.entrySet()) {
String property = entry.getKey();
if (setCount++ > 0) {
sb.append(", ");
}
// translate to db columns and remove table alias placeholders
sb.append(deployParser.parse(property).replace("${}", ""));
sb.append(entry.getValue().bindClause());
}
return sb.toString();
}
/**
* Return a logical set clause to use for isSameByPlan() use.
*/
private String logicalSetClause() {
StringBuilder sb = new StringBuilder();
for (Map.Entry entry : values.entrySet()) {
sb.append(", ");
sb.append(entry.getKey()).append(entry.getValue().bindClause());
}
return sb.toString();
}
}