├── .github └── workflows │ └── webpack.yml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── README1.X.md ├── pom.xml └── src ├── main └── java │ └── com │ └── github │ └── wz2cool │ └── dynamic │ ├── BaseDynamicQuery.java │ ├── BaseFilterDescriptor.java │ ├── BaseFilterGroup.java │ ├── BaseSortDescriptor.java │ ├── CustomFilterDescriptor.java │ ├── CustomSortDescriptor.java │ ├── DynamicQuery.java │ ├── FilterCondition.java │ ├── FilterDescriptor.java │ ├── FilterGroupDescriptor.java │ ├── FilterOperator.java │ ├── FilterOperators.java │ ├── GroupByQuery.java │ ├── GroupedQuery.java │ ├── LogicPagingQuery.java │ ├── NormPagingQuery.java │ ├── NormPagingQueryWrapper.java │ ├── SortDescriptor.java │ ├── SortDirection.java │ ├── SortDirections.java │ ├── UpDown.java │ ├── UpdateQuery.java │ ├── builder │ ├── BaseConditionClauseBuilder.java │ ├── ConditionClauseBuilder.java │ ├── DynamicQueryBuilder.java │ ├── DynamicQueryBuilderHelper.java │ ├── IDynamicQueryBuilder.java │ ├── OrderByClauseBuilder.java │ ├── SelectClauseBuilder.java │ ├── WhereClauseBuilder.java │ ├── direction │ │ ├── Ascending.java │ │ ├── Descending.java │ │ └── ISortDirection.java │ └── opeartor │ │ ├── Between.java │ │ ├── Contains.java │ │ ├── EndWith.java │ │ ├── Equal.java │ │ ├── GreaterThan.java │ │ ├── GreaterThanOrEqual.java │ │ ├── IFilterOperator.java │ │ ├── IMultipleValueFilterOperator.java │ │ ├── ISingleValueFilterOperator.java │ │ ├── ITwoValueFilterOperator.java │ │ ├── In.java │ │ ├── LessThan.java │ │ ├── LessThanOrEqual.java │ │ ├── NotContains.java │ │ ├── NotEqual.java │ │ ├── NotIn.java │ │ └── StartWith.java │ ├── exception │ ├── InternalRuntimeException.java │ ├── PropertyNotFoundException.java │ └── PropertyNotFoundInternalException.java │ ├── helper │ ├── CommonsHelper.java │ ├── ParamResolverHelper.java │ └── ReflectHelper.java │ ├── lambda │ ├── GetBigDecimalPropertyFunction.java │ ├── GetBytePropertyFunction.java │ ├── GetCommonPropertyFunction.java │ ├── GetDatePropertyFunction.java │ ├── GetDoublePropertyFunction.java │ ├── GetFloatPropertyFunction.java │ ├── GetIntegerPropertyFunction.java │ ├── GetLongPropertyFunction.java │ ├── GetPropertyFunction.java │ ├── GetShortPropertyFunction.java │ └── GetStringPropertyFunction.java │ ├── model │ ├── LogicPagingResult.java │ ├── NormPagingResult.java │ ├── PropertyInfo.java │ └── SelectPropertyConfig.java │ └── mybatis │ ├── ColumnInfo.java │ ├── EntityCache.java │ ├── EntityHelper.java │ ├── ExpressionHelper.java │ ├── MybatisQueryProvider.java │ ├── ParamExpression.java │ ├── QueryHelper.java │ ├── TypeHelper.java │ ├── View.java │ └── mapper │ ├── DeleteByDynamicQueryMapper.java │ ├── DynamicQueryMapper.java │ ├── MySqlMapper.java │ ├── SelectAvgByDynamicQueryMapper.java │ ├── SelectByDynamicQueryMapper.java │ ├── SelectByGroupedQueryMapper.java │ ├── SelectCountByDynamicQueryMapper.java │ ├── SelectMaxByDynamicQueryMapper.java │ ├── SelectMaxByGroupedQueryMapper.java │ ├── SelectMinByDynamicQueryMapper.java │ ├── SelectMinByGroupedQueryMapper.java │ ├── SelectRowBoundsByDynamicQueryMapper.java │ ├── SelectSumByDynamicQueryMapper.java │ ├── SelectViewByDynamicQueryMapper.java │ ├── UpdateByDynamicQueryMapper.java │ ├── UpdateByUpdateQueryMapper.java │ ├── UpdateSelectiveByDynamicQueryMapper.java │ ├── batch │ └── MapperBatchAction.java │ ├── constant │ └── MapperConstants.java │ ├── helper │ ├── BaseEnhancedMapperTemplate.java │ ├── DynamicQuerySqlHelper.java │ ├── EnhancedSqlHelper.java │ ├── GroupedQuerySqlHelper.java │ └── LogicPagingHelper.java │ ├── mysql │ ├── InsertIgnoreMapper.java │ └── InsertIgnoreSelectiveMapper.java │ └── provider │ ├── DynamicQueryProvider.java │ ├── GroupedQueryProvider.java │ └── InsertIgnoreProvider.java └── test ├── java └── com │ └── github │ └── wz2cool │ └── dynamic │ ├── CustomFilterDescriptorTest.java │ ├── CustomSortDescriptorTest.java │ ├── DbFilterTest.java │ ├── DbSortTest.java │ ├── DemoTest.java │ ├── DynamicMapperTest.java │ ├── DynamicQueryTest.java │ ├── FilterDescriptorTest.java │ ├── FilterGroupDescriptorTest.java │ ├── JsonSerializeTest.java │ ├── LogicPagingResultTest.java │ ├── LogicPagingTest.java │ ├── NormPagingResultTest.java │ ├── SortDescriptorTest.java │ ├── TestApplication.java │ ├── TransientTest.java │ ├── ViewTest.java │ ├── builder │ ├── DynamicQueryBuilderHelperTest.java │ ├── DynamicQueryBuilderTest.java │ ├── OrderByClauseBuilderTest.java │ ├── SelectClauseBuilderTest.java │ └── WhereClauseBuilderTest.java │ ├── helper │ ├── CommonsHelperTest.java │ └── ReflectHelperTest.java │ ├── model │ ├── Bug.java │ ├── ChildClass.java │ ├── ExampleModel.java │ ├── HelloWorld.java │ ├── ParentClass.java │ └── Student.java │ └── mybatis │ ├── EntityCacheTest.java │ ├── EntityHelperTest.java │ ├── ExpressionHelperTest.java │ ├── MybatisQueryProviderTest.java │ ├── QueryHelperTest.java │ ├── db │ ├── mapper │ │ ├── BugDao.java │ │ ├── CategoryGroupCountMapper.java │ │ ├── CategoryGroupCountMapper2.java │ │ ├── NorthwindDao.java │ │ ├── ProductDao.java │ │ ├── ProductViewMapper.java │ │ ├── StudentMapper.java │ │ └── UserDao.java │ └── model │ │ └── entity │ │ ├── group │ │ └── CategoryGroupCount.java │ │ ├── table │ │ ├── Category.java │ │ ├── Product.java │ │ ├── Product2.java │ │ ├── Product3.java │ │ ├── StudentDO.java │ │ └── User.java │ │ └── view │ │ ├── ProductBaseView.java │ │ └── ProductView.java │ └── mapper │ ├── constant │ └── MapperConstantsTest.java │ └── helper │ └── DynamicQuerySqlHelperTest.java └── resources ├── com └── github │ └── wz2cool │ └── dynamic │ └── mybatis │ └── db │ └── mapper │ └── NorthwindDao.xml ├── config ├── application-h2.properties ├── application-mysql.properties ├── application-postresql.properties ├── application-sqlserver.properties └── application.properties ├── mybatis-config.xml ├── schema-h2.sql ├── schema-mysql.sql ├── schema-postgresql.sql └── schema-sqlserver.sql /.github/workflows/webpack.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: [push, pull_request] 3 | env: 4 | CI: true 5 | 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v4 12 | - name: Set up JDK 8 13 | uses: actions/setup-java@v4 14 | with: 15 | java-version: '8' 16 | distribution: 'temurin' 17 | cache: maven 18 | - name: Build with Maven 19 | run: mvn clean verify org.jacoco:jacoco-maven-plugin:prepare-agent package org.jacoco:jacoco-maven-plugin:report -B 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | sudo: false 3 | install: true 4 | 5 | 6 | addons: 7 | sonarcloud: 8 | organization: "wz2cool-github" # the key of the org you chose at step #3 9 | token: 10 | secure: "Zd5JBJiCw7OrIgZz5bBw7gc2Konte7ZrjmsYcF8O/uGktDSMI9vIW1eVwYpb9GbOpou+OyvAvyMP5yFhbzcjtXDrylxqO+Kywl145CAuq6M00ITf00kajWTuNYWfhI41izV22oaFHDjf1xoWpH9EME7+bZjYWNrN6F+Y8eMoYw/ur+8dyKlcZDuDgSw6feBsl6Ii017neiuU1JGoSbS/HuWox6h+tGB3u2avjNgkVaTRwhoqIloP27ljfDMI9holzAD5n6lJycQsslkwkzlSawo/9I0G7a/Womjf+p3MjJmCdyQAsjh0YA7saPDxoxa21nrj2wQ8VpVqqRB1PX0w1gcznLDwGKa0KZmL9sjXSLYJhZDx9a9n819vF9b+uzSyxYsIcBhP9xtxzgYb+K8kkuG/jKNOsPl9n/KD8ccBWB9P1gIN9aKy88VTeTG5Y0u0cvDfWG4VMwZEmJXmQaOPwOaMSOFtpyYgngBITgYDDQ1kZbOiGEV9Afx+MJmFm12vC+kQUd9krXI3lpWUMqx/Rz6WsB0IiJq13C8tctPIaZckhrzpYc2QcC4F4Bcfk7En8LDOb33f0pEFPPErLvlKGBplGgTiOkLuaI2nMlZuqSShhsFQJJY/TRUWUkqTA9nhB7xM3jtbTdURO9sVY7gByDl6iRAPeUm9SjXoKtaA9+A=" # encrypted value of your token 11 | script: 12 | - mvn clean verify org.jacoco:jacoco-maven-plugin:prepare-agent package org.jacoco:jacoco-maven-plugin:report -B 13 | # setup JDK 11 for sonar scan 14 | - wget https://github.com/sormuras/bach/raw/master/install-jdk.sh && . ./install-jdk.sh -F 11 -L GPL 15 | 16 | after_success: 17 | - mvn -q clean test jacoco:report coveralls:report 18 | 19 | cache: 20 | directories: 21 | - '$HOME/.m2/repository' 22 | - '$HOME/.sonar/cache' 23 | 24 | jdk: 25 | - openjdk8 26 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [v1.0.1](https://github.com/wz2cool/mybatis-dynamic-query/tree/v1.0.1) (2017-07-24) 4 | 5 | **Feature:** 6 | - merge "QueryColumn" annotation and "DbColumn" annotation to Column annotation. 7 | - change "DbTable" annotation to "Table" annotation 8 | 9 | ## [v1.0.2](https://github.com/wz2cool/mybatis-dynamic-query/tree/v1.0.1) (2017-08-02) 10 | **Feature** 11 | - add bulk insert expression 12 | - add delete expression 13 | - add jdbcType and insertIgnore property in Column annotation 14 | - add jdbcType when generating insert/update/delete expression enhancement 15 | - add method to support lambda expression to get field name. 16 | 17 | **Bug fix** 18 | - [sql server] update will throw exception bug 19 | 20 | ## [v2.0.0](https://github.com/wz2cool/mybatis-dynamic-query/tree/v2.0.0) (2017-08-14) 21 | **Feature** 22 | - integrate tk.mybatis.mapper 23 | - add DynamicQueryMapper 24 | - remove generating insert/delete method since we can use DynamicQueryMapper. 25 | - add CustomFilterDescriptor 26 | - support serialize FilterDescriptor/FilterGroupDescriptor/CustomFilterDescriptor to json 27 | 28 | ## [v2.0.1](https://github.com/wz2cool/mybatis-dynamic-query/tree/v2.0.1) (2017-09-11) 29 | **Feature** 30 | - support serialize DynamicQuery to json 31 | 32 | ## [v2.0.2](https://github.com/wz2cool/mybatis-dynamic-query/tree/v2.0.2) (2017-10-05) 33 | **Feature** 34 | - add custom sort descriptor 35 | - get query column ([tableName].[columnName]) 36 | - createInstance for MybatisQueryProvider 37 | 38 | ## [v2.0.3](https://github.com/wz2cool/mybatis-dynamic-query/tree/v2.0.3) (2018-11-14) 39 | **Feature** 40 | - add Select Fields(columns) 41 | 42 | ## [v2.0.4](https://github.com/wz2cool/mybatis-dynamic-query/tree/v2.0.4) (2018-11-18) 43 | **Feature** 44 | - change select fields to select property 45 | 46 | ## [v2.0.5](https://github.com/wz2cool/mybatis-dynamic-query/tree/v2.0.5) (2018-11-18) 47 | **bug** 48 | - change "selectProperties" field to "selectedProperties" 49 | 50 | ## [v2.0.6](https://github.com/wz2cool/mybatis-dynamic-query/tree/v2.0.6) (2018-11-18) 51 | **Feature** 52 | - add MapUnderscoreToCamelCase to dynamic query 53 | 54 | ## [v2.0.7](https://github.com/wz2cool/mybatis-dynamic-query/tree/v2.0.7) (2019-04-12) 55 | **Feature** 56 | - remove MapUnderscoreToCamelCase from dynamic query 57 | - read MapUnderscoreToCamelCase from config 58 | 59 | ## [v2.0.9](https://github.com/wz2cool/mybatis-dynamic-query/tree/v2.0.9) (2019-04-13) 60 | **Bug** 61 | - fix mapping issue 62 | 63 | ## [v2.0.10](https://github.com/wz2cool/mybatis-dynamic-query/tree/v2.0.10) (2019-05-10) 64 | **Bug** 65 | - change selectCount result type from long to int 66 | 67 | ## v2.0.11 (2019-05-10) 68 | **Bug** 69 | - fix sonar issue 70 | 71 | ## v2.0.12 (2019-05-22) 72 | **feature** 73 | - add InsertList support -------------------------------------------------------------------------------- /README1.X.md: -------------------------------------------------------------------------------- 1 | MyBatis Dynamic Query 2 | ===================================== 3 | 4 | [![License](http://img.shields.io/:license-apache-brightgreen.svg)](http://www.apache.org/licenses/LICENSE-2.0.html) 5 | [![Build Status](https://travis-ci.org/wz2cool/mybatis-dynamic-query.svg?branch=master)](https://travis-ci.org/wz2cool/mybatis-dynamic-query) 6 | [![Coverage Status](https://coveralls.io/repos/github/wz2cool/mybatis-dynamic-query/badge.svg?branch=master)](https://coveralls.io/github/wz2cool/mybatis-dynamic-query?branch=master) 7 | [![Dependency Status](https://www.versioneye.com/user/projects/597283ce368b08005906060c/badge.svg?style=flat-square)](https://www.versioneye.com/user/projects/597283ce368b08005906060c) 8 | [![Maven central](https://maven-badges.herokuapp.com/maven-central/com.github.wz2cool/mybatis-dynamic-query/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.wz2cool/mybatis-dynamic-query) 9 | 10 | The MyBatis Dynamic Query framework makes it easier to generate "where" and "order" expression dynamically in mapper xml. 11 | mybatis-dynamic-query comes to solve four problem: 12 | - no need write lots of code in xml. 13 | - filtering or sorting maintained by java code. 14 | - hot update "where" and "order" expression. 15 | - save filter or sort descriptor and re-use them. 16 | 17 | ## Database support 18 | - H2 19 | - MySql 20 | - SqlServer 21 | - Postresql (BETA) 22 | - Oracle (TODO) 23 | 24 | ## Maven 25 | ```xml 26 | 27 | com.github.wz2cool 28 | mybatis-dynamic-query 29 | 1.0.2 30 | 31 | ``` 32 | 33 | ## Example 34 | - create a table by sql. 35 | ```sql 36 | CREATE TABLE product ( 37 | product_id INT PRIMARY KEY, 38 | category_id INT NOT NULL, 39 | product_name VARCHAR (50) NOT NULL, 40 | price DECIMAL 41 | ); 42 | ``` 43 | - create a model map to this table. 44 | ```java 45 | public class Product { 46 | @Column(name = "product_id") // custom column name 47 | private Integer productId; 48 | private String productName; 49 | private BigDecimal price; 50 | private Integer categoryId; 51 | 52 | // get, set method. 53 | } 54 | ``` 55 | - create a dynamic select in mapper interface / xml. 56 | ```java 57 | List getProductByDynamic(Map params); 58 | ``` 59 | ```xml 60 | 66 | ``` 67 | - generate expression and param map (NOTE: expression string also put into map). 68 | ```java 69 | @Test 70 | public void simpleDemo() throws Exception { 71 | and 72 | FilterDescriptor idFilter = 73 | new FilterDescriptor(FilterCondition.AND, "productId", FilterOperator.EQUAL, 2); 74 | and 75 | Map queryParams = 76 | mybatisQueryProvider.getWhereQueryParamMap( 77 | Product.class, "whereExpression", idFilter); 78 | // pass query params. 79 | Product productView = 80 | northwindDao.getProductByDynamic(queryParams).stream().findFirst().orElse(null); 81 | 82 | assertEquals(Integer.valueOf(2), productView.getProductID()); 83 | } 84 | ``` 85 | ## Docs 86 | [中文文档](https://wz2cool.gitbooks.io/mybatis-dynamic-query-zh-cn/content/) -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/BaseFilterDescriptor.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | import com.fasterxml.jackson.annotation.JsonSubTypes; 4 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 5 | 6 | /** 7 | * @author Frank 8 | */ 9 | @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT, property = "type") 10 | @JsonSubTypes({ 11 | @JsonSubTypes.Type(value = FilterDescriptor.class, name = "filterDescriptor"), 12 | @JsonSubTypes.Type(value = FilterGroupDescriptor.class, name = "filterGroupDescriptor"), 13 | @JsonSubTypes.Type(value = CustomFilterDescriptor.class, name = "customFilterDescriptor") 14 | }) 15 | @SuppressWarnings("java:S2326") 16 | public interface BaseFilterDescriptor { 17 | /** 18 | * get condition of and 19 | * 20 | * @return condition of and 21 | */ 22 | FilterCondition getCondition(); 23 | 24 | /** 25 | * set condition 26 | * 27 | * @param condition condition of and 28 | */ 29 | void setCondition(FilterCondition condition); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/BaseSortDescriptor.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | import com.fasterxml.jackson.annotation.JsonSubTypes; 4 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 5 | 6 | /** 7 | * @author Frank 8 | */ 9 | @SuppressWarnings("squid:S1610") 10 | @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT, property = "type") 11 | @JsonSubTypes({ 12 | @JsonSubTypes.Type(value = SortDescriptor.class, name = "SortDescriptor"), 13 | @JsonSubTypes.Type(value = CustomSortDescriptor.class, name = "CustomSortDescriptor") 14 | }) 15 | public abstract class BaseSortDescriptor { 16 | } -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/CustomFilterDescriptor.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | import com.fasterxml.jackson.annotation.JsonTypeName; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * @author Frank 9 | */ 10 | @SuppressWarnings("squid:S1948") 11 | @JsonTypeName("customFilterDescriptor") 12 | public class CustomFilterDescriptor implements Serializable, BaseFilterDescriptor { 13 | private static final long serialVersionUID = 7448086874396793224L; 14 | 15 | private FilterCondition condition = FilterCondition.AND; 16 | 17 | private String expression; 18 | private Object[] params; 19 | 20 | public String getExpression() { 21 | return expression; 22 | } 23 | 24 | public void setExpression(String expression) { 25 | this.expression = expression; 26 | } 27 | 28 | public Object[] getParams() { 29 | return params; 30 | } 31 | 32 | public void setParams(Object... params) { 33 | this.params = params; 34 | } 35 | 36 | public CustomFilterDescriptor() { 37 | // create empty constructor 38 | } 39 | 40 | public CustomFilterDescriptor(String expression, Object... params) { 41 | this.setExpression(expression); 42 | this.setParams(params); 43 | } 44 | 45 | public CustomFilterDescriptor(FilterCondition condition, String expression, Object... params) { 46 | this.setCondition(condition); 47 | this.setExpression(expression); 48 | this.setParams(params); 49 | } 50 | 51 | @Override 52 | public FilterCondition getCondition() { 53 | return condition; 54 | } 55 | 56 | @Override 57 | public void setCondition(FilterCondition condition) { 58 | this.condition = condition; 59 | } 60 | } -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/CustomSortDescriptor.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | import com.fasterxml.jackson.annotation.JsonTypeName; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * @author Frank 9 | */ 10 | @SuppressWarnings("squid:S1948") 11 | @JsonTypeName("customSortDescriptor") 12 | public class CustomSortDescriptor extends BaseSortDescriptor implements Serializable { 13 | private static final long serialVersionUID = -8776490725097358688L; 14 | private String expression; 15 | private Object[] params; 16 | 17 | public String getExpression() { 18 | return expression; 19 | } 20 | 21 | public void setExpression(String expression) { 22 | this.expression = expression; 23 | } 24 | 25 | public Object[] getParams() { 26 | return params; 27 | } 28 | 29 | public void setParams(Object... params) { 30 | this.params = params; 31 | } 32 | 33 | public CustomSortDescriptor() { 34 | // create empty constructor 35 | } 36 | 37 | public CustomSortDescriptor(String expression, Object... params) { 38 | this.setExpression(expression); 39 | this.setParams(params); 40 | } 41 | } -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/DynamicQuery.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.github.wz2cool.dynamic.builder.direction.ISortDirection; 5 | import com.github.wz2cool.dynamic.helper.CommonsHelper; 6 | import com.github.wz2cool.dynamic.lambda.GetCommonPropertyFunction; 7 | import com.github.wz2cool.dynamic.lambda.GetPropertyFunction; 8 | import com.github.wz2cool.dynamic.mybatis.ParamExpression; 9 | import com.github.wz2cool.dynamic.mybatis.QueryHelper; 10 | import com.github.wz2cool.dynamic.mybatis.mapper.constant.MapperConstants; 11 | import org.apache.commons.lang3.ArrayUtils; 12 | 13 | import java.util.Map; 14 | 15 | /** 16 | * @author Frank 17 | **/ 18 | @JsonIgnoreProperties(ignoreUnknown = true) 19 | public class DynamicQuery extends BaseDynamicQuery> { 20 | 21 | private static final long serialVersionUID = -4044703018297658438L; 22 | 23 | public DynamicQuery() { 24 | // for json 25 | } 26 | 27 | public DynamicQuery(Class entityClass) { 28 | this.setEntityClass(entityClass); 29 | } 30 | 31 | public static DynamicQuery createQuery(Class entityClass) { 32 | return new DynamicQuery<>(entityClass); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/FilterCondition.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * The enum Filter condition. 7 | * @author Frank 8 | */ 9 | public enum FilterCondition implements Serializable { 10 | /** 11 | * And and condition. 12 | */ 13 | AND, 14 | /** 15 | * Or and condition. 16 | */ 17 | OR 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/FilterDescriptor.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | import com.fasterxml.jackson.annotation.JsonTypeName; 4 | 5 | /** 6 | * @author Frank 7 | **/ 8 | @SuppressWarnings({"squid:S1172", "squid:S2326"}) 9 | @JsonTypeName("filterDescriptor") 10 | public class FilterDescriptor implements BaseFilterDescriptor { 11 | 12 | private FilterCondition condition = FilterCondition.AND; 13 | private FilterOperator operator = FilterOperator.EQUAL; 14 | private String propertyName; 15 | private Object value; 16 | 17 | @Override 18 | public FilterCondition getCondition() { 19 | return condition; 20 | } 21 | 22 | @Override 23 | public void setCondition(FilterCondition condition) { 24 | this.condition = condition; 25 | } 26 | 27 | public FilterOperator getOperator() { 28 | return operator; 29 | } 30 | 31 | public void setOperator(FilterOperator operator) { 32 | this.operator = operator; 33 | } 34 | 35 | public String getPropertyName() { 36 | return propertyName; 37 | } 38 | 39 | public void setPropertyName(String propertyName) { 40 | this.propertyName = propertyName; 41 | } 42 | 43 | public Object getValue() { 44 | return value; 45 | } 46 | 47 | public void setValue(Object value) { 48 | this.value = value; 49 | } 50 | 51 | public FilterDescriptor() { 52 | // for json 53 | } 54 | 55 | public FilterDescriptor(String propertyName, FilterOperator operator, Object value) { 56 | this.propertyName = propertyName; 57 | this.operator = operator; 58 | this.value = value; 59 | } 60 | 61 | public FilterDescriptor(FilterCondition condition, String propertyName, FilterOperator operator, Object value) { 62 | this.condition = condition; 63 | this.propertyName = propertyName; 64 | this.operator = operator; 65 | this.value = value; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/FilterGroupDescriptor.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | import com.fasterxml.jackson.annotation.JsonTypeName; 4 | 5 | /** 6 | * @author Frank 7 | **/ 8 | @SuppressWarnings("squid:S1172") 9 | @JsonTypeName("filterGroupDescriptor") 10 | public class FilterGroupDescriptor 11 | extends BaseFilterGroup> 12 | implements BaseFilterDescriptor { 13 | 14 | private FilterCondition condition = FilterCondition.AND; 15 | 16 | private Class clazz; 17 | 18 | public FilterGroupDescriptor() { 19 | // hide construct 20 | } 21 | 22 | public FilterGroupDescriptor(Class clazz) { 23 | this.clazz = clazz; 24 | } 25 | 26 | public static FilterGroupDescriptor create(Class clazz) { 27 | return new FilterGroupDescriptor<>(clazz); 28 | } 29 | 30 | public Class getClazz() { 31 | return clazz; 32 | } 33 | 34 | @Override 35 | public FilterCondition getCondition() { 36 | return condition; 37 | } 38 | 39 | @Override 40 | public void setCondition(FilterCondition condition) { 41 | this.condition = condition; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/FilterOperator.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | 4 | import java.io.Serializable; 5 | 6 | /** 7 | * The enum Filter operator. 8 | * @author Frank 9 | */ 10 | public enum FilterOperator implements Serializable { 11 | /** 12 | * Less than and operator. 13 | */ 14 | LESS_THAN, 15 | /** 16 | * Less than or equal and operator. 17 | */ 18 | LESS_THAN_OR_EQUAL, 19 | /** 20 | * Equal and operator. 21 | */ 22 | EQUAL, 23 | /** 24 | * Not equal and operator. 25 | */ 26 | NOT_EQUAL, 27 | /** 28 | * Greater than or equal and operator. 29 | */ 30 | GREATER_THAN_OR_EQUAL, 31 | /** 32 | * Greater than and operator. 33 | */ 34 | GREATER_THAN, 35 | /** 36 | * Start with and operator. 37 | */ 38 | START_WITH, 39 | /** 40 | * End with and operator. 41 | */ 42 | END_WITH, 43 | /** 44 | * Contains and operator. 45 | */ 46 | CONTAINS, 47 | /** 48 | * In and operator. 49 | */ 50 | IN, 51 | /** 52 | * Not in and operator. 53 | */ 54 | NOT_IN, 55 | /** 56 | * Between and operator. 57 | */ 58 | BETWEEN, 59 | /** 60 | * 61 | */ 62 | NOT_CONTAINS 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/FilterOperators.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | import com.github.wz2cool.dynamic.builder.opeartor.*; 4 | 5 | import java.util.Collection; 6 | 7 | public final class FilterOperators { 8 | 9 | /// region and operator 10 | 11 | public LessThan lessThan(R value) { 12 | return new LessThan<>(value); 13 | } 14 | 15 | public LessThanOrEqual lessThanOrEqual(R value) { 16 | return new LessThanOrEqual<>(value); 17 | } 18 | 19 | public Equal isEqual(R value) { 20 | return new Equal<>(value); 21 | } 22 | 23 | public NotEqual notEqual(R value) { 24 | return new NotEqual<>(value); 25 | } 26 | 27 | public GreaterThanOrEqual greaterThanOrEqual(R value) { 28 | return new GreaterThanOrEqual<>(value); 29 | } 30 | 31 | public GreaterThan greaterThan(R value) { 32 | return new GreaterThan<>(value); 33 | } 34 | 35 | public StartWith startWith(R value) { 36 | return new StartWith<>(value); 37 | } 38 | 39 | public EndWith endWith(R value) { 40 | return new EndWith<>(value); 41 | } 42 | 43 | public Contains contains(R value) { 44 | return new Contains<>(value); 45 | } 46 | 47 | public NotContains notContains(R value) { 48 | return new NotContains<>(value); 49 | } 50 | 51 | @SafeVarargs 52 | public final In in(R... values) { 53 | return new In<>(values); 54 | } 55 | 56 | public In in(Collection values) { 57 | return new In<>(values); 58 | } 59 | 60 | @SafeVarargs 61 | public final NotIn notIn(R... values) { 62 | return new NotIn<>(values); 63 | } 64 | 65 | public NotIn notIn(Collection values) { 66 | return new NotIn<>(values); 67 | } 68 | 69 | public Between between(R value1, R value2) { 70 | return new Between<>(value1, value2); 71 | } 72 | 73 | /// endregion 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/GroupedQuery.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | import com.github.wz2cool.dynamic.builder.direction.ISortDirection; 4 | import com.github.wz2cool.dynamic.helper.CommonsHelper; 5 | import com.github.wz2cool.dynamic.lambda.GetPropertyFunction; 6 | import com.github.wz2cool.dynamic.mybatis.ParamExpression; 7 | import com.github.wz2cool.dynamic.mybatis.QueryHelper; 8 | import com.github.wz2cool.dynamic.mybatis.mapper.constant.MapperConstants; 9 | import org.apache.commons.lang3.ArrayUtils; 10 | 11 | import java.util.Map; 12 | 13 | /** 14 | * @author Frank 15 | **/ 16 | public class GroupedQuery extends BaseFilterGroup> { 17 | 18 | private static final QueryHelper QUERY_HELPER = new QueryHelper(); 19 | private final GroupByQuery groupByQuery; 20 | 21 | public GroupedQuery(GroupByQuery groupByQuery) { 22 | this.groupByQuery = groupByQuery; 23 | } 24 | 25 | public Class getQueryClass() { 26 | return this.groupByQuery.tQueryClass; 27 | } 28 | 29 | public Class getSelectClass() { 30 | return this.groupByQuery.tSelectClass; 31 | } 32 | 33 | /// region sort 34 | 35 | private BaseSortDescriptor[] sorts = new BaseSortDescriptor[]{}; 36 | 37 | public BaseSortDescriptor[] getSorts() { 38 | return sorts; 39 | } 40 | 41 | public void setSorts(BaseSortDescriptor[] sorts) { 42 | this.sorts = sorts; 43 | } 44 | 45 | public void addSorts(BaseSortDescriptor... newSorts) { 46 | setSorts(ArrayUtils.addAll(sorts, newSorts)); 47 | } 48 | 49 | public void removeSorts(BaseSortDescriptor... newSorts) { 50 | for (BaseSortDescriptor newSort : newSorts) { 51 | setSorts(ArrayUtils.removeAllOccurences(sorts, newSort)); 52 | } 53 | } 54 | 55 | public GroupedQuery orderBy(GetPropertyFunction getPropertyFunc, ISortDirection sortDirection) { 56 | return orderBy(true, getPropertyFunc, sortDirection); 57 | } 58 | 59 | public GroupedQuery orderBy( 60 | boolean enable, GetPropertyFunction getPropertyFunc, ISortDirection sortDirection) { 61 | if (enable) { 62 | String propertyName = CommonsHelper.getPropertyName(getPropertyFunc); 63 | SortDirection direction = sortDirection.getDirection(); 64 | SortDescriptor sortDescriptor = new SortDescriptor(); 65 | sortDescriptor.setPropertyName(propertyName); 66 | sortDescriptor.setDirection(direction); 67 | addSorts(sortDescriptor); 68 | } 69 | return this; 70 | } 71 | 72 | public GroupedQuery orderByNull() { 73 | // 增加性能 74 | SortDescriptor sortDescriptor = new SortDescriptor(); 75 | sortDescriptor.setPropertyName(null); 76 | sortDescriptor.setDirection(SortDirection.DESC); 77 | addSorts(sortDescriptor); 78 | return this; 79 | } 80 | 81 | /// endregion 82 | 83 | public Map toQueryParamMap(boolean isMapUnderscoreToCamelCase) { 84 | // 筛选 85 | ParamExpression whereParamExpression = QUERY_HELPER.toWhereExpression( 86 | this.getQueryClass(), this.groupByQuery.getFilters()); 87 | String whereExpression = whereParamExpression.getExpression(); 88 | Map paramMap = whereParamExpression.getParamMap(); 89 | for (Map.Entry param : paramMap.entrySet()) { 90 | String key = param.getKey(); 91 | String newKey = String.format("%s.%s", MapperConstants.GROUPED_QUERY_PARAMS, key); 92 | whereExpression = whereExpression.replace(key, newKey); 93 | } 94 | paramMap.put(MapperConstants.WHERE_EXPRESSION, whereExpression); 95 | // 分组 96 | String groupColumnExpression = QUERY_HELPER.toGroupByColumnsExpression( 97 | this.groupByQuery.tQueryClass, this.groupByQuery.getGroupedProperties()); 98 | paramMap.put(MapperConstants.GROUP_COLUMNS_EXPRESSION, groupColumnExpression); 99 | // having 100 | ParamExpression havingParamExpression = QUERY_HELPER.toWhereExpression( 101 | this.getSelectClass(), this.getFilters()); 102 | String havingExpression = havingParamExpression.getExpression(); 103 | for (Map.Entry param : havingParamExpression.getParamMap().entrySet()) { 104 | String key = param.getKey(); 105 | String newKey = String.format("%s.%s", MapperConstants.GROUPED_QUERY_PARAMS, key); 106 | havingExpression = havingExpression.replace(key, newKey); 107 | paramMap.put(key, param.getValue()); 108 | } 109 | paramMap.put(MapperConstants.HAVING_EXPRESSION, havingExpression); 110 | // 排序 111 | ParamExpression sortExpression = QUERY_HELPER.toSortExpression(this.getSelectClass(), sorts); 112 | paramMap.put(MapperConstants.SORT_EXPRESSION, sortExpression.getExpression()); 113 | // 选择 114 | String selectColumnExpression = QUERY_HELPER.toSelectColumnsExpression( 115 | this.groupByQuery.tSelectClass, 116 | this.groupByQuery.getSelectedProperties(), 117 | this.groupByQuery.getIgnoredProperties(), isMapUnderscoreToCamelCase, false); 118 | paramMap.put(MapperConstants.SELECT_COLUMNS_EXPRESSION, selectColumnExpression); 119 | this.groupByQuery.initDefaultQueryParams(); 120 | paramMap.putAll(this.groupByQuery.getCustomDynamicQueryParams()); 121 | return paramMap; 122 | 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/NormPagingQuery.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | /** 4 | * @author Frank 5 | */ 6 | public class NormPagingQuery extends BaseDynamicQuery> { 7 | 8 | private final int pageNum; 9 | private final int pageSize; 10 | private final boolean calcTotal; 11 | private boolean autoBackIfEmpty; 12 | 13 | public int getPageNum() { 14 | return pageNum; 15 | } 16 | 17 | public int getPageSize() { 18 | return pageSize; 19 | } 20 | 21 | public boolean isCalcTotal() { 22 | return calcTotal; 23 | } 24 | 25 | public boolean isAutoBackIfEmpty() { 26 | return autoBackIfEmpty; 27 | } 28 | 29 | public void setAutoBackIfEmpty(boolean autoBackIfEmpty) { 30 | this.autoBackIfEmpty = autoBackIfEmpty; 31 | } 32 | 33 | private NormPagingQuery(Class clazz, int pageNum, int pageSize, boolean autoBackIfEmpty, boolean calcTotal) { 34 | this.setEntityClass(clazz); 35 | this.pageNum = pageNum; 36 | this.pageSize = pageSize; 37 | this.autoBackIfEmpty = autoBackIfEmpty; 38 | this.calcTotal = calcTotal; 39 | } 40 | 41 | public static NormPagingQuery createQuery( 42 | Class clazz, int pageNum, int pageSize, boolean autoBackIfEmpty, boolean calcTotal) { 43 | return new NormPagingQuery<>(clazz, pageNum, pageSize, autoBackIfEmpty, calcTotal); 44 | } 45 | 46 | public static NormPagingQuery createQuery( 47 | Class clazz, int pageNum, int pageSize, boolean autoBackIfEmpty) { 48 | return new NormPagingQuery<>(clazz, pageNum, pageSize, autoBackIfEmpty, true); 49 | } 50 | 51 | public static NormPagingQuery createQuery(Class clazz, int pageNum, int pageSize) { 52 | return new NormPagingQuery<>(clazz, pageNum, pageSize, false, true); 53 | } 54 | 55 | public DynamicQuery getDynamicQuery() { 56 | DynamicQuery dynamicQuery = DynamicQuery.createQuery(getEntityClass()); 57 | dynamicQuery.addFilters(this.getFilters()); 58 | dynamicQuery.addSorts(this.getSorts()); 59 | dynamicQuery.setDistinct(this.isDistinct()); 60 | dynamicQuery.setSelectedProperties(this.getSelectedProperties()); 61 | dynamicQuery.setIgnoredProperties(this.getIgnoredProperties()); 62 | dynamicQuery.customDynamicQueryParams.putAll(this.customDynamicQueryParams); 63 | return dynamicQuery; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/NormPagingQueryWrapper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | /** 4 | * @author Frank 5 | **/ 6 | public class NormPagingQueryWrapper> { 7 | 8 | private final S searchQuery; 9 | private int pageNum = 1; 10 | private int pageSize = 10; 11 | private boolean calcTotal = true; 12 | private boolean autoBackIfEmpty = false; 13 | 14 | public S getSearchQuery() { 15 | return searchQuery; 16 | } 17 | 18 | public int getPageNum() { 19 | return pageNum; 20 | } 21 | 22 | public int getPageSize() { 23 | return pageSize; 24 | } 25 | 26 | public boolean isCalcTotal() { 27 | return calcTotal; 28 | } 29 | 30 | public boolean isAutoBackIfEmpty() { 31 | return autoBackIfEmpty; 32 | } 33 | 34 | public void setPageNum(int pageNum) { 35 | this.pageNum = pageNum; 36 | } 37 | 38 | public void setPageSize(int pageSize) { 39 | this.pageSize = pageSize; 40 | } 41 | 42 | public void setCalcTotal(boolean calcTotal) { 43 | this.calcTotal = calcTotal; 44 | } 45 | 46 | public void setAutoBackIfEmpty(boolean autoBackIfEmpty) { 47 | this.autoBackIfEmpty = autoBackIfEmpty; 48 | } 49 | 50 | public NormPagingQueryWrapper(S searchQuery) { 51 | this.searchQuery = searchQuery; 52 | } 53 | 54 | public static > NormPagingQueryWrapper create(S searchQuery) { 55 | return new NormPagingQueryWrapper<>(searchQuery); 56 | } 57 | 58 | public static > NormPagingQueryWrapper create(S searchQuery, int pageNum, int pageSize) { 59 | return create(searchQuery, pageNum, pageSize, true); 60 | } 61 | 62 | public static > NormPagingQueryWrapper create( 63 | S searchQuery, int pageNum, int pageSize, boolean calcTotal) { 64 | return create(searchQuery, pageNum, pageSize, calcTotal, false); 65 | } 66 | 67 | public static > NormPagingQueryWrapper create( 68 | S searchQuery, int pageNum, int pageSize, boolean calcTotal, boolean autoBackIfEmpty) { 69 | final NormPagingQueryWrapper normPagingQueryWrapper = new NormPagingQueryWrapper<>(searchQuery); 70 | normPagingQueryWrapper.setPageNum(pageNum); 71 | normPagingQueryWrapper.setPageSize(pageSize); 72 | normPagingQueryWrapper.setCalcTotal(calcTotal); 73 | normPagingQueryWrapper.setAutoBackIfEmpty(autoBackIfEmpty); 74 | return normPagingQueryWrapper; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/SortDescriptor.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | 4 | import com.github.wz2cool.dynamic.helper.CommonsHelper; 5 | import com.github.wz2cool.dynamic.lambda.GetPropertyFunction; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * The type Sort descriptor. 11 | * 12 | * @author Frank 13 | */ 14 | public class SortDescriptor extends BaseSortDescriptor implements Serializable { 15 | private static final long serialVersionUID = 819843464658066502L; 16 | 17 | private String propertyName; 18 | private SortDirection direction = SortDirection.ASC; 19 | 20 | /** 21 | * Instantiates a new Sort descriptor. 22 | */ 23 | public SortDescriptor() { 24 | // create a empty instance. 25 | } 26 | 27 | /** 28 | * Instantiates a new Sort descriptor. 29 | * 30 | * @param propertyName the property path 31 | * @param direction the sort direction 32 | */ 33 | public SortDescriptor(String propertyName, SortDirection direction) { 34 | this.propertyName = propertyName; 35 | this.direction = direction; 36 | } 37 | 38 | public SortDescriptor(GetPropertyFunction getFieldFunc, SortDirection direction) { 39 | this.propertyName = CommonsHelper.getPropertyInfo(getFieldFunc).getPropertyName(); 40 | this.direction = direction; 41 | } 42 | 43 | /** 44 | * Gets property path. 45 | * 46 | * @return the property path 47 | */ 48 | public String getPropertyName() { 49 | return propertyName; 50 | } 51 | 52 | /** 53 | * Sets property path. 54 | * 55 | * @param propertyName the property path 56 | */ 57 | public void setPropertyName(String propertyName) { 58 | this.propertyName = propertyName; 59 | } 60 | 61 | public void setPropertyPath(GetPropertyFunction getFieldFunc) { 62 | this.propertyName = CommonsHelper.getPropertyInfo(getFieldFunc).getPropertyName(); 63 | } 64 | 65 | /** 66 | * Gets sort direction. 67 | * 68 | * @return the sort direction 69 | */ 70 | public SortDirection getDirection() { 71 | return direction; 72 | } 73 | 74 | /** 75 | * Sets sort direction. 76 | * 77 | * @param direction the sort direction 78 | */ 79 | public void setDirection(SortDirection direction) { 80 | this.direction = direction; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/SortDirection.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | 4 | import java.io.Serializable; 5 | 6 | /** 7 | * The enum Sort direction. 8 | * @author Frank 9 | */ 10 | public enum SortDirection implements Serializable { 11 | /** 12 | * Asc sort direction. 13 | */ 14 | ASC, 15 | /** 16 | * Desc sort direction. 17 | */ 18 | DESC 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/SortDirections.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | 4 | import com.github.wz2cool.dynamic.builder.direction.Ascending; 5 | import com.github.wz2cool.dynamic.builder.direction.Descending; 6 | 7 | /** 8 | * The enum Sort direction. 9 | * 10 | * @author Frank 11 | */ 12 | public final class SortDirections { 13 | /// region sort direction 14 | 15 | private static final Ascending ASC = new Ascending(); 16 | private static final Descending DESC = new Descending(); 17 | 18 | public Ascending asc() { 19 | return ASC; 20 | } 21 | 22 | public Descending desc() { 23 | return DESC; 24 | } 25 | 26 | /// endregion 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/UpDown.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | /** 4 | * @author Frank 5 | **/ 6 | public enum UpDown { 7 | /** 8 | * NONE 9 | */ 10 | NONE, 11 | /** 12 | * UP 13 | */ 14 | UP, 15 | /** 16 | * DOWN 17 | */ 18 | DOWN 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/ConditionClauseBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder; 2 | 3 | import com.github.wz2cool.dynamic.*; 4 | import com.github.wz2cool.dynamic.builder.opeartor.IFilterOperator; 5 | import com.github.wz2cool.dynamic.helper.CommonsHelper; 6 | import com.github.wz2cool.dynamic.lambda.GetPropertyFunction; 7 | import org.apache.commons.lang3.ArrayUtils; 8 | 9 | /** 10 | * @author Frank 11 | */ 12 | public class ConditionClauseBuilder extends BaseConditionClauseBuilder, T> { 13 | 14 | private final FilterCondition condition; 15 | private final String propertyName; 16 | private final FilterOperator filterOperator; 17 | private final Object value; 18 | private final ConditionClauseBuilder[] subConditionClauseBuilders; 19 | 20 | public ConditionClauseBuilder( 21 | FilterCondition condition, 22 | GetPropertyFunction getPropertyFunction, 23 | IFilterOperator operator, 24 | ConditionClauseBuilder[] subConditionClauseBuilders) { 25 | this.condition = condition; 26 | this.propertyName = CommonsHelper.getPropertyName(getPropertyFunction); 27 | this.filterOperator = operator.getOperator(); 28 | this.value = operator.getValue(); 29 | this.subConditionClauseBuilders = subConditionClauseBuilders; 30 | } 31 | 32 | public BaseFilterDescriptor toFilter() { 33 | FilterDescriptor filterDescriptor = new FilterDescriptor(); 34 | 35 | filterDescriptor.setCondition(this.condition); 36 | filterDescriptor.setPropertyName(this.propertyName); 37 | filterDescriptor.setOperator(this.filterOperator); 38 | filterDescriptor.setValue(this.value); 39 | 40 | if (ArrayUtils.isEmpty(subConditionClauseBuilders)) { 41 | return filterDescriptor; 42 | } 43 | 44 | FilterGroupDescriptor filterGroupDescriptor = new FilterGroupDescriptor(); 45 | filterGroupDescriptor.setCondition(this.condition); 46 | filterGroupDescriptor.addFilters(filterDescriptor); 47 | 48 | for (ConditionClauseBuilder subClause : subConditionClauseBuilders) { 49 | filterGroupDescriptor.addFilters(subClause.toFilter()); 50 | } 51 | return filterGroupDescriptor; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/IDynamicQueryBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder; 2 | 3 | import com.github.wz2cool.dynamic.DynamicQuery; 4 | 5 | /** 6 | * @author Frank 7 | */ 8 | public interface IDynamicQueryBuilder { 9 | /** 10 | * build to dynamic Query. 11 | * 12 | * @return dynamic query. 13 | */ 14 | DynamicQuery build(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/OrderByClauseBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder; 2 | 3 | import com.github.wz2cool.dynamic.BaseSortDescriptor; 4 | import com.github.wz2cool.dynamic.DynamicQuery; 5 | import com.github.wz2cool.dynamic.SortDescriptor; 6 | import com.github.wz2cool.dynamic.builder.direction.Ascending; 7 | import com.github.wz2cool.dynamic.builder.direction.ISortDirection; 8 | import com.github.wz2cool.dynamic.helper.CommonsHelper; 9 | import com.github.wz2cool.dynamic.lambda.GetCommonPropertyFunction; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | /** 15 | * @author Frank 16 | */ 17 | public class OrderByClauseBuilder implements IDynamicQueryBuilder { 18 | 19 | private final List sortDescriptors = new ArrayList<>(); 20 | private final DynamicQueryBuilder dynamicQueryBuilder; 21 | 22 | public OrderByClauseBuilder( 23 | DynamicQueryBuilder dynamicQueryBuilder, 24 | GetCommonPropertyFunction getPropertyFunction, ISortDirection sortDirection) { 25 | this.dynamicQueryBuilder = dynamicQueryBuilder; 26 | dynamicQueryBuilder.setOrderByClauseBuilder(this); 27 | addSort(getPropertyFunction, sortDirection); 28 | } 29 | 30 | public OrderByClauseBuilder( 31 | DynamicQueryBuilder dynamicQueryBuilder, 32 | GetCommonPropertyFunction getPropertyFunction) { 33 | this.dynamicQueryBuilder = dynamicQueryBuilder; 34 | dynamicQueryBuilder.setOrderByClauseBuilder(this); 35 | addSort(getPropertyFunction, new Ascending()); 36 | } 37 | 38 | public OrderByClauseBuilder thenBy( 39 | GetCommonPropertyFunction getPropertyFunction, ISortDirection sortDirection) { 40 | addSort(getPropertyFunction, sortDirection); 41 | return this; 42 | } 43 | 44 | public OrderByClauseBuilder thenBy( 45 | GetCommonPropertyFunction getPropertyFunction) { 46 | addSort(getPropertyFunction, new Ascending()); 47 | return this; 48 | } 49 | 50 | @Override 51 | public DynamicQuery build() { 52 | return dynamicQueryBuilder.build(); 53 | } 54 | 55 | BaseSortDescriptor[] getSorts() { 56 | return this.sortDescriptors.toArray(new BaseSortDescriptor[0]); 57 | } 58 | 59 | private void addSort(GetCommonPropertyFunction getPropertyFunction, ISortDirection sortDirection) { 60 | String propertyName = CommonsHelper.getPropertyName(getPropertyFunction); 61 | SortDescriptor sortDescriptor = new SortDescriptor(); 62 | sortDescriptor.setPropertyName(propertyName); 63 | sortDescriptor.setDirection(sortDirection.getDirection()); 64 | this.sortDescriptors.add(sortDescriptor); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/WhereClauseBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder; 2 | 3 | import com.github.wz2cool.dynamic.BaseFilterDescriptor; 4 | import com.github.wz2cool.dynamic.DynamicQuery; 5 | import com.github.wz2cool.dynamic.FilterCondition; 6 | import com.github.wz2cool.dynamic.builder.direction.ISortDirection; 7 | import com.github.wz2cool.dynamic.builder.opeartor.IFilterOperator; 8 | import com.github.wz2cool.dynamic.lambda.GetCommonPropertyFunction; 9 | import com.github.wz2cool.dynamic.lambda.GetPropertyFunction; 10 | 11 | /** 12 | * @author Frank 13 | */ 14 | public class WhereClauseBuilder 15 | extends BaseConditionClauseBuilder, T> 16 | implements IDynamicQueryBuilder { 17 | 18 | private final DynamicQueryBuilder dynamicQueryBuilder; 19 | 20 | public WhereClauseBuilder( 21 | DynamicQueryBuilder dynamicQueryBuilder, 22 | GetPropertyFunction getPropertyFunction, 23 | IFilterOperator operator, 24 | ConditionClauseBuilder[] conditionClauseBuilders) { 25 | this.dynamicQueryBuilder = dynamicQueryBuilder; 26 | dynamicQueryBuilder.setWhereClauseBuilder(this); 27 | andOrInternal(FilterCondition.AND, getPropertyFunction, operator, conditionClauseBuilders); 28 | } 29 | 30 | public OrderByClauseBuilder orderBy(GetCommonPropertyFunction getPropertyFunction) { 31 | return new OrderByClauseBuilder<>(dynamicQueryBuilder, getPropertyFunction); 32 | } 33 | 34 | public OrderByClauseBuilder orderBy(GetCommonPropertyFunction getPropertyFunction, ISortDirection direction) { 35 | return new OrderByClauseBuilder<>(dynamicQueryBuilder, getPropertyFunction, direction); 36 | } 37 | 38 | @Override 39 | public DynamicQuery build() { 40 | return dynamicQueryBuilder.build(); 41 | } 42 | 43 | BaseFilterDescriptor[] getFilters() { 44 | return this.conditionClauseBuilders.stream().map(ConditionClauseBuilder::toFilter) 45 | .toArray(BaseFilterDescriptor[]::new); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/direction/Ascending.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder.direction; 2 | 3 | import com.github.wz2cool.dynamic.SortDirection; 4 | 5 | /** 6 | * @author Frank 7 | */ 8 | public class Ascending implements ISortDirection { 9 | @Override 10 | public SortDirection getDirection() { 11 | return SortDirection.ASC; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/direction/Descending.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder.direction; 2 | 3 | import com.github.wz2cool.dynamic.SortDirection; 4 | 5 | /** 6 | * @author Frank 7 | */ 8 | public class Descending implements ISortDirection { 9 | @Override 10 | public SortDirection getDirection() { 11 | return SortDirection.DESC; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/direction/ISortDirection.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder.direction; 2 | 3 | import com.github.wz2cool.dynamic.SortDirection; 4 | 5 | /** 6 | * @author Frank 7 | */ 8 | public interface ISortDirection { 9 | /** 10 | * Get sort direction. 11 | * 12 | * @return SortDirection enum. 13 | */ 14 | SortDirection getDirection(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/opeartor/Between.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder.opeartor; 2 | 3 | import com.github.wz2cool.dynamic.FilterOperator; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * @author Frank 10 | */ 11 | public class Between implements ITwoValueFilterOperator { 12 | 13 | private final List value; 14 | 15 | public Between(T value1, T value2) { 16 | List values = new ArrayList<>(); 17 | values.add(value1); 18 | values.add(value2); 19 | this.value = values; 20 | } 21 | 22 | @Override 23 | public List getValue() { 24 | return value; 25 | } 26 | 27 | @Override 28 | public FilterOperator getOperator() { 29 | return FilterOperator.BETWEEN; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/opeartor/Contains.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder.opeartor; 2 | 3 | import com.github.wz2cool.dynamic.FilterOperator; 4 | 5 | /** 6 | * @author Frank 7 | */ 8 | public class Contains implements ISingleValueFilterOperator { 9 | 10 | private final T value; 11 | 12 | public Contains(T value) { 13 | this.value = value; 14 | } 15 | 16 | @Override 17 | public T getValue() { 18 | return this.value; 19 | } 20 | 21 | @Override 22 | public FilterOperator getOperator() { 23 | return FilterOperator.CONTAINS; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/opeartor/EndWith.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder.opeartor; 2 | 3 | import com.github.wz2cool.dynamic.FilterOperator; 4 | 5 | /** 6 | * @author Frank 7 | */ 8 | public class EndWith implements ISingleValueFilterOperator { 9 | 10 | private final T value; 11 | 12 | public EndWith(T value) { 13 | this.value = value; 14 | } 15 | 16 | @Override 17 | public T getValue() { 18 | return this.value; 19 | } 20 | 21 | @Override 22 | public FilterOperator getOperator() { 23 | return FilterOperator.END_WITH; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/opeartor/Equal.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder.opeartor; 2 | 3 | import com.github.wz2cool.dynamic.FilterOperator; 4 | 5 | /** 6 | * @author Frank 7 | */ 8 | public class Equal implements ISingleValueFilterOperator { 9 | 10 | private final T value; 11 | 12 | public Equal(T value) { 13 | this.value = value; 14 | } 15 | 16 | @Override 17 | public T getValue() { 18 | return this.value; 19 | } 20 | 21 | @Override 22 | public FilterOperator getOperator() { 23 | return FilterOperator.EQUAL; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/opeartor/GreaterThan.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder.opeartor; 2 | 3 | import com.github.wz2cool.dynamic.FilterOperator; 4 | 5 | /** 6 | * @author Frank 7 | */ 8 | public class GreaterThan implements ISingleValueFilterOperator { 9 | 10 | private final T value; 11 | 12 | public GreaterThan(T value) { 13 | this.value = value; 14 | } 15 | 16 | @Override 17 | public FilterOperator getOperator() { 18 | return FilterOperator.GREATER_THAN; 19 | } 20 | 21 | @Override 22 | public T getValue() { 23 | return this.value; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/opeartor/GreaterThanOrEqual.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder.opeartor; 2 | 3 | import com.github.wz2cool.dynamic.FilterOperator; 4 | 5 | /** 6 | * @author Frank 7 | */ 8 | public class GreaterThanOrEqual implements ISingleValueFilterOperator { 9 | 10 | private final T value; 11 | 12 | public GreaterThanOrEqual(T value) { 13 | this.value = value; 14 | } 15 | 16 | @Override 17 | public FilterOperator getOperator() { 18 | return FilterOperator.GREATER_THAN_OR_EQUAL; 19 | } 20 | 21 | @Override 22 | public T getValue() { 23 | return this.value; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/opeartor/IFilterOperator.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder.opeartor; 2 | 3 | import com.github.wz2cool.dynamic.FilterOperator; 4 | 5 | /** 6 | * @author Frank 7 | */ 8 | @SuppressWarnings("squid:S2326") 9 | public interface IFilterOperator { 10 | /** 11 | * Get and operator. 12 | * 13 | * @return filterOperator enum. 14 | */ 15 | FilterOperator getOperator(); 16 | 17 | /** 18 | * Get and value. 19 | * 20 | * @return and value. 21 | */ 22 | Object getValue(); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/opeartor/IMultipleValueFilterOperator.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder.opeartor; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author Frank 7 | */ 8 | public interface IMultipleValueFilterOperator extends IFilterOperator { 9 | /** 10 | * Get and value. 11 | * 12 | * @return and value. 13 | */ 14 | @Override 15 | List getValue(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/opeartor/ISingleValueFilterOperator.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder.opeartor; 2 | 3 | /** 4 | * @author Frank 5 | */ 6 | public interface ISingleValueFilterOperator extends IFilterOperator { 7 | /** 8 | * Get and value. 9 | * 10 | * @return and value. 11 | */ 12 | @Override 13 | T getValue(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/opeartor/ITwoValueFilterOperator.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder.opeartor; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author Frank 7 | */ 8 | public interface ITwoValueFilterOperator extends IFilterOperator { 9 | /** 10 | * Get and value. 11 | * 12 | * @return and value. 13 | */ 14 | @Override 15 | List getValue(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/opeartor/In.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder.opeartor; 2 | 3 | import com.github.wz2cool.dynamic.FilterOperator; 4 | 5 | import java.util.*; 6 | 7 | /** 8 | * @author Frank 9 | */ 10 | public class In implements IMultipleValueFilterOperator { 11 | 12 | private List value; 13 | 14 | public In(T[] values) { 15 | if (Objects.isNull(values)) { 16 | this.value = new ArrayList<>(); 17 | } else { 18 | this.value = Arrays.asList(values); 19 | } 20 | } 21 | 22 | public In(Collection values) { 23 | if (Objects.isNull(values)) { 24 | this.value = new ArrayList<>(); 25 | } else { 26 | this.value = new ArrayList<>(values); 27 | } 28 | } 29 | 30 | @Override 31 | public FilterOperator getOperator() { 32 | return FilterOperator.IN; 33 | } 34 | 35 | @Override 36 | public List getValue() { 37 | return this.value; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/opeartor/LessThan.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder.opeartor; 2 | 3 | import com.github.wz2cool.dynamic.FilterOperator; 4 | 5 | /** 6 | * @author Frank 7 | */ 8 | public class LessThan implements ISingleValueFilterOperator { 9 | private final T value; 10 | 11 | public LessThan(T value) { 12 | this.value = value; 13 | } 14 | 15 | @Override 16 | public FilterOperator getOperator() { 17 | return FilterOperator.LESS_THAN; 18 | } 19 | 20 | @Override 21 | public T getValue() { 22 | return this.value; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/opeartor/LessThanOrEqual.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder.opeartor; 2 | 3 | import com.github.wz2cool.dynamic.FilterOperator; 4 | 5 | /** 6 | * @author Frank 7 | */ 8 | public class LessThanOrEqual implements ISingleValueFilterOperator { 9 | 10 | private final T value; 11 | 12 | public LessThanOrEqual(T value) { 13 | this.value = value; 14 | } 15 | 16 | @Override 17 | public FilterOperator getOperator() { 18 | return FilterOperator.LESS_THAN_OR_EQUAL; 19 | } 20 | 21 | @Override 22 | public T getValue() { 23 | return this.value; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/opeartor/NotContains.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder.opeartor; 2 | 3 | import com.github.wz2cool.dynamic.FilterOperator; 4 | 5 | /** 6 | * @author Frank 7 | */ 8 | public class NotContains implements ISingleValueFilterOperator { 9 | 10 | private final T value; 11 | 12 | public NotContains(T value) { 13 | this.value = value; 14 | } 15 | 16 | @Override 17 | public T getValue() { 18 | return this.value; 19 | } 20 | 21 | @Override 22 | public FilterOperator getOperator() { 23 | return FilterOperator.NOT_CONTAINS; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/opeartor/NotEqual.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder.opeartor; 2 | 3 | import com.github.wz2cool.dynamic.FilterOperator; 4 | 5 | /** 6 | * @author Frank 7 | */ 8 | public class NotEqual implements ISingleValueFilterOperator { 9 | 10 | private final T value; 11 | 12 | public NotEqual(T value) { 13 | this.value = value; 14 | } 15 | 16 | @Override 17 | public FilterOperator getOperator() { 18 | return FilterOperator.NOT_EQUAL; 19 | } 20 | 21 | @Override 22 | public T getValue() { 23 | return this.value; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/opeartor/NotIn.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder.opeartor; 2 | 3 | import com.github.wz2cool.dynamic.FilterOperator; 4 | 5 | import java.util.*; 6 | 7 | /** 8 | * @author Frank 9 | */ 10 | public class NotIn implements IMultipleValueFilterOperator { 11 | 12 | private List value; 13 | 14 | public NotIn(T[] values) { 15 | if (Objects.isNull(values)) { 16 | this.value = new ArrayList<>(); 17 | } else { 18 | this.value = Arrays.asList(values); 19 | } 20 | } 21 | 22 | public NotIn(Collection values) { 23 | if (Objects.isNull(values)) { 24 | this.value = new ArrayList<>(); 25 | } else { 26 | this.value = new ArrayList<>(values); 27 | } 28 | } 29 | 30 | @Override 31 | public FilterOperator getOperator() { 32 | return FilterOperator.NOT_IN; 33 | } 34 | 35 | @Override 36 | public List getValue() { 37 | return this.value; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/builder/opeartor/StartWith.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder.opeartor; 2 | 3 | import com.github.wz2cool.dynamic.FilterOperator; 4 | 5 | /** 6 | * @author Frank 7 | */ 8 | public class StartWith implements ISingleValueFilterOperator { 9 | 10 | private final T value; 11 | 12 | public StartWith(T value) { 13 | this.value = value; 14 | } 15 | 16 | @Override 17 | public FilterOperator getOperator() { 18 | return FilterOperator.START_WITH; 19 | } 20 | 21 | @Override 22 | public T getValue() { 23 | return this.value; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/exception/InternalRuntimeException.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.exception; 2 | 3 | /** 4 | * @author Frank 5 | */ 6 | public class InternalRuntimeException extends RuntimeException { 7 | public InternalRuntimeException(Throwable cause) { 8 | super(cause); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/exception/PropertyNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.exception; 2 | 3 | /** 4 | * @author Frank 5 | */ 6 | public class PropertyNotFoundException extends Exception { 7 | public PropertyNotFoundException(String message) { 8 | super(message); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/exception/PropertyNotFoundInternalException.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.exception; 2 | 3 | /** 4 | * @author Frank 5 | */ 6 | public class PropertyNotFoundInternalException extends RuntimeException { 7 | public PropertyNotFoundInternalException(String message) { 8 | super(message); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/helper/CommonsHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.helper; 2 | 3 | import com.github.wz2cool.dynamic.exception.InternalRuntimeException; 4 | import com.github.wz2cool.dynamic.lambda.GetPropertyFunction; 5 | import com.github.wz2cool.dynamic.model.PropertyInfo; 6 | 7 | import java.lang.invoke.SerializedLambda; 8 | import java.lang.reflect.Array; 9 | import java.lang.reflect.Method; 10 | import java.util.ArrayList; 11 | import java.util.Collection; 12 | import java.util.concurrent.ConcurrentHashMap; 13 | 14 | 15 | /** 16 | * @author Frank 17 | */ 18 | public class CommonsHelper { 19 | private static ConcurrentHashMap classMap = new ConcurrentHashMap<>(); 20 | 21 | private CommonsHelper() { 22 | throw new UnsupportedOperationException(); 23 | } 24 | 25 | public static boolean isNumeric(final Class targetClass) { 26 | if (targetClass == null) { 27 | return false; 28 | } 29 | 30 | return Number.class.isAssignableFrom(targetClass); 31 | } 32 | 33 | public static boolean isArrayOrCollection(final Object value) { 34 | return isArray(value) || isCollection(value); 35 | } 36 | 37 | public static boolean isArray(final Object value) { 38 | return value != null && value.getClass().isArray(); 39 | } 40 | 41 | public static boolean isCollection(final Object value) { 42 | return value instanceof Iterable; 43 | } 44 | 45 | public static Object[] getCollectionValues(final Object inputValue) { 46 | if (inputValue == null) { 47 | throw new NullPointerException("inputValue"); 48 | } 49 | 50 | if (!isArrayOrCollection(inputValue)) { 51 | throw new IllegalArgumentException("inputValue should be array or collection"); 52 | } 53 | 54 | Collection values = new ArrayList<>(); 55 | if (inputValue instanceof Iterable) { 56 | Iterable iterable = (Iterable) inputValue; 57 | for (Object value : iterable) { 58 | values.add(value); 59 | } 60 | } else { 61 | int length = Array.getLength(inputValue); 62 | for (int i = 0; i < length; i++) { 63 | Object value = Array.get(inputValue, i); 64 | values.add(value); 65 | } 66 | } 67 | 68 | return values.toArray(); 69 | } 70 | 71 | public static String toStringSafe(final Object obj) { 72 | if (obj == null) { 73 | return ""; 74 | } 75 | 76 | return obj.toString(); 77 | } 78 | 79 | public static String getPropertyName(GetPropertyFunction fn) { 80 | return getPropertyInfo(fn).getPropertyName(); 81 | } 82 | 83 | @SuppressWarnings("squid:S00112") 84 | public static PropertyInfo getPropertyInfo(GetPropertyFunction fn) { 85 | try { 86 | Method method = fn.getClass().getDeclaredMethod("writeReplace"); 87 | method.setAccessible(true); 88 | SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn); 89 | String methodName = serializedLambda.getImplMethodName(); 90 | String className = serializedLambda.getImplClass(); 91 | String propertyName; 92 | String getString = "get"; 93 | String isString = "is"; 94 | if (methodName.startsWith(getString)) { 95 | propertyName = java.beans.Introspector.decapitalize(methodName.substring(3)); 96 | } else if (methodName.startsWith(isString)) { 97 | propertyName = java.beans.Introspector.decapitalize(methodName.substring(2)); 98 | } else { 99 | propertyName = methodName; 100 | } 101 | 102 | Class ownerClass; 103 | if (classMap.containsKey(className)) { 104 | ownerClass = classMap.get(className); 105 | } else { 106 | ownerClass = Class.forName(className.replace('/', '.')); 107 | classMap.put(className, ownerClass); 108 | } 109 | 110 | PropertyInfo propertyInfo = new PropertyInfo(); 111 | propertyInfo.setPropertyName(propertyName); 112 | propertyInfo.setOwnerClass(ownerClass); 113 | return propertyInfo; 114 | } catch (ReflectiveOperationException e) { 115 | throw new InternalRuntimeException(e); 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/helper/ParamResolverHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.helper; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | import java.util.regex.Matcher; 8 | import java.util.regex.Pattern; 9 | 10 | public class ParamResolverHelper { 11 | 12 | private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("[#|\\$]\\{([A-Za-z0-9_]+)\\}"); 13 | 14 | private static final Map EXPRESSION_CACHE = new ConcurrentHashMap<>(); 15 | 16 | private ParamResolverHelper() { 17 | } 18 | 19 | public static String resolveExpression(String expression) { 20 | if (EXPRESSION_CACHE.containsKey(expression)) { 21 | return EXPRESSION_CACHE.get(expression); 22 | } 23 | 24 | String newExpression = expression; 25 | List params = listParams(expression); 26 | for (String param : params) { 27 | String newParam = toNewParam(param); 28 | newExpression = newExpression.replace(param, newParam); 29 | } 30 | EXPRESSION_CACHE.put(expression, newExpression); 31 | return newExpression; 32 | } 33 | 34 | private static List listParams(String expression) { 35 | List result = new ArrayList<>(); 36 | Matcher matcher = PLACEHOLDER_PATTERN.matcher(expression); 37 | while (matcher.find()) { 38 | result.add(matcher.group()); 39 | } 40 | return result; 41 | } 42 | 43 | private static String toNewParam(String param) { 44 | String substring = param.substring(2); 45 | // 补充前缀 46 | String newSubString = "dynamicQueryParams." + substring; 47 | return param.replace(substring, newSubString); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/helper/ReflectHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.helper; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | 5 | import java.lang.reflect.Field; 6 | import java.lang.reflect.Method; 7 | import java.util.ArrayList; 8 | import java.util.Collection; 9 | 10 | /** 11 | * @author Frank 12 | */ 13 | public class ReflectHelper { 14 | private ReflectHelper() { 15 | throw new UnsupportedOperationException(); 16 | } 17 | 18 | public static Field[] getProperties(Class targetClass) { 19 | Collection fields = new ArrayList<>(); 20 | getProperties(targetClass, fields); 21 | return fields.toArray(new Field[fields.size()]); 22 | } 23 | 24 | public static Field[] getPropertiesForCurrentClass(Class targetClass) { 25 | Method[] methods = targetClass.getMethods(); 26 | Field[] fields = targetClass.getDeclaredFields(); 27 | 28 | Collection result = new ArrayList<>(); 29 | for (Field field : fields) { 30 | if (isProperty(field, methods)) { 31 | result.add(field); 32 | } 33 | } 34 | return result.toArray(new Field[result.size()]); 35 | } 36 | 37 | public static boolean hasParent(final Class current, final Class expectParent) { 38 | if (current == null || expectParent == null) { 39 | return false; 40 | } 41 | 42 | if (current == expectParent) { 43 | return true; 44 | } 45 | 46 | if (expectParent.isInterface()) { 47 | return hasParentInterface(current, expectParent); 48 | } else { 49 | return hasParentClass(current, expectParent); 50 | } 51 | } 52 | 53 | public static boolean hasParentClass(final Class current, final Class expectParentClass) { 54 | if (current == null || expectParentClass == null) { 55 | return false; 56 | } 57 | 58 | if (current == expectParentClass) { 59 | return true; 60 | } 61 | 62 | Class parentClass = current.getSuperclass(); 63 | if (parentClass == null) { 64 | return false; 65 | } 66 | 67 | if (parentClass == expectParentClass) { 68 | return true; 69 | } 70 | 71 | return hasParent(parentClass, expectParentClass); 72 | } 73 | 74 | public static boolean hasParentInterface(final Class current, final Class expectParentInterface) { 75 | if (current == null || expectParentInterface == null) { 76 | return false; 77 | } 78 | 79 | if (current == expectParentInterface) { 80 | return true; 81 | } 82 | 83 | Class[] interfaces = current.getInterfaces(); 84 | if (interfaces == null || interfaces.length == 0) { 85 | return false; 86 | } 87 | 88 | boolean result = false; 89 | for (Class iClass : interfaces) { 90 | if (iClass == expectParentInterface 91 | || hasParent(iClass, expectParentInterface)) { 92 | result = true; 93 | break; 94 | } 95 | } 96 | 97 | return result; 98 | } 99 | 100 | public static boolean isProperty(final Field field, final Method[] methods) { 101 | if (field == null || methods == null || methods.length == 0) { 102 | return false; 103 | } 104 | 105 | String name = field.getName(); 106 | String getMethodName = String.format("get%s", name); 107 | String isMethodName = String.format("is%s", name); 108 | String setMethodName = String.format("set%s", name); 109 | 110 | boolean hasGetMethod = false; 111 | boolean hasSetMethod = false; 112 | for (Method method : methods) { 113 | if (hasGetMethod && hasSetMethod) { 114 | break; 115 | } 116 | 117 | if (getMethodName.equalsIgnoreCase(method.getName()) 118 | || isMethodName.equalsIgnoreCase(method.getName())) { 119 | hasGetMethod = true; 120 | } 121 | 122 | if (setMethodName.equalsIgnoreCase(method.getName())) { 123 | hasSetMethod = true; 124 | } 125 | } 126 | return hasGetMethod && hasSetMethod; 127 | } 128 | 129 | private static void getProperties(Class targetClass, final Collection fields) { 130 | Class parentClass = targetClass.getSuperclass(); 131 | Field[] currentFields = getPropertiesForCurrentClass(targetClass); 132 | 133 | Collection filterDuplicatedFields = new ArrayList<>(); 134 | for (Field field : currentFields) { 135 | if (!hasContainsFieldName(field.getName(), fields)) { 136 | filterDuplicatedFields.add(field); 137 | } 138 | } 139 | 140 | fields.addAll(filterDuplicatedFields); 141 | if (parentClass != null) { 142 | getProperties(parentClass, fields); 143 | } 144 | } 145 | 146 | static boolean hasContainsFieldName(String fieldName, final Collection fields) { 147 | if (StringUtils.isBlank(fieldName)) { 148 | return false; 149 | } 150 | 151 | for (Field field : fields) { 152 | if (fieldName.equalsIgnoreCase(field.getName())) { 153 | return true; 154 | } 155 | } 156 | 157 | return false; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/lambda/GetBigDecimalPropertyFunction.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.lambda; 2 | 3 | import java.math.BigDecimal; 4 | 5 | /** 6 | * @author Frank 7 | */ 8 | public interface GetBigDecimalPropertyFunction extends GetPropertyFunction { 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/lambda/GetBytePropertyFunction.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.lambda; 2 | 3 | /** 4 | * @author Frank 5 | */ 6 | public interface GetBytePropertyFunction extends GetPropertyFunction { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/lambda/GetCommonPropertyFunction.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.lambda; 2 | 3 | /** 4 | * @author Frank 5 | */ 6 | public interface GetCommonPropertyFunction extends GetPropertyFunction { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/lambda/GetDatePropertyFunction.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.lambda; 2 | 3 | import java.util.Date; 4 | 5 | /** 6 | * @author Frank 7 | */ 8 | public interface GetDatePropertyFunction extends GetPropertyFunction { 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/lambda/GetDoublePropertyFunction.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.lambda; 2 | 3 | /** 4 | * @author Frank 5 | */ 6 | public interface GetDoublePropertyFunction extends GetPropertyFunction { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/lambda/GetFloatPropertyFunction.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.lambda; 2 | 3 | /** 4 | * @author Frank 5 | */ 6 | public interface GetFloatPropertyFunction extends GetPropertyFunction { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/lambda/GetIntegerPropertyFunction.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.lambda; 2 | 3 | /** 4 | * @author Frank 5 | */ 6 | public interface GetIntegerPropertyFunction extends GetPropertyFunction { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/lambda/GetLongPropertyFunction.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.lambda; 2 | 3 | /** 4 | * @author Frank 5 | */ 6 | public interface GetLongPropertyFunction extends GetPropertyFunction { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/lambda/GetPropertyFunction.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.lambda; 2 | 3 | import java.io.Serializable; 4 | import java.util.function.Function; 5 | 6 | /** 7 | * @author Frank 8 | */ 9 | @FunctionalInterface 10 | public interface GetPropertyFunction extends Function, Serializable { 11 | } -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/lambda/GetShortPropertyFunction.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.lambda; 2 | 3 | /** 4 | * @author Frank 5 | */ 6 | public interface GetShortPropertyFunction extends GetPropertyFunction { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/lambda/GetStringPropertyFunction.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.lambda; 2 | 3 | /** 4 | * @author Frank 5 | */ 6 | public interface GetStringPropertyFunction extends GetPropertyFunction { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/model/LogicPagingResult.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.function.Function; 6 | 7 | import static java.util.stream.Collectors.toList; 8 | 9 | /** 10 | * @author Frank 11 | **/ 12 | public class LogicPagingResult { 13 | private boolean hasPreviousPage; 14 | private boolean hasNextPage; 15 | private int pageSize; 16 | private long startPageId; 17 | private long endPageId; 18 | private List list = new ArrayList<>(); 19 | 20 | /** 21 | * 转换 LogicPagingResult 的数据泛型 22 | * 23 | * @param mapper 数据类型映射关系 24 | * @param 目标数据泛型 25 | * @return 目标数据泛型的 {@link NormPagingResult} 26 | */ 27 | public LogicPagingResult convert(Function mapper) { 28 | List collect = this.getList().stream().map(mapper).collect(toList()); 29 | ((LogicPagingResult)this).setList(collect); 30 | return ((LogicPagingResult)this); 31 | } 32 | 33 | public boolean isHasPreviousPage() { 34 | return hasPreviousPage; 35 | } 36 | 37 | public void setHasPreviousPage(boolean hasPreviousPage) { 38 | this.hasPreviousPage = hasPreviousPage; 39 | } 40 | 41 | public boolean isHasNextPage() { 42 | return hasNextPage; 43 | } 44 | 45 | public void setHasNextPage(boolean hasNextPage) { 46 | this.hasNextPage = hasNextPage; 47 | } 48 | 49 | public int getPageSize() { 50 | return pageSize; 51 | } 52 | 53 | public void setPageSize(int pageSize) { 54 | this.pageSize = pageSize; 55 | } 56 | 57 | public long getStartPageId() { 58 | return startPageId; 59 | } 60 | 61 | public void setStartPageId(long startPageId) { 62 | this.startPageId = startPageId; 63 | } 64 | 65 | public long getEndPageId() { 66 | return endPageId; 67 | } 68 | 69 | public void setEndPageId(long endPageId) { 70 | this.endPageId = endPageId; 71 | } 72 | 73 | public List getList() { 74 | return list == null ? new ArrayList<>() : new ArrayList<>(list); 75 | } 76 | 77 | public void setList(List list) { 78 | this.list = list == null ? new ArrayList<>() : new ArrayList<>(list); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/model/NormPagingResult.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.function.Function; 6 | 7 | import static java.util.stream.Collectors.toList; 8 | 9 | /** 10 | * @author Frank 11 | **/ 12 | public class NormPagingResult { 13 | /** 14 | * 是否有上一页 15 | */ 16 | private boolean hasPreviousPage; 17 | /** 18 | * 是否有下一页 19 | */ 20 | private boolean hasNextPage; 21 | /** 22 | * 每页数量 23 | */ 24 | private int pageSize; 25 | /** 26 | * 页码 27 | */ 28 | private int pageNum; 29 | /** 30 | * 总页数 31 | */ 32 | private int pages; 33 | /** 34 | * 总记录数 35 | */ 36 | private long total; 37 | /** 38 | * 结果集 39 | */ 40 | private List list = new ArrayList<>(); 41 | 42 | 43 | /** 44 | * 转换 NormPagingResult 的数据泛型 45 | * 46 | * @param mapper 数据类型映射关系 47 | * @param 目标数据泛型 48 | * @return 目标数据泛型的 {@link NormPagingResult} 49 | */ 50 | public NormPagingResult convert(Function mapper) { 51 | List collect = this.getList().stream().map(mapper).collect(toList()); 52 | ((NormPagingResult)this).setList(collect); 53 | return ((NormPagingResult)this); 54 | } 55 | 56 | public boolean isHasPreviousPage() { 57 | return hasPreviousPage; 58 | } 59 | 60 | public void setHasPreviousPage(boolean hasPreviousPage) { 61 | this.hasPreviousPage = hasPreviousPage; 62 | } 63 | 64 | public boolean isHasNextPage() { 65 | return hasNextPage; 66 | } 67 | 68 | public void setHasNextPage(boolean hasNextPage) { 69 | this.hasNextPage = hasNextPage; 70 | } 71 | 72 | public int getPageSize() { 73 | return pageSize; 74 | } 75 | 76 | public void setPageSize(int pageSize) { 77 | this.pageSize = pageSize; 78 | } 79 | 80 | public List getList() { 81 | return list == null ? new ArrayList<>() : new ArrayList<>(list); 82 | } 83 | 84 | public void setList(List list) { 85 | this.list = list == null ? new ArrayList<>() : new ArrayList<>(list); 86 | } 87 | 88 | public int getPageNum() { 89 | return pageNum; 90 | } 91 | 92 | public void setPageNum(int pageNum) { 93 | this.pageNum = pageNum; 94 | } 95 | 96 | public int getPages() { 97 | return pages; 98 | } 99 | 100 | public void setPages(int pages) { 101 | this.pages = pages; 102 | } 103 | 104 | public long getTotal() { 105 | return total; 106 | } 107 | 108 | public void setTotal(long total) { 109 | this.total = total; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/model/PropertyInfo.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.model; 2 | 3 | /** 4 | * @author Frank 5 | */ 6 | public class PropertyInfo { 7 | private String propertyName; 8 | private Class ownerClass; 9 | 10 | public String getPropertyName() { 11 | return propertyName; 12 | } 13 | 14 | public void setPropertyName(String propertyName) { 15 | this.propertyName = propertyName; 16 | } 17 | 18 | public Class getOwnerClass() { 19 | return ownerClass; 20 | } 21 | 22 | public void setOwnerClass(Class ownerClass) { 23 | this.ownerClass = ownerClass; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/model/SelectPropertyConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.model; 2 | 3 | import com.github.wz2cool.dynamic.helper.CommonsHelper; 4 | import com.github.wz2cool.dynamic.lambda.GetCommonPropertyFunction; 5 | 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | public class SelectPropertyConfig { 10 | 11 | private final Set selectPropertyNames = new HashSet<>(); 12 | private final Set ignorePropertyNames = new HashSet<>(); 13 | 14 | public Set getSelectPropertyNames() { 15 | return selectPropertyNames; 16 | } 17 | 18 | public Set getIgnorePropertyNames() { 19 | return ignorePropertyNames; 20 | } 21 | 22 | @SafeVarargs 23 | public final SelectPropertyConfig select(boolean enable, GetCommonPropertyFunction... getCommonPropertyFuncs) { 24 | for (GetCommonPropertyFunction getCommonPropertyFunc : getCommonPropertyFuncs) { 25 | final String propertyName = CommonsHelper.getPropertyName(getCommonPropertyFunc); 26 | selectPropertyNames.add(propertyName); 27 | } 28 | return this; 29 | } 30 | 31 | @SafeVarargs 32 | public final SelectPropertyConfig select(GetCommonPropertyFunction... getCommonPropertyFuncs) { 33 | return select(true, getCommonPropertyFuncs); 34 | } 35 | 36 | @SafeVarargs 37 | public final SelectPropertyConfig ignore(boolean enable, GetCommonPropertyFunction... getCommonPropertyFuncs) { 38 | for (GetCommonPropertyFunction getCommonPropertyFunc : getCommonPropertyFuncs) { 39 | final String propertyName = CommonsHelper.getPropertyName(getCommonPropertyFunc); 40 | ignorePropertyNames.add(propertyName); 41 | } 42 | return this; 43 | } 44 | 45 | @SafeVarargs 46 | public final SelectPropertyConfig ignore(GetCommonPropertyFunction... getCommonPropertyFuncs) { 47 | return ignore(true, getCommonPropertyFuncs); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/ColumnInfo.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | 5 | import java.lang.reflect.Field; 6 | 7 | /** 8 | * Created by Frank on 2017/6/25. 9 | */ 10 | public class ColumnInfo { 11 | private String columnName; 12 | private String tableOrAlias; 13 | private Field field; 14 | 15 | public Field getField() { 16 | return field; 17 | } 18 | 19 | public void setField(Field field) { 20 | this.field = field; 21 | } 22 | 23 | public String getColumnName() { 24 | return columnName; 25 | } 26 | 27 | public void setColumnName(String columnName) { 28 | this.columnName = columnName; 29 | } 30 | 31 | public String getTableOrAlias() { 32 | return tableOrAlias; 33 | } 34 | 35 | public void setTableOrAlias(String tableOrAlias) { 36 | this.tableOrAlias = tableOrAlias; 37 | } 38 | 39 | public String getQueryColumn() { 40 | if (StringUtils.isNotBlank(getTableOrAlias())) { 41 | return String.format("%s.%s", getTableOrAlias(), getColumnName()); 42 | } else { 43 | return this.columnName; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/EntityCache.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis; 2 | 3 | import com.github.wz2cool.dynamic.exception.PropertyNotFoundInternalException; 4 | import com.github.wz2cool.dynamic.helper.ParamResolverHelper; 5 | import com.github.wz2cool.dynamic.helper.ReflectHelper; 6 | import org.apache.commons.lang3.StringUtils; 7 | 8 | import javax.persistence.Column; 9 | import javax.persistence.Transient; 10 | import java.lang.reflect.Field; 11 | import java.util.*; 12 | import java.util.concurrent.ConcurrentHashMap; 13 | 14 | class EntityCache { 15 | private static EntityCache instance = new EntityCache(); 16 | private final Map propertyNameCacheMap = new ConcurrentHashMap<>(); 17 | private final Map> columnInfoCacheMap = new ConcurrentHashMap<>(); 18 | private static final String ENTITY_CLASS = "entityClass"; 19 | private final Map viewExpressionCacheMap = new ConcurrentHashMap<>(); 20 | 21 | // region implement singleton. 22 | 23 | private EntityCache() { 24 | } 25 | 26 | static EntityCache getInstance() { 27 | return instance; 28 | } 29 | 30 | // endregion 31 | 32 | String getViewExpression(Class entityClass) { 33 | String viewExpression = viewExpressionCacheMap.get(entityClass); 34 | if (Objects.nonNull(viewExpression)) { 35 | return viewExpression; 36 | } 37 | 38 | View view = (View) entityClass.getAnnotation(View.class); 39 | if (Objects.nonNull(view)) { 40 | viewExpression = ParamResolverHelper.resolveExpression(view.value()); 41 | viewExpressionCacheMap.put(entityClass, viewExpression); 42 | } else { 43 | viewExpressionCacheMap.put(entityClass, ""); 44 | } 45 | return viewExpression; 46 | } 47 | 48 | String[] getPropertyNames(final Class entityClass) { 49 | if (entityClass == null) { 50 | throw new NullPointerException(ENTITY_CLASS); 51 | } 52 | 53 | if (propertyNameCacheMap.containsKey(entityClass)) { 54 | return propertyNameCacheMap.get(entityClass); 55 | } else { 56 | Field[] fields = ReflectHelper.getProperties(entityClass); 57 | Collection propertyNames = new ArrayList<>(); 58 | for (Field field : fields) { 59 | propertyNames.add(field.getName()); 60 | } 61 | String[] fieldArray = propertyNames.toArray(new String[propertyNames.size()]); 62 | propertyNameCacheMap.put(entityClass, fieldArray); 63 | return fieldArray; 64 | } 65 | } 66 | 67 | boolean hasProperty(final Class entityClass, final String propertyName) { 68 | if (StringUtils.isBlank(propertyName)) { 69 | return false; 70 | } 71 | 72 | String[] propertyNames = getPropertyNames(entityClass); 73 | for (String pName : propertyNames) { 74 | if (propertyName.equalsIgnoreCase(pName)) { 75 | return true; 76 | } 77 | } 78 | 79 | return false; 80 | } 81 | 82 | ColumnInfo getColumnInfo(Class entityClass, String propertyName) { 83 | if (propertyName == null) { 84 | throw new NullPointerException("propertyName"); 85 | } 86 | 87 | Map propertyDbColumnMap = getPropertyColumnInfoMap(entityClass); 88 | if (!propertyDbColumnMap.containsKey(propertyName)) { 89 | throw new PropertyNotFoundInternalException(String.format("Can't found property: %s", propertyName)); 90 | } 91 | 92 | return propertyDbColumnMap.get(propertyName); 93 | } 94 | 95 | ColumnInfo[] getColumnInfos(Class entityClass) { 96 | Map propertyDbColumnMap = getPropertyColumnInfoMap(entityClass); 97 | Collection columnInfos = propertyDbColumnMap.values(); 98 | return columnInfos.toArray(new ColumnInfo[columnInfos.size()]); 99 | } 100 | 101 | Map getPropertyColumnInfoMap(Class entityClass) { 102 | if (entityClass == null) { 103 | throw new NullPointerException(ENTITY_CLASS); 104 | } 105 | 106 | Map propertyDbColumnMap; 107 | if (columnInfoCacheMap.containsKey(entityClass)) { 108 | propertyDbColumnMap = columnInfoCacheMap.get(entityClass); 109 | } else { 110 | Map map = new HashMap<>(10); 111 | Field[] properties = ReflectHelper.getProperties(entityClass); 112 | 113 | for (Field field : properties) { 114 | field.setAccessible(true); 115 | // and Transient 116 | if (field.isAnnotationPresent(Transient.class)) { 117 | continue; 118 | } 119 | 120 | ColumnInfo columnInfo = new ColumnInfo(); 121 | columnInfo.setField(field); 122 | String pName = field.getName(); 123 | String columnName = EntityHelper.getColumnNameByProperty(pName, properties); 124 | columnInfo.setColumnName(columnName); 125 | 126 | Column column = EntityHelper.getColumnByProperty(pName, properties); 127 | String tableOrAlias = column == null ? "" : ParamResolverHelper.resolveExpression(column.table()); 128 | columnInfo.setTableOrAlias(tableOrAlias); 129 | map.put(pName, columnInfo); 130 | } 131 | columnInfoCacheMap.put(entityClass, map); 132 | propertyDbColumnMap = map; 133 | } 134 | 135 | return propertyDbColumnMap; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/EntityHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis; 2 | 3 | import com.github.wz2cool.dynamic.exception.PropertyNotFoundInternalException; 4 | import org.apache.commons.lang3.StringUtils; 5 | 6 | import javax.persistence.Column; 7 | import javax.persistence.Table; 8 | import java.lang.reflect.Field; 9 | 10 | /** 11 | * @author Frank 12 | */ 13 | public class EntityHelper { 14 | private EntityHelper() { 15 | throw new UnsupportedOperationException(); 16 | } 17 | 18 | static String getTableName(final Class tableClass) { 19 | if (tableClass == null) { 20 | throw new NullPointerException("tableClass"); 21 | } 22 | 23 | if (tableClass.isAnnotationPresent(Table.class)) { 24 | Table table = tableClass.getAnnotation(Table.class); 25 | String dbTableName = table.name(); 26 | if (StringUtils.isNotBlank(dbTableName)) { 27 | return dbTableName; 28 | } 29 | } 30 | 31 | String useTableName = tableClass.getSimpleName(); 32 | return camelCaseToUnderscore(useTableName); 33 | } 34 | 35 | static String getColumnNameByProperty(final String propertyName, final Field[] properties) { 36 | Field matchProperty = getPropertyField(propertyName, properties); 37 | Column column = getColumnByProperty(propertyName, properties); 38 | if (column != null && StringUtils.isNotBlank(column.name())) { 39 | return column.name(); 40 | } 41 | 42 | 43 | String usePropertyName = matchProperty.getName(); 44 | return camelCaseToUnderscore(usePropertyName); 45 | } 46 | 47 | static Column getColumnByProperty(final String propertyName, final Field[] properties) { 48 | Field matchProperty = getPropertyField(propertyName, properties); 49 | if (matchProperty.isAnnotationPresent(Column.class)) { 50 | return matchProperty.getAnnotation(Column.class); 51 | } 52 | 53 | return null; 54 | } 55 | 56 | static Field getPropertyField(final String propertyName, final Field[] properties) { 57 | if (StringUtils.isBlank(propertyName) || properties == null || properties.length == 0) { 58 | throw new PropertyNotFoundInternalException(String.format("Can't find property: %s", propertyName)); 59 | } 60 | 61 | Field result = null; 62 | for (Field property : properties) { 63 | if (propertyName.trim().equalsIgnoreCase(property.getName())) { 64 | result = property; 65 | break; 66 | } 67 | } 68 | 69 | if (result != null) { 70 | return result; 71 | } else { 72 | throw new PropertyNotFoundInternalException(String.format("Can't find property: %s", propertyName)); 73 | } 74 | } 75 | 76 | public static String camelCaseToUnderscore(String str) { 77 | return str.replaceAll("(.)(\\p{Lu})", "$1_$2").toLowerCase(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/ExpressionHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis; 2 | 3 | import com.github.wz2cool.dynamic.FilterOperator; 4 | 5 | import java.security.InvalidParameterException; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * Created by Frank on 7/17/2017. 11 | */ 12 | @SuppressWarnings("squid:S1192") 13 | class ExpressionHelper { 14 | 15 | @SuppressWarnings("squid:MethodCyclomaticComplexity") 16 | String getExpression(final FilterOperator operator, final ColumnInfo columnInfo, final Object filterValue, final String... paramPlaceholders) { 17 | switch (operator) { 18 | case EQUAL: 19 | return getEqualExpression(columnInfo, filterValue, paramPlaceholders); 20 | case NOT_EQUAL: 21 | return getNotEqualExpression(columnInfo, filterValue, paramPlaceholders); 22 | case LESS_THAN: 23 | return getLessThanExpression(columnInfo, paramPlaceholders); 24 | case LESS_THAN_OR_EQUAL: 25 | return getLessThanOrEqualExpression(columnInfo, paramPlaceholders); 26 | case GREATER_THAN_OR_EQUAL: 27 | return getGreaterThanOrEqualExpression(columnInfo, paramPlaceholders); 28 | case GREATER_THAN: 29 | return getGreaterThanExpression(columnInfo, paramPlaceholders); 30 | case START_WITH: 31 | case END_WITH: 32 | case CONTAINS: 33 | return getLikeExpression(columnInfo, paramPlaceholders); 34 | case IN: 35 | return getInExpression(columnInfo, paramPlaceholders); 36 | case NOT_IN: 37 | return getNotInExpression(columnInfo, paramPlaceholders); 38 | case BETWEEN: 39 | return getBetweenExpression(columnInfo, paramPlaceholders); 40 | case NOT_CONTAINS: 41 | return getNotLikeExpression(columnInfo, paramPlaceholders); 42 | default: 43 | throw new UnsupportedOperationException(String.format("not support operator: %s", operator)); 44 | } 45 | } 46 | 47 | String getNotLikeExpression(final ColumnInfo columnInfo, final String... paramPlaceholders) { 48 | return String.format("%s NOT LIKE #{%s}", columnInfo.getQueryColumn(), paramPlaceholders[0]); 49 | 50 | } 51 | 52 | String getEqualExpression(final ColumnInfo columnInfo, Object filterValue, final String... paramPlaceholders) { 53 | if (filterValue == null) { 54 | return String.format("%s IS NULL", columnInfo.getQueryColumn()); 55 | } 56 | 57 | return String.format("%s = #{%s}", columnInfo.getQueryColumn(), paramPlaceholders[0]); 58 | } 59 | 60 | String getNotEqualExpression(final ColumnInfo columnInfo, Object filterValue, final String... paramPlaceholders) { 61 | if (filterValue == null) { 62 | return String.format("%s IS NOT NULL", columnInfo.getQueryColumn()); 63 | } 64 | 65 | return String.format("%s <> #{%s}", columnInfo.getQueryColumn(), paramPlaceholders[0]); 66 | } 67 | 68 | String getLessThanExpression(final ColumnInfo columnInfo, final String... paramPlaceholders) { 69 | return String.format("%s < #{%s}", columnInfo.getQueryColumn(), paramPlaceholders[0]); 70 | } 71 | 72 | String getLessThanOrEqualExpression(final ColumnInfo columnInfo, final String... paramPlaceholders) { 73 | return String.format("%s <= #{%s}", columnInfo.getQueryColumn(), paramPlaceholders[0]); 74 | } 75 | 76 | String getGreaterThanOrEqualExpression(final ColumnInfo columnInfo, final String... paramPlaceholders) { 77 | return String.format("%s >= #{%s}", columnInfo.getQueryColumn(), paramPlaceholders[0]); 78 | } 79 | 80 | String getGreaterThanExpression(final ColumnInfo columnInfo, final String... paramPlaceholders) { 81 | return String.format("%s > #{%s}", columnInfo.getQueryColumn(), paramPlaceholders[0]); 82 | } 83 | 84 | String getLikeExpression(final ColumnInfo columnInfo, final String... paramPlaceholders) { 85 | return String.format("%s LIKE #{%s}", columnInfo.getQueryColumn(), paramPlaceholders[0]); 86 | } 87 | 88 | String getInExpression(final ColumnInfo columnInfo, final String... paramPlaceholders) { 89 | if (paramPlaceholders.length == 0) { 90 | return "FALSE"; 91 | } 92 | 93 | String inStr = "%s IN (%s)"; 94 | List formattedParams = new ArrayList<>(); 95 | for (String paramPlaceholder : paramPlaceholders) { 96 | formattedParams.add(String.format("#{%s}", paramPlaceholder)); 97 | } 98 | return String.format(inStr, columnInfo.getQueryColumn(), String.join(",", formattedParams)); 99 | } 100 | 101 | String getNotInExpression(final ColumnInfo columnInfo, final String... paramPlaceholders) { 102 | if (paramPlaceholders.length == 0) { 103 | return "TRUE"; 104 | } 105 | 106 | String notInStr = "%s NOT IN (%s)"; 107 | List formattedParams = new ArrayList<>(); 108 | for (String paramPlaceholder : paramPlaceholders) { 109 | formattedParams.add(String.format("#{%s}", paramPlaceholder)); 110 | } 111 | return String.format(notInStr, columnInfo.getQueryColumn(), String.join(",", formattedParams)); 112 | } 113 | 114 | String getBetweenExpression(final ColumnInfo columnInfo, final String... paramPlaceholders) { 115 | int expectedSize = 2; 116 | if (paramPlaceholders.length != expectedSize) { 117 | String errMsg = "if \"Between\" operator, the count of paramPlaceholders must be 2"; 118 | throw new InvalidParameterException(errMsg); 119 | } 120 | 121 | return String.format("%s BETWEEN #{%s} AND #{%s}", columnInfo.getQueryColumn(), paramPlaceholders[0], paramPlaceholders[1]); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/ParamExpression.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis; 2 | 3 | import java.util.LinkedHashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * @author Frank 8 | */ 9 | public class ParamExpression { 10 | private String expression = ""; 11 | private Map paramMap = new LinkedHashMap<>(); 12 | 13 | public String getExpression() { 14 | return expression; 15 | } 16 | 17 | public void setExpression(String expression) { 18 | this.expression = expression; 19 | } 20 | 21 | public Map getParamMap() { 22 | return paramMap; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/TypeHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.Date; 5 | 6 | /** 7 | * @author Frank 8 | **/ 9 | public class TypeHelper { 10 | private TypeHelper() { 11 | } 12 | 13 | public static BigDecimal getBigDecimal(Object value) { 14 | BigDecimal ret = null; 15 | if (value != null) { 16 | if (value instanceof BigDecimal) { 17 | ret = (BigDecimal)value; 18 | } else { 19 | ret = new BigDecimal(value.toString()); 20 | } 21 | } 22 | 23 | return ret; 24 | } 25 | 26 | public static Byte getByte(Object value) { 27 | Byte ret = null; 28 | if (value != null) { 29 | if (value instanceof Byte) { 30 | ret = (Byte)value; 31 | } else { 32 | ret = new Byte(value.toString()); 33 | } 34 | } 35 | 36 | return ret; 37 | } 38 | 39 | public static Date getDate(Object value) { 40 | Date ret = null; 41 | if (value != null) { 42 | if (!(value instanceof Date)) { 43 | throw new ClassCastException("Not possible to coerce [" + value + "] from class " + value.getClass() + " into a Date."); 44 | } 45 | 46 | ret = (Date)value; 47 | } 48 | 49 | return ret; 50 | } 51 | 52 | public static Double getDouble(Object value) { 53 | Double ret = null; 54 | if (value != null) { 55 | if (value instanceof Double) { 56 | ret = (Double)value; 57 | } else { 58 | ret = new Double(value.toString()); 59 | } 60 | } 61 | 62 | return ret; 63 | } 64 | 65 | public static Float getFloat(Object value) { 66 | Float ret = null; 67 | if (value != null) { 68 | if (value instanceof Float) { 69 | ret = (Float)value; 70 | } else { 71 | ret = new Float(value.toString()); 72 | } 73 | } 74 | 75 | return ret; 76 | } 77 | 78 | public static Integer getInteger(Object value) { 79 | Integer ret = null; 80 | if (value != null) { 81 | if (value instanceof Integer) { 82 | ret = (Integer)value; 83 | } else { 84 | ret = new Integer(value.toString()); 85 | } 86 | } 87 | 88 | return ret; 89 | } 90 | 91 | public static Long getLong(Object value) { 92 | Long ret = null; 93 | if (value != null) { 94 | if (value instanceof Long) { 95 | ret = (Long)value; 96 | } else { 97 | ret = new Long(value.toString()); 98 | } 99 | } 100 | 101 | return ret; 102 | } 103 | 104 | public static Short getShort(Object value) { 105 | Short ret = null; 106 | if (value != null) { 107 | if (value instanceof Short) { 108 | ret = (Short)value; 109 | } else { 110 | ret = new Short(value.toString()); 111 | } 112 | } 113 | 114 | return ret; 115 | } 116 | 117 | public static String getString(Object value) { 118 | String ret = null; 119 | if (value != null) { 120 | if (value instanceof String) { 121 | ret = (String)value; 122 | } else { 123 | ret = value.toString(); 124 | } 125 | } 126 | 127 | return ret; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/View.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * @author Frank 10 | **/ 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target(ElementType.TYPE) 13 | public @interface View { 14 | String value() default ""; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/mapper/DeleteByDynamicQueryMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.mapper; 2 | 3 | import com.github.wz2cool.dynamic.DynamicQuery; 4 | import com.github.wz2cool.dynamic.mybatis.mapper.constant.MapperConstants; 5 | import com.github.wz2cool.dynamic.mybatis.mapper.provider.DynamicQueryProvider; 6 | import org.apache.ibatis.annotations.DeleteProvider; 7 | import org.apache.ibatis.annotations.Param; 8 | import tk.mybatis.mapper.annotation.RegisterMapper; 9 | 10 | /** 11 | * @author Frank 12 | */ 13 | @RegisterMapper 14 | public interface DeleteByDynamicQueryMapper { 15 | /** 16 | * delete by dynamic query. 17 | * 18 | * @param dynamicQuery dynamic query 19 | * @return effect rows 20 | */ 21 | @DeleteProvider(type = DynamicQueryProvider.class, method = "dynamicSQL") 22 | int deleteByDynamicQuery(@Param(MapperConstants.DYNAMIC_QUERY) DynamicQuery dynamicQuery); 23 | } -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/mapper/MySqlMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.mapper; 2 | 3 | import com.github.wz2cool.dynamic.mybatis.mapper.mysql.InsertIgnoreMapper; 4 | import com.github.wz2cool.dynamic.mybatis.mapper.mysql.InsertIgnoreSelectiveMapper; 5 | import tk.mybatis.mapper.annotation.RegisterMapper; 6 | 7 | @RegisterMapper 8 | public interface MySqlMapper extends 9 | InsertIgnoreMapper, 10 | InsertIgnoreSelectiveMapper { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/mapper/SelectByDynamicQueryMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.mapper; 2 | 3 | import com.github.wz2cool.dynamic.DynamicQuery; 4 | import com.github.wz2cool.dynamic.mybatis.mapper.constant.MapperConstants; 5 | import com.github.wz2cool.dynamic.mybatis.mapper.provider.DynamicQueryProvider; 6 | import org.apache.ibatis.annotations.Param; 7 | import org.apache.ibatis.annotations.SelectProvider; 8 | import tk.mybatis.mapper.annotation.RegisterMapper; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * @author Frank 14 | */ 15 | @RegisterMapper 16 | public interface SelectByDynamicQueryMapper { 17 | 18 | /** 19 | * select by dynamic query 20 | * 21 | * @param dynamicQuery dynamic query 22 | * @return list of item 23 | */ 24 | @SelectProvider(type = DynamicQueryProvider.class, method = "dynamicSQL") 25 | List selectByDynamicQuery(@Param(MapperConstants.DYNAMIC_QUERY) DynamicQuery dynamicQuery); 26 | } -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/mapper/SelectByGroupedQueryMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.mapper; 2 | 3 | import com.github.wz2cool.dynamic.GroupedQuery; 4 | import com.github.wz2cool.dynamic.NormPagingQueryWrapper; 5 | import com.github.wz2cool.dynamic.model.NormPagingResult; 6 | import com.github.wz2cool.dynamic.mybatis.mapper.constant.MapperConstants; 7 | import com.github.wz2cool.dynamic.mybatis.mapper.provider.GroupedQueryProvider; 8 | import org.apache.ibatis.annotations.Param; 9 | import org.apache.ibatis.annotations.SelectProvider; 10 | import org.apache.ibatis.session.RowBounds; 11 | import tk.mybatis.mapper.annotation.RegisterMapper; 12 | 13 | import java.util.List; 14 | import java.util.Optional; 15 | 16 | /** 17 | * @author Frank 18 | **/ 19 | @RegisterMapper 20 | @SuppressWarnings("java:S119") 21 | public interface SelectByGroupedQueryMapper { 22 | 23 | /** 24 | * select by grouped query 25 | * 26 | * @param groupedQuery grouped query 27 | * @return list of item 28 | */ 29 | @SelectProvider(type = GroupedQueryProvider.class, method = "dynamicSQL") 30 | List selectByGroupedQuery(@Param(MapperConstants.GROUPED_QUERY) GroupedQuery groupedQuery); 31 | 32 | 33 | /** 34 | * select count by grouped query. 35 | * 36 | * @param groupedQuery grouped query 37 | * @return the count of items 38 | */ 39 | @SelectProvider(type = GroupedQueryProvider.class, method = "dynamicSQL") 40 | int selectCountByGroupedQuery(@Param(MapperConstants.GROUPED_QUERY) GroupedQuery groupedQuery); 41 | 42 | /** 43 | * select row rounds by grouped query. 44 | * 45 | * @param groupedQuery grouped query 46 | * @param rowBounds row bounds 47 | * @return the list of items 48 | */ 49 | @SelectProvider(type = GroupedQueryProvider.class, method = "dynamicSQL") 50 | List selectRowBoundsByGroupedQuery( 51 | @Param(MapperConstants.GROUPED_QUERY) GroupedQuery groupedQuery, 52 | RowBounds rowBounds); 53 | 54 | /** 55 | * select first record by grouped query 56 | * 57 | * @param groupedQuery grouped query 58 | * @return matched first record 59 | */ 60 | default Optional selectFirstByGroupedQuery(GroupedQuery groupedQuery) { 61 | RowBounds rowBounds = new RowBounds(0, 1); 62 | List result = selectRowBoundsByGroupedQuery(groupedQuery, rowBounds); 63 | if (result == null || result.isEmpty()) { 64 | return Optional.empty(); 65 | } else { 66 | return Optional.ofNullable(result.get(0)); 67 | } 68 | } 69 | 70 | default NormPagingResult selectNormalPagingByGroupedQuery( 71 | NormPagingQueryWrapper> normPagingQueryWrapper) { 72 | NormPagingResult result = new NormPagingResult<>(); 73 | int pageNum = normPagingQueryWrapper.getPageNum() < 1 ? 1 : normPagingQueryWrapper.getPageNum(); 74 | int pageSize = normPagingQueryWrapper.getPageSize(); 75 | int queryPageSize = pageSize + 1; 76 | int offset = (pageNum - 1) * pageSize; 77 | List dataList = selectRowBoundsByGroupedQuery(normPagingQueryWrapper.getSearchQuery(), new RowBounds(offset, queryPageSize)); 78 | // 补偿当前页没有需要到上一页 79 | if (normPagingQueryWrapper.isAutoBackIfEmpty() && dataList.isEmpty() && pageNum > 1) { 80 | int newPageNum = pageNum - 1; 81 | NormPagingQueryWrapper> newNormPagingQueryWrapper = 82 | new NormPagingQueryWrapper<>(normPagingQueryWrapper.getSearchQuery()); 83 | newNormPagingQueryWrapper.setPageNum(newPageNum); 84 | newNormPagingQueryWrapper.setPageSize(normPagingQueryWrapper.getPageSize()); 85 | newNormPagingQueryWrapper.setAutoBackIfEmpty(normPagingQueryWrapper.isAutoBackIfEmpty()); 86 | newNormPagingQueryWrapper.setCalcTotal(normPagingQueryWrapper.isCalcTotal()); 87 | return selectNormalPagingByGroupedQuery(newNormPagingQueryWrapper); 88 | } 89 | if (normPagingQueryWrapper.isCalcTotal()) { 90 | int totalCount = selectCountByGroupedQuery(normPagingQueryWrapper.getSearchQuery()); 91 | int pages = (int) Math.ceil((double) totalCount / pageSize); 92 | result.setTotal(totalCount); 93 | result.setPages(pages); 94 | } 95 | boolean hasNext = dataList.size() > pageSize; 96 | boolean hasPre = pageNum > 1; 97 | result.setHasNextPage(hasNext); 98 | result.setHasPreviousPage(hasPre); 99 | if (dataList.size() > pageSize) { 100 | result.setList(dataList.subList(0, pageSize)); 101 | } else { 102 | result.setList(dataList); 103 | } 104 | result.setPageNum(pageNum); 105 | result.setPageSize(normPagingQueryWrapper.getPageSize()); 106 | return result; 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/mapper/SelectCountByDynamicQueryMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.mapper; 2 | 3 | import com.github.wz2cool.dynamic.DynamicQuery; 4 | import com.github.wz2cool.dynamic.helper.CommonsHelper; 5 | import com.github.wz2cool.dynamic.lambda.GetPropertyFunction; 6 | import com.github.wz2cool.dynamic.mybatis.QueryHelper; 7 | import com.github.wz2cool.dynamic.mybatis.TypeHelper; 8 | import com.github.wz2cool.dynamic.mybatis.mapper.constant.MapperConstants; 9 | import com.github.wz2cool.dynamic.mybatis.mapper.provider.DynamicQueryProvider; 10 | import org.apache.ibatis.annotations.Param; 11 | import org.apache.ibatis.annotations.SelectProvider; 12 | import tk.mybatis.mapper.annotation.RegisterMapper; 13 | 14 | /** 15 | * @author Frank 16 | */ 17 | @RegisterMapper 18 | public interface SelectCountByDynamicQueryMapper { 19 | 20 | QueryHelper QUERY_HELPER = new QueryHelper(); 21 | 22 | /** 23 | * select count by dynamic query. 24 | * 25 | * @param dynamicQuery dynamic query 26 | * @return the count of items 27 | */ 28 | @SelectProvider(type = DynamicQueryProvider.class, method = "dynamicSQL") 29 | int selectCountByDynamicQuery(@Param(MapperConstants.DYNAMIC_QUERY) DynamicQuery dynamicQuery); 30 | 31 | @SelectProvider(type = DynamicQueryProvider.class, method = "dynamicSQL") 32 | Integer selectCountPropertyByDynamicQuery(@Param(MapperConstants.COLUMN) String column, @Param(MapperConstants.DYNAMIC_QUERY) DynamicQuery dynamicQuery); 33 | 34 | default > Integer selectCountPropertyByDynamicQuery(GetPropertyFunction getPropertyFunction, DynamicQuery dynamicQuery) { 35 | Object result = selectCountPropertyByDynamicQueryInternal(getPropertyFunction, dynamicQuery); 36 | return TypeHelper.getInteger(result); 37 | } 38 | 39 | default > Object selectCountPropertyByDynamicQueryInternal( 40 | GetPropertyFunction getPropertyFunction, DynamicQuery dynamicQuery) { 41 | String propertyName = CommonsHelper.getPropertyName(getPropertyFunction); 42 | Class entityClass = dynamicQuery.getEntityClass(); 43 | String queryColumn = QUERY_HELPER.getQueryColumnByProperty(entityClass, propertyName); 44 | return selectCountPropertyByDynamicQuery(queryColumn, dynamicQuery); 45 | } 46 | } -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/mapper/SelectRowBoundsByDynamicQueryMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.mapper; 2 | 3 | import com.github.wz2cool.dynamic.*; 4 | import com.github.wz2cool.dynamic.helper.CommonsHelper; 5 | import com.github.wz2cool.dynamic.model.LogicPagingResult; 6 | import com.github.wz2cool.dynamic.mybatis.mapper.constant.MapperConstants; 7 | import com.github.wz2cool.dynamic.mybatis.mapper.helper.LogicPagingHelper; 8 | import com.github.wz2cool.dynamic.mybatis.mapper.provider.DynamicQueryProvider; 9 | import org.apache.ibatis.annotations.Param; 10 | import org.apache.ibatis.annotations.SelectProvider; 11 | import org.apache.ibatis.session.RowBounds; 12 | import tk.mybatis.mapper.annotation.RegisterMapper; 13 | 14 | import java.util.*; 15 | 16 | /** 17 | * @author Frank 18 | */ 19 | @RegisterMapper 20 | public interface SelectRowBoundsByDynamicQueryMapper { 21 | 22 | /** 23 | * select row rounds by dynamic query. 24 | * 25 | * @param dynamicQuery dynamic query 26 | * @param rowBounds row bounds 27 | * @return the list of items 28 | */ 29 | @SelectProvider(type = DynamicQueryProvider.class, method = "dynamicSQL") 30 | List selectRowBoundsByDynamicQuery( 31 | @Param(MapperConstants.DYNAMIC_QUERY) DynamicQuery dynamicQuery, 32 | RowBounds rowBounds); 33 | 34 | /** 35 | * select first record by dynamic query 36 | * 37 | * @param dynamicQuery dynamic query 38 | * @return matched first record 39 | */ 40 | default Optional selectFirstByDynamicQuery(DynamicQuery dynamicQuery) { 41 | RowBounds rowBounds = new RowBounds(0, 1); 42 | List result = selectRowBoundsByDynamicQuery(dynamicQuery, rowBounds); 43 | if (result == null || result.isEmpty()) { 44 | return Optional.empty(); 45 | } else { 46 | return Optional.ofNullable(result.get(0)); 47 | } 48 | } 49 | 50 | /** 51 | * select by logic paging 52 | * 53 | * @param logicPagingQuery logic paging query 54 | * @return logic paging result 55 | */ 56 | default LogicPagingResult selectByLogicPaging(LogicPagingQuery logicPagingQuery) { 57 | int pageSize = logicPagingQuery.getPageSize(); 58 | int queryPageSize = pageSize + 1; 59 | DynamicQuery dynamicQuery = DynamicQuery.createQuery(logicPagingQuery.getClazz()); 60 | dynamicQuery.addFilters(logicPagingQuery.getFilters()); 61 | dynamicQuery.setDistinct(logicPagingQuery.isDistinct()); 62 | dynamicQuery.setSelectedProperties(logicPagingQuery.getSelectedProperties()); 63 | dynamicQuery.setIgnoredProperties(logicPagingQuery.getIgnoredProperties()); 64 | Map.Entry mapEntry = LogicPagingHelper.getPagingSortFilterMap( 65 | logicPagingQuery.getPagingPropertyFunc(), 66 | logicPagingQuery.getSortDescriptor().getDirection(), 67 | logicPagingQuery.getLastStartPageId(), 68 | logicPagingQuery.getLastEndPageId(), 69 | logicPagingQuery.getUpDown()); 70 | // 加上主要排序 71 | dynamicQuery.addSorts(mapEntry.getKey()); 72 | // 紧跟上次要排序 73 | dynamicQuery.addSorts(logicPagingQuery.getSorts()); 74 | if (Objects.nonNull(mapEntry.getValue())) { 75 | dynamicQuery.addFilters(mapEntry.getValue()); 76 | } 77 | List dataList = selectRowBoundsByDynamicQuery(dynamicQuery, new RowBounds(0, queryPageSize)); 78 | if (!logicPagingQuery.getSortDirection().equals(mapEntry.getKey().getDirection())) { 79 | Collections.reverse(dataList); 80 | } 81 | Optional> logicPagingResultOptional = LogicPagingHelper.getPagingResult( 82 | logicPagingQuery.getPagingPropertyFunc(), 83 | dataList, logicPagingQuery.getPageSize(), logicPagingQuery.getUpDown()); 84 | if (logicPagingResultOptional.isPresent()) { 85 | return logicPagingResultOptional.get(); 86 | } 87 | LogicPagingQuery resetPagingQuery = LogicPagingQuery.createQuery( 88 | logicPagingQuery.getClazz(), 89 | logicPagingQuery.getPagingPropertyFunc(), 90 | logicPagingQuery.getSortDirection(), 91 | UpDown.NONE); 92 | resetPagingQuery.setPageSize(logicPagingQuery.getPageSize()); 93 | resetPagingQuery.setFilters(logicPagingQuery.getFilters()); 94 | return selectByLogicPaging(resetPagingQuery); 95 | } 96 | } -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/mapper/SelectViewByDynamicQueryMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.mapper; 2 | 3 | import tk.mybatis.mapper.annotation.RegisterMapper; 4 | 5 | /** 6 | * @author Frank 7 | **/ 8 | @RegisterMapper 9 | public interface SelectViewByDynamicQueryMapper extends 10 | SelectCountByDynamicQueryMapper, 11 | SelectByDynamicQueryMapper, 12 | SelectRowBoundsByDynamicQueryMapper, 13 | SelectMaxByDynamicQueryMapper, 14 | SelectMinByDynamicQueryMapper, 15 | SelectSumByDynamicQueryMapper, 16 | SelectAvgByDynamicQueryMapper { 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/mapper/UpdateByDynamicQueryMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.mapper; 2 | 3 | import com.github.wz2cool.dynamic.DynamicQuery; 4 | import com.github.wz2cool.dynamic.mybatis.mapper.constant.MapperConstants; 5 | import com.github.wz2cool.dynamic.mybatis.mapper.provider.DynamicQueryProvider; 6 | import org.apache.ibatis.annotations.Param; 7 | import org.apache.ibatis.annotations.UpdateProvider; 8 | import tk.mybatis.mapper.annotation.RegisterMapper; 9 | 10 | /** 11 | * @author Frank 12 | */ 13 | @RegisterMapper 14 | public interface UpdateByDynamicQueryMapper { 15 | /** 16 | * update by dynamic query. 17 | * 18 | * @param record record of item 19 | * @param dynamicQuery dynamic query 20 | * @return effect rows 21 | */ 22 | @UpdateProvider(type = DynamicQueryProvider.class, method = "dynamicSQL") 23 | int updateByDynamicQuery( 24 | @Param("record") T record, 25 | @Param(MapperConstants.DYNAMIC_QUERY) DynamicQuery dynamicQuery); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/mapper/UpdateByUpdateQueryMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.mapper; 2 | 3 | import com.github.wz2cool.dynamic.UpdateQuery; 4 | import com.github.wz2cool.dynamic.mybatis.mapper.constant.MapperConstants; 5 | import com.github.wz2cool.dynamic.mybatis.mapper.provider.DynamicQueryProvider; 6 | import org.apache.ibatis.annotations.Param; 7 | import org.apache.ibatis.annotations.UpdateProvider; 8 | import tk.mybatis.mapper.annotation.RegisterMapper; 9 | 10 | /** 11 | * @author Frank 12 | **/ 13 | @RegisterMapper 14 | public interface UpdateByUpdateQueryMapper { 15 | 16 | /** 17 | * update selective by dynamic query. 18 | * 19 | * @param updateQuery update query 20 | * @return effect rows 21 | */ 22 | @UpdateProvider(type = DynamicQueryProvider.class, method = "dynamicSQL") 23 | int updateByUpdateQuery( 24 | @Param(MapperConstants.DYNAMIC_QUERY) UpdateQuery updateQuery); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/mapper/UpdateSelectiveByDynamicQueryMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.mapper; 2 | 3 | import com.github.wz2cool.dynamic.DynamicQuery; 4 | import com.github.wz2cool.dynamic.mybatis.mapper.constant.MapperConstants; 5 | import com.github.wz2cool.dynamic.mybatis.mapper.provider.DynamicQueryProvider; 6 | import org.apache.ibatis.annotations.Param; 7 | import org.apache.ibatis.annotations.UpdateProvider; 8 | import tk.mybatis.mapper.annotation.RegisterMapper; 9 | 10 | /** 11 | * @author Frank 12 | */ 13 | @RegisterMapper 14 | public interface UpdateSelectiveByDynamicQueryMapper { 15 | 16 | /** 17 | * update selective by dynamic query. 18 | * 19 | * @param record record of item 20 | * @param dynamicQuery dynamic query 21 | * @return effect rows 22 | */ 23 | @UpdateProvider(type = DynamicQueryProvider.class, method = "dynamicSQL") 24 | int updateSelectiveByDynamicQuery( 25 | @Param("record") T record, 26 | @Param(MapperConstants.DYNAMIC_QUERY) DynamicQuery dynamicQuery); 27 | } -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/mapper/batch/MapperBatchAction.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.mapper.batch; 2 | 3 | import com.github.wz2cool.dynamic.mybatis.mapper.DynamicQueryMapper; 4 | import org.apache.ibatis.executor.BatchResult; 5 | import org.apache.ibatis.session.ExecutorType; 6 | import org.apache.ibatis.session.SqlSession; 7 | import org.apache.ibatis.session.SqlSessionFactory; 8 | 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | import java.util.List; 12 | import java.util.function.Consumer; 13 | 14 | /** 15 | * @author Frank 16 | **/ 17 | public class MapperBatchAction> { 18 | 19 | private final SqlSessionFactory sqlSessionFactory; 20 | private final Class mapperClass; 21 | private int batchSize = 100; 22 | 23 | private List> actions = new ArrayList<>(); 24 | 25 | public MapperBatchAction(Class mapperClass, SqlSessionFactory sqlSessionFactory) { 26 | this.sqlSessionFactory = sqlSessionFactory; 27 | this.mapperClass = mapperClass; 28 | } 29 | 30 | public MapperBatchAction(Class mapperClass, SqlSessionFactory sqlSessionFactory, int batchSize) { 31 | this.sqlSessionFactory = sqlSessionFactory; 32 | this.mapperClass = mapperClass; 33 | this.batchSize = batchSize; 34 | } 35 | 36 | public static > MapperBatchAction create( 37 | Class mapperClass, SqlSessionFactory sqlSessionFactory) { 38 | return new MapperBatchAction<>(mapperClass, sqlSessionFactory); 39 | } 40 | 41 | public static > MapperBatchAction create( 42 | Class mapperClass, SqlSessionFactory sqlSessionFactory, int batchSize) { 43 | return new MapperBatchAction<>(mapperClass, sqlSessionFactory, batchSize); 44 | } 45 | 46 | public MapperBatchAction addAction(Consumer action) { 47 | actions.add(action); 48 | return this; 49 | } 50 | 51 | /** 52 | * do batch action and return batch result. 53 | * 54 | * @return batch result. 55 | */ 56 | public List doBatchActionWithResults() { 57 | List result = new ArrayList<>(); 58 | try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false)) { 59 | final M mapper = sqlSession.getMapper(mapperClass); 60 | for (int i = 0; i < actions.size(); i++) { 61 | actions.get(i).accept(mapper); 62 | 63 | if (i != 0 && (i + 1) % batchSize == 0) { 64 | final List batchResults = sqlSession.flushStatements(); 65 | result.addAll(batchResults); 66 | } 67 | } 68 | final List batchResults = sqlSession.flushStatements(); 69 | result.addAll(batchResults); 70 | } 71 | return result; 72 | } 73 | 74 | /** 75 | * do batch action 76 | * 77 | * @return effect rows (update counts) 78 | */ 79 | public int doBatchActions() { 80 | final List batchResults = doBatchActionWithResults(); 81 | return batchResults.stream().mapToInt(x -> { 82 | int effectRows = Arrays.stream(x.getUpdateCounts()).sum(); 83 | if (effectRows > 0) { 84 | return effectRows; 85 | } 86 | return x.getParameterObjects().size(); 87 | }).sum(); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/mapper/constant/MapperConstants.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.mapper.constant; 2 | 3 | /** 4 | * @author Frank 5 | */ 6 | public class MapperConstants { 7 | private MapperConstants() { 8 | throw new UnsupportedOperationException(); 9 | } 10 | 11 | public static final String DISTINCT = "distinct"; 12 | public static final String COLUMN = "column"; 13 | public static final String DYNAMIC_QUERY = "dynamicQuery"; 14 | public static final String DYNAMIC_QUERY_PARAMS = "dynamicQueryParams"; 15 | public static final String GROUPED_QUERY = "groupedQuery"; 16 | // make it sample to make same name of dynamicQueryParams 17 | public static final String GROUPED_QUERY_PARAMS = "dynamicQueryParams"; 18 | public static final String SELECT_COLUMNS_EXPRESSION = "selectColumnsExpression"; 19 | public static final String GROUP_COLUMNS_EXPRESSION = "groupColumnsExpression"; 20 | public static final String WHERE_EXPRESSION = "whereExpression"; 21 | public static final String HAVING_EXPRESSION = "havingExpression"; 22 | public static final String SORT_EXPRESSION = "sortExpression"; 23 | public static final String SET_EXPRESSION = "setExpression"; 24 | public static final String UN_AS_SELECT_COLUMNS_EXPRESSION = "unAsSelectColumnsExpression"; 25 | } -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/mapper/helper/BaseEnhancedMapperTemplate.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.mapper.helper; 2 | 3 | import org.apache.ibatis.mapping.MappedStatement; 4 | import org.apache.ibatis.mapping.ResultFlag; 5 | import org.apache.ibatis.mapping.ResultMap; 6 | import org.apache.ibatis.mapping.ResultMapping; 7 | import org.apache.ibatis.reflection.MetaObject; 8 | import org.apache.ibatis.reflection.SystemMetaObject; 9 | import org.apache.ibatis.session.Configuration; 10 | import tk.mybatis.mapper.MapperException; 11 | import tk.mybatis.mapper.entity.EntityColumn; 12 | import tk.mybatis.mapper.entity.EntityTable; 13 | import tk.mybatis.mapper.mapperhelper.EntityHelper; 14 | import tk.mybatis.mapper.mapperhelper.MapperHelper; 15 | import tk.mybatis.mapper.mapperhelper.MapperTemplate; 16 | 17 | import java.util.*; 18 | import java.util.concurrent.ConcurrentHashMap; 19 | 20 | /** 21 | * @author Frank 22 | */ 23 | public abstract class BaseEnhancedMapperTemplate extends MapperTemplate { 24 | 25 | private static Map resultMapCache = new ConcurrentHashMap<>(); 26 | 27 | public BaseEnhancedMapperTemplate(Class mapperClass, MapperHelper mapperHelper) { 28 | super(mapperClass, mapperHelper); 29 | } 30 | 31 | @Override 32 | protected void setResultType(MappedStatement ms, Class entityClass) { 33 | List resultMaps = new ArrayList<>(); 34 | resultMaps.add(getResultMap(entityClass, ms.getConfiguration())); 35 | MetaObject metaObject = SystemMetaObject.forObject(ms); 36 | metaObject.setValue("resultMaps", Collections.unmodifiableList(resultMaps)); 37 | } 38 | 39 | private ResultMap getResultMap(final Class entityClass, final Configuration configuration) { 40 | ResultMap result = resultMapCache.getOrDefault(entityClass, null); 41 | if (result != null) { 42 | return result; 43 | } else { 44 | result = getResultMapInternal(entityClass, configuration); 45 | resultMapCache.put(entityClass, result); 46 | return result; 47 | } 48 | } 49 | 50 | private ResultMap getResultMapInternal(final Class entityClass, final Configuration configuration) { 51 | EntityTable entityTable = EntityHelper.getEntityTable(entityClass); 52 | List resultMappings = new ArrayList<>(); 53 | Set entityColumnSet = entityTable.getEntityClassColumns(); 54 | 55 | boolean isMapUnderscoreToCamelCase = configuration.isMapUnderscoreToCamelCase(); 56 | for (EntityColumn entityColumn : entityColumnSet) { 57 | String property = entityColumn.getProperty(); 58 | String useFieldName = isMapUnderscoreToCamelCase ? 59 | com.github.wz2cool.dynamic.mybatis.EntityHelper.camelCaseToUnderscore(property) : property; 60 | ResultMapping.Builder builder = new ResultMapping.Builder(configuration, entityColumn.getProperty(), useFieldName, entityColumn.getJavaType()); 61 | if (entityColumn.getJdbcType() != null) { 62 | builder.jdbcType(entityColumn.getJdbcType()); 63 | } 64 | 65 | if (entityColumn.getTypeHandler() != null) { 66 | try { 67 | builder.typeHandler(entityColumn.getTypeHandler().newInstance()); 68 | } catch (Exception var9) { 69 | throw new MapperException(var9); 70 | } 71 | } 72 | 73 | List flags = new ArrayList<>(); 74 | if (entityColumn.isId()) { 75 | flags.add(ResultFlag.ID); 76 | } 77 | 78 | builder.flags(flags); 79 | resultMappings.add(builder.build()); 80 | } 81 | org.apache.ibatis.mapping.ResultMap.Builder builder = 82 | new org.apache.ibatis.mapping.ResultMap.Builder(configuration, "BaseMapperResultMap", entityClass, resultMappings, true); 83 | return builder.build(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/mapper/helper/EnhancedSqlHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.mapper.helper; 2 | 3 | import tk.mybatis.mapper.mapperhelper.SqlHelper; 4 | 5 | public class EnhancedSqlHelper extends SqlHelper { 6 | 7 | /** 8 | * insert ignore into tableName - 动态表名 9 | * 10 | * @param entityClass 11 | * @param defaultTableName 12 | * @return 13 | */ 14 | public static String insertIgnoreIntoTable(Class entityClass, String defaultTableName) { 15 | StringBuilder sql = new StringBuilder(); 16 | sql.append("INSERT IGNORE INTO "); 17 | sql.append(getDynamicTableName(entityClass, defaultTableName)); 18 | sql.append(" "); 19 | return sql.toString(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/mapper/helper/GroupedQuerySqlHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.mapper.helper; 2 | 3 | import com.github.wz2cool.dynamic.mybatis.mapper.constant.MapperConstants; 4 | 5 | /** 6 | * @author Frank 7 | */ 8 | public class GroupedQuerySqlHelper { 9 | private GroupedQuerySqlHelper() { 10 | throw new UnsupportedOperationException(); 11 | } 12 | 13 | private static final String FIRST_SQL = String.format("${%s.mdq_first_sql} ", MapperConstants.GROUPED_QUERY_PARAMS); 14 | private static final String LAST_SQL = String.format(" ${%s.mdq_last_sql}", MapperConstants.GROUPED_QUERY_PARAMS); 15 | private static final String HINT_SQL = String.format(" ${%s.mdq_hint_sql} ", MapperConstants.GROUPED_QUERY_PARAMS); 16 | ; 17 | 18 | public static String getBindFilterParams(boolean isMapUnderscoreToCamelCase) { 19 | StringBuilder sql = new StringBuilder(); 20 | sql.append(""); 27 | return sql.toString(); 28 | } 29 | 30 | public static String getSelectColumnsClause() { 31 | return String.format(" ${%s.%s} ", MapperConstants.GROUPED_QUERY_PARAMS, MapperConstants.SELECT_COLUMNS_EXPRESSION); 32 | } 33 | 34 | public static String getWhereClause() { 35 | String newExpression = String.format("%s.%s", MapperConstants.GROUPED_QUERY_PARAMS, MapperConstants.WHERE_EXPRESSION); 36 | return String.format("WHERE ${%s}", 37 | newExpression, newExpression, newExpression); 38 | } 39 | 40 | public static String getGroupByClause() { 41 | String newExpression = String.format("%s.%s", MapperConstants.GROUPED_QUERY_PARAMS, MapperConstants.GROUP_COLUMNS_EXPRESSION); 42 | return String.format("GROUP BY ${%s}", 43 | newExpression, newExpression, newExpression); 44 | } 45 | 46 | public static String getHavingClause() { 47 | String newExpression = String.format("%s.%s", MapperConstants.GROUPED_QUERY_PARAMS, MapperConstants.HAVING_EXPRESSION); 48 | return String.format("HAVING ${%s}", 49 | newExpression, newExpression, newExpression); 50 | } 51 | 52 | public static String getSortClause() { 53 | String newExpression = String.format("%s.%s", MapperConstants.GROUPED_QUERY_PARAMS, MapperConstants.SORT_EXPRESSION); 54 | return String.format("ORDER BY ${%s}", 55 | newExpression, newExpression, newExpression); 56 | } 57 | 58 | public static String getSelectMax() { 59 | return String.format("SELECT %s MAX(${%s})", getHintClause(), MapperConstants.COLUMN); 60 | } 61 | 62 | public static String getSelectMin() { 63 | return String.format("SELECT %s MIN(${%s})", getHintClause(), MapperConstants.COLUMN); 64 | } 65 | 66 | public static String getSelectSum() { 67 | return String.format("SELECT %s SUM(${%s})", getHintClause(), MapperConstants.COLUMN); 68 | } 69 | 70 | public static String getSelectAvg() { 71 | return String.format("SELECT %s AVG(${%s})", getHintClause(), MapperConstants.COLUMN); 72 | } 73 | 74 | public static String getLastClause() { 75 | return LAST_SQL; 76 | } 77 | 78 | public static String getFirstClause() { 79 | return FIRST_SQL; 80 | } 81 | 82 | public static String getHintClause() { 83 | return HINT_SQL; 84 | } 85 | } -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/mapper/mysql/InsertIgnoreMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.mapper.mysql; 2 | 3 | import com.github.wz2cool.dynamic.mybatis.mapper.provider.InsertIgnoreProvider; 4 | import org.apache.ibatis.annotations.InsertProvider; 5 | import tk.mybatis.mapper.annotation.RegisterMapper; 6 | 7 | /** 8 | * insert ignore mapper (mysql) 9 | * 10 | * @author frank 11 | */ 12 | @RegisterMapper 13 | public interface InsertIgnoreMapper { 14 | 15 | /** 16 | * 保存一个实体,null的属性也会保存,不会使用数据库默认值 17 | * 18 | * @param record 19 | * @return 20 | */ 21 | @InsertProvider(type = InsertIgnoreProvider.class, method = "dynamicSQL") 22 | int insertIgnore(T record); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/github/wz2cool/dynamic/mybatis/mapper/mysql/InsertIgnoreSelectiveMapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2014-2017 abel533@gmail.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.github.wz2cool.dynamic.mybatis.mapper.mysql; 26 | 27 | import com.github.wz2cool.dynamic.mybatis.mapper.provider.InsertIgnoreProvider; 28 | import org.apache.ibatis.annotations.InsertProvider; 29 | import tk.mybatis.mapper.annotation.RegisterMapper; 30 | import tk.mybatis.mapper.provider.base.BaseInsertProvider; 31 | 32 | /** 33 | * 通用Mapper接口,插入 34 | * 35 | * @param 不能为空 36 | * @author liuzh 37 | */ 38 | @RegisterMapper 39 | public interface InsertIgnoreSelectiveMapper { 40 | 41 | /** 42 | * 保存一个实体,null的属性不会保存,会使用数据库默认值 43 | * 44 | * @param record 45 | * @return 46 | */ 47 | @InsertProvider(type = InsertIgnoreProvider.class, method = "dynamicSQL") 48 | int insertIgnoreSelective(T record); 49 | 50 | } -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/CustomFilterDescriptorTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | /** 8 | * \* Created with IntelliJ IDEA. 9 | * \* User: Frank 10 | * \* Date: 8/11/2017 11 | * \* Time: 2:16 PM 12 | * \* To change this template use File | Settings | File Templates. 13 | * \* Description: 14 | * \ 15 | */ 16 | public class CustomFilterDescriptorTest { 17 | 18 | @Test 19 | public void testDefaultConstructor() { 20 | CustomFilterDescriptor customFilterDescriptor = 21 | new CustomFilterDescriptor("age > {0}", 1); 22 | 23 | assertEquals("age > {0}", customFilterDescriptor.getExpression()); 24 | assertEquals(1, customFilterDescriptor.getParams()[0]); 25 | 26 | } 27 | } -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/CustomSortDescriptorTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | 8 | /** 9 | * \* Created with IntelliJ IDEA. 10 | * \* User: Frank 11 | * \* Date: 9/29/2017 12 | * \* Time: 1:55 PM 13 | * \* To change this template use File | Settings | File Templates. 14 | * \* Description: 15 | * \ 16 | */ 17 | public class CustomSortDescriptorTest { 18 | 19 | @Test 20 | public void testDefaultConstructor() { 21 | CustomSortDescriptor customSortDescriptor = 22 | new CustomSortDescriptor("{0} DESC", "test"); 23 | 24 | assertEquals("{0} DESC", customSortDescriptor.getExpression()); 25 | assertEquals("test", customSortDescriptor.getParams()[0]); 26 | } 27 | } -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/DbSortTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | import com.github.wz2cool.dynamic.mybatis.MybatisQueryProvider; 4 | import com.github.wz2cool.dynamic.mybatis.db.mapper.NorthwindDao; 5 | import com.github.wz2cool.dynamic.mybatis.db.mapper.UserDao; 6 | import com.github.wz2cool.dynamic.mybatis.db.model.entity.table.Product; 7 | import com.github.wz2cool.dynamic.mybatis.db.model.entity.view.ProductView; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.beans.factory.annotation.Value; 12 | import org.springframework.boot.test.context.SpringBootTest; 13 | import org.springframework.test.context.ContextConfiguration; 14 | import org.springframework.test.context.junit4.SpringRunner; 15 | 16 | import java.util.List; 17 | import java.util.Map; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | 21 | @RunWith(SpringRunner.class) 22 | @SpringBootTest 23 | @ContextConfiguration(classes = TestApplication.class) 24 | public class DbSortTest { 25 | @Value("${spring.profiles.active}") 26 | private String active; 27 | @Autowired 28 | private NorthwindDao northwindDao; 29 | @Autowired 30 | private UserDao userDao; 31 | 32 | @Test 33 | public void testIdDescSort() throws Exception { 34 | SortDescriptor idSort = new SortDescriptor(Product::getProductId, SortDirection.DESC); 35 | Map queryParam = 36 | MybatisQueryProvider.createInstance(Product.class) 37 | .addSorts("orderExpression", idSort) 38 | .toQueryParam(); 39 | List productList = northwindDao.getProductByDynamic(queryParam); 40 | 41 | for (int i = 0; i < productList.size(); i++) { 42 | if (i == productList.size() - 1) { 43 | break; 44 | } 45 | 46 | Product p1 = productList.get(i); 47 | Product p2 = productList.get(i + 1); 48 | assertEquals(1L, p1.getProductId().compareTo(p2.getProductId())); 49 | } 50 | } 51 | 52 | @Test 53 | public void testCustomSort() throws Exception { 54 | String idQueryColumn = MybatisQueryProvider.getQueryColumn(ProductView::getProductID); 55 | // NOTE: queryColumn cannot be parameter. 56 | // 这里注意:列不能当做参数,否则会报错,所以我们字符串拼接出来。 57 | String customSortExpression = String.format("CASE %s WHEN {0} THEN {1} ELSE product.product_id END DESC", idQueryColumn); 58 | CustomSortDescriptor id2TopSort = new CustomSortDescriptor(); 59 | id2TopSort.setExpression(customSortExpression); 60 | id2TopSort.setParams(2, Integer.MAX_VALUE); 61 | Map queryParam = 62 | MybatisQueryProvider.createInstance(ProductView.class) 63 | .addSorts("orderExpression", id2TopSort) 64 | .toQueryParam(); 65 | List productList = northwindDao.getProductViewsByDynamic(queryParam); 66 | assertEquals(Long.valueOf(2), productList.get(0).getProductID()); 67 | } 68 | } -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/DynamicQueryTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | import static com.github.wz2cool.dynamic.builder.DynamicQueryBuilderHelper.*; 4 | 5 | import com.github.wz2cool.dynamic.model.Student; 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.assertEquals; 9 | 10 | /** 11 | * \* Created with IntelliJ IDEA. 12 | * \* User: Frank 13 | * \* Date: 8/10/2017 14 | * \* Time: 10:15 AM 15 | * \* To change this template use File | Settings | File Templates. 16 | * \* Description: 17 | * \ 18 | */ 19 | public class DynamicQueryTest { 20 | 21 | @Test 22 | public void testAddFilter() { 23 | FilterDescriptor filterDescriptor = 24 | new FilterDescriptor(FilterCondition.AND, "name", FilterOperator.EQUAL, "frank"); 25 | 26 | DynamicQuery dynamicQuery = new DynamicQuery<>(Student.class); 27 | dynamicQuery.addFilters(filterDescriptor); 28 | assertEquals(1, dynamicQuery.getFilters().length); 29 | } 30 | 31 | @Test 32 | public void testRemoveFilter() { 33 | FilterDescriptor filterDescriptor = 34 | new FilterDescriptor(FilterCondition.AND, "name", FilterOperator.EQUAL, "frank"); 35 | 36 | DynamicQuery dynamicQuery = new DynamicQuery<>(Student.class); 37 | dynamicQuery.addFilters(filterDescriptor); 38 | assertEquals(1, dynamicQuery.getFilters().length); 39 | 40 | dynamicQuery.removeFilters(filterDescriptor); 41 | assertEquals(0, dynamicQuery.getFilters().length); 42 | } 43 | 44 | @Test 45 | public void testAddSort() { 46 | SortDescriptor sort = new SortDescriptor("name", SortDirection.DESC); 47 | 48 | DynamicQuery dynamicQuery = new DynamicQuery<>(Student.class); 49 | dynamicQuery.addSorts(sort); 50 | 51 | assertEquals(1, dynamicQuery.getSorts().length); 52 | } 53 | 54 | @Test 55 | public void testRemoveSort() { 56 | SortDescriptor sort = new SortDescriptor("name", SortDirection.DESC); 57 | 58 | DynamicQuery dynamicQuery = new DynamicQuery<>(Student.class); 59 | dynamicQuery.addSorts(sort); 60 | 61 | assertEquals(1, dynamicQuery.getSorts().length); 62 | 63 | dynamicQuery.removeSorts(sort); 64 | assertEquals(0, dynamicQuery.getSorts().length); 65 | } 66 | 67 | @Test 68 | public void testCreateQuery() { 69 | DynamicQuery query = DynamicQuery.createQuery(Student.class); 70 | assertEquals(0, query.getFilters().length); 71 | } 72 | 73 | @Test 74 | public void testAddFilterDescriptor() { 75 | DynamicQuery query = DynamicQuery.createQuery(Student.class) 76 | .or(Student::getName, isEqual("frank")); 77 | FilterDescriptor filterDescriptor = (FilterDescriptor) query.getFilters()[0]; 78 | assertEquals(FilterCondition.OR, filterDescriptor.getCondition()); 79 | assertEquals("name", filterDescriptor.getPropertyName()); 80 | assertEquals(FilterOperator.EQUAL, filterDescriptor.getOperator()); 81 | assertEquals("frank", filterDescriptor.getValue()); 82 | } 83 | 84 | @Test 85 | public void testLinkOperation() { 86 | DynamicQuery query = DynamicQuery.createQuery(Student.class) 87 | .and(Student::getName, isEqual("frank")) 88 | .orderBy(Student::getAge, desc()); 89 | 90 | FilterDescriptor filterDescriptor = (FilterDescriptor) query.getFilters()[0]; 91 | assertEquals(FilterCondition.AND, filterDescriptor.getCondition()); 92 | assertEquals("name", filterDescriptor.getPropertyName()); 93 | assertEquals(FilterOperator.EQUAL, filterDescriptor.getOperator()); 94 | assertEquals("frank", filterDescriptor.getValue()); 95 | 96 | SortDescriptor sortDescriptor = (SortDescriptor) query.getSorts()[0]; 97 | assertEquals("age", sortDescriptor.getPropertyName()); 98 | assertEquals(SortDirection.DESC, sortDescriptor.getDirection()); 99 | 100 | } 101 | 102 | @Test 103 | public void testAddSelectProperty() { 104 | DynamicQuery query = DynamicQuery.createQuery(Student.class) 105 | .select(Student::getAge, Student::getName); 106 | String[] selectFields = query.getSelectedProperties(); 107 | assertEquals("age", selectFields[0]); 108 | assertEquals("name", selectFields[1]); 109 | } 110 | 111 | @Test 112 | public void testAddIgnoredProperty() { 113 | DynamicQuery query = DynamicQuery.createQuery(Student.class) 114 | .ignore(Student::getAge, Student::getName); 115 | String[] ignoredProperties = query.getIgnoredProperties(); 116 | assertEquals("age", ignoredProperties[0]); 117 | assertEquals("name", ignoredProperties[1]); 118 | } 119 | } -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/FilterDescriptorTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | import com.github.wz2cool.dynamic.model.Student; 4 | import org.junit.Test; 5 | 6 | import static org.junit.Assert.assertEquals; 7 | 8 | /** 9 | * \* Created with IntelliJ IDEA. 10 | * \* User: Frank 11 | * \* Date: 7/31/2017 12 | * \* Time: 1:57 PM 13 | * \* To change this template use File | Settings | File Templates. 14 | * \* Description: 15 | * \ 16 | */ 17 | public class FilterDescriptorTest { 18 | @Test 19 | public void lambdaNewInstanceTest() { 20 | FilterDescriptor filterDescriptor = 21 | new FilterDescriptor(FilterCondition.AND, "age", 22 | FilterOperator.EQUAL, "3"); 23 | 24 | assertEquals("age", filterDescriptor.getPropertyName()); 25 | } 26 | 27 | @Test 28 | public void lambdaSetPropertyTest() { 29 | FilterDescriptor filterDescriptor = new FilterDescriptor(); 30 | filterDescriptor.setPropertyName("age"); 31 | assertEquals("age", filterDescriptor.getPropertyName()); 32 | } 33 | } -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/LogicPagingResultTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | import com.github.wz2cool.dynamic.model.LogicPagingResult; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | public class LogicPagingResultTest { 11 | 12 | @Test 13 | public void testModelConvert() { 14 | List userDOS = new ArrayList<>(); 15 | userDOS.add(new UserDO(1L, "zhangsan")); 16 | userDOS.add(new UserDO(2L, "lisi")); 17 | 18 | LogicPagingResult LogicPagingResult = new LogicPagingResult<>(); 19 | LogicPagingResult.setStartPageId(1); 20 | LogicPagingResult.setEndPageId(2); 21 | LogicPagingResult.setPageSize(1); 22 | LogicPagingResult.setHasNextPage(true); 23 | LogicPagingResult.setHasPreviousPage(false); 24 | LogicPagingResult.setList(userDOS); 25 | 26 | LogicPagingResult userDTOLogicPagingResult = LogicPagingResult.convert(u -> { 27 | UserDTO userDTO = new UserDTO(); 28 | userDTO.setId(u.getId()); 29 | userDTO.setName(u.getName()); 30 | userDTO.setMixContent(u.getId() + u.getName()); 31 | return userDTO; 32 | }); 33 | 34 | Assert.assertEquals(userDTOLogicPagingResult.getList().get(0).getMixContent(), "1zhangsan"); 35 | } 36 | 37 | class UserDO { 38 | private Long id; 39 | private String name; 40 | 41 | public UserDO(Long id, String name) { 42 | this.id = id; 43 | this.name = name; 44 | } 45 | 46 | public Long getId() { 47 | return id; 48 | } 49 | 50 | public void setId(Long id) { 51 | this.id = id; 52 | } 53 | 54 | public String getName() { 55 | return name; 56 | } 57 | 58 | public void setName(String name) { 59 | this.name = name; 60 | } 61 | } 62 | 63 | class UserDTO { 64 | private Long id; 65 | private String name; 66 | private String mixContent; 67 | 68 | public Long getId() { 69 | return id; 70 | } 71 | 72 | public void setId(Long id) { 73 | this.id = id; 74 | } 75 | 76 | public String getName() { 77 | return name; 78 | } 79 | 80 | public void setName(String name) { 81 | this.name = name; 82 | } 83 | 84 | public String getMixContent() { 85 | return mixContent; 86 | } 87 | 88 | public void setMixContent(String mixContent) { 89 | this.mixContent = mixContent; 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/NormPagingResultTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | import com.github.wz2cool.dynamic.model.NormPagingResult; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | public class NormPagingResultTest { 11 | 12 | @Test 13 | public void testModelConvert() { 14 | List userDOS = new ArrayList<>(); 15 | userDOS.add(new UserDO(1L, "zhangsan")); 16 | userDOS.add(new UserDO(2L, "lisi")); 17 | 18 | NormPagingResult normPagingResult = new NormPagingResult<>(); 19 | normPagingResult.setPageNum(1); 20 | normPagingResult.setPageSize(1); 21 | normPagingResult.setHasNextPage(true); 22 | normPagingResult.setHasPreviousPage(false); 23 | normPagingResult.setList(userDOS); 24 | 25 | NormPagingResult userDTONormPagingResult = normPagingResult.convert(u -> { 26 | UserDTO userDTO = new UserDTO(); 27 | userDTO.setId(u.getId()); 28 | userDTO.setName(u.getName()); 29 | userDTO.setMixContent(u.getId() + u.getName()); 30 | return userDTO; 31 | }); 32 | 33 | Assert.assertEquals(userDTONormPagingResult.getList().get(0).getMixContent(), "1zhangsan"); 34 | } 35 | 36 | class UserDO { 37 | private Long id; 38 | private String name; 39 | 40 | public UserDO(Long id, String name) { 41 | this.id = id; 42 | this.name = name; 43 | } 44 | 45 | public Long getId() { 46 | return id; 47 | } 48 | 49 | public void setId(Long id) { 50 | this.id = id; 51 | } 52 | 53 | public String getName() { 54 | return name; 55 | } 56 | 57 | public void setName(String name) { 58 | this.name = name; 59 | } 60 | } 61 | 62 | class UserDTO { 63 | private Long id; 64 | private String name; 65 | private String mixContent; 66 | 67 | public Long getId() { 68 | return id; 69 | } 70 | 71 | public void setId(Long id) { 72 | this.id = id; 73 | } 74 | 75 | public String getName() { 76 | return name; 77 | } 78 | 79 | public void setName(String name) { 80 | this.name = name; 81 | } 82 | 83 | public String getMixContent() { 84 | return mixContent; 85 | } 86 | 87 | public void setMixContent(String mixContent) { 88 | this.mixContent = mixContent; 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/SortDescriptorTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | import com.github.wz2cool.dynamic.model.Student; 4 | import org.junit.Test; 5 | 6 | import static org.junit.Assert.assertEquals; 7 | 8 | /** 9 | * \* Created with IntelliJ IDEA. 10 | * \* User: Frank 11 | * \* Date: 7/31/2017 12 | * \* Time: 2:11 PM 13 | * \* To change this template use File | Settings | File Templates. 14 | * \* Description: 15 | * \ 16 | */ 17 | public class SortDescriptorTest { 18 | 19 | @Test 20 | public void lambdaNewInstanceTest() { 21 | SortDescriptor filterDescriptor = 22 | new SortDescriptor(Student::getAge, SortDirection.DESC); 23 | 24 | assertEquals("age", filterDescriptor.getPropertyName()); 25 | } 26 | 27 | 28 | @Test 29 | public void lambdaSetPropertyTest() { 30 | SortDescriptor filterDescriptor = new SortDescriptor(); 31 | filterDescriptor.setPropertyPath(Student::getAge); 32 | assertEquals("age", filterDescriptor.getPropertyName()); 33 | } 34 | } -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/TestApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import tk.mybatis.spring.annotation.MapperScan; 6 | 7 | /** 8 | * Created by Frank on 2017/7/15. 9 | */ 10 | @SpringBootApplication 11 | @MapperScan(basePackages = "com.github.wz2cool.dynamic.mybatis.db.mapper") 12 | public class TestApplication { 13 | public static void main(String[] args) { 14 | SpringApplication.run(TestApplication.class, args); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/TransientTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | import com.github.wz2cool.dynamic.mybatis.MybatisQueryProvider; 4 | import com.github.wz2cool.dynamic.mybatis.db.model.entity.table.User; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.assertEquals; 8 | 9 | /** 10 | * \* Created with IntelliJ IDEA. 11 | * \* User: Frank 12 | * \* Date: 8/11/2017 13 | * \* Time: 5:38 PM 14 | * \* To change this template use File | Settings | File Templates. 15 | * \* Description: 16 | * \ 17 | */ 18 | public class TransientTest { 19 | @Test 20 | public void testGetColumns() { 21 | String result = MybatisQueryProvider.getAllColumnsExpression(User.class); 22 | assertEquals(false, result.contains("useless")); 23 | } 24 | } -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/ViewTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic; 2 | 3 | import com.github.wz2cool.dynamic.mybatis.db.mapper.ProductViewMapper; 4 | import com.github.wz2cool.dynamic.mybatis.db.model.entity.view.ProductView; 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.test.context.ContextConfiguration; 10 | import org.springframework.test.context.junit4.SpringRunner; 11 | 12 | import javax.annotation.Resource; 13 | import java.util.List; 14 | 15 | /** 16 | * @author Frank 17 | **/ 18 | @RunWith(SpringRunner.class) 19 | @SpringBootTest 20 | @ContextConfiguration(classes = TestApplication.class) 21 | public class ViewTest { 22 | 23 | @Resource 24 | private ProductViewMapper productViewMapper; 25 | 26 | 27 | @Test 28 | public void testSelect() { 29 | DynamicQuery query = DynamicQuery.createQuery(ProductView.class) 30 | .first("/*firstSql*/"); 31 | query.queryParam("spring_env", ""); 32 | List productViewList = productViewMapper.selectByDynamicQuery(query); 33 | Assert.assertTrue(!productViewList.isEmpty()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/builder/OrderByClauseBuilderTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder; 2 | 3 | import com.github.wz2cool.dynamic.DynamicQuery; 4 | import com.github.wz2cool.dynamic.SortDescriptor; 5 | import com.github.wz2cool.dynamic.SortDirection; 6 | import com.github.wz2cool.dynamic.model.Student; 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | import static com.github.wz2cool.dynamic.builder.DynamicQueryBuilderHelper.desc; 11 | import static com.github.wz2cool.dynamic.builder.DynamicQueryBuilderHelper.isEqual; 12 | 13 | public class OrderByClauseBuilderTest { 14 | 15 | @Test 16 | public void thenByTest() { 17 | DynamicQuery dynamicQuery = DynamicQueryBuilder.create(Student.class) 18 | .selectAll() 19 | .where(Student::getName, isEqual("frank")) 20 | .orderBy(Student::getAge) 21 | .thenBy(Student::getName, desc()) 22 | .thenBy(Student::isDeleted) 23 | .build(); 24 | 25 | SortDescriptor sort1 = (SortDescriptor) dynamicQuery.getSorts()[0]; 26 | SortDescriptor sort2 = (SortDescriptor) dynamicQuery.getSorts()[1]; 27 | SortDescriptor sort3 = (SortDescriptor) dynamicQuery.getSorts()[2]; 28 | 29 | Assert.assertEquals("age", sort1.getPropertyName()); 30 | Assert.assertEquals(SortDirection.ASC, sort1.getDirection()); 31 | 32 | Assert.assertEquals("name", sort2.getPropertyName()); 33 | Assert.assertEquals(SortDirection.DESC, sort2.getDirection()); 34 | 35 | Assert.assertEquals("deleted", sort3.getPropertyName()); 36 | Assert.assertEquals(SortDirection.ASC, sort3.getDirection()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/builder/WhereClauseBuilderTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.builder; 2 | 3 | import com.github.wz2cool.dynamic.*; 4 | import com.github.wz2cool.dynamic.model.Student; 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | 8 | import static com.github.wz2cool.dynamic.builder.DynamicQueryBuilderHelper.desc; 9 | import static com.github.wz2cool.dynamic.builder.DynamicQueryBuilderHelper.isEqual; 10 | 11 | public class WhereClauseBuilderTest { 12 | 13 | @Test 14 | public void testWhereClauseBuilder() { 15 | WhereClauseBuilder whereClauseBuilder = DynamicQueryBuilder.create(Student.class) 16 | .selectAll() 17 | .where(Student::getName, isEqual("frank")); 18 | 19 | OrderByClauseBuilder orderByClauseBuilder = whereClauseBuilder.orderBy(Student::getAge); 20 | SortDescriptor sortDescriptor = (SortDescriptor) orderByClauseBuilder.getSorts()[0]; 21 | Assert.assertEquals("age", sortDescriptor.getPropertyName()); 22 | Assert.assertEquals(SortDirection.ASC, sortDescriptor.getDirection()); 23 | 24 | OrderByClauseBuilder orderByClauseBuilder1 = whereClauseBuilder.orderBy(Student::getAge, desc()); 25 | SortDescriptor sortDescriptor1 = (SortDescriptor) orderByClauseBuilder1.getSorts()[0]; 26 | Assert.assertEquals("age", sortDescriptor1.getPropertyName()); 27 | Assert.assertEquals(SortDirection.DESC, sortDescriptor1.getDirection()); 28 | } 29 | 30 | @Test 31 | public void buildTest() { 32 | WhereClauseBuilder whereClauseBuilder = DynamicQueryBuilder.create(Student.class) 33 | .selectAll() 34 | .where(Student::getName, isEqual("frank")); 35 | 36 | DynamicQuery dynamicQuery = whereClauseBuilder.build(); 37 | FilterDescriptor filterDescriptor = (FilterDescriptor) dynamicQuery.getFilters()[0]; 38 | Assert.assertEquals("name", filterDescriptor.getPropertyName()); 39 | Assert.assertEquals(FilterOperator.EQUAL, filterDescriptor.getOperator()); 40 | Assert.assertEquals("frank", filterDescriptor.getValue()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/model/Bug.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.model; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Table; 5 | 6 | @Table(name = "bug") 7 | public class Bug { 8 | @Column(name = "id") 9 | private Integer id; 10 | @Column(name = "title") 11 | private String title; 12 | @Column(name = "assignTo") 13 | private String assignTo; 14 | 15 | public Integer getId() { 16 | return id; 17 | } 18 | 19 | public void setId(Integer id) { 20 | this.id = id; 21 | } 22 | 23 | public String getTitle() { 24 | return title; 25 | } 26 | 27 | public void setTitle(String title) { 28 | this.title = title; 29 | } 30 | 31 | public String getAssignTo() { 32 | return assignTo; 33 | } 34 | 35 | public void setAssignTo(String assignTo) { 36 | this.assignTo = assignTo; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/model/ChildClass.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.model; 2 | 3 | /** 4 | * Created by Frank on 7/11/2017. 5 | */ 6 | public class ChildClass extends ParentClass { 7 | private String childP1; 8 | 9 | public String getChildP1() { 10 | return childP1; 11 | } 12 | 13 | public void setChildP1(String childP1) { 14 | this.childP1 = childP1; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/model/ExampleModel.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.model; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.Date; 5 | 6 | public class ExampleModel { 7 | private BigDecimal p1; 8 | private Byte p2; 9 | private Date p3; 10 | private Double p4; 11 | private Float p5; 12 | private Integer p6; 13 | private Long p7; 14 | private Short p8; 15 | private String p9; 16 | 17 | public BigDecimal getP1() { 18 | return p1; 19 | } 20 | 21 | public void setP1(BigDecimal p1) { 22 | this.p1 = p1; 23 | } 24 | 25 | public Byte getP2() { 26 | return p2; 27 | } 28 | 29 | public void setP2(Byte p2) { 30 | this.p2 = p2; 31 | } 32 | 33 | public Date getP3() { 34 | return p3; 35 | } 36 | 37 | public void setP3(Date p3) { 38 | this.p3 = p3; 39 | } 40 | 41 | public Double getP4() { 42 | return p4; 43 | } 44 | 45 | public void setP4(Double p4) { 46 | this.p4 = p4; 47 | } 48 | 49 | public Float getP5() { 50 | return p5; 51 | } 52 | 53 | public void setP5(Float p5) { 54 | this.p5 = p5; 55 | } 56 | 57 | public Integer getP6() { 58 | return p6; 59 | } 60 | 61 | public void setP6(Integer p6) { 62 | this.p6 = p6; 63 | } 64 | 65 | public Long getP7() { 66 | return p7; 67 | } 68 | 69 | public void setP7(Long p7) { 70 | this.p7 = p7; 71 | } 72 | 73 | public Short getP8() { 74 | return p8; 75 | } 76 | 77 | public void setP8(Short p8) { 78 | this.p8 = p8; 79 | } 80 | 81 | public String getP9() { 82 | return p9; 83 | } 84 | 85 | public void setP9(String p9) { 86 | this.p9 = p9; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/model/HelloWorld.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.model; 2 | 3 | import java.util.Date; 4 | 5 | /** 6 | * Created by Frank on 7/10/2017. 7 | */ 8 | public class HelloWorld { 9 | 10 | private String stringProperty; 11 | private Integer integerProperty; 12 | private Date dateProperty; 13 | 14 | public String getStringProperty() { 15 | return stringProperty; 16 | } 17 | 18 | public void setStringProperty(String stringProperty) { 19 | this.stringProperty = stringProperty; 20 | } 21 | 22 | public Integer getIntegerProperty() { 23 | return integerProperty; 24 | } 25 | 26 | public void setIntegerProperty(Integer integerProperty) { 27 | this.integerProperty = integerProperty; 28 | } 29 | 30 | public Date getDateProperty() { 31 | return dateProperty; 32 | } 33 | 34 | public void setDateProperty(Date dateProperty) { 35 | this.dateProperty = dateProperty; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/model/ParentClass.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.model; 2 | 3 | import javax.persistence.Column; 4 | 5 | /** 6 | * Created by Frank on 7/11/2017. 7 | */ 8 | public class ParentClass { 9 | @Column(name = "parent_p1", table = "test") 10 | private String parentP1; 11 | 12 | public String getParentP1() { 13 | return parentP1; 14 | } 15 | 16 | public void setParentP1(String parentP1) { 17 | this.parentP1 = parentP1; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/model/Student.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.model; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Table; 5 | 6 | /** 7 | * Created by Frank on 7/10/2017. 8 | */ 9 | @Table(name = "student") 10 | public class Student { 11 | private long serialId = 123456; 12 | private String name; 13 | private Integer age; 14 | @Column(name = "note", table = "queryColumn") 15 | private String note; 16 | 17 | private boolean deleted; 18 | 19 | public boolean isDeleted() { 20 | return deleted; 21 | } 22 | 23 | public void setDeleted(boolean deleted) { 24 | this.deleted = deleted; 25 | } 26 | 27 | public String getNote() { 28 | return note; 29 | } 30 | 31 | public void setNote(String note) { 32 | this.note = note; 33 | } 34 | 35 | public String getName() { 36 | return name; 37 | } 38 | 39 | public void setName(String name) { 40 | this.name = name; 41 | } 42 | 43 | public Integer getAge() { 44 | return age; 45 | } 46 | 47 | public void setAge(Integer age) { 48 | this.age = age; 49 | } 50 | 51 | public long getSerialId() { 52 | return serialId; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/EntityCacheTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis; 2 | 3 | import com.github.wz2cool.dynamic.exception.PropertyNotFoundInternalException; 4 | import com.github.wz2cool.dynamic.model.Student; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.assertEquals; 8 | 9 | /** 10 | * Created by Frank on 7/11/2017. 11 | */ 12 | public class EntityCacheTest { 13 | 14 | @Test 15 | public void TestGetQueryColumn() { 16 | ColumnInfo result = EntityCache.getInstance().getColumnInfo(Student.class, "name"); 17 | assertEquals("name", result.getQueryColumn()); 18 | 19 | result = EntityCache.getInstance().getColumnInfo(Student.class, "note"); 20 | assertEquals("queryColumn.note", result.getQueryColumn()); 21 | assertEquals("queryColumn", result.getTableOrAlias()); 22 | } 23 | 24 | @Test(expected = NullPointerException.class) 25 | public void TestGetQueryColumnEntityClassNull() { 26 | EntityCache.getInstance().getColumnInfo(null, "name"); 27 | } 28 | 29 | @Test(expected = NullPointerException.class) 30 | public void TestGetQueryColumnPropertyNull() { 31 | EntityCache.getInstance().getColumnInfo(Student.class, null); 32 | } 33 | 34 | @Test(expected = PropertyNotFoundInternalException.class) 35 | public void TestGetQueryColumnPropertyNotFound() { 36 | EntityCache.getInstance().getColumnInfo(Student.class, "notFoundProperty"); 37 | } 38 | 39 | @Test(expected = NullPointerException.class) 40 | public void TestGetDbColumnInfoEntityClassNull() { 41 | EntityCache.getInstance().getColumnInfo(null, "name"); 42 | } 43 | 44 | @Test(expected = NullPointerException.class) 45 | public void TestGetDbColumnInfoPropertyNull() { 46 | EntityCache.getInstance().getColumnInfo(Student.class, null); 47 | } 48 | 49 | @Test(expected = PropertyNotFoundInternalException.class) 50 | public void TestGetDbColumnPropertyNotFound() { 51 | EntityCache.getInstance().getColumnInfo(Student.class, "notFoundProperty"); 52 | } 53 | 54 | @Test 55 | public void TestHasProperty() { 56 | boolean result = EntityCache.getInstance().hasProperty(Student.class, "name"); 57 | assertEquals(true, result); 58 | 59 | result = EntityCache.getInstance().hasProperty(Student.class, "notProperty"); 60 | assertEquals(false, result); 61 | 62 | result = EntityCache.getInstance().hasProperty(Student.class, ""); 63 | assertEquals(false, result); 64 | } 65 | 66 | @Test(expected = NullPointerException.class) 67 | public void TestHasPropertyEntityNull() { 68 | EntityCache.getInstance().hasProperty(null, "name"); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/EntityHelperTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis; 2 | 3 | import com.github.wz2cool.dynamic.exception.PropertyNotFoundInternalException; 4 | import com.github.wz2cool.dynamic.helper.ReflectHelper; 5 | import com.github.wz2cool.dynamic.model.ChildClass; 6 | import com.github.wz2cool.dynamic.model.HelloWorld; 7 | import com.github.wz2cool.dynamic.model.Student; 8 | import org.junit.Test; 9 | 10 | import javax.persistence.Column; 11 | import java.lang.reflect.Constructor; 12 | import java.lang.reflect.Field; 13 | import java.lang.reflect.InvocationTargetException; 14 | import java.lang.reflect.Method; 15 | import java.util.Arrays; 16 | 17 | import static org.junit.Assert.assertEquals; 18 | 19 | /** 20 | * Created by Frank on 7/10/2017. 21 | */ 22 | public class EntityHelperTest { 23 | @Test(expected = InvocationTargetException.class) 24 | public void TestReflectHelper() throws Exception { 25 | Constructor c = EntityHelper.class.getDeclaredConstructor(); 26 | c.setAccessible(true); 27 | c.newInstance(); 28 | } 29 | 30 | @Test 31 | public void TestGetTableName() { 32 | String result = EntityHelper.getTableName(Student.class); 33 | assertEquals("student", result); 34 | 35 | result = EntityHelper.getTableName(HelloWorld.class); 36 | assertEquals("hello_world", result); 37 | } 38 | 39 | @Test(expected = NullPointerException.class) 40 | public void TestGetTableNameArgNullPointer() { 41 | EntityHelper.getTableName(null); 42 | } 43 | 44 | @Test 45 | public void TestGetPropertyField() { 46 | Field[] fields = Student.class.getDeclaredFields(); 47 | Method[] methods = Student.class.getMethods(); 48 | Field[] properties = Arrays.stream(fields) 49 | .filter(x -> ReflectHelper.isProperty(x, methods)) 50 | .toArray(Field[]::new); 51 | 52 | Field result = EntityHelper.getPropertyField("name", properties); 53 | assertEquals(true, result != null); 54 | } 55 | 56 | @Test(expected = PropertyNotFoundInternalException.class) 57 | public void TestGetPropertyFieldNotFound() { 58 | Field[] fields = Student.class.getDeclaredFields(); 59 | Method[] methods = Student.class.getMethods(); 60 | Field[] properties = Arrays.stream(fields) 61 | .filter(x -> ReflectHelper.isProperty(x, methods)) 62 | .toArray(Field[]::new); 63 | 64 | EntityHelper.getPropertyField("", properties); 65 | } 66 | 67 | @Test 68 | public void TestGetDbColumnByProperty() { 69 | Field[] fields = Student.class.getDeclaredFields(); 70 | Method[] methods = Student.class.getMethods(); 71 | Field[] properties = Arrays.stream(fields) 72 | .filter(x -> ReflectHelper.isProperty(x, methods)) 73 | .toArray(Field[]::new); 74 | 75 | Column result = EntityHelper.getColumnByProperty("note", properties); 76 | assertEquals(true, result != null); 77 | 78 | result = EntityHelper.getColumnByProperty("name", properties); 79 | assertEquals(true, result == null); 80 | 81 | 82 | } 83 | 84 | @Test(expected = PropertyNotFoundInternalException.class) 85 | public void TestGetDbColumnByPropertyNotFound() { 86 | Field[] fields = Student.class.getDeclaredFields(); 87 | Method[] methods = Student.class.getMethods(); 88 | Field[] properties = Arrays.stream(fields) 89 | .filter(x -> ReflectHelper.isProperty(x, methods)) 90 | .toArray(Field[]::new); 91 | Column result = EntityHelper.getColumnByProperty("noPropertyTest", properties); 92 | assertEquals(false, result != null); 93 | } 94 | 95 | @Test 96 | public void TestGetDBColumnNameByProperty() { 97 | Field[] fields = Student.class.getDeclaredFields(); 98 | Method[] methods = Student.class.getMethods(); 99 | Field[] properties = Arrays.stream(fields) 100 | .filter(x -> ReflectHelper.isProperty(x, methods)) 101 | .toArray(Field[]::new); 102 | 103 | String result = EntityHelper.getColumnNameByProperty("note", properties); 104 | assertEquals("note", result); 105 | 106 | result = EntityHelper.getColumnNameByProperty("name", properties); 107 | assertEquals("name", result); 108 | } 109 | 110 | @Test(expected = PropertyNotFoundInternalException.class) 111 | public void TestGetDBColumnNameByPropertyNotFound() { 112 | Field[] fields = Student.class.getDeclaredFields(); 113 | Method[] methods = Student.class.getMethods(); 114 | Field[] properties = Arrays.stream(fields) 115 | .filter(x -> ReflectHelper.isProperty(x, methods)) 116 | .toArray(Field[]::new); 117 | 118 | String result = EntityHelper.getColumnNameByProperty("noPropertyTest", properties); 119 | assertEquals("", result); 120 | } 121 | 122 | @Test 123 | public void TestGetQueryColumnByProperty() { 124 | Field[] properties = ReflectHelper.getProperties(ChildClass.class); 125 | 126 | String result = EntityHelper.getColumnNameByProperty("childP1", properties); 127 | assertEquals("child_p1", result); 128 | } 129 | 130 | @Test(expected = PropertyNotFoundInternalException.class) 131 | public void TestGetQueryColumnByPropertyNotFound() { 132 | Field[] properties = ReflectHelper.getProperties(ChildClass.class); 133 | EntityHelper.getColumnNameByProperty("", properties); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/MybatisQueryProviderTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis; 2 | 3 | import com.github.wz2cool.dynamic.*; 4 | import com.github.wz2cool.dynamic.model.Student; 5 | import com.github.wz2cool.dynamic.mybatis.db.model.entity.view.ProductView; 6 | import org.junit.Test; 7 | 8 | import java.lang.reflect.InvocationTargetException; 9 | import java.lang.reflect.Method; 10 | import java.util.Map; 11 | import java.util.regex.Pattern; 12 | 13 | import static org.junit.Assert.assertEquals; 14 | 15 | public class MybatisQueryProviderTest { 16 | 17 | @Test 18 | public void TestGetWhereExpression() throws Exception { 19 | FilterDescriptor filterDescriptor = 20 | new FilterDescriptor(FilterCondition.AND, "age", FilterOperator.EQUAL, 30); 21 | 22 | ParamExpression result = MybatisQueryProvider.getWhereExpression(Student.class, filterDescriptor); 23 | String pattern = "^\\(age = #\\{param_age_EQUAL_\\w+\\}\\)$"; 24 | assertEquals(true, Pattern.matches(pattern, result.getExpression())); 25 | assertEquals(30, result.getParamMap().values().iterator().next()); 26 | } 27 | 28 | @Test 29 | public void TestGetSortExpression() throws Exception { 30 | SortDescriptor sortDescriptor = 31 | new SortDescriptor("age", SortDirection.DESC); 32 | 33 | ParamExpression result = MybatisQueryProvider.getSortExpression(Student.class, sortDescriptor); 34 | assertEquals("age DESC", result.getExpression()); 35 | } 36 | 37 | @Test 38 | public void testGetSortQueryParamMap() throws Exception { 39 | SortDescriptor ageSort = new SortDescriptor(); 40 | ageSort.setPropertyName("age"); 41 | ageSort.setDirection(SortDirection.DESC); 42 | Map result = MybatisQueryProvider.getSortQueryParamMap(Student.class, "sortExpression", ageSort); 43 | assertEquals("age DESC", result.get("sortExpression")); 44 | } 45 | 46 | @Test(expected = NullPointerException.class) 47 | public void testGetSortQueryParamMapThrowNull() throws Exception { 48 | SortDescriptor ageSort = new SortDescriptor(); 49 | ageSort.setPropertyName("age"); 50 | ageSort.setDirection(SortDirection.DESC); 51 | MybatisQueryProvider.getSortQueryParamMap(Student.class, "", ageSort); 52 | } 53 | 54 | @Test(expected = NullPointerException.class) 55 | public void testGetWhereQueryParamMapThrowNull() throws Exception { 56 | FilterDescriptor nameFilter = new FilterDescriptor(); 57 | nameFilter.setPropertyName("name"); 58 | nameFilter.setOperator(FilterOperator.EQUAL); 59 | nameFilter.setValue("frank"); 60 | 61 | MybatisQueryProvider.getWhereQueryParamMap(Student.class, "", nameFilter); 62 | } 63 | 64 | @Test 65 | public void testGetQueryParamMap() throws Exception { 66 | DynamicQuery dynamicQuery = new DynamicQuery<>(Student.class); 67 | FilterDescriptor nameFilter = 68 | new FilterDescriptor(FilterCondition.AND, "name", FilterOperator.EQUAL, "frank"); 69 | SortDescriptor ageSort = 70 | new SortDescriptor(Student::getAge, SortDirection.DESC); 71 | dynamicQuery.addFilters(nameFilter); 72 | dynamicQuery.addSorts(ageSort); 73 | 74 | 75 | Method method = MybatisQueryProvider.class.getDeclaredMethod("getQueryParamMap", 76 | DynamicQuery.class, String.class, String.class, String.class); 77 | method.setAccessible(true); 78 | 79 | Map result = (Map) method.invoke(MybatisQueryProvider.class, 80 | dynamicQuery, 81 | "wherePlaceholder", 82 | "sortPlaceholder", 83 | "columnsPlaceholder"); 84 | assertEquals("age DESC", result.get("sortPlaceholder")); 85 | assertEquals("queryColumn.note AS note, deleted AS deleted, name AS name, age AS age", result.get("columnsPlaceholder")); 86 | } 87 | 88 | @Test(expected = InvocationTargetException.class) 89 | public void testGetQueryParamMapThrowNull() throws Exception { 90 | Method method = MybatisQueryProvider.class.getDeclaredMethod("getQueryParamMap", 91 | DynamicQuery.class, String.class, String.class, String.class); 92 | method.setAccessible(true); 93 | method.invoke( 94 | MybatisQueryProvider.class, 95 | null, 96 | "wherePlaceholder", 97 | "sortPlaceholder", 98 | "columnsPlaceholder"); 99 | } 100 | 101 | @Test 102 | public void testGetQueryColumn() throws Exception { 103 | String nameColumn = MybatisQueryProvider.getQueryColumn(Student::getName); 104 | assertEquals("name", nameColumn); 105 | 106 | String productIdColumn = MybatisQueryProvider.getQueryColumn(ProductView::getProductID); 107 | assertEquals("product.product_id", productIdColumn); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/db/mapper/BugDao.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.db.mapper; 2 | 3 | import com.github.wz2cool.dynamic.model.Bug; 4 | import com.github.wz2cool.dynamic.mybatis.mapper.DynamicQueryMapper; 5 | 6 | public interface BugDao extends DynamicQueryMapper { 7 | } 8 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/db/mapper/CategoryGroupCountMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.db.mapper; 2 | 3 | import com.github.wz2cool.dynamic.mybatis.db.model.entity.group.CategoryGroupCount; 4 | import com.github.wz2cool.dynamic.mybatis.db.model.entity.table.Product; 5 | import com.github.wz2cool.dynamic.mybatis.mapper.SelectByGroupedQueryMapper; 6 | import com.github.wz2cool.dynamic.mybatis.mapper.SelectMaxByGroupedQueryMapper; 7 | import com.github.wz2cool.dynamic.mybatis.mapper.SelectMinByGroupedQueryMapper; 8 | 9 | /** 10 | * @author Frank 11 | **/ 12 | public interface CategoryGroupCountMapper extends 13 | SelectByGroupedQueryMapper, 14 | SelectMaxByGroupedQueryMapper, 15 | SelectMinByGroupedQueryMapper { 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/db/mapper/CategoryGroupCountMapper2.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.db.mapper; 2 | 3 | import com.github.wz2cool.dynamic.mybatis.db.model.entity.group.CategoryGroupCount; 4 | import com.github.wz2cool.dynamic.mybatis.db.model.entity.view.ProductBaseView; 5 | import com.github.wz2cool.dynamic.mybatis.mapper.SelectByGroupedQueryMapper; 6 | import com.github.wz2cool.dynamic.mybatis.mapper.SelectMaxByGroupedQueryMapper; 7 | import com.github.wz2cool.dynamic.mybatis.mapper.SelectMinByGroupedQueryMapper; 8 | 9 | /** 10 | * @author Frank 11 | **/ 12 | public interface CategoryGroupCountMapper2 extends 13 | SelectByGroupedQueryMapper, 14 | SelectMaxByGroupedQueryMapper, 15 | SelectMinByGroupedQueryMapper { 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/db/mapper/NorthwindDao.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.db.mapper; 2 | 3 | import com.github.wz2cool.dynamic.mybatis.db.model.entity.table.Category; 4 | import com.github.wz2cool.dynamic.mybatis.db.model.entity.table.Product; 5 | import com.github.wz2cool.dynamic.mybatis.db.model.entity.view.ProductView; 6 | import org.apache.ibatis.annotations.Mapper; 7 | 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | /** 12 | * Created by Frank on 2017/7/16. 13 | */ 14 | @Mapper 15 | public interface NorthwindDao { 16 | List getCategories(); 17 | 18 | List getProducts(); 19 | 20 | List getProductByDynamic(Map params); 21 | 22 | List getProductViewsByDynamic(Map params); 23 | 24 | List getProductViewsByDynamic2(Map params); 25 | 26 | int insert(Map params); 27 | 28 | int update(Map params); 29 | 30 | int delete(Map params); 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/db/mapper/ProductDao.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.db.mapper; 2 | 3 | import com.github.wz2cool.dynamic.mybatis.db.model.entity.table.Product; 4 | import com.github.wz2cool.dynamic.mybatis.mapper.DynamicQueryMapper; 5 | 6 | public interface ProductDao extends DynamicQueryMapper { 7 | } 8 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/db/mapper/ProductViewMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.db.mapper; 2 | 3 | import com.github.wz2cool.dynamic.mybatis.db.model.entity.view.ProductView; 4 | import com.github.wz2cool.dynamic.mybatis.mapper.SelectViewByDynamicQueryMapper; 5 | import org.apache.ibatis.annotations.Mapper; 6 | 7 | /** 8 | * @author Frank 9 | **/ 10 | @Mapper 11 | public interface ProductViewMapper extends SelectViewByDynamicQueryMapper { 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/db/mapper/StudentMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.db.mapper; 2 | 3 | import com.github.wz2cool.dynamic.mybatis.db.model.entity.table.StudentDO; 4 | import com.github.wz2cool.dynamic.mybatis.mapper.DynamicQueryMapper; 5 | import org.apache.ibatis.annotations.Mapper; 6 | 7 | /** 8 | * @author Frank 9 | **/ 10 | @Mapper 11 | public interface StudentMapper extends DynamicQueryMapper { 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/db/mapper/UserDao.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.db.mapper; 2 | 3 | import com.github.wz2cool.dynamic.mybatis.db.model.entity.table.User; 4 | import com.github.wz2cool.dynamic.mybatis.mapper.DynamicQueryMapper; 5 | 6 | /** 7 | * \* Created with IntelliJ IDEA. 8 | * \* User: Frank 9 | * \* Date: 8/7/2017 10 | * \* Time: 5:39 PM 11 | * \* To change this template use File | Settings | File Templates. 12 | * \* Description: 13 | * \ 14 | */ 15 | public interface UserDao extends DynamicQueryMapper { 16 | } -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/db/model/entity/group/CategoryGroupCount.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.db.model.entity.group; 2 | 3 | import javax.persistence.Column; 4 | 5 | /** 6 | * @author Frank 7 | **/ 8 | public class CategoryGroupCount { 9 | public Integer categoryId; 10 | 11 | @Column(name = "COUNT(product_id)") 12 | private Integer count; 13 | 14 | public Integer getCategoryId() { 15 | return categoryId; 16 | } 17 | 18 | public void setCategoryId(Integer categoryId) { 19 | this.categoryId = categoryId; 20 | } 21 | 22 | public Integer getCount() { 23 | return count; 24 | } 25 | 26 | public void setCount(Integer count) { 27 | this.count = count; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/db/model/entity/table/Category.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.db.model.entity.table; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Table; 5 | 6 | /** 7 | * Created by Frank on 2017/7/15. 8 | */ 9 | @Table(name = "category") 10 | public class Category { 11 | @Column(name = "category_id") 12 | private Integer categoryID; 13 | private String categoryName; 14 | private String description; 15 | 16 | public Integer getCategoryID() { 17 | return categoryID; 18 | } 19 | 20 | public void setCategoryID(Integer categoryID) { 21 | this.categoryID = categoryID; 22 | } 23 | 24 | public String getCategoryName() { 25 | return categoryName; 26 | } 27 | 28 | public void setCategoryName(String categoryName) { 29 | this.categoryName = categoryName; 30 | } 31 | 32 | public String getDescription() { 33 | return description; 34 | } 35 | 36 | public void setDescription(String description) { 37 | this.description = description; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/db/model/entity/table/Product.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.db.model.entity.table; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Table; 5 | import java.math.BigDecimal; 6 | 7 | /** 8 | * Created by Frank on 2017/7/15. 9 | */ 10 | @Table(name = "product") 11 | public class Product { 12 | @Column(name = "product_id", insertable = false, updatable = false) 13 | private Long productId; 14 | private String productName; 15 | private BigDecimal price; 16 | private Integer categoryId; 17 | 18 | public Integer getCategoryId() { 19 | return categoryId; 20 | } 21 | 22 | public void setCategoryId(Integer categoryId) { 23 | this.categoryId = categoryId; 24 | } 25 | 26 | public Long getProductId() { 27 | return productId; 28 | } 29 | 30 | public void setProductId(Long productId) { 31 | this.productId = productId; 32 | } 33 | 34 | public String getProductName() { 35 | return productName; 36 | } 37 | 38 | public void setProductName(String productName) { 39 | this.productName = productName; 40 | } 41 | 42 | public BigDecimal getPrice() { 43 | return price; 44 | } 45 | 46 | public void setPrice(BigDecimal price) { 47 | this.price = price; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/db/model/entity/table/Product2.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.db.model.entity.table; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Table; 5 | import java.math.BigDecimal; 6 | 7 | /** 8 | * Created by Frank on 2017/7/15. 9 | */ 10 | @Table(name = "product") 11 | public class Product2 { 12 | @Column(name = "product_id") 13 | private Integer productID; 14 | private String productName; 15 | private BigDecimal price; 16 | private Integer categoryID; 17 | 18 | public Integer getCategoryID() { 19 | return categoryID; 20 | } 21 | 22 | public void setCategoryID(Integer categoryID) { 23 | this.categoryID = categoryID; 24 | } 25 | 26 | public Integer getProductID() { 27 | return productID; 28 | } 29 | 30 | public void setProductID(Integer productID) { 31 | this.productID = productID; 32 | } 33 | 34 | public String getProductName() { 35 | return productName; 36 | } 37 | 38 | public void setProductName(String productName) { 39 | this.productName = productName; 40 | } 41 | 42 | public BigDecimal getPrice() { 43 | return price; 44 | } 45 | 46 | public void setPrice(BigDecimal price) { 47 | this.price = price; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/db/model/entity/table/Product3.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.db.model.entity.table; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Table; 5 | import java.math.BigDecimal; 6 | 7 | /** 8 | * \* Created with IntelliJ IDEA. 9 | * \* User: Frank 10 | * \* Date: 7/31/2017 11 | * \* Time: 3:42 PM 12 | * \* To change this template use File | Settings | File Templates. 13 | * \* Description: 14 | * \ 15 | */ 16 | @Table(name = "product") 17 | public class Product3 { 18 | // id 为null 的时候不插入 19 | @Column(name = "product_id") 20 | private Integer productID; 21 | private String productName; 22 | private BigDecimal price; 23 | private Integer categoryID; 24 | 25 | public Integer getProductID() { 26 | return productID; 27 | } 28 | 29 | public void setProductID(Integer productID) { 30 | this.productID = productID; 31 | } 32 | 33 | public String getProductName() { 34 | return productName; 35 | } 36 | 37 | public void setProductName(String productName) { 38 | this.productName = productName; 39 | } 40 | 41 | public BigDecimal getPrice() { 42 | return price; 43 | } 44 | 45 | public void setPrice(BigDecimal price) { 46 | this.price = price; 47 | } 48 | 49 | public Integer getCategoryID() { 50 | return categoryID; 51 | } 52 | 53 | public void setCategoryID(Integer categoryID) { 54 | this.categoryID = categoryID; 55 | } 56 | } -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/db/model/entity/table/StudentDO.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.db.model.entity.table; 2 | 3 | 4 | import javax.persistence.Table; 5 | 6 | /** 7 | * @author Frank 8 | **/ 9 | @Table(name = "student") 10 | public class StudentDO { 11 | private Long id; 12 | private String name; 13 | 14 | public Long getId() { 15 | return id; 16 | } 17 | 18 | public void setId(Long id) { 19 | this.id = id; 20 | } 21 | 22 | public String getName() { 23 | return name; 24 | } 25 | 26 | public void setName(String name) { 27 | this.name = name; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/db/model/entity/table/User.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.db.model.entity.table; 2 | 3 | import javax.persistence.Id; 4 | import javax.persistence.Table; 5 | import javax.persistence.Transient; 6 | 7 | /** 8 | * \* Created with IntelliJ IDEA. 9 | * \* User: Frank 10 | * \* Date: 8/7/2017 11 | * \* Time: 5:37 PM 12 | * \* To change this template use File | Settings | File Templates. 13 | * \* Description: 14 | * \ 15 | */ 16 | @Table(name = "users") 17 | public class User { 18 | @Id 19 | private Integer id; 20 | private String userName; 21 | private String password; 22 | 23 | @Transient 24 | private String uselessProperty; 25 | 26 | public Integer getId() { 27 | return id; 28 | } 29 | 30 | public void setId(Integer id) { 31 | this.id = id; 32 | } 33 | 34 | public String getUserName() { 35 | return userName; 36 | } 37 | 38 | public void setUserName(String userName) { 39 | this.userName = userName; 40 | } 41 | 42 | public String getPassword() { 43 | return password; 44 | } 45 | 46 | public void setPassword(String password) { 47 | this.password = password; 48 | } 49 | 50 | public String getUselessProperty() { 51 | return uselessProperty; 52 | } 53 | 54 | public void setUselessProperty(String uselessProperty) { 55 | this.uselessProperty = uselessProperty; 56 | } 57 | } -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/db/model/entity/view/ProductBaseView.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.db.model.entity.view; 2 | 3 | import com.github.wz2cool.dynamic.mybatis.View; 4 | 5 | import javax.persistence.Column; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * Created by Frank on 2017/7/15. 10 | */ 11 | @View("${product_base_view}") 12 | public class ProductBaseView { 13 | @Column(name = "product_id", insertable = false, updatable = false) 14 | private Long productId; 15 | private String productName; 16 | private BigDecimal price; 17 | private Integer categoryId; 18 | 19 | public Long getProductId() { 20 | return productId; 21 | } 22 | 23 | public void setProductId(Long productId) { 24 | this.productId = productId; 25 | } 26 | 27 | public String getProductName() { 28 | return productName; 29 | } 30 | 31 | public void setProductName(String productName) { 32 | this.productName = productName; 33 | } 34 | 35 | public BigDecimal getPrice() { 36 | return price; 37 | } 38 | 39 | public void setPrice(BigDecimal price) { 40 | this.price = price; 41 | } 42 | 43 | public Integer getCategoryId() { 44 | return categoryId; 45 | } 46 | 47 | public void setCategoryId(Integer categoryId) { 48 | this.categoryId = categoryId; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/db/model/entity/view/ProductView.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.db.model.entity.view; 2 | 3 | import com.github.wz2cool.dynamic.mybatis.View; 4 | 5 | import javax.persistence.Column; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * Created by Frank on 2017/7/15. 10 | */ 11 | @View("product LEFT JOIN ${spring_env}category ON product.category_id = category.category_id") 12 | public class ProductView { 13 | @Column(name = "product_id", table = "product") 14 | private Long productID; 15 | @Column(name = "product_name", table = "product") 16 | private String productName; 17 | @Column(name = "price", table = "product") 18 | private BigDecimal price; 19 | 20 | @Column(name = "category_id", table = "category") 21 | private Long categoryID; 22 | @Column(name = "category_name", table = "category") 23 | private String categoryName; 24 | @Column(name = "description", table = "category") 25 | private String description; 26 | @Column(name = "description", table = "product") 27 | private String productDescription; 28 | 29 | public Long getProductID() { 30 | return productID; 31 | } 32 | 33 | public void setProductID(Long productID) { 34 | this.productID = productID; 35 | } 36 | 37 | public String getProductName() { 38 | return productName; 39 | } 40 | 41 | public void setProductName(String productName) { 42 | this.productName = productName; 43 | } 44 | 45 | public BigDecimal getPrice() { 46 | return price; 47 | } 48 | 49 | public void setPrice(BigDecimal price) { 50 | this.price = price; 51 | } 52 | 53 | public Long getCategoryID() { 54 | return categoryID; 55 | } 56 | 57 | public void setCategoryID(Long categoryID) { 58 | this.categoryID = categoryID; 59 | } 60 | 61 | public String getCategoryName() { 62 | return categoryName; 63 | } 64 | 65 | public void setCategoryName(String categoryName) { 66 | this.categoryName = categoryName; 67 | } 68 | 69 | public String getDescription() { 70 | return description; 71 | } 72 | 73 | public void setDescription(String description) { 74 | this.description = description; 75 | } 76 | 77 | public String getProductDescription() { 78 | return productDescription; 79 | } 80 | 81 | public void setProductDescription(String productDescription) { 82 | this.productDescription = productDescription; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/mapper/constant/MapperConstantsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.mapper.constant; 2 | 3 | import org.junit.Test; 4 | 5 | import java.lang.reflect.Constructor; 6 | import java.lang.reflect.InvocationTargetException; 7 | 8 | public class MapperConstantsTest { 9 | @Test(expected = InvocationTargetException.class) 10 | public void TestMapperConstants() throws Exception { 11 | Constructor c = MapperConstants.class.getDeclaredConstructor(); 12 | c.setAccessible(true); 13 | c.newInstance(); 14 | } 15 | } -------------------------------------------------------------------------------- /src/test/java/com/github/wz2cool/dynamic/mybatis/mapper/helper/DynamicQuerySqlHelperTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wz2cool.dynamic.mybatis.mapper.helper; 2 | 3 | import com.github.wz2cool.dynamic.mybatis.MybatisQueryProvider; 4 | import com.github.wz2cool.dynamic.mybatis.mapper.helper.DynamicQuerySqlHelper; 5 | import org.junit.Test; 6 | 7 | import java.lang.reflect.Constructor; 8 | import java.lang.reflect.InvocationTargetException; 9 | 10 | /** 11 | * \* Created with IntelliJ IDEA. 12 | * \* User: Frank 13 | * \* Date: 8/11/2017 14 | * \* Time: 3:00 PM 15 | * \* To change this template use File | Settings | File Templates. 16 | * \* Description: 17 | * \ 18 | */ 19 | public class DynamicQuerySqlHelperTest { 20 | @Test(expected = InvocationTargetException.class) 21 | public void TestDynamicQuerySqlHelper() throws Exception { 22 | Constructor c = DynamicQuerySqlHelper.class.getDeclaredConstructor(); 23 | c.setAccessible(true); 24 | c.newInstance(); 25 | } 26 | } -------------------------------------------------------------------------------- /src/test/resources/com/github/wz2cool/dynamic/mybatis/db/mapper/NorthwindDao.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 10 | 11 | 15 | 16 | 31 | 32 | 41 | 42 | 43 | 44 | 45 | ${insertExpression} 46 | 47 | 48 | 49 | 50 | ${deleteExpression} 51 | 52 | 53 | 54 | 55 | ${updateExpression} 56 | 57 | 58 | 59 | 65 | 66 | -------------------------------------------------------------------------------- /src/test/resources/config/application-h2.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.driver=org.h2.Driver 2 | spring.datasource.hikari.driver-class-name=org.h2.Driver 3 | spring.datasource.url=jdbc:h2:mem:default 4 | spring.datasource.username=sa 5 | spring.datasource.password= 6 | spring.datasource.platform=h2 7 | spring.datasource.initialize=true 8 | mybatis.config-location=classpath:mybatis-config.xml 9 | pagehelper.helperDialect=h2 -------------------------------------------------------------------------------- /src/test/resources/config/application-mysql.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 2 | spring.datasource.url=jdbc:mysql://192.168.8.190:3306/dmdb 3 | spring.datasource.username=innodealing 4 | spring.datasource.password=innodealing 5 | spring.datasource.platform=mysql 6 | spring.datasource.initialize=true 7 | mybatis.config-location=classpath:mybatis-config.xml 8 | pagehelper.helperDialect=mysql -------------------------------------------------------------------------------- /src/test/resources/config/application-postresql.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.driver-class-name=org.postgresql.Driver 2 | spring.datasource.url=jdbc:postgresql://169.254.240.190:5432/postgres 3 | spring.datasource.username=postgres 4 | spring.datasource.password=innodealing 5 | spring.datasource.platform=postgresql 6 | spring.datasource.initialize=true 7 | mybatis.config-location=classpath:mybatis-config.xml 8 | pagehelper.helperDialect=PostgreSQL -------------------------------------------------------------------------------- /src/test/resources/config/application-sqlserver.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver 2 | spring.datasource.url=jdbc:sqlserver://169.254.240.190:1433;DatabaseName=dmdb 3 | spring.datasource.username=sa 4 | spring.datasource.password=innodealing 5 | spring.datasource.platform=sqlserver 6 | spring.datasource.initialize=true 7 | mybatis.config-location=classpath:mybatis-config.xml 8 | pagehelper.helperDialect=sqlserver -------------------------------------------------------------------------------- /src/test/resources/config/application.properties: -------------------------------------------------------------------------------- 1 | spring.profiles.active=h2 2 | #spring.profiles.active=mysql 3 | #spring.profiles.active=sqlserver 4 | #spring.profiles.active=postresql 5 | #pagehelper 6 | pagehelper.reasonable=true 7 | pagehelper.supportMethodsArguments=true 8 | pagehelper.params=count=countSql 9 | -------------------------------------------------------------------------------- /src/test/resources/mybatis-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/test/resources/schema-h2.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS users; 2 | CREATE TABLE users 3 | ( 4 | id INT PRIMARY KEY, 5 | user_name VARCHAR(64) NOT NULL, 6 | password VARCHAR(64) 7 | ); 8 | 9 | DROP TABLE IF EXISTS student; 10 | CREATE TABLE student 11 | ( 12 | id INT PRIMARY KEY, 13 | name VARCHAR(64) NOT NULL 14 | ); 15 | 16 | 17 | DROP TABLE IF EXISTS category; 18 | CREATE TABLE category 19 | ( 20 | category_id INT PRIMARY KEY, 21 | category_name VARCHAR(50) NOT NULL, 22 | description VARCHAR(100) 23 | ); 24 | 25 | DROP TABLE IF EXISTS product; 26 | CREATE TABLE product 27 | ( 28 | product_id INT PRIMARY KEY auto_increment, 29 | category_id INT NOT NULL, 30 | product_name VARCHAR(50) NOT NULL, 31 | price DECIMAL, 32 | description VARCHAR(100) 33 | ); 34 | 35 | DROP TABLE IF EXISTS bug; 36 | CREATE TABLE bug 37 | ( 38 | id INT PRIMARY KEY auto_increment, 39 | title VARCHAR(255) NOT NULL, 40 | assignTo VARCHAR(255) NOT NULL 41 | ); 42 | 43 | DELETE 44 | FROM users; 45 | INSERT INTO users (id, user_name, password) 46 | VALUES 47 | (1, 'usr1', 'bigSecret'), 48 | (2, 'usr2', 'topSecret'); 49 | 50 | 51 | DELETE 52 | FROM category; 53 | INSERT INTO category (category_id, category_name, description) 54 | VALUES 55 | (1, 'Beverages', 'test'), 56 | (2, 'Condiments', 'test'), 57 | (3, 'Oil', 'test'); 58 | 59 | DELETE 60 | FROM product; 61 | INSERT INTO product (product_id, category_id, product_name, price, description) 62 | VALUES 63 | (1, 1, 'Northwind Traders Chai', 18.0000, 'p1'), 64 | (2, 2, 'Northwind Traders Syrup', 9.000, 'p2'), 65 | (3, 2, 'Northwind Traders Cajun Seasoning', 16.000, 'p3'), 66 | (4, 3, 'Northwind Traders Olive Oil', 16.000, 'p4'), 67 | (5, 3, 'Northwind Traders xxxx Oil', 16.000, 'p5'); 68 | 69 | DELETE 70 | FROM bug; 71 | INSERT INTO bug (id, title, assignTo) 72 | VALUES 73 | (1, 'TEST_1', 'FRANK'), 74 | (2, 'TEST_2', 'Jack'); 75 | 76 | DELETE 77 | FROM student; 78 | INSERT INTO student (id, name) 79 | VALUES 80 | (1, 'Ernest Emerson'), 81 | (2, 'Rosemary Ernest'), 82 | (3, 'Prima Ramsden'), 83 | (4, 'Haley Noyes'), 84 | (5, 'Mildred Juliet'), 85 | (6, 'Elvira Daisy'), 86 | (7, 'Monica Robeson'), 87 | (8, 'Katherine Eliot'), 88 | (9, 'Hamiltion Hamlet'); 89 | -------------------------------------------------------------------------------- /src/test/resources/schema-mysql.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS users; 2 | CREATE TABLE users 3 | ( 4 | id INT PRIMARY KEY, 5 | username VARCHAR(64) NOT NULL, 6 | password VARCHAR(64) 7 | ); 8 | 9 | DROP TABLE IF EXISTS category; 10 | CREATE TABLE category 11 | ( 12 | category_id INT PRIMARY KEY, 13 | category_name VARCHAR(50) NOT NULL, 14 | description VARCHAR(100) 15 | ); 16 | 17 | DROP TABLE IF EXISTS product; 18 | CREATE TABLE product 19 | ( 20 | product_id INT PRIMARY KEY auto_increment, 21 | category_id INT NOT NULL, 22 | product_name VARCHAR(50) NOT NULL, 23 | price DECIMAL 24 | ); 25 | 26 | DELETE 27 | FROM users; 28 | INSERT INTO users (id, username, password) 29 | VALUES 30 | (1, 'usr1', 'bigSecret'), 31 | (2, 'usr2', 'topSecret'); 32 | 33 | 34 | DROP TABLE IF EXISTS bug; 35 | CREATE TABLE bug 36 | ( 37 | id INT PRIMARY KEY auto_increment, 38 | title VARCHAR(255) NOT NULL, 39 | assignTo VARCHAR(255) NOT NULL 40 | ); 41 | 42 | DELETE 43 | FROM category; 44 | INSERT INTO category (category_id, category_name, description) 45 | VALUES 46 | (1, 'Beverages', 'test'), 47 | (2, 'Condiments', 'test'), 48 | (3, 'Oil', 'test'); 49 | 50 | DELETE 51 | FROM product; 52 | INSERT INTO product (category_id, product_name, price) 53 | VALUES 54 | (1, 'Northwind Traders Chai', 18.0000), 55 | (2, 'Northwind Traders Syrup', 7.5000), 56 | (2, 'Northwind Traders Cajun Seasoning', 16.5000), 57 | (3, 'Northwind Traders Olive Oil', 16.5000); 58 | 59 | 60 | DELETE 61 | FROM bug; 62 | INSERT INTO bug (id, title, assignTo) 63 | VALUES 64 | (1, 'TEST_1', 'FRANK'), 65 | (2, 'TEST_2', 'Jack'); 66 | 67 | -------------------------------------------------------------------------------- /src/test/resources/schema-postgresql.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS users; 2 | CREATE TABLE users ( 3 | id INT PRIMARY KEY, 4 | username VARCHAR(64) NOT NULL, 5 | password VARCHAR(64) 6 | ); 7 | 8 | DROP TABLE IF EXISTS category; 9 | CREATE TABLE category ( 10 | category_id INT PRIMARY KEY , 11 | category_name VARCHAR (50) NOT NULL, 12 | description VARCHAR (100) 13 | ); 14 | 15 | 16 | DROP TABLE IF EXISTS product; 17 | CREATE TABLE product ( 18 | product_id Serial PRIMARY KEY, 19 | category_id INT NOT NULL, 20 | product_name VARCHAR (50) NOT NULL, 21 | price DECIMAL 22 | ); 23 | 24 | DELETE FROM users; 25 | INSERT INTO users (id, username, password) VALUES 26 | (1, 'usr1', 'bigSecret'), 27 | (2, 'usr2', 'topSecret'); 28 | 29 | 30 | DELETE FROM category; 31 | INSERT INTO category (category_id, category_name, description) VALUES 32 | (1, 'Beverages', 'test'), 33 | (2, 'Condiments', 'test'), 34 | (3, 'Oil', 'test'); 35 | 36 | DELETE FROM product; 37 | INSERT INTO product (category_id, product_name, price) VALUES 38 | (1, 'Northwind Traders Chai', 18.0000), 39 | (2, 'Northwind Traders Syrup', 7.5000), 40 | (2, 'Northwind Traders Cajun Seasoning', 16.5000), 41 | (3, 'Northwind Traders Olive Oil', 16.5000); 42 | -------------------------------------------------------------------------------- /src/test/resources/schema-sqlserver.sql: -------------------------------------------------------------------------------- 1 | IF OBJECT_ID('users', 'U') IS NOT NULL 2 | DROP TABLE users; 3 | CREATE TABLE users ( 4 | id INT PRIMARY KEY, 5 | username VARCHAR(64) NOT NULL, 6 | password VARCHAR(64) 7 | ); 8 | 9 | IF OBJECT_ID('category', 'U') IS NOT NULL 10 | DROP TABLE category; 11 | CREATE TABLE category ( 12 | category_id INT PRIMARY KEY, 13 | category_name VARCHAR (50) NOT NULL, 14 | description VARCHAR (100) 15 | ); 16 | 17 | IF OBJECT_ID('product', 'U') IS NOT NULL 18 | DROP TABLE product; 19 | CREATE TABLE product ( 20 | product_id INT PRIMARY KEY IDENTITY(1,1), 21 | category_id INT NOT NULL, 22 | product_name VARCHAR (50) NOT NULL, 23 | price DECIMAL 24 | ); 25 | 26 | DELETE FROM users; 27 | INSERT INTO users (id, username, password) VALUES 28 | (1, 'usr1', 'bigSecret'), 29 | (2, 'usr2', 'topSecret'); 30 | 31 | 32 | DELETE FROM category; 33 | INSERT INTO category (category_id, category_name, description) VALUES 34 | (1, 'Beverages', 'test'), 35 | (2, 'Condiments', 'test'), 36 | (3, 'Oil', 'test'); 37 | 38 | DELETE FROM product; 39 | INSERT INTO product (category_id, product_name, price) VALUES 40 | (1, 'Northwind Traders Chai', 18.0000), 41 | (2, 'Northwind Traders Syrup', 7.5000), 42 | (2, 'Northwind Traders Cajun Seasoning', 16.5000), 43 | (3, 'Northwind Traders Olive Oil', 16.5000); --------------------------------------------------------------------------------