diff --git a/pom.xml b/pom.xml index 9702732..c618997 100644 --- a/pom.xml +++ b/pom.xml @@ -1,66 +1,81 @@ - - - 4.0.0 - net.paoding - jade-plugin-sql - jar - 0.0.1-SNAPSHOT - jade-plugin-sql + + + 4.0.0 + net.paoding + jade-plugin-sql + jar + 0.0.1-SNAPSHOT + jade-plugin-sql - - - net.paoding - paoding-rose-parent - 2.0.u04 - + + + net.paoding + paoding-rose-parent + 2.0.u08 + - - - - 耿直Alan.Geng - gengzhi718@gmail.com - - - + + + + 耿直Alan.Geng + gengzhi718@gmail.com + + - - - scm:git:git@github.com:paoding-code/jade-plugin-sql.git - scm:git:git@github.com:paoding-code/jade-plugin-sql.git - git@github.com:paoding-code/jade-plugin-sql.git - - - - - - 18.0 - 1.2.6 - - - - - net.paoding - paoding-rose-jade - - - com.google.guava - guava - ${guava.version} - + + + scm:git:git@github.com:paoding-code/jade-plugin-sql.git + scm:git:git@github.com:paoding-code/jade-plugin-sql.git + git@github.com:paoding-code/jade-plugin-sql.git + - - - com.alibaba - fastjson - ${fastjson.version} - test - - - org.hsqldb - hsqldb - ${hsqldb.version} - test - - + + + + 18.0 + 1.2.6 + 11.2.0.3 + + + + + + net.paoding + paoding-rose-jade + + + com.google.guava + guava + ${guava.version} + + + + + com.alibaba + fastjson + ${fastjson.version} + test + + + org.hsqldb + hsqldb + ${hsqldb.version} + test + + + com.oracle + ojdbc6 + ${oracle.version} + test + + + + + + codelds + https://code.lds.org/nexus/content/groups/main-repo + + diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/GenericDAO.java b/src/main/java/net/paoding/rose/jade/plugin/sql/GenericDAO.java index 542673c..141f363 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/GenericDAO.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/GenericDAO.java @@ -5,9 +5,11 @@ import java.util.List; +import net.paoding.rose.jade.annotation.AfterInvocation; import net.paoding.rose.jade.annotation.ReturnGeneratedKeys; import net.paoding.rose.jade.annotation.SQL; import net.paoding.rose.jade.annotation.SQLParam; +import net.paoding.rose.jade.plugin.sql.id.AutoIncrementProcessor; /** * @author Alan.Geng[gengzhi718@gmail.com] @@ -27,7 +29,8 @@ public interface GenericDAO { * * @return auto increment id */ - @ReturnGeneratedKeys + @ReturnGeneratedKeys(AutoIncrementProcessor.class) + @AfterInvocation(AutoIncrementProcessor.class) ID save(@SQLParam("entity") E entity); /** diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/PlumSQLInterpreter.java b/src/main/java/net/paoding/rose/jade/plugin/sql/PlumSQLInterpreter.java index 121683c..16fbbad 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/PlumSQLInterpreter.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/PlumSQLInterpreter.java @@ -4,6 +4,8 @@ package net.paoding.rose.jade.plugin.sql; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -37,13 +39,20 @@ @Order(-1) public class PlumSQLInterpreter implements Interpreter, InitializingBean, ApplicationContextAware { - private static final Log logger = LogFactory.getLog(PlumSQLInterpreter.class); + private static final Log logger = LogFactory.getLog(PlumSQLInterpreter.class); - private ApplicationContext applicationContext; + private ApplicationContext applicationContext; private OperationMapperManager operationMapperManager; private IDialect dialect; + + private Map packageScopeDialect; + + public static final String ATTRIBUTE_NAME_INTERPRETER = "jade-plugin-sql.interpreter"; + + public static final String SQL_ANNOTATION_MARKUP = "jade-plugin-sql"; + public void setDialect(IDialect dialect) { this.dialect = dialect; @@ -68,41 +77,61 @@ public void afterPropertiesSet() throws Exception { // 将来可能扩展点:不同的DAO可以有不同的Dialect哦,而且是自动知道,不需要外部设置。 dialect = new MySQLDialect(); } + + this.loadPackageRegionDialect(); + // if (logger.isInfoEnabled()) { - String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(// - applicationContext, GenericDAO.class); - logger.info("[jade-plugin-sql] found " + beanNames.length + " GenericDAOs: " - + Arrays.toString(beanNames)); + if (applicationContext != null) { + String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(// + applicationContext, GenericDAO.class); + logger.info("[jade-plugin-sql] found " + beanNames.length + " GenericDAOs: " + + Arrays.toString(beanNames)); + } } } + + public void loadPackageRegionDialect() { + String[] dialectBeanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, IDialect.class); + for(String beanName : dialectBeanNames) { + if(packageScopeDialect == null) { + packageScopeDialect = new HashMap(); + } + + String packageName = beanName.substring("plum.dialect.".length()); + + packageScopeDialect.put(packageName, (IDialect) applicationContext.getBean(beanName)); + } + } /** - * 对 {@link GenericDAO} 及其子DAO接口中没有注解®SQL或仅仅®SQL("")的方法进行解析,根据实际参数情况自动动态生成SQL语句 + * 对 {@link GenericDAO} 及其子DAO接口中没有注解@SQL或仅仅@SQL("")的方法进行解析,根据实际参数情况自动动态生成SQL语句 */ @Override public void interpret(StatementRuntime runtime) { - final String interpreterAttribute = "jade-plugin-sql.interpreter"; - Interpreter interpreter = runtime.getMetaData().getAttribute(interpreterAttribute); + Interpreter interpreter = runtime.getMetaData().getAttribute(ATTRIBUTE_NAME_INTERPRETER); if (interpreter == null) { StatementMetaData smd = runtime.getMetaData(); synchronized (smd) { - interpreter = smd.getAttribute(interpreterAttribute); + interpreter = smd.getAttribute(ATTRIBUTE_NAME_INTERPRETER); if (interpreter == null) { - interpreter = PassThroughInterpreter; + interpreter = PASS_THROUGH_INTERPRETER; if (GenericDAO.class.isAssignableFrom(smd.getDAOMetaData().getDAOClass())) { - interpreter = VariableResolverInterpreter; SQL sqlAnnotation = smd.getMethod().getAnnotation(SQL.class); if (sqlAnnotation == null // 没有注解@SQL || PlumUtils.isBlank(sqlAnnotation.value()) // 虽注解但没有写SQL - || "jade-plugin-sql".equals(sqlAnnotation.value())) // 明确表示使用jade-plugin-sql + || SQL_ANNOTATION_MARKUP.equals(sqlAnnotation.value())) // 明确表示使用jade-plugin-sql { + // 将表名、主键名放入DAO的attributes中 + putExtraAttributes(smd.getDAOMetaData()); + // 创建 IOperationMapper IOperationMapper mapper = operationMapperManager.create(smd); + // 生成最后的解析器 interpreter = new SQLGeneratorInterpreter(mapper); } } - smd.setAttribute(interpreterAttribute, interpreter); + smd.setAttribute(ATTRIBUTE_NAME_INTERPRETER, interpreter); } } } @@ -112,7 +141,7 @@ public void interpret(StatementRuntime runtime) { /** * 透传SQL解析器 */ - private static final Interpreter PassThroughInterpreter = new Interpreter() { + private static final Interpreter PASS_THROUGH_INTERPRETER = new Interpreter() { @Override public void interpret(StatementRuntime runtime) { @@ -125,12 +154,30 @@ public void interpret(StatementRuntime runtime) { * 实际SQL解析器 * */ - private class SQLGeneratorInterpreter implements Interpreter { + public class SQLGeneratorInterpreter implements Interpreter { final IOperationMapper operationMapper; + + private IDialect dialect; public SQLGeneratorInterpreter(IOperationMapper operationMapper) { this.operationMapper = operationMapper; + + if(packageScopeDialect != null) { + Class daoClass = operationMapper.getOriginal().getDAOMetaData().getDAOClass(); + String daoPkg = daoClass.getPackage().getName(); + while(daoPkg.contains(".") + && (dialect = packageScopeDialect.get(daoPkg)) == null) { + + // Find the package region dialect layer by layer. + daoPkg = daoPkg.substring(0, daoPkg.lastIndexOf(".")); + } + } + + if(dialect == null) { + // When miss the dialect in package region, use default. + dialect = PlumSQLInterpreter.this.dialect; + } } @Override @@ -148,83 +195,69 @@ public void interpret(StatementRuntime runtime) { } } + public IOperationMapper getOperationMapper() { + return operationMapper; + } + }; + // 以下是临时代码 @Alan /** * 变量解析器(表名、主键名等) - * -- 以下为临时性hardcode代码,不可维护的代码,不和谐的代码,搬到哪里去才能漂亮呢?@Alan */ - private static final Interpreter VariableResolverInterpreter = new Interpreter() { - - @Override - public void interpret(StatementRuntime runtime) { - // 临时hard代码2-1:获取table_name替换原始SQL中的{table_name}变量 - String sql = runtime.getSQL(); - // 替换表名 - if (sql.contains("{table_name}")) { - StatementMetaData smd = runtime.getMetaData(); - DAOMetaData dmd = smd.getDAOMetaData(); - final String tableNameAttribute = "jade-plugin-sql.interpreter"; - String tableName = dmd.getAttribute(tableNameAttribute); - if (tableName == null) { - Class entityType = smd.getDAOMetaData().resolveTypeVariable(// - GenericDAO.class, "E"); - Table tableAnnotation = entityType.getAnnotation(Table.class); - if (tableAnnotation != null) { - tableName = tableAnnotation.value(); - } - if (PlumUtils.isBlank(tableName)) { - tableName = entityType.getSimpleName().substring(0, - entityType.getSimpleName().length() - 2); - tableName = generateName(tableName); - } - dmd.setAttribute(tableNameAttribute, tableName); - } - sql = sql.replace("{table_name}", tableName); - runtime.setSQL(sql); + protected void putExtraAttributes(DAOMetaData md) { + synchronized (md) { + if (md.getAttribute("table_name") != null) { + return; } - // 替换主键 - if (sql.contains("{primary_key}")) { - //TODO: 假装pk都是“id” - sql = sql.replace("{primary_key}", "id"); - runtime.setSQL(sql); + Class entityType = md.resolveTypeVariable(// + GenericDAO.class, "E"); + Table tableAnnotation = entityType.getAnnotation(Table.class); + String tableName = null; + if (tableAnnotation != null) { + tableName = tableAnnotation.value(); } - - // 临时hard代码2-1结束 - + if (PlumUtils.isBlank(tableName)) { + tableName = entityType.getSimpleName().substring(0, + entityType.getSimpleName().length() - 2); + tableName = generateName(tableName); + } + md.setAttribute("{table_name}", tableName); + md.setAttribute("{primary_key}", "id"); // 当前阶段,假装primary_key都是id } + } - // 临时代码2-2,copied from AbstractMapper#generateName - private String generateName(String source) { - if (PlumUtils.isBlank(source)) { - return null; - } + // 以下是临时代码 + // copied from AbstractMapper#generateName + protected String generateName(String source) { + if (PlumUtils.isBlank(source)) { + return null; + } - if (source.matches("^[a-zA-Z\\\\.]+$")) { - StringBuilder result = new StringBuilder(); + if (source.matches("^[a-zA-Z\\\\.]+$")) { + StringBuilder result = new StringBuilder(); - for (int i = 0; i < source.length(); i++) { - char c = source.charAt(i); + for (int i = 0; i < source.length(); i++) { + char c = source.charAt(i); - if (Character.isWhitespace(c)) { - continue; - } + if (Character.isWhitespace(c)) { + continue; + } - if (Character.isUpperCase(c)) { - if (result.length() > 0) { - result.append("_"); - } - result.append(Character.toLowerCase(c)); - } else { - result.append(c); + if (Character.isUpperCase(c)) { + if (result.length() > 0) { + result.append("_"); } + result.append(Character.toLowerCase(c)); + } else { + result.append(c); } - - return result.toString(); - } else { - throw new IllegalArgumentException("Illegal naming conventions."); } + + return result.toString(); + } else { + throw new IllegalArgumentException("Illegal naming conventions."); } - }; + } } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/annotations/Column.java b/src/main/java/net/paoding/rose/jade/plugin/sql/annotations/Column.java index 51b9f31..f0d826e 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/annotations/Column.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/annotations/Column.java @@ -7,6 +7,8 @@ import java.lang.annotation.Target; import net.paoding.rose.jade.plugin.sql.Order.Direction; +import net.paoding.rose.jade.plugin.sql.id.IDGenerator; +import net.paoding.rose.jade.plugin.sql.id.NonID; import java.lang.annotation.ElementType; import java.lang.annotation.RetentionPolicy; @@ -26,9 +28,16 @@ String value() default ""; /** - * 是否为主键,默认false。 + * 主键 * @return */ + Class> id() default NonID.class; + + /** + * 是否为主键 + * @return + */ + @Deprecated boolean pk() default false; /** diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/annotations/Offset.java b/src/main/java/net/paoding/rose/jade/plugin/sql/annotations/Offset.java index 75c0528..60a1007 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/annotations/Offset.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/annotations/Offset.java @@ -9,7 +9,7 @@ import java.lang.annotation.Target; /** - * 查询数据的偏移量 + * 查询数据的偏移量,从0开始。 * @author Alan.Geng[gengzhi718@gmail.com] */ @Target(ElementType.PARAMETER) diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/IDialect.java b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/IDialect.java index 2f0980a..76e3375 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/IDialect.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/IDialect.java @@ -22,5 +22,5 @@ public interface IDialect { * @see IOperationMapper * @see StatementRuntime */ - public String translate(T operation, StatementRuntime runtime); + public String translate(IOperationMapper operation, StatementRuntime runtime); } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/ISQLGenerator.java b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/ISQLGenerator.java index 5a26307..1a9a1e9 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/ISQLGenerator.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/ISQLGenerator.java @@ -3,14 +3,26 @@ */ package net.paoding.rose.jade.plugin.sql.dialect; +import net.paoding.rose.jade.plugin.sql.dialect.mysql.SelectGenerator; +import net.paoding.rose.jade.plugin.sql.dialect.standard.DeleteGenerator; +import net.paoding.rose.jade.plugin.sql.dialect.standard.InsertGenerator; +import net.paoding.rose.jade.plugin.sql.dialect.standard.UpdateGenerator; import net.paoding.rose.jade.plugin.sql.mapper.IOperationMapper; import net.paoding.rose.jade.statement.StatementRuntime; /** - * 查询语句生成器 + * SQL语句生成器

