From e8237cc04fa36c387f63df0a80884d646b4cca6e Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Wed, 9 Nov 2016 15:59:01 +0100 Subject: [PATCH] ENH: Support for @Formula in combination with @ManyToOne --- .../server/deploy/BeanDescriptor.java | 5 +- .../server/deploy/BeanPropertyAssocOne.java | 5 +- .../server/deploy/BeanTable.java | 6 +- .../server/deploy/TableJoinColumn.java | 23 ++++++- .../deploy/meta/DeployTableJoinColumn.java | 60 +++++++++++++++++-- .../deploy/parse/AnnotationAssocManys.java | 2 +- .../deploy/parse/AnnotationAssocOnes.java | 2 +- .../server/deploy/parse/AnnotationFields.java | 5 ++ .../server/query/DefaultDbSqlContext.java | 15 ++++- 9 files changed, 110 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java index 38d979e14..8d8c17d7a 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java @@ -85,6 +85,7 @@ import javax.persistence.PersistenceException; import java.io.IOException; import java.lang.reflect.Modifier; import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; import java.sql.Types; import java.util.ArrayList; import java.util.Collection; @@ -868,7 +869,9 @@ public class BeanDescriptor implements MetaBeanInfo, BeanType { public void initialiseFkeys() { for (BeanPropertyAssocOne aPropertiesOneImported : propertiesOneImported) { - aPropertiesOneImported.addFkey(); + if (!aPropertiesOneImported.isFormula()) { + aPropertiesOneImported.addFkey(); + } } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java index 66b57efed..1d4ff4b3f 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java @@ -561,7 +561,9 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { @Override public void appendSelect(DbSqlContext ctx, boolean subQuery) { - if (!isTransient) { + if (formula) { + ctx.appendFormulaSelect(sqlFormulaSelect); + } else if (!isTransient) { localHelp.appendSelect(ctx, subQuery); } } @@ -569,6 +571,7 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { @Override public void appendFrom(DbSqlContext ctx, SqlJoinType joinType) { if (!isTransient) { + // TODO JOINS localHelp.appendFrom(ctx, joinType); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanTable.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanTable.java index 6e4a0f4ed..b19123965 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanTable.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanTable.java @@ -76,7 +76,7 @@ public class BeanTable { return beanType; } - public void createJoinColumn(String foreignKeyPrefix, DeployTableJoin join, boolean reverse) { + public void createJoinColumn(String foreignKeyPrefix, DeployTableJoin join, boolean reverse, String sqlFormulaSelect) { boolean complexKey = false; BeanProperty[] props = idProperties; @@ -104,8 +104,12 @@ public class BeanTable { logger.debug(msg); fk = lc; } + if (sqlFormulaSelect != null) { + fk = sqlFormulaSelect; + } DeployTableJoinColumn joinCol = new DeployTableJoinColumn(lc, fk); + joinCol.setForeignSqlFormula(sqlFormulaSelect); if (reverse) { joinCol = joinCol.reverse(); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/TableJoinColumn.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/TableJoinColumn.java index d64679402..4c5314a72 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/TableJoinColumn.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/TableJoinColumn.java @@ -13,14 +13,19 @@ public class TableJoinColumn { */ private final String localDbColumn; + private final String localSqlFormula; + /** * The foreign database column name. */ private final String foreignDbColumn; + + private final String foreignSqlFormula; private final boolean insertable; private final boolean updateable; + /** * Hash for including in a query plan @@ -33,6 +38,9 @@ public class TableJoinColumn { public TableJoinColumn(DeployTableJoinColumn deploy) { this.localDbColumn = InternString.intern(deploy.getLocalDbColumn()); this.foreignDbColumn = InternString.intern(deploy.getForeignDbColumn()); + this.localSqlFormula = InternString.intern(deploy.getLocalSqlFormula()); + this.foreignSqlFormula = InternString.intern(deploy.getForeignSqlFormula()); + this.insertable = deploy.isInsertable(); this.updateable = deploy.isUpdateable(); this.queryHash = hash(); @@ -41,8 +49,11 @@ public class TableJoinColumn { int hash() { int result = localDbColumn != null ? localDbColumn.hashCode() : 0; result = 92821 * result + (foreignDbColumn != null ? foreignDbColumn.hashCode() : 0); + result = 92821 * result + (localSqlFormula != null ? localSqlFormula.hashCode() : 0); + result = 92821 * result + (foreignSqlFormula != null ? foreignSqlFormula.hashCode() : 0); result = 92821 * result + (insertable ? 1 : 0); result = 92821 * result + (updateable ? 1 : 0); + return result; } @@ -64,7 +75,8 @@ public class TableJoinColumn { } public String toString() { - return localDbColumn + " = " + foreignDbColumn; + return (localSqlFormula == null ? localDbColumn : localSqlFormula) + " = " + + (foreignSqlFormula == null ? foreignDbColumn : foreignSqlFormula); } /** @@ -101,4 +113,13 @@ public class TableJoinColumn { public boolean isUpdateable() { return updateable; } + + public String getLocalSqlFormula() { + return localSqlFormula; + } + + public String getForeignSqlFormula() { + return foreignSqlFormula; + } + } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployTableJoinColumn.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployTableJoinColumn.java index cc2a8ca50..293857cdc 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployTableJoinColumn.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployTableJoinColumn.java @@ -15,14 +15,26 @@ public class DeployTableJoinColumn { */ String localDbColumn; + /** + * SQL formula used for local column + */ + String localSqlFormula; + /** * The foreign database column name. */ String foreignDbColumn; + + /** + * SQL formula used for foreign column + */ + String foreignSqlFormula; - final boolean insertable; + boolean insertable; + + boolean updateable; + - final boolean updateable; /** * Construct when automatically determining the join. @@ -43,7 +55,34 @@ public class DeployTableJoinColumn { this.insertable = insertable; this.updateable = updateable; } - + + public void setLocalSqlFormula(String localSqlFormula) { + if (localSqlFormula != null) { + this.localSqlFormula = localSqlFormula; + this.localDbColumn = null; + this.insertable = false; + this.updateable = false; + } + } + + public String getLocalSqlFormula() { + return localSqlFormula; + } + + public void setForeignSqlFormula(String foreignSqlFormula) { + if (foreignSqlFormula != null) { + this.foreignSqlFormula = foreignSqlFormula; + this.foreignDbColumn = null; + this.insertable = false; + this.updateable = false; + } + } + + public String getForeignSqlFormula() { + return foreignSqlFormula; + } + + public DeployTableJoinColumn(boolean order, JoinColumn jc, BeanTable beanTable) { this(jc.referencedColumnName(), jc.name(), jc.insertable(), jc.updatable()); setReferencedColumn(beanTable); @@ -68,6 +107,10 @@ public class DeployTableJoinColumn { String temp = localDbColumn; localDbColumn = foreignDbColumn; foreignDbColumn = temp; + + temp = localSqlFormula; + localSqlFormula = foreignSqlFormula; + foreignSqlFormula = temp; return this; } @@ -86,12 +129,18 @@ public class DeployTableJoinColumn { // Note that the insertable and updateable are just copied // which may not always be the correct thing to do // but will leave it like this for now + DeployTableJoinColumn ret; if (reverse){ - return new DeployTableJoinColumn(foreignDbColumn, localDbColumn, insertable, updateable); + ret = new DeployTableJoinColumn(foreignDbColumn, localDbColumn, insertable, updateable); + ret.setLocalSqlFormula(foreignSqlFormula); + ret.setForeignSqlFormula(localSqlFormula); } else { - return new DeployTableJoinColumn(localDbColumn, foreignDbColumn, insertable, updateable); + ret = new DeployTableJoinColumn(localDbColumn, foreignDbColumn, insertable, updateable); + ret.setLocalSqlFormula(localSqlFormula); + ret.setForeignSqlFormula(foreignSqlFormula); } + return ret; } public String toString() { @@ -132,4 +181,5 @@ public class DeployTableJoinColumn { public void setLocalDbColumn(String localDbColumn) { this.localDbColumn = localDbColumn; } + } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java index f5385890f..e597d8a12 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java @@ -136,7 +136,7 @@ public class AnnotationAssocManys extends AnnotationParser { // Use the owning bean table to define the join BeanTable owningBeanTable = factory.getBeanTable(descriptor.getBeanType()); - owningBeanTable.createJoinColumn(fkeyPrefix, prop.getTableJoin(), false); + owningBeanTable.createJoinColumn(fkeyPrefix, prop.getTableJoin(), false, prop.getSqlFormulaSelect()); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java index 6ade29cba..64242e408 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java @@ -142,7 +142,7 @@ public class AnnotationAssocOnes extends AnnotationParser { fkeyPrefix = nc.getColumnFromProperty(beanType, prop.getName()); } - beanTable.createJoinColumn(fkeyPrefix, prop.getTableJoin(), true); + beanTable.createJoinColumn(fkeyPrefix, prop.getTableJoin(), true, prop.getSqlFormulaSelect()); } } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationFields.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationFields.java index ac5172534..8e04be070 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationFields.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationFields.java @@ -103,6 +103,11 @@ public class AnnotationFields extends AnnotationParser { } readEmbeddedAttributeOverrides((DeployBeanPropertyAssocOne) prop); } + + Formula formula = get(prop, Formula.class); + if (formula != null) { + prop.setSqlFormula(formula.select(), formula.join()); + } } private void readField(DeployBeanProperty prop) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/DefaultDbSqlContext.java b/src/main/java/com/avaje/ebeaninternal/server/query/DefaultDbSqlContext.java index 67a3e7ceb..0329ddbb4 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/DefaultDbSqlContext.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/DefaultDbSqlContext.java @@ -136,9 +136,20 @@ class DefaultDbSqlContext implements DbSqlContext { if (i > 0) { sb.append(" and "); } - sb.append(a2).append(".").append(pair.getForeignDbColumn()); + + if (pair.getForeignSqlFormula() != null) { + sb.append(pair.getForeignSqlFormula().replace(tableAliasPlaceHolder, a2)); + } else { + sb.append(a2).append(".").append(pair.getForeignDbColumn()); + } + sb.append(" = "); - sb.append(a1).append(".").append(pair.getLocalDbColumn()); + + if (pair.getLocalSqlFormula() != null) { + sb.append(pair.getLocalSqlFormula().replace(tableAliasPlaceHolder, a1)); + } else { + sb.append(a1).append(".").append(pair.getLocalDbColumn()); + } } // add on any inheritance where clause