#919 - io.ebean package initial

This commit is contained in:
Rob Bygrave
2016-12-11 23:23:22 +13:00
parent 5821dc96b9
commit 971e2dc91b
2134 changed files with 10721 additions and 8652 deletions
@@ -0,0 +1,200 @@
package io.ebeaninternal.server.deploy.id;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.core.DefaultSqlUpdate;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.type.DataBind;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
/**
* Binds id values to prepared statements.
*/
public interface IdBinder {
/**
* Initialise the binder.
*/
void initialise();
/**
* Return true if this is a compound key and must use expanded and or form.
*/
boolean isIdInExpandedForm();
/**
* Write the Id value to binary DataOuput.
*/
void writeData(DataOutput dataOutput, Object idValue) throws IOException;
/**
* Read the Id value from the binary DataInput.
*/
Object readData(DataInput dataInput) throws IOException;
/**
* Return the name(s) of the Id property(s). Comma delimited if there is more
* than one.
* <p>
* This can be used to include in a query.
* </p>
*/
String getIdProperty();
/**
* Return the Id BeanProperty.
*/
BeanProperty getBeanProperty();
/**
* Find a BeanProperty that is mapped to the database column.
*/
BeanProperty findBeanProperty(String dbColumnName);
/**
* Return false if the id is a simple scalar and false if it is embedded or
* concatenated.
*/
boolean isComplexId();
/**
* Return the default order by that may need to be used if the query includes
* a many property.
*/
String getDefaultOrderBy();
String getOrderBy(String pathPrefix, boolean ascending);
/**
* Return the values as an array of scalar bindable values.
* <p>
* For concatenated keys that use an Embedded bean or multiple id properties
* this determines the field values are returns them as an Object array.
* </p>
* <p>
* Added primarily for Query.addWhere().add(Expr.idEq()) support.
* </p>
*/
Object[] getBindValues(Object idValue);
/**
* For EmbeddedId convert the idValue into a simple map.
* Otherwise the idValue is just returned as is.
* <p>
* This is used to provide a simple JSON serializable version of the id value.
* </p>
*/
Object getIdForJson(EntityBean idValue);
/**
* For EmbeddedId the value is assumed to be a Map and this is
* takes the values from the map and builds an embedded id bean.
* <p>
* For other simple id's this just returns the value (no conversion required).
* </p>
* <p>
* This is used to provide a simple JSON serializable version of the id value.
* </p>
*/
Object convertIdFromJson(Object value);
/**
* Return the id values for a given bean.
*/
Object[] getIdValues(EntityBean bean);
/**
* Build a string of the logical expressions.
* <p>
* Typically used to build a id = ? string.
* </p>
*/
String getAssocOneIdExpr(String prefix, String operator);
/**
* Return the logical id in expression taking into account embedded id's.
*/
String getAssocIdInExpr(String prefix);
/**
* Binds an id value to a prepared statement.
*/
void bindId(DataBind dataBind, Object value) throws SQLException;
/**
* Bind the id value to a SqlUpdate statement.
*/
void bindId(DefaultSqlUpdate sqlUpdate, Object value);
void addIdInBindValue(SpiExpressionRequest request, Object value);
/**
* Return the sql for binding the id using an IN clause.
*/
String getBindIdInSql(String baseTableAlias);
/**
* Return the binding expression (like "?" or "(?,?)")for the Id.
*/
String getIdInValueExpr(int size);
/**
* Same as getIdInValueExpr but for delete by id.
*/
String getIdInValueExprDelete(int size);
void buildRawSqlSelectChain(String prefix, List<String> selectChain);
/**
* Read the id value from the result set and set it to the bean also returning
* it.
*/
Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException;
/**
* Ignore the appropriate number of scalar properties for this id.
*/
void loadIgnore(DbReadContext ctx);
/**
* Read the id value from the result set and return it.
*/
Object read(DbReadContext ctx) throws SQLException;
/**
* Append to the select clause.
*/
void appendSelect(DbSqlContext ctx, boolean subQuery);
/**
* Return the sql for binding the id to. This includes table alias and columns
* that make up the id.
*/
String getBindIdSql(String baseTableAlias);
/**
* Cast or convert the Id value if necessary and optionally set it.
* <p>
* The Id value is not assumed to be the correct type so it is converted to
* the correct type. Typically this is because we could get a Integer, Long or
* BigDecimal depending on the JDBC driver and situation.
* </p>
* <p>
* If the bean is not null, then the value is set to the bean.
* </p>
*/
Object convertSetId(Object idValue, EntityBean bean);
/**
* Cast or convert the Id value if necessary.
*/
Object convertId(Object idValue);
}
@@ -0,0 +1,438 @@
package io.ebeaninternal.server.deploy.id;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.core.DefaultSqlUpdate;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.query.SplitName;
import io.ebeaninternal.server.type.DataBind;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Bind an Id that is an Embedded bean.
*/
public final class IdBinderEmbedded implements IdBinder {
private final BeanPropertyAssocOne<?> embIdProperty;
private final boolean idInExpandedForm;
private BeanProperty[] props;
private BeanDescriptor<?> idDesc;
private String idInValueSql;
public IdBinderEmbedded(boolean idInExpandedForm, BeanPropertyAssocOne<?> embIdProperty) {
this.idInExpandedForm = idInExpandedForm;
this.embIdProperty = embIdProperty;
}
public void initialise() {
this.idDesc = embIdProperty.getTargetDescriptor();
this.props = embIdProperty.getProperties();
this.idInValueSql = idInExpandedForm ? idInExpanded() : idInCompressed();
}
public boolean isIdInExpandedForm() {
return idInExpandedForm;
}
private String idInExpanded() {
StringBuilder sb = new StringBuilder(30);
sb.append("(");
for (int i = 0; i < props.length; i++) {
if (i > 0) {
sb.append(" and ");
}
sb.append(idDesc.getBaseTableAlias());
sb.append(".");
sb.append(props[i].getDbColumn());
sb.append("=?");
}
sb.append(")");
return sb.toString();
}
private String idInCompressed() {
StringBuilder sb = new StringBuilder();
sb.append("(");
for (int i = 0; i < props.length; i++) {
if (i > 0) {
sb.append(",");
}
sb.append("?");
}
sb.append(")");
return sb.toString();
}
@Override
public BeanProperty getBeanProperty() {
return embIdProperty;
}
public String getOrderBy(String pathPrefix, boolean ascending) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < props.length; i++) {
if (i > 0) {
sb.append(", ");
}
if (pathPrefix != null) {
sb.append(pathPrefix).append(".");
}
sb.append(embIdProperty.getName()).append(".");
sb.append(props[i].getName());
if (!ascending) {
sb.append(" desc");
}
}
return sb.toString();
}
public BeanDescriptor<?> getIdBeanDescriptor() {
return idDesc;
}
public String getIdProperty() {
return embIdProperty.getName();
}
public void buildRawSqlSelectChain(String prefix, List<String> selectChain) {
prefix = SplitName.add(prefix, embIdProperty.getName());
for (BeanProperty prop : props) {
prop.buildRawSqlSelectChain(prefix, selectChain);
}
}
public BeanProperty findBeanProperty(String dbColumnName) {
for (BeanProperty prop : props) {
if (dbColumnName.equalsIgnoreCase(prop.getDbColumn())) {
return prop;
}
}
return null;
}
public boolean isComplexId() {
return true;
}
public String getDefaultOrderBy() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < props.length; i++) {
if (i > 0) {
sb.append(",");
}
sb.append(embIdProperty.getName());
sb.append(".");
sb.append(props[i].getName());
}
return sb.toString();
}
public BeanProperty[] getProperties() {
return props;
}
public void addIdInBindValue(SpiExpressionRequest request, Object value) {
for (BeanProperty prop : props) {
request.addBindValue(prop.getValue((EntityBean) value));
}
}
public String getIdInValueExprDelete(int size) {
if (!idInExpandedForm) {
return getIdInValueExpr(size);
}
StringBuilder sb = new StringBuilder();
sb.append("(");
for (int j = 0; j < size; j++) {
if (j > 0) {
sb.append(" or ");
}
sb.append("(");
for (int i = 0; i < props.length; i++) {
if (i > 0) {
sb.append(" and ");
}
sb.append(props[i].getDbColumn());
sb.append("=?");
}
sb.append(")");
}
sb.append(") ");
return sb.toString();
}
public String getIdInValueExpr(int size) {
StringBuilder sb = new StringBuilder();
if (!idInExpandedForm) {
sb.append(" in");
}
sb.append(" (");
for (int i = 0; i < size; i++) {
if (i > 0) {
if (idInExpandedForm) {
sb.append(" or ");
} else {
sb.append(",");
}
}
sb.append(idInValueSql);
}
sb.append(") ");
return sb.toString();
}
public Object[] getIdValues(EntityBean bean) {
Object val = embIdProperty.getValue(bean);
Object[] bindvalues = new Object[props.length];
for (int i = 0; i < props.length; i++) {
bindvalues[i] = props[i].getValue((EntityBean) val);
}
return bindvalues;
}
public Object[] getBindValues(Object value) {
Object[] bindvalues = new Object[props.length];
for (int i = 0; i < props.length; i++) {
bindvalues[i] = props[i].getValue((EntityBean) value);
}
return bindvalues;
}
/**
* Convert from embedded bean to Map.
*/
@Override
public Object getIdForJson(EntityBean bean) {
EntityBean ebValue = (EntityBean)embIdProperty.getValue(bean);
Map<String,Object> map = new LinkedHashMap<>();
for (BeanProperty prop : props) {
map.put(prop.getName(), prop.getValue(ebValue));
}
return map;
}
/**
* Convert back from a Map to embedded bean.
*/
@SuppressWarnings("unchecked")
public Object convertIdFromJson(Object value) {
Map<String,Object> map = (Map<String, Object>)value;
EntityBean idValue = idDesc.createEntityBean();
for (BeanProperty prop : props) {
Object val = map.get(prop.getName());
prop.setValue(idValue, val);
}
return idValue;
}
public void bindId(DefaultSqlUpdate sqlUpdate, Object value) {
for (BeanProperty prop : props) {
Object embFieldValue = prop.getValue((EntityBean) value);
sqlUpdate.addParameter(embFieldValue);
}
}
public void bindId(DataBind dataBind, Object value) throws SQLException {
for (BeanProperty prop : props) {
Object embFieldValue = prop.getValue((EntityBean) value);
prop.bind(dataBind, embFieldValue);
}
}
public Object readData(DataInput dataInput) throws IOException {
EntityBean embId = idDesc.createEntityBean();
boolean notNull = true;
for (BeanProperty prop : props) {
Object value = prop.readData(dataInput);
prop.setValue(embId, value);
if (value == null) {
notNull = false;
}
}
if (notNull) {
return embId;
} else {
return null;
}
}
public void writeData(DataOutput dataOutput, Object idValue) throws IOException {
for (BeanProperty prop : props) {
Object embFieldValue = prop.getValue((EntityBean) idValue);
prop.writeData(dataOutput, embFieldValue);
}
}
public void loadIgnore(DbReadContext ctx) {
for (BeanProperty prop : props) {
prop.loadIgnore(ctx);
}
}
public Object read(DbReadContext ctx) throws SQLException {
EntityBean embId = idDesc.createEntityBean();
boolean notNull = true;
for (BeanProperty prop : props) {
Object value = prop.readSet(ctx, embId);
if (value == null) {
notNull = false;
}
}
if (notNull) {
return embId;
} else {
return null;
}
}
public Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException {
Object embId = read(ctx);
if (embId != null) {
embIdProperty.setValue(bean, embId);
return embId;
} else {
return null;
}
}
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
for (BeanProperty prop : props) {
prop.appendSelect(ctx, subQuery);
}
}
public String getAssocIdInExpr(String prefix) {
StringBuilder sb = new StringBuilder();
sb.append("(");
for (int i = 0; i < props.length; i++) {
if (i > 0) {
sb.append(",");
}
if (prefix != null) {
sb.append(prefix);
sb.append(".");
}
sb.append(props[i].getName());
}
sb.append(")");
return sb.toString();
}
public String getAssocOneIdExpr(String prefix, String operator) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < props.length; i++) {
if (i > 0) {
sb.append(" and ");
}
if (prefix != null) {
sb.append(prefix);
sb.append(".");
}
sb.append(embIdProperty.getName());
sb.append(".");
sb.append(props[i].getName());
sb.append(operator);
}
return sb.toString();
}
public String getBindIdSql(String baseTableAlias) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < props.length; i++) {
if (i > 0) {
sb.append(" and ");
}
if (baseTableAlias != null) {
sb.append(baseTableAlias);
sb.append(".");
}
sb.append(props[i].getDbColumn());
sb.append(" = ? ");
}
return sb.toString();
}
public String getBindIdInSql(String baseTableAlias) {
if (idInExpandedForm) {
return "";
}
StringBuilder sb = new StringBuilder();
sb.append("(");
for (int i = 0; i < props.length; i++) {
if (i > 0) {
sb.append(",");
}
if (baseTableAlias != null) {
sb.append(baseTableAlias);
sb.append(".");
}
sb.append(props[i].getDbColumn());
}
sb.append(")");
return sb.toString();
}
@Override
public Object convertId(Object idValue) {
// can not cast/convert if it is embedded
return idValue;
}
public Object convertSetId(Object idValue, EntityBean bean) {
// can not cast/convert if it is embedded
if (bean != null) {
// support PropertyChangeSupport
embIdProperty.setValueIntercept(bean, idValue);
}
return idValue;
}
}
@@ -0,0 +1,149 @@
package io.ebeaninternal.server.deploy.id;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.core.DefaultSqlUpdate;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.type.DataBind;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
/**
* For beans with no id properties AKA report type beans.
*/
public final class IdBinderEmpty implements IdBinder {
private static final String bindIdSql = "";
public IdBinderEmpty() {
}
public void initialise() {
}
public boolean isIdInExpandedForm() {
return false;
}
public String getOrderBy(String pathPrefix, boolean ascending) {
return pathPrefix;
}
public void buildRawSqlSelectChain(String prefix, List<String> selectChain) {
}
@Override
public BeanProperty getBeanProperty() {
return null;
}
public String getIdProperty() {
return null;
}
public BeanProperty findBeanProperty(String dbColumnName) {
return null;
}
public boolean isComplexId() {
return true;
}
public String getDefaultOrderBy() {
// this should never happen?
return "";
}
public String getBindIdSql(String baseTableAlias) {
return bindIdSql;
}
public String getAssocOneIdExpr(String prefix, String operator) {
return null;
}
public String getAssocIdInExpr(String prefix) {
return null;
}
public void addIdInBindValue(SpiExpressionRequest request, Object value) {
}
public String getIdInValueExprDelete(int size) {
return getIdInValueExpr(size);
}
public String getIdInValueExpr(int size) {
return "";
}
public String getBindIdInSql(String baseTableAlias) {
return null;
}
public Object[] getIdValues(EntityBean bean) {
return null;
}
public Object[] getBindValues(Object idValue) {
return new Object[]{idValue};
}
@Override
public Object getIdForJson(EntityBean bean) {
return null;
}
@Override
public Object convertIdFromJson(Object value) {
return value;
}
public void bindId(DefaultSqlUpdate sqlUpdate, Object value) {
}
public void bindId(DataBind dataBind, Object value) throws SQLException {
}
public void loadIgnore(DbReadContext ctx) {
}
public Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException {
return null;
}
public Object read(DbReadContext ctx) throws SQLException {
return null;
}
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
}
public Object convertSetId(Object idValue, EntityBean bean) {
return idValue;
}
@Override
public Object convertId(Object idValue) {
return idValue;
}
public Object readData(DataInput dataOutput) throws IOException {
return null;
}
public void writeData(DataOutput dataOutput, Object idValue) throws IOException {
}
}
@@ -0,0 +1,36 @@
package io.ebeaninternal.server.deploy.id;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
/**
* Creates the appropriate IdConvertSet depending on the type of Id property(s).
*/
public class IdBinderFactory {
private static final IdBinderEmpty EMPTY = new IdBinderEmpty();
private final boolean idInExpandedForm;
public IdBinderFactory(boolean idInExpandedForm) {
this.idInExpandedForm = idInExpandedForm;
}
/**
* Create the IdConvertSet for the given type of Id properties.
*/
public IdBinder createIdBinder(BeanProperty id) {
if (id == null) {
// for report type beans that don't need an id
return EMPTY;
}
if (id.isEmbedded()) {
return new IdBinderEmbedded(idInExpandedForm, (BeanPropertyAssocOne<?>) id);
} else {
return new IdBinderSimple(id);
}
}
}
@@ -0,0 +1,226 @@
package io.ebeaninternal.server.deploy.id;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.core.DefaultSqlUpdate;
import io.ebeaninternal.server.core.InternString;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.type.DataBind;
import io.ebeaninternal.server.type.ScalarType;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
/**
* Bind an Id where the Id is made of a single property (not embedded).
*/
public final class IdBinderSimple implements IdBinder {
private final BeanProperty idProperty;
private final String bindIdSql;
private final Class<?> expectedType;
@SuppressWarnings("rawtypes")
private final ScalarType scalarType;
public IdBinderSimple(BeanProperty idProperty) {
this.idProperty = idProperty;
this.scalarType = idProperty.getScalarType();
this.expectedType = idProperty.getPropertyType();
bindIdSql = InternString.intern(idProperty.getDbColumn() + " = ? ");
}
public void initialise() {
// do nothing
}
public boolean isIdInExpandedForm() {
return false;
}
public String getOrderBy(String pathPrefix, boolean ascending) {
StringBuilder sb = new StringBuilder();
if (pathPrefix != null) {
sb.append(pathPrefix).append(".");
}
sb.append(idProperty.getName());
if (!ascending) {
sb.append(" desc");
}
return sb.toString();
}
public void buildRawSqlSelectChain(String prefix, List<String> selectChain) {
idProperty.buildRawSqlSelectChain(prefix, selectChain);
}
@Override
public BeanProperty getBeanProperty() {
return idProperty;
}
public String getIdProperty() {
return idProperty.getName();
}
public BeanProperty findBeanProperty(String dbColumnName) {
if (dbColumnName.equalsIgnoreCase(idProperty.getDbColumn())) {
return idProperty;
}
return null;
}
public boolean isComplexId() {
return false;
}
public String getDefaultOrderBy() {
return idProperty.getName();
}
public String getBindIdInSql(String baseTableAlias) {
if (baseTableAlias == null) {
return idProperty.getDbColumn();
} else {
return baseTableAlias + "." + idProperty.getDbColumn();
}
}
public String getBindIdSql(String baseTableAlias) {
if (baseTableAlias == null) {
return bindIdSql;
} else {
return baseTableAlias + "." + bindIdSql;
}
}
public Object[] getIdValues(EntityBean bean) {
return new Object[]{idProperty.getValue(bean)};
}
public Object[] getBindValues(Object idValue) {
return new Object[]{idValue};
}
public String getIdInValueExprDelete(int size) {
return getIdInValueExpr(size);
}
public String getIdInValueExpr(int size) {
StringBuilder sb = new StringBuilder(2 * size + 10);
sb.append(" in");
sb.append(" (?");
for (int i = 1; i < size; i++) {
sb.append(",?");
}
sb.append(") ");
return sb.toString();
}
public void addIdInBindValue(SpiExpressionRequest request, Object value) {
value = convertSetId(value, null);
request.addBindValue(value);
}
@Override
public Object getIdForJson(EntityBean bean) {
return idProperty.getValue(bean);
}
@Override
public Object convertIdFromJson(Object value) {
// handle simple type conversion if required
return convertId(value);
}
public void bindId(DefaultSqlUpdate sqlUpdate, Object value) {
sqlUpdate.addParameter(value);
}
public void bindId(DataBind dataBind, Object value) throws SQLException {
if (!value.getClass().equals(expectedType)) {
value = scalarType.toBeanType(value);
}
idProperty.bind(dataBind, value);
}
public void writeData(DataOutput os, Object value) throws IOException {
idProperty.writeData(os, value);
}
public Object readData(DataInput is) throws IOException {
return idProperty.readData(is);
}
public void loadIgnore(DbReadContext ctx) {
idProperty.loadIgnore(ctx);
}
public Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException {
Object id = idProperty.read(ctx);
if (id != null) {
idProperty.setValue(bean, id);
}
return id;
}
public Object read(DbReadContext ctx) throws SQLException {
return idProperty.read(ctx);
}
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
idProperty.appendSelect(ctx, subQuery);
}
public String getAssocOneIdExpr(String prefix, String operator) {
StringBuilder sb = new StringBuilder();
if (prefix != null) {
sb.append(prefix);
sb.append(".");
}
sb.append(idProperty.getName());
sb.append(operator);
return sb.toString();
}
public String getAssocIdInExpr(String prefix) {
StringBuilder sb = new StringBuilder();
if (prefix != null) {
sb.append(prefix);
sb.append(".");
}
sb.append(idProperty.getName());
return sb.toString();
}
public Object convertId(Object idValue) {
if (!idValue.getClass().equals(expectedType)) {
return scalarType.toBeanType(idValue);
}
return idValue;
}
public Object convertSetId(Object idValue, EntityBean bean) {
if (!idValue.getClass().equals(expectedType)) {
idValue = scalarType.toBeanType(idValue);
}
if (bean != null) {
// support PropertyChangeSupport
idProperty.setValueIntercept(bean, idValue);
}
return idValue;
}
}
@@ -0,0 +1,69 @@
package io.ebeaninternal.server.deploy.id;
import java.sql.SQLException;
import io.ebean.SqlUpdate;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.IntersectionRow;
import io.ebeaninternal.server.persist.dml.GenerateDmlRequest;
import io.ebeaninternal.server.persist.dmlbind.BindableRequest;
/**
* Represents a imported property.
*/
public interface ImportedId {
void addFkeys(String name);
/**
* Return true if this id is a simple single scalar value. False if it is a
* compound id (embedded or multiple).
*/
boolean isScalar();
/**
* For scalar id return the related single db column.
* <p>
* This is essentially the imported foreign key column (where there is only
* one).
* </p>
*/
String getDbColumn();
/**
* Append the the SQL query statement.
*/
void sqlAppend(DbSqlContext ctx);
/**
* Append to the DML statement.
*/
void dmlAppend(GenerateDmlRequest request);
/**
* Bind the value from the bean.
*/
Object bind(BindableRequest request, EntityBean bean) throws SQLException;
/**
* Bind the imported Id value to the SqlUpdate.
*/
int bind(int position, SqlUpdate update, EntityBean bean);
/**
* For inserting into ManyToMany intersection.
*/
void buildImport(IntersectionRow row, EntityBean other);
/**
* Used to derive a missing concatenated key from multiple imported keys.
*/
BeanProperty findMatchImport(String matchDbColumn);
/**
* Return the set importedId clause.
*/
String importedIdClause();
}
@@ -0,0 +1,152 @@
package io.ebeaninternal.server.deploy.id;
import java.sql.SQLException;
import javax.persistence.PersistenceException;
import io.ebean.SqlUpdate;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.server.deploy.BeanFkeyProperty;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssoc;
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.IntersectionRow;
import io.ebeaninternal.server.persist.dml.GenerateDmlRequest;
import io.ebeaninternal.server.persist.dmlbind.BindableRequest;
/**
* Imported Embedded id.
*/
public class ImportedIdEmbedded implements ImportedId {
private final BeanPropertyAssoc<?> owner;
private final BeanPropertyAssocOne<?> foreignAssocOne;
private final ImportedIdSimple[] imported;
public ImportedIdEmbedded(BeanPropertyAssoc<?> owner, BeanPropertyAssocOne<?> foreignAssocOne, ImportedIdSimple[] imported) {
this.owner = owner;
this.foreignAssocOne = foreignAssocOne;
this.imported = imported;
}
public void addFkeys(String name) {
BeanProperty[] embeddedProps = foreignAssocOne.getProperties();
for (int i = 0; i < imported.length; i++) {
String n = name + "." + foreignAssocOne.getName() + "." + embeddedProps[i].getName();
BeanFkeyProperty fkey = new BeanFkeyProperty(n, imported[i].localDbColumn, foreignAssocOne.getDeployOrder());
owner.getBeanDescriptor().add(fkey);
}
}
public boolean isScalar() {
return false;
}
public String getDbColumn() {
return null;
}
public void sqlAppend(DbSqlContext ctx) {
for (ImportedIdSimple anImported : imported) {
ctx.appendColumn(anImported.localDbColumn);
}
}
public void dmlAppend(GenerateDmlRequest request) {
for (ImportedIdSimple anImported : imported) {
request.appendColumn(anImported.localDbColumn);
}
}
@Override
public String importedIdClause() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < imported.length; i++) {
if (i > 0) {
sb.append(", ");
}
sb.append(imported[i].localDbColumn).append(" = ?");
}
return sb.toString();
}
@Override
public int bind(int position, SqlUpdate update, EntityBean bean) {
int pos = position;
EntityBean embedded = (EntityBean) foreignAssocOne.getValue(bean);
for (ImportedIdSimple anImported : imported) {
if (anImported.owner.isUpdateable()) {
Object scalarValue = anImported.foreignProperty.getValue(embedded);
update.setParameter(pos++, scalarValue);
}
}
return pos;
}
public Object bind(BindableRequest request, EntityBean bean) throws SQLException {
Object embeddedId = null;
if (bean != null) {
embeddedId = foreignAssocOne.getValue(bean);
}
if (embeddedId == null) {
for (ImportedIdSimple anImported : imported) {
if (anImported.owner.isUpdateable()) {
request.bind(null, anImported.foreignProperty);
}
}
} else {
EntityBean embedded = (EntityBean) embeddedId;
for (ImportedIdSimple anImported : imported) {
if (anImported.owner.isUpdateable()) {
Object scalarValue = anImported.foreignProperty.getValue(embedded);
request.bind(scalarValue, anImported.foreignProperty);
}
}
}
// hmmm, not worrying about this just yet
return null;
}
public void buildImport(IntersectionRow row, EntityBean other) {
EntityBean embeddedId = (EntityBean) foreignAssocOne.getValue(other);
if (embeddedId == null) {
String msg = "Foreign Key value null?";
throw new PersistenceException(msg);
}
for (ImportedIdSimple anImported : imported) {
Object scalarValue = anImported.foreignProperty.getValue(embeddedId);
row.put(anImported.localDbColumn, scalarValue);
}
}
/**
* Not supported for embedded id.
*/
public BeanProperty findMatchImport(String matchDbColumn) {
for (ImportedIdSimple anImported : imported) {
BeanProperty p = anImported.findMatchImport(matchDbColumn);
if (p != null) {
return p;
}
}
return null;
}
}
@@ -0,0 +1,150 @@
package io.ebeaninternal.server.deploy.id;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import javax.persistence.PersistenceException;
import io.ebean.SqlUpdate;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.server.core.InternString;
import io.ebeaninternal.server.deploy.BeanFkeyProperty;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssoc;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.IntersectionRow;
import io.ebeaninternal.server.persist.dml.GenerateDmlRequest;
import io.ebeaninternal.server.persist.dmlbind.BindableRequest;
/**
* Single scalar imported id.
*/
public final class ImportedIdSimple implements ImportedId, Comparable<ImportedIdSimple> {
/**
* Helper class to sort ImportedIdSimple.
*/
private final static class EntryComparator implements Comparator<ImportedIdSimple> {
public int compare(ImportedIdSimple o1, ImportedIdSimple o2) {
return o1.compareTo(o2);
}
}
private static final EntryComparator COMPARATOR = new EntryComparator();
protected final BeanPropertyAssoc<?> owner;
protected final String localDbColumn;
protected final String localSqlFormula;
protected final String logicalName;
protected final BeanProperty foreignProperty;
protected final int position;
public ImportedIdSimple(BeanPropertyAssoc<?> owner, String localDbColumn, String localSqlFormula, BeanProperty foreignProperty, int position) {
this.owner = owner;
this.localDbColumn = InternString.intern(localDbColumn);
this.localSqlFormula = InternString.intern(localSqlFormula);
this.foreignProperty = foreignProperty;
this.position = position;
this.logicalName = InternString.intern(owner.getName() + "." + foreignProperty.getName());
}
/**
* Return the list as an array sorted into the same order as the Bean Properties.
*/
public static ImportedIdSimple[] sort(List<ImportedIdSimple> list) {
ImportedIdSimple[] importedIds = list.toArray(new ImportedIdSimple[list.size()]);
// sort into the same order as the BeanProperties
Arrays.sort(importedIds, COMPARATOR);
return importedIds;
}
@Override
public boolean equals(Object obj) {
// remove FindBugs warning
return obj == this;
}
public int compareTo(ImportedIdSimple other) {
return (position < other.position ? -1 : (position == other.position ? 0 : 1));
}
public void addFkeys(String name) {
BeanFkeyProperty fkey = new BeanFkeyProperty(name + "." + foreignProperty.getName(), localDbColumn, owner.getDeployOrder());
owner.getBeanDescriptor().add(fkey);
}
public boolean isScalar() {
return true;
}
public String getDbColumn() {
return localDbColumn;
}
private Object getIdValue(EntityBean bean) {
return foreignProperty.getValue(bean);
}
public void buildImport(IntersectionRow row, EntityBean other) {
Object value = getIdValue(other);
if (value == null) {
String msg = "Foreign Key value null?";
throw new PersistenceException(msg);
}
row.put(localDbColumn, value);
}
public void sqlAppend(DbSqlContext ctx) {
if (localSqlFormula != null) {
ctx.appendFormulaSelect(localSqlFormula);
} else {
ctx.appendColumn(localDbColumn);
}
}
public void dmlAppend(GenerateDmlRequest request) {
request.appendColumn(localDbColumn);
}
@Override
public String importedIdClause() {
return localDbColumn + " = ?";
}
@Override
public int bind(int position, SqlUpdate update, EntityBean bean) {
Object value = getIdValue(bean);
update.setParameter(position, value);
return ++position;
}
public Object bind(BindableRequest request, EntityBean bean) throws SQLException {
Object value = null;
if (bean != null) {
value = getIdValue(bean);
}
request.bind(value, foreignProperty);
return value;
}
public BeanProperty findMatchImport(String matchDbColumn) {
if (matchDbColumn.equals(localDbColumn)) {
return foreignProperty;
}
return null;
}
}
@@ -0,0 +1,10 @@
<HTML>
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
<TITLE>Helpers for Id property conversion</TITLE>
</HEAD>
<Body BGCOLOR="#ffffff">
Helpers for Id property conversion
</Body>
</HTML>