+ * + * 以 MySQL 的实现为例,SQL语句分为2大类,第一大类是条件语句,第二类是插入语句。其中条件语句详细分为查询语句、更新语句、删除语句。 + * + * @see SelectGenerator + * @see UpdateGenerator + * @see DeleteGenerator + * @see InsertGenerator + * * @author Alan.Geng[gengzhi718@gmail.com] */ -public interface ISQLGenerator { +public interface ISQLGenerator { /** * 将某种操作生成SQL @@ -18,6 +30,6 @@ public interface ISQLGenerator { * @param runtime * @return */ - String generate(T operationMapper, StatementRuntime runtime); + String generate(IOperationMapper operationMapper, StatementRuntime runtime); } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/MySQLDialect.java b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/MySQLDialect.java index 2c50bb7..b59faad 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/MySQLDialect.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/MySQLDialect.java @@ -6,10 +6,10 @@ import java.util.HashMap; import java.util.Map; -import net.paoding.rose.jade.plugin.sql.dialect.mysql.DeleteGenerator; -import net.paoding.rose.jade.plugin.sql.dialect.mysql.InsertGenerator; import net.paoding.rose.jade.plugin.sql.dialect.mysql.SelectGenerator; -import net.paoding.rose.jade.plugin.sql.dialect.mysql.UpdateGenerator; +import net.paoding.rose.jade.plugin.sql.dialect.standard.DeleteGenerator; +import net.paoding.rose.jade.plugin.sql.dialect.standard.InsertGenerator; +import net.paoding.rose.jade.plugin.sql.dialect.standard.UpdateGenerator; import net.paoding.rose.jade.plugin.sql.mapper.IOperationMapper; import net.paoding.rose.jade.statement.StatementRuntime; @@ -19,10 +19,10 @@ */ public class MySQLDialect implements IDialect { - private Map> generators; + private Map generators; public MySQLDialect() { - generators = new HashMap>(); + generators = new HashMap(); generators.put(IOperationMapper.OPERATION_SELECT, new SelectGenerator()); generators.put(IOperationMapper.OPERATION_INSERT, new InsertGenerator()); generators.put(IOperationMapper.OPERATION_UPDATE, new UpdateGenerator()); @@ -32,10 +32,9 @@ public MySQLDialect() { /* (non-Javadoc) * @see com.cainiao.depot.project.biz.common.jade.dialect.IDialect#translate(com.cainiao.depot.project.biz.common.jade.mapper.IOperationMapper) */ - @SuppressWarnings("unchecked") @Override - public String translate(T operation, StatementRuntime runtime) { - ISQLGenerator gen = (ISQLGenerator) generators.get(operation.getName()); + public String translate(IOperationMapper operation, StatementRuntime runtime) { + ISQLGenerator gen = (ISQLGenerator) generators.get(operation.getDestName()); if(gen != null) { return gen.generate(operation, runtime); } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/OracleDialect.java b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/OracleDialect.java new file mode 100644 index 0000000..7f5522a --- /dev/null +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/OracleDialect.java @@ -0,0 +1,44 @@ +/** + * + */ +package net.paoding.rose.jade.plugin.sql.dialect; + +import java.util.HashMap; +import java.util.Map; + +import net.paoding.rose.jade.plugin.sql.dialect.oracle.SelectGenerator; +import net.paoding.rose.jade.plugin.sql.dialect.standard.DeleteGenerator; +import net.paoding.rose.jade.plugin.sql.dialect.standard.InsertGenerator; +import net.paoding.rose.jade.plugin.sql.dialect.standard.UpdateGenerator; +import net.paoding.rose.jade.plugin.sql.mapper.IOperationMapper; +import net.paoding.rose.jade.statement.StatementRuntime; + +/** + * @author Alan + * + */ +public class OracleDialect implements IDialect { + +private Map generators; + + public OracleDialect() { + generators = new HashMap(); + generators.put(IOperationMapper.OPERATION_SELECT, new SelectGenerator()); + generators.put(IOperationMapper.OPERATION_INSERT, new InsertGenerator()); + generators.put(IOperationMapper.OPERATION_UPDATE, new UpdateGenerator()); + generators.put(IOperationMapper.OPERATION_DELETE, new DeleteGenerator()); + } + + /* (non-Javadoc) + * @see com.cainiao.depot.project.biz.common.jade.dialect.IDialect#translate(com.cainiao.depot.project.biz.common.jade.mapper.IOperationMapper) + */ + @Override + public String translate(IOperationMapper operation, StatementRuntime runtime) { + ISQLGenerator gen = (ISQLGenerator) generators.get(operation.getDestName()); + if(gen != null) { + return gen.generate(operation, runtime); + } + return null; + } + +} diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/mysql/InsertGenerator.java b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/mysql/InsertGenerator.java deleted file mode 100644 index a297860..0000000 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/mysql/InsertGenerator.java +++ /dev/null @@ -1,73 +0,0 @@ -/** - * - */ -package net.paoding.rose.jade.plugin.sql.dialect.mysql; - -import java.util.List; - -import net.paoding.rose.jade.plugin.sql.dialect.ISQLGenerator; -import net.paoding.rose.jade.plugin.sql.mapper.IEntityMapper; -import net.paoding.rose.jade.plugin.sql.mapper.IExpandableParameterMapper; -import net.paoding.rose.jade.plugin.sql.mapper.IOperationMapper; -import net.paoding.rose.jade.plugin.sql.mapper.IParameterMapper; -import net.paoding.rose.jade.plugin.sql.mapper.OperationMapper; -import net.paoding.rose.jade.statement.StatementRuntime; - -import org.springframework.util.CollectionUtils; - -/** - * @author Alan.Geng[gengzhi718@gmail.com] - * - */ -public class InsertGenerator implements ISQLGenerator { - - /* (non-Javadoc) - * @see com.cainiao.depot.project.biz.common.jade.dialect.ISQLGenerator#generate(com.cainiao.depot.project.biz.common.jade.mapper.IOperationMapper) - */ - @Override - public String generate(OperationMapper operationMapper, StatementRuntime runtime) { - if(!operationMapper.getName().equals(IOperationMapper.OPERATION_INSERT)) { - throw new IllegalArgumentException("Operation mapper must be a insert."); - } - - List parameters = operationMapper.getParameters(); - - if(CollectionUtils.isEmpty(parameters)) { - throw new IllegalArgumentException("Update operation must have parameters."); - } - - IEntityMapper targetEntityMapper = operationMapper.getTargetEntityMapper(); - - IParameterMapper entityParam = parameters.get(0); - - if(entityParam instanceof IExpandableParameterMapper) { - List expandParams = ((IExpandableParameterMapper) entityParam).expand(); - StringBuilder sql = new StringBuilder("INSERT INTO "); - StringBuilder values = new StringBuilder(); - sql.append(targetEntityMapper.getName()); - sql.append("("); - - for(IParameterMapper param : expandParams) { - sql.append(param.getColumnMapper().getName()); - sql.append(","); - - values.append(":"); - values.append(entityParam.getName()); - values.append("."); - values.append(param.getColumnMapper().getOriginalName()); - values.append(","); - } - sql.setLength(sql.length() - 1); - values.setLength(values.length() - 1); - - sql.append(")VALUES("); - sql.append(values.toString()); - sql.append(")"); - - return sql.toString(); - } else { - throw new IllegalArgumentException("Parameter \"" + entityParam.getOriginalName() + "\" cannot expend."); - } - } - -} diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/mysql/SelectGenerator.java b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/mysql/SelectGenerator.java index f100ca2..d6b61d9 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/mysql/SelectGenerator.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/mysql/SelectGenerator.java @@ -3,122 +3,25 @@ */ package net.paoding.rose.jade.plugin.sql.dialect.mysql; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; import java.util.Map; -import net.paoding.rose.jade.plugin.sql.Order; -import net.paoding.rose.jade.plugin.sql.Order.Direction; -import net.paoding.rose.jade.plugin.sql.Order.Group; +import net.paoding.rose.jade.plugin.sql.dialect.standard.AbstractSelectGenerator; import net.paoding.rose.jade.plugin.sql.mapper.ConditionalOperationMapper; -import net.paoding.rose.jade.plugin.sql.mapper.IColumnMapper; -import net.paoding.rose.jade.plugin.sql.mapper.IEntityMapper; import net.paoding.rose.jade.statement.StatementRuntime; /** * @author Alan.Geng[gengzhi718@gmail.com] * */ -public class SelectGenerator extends ConditionalGenerator { +public class SelectGenerator extends AbstractSelectGenerator { - private static final Map DIRECTIONS; - - static { - Map directions = new HashMap(2); - directions.put(Direction.ASC, "ASC"); - directions.put(Direction.DESC, "DESC"); - - DIRECTIONS = Collections.unmodifiableMap(directions); - } - - @Override - protected void beforeApplyConditions(ConditionalOperationMapper operationMapper, StatementRuntime runtime, StringBuilder sql) { - super.beforeApplyConditions(operationMapper, runtime, sql); - IEntityMapper targetEntityMapper = operationMapper.getTargetEntityMapper(); - List columns = targetEntityMapper.getColumns(); - - sql.append(operationMapper.getName()); - sql.append(" "); - - for(IColumnMapper col : columns) { - String name = col.getName(); - sql.append(name); - sql.append(","); - } - - sql.setLength(sql.length() - 1); - sql.append(" FROM "); - sql.append(targetEntityMapper.getName()); - } - - @Override - protected void afterApplyConditions(ConditionalOperationMapper operationMapper, StatementRuntime runtime, StringBuilder sql) { - super.afterApplyConditions(operationMapper, runtime, sql); - applyOrderBy(operationMapper, runtime, sql); - applyRange(operationMapper, runtime, sql); - } - - protected void applyOrderBy(ConditionalOperationMapper operationMapper, StatementRuntime runtime, StringBuilder sql) { - if(operationMapper.containsOrder()) { - IEntityMapper targetEntityMapper = operationMapper.getTargetEntityMapper(); - - Order order = null; - Integer orderParameterIndex = operationMapper.getOrderParameterIndex(); - - if(orderParameterIndex == -1) { - order = targetEntityMapper.getDefaultOrder(); - } else { - Object value = runtime.getParameters().get(":" + (operationMapper.getOrderParameterIndex() + 1)); - order = (Order) value; - } - - sql.append(" ORDER BY "); - - List groups = order.getGroups(); - - if(groups.size() > 0) { - for(Group group : groups) { - String[] fields = group.getFields(); - - for(String field : fields) { - IColumnMapper col = targetEntityMapper.getColumnMapperByFieldName(field); - - if(col != null) { - - sql.append(col.getName()); - sql.append(" "); - sql.append(DIRECTIONS.get(group.getDirection())); - sql.append(","); - } else { - throw new IllegalArgumentException("Cannot find column by field name \"" + field + "\"."); - } - } - } - - sql.setLength(sql.length() - 1); - } - } - } - - protected void applyRange(ConditionalOperationMapper operationMapper, StatementRuntime runtime, StringBuilder sql) { + protected StringBuilder applyRange(ConditionalOperationMapper operationMapper, + StatementRuntime runtime, + StringBuilder sql, + Long offset, + Long limit) { Map parameters = runtime.getParameters(); - Number offset = null; - Number limit = null; - - if(operationMapper.containsOffset()) { - offset = (Number) parameters.get(":" + (operationMapper.getOffsetParameterIndex() + 1)); - } - - if(operationMapper.containsLimit()) { - limit = (Number) parameters.get(":" + (operationMapper.getLimitParameterIndex() + 1)); - } - - if(limit == null && offset == null) { - return; - } - sql.append(" LIMIT :__offset, :__limit"); if(limit != null && offset != null) { @@ -127,9 +30,11 @@ protected void applyRange(ConditionalOperationMapper operationMapper, StatementR } else if(offset != null) { parameters.put("__offset", offset); parameters.put("__limit", -1); - } else if(limit != null && limit.longValue() >= 0) { + } else if(limit != null && limit >= 0) { parameters.put("__offset", 0); parameters.put("__limit", limit); } + + return sql; } } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/oracle/SelectGenerator.java b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/oracle/SelectGenerator.java new file mode 100644 index 0000000..e70e66c --- /dev/null +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/oracle/SelectGenerator.java @@ -0,0 +1,95 @@ +/** + * + */ +package net.paoding.rose.jade.plugin.sql.dialect.oracle; + +import java.util.Map; + +import net.paoding.rose.jade.plugin.sql.dialect.standard.AbstractSelectGenerator; +import net.paoding.rose.jade.plugin.sql.mapper.ConditionalOperationMapper; +import net.paoding.rose.jade.plugin.sql.mapper.IColumnMapper; +import net.paoding.rose.jade.statement.StatementRuntime; + +/** + * @author Alan + * + */ +public class SelectGenerator extends AbstractSelectGenerator { + + protected static final String ROWNUM_ALIAS = "RN"; + + /* (non-Javadoc) + * @see net.paoding.rose.jade.plugin.sql.dialect.standard.AbstractSelectGenerator#applyRange(net.paoding.rose.jade.plugin.sql.mapper.ConditionalOperationMapper, net.paoding.rose.jade.statement.StatementRuntime, java.lang.StringBuilder, java.lang.Number, java.lang.Number) + */ + @Override + protected StringBuilder applyRange(ConditionalOperationMapper operationMapper, + StatementRuntime runtime, StringBuilder sql, Long offset, + Long limit) { + + Map parameters = runtime.getParameters(); + + // 在Oracle数据库版本12g之前,limit与offset通过ROWNUM计算,且offset必须使用子查询。 + Long realOffset = null; + + if(offset == null) { + offset = 0L; + } + + if(offset != null) { + realOffset = offset + 1; + } + + if(limit != null && limit > 0) { + if(containsConditions()) { + sql.append(" AND "); + } + sql.append(" ROWNUM < :__limit"); + parameters.put("__limit", realOffset + limit); + } + + if(offset != null && offset > 1) { + StringBuilder outerSql = new StringBuilder(operationMapper.getDestName()); + outerSql.append(" "); + applyColumns(operationMapper.getTargetEntityMapper(), outerSql); + + outerSql.append(" FROM ("); + outerSql.append(sql); + outerSql.append(") WHERE "); + outerSql.append(ROWNUM_ALIAS); + outerSql.append(" >= :__offset"); + + parameters.put("__offset", realOffset); + + sql = outerSql; + } + + return sql; + } + + @Override + protected void applyColumns(ConditionalOperationMapper operationMapper, StatementRuntime runtime, + StringBuilder sql) { + super.applyColumns(operationMapper, runtime, sql); + + if(!operationMapper.isCountQuery() + && operationMapper.containsOffset()) { + Number val = (Number) runtime.getParameters().get(":" + (operationMapper.getOffsetParameterIndex() + 1)); + if(val != null + && val.longValue() > 1) { + // 提供给外部查询做偏移量判定 + sql.append(", ROWNUM "); + sql.append(ROWNUM_ALIAS); + } + } + } + + @Override + protected String getColumnAlias(IColumnMapper column) { + if(column.getDestName().startsWith("\"") + && column.getDestName().endsWith("\"")) { + return "\"" + super.getColumnAlias(column) + "\""; + } + return super.getColumnAlias(column); + } + +} diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/standard/AbstractSelectGenerator.java b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/standard/AbstractSelectGenerator.java new file mode 100644 index 0000000..9413685 --- /dev/null +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/standard/AbstractSelectGenerator.java @@ -0,0 +1,163 @@ +/** + * + */ +package net.paoding.rose.jade.plugin.sql.dialect.standard; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.paoding.rose.jade.plugin.sql.Order; +import net.paoding.rose.jade.plugin.sql.Order.Direction; +import net.paoding.rose.jade.plugin.sql.Order.Group; +import net.paoding.rose.jade.plugin.sql.dialect.standard.ConditionalGenerator; +import net.paoding.rose.jade.plugin.sql.mapper.ConditionalOperationMapper; +import net.paoding.rose.jade.plugin.sql.mapper.IColumnMapper; +import net.paoding.rose.jade.plugin.sql.mapper.IEntityMapper; +import net.paoding.rose.jade.statement.StatementRuntime; + +/** + * @author Alan.Geng[gengzhi718@gmail.com] + * + */ +public abstract class AbstractSelectGenerator extends ConditionalGenerator { + + private static final Map DIRECTIONS; + + static { + Map directions = new HashMap(2); + directions.put(Direction.ASC, "ASC"); + directions.put(Direction.DESC, "DESC"); + + DIRECTIONS = Collections.unmodifiableMap(directions); + } + + @Override + protected StringBuilder beforeApplyConditions(ConditionalOperationMapper operationMapper, StatementRuntime runtime, StringBuilder sql) { + super.beforeApplyConditions(operationMapper, runtime, sql); + IEntityMapper targetEntityMapper = operationMapper.getTargetEntityMapper(); + sql.append(operationMapper.getDestName()); + sql.append(" "); + + applyColumns(operationMapper, runtime, sql); + + sql.append(" FROM "); + sql.append(targetEntityMapper.getDestName()); + + return sql; + } + + protected void applyColumns(ConditionalOperationMapper operationMapper, StatementRuntime runtime, StringBuilder sql) { + IEntityMapper targetEntityMapper = operationMapper.getTargetEntityMapper(); + if(operationMapper.isCountQuery()) { + sql.append("COUNT(*)"); + } else { + applyColumns(targetEntityMapper, sql); + } + } + + protected void applyColumns(IEntityMapper targetEntityMapper, StringBuilder sql) { + List columns = targetEntityMapper.getColumns(); + + for(IColumnMapper col : columns) { + String name = col.getDestName(); + sql.append(name); + sql.append(" "); + sql.append(getColumnAlias(col)); + sql.append(","); + } + + sql.setLength(sql.length() - 1); + } + + protected String getColumnAlias(IColumnMapper column) { + return column.getOriginalName(); + } + + @Override + protected StringBuilder afterApplyConditions(ConditionalOperationMapper operationMapper, StatementRuntime runtime, StringBuilder sql) { + super.afterApplyConditions(operationMapper, runtime, sql); + + if(!operationMapper.isCountQuery()) { + // 节省数据库性能开销,count操作不需要orderBy。 + sql = applyOrderBy(operationMapper, runtime, sql); + } + + Map parameters = runtime.getParameters(); + + Long offset = null; + Long limit = null; + + if(operationMapper.containsOffset()) { + Number val = (Number) parameters.get(":" + (operationMapper.getOffsetParameterIndex() + 1)); + if(val != null) { + offset = val.longValue(); + } + } + + if(operationMapper.containsLimit()) { + Number val = (Number) parameters.get(":" + (operationMapper.getLimitParameterIndex() + 1)); + if(val != null) { + limit = val.longValue(); + } + } + + if(limit != null || offset != null) { + sql = applyRange(operationMapper, runtime, sql, offset, limit); + } + + return sql; + } + + protected StringBuilder applyOrderBy(ConditionalOperationMapper operationMapper, StatementRuntime runtime, StringBuilder sql) { + if(operationMapper.containsOrder() + && !operationMapper.isPrimaryKeyMode()) { + IEntityMapper targetEntityMapper = operationMapper.getTargetEntityMapper(); + + Order order = null; + Integer orderParameterIndex = operationMapper.getOrderParameterIndex(); + + if(orderParameterIndex == -1) { + order = targetEntityMapper.getDefaultOrder(); + } else { + Object value = runtime.getParameters().get(":" + (operationMapper.getOrderParameterIndex() + 1)); + order = (Order) value; + } + + sql.append(" ORDER BY "); + + List groups = order.getGroups(); + + if(groups.size() > 0) { + for(Group group : groups) { + String[] fields = group.getFields(); + + for(String field : fields) { + IColumnMapper col = targetEntityMapper.getColumnMapperByFieldName(field); + + if(col != null) { + + sql.append(col.getDestName()); + sql.append(" "); + sql.append(DIRECTIONS.get(group.getDirection())); + sql.append(","); + } else { + throw new IllegalArgumentException("Cannot find column by field name \"" + field + "\"."); + } + } + } + + sql.setLength(sql.length() - 1); + } + } + + return sql; + } + + protected abstract StringBuilder applyRange(ConditionalOperationMapper operationMapper, + StatementRuntime runtime, + StringBuilder sql, + Long offset, + Long limit); +} diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/mysql/ConditionalGenerator.java b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/standard/ConditionalGenerator.java similarity index 72% rename from src/main/java/net/paoding/rose/jade/plugin/sql/dialect/mysql/ConditionalGenerator.java rename to src/main/java/net/paoding/rose/jade/plugin/sql/dialect/standard/ConditionalGenerator.java index 6668939..457f63c 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/mysql/ConditionalGenerator.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/standard/ConditionalGenerator.java @@ -1,7 +1,7 @@ /** * */ -package net.paoding.rose.jade.plugin.sql.dialect.mysql; +package net.paoding.rose.jade.plugin.sql.dialect.standard; import java.util.Collections; import java.util.HashMap; @@ -12,6 +12,7 @@ import net.paoding.rose.jade.plugin.sql.dialect.ISQLGenerator; import net.paoding.rose.jade.plugin.sql.mapper.ConditionalOperationMapper; import net.paoding.rose.jade.plugin.sql.mapper.IColumnMapper; +import net.paoding.rose.jade.plugin.sql.mapper.IOperationMapper; import net.paoding.rose.jade.plugin.sql.mapper.IParameterMapper; import net.paoding.rose.jade.plugin.sql.util.PlumUtils; import net.paoding.rose.jade.statement.StatementRuntime; @@ -20,10 +21,12 @@ * @author Alan.Geng[gengzhi718@gmail.com] * */ -public abstract class ConditionalGenerator implements ISQLGenerator { +public abstract class ConditionalGenerator implements ISQLGenerator { private static final Map OPERATORS; + private boolean containsConditions = false; + static { Map operators = new HashMap(Operator.values().length); operators.put(Operator.EQ, " = "); @@ -39,15 +42,15 @@ public abstract class ConditionalGenerator implements ISQLGenerator primaryKey = operationMapper.getTargetEntityMapper().getPrimaryKey(); @@ -58,13 +61,19 @@ protected void applyConditions(ConditionalOperationMapper operationMapper, State sql.append(" AND "); } - sql.append(col.getName()); + sql.append(col.getDestName()); sql.append(" = "); sql.append(":"); - // TODO:当实体为符合主键并且参数列表中的顺序与实体中字段顺序不一致,则会发生错误。 - sql.append(i + 1); + // 复合主键一定要在DAO方法中的指明各个参数名,并与Bean的字段名(field.getName)一致 + if (primaryKey.size() > 1) { + sql.append(col.getOriginal().getName()); + } else { + sql.append(i + 1); + } } + + containsConditions = true; } else if(operationMapper.isComplexMode()) { List parameters = operationMapper.getParameters(); if(PlumUtils.isNotEmpty(parameters)) { @@ -82,6 +91,7 @@ protected void applyConditions(ConditionalOperationMapper operationMapper, State if(condition != null) { if(and.length() == 0) { sql.append(" WHERE "); + containsConditions = true; } sql.append(and); sql.append(condition); @@ -92,6 +102,7 @@ protected void applyConditions(ConditionalOperationMapper operationMapper, State } else { throw new UnsupportedOperationException("Unknown condition mode."); } + return sql; } protected String generateCondition(ConditionalOperationMapper operationMapper, IParameterMapper param, StatementRuntime runtime, int index) { @@ -115,7 +126,7 @@ protected String generateCondition(ConditionalOperationMapper operationMapper, I StringBuilder sql = new StringBuilder(); - sql.append(param.getName()); + sql.append(param.getDestName()); if(op != Operator.LIKE && op != Operator.EQ @@ -146,12 +157,16 @@ protected String generateCondition(ConditionalOperationMapper operationMapper, I return sql.toString(); } - protected void beforeApplyConditions(ConditionalOperationMapper operationMapper, StatementRuntime runtime, StringBuilder sql) { - + protected StringBuilder beforeApplyConditions(ConditionalOperationMapper operationMapper, StatementRuntime runtime, StringBuilder sql) { + return sql; } - protected void afterApplyConditions(ConditionalOperationMapper operationMapper, StatementRuntime runtime, StringBuilder sql) { - + protected StringBuilder afterApplyConditions(ConditionalOperationMapper operationMapper, StatementRuntime runtime, StringBuilder sql) { + return sql; + } + + protected boolean containsConditions() { + return containsConditions; } } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/mysql/DeleteGenerator.java b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/standard/DeleteGenerator.java similarity index 61% rename from src/main/java/net/paoding/rose/jade/plugin/sql/dialect/mysql/DeleteGenerator.java rename to src/main/java/net/paoding/rose/jade/plugin/sql/dialect/standard/DeleteGenerator.java index 2340783..d99c5b8 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/mysql/DeleteGenerator.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/standard/DeleteGenerator.java @@ -1,7 +1,7 @@ /** * */ -package net.paoding.rose.jade.plugin.sql.dialect.mysql; +package net.paoding.rose.jade.plugin.sql.dialect.standard; import net.paoding.rose.jade.plugin.sql.mapper.ConditionalOperationMapper; import net.paoding.rose.jade.statement.StatementRuntime; @@ -13,13 +13,14 @@ public class DeleteGenerator extends ConditionalGenerator { @Override - protected void beforeApplyConditions( + protected StringBuilder beforeApplyConditions( ConditionalOperationMapper operationMapper, StatementRuntime runtime, StringBuilder sql) { - super.beforeApplyConditions(operationMapper, runtime, sql); - + sql = super.beforeApplyConditions(operationMapper, runtime, sql); sql.append("DELETE FROM "); - sql.append(operationMapper.getTargetEntityMapper().getName()); + sql.append(operationMapper.getTargetEntityMapper().getDestName()); + + return sql; } } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/standard/InsertGenerator.java b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/standard/InsertGenerator.java new file mode 100644 index 0000000..c094ac3 --- /dev/null +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/standard/InsertGenerator.java @@ -0,0 +1,106 @@ +/** + * + */ +package net.paoding.rose.jade.plugin.sql.dialect.standard; + +import java.util.List; + +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.util.CollectionUtils; + +import net.paoding.rose.jade.plugin.sql.dialect.ISQLGenerator; +import net.paoding.rose.jade.plugin.sql.id.CachedIDGeneratorManager; +import net.paoding.rose.jade.plugin.sql.id.IDGenerator; +import net.paoding.rose.jade.plugin.sql.id.IDGeneratorManager; +import net.paoding.rose.jade.plugin.sql.id.ManualGenerator; +import net.paoding.rose.jade.plugin.sql.id.NativeGenerator; +import net.paoding.rose.jade.plugin.sql.id.NonID; +import net.paoding.rose.jade.plugin.sql.mapper.IColumnMapper; +import net.paoding.rose.jade.plugin.sql.mapper.IEntityMapper; +import net.paoding.rose.jade.plugin.sql.mapper.IExpandableParameterMapper; +import net.paoding.rose.jade.plugin.sql.mapper.IOperationMapper; +import net.paoding.rose.jade.plugin.sql.mapper.IParameterMapper; +import net.paoding.rose.jade.statement.StatementRuntime; + +/** + * @author Alan.Geng[gengzhi718@gmail.com] + * + */ +public class InsertGenerator implements ISQLGenerator { + + private IDGeneratorManager idGeneratorManager = new CachedIDGeneratorManager(); + + /* (non-Javadoc) + * @see com.cainiao.depot.project.biz.common.jade.dialect.ISQLGenerator#generate(com.cainiao.depot.project.biz.common.jade.mapper.IOperationMapper) + */ + @Override + public String generate(IOperationMapper operationMapper, StatementRuntime runtime) { + if(!operationMapper.getDestName().equals(IOperationMapper.OPERATION_INSERT)) { + throw new IllegalArgumentException("Operation mapper must be a insert."); + } + + List parameters = operationMapper.getParameters(); + + if(CollectionUtils.isEmpty(parameters)) { + throw new IllegalArgumentException("Update operation must have parameters."); + } + + IEntityMapper targetEntityMapper = operationMapper.getTargetEntityMapper(); + + IParameterMapper entityParam = parameters.get(0); + + if(entityParam instanceof IExpandableParameterMapper) { + List expandParams = ((IExpandableParameterMapper) entityParam).expand(); + StringBuilder sql = new StringBuilder(500); + StringBuilder values = new StringBuilder(); + sql.append("INSERT INTO "); + sql.append(targetEntityMapper.getDestName()); + sql.append("("); + + for(IParameterMapper param : expandParams) { + IColumnMapper columnMapper = param.getColumnMapper(); + if(columnMapper.isPrimaryKey()) { + Class> idGeneratorType = columnMapper.getIDGeneratorType(); + + if(idGeneratorType == NativeGenerator.class + // 兼容pk属性 + || idGeneratorType == NonID.class) { + // 数据库自增型ID在插入时不做任何处理,也不参与插入字段。 + continue; + } else if(idGeneratorType != ManualGenerator.class){ + // 非手动设置ID,则需要生成值。 + IDGenerator idGenerator = idGeneratorManager.get(idGeneratorType); + if(idGenerator != null) { + Object entity = runtime.getParameters().get(":1"); + Object idValue = idGenerator.generate(entity); + + try { + columnMapper.getOriginal().set(entity, idValue); + } catch (Exception e) { + throw new InvalidDataAccessApiUsageException("Cannot set id to entity property."); + } + } + } + } + + sql.append(param.getColumnMapper().getDestName()); + sql.append(","); + + values.append(":1."); + values.append(param.getColumnMapper().getOriginalName()); + values.append(","); + } + sql.setLength(sql.length() - 1); + values.setLength(values.length() - 1); + + sql.append(")VALUES("); + sql.append(values); + sql.append(")"); + + return sql.toString(); + } else { + throw new IllegalArgumentException("Parameter \"" + entityParam.getOriginalName() + "\" cannot expend."); + } + } + +} diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/mysql/UpdateGenerator.java b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/standard/UpdateGenerator.java similarity index 52% rename from src/main/java/net/paoding/rose/jade/plugin/sql/dialect/mysql/UpdateGenerator.java rename to src/main/java/net/paoding/rose/jade/plugin/sql/dialect/standard/UpdateGenerator.java index d394856..170b8e9 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/mysql/UpdateGenerator.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/dialect/standard/UpdateGenerator.java @@ -1,7 +1,7 @@ /** * */ -package net.paoding.rose.jade.plugin.sql.dialect.mysql; +package net.paoding.rose.jade.plugin.sql.dialect.standard; import java.lang.reflect.Field; import java.util.List; @@ -25,24 +25,26 @@ public class UpdateGenerator extends ConditionalGenerator { @Override - protected void beforeApplyConditions( + protected StringBuilder beforeApplyConditions( ConditionalOperationMapper operationMapper, StatementRuntime runtime, StringBuilder sql) { - super.beforeApplyConditions(operationMapper, runtime, sql); + sql = super.beforeApplyConditions(operationMapper, runtime, sql); sql.append("UPDATE "); - sql.append(operationMapper.getTargetEntityMapper().getName()); + sql.append(operationMapper.getTargetEntityMapper().getDestName()); + + return sql; } @Override - public void applyConditions(ConditionalOperationMapper operationMapper, + public StringBuilder applyConditions(ConditionalOperationMapper operationMapper, StatementRuntime runtime, StringBuilder sql) { if(operationMapper.isEntityMode() || operationMapper.isEntityCollectionMode()) { // 通过实体或实体集合更新 Map parametersValue = runtime.getParameters(); - if(!operationMapper.getName().equals(IOperationMapper.OPERATION_UPDATE)) { + if(!operationMapper.getDestName().equals(IOperationMapper.OPERATION_UPDATE)) { throw new InvalidDataAccessApiUsageException("Operation mapper must be a update."); } @@ -59,7 +61,7 @@ public void applyConditions(ConditionalOperationMapper operationMapper, if(param instanceof IExpandableParameterMapper) { List expandParams = ((IExpandableParameterMapper) param).expand(); - Object parameterValue = parametersValue.entrySet().iterator().next().getValue(); + Object parameterValue = parametersValue.get(":1"); sql.append(" SET "); for(IParameterMapper p : expandParams) { @@ -75,7 +77,7 @@ public void applyConditions(ConditionalOperationMapper operationMapper, if(p.getColumnMapper().isPrimaryKey()) { // 主键视为条件 if(value == null) { - throw new IllegalArgumentException("Cannot execute update, primary key \"" + p.getColumnMapper().getName() + "\" must not be null."); + throw new IllegalArgumentException("Cannot execute update, primary key \"" + p.getColumnMapper().getDestName() + "\" must not be null."); } if(where.length() > 0) { @@ -84,21 +86,17 @@ public void applyConditions(ConditionalOperationMapper operationMapper, where.append(" WHERE "); } - where.append(p.getColumnMapper().getName()); - where.append(" = :"); - where.append(param.getName()); - where.append("."); + where.append(p.getColumnMapper().getDestName()); + where.append(" = :1."); where.append(p.getColumnMapper().getOriginalName()); } else { if(param.isIgnoreNull() && value == null) { continue; } else { - sql.append(p.getColumnMapper().getName()); + sql.append(p.getColumnMapper().getDestName()); sql.append(" = "); - sql.append(":"); - sql.append(param.getName()); - sql.append("."); + sql.append(":1."); sql.append(p.getColumnMapper().getOriginalName()); sql.append(","); } @@ -131,7 +129,7 @@ public void applyConditions(ConditionalOperationMapper operationMapper, if(sql.length() == start) { sql.append(" SET "); } - sql.append(param.getName()); + sql.append(param.getDestName()); sql.append(" = :"); sql.append(param.getOriginalName()); sql.append(","); @@ -144,89 +142,10 @@ public void applyConditions(ConditionalOperationMapper operationMapper, if(sql.charAt(sql.length() - 1) == ',') { sql.setLength(sql.length() - 1); } - super.applyConditions(operationMapper, runtime, sql); - } - } - - /* (non-Javadoc) - * @see com.cainiao.depot.project.biz.common.jade.dialect.ISQLGenerator#generate(com.cainiao.depot.project.biz.common.jade.mapper.IOperationMapper) - */ - /* - @Override - public String generate(OperationMapper operationMapper, StatementRuntime runtime) { - Map params = runtime.getParameters(); - if(!operationMapper.getName().equals(IOperationMapper.OPERATION_UPDATE)) { - throw new InvalidDataAccessApiUsageException("Operation mapper must be a update."); - } - - List parameters = operationMapper.getParameters(); - if(MyLangUtils.isEmpty(parameters)) { - throw new InvalidDataAccessApiUsageException("Update operation must have parameters."); + sql = super.applyConditions(operationMapper, runtime, sql); } - IEntityMapper targetEntityMapper = operationMapper.getTargetEntityMapper(); - - if(parameters.size() == 1 && parameters.get(0).getType().equals(targetEntityMapper.getOriginal())) { - StringBuilder sql = new StringBuilder(256); - sql.append("UPDATE "); - StringBuilder where = new StringBuilder(32); - sql.append(targetEntityMapper.getName()); - - IParameterMapper param = parameters.get(0); - - if(param instanceof IExpandableParameterMapper) { - List expandParams = ((IExpandableParameterMapper) param).expand(); - Object entityObject = params.entrySet().iterator().next().getValue(); - - sql.append(" SET"); - try { - for(IParameterMapper p : expandParams) { - IColumnMapper columnMapper = p.getColumnMapper(); - if(columnMapper != null) { - Field field = p.getColumnMapper().getOriginal(); - Object value = field.get(entityObject); - if(p.getColumnMapper().isPrimaryKey()) { - // 主键视为条件 - if(value == null) { - throw new IllegalArgumentException("Cannot execute update, primary key \"" + p.getColumnMapper().getName() + "\" must not be null."); - } - - if(where.length() > 0) { - where.append(" AND "); - } else { - where.append(" WHERE "); - } - - where.append(p.getName()); - where.append(" = :"); - where.append(p.getOriginalName()); - } else { - if(value != null) { - sql.append(" "); - sql.append(p.getName()); - sql.append(" = "); - sql.append(":"); - sql.append(p.getOriginalName()); - sql.append(","); - } - } - } - } - sql.setLength(sql.length() - 1); - sql.append(where); - } catch(IllegalArgumentException e) { - throw new InvalidDataAccessApiUsageException("", e); - } catch (Exception e) { - throw new InvalidDataAccessApiUsageException("Cannot generate sql.", e); - } - } else { - throw new InvalidDataAccessApiUsageException("Auto update operation parameter must be a expandable."); - } - - return sql.toString(); - } else { - throw new InvalidDataAccessApiUsageException("Please use the entity object to update."); - } + return sql; } - */ + } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/id/AutoIncrementProcessor.java b/src/main/java/net/paoding/rose/jade/plugin/sql/id/AutoIncrementProcessor.java new file mode 100644 index 0000000..0bef11f --- /dev/null +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/id/AutoIncrementProcessor.java @@ -0,0 +1,87 @@ +/** + * + */ +package net.paoding.rose.jade.plugin.sql.id; + +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import net.paoding.rose.jade.plugin.sql.PlumSQLInterpreter; +import net.paoding.rose.jade.plugin.sql.PlumSQLInterpreter.SQLGeneratorInterpreter; +import net.paoding.rose.jade.plugin.sql.mapper.IColumnMapper; +import net.paoding.rose.jade.plugin.sql.mapper.IEntityMapper; +import net.paoding.rose.jade.plugin.sql.mapper.IOperationMapper; +import net.paoding.rose.jade.statement.AfterInvocationCallback; +import net.paoding.rose.jade.statement.DynamicReturnGeneratedKeys; +import net.paoding.rose.jade.statement.StatementMetaData; +import net.paoding.rose.jade.statement.StatementRuntime; + +/** + * @author cunxin.gz + * + */ +public class AutoIncrementProcessor extends DynamicReturnGeneratedKeys implements AfterInvocationCallback { + + private Log logger = LogFactory.getLog(getClass()); + + /* (non-Javadoc) + * @see net.paoding.rose.jade.statement.AfterInvocationCallback#execute(net.paoding.rose.jade.statement.StatementRuntime, java.lang.Object) + */ + @Override + public Object execute(StatementRuntime runtime, Object returnValue) { + SQLGeneratorInterpreter attribute = runtime.getMetaData().getAttribute(PlumSQLInterpreter.ATTRIBUTE_NAME_INTERPRETER); + if(attribute != null) { + IOperationMapper operationMapper = attribute.getOperationMapper(); + + if(IOperationMapper.OPERATION_INSERT.equals(operationMapper.getDestName())) { + IEntityMapper targetEntityMapper = operationMapper.getTargetEntityMapper(); + + if(targetEntityMapper.containsAutoIncrementPrimaryKey()) { + if(returnValue.getClass().isArray()) { + + } else { + Object param = runtime.getParameters().get(":1"); + List primaryKey = targetEntityMapper.getPrimaryKey(); + IColumnMapper iColumnMapper = primaryKey.get(0); + try { + iColumnMapper.getOriginal().set(param, returnValue); + } catch (Exception e) { + logger.error("Error to set auto increment value to entity object.", e); + } + } + } + } + + } + return returnValue; + } + + @Override + public boolean shouldReturnGerneratedKeys(StatementRuntime runtime) { + return isAutoIncrementPrimaryKey(runtime.getMetaData()); + } + + @Override + public void checkMethodReturnType(Class returnType, StatementMetaData metaData) { + if(isAutoIncrementPrimaryKey(metaData)) { + super.checkMethodReturnType(returnType, metaData); + } + } + + private boolean isAutoIncrementPrimaryKey(StatementMetaData metaData) { + SQLGeneratorInterpreter attribute = metaData.getAttribute(PlumSQLInterpreter.ATTRIBUTE_NAME_INTERPRETER); + + if(attribute != null) { + IOperationMapper operationMapper = attribute.getOperationMapper(); + + if(IOperationMapper.OPERATION_INSERT.equals(operationMapper.getDestName())) { + IEntityMapper targetEntityMapper = operationMapper.getTargetEntityMapper(); + return targetEntityMapper.containsAutoIncrementPrimaryKey(); + } + } + return false; + } + +} diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/id/CachedIDGeneratorManager.java b/src/main/java/net/paoding/rose/jade/plugin/sql/id/CachedIDGeneratorManager.java new file mode 100644 index 0000000..d597e65 --- /dev/null +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/id/CachedIDGeneratorManager.java @@ -0,0 +1,48 @@ +/** + * + */ +package net.paoding.rose.jade.plugin.sql.id; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; + +/** + * @author Alan + * + */ +public class CachedIDGeneratorManager implements IDGeneratorManager { + + private final CacheLoader>, IDGenerator> loader = new CacheLoader>, IDGenerator>() { + + @Override + public IDGenerator load(Class> key) + throws Exception { + return create(key); + } + }; + + private LoadingCache>, IDGenerator> cache = CacheBuilder.newBuilder().build(loader); + + /* (non-Javadoc) + * @see net.paoding.rose.jade.plugin.sql.id.IDGeneratorManager#get(java.lang.Class) + */ + @Override + public IDGenerator get(Class> type) { + try { + return cache.get(type); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public IDGenerator create(Class> type) { + try { + return type.newInstance(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/id/IDGenerator.java b/src/main/java/net/paoding/rose/jade/plugin/sql/id/IDGenerator.java new file mode 100644 index 0000000..2713625 --- /dev/null +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/id/IDGenerator.java @@ -0,0 +1,14 @@ +/** + * + */ +package net.paoding.rose.jade.plugin.sql.id; + +/** + * @author Alan + * + */ +public interface IDGenerator { + + public T generate(Object entity); + +} diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/id/IDGeneratorManager.java b/src/main/java/net/paoding/rose/jade/plugin/sql/id/IDGeneratorManager.java new file mode 100644 index 0000000..524d7e4 --- /dev/null +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/id/IDGeneratorManager.java @@ -0,0 +1,16 @@ +/** + * + */ +package net.paoding.rose.jade.plugin.sql.id; + +/** + * @author Alan + * + */ +public interface IDGeneratorManager { + + IDGenerator create(Class> type); + + IDGenerator get(Class> type); + +} diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/id/ManualGenerator.java b/src/main/java/net/paoding/rose/jade/plugin/sql/id/ManualGenerator.java new file mode 100644 index 0000000..2b13d7c --- /dev/null +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/id/ManualGenerator.java @@ -0,0 +1,20 @@ +/** + * + */ +package net.paoding.rose.jade.plugin.sql.id; + +/** + * @author Alan + * + */ +public final class ManualGenerator implements IDGenerator { + + /* (non-Javadoc) + * @see net.paoding.rose.jade.plugin.sql.util.IDGenerator#generate(java.lang.Object) + */ + @Override + public Void generate(Object entity) { + return null; + } + +} diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/id/NativeGenerator.java b/src/main/java/net/paoding/rose/jade/plugin/sql/id/NativeGenerator.java new file mode 100644 index 0000000..a42bdc8 --- /dev/null +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/id/NativeGenerator.java @@ -0,0 +1,17 @@ +/** + * + */ +package net.paoding.rose.jade.plugin.sql.id; + +/** + * @author Alan + * + */ +public final class NativeGenerator implements IDGenerator { + + @Override + public Void generate(Object entity) { + return null; + } + +} diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/id/NonID.java b/src/main/java/net/paoding/rose/jade/plugin/sql/id/NonID.java new file mode 100644 index 0000000..8bae3d0 --- /dev/null +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/id/NonID.java @@ -0,0 +1,20 @@ +/** + * + */ +package net.paoding.rose.jade.plugin.sql.id; + +/** + * @author Alan + * + */ +public final class NonID implements IDGenerator { + + /* (non-Javadoc) + * @see net.paoding.rose.jade.plugin.sql.util.IDGenerator#generate(java.lang.Object) + */ + @Override + public Void generate(Object entity) { + return null; + } + +} diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/id/UUIDStringGenerator.java b/src/main/java/net/paoding/rose/jade/plugin/sql/id/UUIDStringGenerator.java new file mode 100644 index 0000000..5b91462 --- /dev/null +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/id/UUIDStringGenerator.java @@ -0,0 +1,22 @@ +/** + * + */ +package net.paoding.rose.jade.plugin.sql.id; + +import java.util.UUID; + +/** + * @author Alan + * + */ +public class UUIDStringGenerator implements IDGenerator { + + /* (non-Javadoc) + * @see net.paoding.rose.jade.plugin.sql.util.IDGenerator#generate(java.lang.Object) + */ + @Override + public String generate(Object entity) { + return UUID.randomUUID().toString(); + } + +} diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/AbstractMapper.java b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/AbstractMapper.java index 2a8f2f5..631c0b3 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/AbstractMapper.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/AbstractMapper.java @@ -3,6 +3,9 @@ */ package net.paoding.rose.jade.plugin.sql.mapper; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import net.paoding.rose.jade.plugin.sql.util.PlumUtils; /** @@ -13,27 +16,24 @@ public abstract class AbstractMapper implements IMapper { protected O original; - private String name; + private String destName; private String originalName; - private boolean mapped; - public static final char SEPARATOR = '_'; + protected static Log logger = LogFactory.getLog(IMapper.class); + public AbstractMapper(O original) { this.original = original; + this.originalName = generateOriginalName(); + this.destName = generateDestName(getOriginalName()); } + - @Override - public void map() { - if(!mapped) { - this.originalName = generateOriginalName(); - this.name = generateName(getOriginalName()); - doMap(); - mapped = true; - } - } + @Override + public void init() { + } public O getOriginal() { return original; @@ -47,7 +47,7 @@ protected String generateOriginalName() { return original.toString(); } - public String generateName(String source) { + public String generateDestName(String source) { if(PlumUtils.isBlank(source)) { return null; } @@ -77,13 +77,10 @@ public String generateName(String source) { throw new IllegalArgumentException("Illegal naming conventions."); } } - - protected void doMap() { - - }; - public String getName() { - return name; + @Override + public String getDestName() { + return destName; } } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/ColumnMapper.java b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/ColumnMapper.java index 0bd3421..1f048da 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/ColumnMapper.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/ColumnMapper.java @@ -7,6 +7,8 @@ import net.paoding.rose.jade.plugin.sql.Order.Direction; import net.paoding.rose.jade.plugin.sql.annotations.Column; +import net.paoding.rose.jade.plugin.sql.id.IDGenerator; +import net.paoding.rose.jade.plugin.sql.id.NonID; import net.paoding.rose.jade.plugin.sql.util.PlumUtils; /** @@ -31,26 +33,32 @@ protected String generateOriginalName() { } @Override - protected void doMap() { + public void init() { defaultOrderDirection = annotation.order(); - super.doMap(); + super.init(); } @Override - public String generateName(String source) { + public String generateDestName(String source) { if(PlumUtils.isNotBlank(annotation.value())) { return annotation.value(); } - return super.generateName(source); + return super.generateDestName(source); } + @SuppressWarnings("deprecation") @Override public boolean isPrimaryKey() { - return annotation.pk(); + return annotation.id() != NonID.class || annotation.pk(); } public Direction getDefaultOrderDirection() { return defaultOrderDirection; } + + @Override + public Class> getIDGeneratorType() { + return annotation != null ? annotation.id() : null; + } } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/ConditionalOperationMapper.java b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/ConditionalOperationMapper.java index c65bbd6..fb8e82e 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/ConditionalOperationMapper.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/ConditionalOperationMapper.java @@ -91,7 +91,7 @@ && getPrimaryKeyType().isAssignableFrom(type) } limitParameterIndex = index; } else if(annotation.annotationType() == Where.class - && OPERATION_UPDATE.equals(getName())) { + && OPERATION_UPDATE.equals(getDestName())) { // Where条件的位置,用于更新操作,其他操作该注解无任何意义。 if(index == 0) { // 如果该注解被标记在第一个参数前,证明该操作没有任何值用于更新。 @@ -107,11 +107,6 @@ && getPrimaryKeyType().isAssignableFrom(type) // :) Have to say, [Casablanca - Bertie Higgins] very nice! } - @Override - protected void doMap() { - super.doMap(); - } - public boolean containsOrder() { return orderParameterIndex != -1 || getTargetEntityMapper().getDefaultOrder() != null; } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/EntityMapper.java b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/EntityMapper.java index f11f808..8802c0d 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/EntityMapper.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/EntityMapper.java @@ -14,6 +14,7 @@ import net.paoding.rose.jade.plugin.sql.Plum; import net.paoding.rose.jade.plugin.sql.annotations.Column; import net.paoding.rose.jade.plugin.sql.annotations.Table; +import net.paoding.rose.jade.plugin.sql.id.NativeGenerator; import net.paoding.rose.jade.plugin.sql.util.PlumUtils; /** @@ -32,26 +33,35 @@ public class EntityMapper extends AbstractMapper> implements IEntityMap private Order defaultOrder; + private boolean containsAutoIncrementPrimaryKey; + public EntityMapper(Class from) { super(from); } @Override - protected void doMap() { - super.doMap(); + public void init() { + super.init(); this.columns = generateColumns(); this.columnsMap = new HashMap(this.columns.size()); this.primaryKey = new ArrayList(1); for(IColumnMapper col : columns) { + if(this.columnsMap.containsKey(col.getOriginal().getName())) { + logger.info("More than one name is " + col.getOriginal().getName() + " field was found, the nearest will be received."); + } + if(col.isPrimaryKey()) { primaryKey.add(col); + if(col.getIDGeneratorType() == NativeGenerator.class) { + containsAutoIncrementPrimaryKey = true; + } } if(col.getDefaultOrderDirection() != Direction.NONE) { if(defaultOrder == null) { defaultOrder = Plum.orderBy(col.getDefaultOrderDirection(), col.getOriginal().getName()); } else { - defaultOrder.orderBy(col.getDefaultOrderDirection(), col.getName()); + defaultOrder.orderBy(col.getDefaultOrderDirection(), col.getDestName()); } } this.columnsMap.put(col.getOriginal().getName(), col); @@ -59,14 +69,17 @@ protected void doMap() { } protected List generateColumns() { - Field[] fields = original.getDeclaredFields(); + Class entityClass = original; List columns = new ArrayList(); - - for(Field field : fields) { - if(field.isAnnotationPresent(Column.class)) { - columns.add(createColumnMapper(field)); + while(entityClass != Object.class) { + Field[] entityFields = entityClass.getDeclaredFields(); + for(Field entityField : entityFields) { + if(entityField.isAnnotationPresent(Column.class)) { + columns.add(createColumnMapper(entityField)); + } } + entityClass = entityClass.getSuperclass(); } if(columns.size() == 0) { @@ -78,7 +91,7 @@ protected List generateColumns() { protected IColumnMapper createColumnMapper(Field field) { IColumnMapper cm = new ColumnMapper(field); - cm.map(); + cm.init(); return cm; } @@ -97,12 +110,12 @@ protected String generateOriginalName() { } @Override - public String generateName(String source) { + public String generateDestName(String source) { Table table = original.getAnnotation(Table.class); if(table != null && PlumUtils.isNotBlank(table.value())) { return table.value(); } - return super.generateName(source); + return super.generateDestName(source); } @Override @@ -119,4 +132,8 @@ public Order getDefaultOrder() { return defaultOrder; } + public boolean containsAutoIncrementPrimaryKey() { + return containsAutoIncrementPrimaryKey; + } + } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/EntityMapperManager.java b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/EntityMapperManager.java index 6a1057a..88225b2 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/EntityMapperManager.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/EntityMapperManager.java @@ -11,7 +11,7 @@ public class EntityMapperManager extends AbstractCachedMapperManager, I public IEntityMapper create(Class clazz) { IEntityMapper entityMapper = new EntityMapper(clazz); - entityMapper.map(); + entityMapper.init(); return entityMapper; } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/ExpandableParameterMapper.java b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/ExpandableParameterMapper.java index 16935e8..867cee0 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/ExpandableParameterMapper.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/ExpandableParameterMapper.java @@ -3,28 +3,26 @@ */ package net.paoding.rose.jade.plugin.sql.mapper; +import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.List; -import net.paoding.rose.jade.annotation.SQLParam; - /** * @author Alan.Geng[gengzhi718@gmail.com] * */ public class ExpandableParameterMapper extends ParameterMapper implements IExpandableParameterMapper { - private EntityMapperManager entityMapperManager; - - private List expendedParameters; - - public ExpandableParameterMapper(IOperationMapper operationMapper, SQLParam original, Class type) { - super(operationMapper, original, type, null); + public ExpandableParameterMapper(IOperationMapper operationMapper, + Class type, Annotation[] annotations) { + super(operationMapper, type, annotations); } + private List expendedParameters; + @Override - public void doMap() { - super.doMap(); + public void init() { + super.init(); try { mapExpendedParameterMapper(); } catch (Exception e) { @@ -33,7 +31,7 @@ public void doMap() { } protected void mapExpendedParameterMapper() throws Exception { - IEntityMapper entityMapper = entityMapperManager.createGet((Class) getType()); + IEntityMapper entityMapper = getOperationMapper().getTargetEntityMapper(); if(entityMapper != null) { List columns = entityMapper.getColumns(); expendedParameters = new ArrayList(columns.size()); @@ -45,15 +43,10 @@ protected void mapExpendedParameterMapper() throws Exception { protected ParameterMapper createExpendedParameterMapper(IColumnMapper col) { ParameterMapper expended = new ParameterMapper(this, col); - expended.map(); + expended.init(); return expended; } - @Override - public void setEntityMapperManager(EntityMapperManager entityMapperManager) { - this.entityMapperManager = entityMapperManager; - } - @Override public List expand() { return expendedParameters; diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IColumnMapper.java b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IColumnMapper.java index f7e221a..f854b8a 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IColumnMapper.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IColumnMapper.java @@ -6,14 +6,34 @@ import java.lang.reflect.Field; import net.paoding.rose.jade.plugin.sql.Order.Direction; +import net.paoding.rose.jade.plugin.sql.id.IDGenerator; /** + * 负责列的映射。 + * * @author Alan.Geng[gengzhi718@gmail.com] * */ public interface IColumnMapper extends IMapper { + /** + * 该列是否是表的主键? + * + * @return + */ boolean isPrimaryKey(); + /** + * 该列的默认排序规则,可用在SQL查询语句 + * + * @return + */ Direction getDefaultOrderDirection(); + + /** + * 主键生成器 + * + * @return + */ + Class> getIDGeneratorType(); } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IEntityMapper.java b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IEntityMapper.java index abe73a4..3965cb2 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IEntityMapper.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IEntityMapper.java @@ -20,4 +20,6 @@ public interface IEntityMapper extends IMapper> { IColumnMapper getColumnMapperByFieldName(String fieldName); Order getDefaultOrder(); + + boolean containsAutoIncrementPrimaryKey(); } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IExpandableParameterMapper.java b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IExpandableParameterMapper.java index 82e2c68..ba0f727 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IExpandableParameterMapper.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IExpandableParameterMapper.java @@ -13,5 +13,4 @@ public interface IExpandableParameterMapper extends IParameterMapper { List expand(); - void setEntityMapperManager(EntityMapperManager entityMapperManager); } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IMapper.java b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IMapper.java index 9fb86a1..e9ff431 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IMapper.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IMapper.java @@ -3,18 +3,44 @@ */ package net.paoding.rose.jade.plugin.sql.mapper; +import net.paoding.rose.jade.statement.StatementMetaData; + /** + * + * {@link IMapper}用以封装提取的一些信息,用于生成SQL、设置参数或解析结果。 + * + * {@link IEntityMapper}用以封装实体类的信息(对应DO类)。

+ * {@link IOperationMapper}用以封装语句信息(对应DAO的方法) + * * @author Alan.Geng[gengzhi718@gmail.com] * */ public interface IMapper { - public O getOriginal(); - - void map(); - - String getOriginalName(); - - String getName(); - + /** + * 信息的原始起源地,比如某个DO实例或{@link StatementMetaData}实例等等 + * + * @return + */ + public O getOriginal(); + + /** + * 原始起源地名称(比如类名、字段名等) + * + * @return + */ + String getOriginalName(); + + /** + * 初始化 (此时 {@link #getOriginal()}和 {@link #getOriginalName()}应该已就绪) + */ + void init(); + + /** + * + * + * @return + */ + String getDestName(); + } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IOperationMapper.java b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IOperationMapper.java index e0b4258..feddf3f 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IOperationMapper.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IOperationMapper.java @@ -45,4 +45,6 @@ public interface IOperationMapper extends IMapper { IgnoreNull getIgnoreNull(); + boolean isCountQuery(); + } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IParameterMapper.java b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IParameterMapper.java index 3354af6..f70bd2d 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IParameterMapper.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/IParameterMapper.java @@ -25,4 +25,7 @@ public interface IParameterMapper extends IMapper { boolean isIgnoreNull(); IgnoreNull getIgnoreNull(); + + IOperationMapper getOperationMapper(); + } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/OperationMapper.java b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/OperationMapper.java index c78b846..7d7415e 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/OperationMapper.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/OperationMapper.java @@ -14,7 +14,6 @@ import java.util.Collections; import java.util.List; -import net.paoding.rose.jade.annotation.SQLParam; import net.paoding.rose.jade.plugin.sql.GenericDAO; import net.paoding.rose.jade.plugin.sql.Plum; import net.paoding.rose.jade.plugin.sql.annotations.IgnoreNull; @@ -38,6 +37,8 @@ public class OperationMapper extends AbstractMapper implement private IgnoreNull ignoreNull; + private boolean countQuery; + public static final List NO_PARAMETER = Collections.unmodifiableList(new ArrayList()); public OperationMapper(StatementMetaData original) { @@ -50,8 +51,14 @@ public IEntityMapper getTargetEntityMapper() { } @Override - protected void doMap() { + public void init() { ignoreNull = original.getAnnotation(IgnoreNull.class); + + if(original.getMethod().getName().startsWith("count") + && Number.class.isAssignableFrom(original.getReturnType())) { + countQuery = true; + } + mapGenericEntityType(); mapTargetEntityMapper(); mapParameters(); @@ -78,9 +85,9 @@ protected void mapParameters() { || parameterTypes.length == 0) { parameters = NO_PARAMETER; - if((getName() == OPERATION_INSERT - || getName() == OPERATION_DELETE - || getName() == OPERATION_UPDATE) + if((getDestName().equals(OPERATION_INSERT) + || getDestName().equals(OPERATION_DELETE) + || getDestName().equals(OPERATION_UPDATE)) && parameters == NO_PARAMETER) { // 写操作必须存在参数 throw new MappingException("The insert operation must has least 1 parameters."); @@ -113,7 +120,7 @@ protected Class resolveParameterType(Type type) { // GenericDAO中的非集合泛型参数,或许是主键或许是实体。 GenericDeclaration genericDeclaration = ((TypeVariable) type).getGenericDeclaration(); - if(genericDeclaration == GenericDAO.class) { + if(GenericDAO.class.isAssignableFrom((Class)genericDeclaration)) { Type[] bounds = ((TypeVariable) type).getBounds(); if(bounds[0] == Object.class) { @@ -135,35 +142,16 @@ protected Class resolveParameterType(Type type) { throw new MappingException("Unknown type \"" + type + "\"."); } - protected Type[] getCollectionTypeBounds(Class collectionType) { - TypeVariable[] typeParameters = collectionType.getTypeParameters(); - if(typeParameters.length == 0) { - throw new MappingException("The generic type of collection must be specified."); - } - TypeVariable typeVariable = collectionType.getTypeParameters()[0]; - return typeVariable.getBounds(); - } - protected IParameterMapper createParameterMapper(Class type, Annotation[] annotations, int index) { - SQLParam sp = null; - - if(annotations != null && annotations.length > 0) { - for(Annotation annotation : annotations) { - if(annotation.annotationType().equals(SQLParam.class)) { - sp = (SQLParam) annotation; - break; - } - } - } IParameterMapper param = null; if(isExpandableParameterType(type)) { - param = new ExpandableParameterMapper(this, sp, (Class) type); - ((ExpandableParameterMapper) param).setEntityMapperManager(entityMapperManager); + param = new ExpandableParameterMapper(this, type, annotations); } else { - param = new ParameterMapper(this, sp, type, annotations); + param = new ParameterMapper(this, type, annotations); } - param.map(); + + param.init(); return param; } @@ -186,7 +174,7 @@ protected String generateOriginalName() { } @Override - public String generateName(String source) { + public String generateDestName(String source) { for(int i = 0; i < OPERATION_PREFIX.length; i++) { String[] prefixs = OPERATION_PREFIX[i]; for(int j = 0; j < prefixs.length; j++) { @@ -224,5 +212,9 @@ public boolean isIgnoreNull() { public IgnoreNull getIgnoreNull() { return ignoreNull; } + + public boolean isCountQuery() { + return countQuery; + } } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/OperationMapperManager.java b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/OperationMapperManager.java index 0d7a73b..c3165d8 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/OperationMapperManager.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/OperationMapperManager.java @@ -28,7 +28,7 @@ public IOperationMapper create(StatementMetaData source) { } mapper.setEntityMapperManager(entityMapperManager); - mapper.map(); + mapper.init(); return mapper; } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/ParameterMapper.java b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/ParameterMapper.java index 1799cb2..b058d9c 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/ParameterMapper.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/ParameterMapper.java @@ -8,7 +8,6 @@ import java.util.HashMap; import java.util.Map; -import net.paoding.rose.jade.annotation.SQLParam; import net.paoding.rose.jade.plugin.sql.Plum; import net.paoding.rose.jade.plugin.sql.Plum.Operator; import net.paoding.rose.jade.plugin.sql.annotations.Eq; @@ -61,19 +60,23 @@ public class ParameterMapper extends AbstractMapper implement } public ParameterMapper(IParameterMapper parent, IColumnMapper columnMapper) { - super(new ParameterOriginal(null, columnMapper.getOriginal().getType(), null)); + super(new ParameterOriginal(columnMapper.getOriginal().getType(), null)); this.parent = parent; this.columnMapper = columnMapper; } - public ParameterMapper(IOperationMapper operationMapper, SQLParam original, Class type, Annotation[] annotations) { - super(new ParameterOriginal(original, type, annotations)); + public ParameterMapper(IOperationMapper operationMapper, Class type, Annotation[] annotations) { + super(new ParameterOriginal(type, annotations)); this.operationMapper = operationMapper; + + if(getOriginal().getSqlParam() != null) { + this.columnMapper = operationMapper.getTargetEntityMapper().getColumnMapperByFieldName(getOriginal().getName()); + } } @Override - protected void doMap() { - super.doMap(); + public void init() { + super.init(); Annotation[] annotations = original.getAnnotations(); if(annotations != null && annotations.length > 0) { for(Annotation annotation : annotations) { @@ -139,5 +142,18 @@ public IgnoreNull getIgnoreNull() { } return null; } + + @Override + public IOperationMapper getOperationMapper() { + return parent != null ? parent.getOperationMapper() : operationMapper; + } + + @Override + public String getDestName() { + if(columnMapper != null) { + return columnMapper.getDestName(); + } + return super.getDestName(); + } } diff --git a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/ParameterOriginal.java b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/ParameterOriginal.java index c4b7bcc..6980f6c 100644 --- a/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/ParameterOriginal.java +++ b/src/main/java/net/paoding/rose/jade/plugin/sql/mapper/ParameterOriginal.java @@ -19,10 +19,18 @@ public class ParameterOriginal { private Annotation[] annotations; - public ParameterOriginal(SQLParam sqlParam, Class type, Annotation[] annotations) { - this.sqlParam = sqlParam; + public ParameterOriginal(Class type, Annotation[] annotations) { this.type = type; this.annotations = annotations; + + if(annotations != null && annotations.length > 0) { + for(Annotation annotation : annotations) { + if(annotation.annotationType().equals(SQLParam.class)) { + sqlParam = (SQLParam) annotation; + break; + } + } + } } public Class getType() { diff --git a/src/test/java/net/paoding/rose/jade/plugin/sql/AbstractTestCase.java b/src/test/java/net/paoding/rose/jade/plugin/sql/AbstractTestCase.java index 1de5ecf..7736b28 100644 --- a/src/test/java/net/paoding/rose/jade/plugin/sql/AbstractTestCase.java +++ b/src/test/java/net/paoding/rose/jade/plugin/sql/AbstractTestCase.java @@ -13,6 +13,7 @@ import com.alibaba.fastjson.JSON; import junit.framework.TestCase; +import net.paoding.rose.jade.plugin.sql.dao.BooleanEnum; import net.paoding.rose.jade.plugin.sql.dao.CreateTableDAO; import net.paoding.rose.jade.plugin.sql.dao.UserInfoDAO; import net.paoding.rose.jade.plugin.sql.model.UserInfoDO;; @@ -65,6 +66,7 @@ private static UserInfoDO createUserInfoDO(long group, int age) { userInfo.setCreateTime(new Date()); userInfo.setEditable(true); userInfo.setLastUpdateTime(new Date()); + userInfo.setBoolEnum(BooleanEnum.FALSE); return userInfo; } diff --git a/src/test/java/net/paoding/rose/jade/plugin/sql/PlumInsertTestCase.java b/src/test/java/net/paoding/rose/jade/plugin/sql/PlumInsertTestCase.java index eec074d..ae8fb56 100644 --- a/src/test/java/net/paoding/rose/jade/plugin/sql/PlumInsertTestCase.java +++ b/src/test/java/net/paoding/rose/jade/plugin/sql/PlumInsertTestCase.java @@ -14,6 +14,7 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.serializer.SerializerFeature; +import net.paoding.rose.jade.plugin.sql.dao.BooleanEnum; import net.paoding.rose.jade.plugin.sql.dao.UserInfoDAO; import net.paoding.rose.jade.plugin.sql.model.UserInfoDO; @@ -35,10 +36,10 @@ protected void setUp() throws Exception { public void testInsert() { UserInfoDO userInfo = createUserInfoDO(102, 30); - Long id = userInfoDAO.save(userInfo); + userInfoDAO.save(userInfo); - System.out.println(JSON.toJSONString(userInfoDAO.get(id), SerializerFeature.PrettyFormat)); + System.out.println(JSON.toJSONString(userInfoDAO.findByGroupId(102L), SerializerFeature.PrettyFormat)); } public void testBatchInsert() { @@ -62,6 +63,7 @@ private static UserInfoDO createUserInfoDO(long group, int age) { userInfo.setCreateTime(new Date()); userInfo.setEditable(true); userInfo.setLastUpdateTime(new Date()); + userInfo.setBoolEnum(BooleanEnum.TRUE); return userInfo; } diff --git a/src/test/java/net/paoding/rose/jade/plugin/sql/PlumOracleSelectTestCase.java b/src/test/java/net/paoding/rose/jade/plugin/sql/PlumOracleSelectTestCase.java new file mode 100644 index 0000000..4588eb8 --- /dev/null +++ b/src/test/java/net/paoding/rose/jade/plugin/sql/PlumOracleSelectTestCase.java @@ -0,0 +1,38 @@ +/** + * + */ +package net.paoding.rose.jade.plugin.sql; + +import java.util.List; + +import net.paoding.rose.jade.plugin.sql.oracle.dao.ItemDAO; +import net.paoding.rose.jade.plugin.sql.oracle.model.Item; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.serializer.SerializerFeature; + +/** + * @author Alan + * + */ +public class PlumOracleSelectTestCase extends AbstractTestCase { + + @Autowired + private ItemDAO itemDAO; + + public void testFindByName() { + String name = "%可乐%"; + List items = itemDAO.findByName(name, 10L, 10L); + + System.out.println(JSON.toJSONString(items, SerializerFeature.PrettyFormat)); + } + + public void testFindByName2() { + String name = "%可乐%"; + List items = itemDAO.findByName(name, 10L); + + System.out.println(JSON.toJSONString(items, SerializerFeature.PrettyFormat)); + } +} diff --git a/src/test/java/net/paoding/rose/jade/plugin/sql/PlumSelectTestCase.java b/src/test/java/net/paoding/rose/jade/plugin/sql/PlumSelectTestCase.java index 09951d8..fed110e 100644 --- a/src/test/java/net/paoding/rose/jade/plugin/sql/PlumSelectTestCase.java +++ b/src/test/java/net/paoding/rose/jade/plugin/sql/PlumSelectTestCase.java @@ -72,4 +72,8 @@ public void testFindByGroupIds() { System.out.println(JSON.toJSONString(userInfos, SerializerFeature.PrettyFormat)); } + public void testCountByGroupId() { + System.out.println(userInfoDAO.countByGroupId(100)); + } + } diff --git a/src/test/java/net/paoding/rose/jade/plugin/sql/PlumUpdateTestCase.java b/src/test/java/net/paoding/rose/jade/plugin/sql/PlumUpdateTestCase.java index 315c77c..21057ce 100644 --- a/src/test/java/net/paoding/rose/jade/plugin/sql/PlumUpdateTestCase.java +++ b/src/test/java/net/paoding/rose/jade/plugin/sql/PlumUpdateTestCase.java @@ -12,6 +12,8 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.serializer.SerializerFeature; +import junit.framework.Assert; +import net.paoding.rose.jade.plugin.sql.dao.BooleanEnum; import net.paoding.rose.jade.plugin.sql.dao.UserInfoDAO; import net.paoding.rose.jade.plugin.sql.model.UserInfoDO; @@ -22,36 +24,62 @@ public class PlumUpdateTestCase extends AbstractTestCase { @Autowired - private UserInfoDAO purchaseContractDAO; - - public void testUpdate() { - UserInfoDO contract = new UserInfoDO(); - - contract.setId(1L); - contract.setLastUpdateTime(new Date()); - contract.setName("Alan.Geng"); - - System.out.println(purchaseContractDAO.update(contract)); - - UserInfoDO user = purchaseContractDAO.get(1L); - System.out.println(JSON.toJSONString(user, SerializerFeature.PrettyFormat)); - } - - public void testSpecialUpdate() { - purchaseContractDAO.updateByGroup(null, 25, 100); - - List updated = purchaseContractDAO.findByGroupId(100L); - System.out.println(JSON.toJSONString(updated, SerializerFeature.PrettyFormat)); - } + private UserInfoDAO userInfoDAO; + + public void testUpdate() { + UserInfoDO contract = new UserInfoDO(); + + contract.setId(1L); + contract.setLastUpdateTime(new Date()); + contract.setName("Alan.Geng"); + + System.out.println(userInfoDAO.update(contract)); + + UserInfoDO user = userInfoDAO.get(1L); + System.out.println(JSON.toJSONString(user, SerializerFeature.PrettyFormat)); + } + + public void testUpdateEnum() { + + userInfoDAO.updateBoolEnum(1, BooleanEnum.TRUE); + + UserInfoDO user = userInfoDAO.get(1L); + System.out.println(JSON.toJSONString(user, SerializerFeature.PrettyFormat)); + // + userInfoDAO.updateBoolEnum(1, BooleanEnum.FALSE); + + UserInfoDO user2 = userInfoDAO.get(1L); + System.out.println(JSON.toJSONString(user2, SerializerFeature.PrettyFormat)); + } + + public void testBaseDAOUpdate() { + UserInfoDO user = userInfoDAO.findAll().get(0); + userInfoDAO.updateStatus(user.getId(), 123); + + int status = userInfoDAO.getStatus(user.getId()); + + Assert.assertEquals(123, status); + + + user = userInfoDAO.get(user.getId()); + System.out.println(JSON.toJSONString(user, SerializerFeature.PrettyFormat)); + } + + public void testSpecialUpdate() { + userInfoDAO.updateByGroup(null, 25, 100); + + List updated = userInfoDAO.findByGroupId(100L); + System.out.println(JSON.toJSONString(updated, SerializerFeature.PrettyFormat)); + } public void testSpecialInUpdate() { List groupIds = new ArrayList(); groupIds.add(100); groupIds.add(101); - purchaseContractDAO.updateByGroupIds("Alan.Geng", 29, groupIds); + userInfoDAO.updateByGroupIds("Alan.Geng", 29, groupIds); - List updated = purchaseContractDAO.findByGroupIds(groupIds); + List updated = userInfoDAO.findByGroupIds(groupIds); System.out.println(JSON.toJSONString(updated, SerializerFeature.PrettyFormat)); } } diff --git a/src/test/java/net/paoding/rose/jade/plugin/sql/dao/BaseDAO.java b/src/test/java/net/paoding/rose/jade/plugin/sql/dao/BaseDAO.java new file mode 100644 index 0000000..b07654b --- /dev/null +++ b/src/test/java/net/paoding/rose/jade/plugin/sql/dao/BaseDAO.java @@ -0,0 +1,13 @@ +package net.paoding.rose.jade.plugin.sql.dao; + +import net.paoding.rose.jade.annotation.SQL; +import net.paoding.rose.jade.plugin.sql.GenericDAO; + +public interface BaseDAO extends GenericDAO { + + @SQL("update {table_name} set status=:2 where id=:1") + void updateStatus(ID id, int status); + + @SQL("select status from {table_name} where id=:1") + int getStatus(ID id); +} diff --git a/src/test/java/net/paoding/rose/jade/plugin/sql/dao/BooleanEnum.java b/src/test/java/net/paoding/rose/jade/plugin/sql/dao/BooleanEnum.java new file mode 100644 index 0000000..59fdef0 --- /dev/null +++ b/src/test/java/net/paoding/rose/jade/plugin/sql/dao/BooleanEnum.java @@ -0,0 +1,8 @@ +package net.paoding.rose.jade.plugin.sql.dao; + +public enum BooleanEnum { + + TRUE, + + FALSE +} diff --git a/src/test/java/net/paoding/rose/jade/plugin/sql/dao/CreateTableDAO.java b/src/test/java/net/paoding/rose/jade/plugin/sql/dao/CreateTableDAO.java index cdab330..f290937 100644 --- a/src/test/java/net/paoding/rose/jade/plugin/sql/dao/CreateTableDAO.java +++ b/src/test/java/net/paoding/rose/jade/plugin/sql/dao/CreateTableDAO.java @@ -18,7 +18,9 @@ public interface CreateTableDAO { + ",create_time datetime not null" + ",last_update_time timestamp not null" + ",status int not null" - + ",editable int not null" + ");"; + + ",editable int not null" + + ",bool_enum varchar(10) not null" + + ");"; @SQL(create_user_info_table) public void createUserInfoTable(); diff --git a/src/test/java/net/paoding/rose/jade/plugin/sql/dao/UserInfoDAO.java b/src/test/java/net/paoding/rose/jade/plugin/sql/dao/UserInfoDAO.java index ad86992..ad3fed9 100644 --- a/src/test/java/net/paoding/rose/jade/plugin/sql/dao/UserInfoDAO.java +++ b/src/test/java/net/paoding/rose/jade/plugin/sql/dao/UserInfoDAO.java @@ -6,8 +6,8 @@ import java.util.List; import net.paoding.rose.jade.annotation.DAO; +import net.paoding.rose.jade.annotation.SQL; import net.paoding.rose.jade.annotation.SQLParam; -import net.paoding.rose.jade.plugin.sql.GenericDAO; import net.paoding.rose.jade.plugin.sql.Order; import net.paoding.rose.jade.plugin.sql.annotations.Ge; import net.paoding.rose.jade.plugin.sql.annotations.IgnoreNull; @@ -31,7 +31,7 @@ * spring框架将自动注入一个自动生成的实现。 */ @DAO -public interface UserInfoDAO extends GenericDAO { +public interface UserInfoDAO extends BaseDAO { /** * 指定字段查询 @@ -117,4 +117,18 @@ public void updateByGroupIds( */ public void deleteByGroupId( @SQLParam("groupId") Integer groupId); + + /** + * 测试更新枚举类型(实际存储枚举类型的name值) + * @param id + * @param bool + * @return + */ + @SQL("update {table_name} set bool_enum=:2 where id=:1") + public boolean updateBoolEnum(int id, BooleanEnum bool); + + @SQL("select * from {table_name} ") + public List findAll(); + + public Long countByGroupId(@SQLParam("groupId") Integer groupId); } diff --git a/src/test/java/net/paoding/rose/jade/plugin/sql/model/UserInfoDO.java b/src/test/java/net/paoding/rose/jade/plugin/sql/model/UserInfoDO.java index 860b245..4bc2951 100644 --- a/src/test/java/net/paoding/rose/jade/plugin/sql/model/UserInfoDO.java +++ b/src/test/java/net/paoding/rose/jade/plugin/sql/model/UserInfoDO.java @@ -10,6 +10,7 @@ import net.paoding.rose.jade.plugin.sql.Order.Direction; import net.paoding.rose.jade.plugin.sql.annotations.Column; import net.paoding.rose.jade.plugin.sql.annotations.Table; +import net.paoding.rose.jade.plugin.sql.dao.BooleanEnum; /** * @author Alan.Geng[gengzhi718@gmail.com] @@ -59,6 +60,9 @@ public class UserInfoDO implements Serializable { @Column private Boolean editable; + @Column + private BooleanEnum boolEnum; + // Getter & Setter public Long getId() { @@ -141,4 +145,12 @@ public void setLastUpdateTime(Date lastUpdateTime) { this.lastUpdateTime = lastUpdateTime; } + public void setBoolEnum(BooleanEnum boolEnum) { + this.boolEnum = boolEnum; + } + + public BooleanEnum getBoolEnum() { + return boolEnum; + } + } diff --git a/src/test/java/net/paoding/rose/jade/plugin/sql/oracle/dao/ItemDAO.java b/src/test/java/net/paoding/rose/jade/plugin/sql/oracle/dao/ItemDAO.java new file mode 100644 index 0000000..6215f4d --- /dev/null +++ b/src/test/java/net/paoding/rose/jade/plugin/sql/oracle/dao/ItemDAO.java @@ -0,0 +1,31 @@ +/** + * + */ +package net.paoding.rose.jade.plugin.sql.oracle.dao; + +import java.util.List; + +import net.paoding.rose.jade.annotation.DAO; +import net.paoding.rose.jade.annotation.SQLParam; +import net.paoding.rose.jade.plugin.sql.GenericDAO; +import net.paoding.rose.jade.plugin.sql.annotations.Like; +import net.paoding.rose.jade.plugin.sql.annotations.Limit; +import net.paoding.rose.jade.plugin.sql.annotations.Offset; +import net.paoding.rose.jade.plugin.sql.oracle.model.Item; + +/** + * @author Alan + * + */ +@DAO +public interface ItemDAO extends GenericDAO { + + List findByName( + @SQLParam("color") @Like String name, + @Offset Long offset, + @Limit Long limit); + + List findByName( + @SQLParam("color") @Like String name, + @Limit Long limit); +} diff --git a/src/test/java/net/paoding/rose/jade/plugin/sql/oracle/model/Item.java b/src/test/java/net/paoding/rose/jade/plugin/sql/oracle/model/Item.java new file mode 100644 index 0000000..5b51d6f --- /dev/null +++ b/src/test/java/net/paoding/rose/jade/plugin/sql/oracle/model/Item.java @@ -0,0 +1,38 @@ +/** + * + */ +package net.paoding.rose.jade.plugin.sql.oracle.model; + +import net.paoding.rose.jade.plugin.sql.annotations.Column; +import net.paoding.rose.jade.plugin.sql.annotations.Table; + +/** + * @author Alan + * + */ +@Table("\"MIRACLE\".\"goods_details\"") +public class Item { + + @Column("\"id\"") + private Long id; + + @Column("\"color\"") + private String color; + + public void setId(Long id) { + this.id = id; + } + + public Long getId() { + return id; + } + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } + +} diff --git a/src/test/resources/junit-test.spring.xml b/src/test/resources/junit-test.spring.xml index 5f9a0c2..d36f5e2 100644 --- a/src/test/resources/junit-test.spring.xml +++ b/src/test/resources/junit-test.spring.xml @@ -14,6 +14,13 @@ + + + + + + + @@ -24,5 +31,8 @@ + + \ No newline at end of file