diff --git a/changes.txt b/changes.txt index cec474ec..a2f25361 100644 --- a/changes.txt +++ b/changes.txt @@ -1,3 +1,35 @@ +mybatis-flex v1.3.2 20230528: +新增:select (field1 * field2 * 100) as xxx from ... 的 SQL 构建场景 +优化:ClassUtil.wrap 方法修改为 getWrapType +优化:重构 BaseMapper.selectListByQueryAs() 方法,使其更加通用 +优化:重构 EnumWrapper.java,使之方法和变量更加明确易读 +优化:WrapperUtil.buildAsAlias 方法,使之在多种场景下有统一行为 +优化:优化 Row,添加 prepareAttrs() 等方法 +修复:EnumWrapper 对其 getter 方法判断错误的问题 +文档:更新一对多、多对一的子查询相关文档 + + + +mybatis-flex v1.3.1 20230526: +新增:分页查询添加关联字段查询功能; +新增:Mapper 添加 updateNumberAddByQuery 方法,用于 update table set xxx = xxx + 1 的场景; +优化:添加 FieldWrapper 使得关联字段查询拥有更高的性能 +优化:优化 EnumWrapper 使之逻辑更加清晰简单 +优化:字段子查询不在需要配置 type +优化:代码生成器 remarks 修改为 comment; 感谢 @王帅 +优化:代码生成器 GlobalConfig 拆分,使之更加直观; 感谢 @王帅 +优化:代码生成器新增注释生成配置; 感谢 @王帅 +优化:代码生成器新增 mapper xml 生成功能; 感谢 @王帅 +优化:代码生成器新增 package-info.java 生成功能; 感谢 @王帅 +优化:代码生成器新增 Controller 生成功能; 感谢 @王帅 +优化:代码生成器每个生成的文件,单独支持是否覆盖已生成的文件; 感谢 @王帅 +优化:代码生成器新增设置模板文件位置,可以使用指定的模板生成文件; 感谢 @王帅 +修复:select max(select(...)) 等函数内部有参数时,无法获取的问题; +文档:更新代码生成器文档。感谢 @王帅 +文档:优化 QueryWrapper 的相关文档 + + + mybatis-flex v1.3.0 20230525: 新增:新增 一对多、多对一 查询功能 新增:为 SqlServer 添加独立的 LimitOffset 处理器 diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 9aa14409..893e1f2a 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -11,6 +11,7 @@ export default defineConfig({ // logo: '/assets/images/logo02.png', themeConfig: { + outlineTitle:'章节', search: { provider: 'local' }, diff --git a/docs/.vitepress/theme/MyLayout.vue b/docs/.vitepress/theme/MyLayout.vue index 6137c142..b2c325ba 100644 --- a/docs/.vitepress/theme/MyLayout.vue +++ b/docs/.vitepress/theme/MyLayout.vue @@ -1,16 +1,19 @@ \ No newline at end of file diff --git a/docs/zh/base/add-delete-update.md b/docs/zh/base/add-delete-update.md index 3157e206..8cceab14 100644 --- a/docs/zh/base/add-delete-update.md +++ b/docs/zh/base/add-delete-update.md @@ -64,6 +64,7 @@ delete from tb_account where id >= 100; - **updateByQuery(entity, queryWrapper)**:根据 queryWrapper 组成的条件更新到 entity 到数据库,entity 可以没有主键(如果有也会被忽略), entity 的 null 属性,会自动被忽略。 - **updateByQuery(entity, ignoreNulls, queryWrapper)**:据 queryWrapper 组成的条件更新到 entity 到数据库,entity 可以没有主键(如果有也会被忽略)。 ignoreNulls 用于是否忽略 entity 的 null 属性 , 若 ignoreNulls 为 false,entity 的所有 null 属性都会被更新到数据库。 +- **updateNumberAddByQuery(fieldName,value,queryWrapper)**:通过 `update table set field = field + 1 where ... ` 的这种方向更新数据库某个字段内容。 ## 部分字段更新 diff --git a/docs/zh/base/field-query.md b/docs/zh/base/field-query.md index ee8cb2ae..bb1ac72a 100644 --- a/docs/zh/base/field-query.md +++ b/docs/zh/base/field-query.md @@ -21,7 +21,7 @@ public class Article { 查询代码如下: -```java {10-14} +```java {9-13} QueryWrapper queryWrapper = QueryWrapper.create() .select().form(ARTICLE) .where(ARTICLE.id.ge(100)); @@ -29,7 +29,6 @@ QueryWrapper queryWrapper = QueryWrapper.create() List
articles = mapper.selectListByQuery(queryWrapper , fieldQueryBuilder -> fieldQueryBuilder .field(Article::getCategories) // 或者 .field("categories") - .type(Category.class) //非集合,自动读取 type,可以不指定 type .queryWrapper(article -> QueryWrapper.create() .select().from(CATEGORY) .where(CATEGORY.id.in( @@ -42,7 +41,7 @@ List
articles = mapper.selectListByQuery(queryWrapper 通过以上代码可以看出,`Article.categories` 字段的结果,来源于 `queryWrapper()` 方法构建的 `QueryWrapper`。 -其原理是:MyBatis-Flex 的内部逻辑是先查询出 `Article` 的数据,然后再根据 `Article` 构建出新的 SQL,查询分类,并赋值给 `Article.categories`, +其原理是:MyBatis-Flex 的内部逻辑是先查询出 `Article` 的数据,然后再根据 `Article` 构建出新的 SQL,查询分类,并赋值给 `Article.categories` 属性, 假设 `Article` 有 10 条数据,那么最终会进行 11 次数据库查询。 查询的 SQL 大概如下: @@ -82,7 +81,27 @@ select * from tb_category where id in (select category_id from article_category_mapping where article_id = 109); ``` -## 其他场景 +## 知识点 +MyBatis-Flex 的关联子查询,和 JPA 等其他第三方框架有很大的差异,比如 JPA 是通过配置来构建查询 SQL,其构建生成的 SQL 对于用户来说是不透明的。 +因此,用户几乎无法对 JPA 的注解生成 SQL 优化。 + +而 MyBatis-Flex 关联子查询的 SQL 完全是由用户构建的,因此会更加灵活,更加有利于我们进行 SQL 优化。在子查询中,有很多的场景, JPA 对一对一、 +一对多等等不同的场景给出了不同的注解、以及参数,导致用户的学习成本非常高。 + +对 MyBatis-Flex 来说,学习成本是非常低的,在构建子查询时,只需要明白为哪个字段、通过什么样的 SQL 查询就可以了,以下是示例: + +```java 3,4 +List
articles = mapper.selectListByQuery(query + , fieldQueryBuilder -> fieldQueryBuilder + .field(...) // 为哪个字段查询的? + .queryWrapper(...) // 通过什么样的 SQL 查询的? + ); +``` + +因此,在 MyBatis-Flex 的设计中,无论是一对多、多对一、多对多... 还是其他任何一种场景,其逻辑都是一样的。 + + +## 更多场景 通过以上内容看出,`Article` 的任何属性,都是可以通过传入 `FieldQueryBuilder` 来构建 `QueryWrapper` 进行再次查询, 这些不仅仅只适用于 `一对多`、`一对一`、`多对一`、`多对多`等场景。任何 `Article` 对象里的属性,需要二次查询赋值的,都是可以通过这种方式进行。 \ No newline at end of file diff --git a/docs/zh/base/querywrapper.md b/docs/zh/base/querywrapper.md index 761e5dec..46142040 100644 --- a/docs/zh/base/querywrapper.md +++ b/docs/zh/base/querywrapper.md @@ -125,11 +125,14 @@ FROM tb_account ```java QueryWrapper wrapper = QueryWrapper.create() - .select(ACCOUNT.ID - ,case_().when(ACCOUNT.ID.ge(2)).then("x2") - .when(ACCOUNT.ID.ge(1)).then("x1") - .else_("x100") - .end().as("xName") + .select( + ACCOUNT.ID + ,case_() + .when(ACCOUNT.ID.ge(2)).then("x2") + .when(ACCOUNT.ID.ge(1)).then("x1") + .else_("x100") + .end().as("xName") + ) ``` 其查询生成的 Sql 如下: @@ -156,11 +159,13 @@ SQL 执行的结果如下: ```java QueryWrapper queryWrapper = QueryWrapper.create() - .select(ACCOUNT.ALL_COLUMNS, - case_(ACCOUNT.ID) - .when(100).then(100) - .when(200).then(200) - .else_(300).end().as("result")) + .select( + ACCOUNT.ALL_COLUMNS, + case_(ACCOUNT.ID) + .when(100).then(100) + .when(200).then(200) + .else_(300).end().as("result") + ) .from(ACCOUNT) .where(ACCOUNT.USER_NAME.like("michael")); ``` @@ -173,7 +178,8 @@ SELECT *, WHEN 100 THEN 100 WHEN 200 THEN 200 ELSE 300 END) AS `result` -FROM `tb_account` WHERE `user_name` LIKE ? +FROM `tb_account` +WHERE `user_name` LIKE ? ``` ::: tip 提示 diff --git a/docs/zh/core/multi-datasource.md b/docs/zh/core/multi-datasource.md index 1b66ff6e..e1f26bd4 100644 --- a/docs/zh/core/multi-datasource.md +++ b/docs/zh/core/multi-datasource.md @@ -142,7 +142,7 @@ mybatis-flex: 同时,项目若使用到了多个数据源类型,则也需要添加 `type` 来指定当前数据源的类型。 -除了 `type`、`url`、`username`、`password` 的配置以为,MyBatis-Flex 支持该 `DataSource` 类型的所有参数配置, +除了 `type`、`url`、`username`、`password` 的配置以外,MyBatis-Flex 支持该 `DataSource` 类型的所有参数配置, 例如,在 `DruidDataSource` 类中存在 `setAsyncInit` 方法,我们就可以添加 `asyncInit` 的配置,如下所示: ```yaml 8 diff --git a/docs/zh/intro/getting-started.md b/docs/zh/intro/getting-started.md index 8e98c533..fffa7572 100644 --- a/docs/zh/intro/getting-started.md +++ b/docs/zh/intro/getting-started.md @@ -27,12 +27,12 @@ Maven示例: com.mybatis-flex mybatis-flex-core - 1.3.0 + 1.3.2 com.mybatis-flex mybatis-flex-processor - 1.3.0 + 1.3.2 provided ``` @@ -46,7 +46,7 @@ Gradle示例: ```groovy // file: build.gradle ext { - mybatis_flex_version = '1.3.0' + mybatis_flex_version = '1.3.2' } dependencies { implementation("com.mybatis-flex:mybatis-flex-core:${mybatis_flex_version}") diff --git a/docs/zh/intro/maven.md b/docs/zh/intro/maven.md index c86b6040..fc1d6f56 100644 --- a/docs/zh/intro/maven.md +++ b/docs/zh/intro/maven.md @@ -12,12 +12,12 @@ com.mybatis-flex mybatis-flex-core - 1.3.0 + 1.3.2 com.mybatis-flex mybatis-flex-processor - 1.3.0 + 1.3.2 provided ``` @@ -28,12 +28,12 @@ com.mybatis-flex mybatis-flex-spring - 1.3.0 + 1.3.2 com.mybatis-flex mybatis-flex-processor - 1.3.0 + 1.3.2 provided `````` @@ -44,12 +44,12 @@ com.mybatis-flex mybatis-flex-spring-boot-starter - 1.3.0 + 1.3.2 com.mybatis-flex mybatis-flex-processor - 1.3.0 + 1.3.2 provided ``` @@ -70,7 +70,7 @@ com.mybatis-flex mybatis-flex-processor - 1.3.0 + 1.3.2 diff --git a/docs/zh/others/apt.md b/docs/zh/others/apt.md index bbd8c31e..83db7798 100644 --- a/docs/zh/others/apt.md +++ b/docs/zh/others/apt.md @@ -179,7 +179,7 @@ processor.baseMapperClass=com.domain.mapper.MyBaseMapper ``` dependencies { ... - annotationProcessor 'com.mybatis-flex:mybatis-flex-processor:1.3.0' + annotationProcessor 'com.mybatis-flex:mybatis-flex-processor:1.3.2' } ``` diff --git a/docs/zh/others/codegen.md b/docs/zh/others/codegen.md index 92199f35..9beed72f 100644 --- a/docs/zh/others/codegen.md +++ b/docs/zh/others/codegen.md @@ -10,7 +10,7 @@ com.mybatis-flex mybatis-flex-codegen - 1.3.0 + 1.3.2 ``` diff --git a/mybatis-flex-annotation/pom.xml b/mybatis-flex-annotation/pom.xml index 2d92199c..27b70186 100644 --- a/mybatis-flex-annotation/pom.xml +++ b/mybatis-flex-annotation/pom.xml @@ -5,7 +5,7 @@ parent com.mybatis-flex - 1.3.0 + 1.3.2 4.0.0 diff --git a/mybatis-flex-codegen/pom.xml b/mybatis-flex-codegen/pom.xml index 1f4f674f..4ed08b72 100644 --- a/mybatis-flex-codegen/pom.xml +++ b/mybatis-flex-codegen/pom.xml @@ -5,7 +5,7 @@ parent com.mybatis-flex - 1.3.0 + 1.3.2 4.0.0 @@ -27,7 +27,7 @@ com.mybatis-flex mybatis-flex-spring - 1.3.0 + 1.3.2 diff --git a/mybatis-flex-codegen/src/test/java/com/mybatisflex/codegen/test/GeneratorTest.java b/mybatis-flex-codegen/src/test/java/com/mybatisflex/codegen/test/GeneratorTest.java index 2efebe31..2c256448 100644 --- a/mybatis-flex-codegen/src/test/java/com/mybatisflex/codegen/test/GeneratorTest.java +++ b/mybatis-flex-codegen/src/test/java/com/mybatisflex/codegen/test/GeneratorTest.java @@ -19,7 +19,6 @@ package com.mybatisflex.codegen.test; import com.mybatisflex.codegen.Generator; import com.mybatisflex.codegen.config.GlobalConfig; import com.zaxxer.hikari.HikariDataSource; -import org.junit.Test; import java.util.function.UnaryOperator; @@ -82,7 +81,7 @@ public class GeneratorTest { generator.generate(); } - @Test +// @Test public void testCodeGen2() { //配置数据源 HikariDataSource dataSource = new HikariDataSource(); diff --git a/mybatis-flex-core/pom.xml b/mybatis-flex-core/pom.xml index e87d997f..13a56117 100644 --- a/mybatis-flex-core/pom.xml +++ b/mybatis-flex-core/pom.xml @@ -5,7 +5,7 @@ parent com.mybatis-flex - 1.3.0 + 1.3.2 4.0.0 @@ -22,13 +22,13 @@ com.mybatis-flex mybatis-flex-annotation - 1.3.0 + 1.3.2 com.mybatis-flex mybatis-flex-processor - 1.3.0 + 1.3.2 diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/BaseMapper.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/BaseMapper.java index b220ef16..aa33f018 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/BaseMapper.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/BaseMapper.java @@ -24,14 +24,9 @@ import com.mybatisflex.core.provider.EntitySqlProvider; import com.mybatisflex.core.query.*; import com.mybatisflex.core.table.TableInfo; import com.mybatisflex.core.table.TableInfoFactory; -import com.mybatisflex.core.util.CollectionUtil; -import com.mybatisflex.core.util.ConvertUtil; -import com.mybatisflex.core.util.ObjectUtil; -import com.mybatisflex.core.util.StringUtil; +import com.mybatisflex.core.util.*; import org.apache.ibatis.annotations.*; import org.apache.ibatis.builder.annotation.ProviderContext; -import org.apache.ibatis.reflection.MetaObject; -import org.apache.ibatis.reflection.SystemMetaObject; import java.io.Serializable; import java.util.*; @@ -283,6 +278,33 @@ public interface BaseMapper { int updateByQuery(@Param(FlexConsts.ENTITY) T entity, @Param(FlexConsts.IGNORE_NULLS) boolean ignoreNulls, @Param(FlexConsts.QUERY) QueryWrapper queryWrapper); + /** + * 执行类似 update table set field=field+1 where ... 的场景 + * + * @param fieldName 字段名 + * @param value 值( >=0 加,小于 0 减) + * @param queryWrapper 条件 + * @see EntitySqlProvider#updateNumberAddByQuery(Map, ProviderContext) + */ + @UpdateProvider(type = EntitySqlProvider.class, method = "updateNumberAddByQuery") + int updateNumberAddByQuery(@Param(FlexConsts.FIELD_NAME) String fieldName, @Param(FlexConsts.VALUE) Number value, @Param(FlexConsts.QUERY) QueryWrapper queryWrapper); + + + /** + * 执行类似 update table set field=field+1 where ... 的场景 + * + * @param fn 字段名 + * @param value 值( >=0 加,小于 0 减) + * @param queryWrapper 条件 + * @see EntitySqlProvider#updateNumberAddByQuery(Map, ProviderContext) + */ + default int updateNumberAddByQuery(LambdaGetter fn, Number value, QueryWrapper queryWrapper) { + TableInfo tableInfo = TableInfoFactory.ofMapperClass(ClassUtil.getUsefulClass(getClass())); + String column = tableInfo.getColumnByProperty(LambdaUtil.getFieldName(fn)); + return updateNumberAddByQuery(column, value, queryWrapper); + } + + /** * 根据主键来选择数据 * @@ -336,13 +358,8 @@ public interface BaseMapper { * @return 数据内容 */ default R selectOneByQueryAs(QueryWrapper queryWrapper, Class asType) { - try { - MappedStatementTypes.setCurrentType(asType); - List entities = selectListByQueryAs(queryWrapper.limit(1), asType); - return (entities == null || entities.isEmpty()) ? null : entities.get(0); - } finally { - MappedStatementTypes.clear(); - } + List entities = selectListByQueryAs(queryWrapper.limit(1), asType); + return (entities == null || entities.isEmpty()) ? null : entities.get(0); } /** @@ -412,7 +429,7 @@ public interface BaseMapper { List selectListByQuery(@Param(FlexConsts.QUERY) QueryWrapper queryWrapper); - default List selectListByQuery(@Param(FlexConsts.QUERY) QueryWrapper queryWrapper + default List selectListByQuery(QueryWrapper queryWrapper , Consumer>... consumers) { List list = selectListByQuery(queryWrapper); @@ -420,46 +437,7 @@ public interface BaseMapper { return Collections.emptyList(); } - list.forEach(entity -> { - for (Consumer> consumer : consumers) { - FieldQueryBuilder fieldQueryBuilder = new FieldQueryBuilder<>(entity); - consumer.accept(fieldQueryBuilder); - FieldQuery fieldQuery = fieldQueryBuilder.build(); - QueryWrapper childQuery = fieldQuery.getQueryWrapper(); - MetaObject entityMetaObject = SystemMetaObject.forObject(entity); - Class setterType = entityMetaObject.getSetterType(fieldQuery.getField()); - - Class mappingType = fieldQuery.getMappingType(); - if (mappingType == null) { - if (setterType.isAssignableFrom(Collection.class)) { - throw new IllegalStateException("Mapping Type can not be null for query Many."); - } else if (setterType.isArray()) { - mappingType = setterType.getComponentType(); - } else { - mappingType = setterType; - } - } - - Object value; - try { - MappedStatementTypes.setCurrentType(mappingType); - if (setterType.isAssignableFrom(List.class)) { - value = selectListByQueryAs(childQuery, mappingType); - } else if (setterType.isAssignableFrom(Set.class)) { - value = selectListByQueryAs(childQuery, mappingType); - value = new HashSet<>((Collection) value); - } else if (setterType.isArray()) { - value = selectListByQueryAs(childQuery, mappingType); - value = ((List) value).toArray(); - } else { - value = selectOneByQueryAs(childQuery, mappingType); - } - } finally { - MappedStatementTypes.clear(); - } - entityMetaObject.setValue(fieldQuery.getField(), value); - } - }); + __queryFields(list, consumers); return list; } @@ -473,69 +451,25 @@ public interface BaseMapper { * @param asType 接收数据类型 * @return 数据列表 */ - @SelectProvider(type = EntitySqlProvider.class, method = "selectListByQuery") - List selectListByQueryAs(@Param(FlexConsts.QUERY) QueryWrapper queryWrapper, Class asType); - - - default List selectListByQueryAs(@Param(FlexConsts.QUERY) QueryWrapper queryWrapper, Class asType - , Consumer>... consumers) { - List list; + default List selectListByQueryAs(QueryWrapper queryWrapper, Class asType) { try { MappedStatementTypes.setCurrentType(asType); - list = selectListByQueryAs(queryWrapper, asType); + return (List) selectListByQuery(queryWrapper); } finally { MappedStatementTypes.clear(); } + } + + default List selectListByQueryAs(QueryWrapper queryWrapper, Class asType + , Consumer>... consumers) { + List list = selectListByQueryAs(queryWrapper, asType); if (list == null || list.isEmpty()) { return Collections.emptyList(); + } else { + __queryFields(list, consumers); + return list; } - - list.forEach(entity -> { - for (Consumer> consumer : consumers) { - FieldQueryBuilder fieldQueryBuilder = new FieldQueryBuilder<>(entity); - consumer.accept(fieldQueryBuilder); - FieldQuery fieldQuery = fieldQueryBuilder.build(); - QueryWrapper childQuery = fieldQuery.getQueryWrapper(); - - MetaObject entityMetaObject = SystemMetaObject.forObject(entity); - Class setterType = entityMetaObject.getSetterType(fieldQuery.getField()); - - Class mappingType = fieldQuery.getMappingType(); - if (mappingType == null) { - if (setterType.isAssignableFrom(Collection.class)) { - throw new IllegalStateException("Mapping Type can not be null for query Many."); - } else if (setterType.isArray()) { - mappingType = setterType.getComponentType(); - } else { - mappingType = setterType; - } - } - - Object value; - try { - MappedStatementTypes.setCurrentType(mappingType); - if (setterType.isAssignableFrom(List.class)) { - value = selectListByQueryAs(childQuery, mappingType); - } else if (setterType.isAssignableFrom(Set.class)) { - value = selectListByQueryAs(childQuery, mappingType); - value = new HashSet<>((Collection) value); - } else if (setterType.isArray()) { - value = selectListByQueryAs(childQuery, mappingType); - value = ((List) value).toArray(); - } else { - value = selectOneByQueryAs(childQuery, mappingType); - } - } finally { - MappedStatementTypes.clear(); - } - - - entityMetaObject.setValue(fieldQuery.getField(), value); - } - }); - - return list; } @@ -694,12 +628,12 @@ public interface BaseMapper { * @param queryWrapper 查询条件 * @return page 数据 */ - default Page paginate(Page page, QueryWrapper queryWrapper) { - return paginateAs(page, queryWrapper, null); + default Page paginate(Page page, QueryWrapper queryWrapper, Consumer>... consumers) { + return paginateAs(page, queryWrapper, null, consumers); } - default Page paginateAs(Page page, QueryWrapper queryWrapper, Class asType) { + default Page paginateAs(Page page, QueryWrapper queryWrapper, Class asType, Consumer>... consumers) { List selectColumns = CPI.getSelectColumns(queryWrapper); List orderBys = CPI.getOrderBys(queryWrapper); @@ -776,19 +710,48 @@ public interface BaseMapper { queryWrapper.limit(offset, page.getPageSize()); if (asType != null) { - try { - // 调用内部方法,不走代理,需要主动设置 MappedStatementType - // fixed https://gitee.com/mybatis-flex/mybatis-flex/issues/I73BP6 - MappedStatementTypes.setCurrentType(asType); - List records = selectListByQueryAs(queryWrapper, asType); - page.setRecords(records); - } finally { - MappedStatementTypes.clear(); - } + List records = selectListByQueryAs(queryWrapper, asType); + __queryFields(records, consumers); + page.setRecords(records); } else { List records = (List) selectListByQuery(queryWrapper); + __queryFields(records, consumers); page.setRecords(records); } return page; } + + + default void __queryFields(List list, Consumer>[] consumers) { + if (CollectionUtil.isEmpty(list) || ArrayUtil.isEmpty(consumers) || consumers[0] == null) { + return; + } + list.forEach(entity -> { + for (Consumer> consumer : consumers) { + FieldQueryBuilder fieldQueryBuilder = new FieldQueryBuilder<>(entity); + consumer.accept(fieldQueryBuilder); + FieldQuery fieldQuery = fieldQueryBuilder.build(); + QueryWrapper childQuery = fieldQuery.getQueryWrapper(); + + FieldWrapper fieldWrapper = FieldWrapper.of(entity.getClass(), fieldQuery.getField()); + + Class fieldType = fieldWrapper.getFieldType(); + Class mappingType = fieldWrapper.getMappingType(); + + Object value; + if (fieldType.isAssignableFrom(List.class)) { + value = selectListByQueryAs(childQuery, mappingType); + } else if (fieldType.isAssignableFrom(Set.class)) { + value = selectListByQueryAs(childQuery, mappingType); + value = new HashSet<>((Collection) value); + } else if (fieldType.isArray()) { + value = selectListByQueryAs(childQuery, mappingType); + value = ((List) value).toArray(); + } else { + value = selectOneByQueryAs(childQuery, mappingType); + } + fieldWrapper.set(value, entity); + } + }); + } } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/FlexConsts.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/FlexConsts.java index f7da32b9..7a7d766c 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/FlexConsts.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/FlexConsts.java @@ -20,15 +20,17 @@ package com.mybatisflex.core; */ public class FlexConsts { public static final String NAME = "MyBatis-Flex"; - public static final String VERSION = "1.3.0"; + public static final String VERSION = "1.3.2"; public static final String DEFAULT_PRIMARY_FIELD = "id"; public static final String SQL = "$$sql"; public static final String SQL_ARGS = "$$sql_args"; public static final String TABLE_NAME = "$$tableName"; + public static final String FIELD_NAME = "$$fieldName"; public static final String PRIMARY_KEY = "$$primaryKey"; public static final String PRIMARY_VALUE = "$$primaryValue"; + public static final String VALUE = "$$value"; public static final String QUERY = "$$query"; public static final String ROW = "$$row"; @@ -39,7 +41,6 @@ public class FlexConsts { public static final String IGNORE_NULLS = "$$ignoreNulls"; public static final String METHOD_INSERT_BATCH = "insertBatch"; - public static final String METHOD_SELECT_LIST_BY_QUERY_AS = "selectListByQueryAs"; /** * 当 entity 使用逻辑删除时,0 为 entity 的正常状态 diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/dialect/IDialect.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/dialect/IDialect.java index 270c7da2..5fefcc4e 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/dialect/IDialect.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/dialect/IDialect.java @@ -70,6 +70,8 @@ public interface IDialect { String forUpdateEntityByQuery(TableInfo tableInfo, Object entity, boolean ignoreNulls, QueryWrapper queryWrapper); + String forUpdateNumberAddByQuery(String tableName, String fieldName, Number value, QueryWrapper queryWrapper); + String forSelectOneEntityById(TableInfo tableInfo); String forSelectEntityListByIds(TableInfo tableInfo, Object[] primaryValues); diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/dialect/impl/CommonsDialectImpl.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/dialect/impl/CommonsDialectImpl.java index 3f6811ea..12f680ee 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/dialect/impl/CommonsDialectImpl.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/dialect/impl/CommonsDialectImpl.java @@ -667,6 +667,33 @@ public class CommonsDialectImpl implements IDialect { return sql.toString(); } + + @Override + public String forUpdateNumberAddByQuery(String tableName, String fieldName, Number value, QueryWrapper queryWrapper) { + StringBuilder sql = new StringBuilder(); + sql.append("UPDATE ").append(forHint(CPI.getHint(queryWrapper))).append(wrap(tableName)).append(" SET "); + sql.append(wrap(fieldName)).append("=").append(wrap(fieldName)).append(value.intValue() >= 0 ? " + " : " - ").append(Math.abs(value.longValue())); + + String whereConditionSql = buildWhereConditionSql(queryWrapper); + + //不允许全量更新 + if (StringUtil.isBlank(whereConditionSql)) { + throw new IllegalArgumentException("Not allowed UPDATE a table without where condition."); + } + + sql.append(" WHERE ").append(whereConditionSql); + + List endFragments = CPI.getEndFragments(queryWrapper); + if (CollectionUtil.isNotEmpty(endFragments)) { + for (String endFragment : endFragments) { + sql.append(" ").append(endFragment); + } + } + + return sql.toString(); + } + + @Override public String forSelectOneEntityById(TableInfo tableInfo) { StringBuilder sql = buildSelectColumnSql(null, null, null); diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/field/FieldQuery.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/field/FieldQuery.java index e0d662a6..372f7fdd 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/field/FieldQuery.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/field/FieldQuery.java @@ -22,7 +22,7 @@ import java.io.Serializable; public class FieldQuery implements Serializable { private String field; - private Class mappingType; +// private Class mappingType; private QueryWrapper queryWrapper; public String getField() { @@ -33,13 +33,13 @@ public class FieldQuery implements Serializable { this.field = field; } - public Class getMappingType() { - return mappingType; - } - - public void setMappingType(Class mappingType) { - this.mappingType = mappingType; - } +// public Class getMappingType() { +// return mappingType; +// } +// +// public void setMappingType(Class mappingType) { +// this.mappingType = mappingType; +// } public QueryWrapper getQueryWrapper() { return queryWrapper; diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/field/FieldQueryBuilder.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/field/FieldQueryBuilder.java index 47d74353..f147265f 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/field/FieldQueryBuilder.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/field/FieldQueryBuilder.java @@ -38,10 +38,10 @@ public class FieldQueryBuilder implements Serializable { return field(LambdaUtil.getFieldName(fn)); } - public FieldQueryBuilder type(Class mappingType){ - fieldQuery.setMappingType(mappingType); - return this; - } +// public FieldQueryBuilder type(Class mappingType){ +// fieldQuery.setMappingType(mappingType); +// return this; +// } public FieldQueryBuilder queryWrapper(QueryBuilder fun){ fieldQuery.setQueryWrapper(fun.build(entity)); diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/handler/FlexEnumTypeHandler.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/handler/FlexEnumTypeHandler.java index c819e2da..1dd50d7d 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/handler/FlexEnumTypeHandler.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/handler/FlexEnumTypeHandler.java @@ -45,31 +45,31 @@ public class FlexEnumTypeHandler> extends BaseTypeHandler { @Override public E getNullableResult(ResultSet rs, String columnName) throws SQLException { - Object value = rs.getObject(columnName, enumWrapper.getEnumPropertyType()); + Object value = rs.getObject(columnName, enumWrapper.getPropertyType()); if (null == value && rs.wasNull()) { return null; } - return enumWrapper.toEnum(value); + return enumWrapper.getEnum(value); } @Override public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException { - Object value = rs.getObject(columnIndex, enumWrapper.getEnumPropertyType()); + Object value = rs.getObject(columnIndex, enumWrapper.getPropertyType()); if (null == value && rs.wasNull()) { return null; } - return enumWrapper.toEnum(value); + return enumWrapper.getEnum(value); } @Override public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { - Object value = cs.getObject(columnIndex, enumWrapper.getEnumPropertyType()); + Object value = cs.getObject(columnIndex, enumWrapper.getPropertyType()); if (null == value && cs.wasNull()) { return null; } - return enumWrapper.toEnum(value); + return enumWrapper.getEnum(value); } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/mybatis/FlexConfiguration.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/mybatis/FlexConfiguration.java index 954bb556..99ad428b 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/mybatis/FlexConfiguration.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/mybatis/FlexConfiguration.java @@ -133,9 +133,9 @@ public class FlexConfiguration extends Configuration { public MappedStatement getMappedStatement(String id) { MappedStatement ms = super.getMappedStatement(id); - //动态 resultsMap - if (id.endsWith(FlexConsts.METHOD_SELECT_LIST_BY_QUERY_AS)) { - Class asType = MappedStatementTypes.getCurrentType(); + //动态 resultsMap,方法名称为:selectListByQuery + Class asType = MappedStatementTypes.getCurrentType(); + if (asType != null) { return MapUtil.computeIfAbsent(dynamicMappedStatementCache, asType, aClass -> replaceResultMap(ms, TableInfoFactory.ofEntityClass(asType)) ); diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/mybatis/MapperInvocationHandler.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/mybatis/MapperInvocationHandler.java index 5a3d2e77..cc9028cf 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/mybatis/MapperInvocationHandler.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/mybatis/MapperInvocationHandler.java @@ -16,7 +16,6 @@ package com.mybatisflex.core.mybatis; import com.mybatisflex.annotation.UseDataSource; -import com.mybatisflex.core.FlexConsts; import com.mybatisflex.core.FlexGlobalConfig; import com.mybatisflex.core.datasource.DataSourceKey; import com.mybatisflex.core.datasource.FlexDataSource; @@ -46,11 +45,7 @@ public class MapperInvocationHandler implements InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { boolean clearDsKey = false; boolean clearDbType = false; - boolean isSelectListByQueryAsMethod = FlexConsts.METHOD_SELECT_LIST_BY_QUERY_AS.equals(method.getName()); try { - if (isSelectListByQueryAsMethod){ - MappedStatementTypes.setCurrentType((Class) args[1]); - } //获取用户动态指定,由用户指定数据源,则应该有用户清除 String dataSourceKey = DataSourceKey.get(); @@ -78,9 +73,6 @@ public class MapperInvocationHandler implements InvocationHandler { } return method.invoke(mapper, args); } finally { - if (isSelectListByQueryAsMethod){ - MappedStatementTypes.clear(); - } if (clearDbType) { DialectFactory.clearHintDbType(); } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/provider/EntitySqlProvider.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/provider/EntitySqlProvider.java index 35aa7034..2c5f1072 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/provider/EntitySqlProvider.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/provider/EntitySqlProvider.java @@ -247,6 +247,32 @@ public class EntitySqlProvider { return DialectFactory.getDialect().forUpdateEntityByQuery(tableInfo, entity, ignoreNulls, queryWrapper); } + /** + * updateNumberByQuery 的 sql 构建 + * + * @param params + * @param context + * @return sql + * @see com.mybatisflex.core.BaseMapper#updateNumberAddByQuery(String, Number, QueryWrapper) + */ + public static String updateNumberAddByQuery(Map params, ProviderContext context) { + QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params); + + String fieldName = ProviderUtil.getFieldName(params); + Number value = (Number) ProviderUtil.getValue(params); + + TableInfo tableInfo = ProviderUtil.getTableInfo(context); + + //处理逻辑删除 和 多租户等 + tableInfo.appendConditions(null, queryWrapper); + + Object[] queryParams = CPI.getValueArray(queryWrapper); + + ProviderUtil.setSqlArgs(params, queryParams); + + return DialectFactory.getDialect().forUpdateNumberAddByQuery(tableInfo.getTableName(), fieldName, value, queryWrapper); + } + /** * selectOneById 的 sql 构建 @@ -350,10 +376,6 @@ public class EntitySqlProvider { } - - - - private static List getTableInfos(ProviderContext context, QueryWrapper queryWrapper) { List tableInfos; List queryTables = CPI.getQueryTables(queryWrapper); diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/provider/ProviderUtil.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/provider/ProviderUtil.java index 6cb5dd08..0e56bb28 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/provider/ProviderUtil.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/provider/ProviderUtil.java @@ -91,6 +91,13 @@ class ProviderUtil { return params.get(FlexConsts.ENTITY); } + public static String getFieldName(Map params) { + return (String) params.get(FlexConsts.FIELD_NAME); + } + + public static Object getValue(Map params) { + return params.get(FlexConsts.VALUE); + } public static List getEntities(Map params) { return (List) params.get(FlexConsts.ENTITIES); diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/provider/RowSqlProvider.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/provider/RowSqlProvider.java index 31253a01..8c30cabf 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/provider/RowSqlProvider.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/provider/RowSqlProvider.java @@ -82,10 +82,10 @@ public class RowSqlProvider { throw FlexExceptions.wrap("rows can not be null or empty."); } - //让所有 row 的列顺序和值的数量与第条数据保持一致 - //这个必须 new 一个 LinkedHashSet,因为 keepModifyAttrs 会清除 row 所有的 modifyAttrs + // 让所有 row 的列顺序和值的数量与第条数据保持一致 + // 这个必须 new 一个 LinkedHashSet,因为 keepModifyAttrs 会清除 row 所有的 modifyAttrs Set modifyAttrs = new LinkedHashSet<>(rows.get(0).obtainModifyAttrs()); - rows.forEach(row -> RowCPI.keepModifyAttrs(row, modifyAttrs)); + rows.forEach(row -> row.prepareAttrs(modifyAttrs)); Object[] values = new Object[]{}; @@ -245,6 +245,29 @@ public class RowSqlProvider { return DialectFactory.getDialect().forUpdateEntity(tableInfo, entity, false); } + /** + * 执行类似 update table set field=field+1 where ... 的场景 + * + * @param params + * @return sql + * @see RowMapper#updateNumberAddByQuery(String, String, Number, QueryWrapper) + */ + public static String updateNumberAddByQuery(Map params) { + + QueryWrapper queryWrapper = ProviderUtil.getQueryWrapper(params); + + String tableName = ProviderUtil.getTableName(params); + String fieldName = ProviderUtil.getFieldName(params); + Number value = (Number) ProviderUtil.getValue(params); + + + Object[] queryParams = CPI.getValueArray(queryWrapper); + + ProviderUtil.setSqlArgs(params, queryParams); + + return DialectFactory.getDialect().forUpdateNumberAddByQuery(tableName, fieldName, value, queryWrapper); + } + /** * selectOneById 的 sql 构建 diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/ArithmeticQueryColumn.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/ArithmeticQueryColumn.java new file mode 100644 index 00000000..7d160fed --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/ArithmeticQueryColumn.java @@ -0,0 +1,133 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.core.query; + +import com.mybatisflex.core.dialect.IDialect; +import com.mybatisflex.core.util.StringUtil; + +import java.util.ArrayList; +import java.util.List; + +public class ArithmeticQueryColumn extends QueryColumn { + + private List arithmeticInfos; + + public ArithmeticQueryColumn(Object value) { + arithmeticInfos = new ArrayList<>(); + arithmeticInfos.add(new ArithmeticInfo(value)); + } + + @Override + public QueryColumn add(QueryColumn queryColumn) { + arithmeticInfos.add(new ArithmeticInfo(" + ", queryColumn)); + return this; + } + + @Override + public QueryColumn add(Number number) { + arithmeticInfos.add(new ArithmeticInfo(" + ", number)); + return this; + } + + @Override + public QueryColumn subtract(QueryColumn queryColumn) { + arithmeticInfos.add(new ArithmeticInfo(" - ", queryColumn)); + return this; + } + + @Override + public QueryColumn subtract(Number number) { + arithmeticInfos.add(new ArithmeticInfo(" - ", number)); + return this; + } + + @Override + public QueryColumn multiply(QueryColumn queryColumn) { + arithmeticInfos.add(new ArithmeticInfo(" * ", queryColumn)); + return this; + } + + @Override + public QueryColumn multiply(Number number) { + arithmeticInfos.add(new ArithmeticInfo(" * ", number)); + return this; + } + + @Override + public QueryColumn divide(QueryColumn queryColumn) { + arithmeticInfos.add(new ArithmeticInfo(" / ", queryColumn)); + return this; + } + + @Override + public QueryColumn divide(Number number) { + arithmeticInfos.add(new ArithmeticInfo(" / ", number)); + return this; + } + + @Override + public QueryColumn as(String alias) { + this.alias = alias; + return this; + } + + @Override + String toSelectSql(List queryTables, IDialect dialect) { + StringBuilder sql = new StringBuilder(); + for (int i = 0; i < arithmeticInfos.size(); i++) { + sql.append(arithmeticInfos.get(i).toSql(queryTables, dialect, i)); + } + if (StringUtil.isNotBlank(alias)) { + return "(" + sql + ") AS " + dialect.wrap(alias); + } + return sql.toString(); + } + + + @Override + String toConditionSql(List queryTables, IDialect dialect) { + StringBuilder sql = new StringBuilder(); + for (int i = 0; i < arithmeticInfos.size(); i++) { + sql.append(arithmeticInfos.get(i).toSql(queryTables, dialect, i)); + } + return "(" + sql + ")"; + } + + + static class ArithmeticInfo { + private String symbol; + private Object value; + + public ArithmeticInfo(Object value) { + this.value = value; + } + + public ArithmeticInfo(String symbol, Object value) { + this.symbol = symbol; + this.value = value; + } + + private String toSql(List queryTables, IDialect dialect, int index) { + String valueSql; + if (value instanceof QueryColumn) { + valueSql = ((QueryColumn) value).toConditionSql(queryTables, dialect); + } else { + valueSql = String.valueOf(value); + } + return index == 0 ? valueSql : symbol + valueSql; + } + } +} diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/FunctionQueryColumn.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/FunctionQueryColumn.java index d580fa2e..37507872 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/FunctionQueryColumn.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/FunctionQueryColumn.java @@ -60,7 +60,7 @@ public class FunctionQueryColumn extends QueryColumn implements HasParamsColumn @Override public Object[] getParamValues() { - if (column instanceof HasParamsColumn){ + if (column instanceof HasParamsColumn) { return ((HasParamsColumn) column).getParamValues(); } return WrapperUtil.NULL_PARA_ARRAY; @@ -69,7 +69,7 @@ public class FunctionQueryColumn extends QueryColumn implements HasParamsColumn @Override public String toSelectSql(List queryTables, IDialect dialect) { String sql = column.toSelectSql(queryTables, dialect); - return StringUtil.isBlank(sql) ? "" : fnName + "(" + sql + ")" + WrapperUtil.buildAsAlias(alias); + return StringUtil.isBlank(sql) ? "" : fnName + "(" + sql + ")" + WrapperUtil.buildAsAlias(alias, dialect); } @Override diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryColumn.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryColumn.java index 2d5f10b3..9bf82fa0 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryColumn.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryColumn.java @@ -224,7 +224,7 @@ public class QueryColumn implements Serializable { */ public QueryCondition in(Object... arrays) { //忽略 QueryWrapper.in("name", null) 的情况 - if (arrays == null || arrays.length == 0 || (arrays.length == 1 && arrays[0] == null)) { + if (arrays == null || arrays.length == 0 || (arrays.length == 1 && arrays[0] == null)) { return QueryCondition.createEmpty(); } return QueryCondition.create(this, QueryCondition.LOGIC_IN, arrays); @@ -262,7 +262,7 @@ public class QueryColumn implements Serializable { */ public QueryCondition notIn(Object... arrays) { //忽略 QueryWrapper.notIn("name", null) 的情况 - if (arrays == null || arrays.length == 0 || (arrays.length == 1 && arrays[0] == null)) { + if (arrays == null || arrays.length == 0 || (arrays.length == 1 && arrays[0] == null)) { return QueryCondition.createEmpty(); } return QueryCondition.create(this, QueryCondition.LOGIC_NOT_IN, arrays); @@ -324,6 +324,40 @@ public class QueryColumn implements Serializable { } + // 运算 加减乘除 + - * / + public QueryColumn add(QueryColumn queryColumn) { + return new ArithmeticQueryColumn(this).add(queryColumn); + } + + public QueryColumn add(Number number) { + return new ArithmeticQueryColumn(this).add(number); + } + + public QueryColumn subtract(QueryColumn queryColumn) { + return new ArithmeticQueryColumn(this).subtract(queryColumn); + } + + public QueryColumn subtract(Number number) { + return new ArithmeticQueryColumn(this).subtract(number); + } + + public QueryColumn multiply(QueryColumn queryColumn) { + return new ArithmeticQueryColumn(this).multiply(queryColumn); + } + + public QueryColumn multiply(Number number) { + return new ArithmeticQueryColumn(this).multiply(number); + } + + public QueryColumn divide(QueryColumn queryColumn) { + return new ArithmeticQueryColumn(this).divide(queryColumn); + } + + public QueryColumn divide(Number number) { + return new ArithmeticQueryColumn(this).divide(number); + } + + protected String wrap(IDialect dialect, String table, String column) { if (StringUtil.isNotBlank(table)) { return dialect.wrap(table) + "." + dialect.wrap(column); @@ -340,7 +374,7 @@ public class QueryColumn implements Serializable { String toSelectSql(List queryTables, IDialect dialect) { String tableName = WrapperUtil.getColumnTableName(queryTables, table); - return wrap(dialect, tableName, name) + WrapperUtil.buildAsAlias(dialect.wrap(alias)); + return wrap(dialect, tableName, name) + WrapperUtil.buildAsAlias(alias, dialect); } @Override diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryTable.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryTable.java index c8d14905..2268fcb1 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryTable.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryTable.java @@ -63,7 +63,7 @@ public class QueryTable implements Serializable { } public String toSql(IDialect dialect) { - return dialect.wrap(name) + WrapperUtil.buildAsAlias(dialect.wrap(alias)); + return dialect.wrap(name) + WrapperUtil.buildAsAlias(alias, dialect); } @Override diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/StringFunctionQueryColumn.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/StringFunctionQueryColumn.java index 8fb5cbd6..778eeba1 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/StringFunctionQueryColumn.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/StringFunctionQueryColumn.java @@ -30,7 +30,7 @@ public class StringFunctionQueryColumn extends QueryColumn { protected String fnName; protected List params; - public StringFunctionQueryColumn(String fnName, String ...params) { + public StringFunctionQueryColumn(String fnName, String... params) { SqlUtil.keepColumnSafely(fnName); this.fnName = fnName; this.params = Arrays.asList(params); @@ -56,13 +56,13 @@ public class StringFunctionQueryColumn extends QueryColumn { @Override public String toSelectSql(List queryTables, IDialect dialect) { - String sql = StringUtil.join(", ",params); - return StringUtil.isBlank(sql) ? "" : fnName + "(" + sql + ")" + WrapperUtil.buildAsAlias(alias); + String sql = StringUtil.join(", ", params); + return StringUtil.isBlank(sql) ? "" : fnName + "(" + sql + ")" + WrapperUtil.buildAsAlias(alias, dialect); } @Override String toConditionSql(List queryTables, IDialect dialect) { - String sql = StringUtil.join(", ",params); + String sql = StringUtil.join(", ", params); return StringUtil.isBlank(sql) ? "" : fnName + "(" + sql + ")"; } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/WrapperUtil.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/WrapperUtil.java index ae9d27ba..cd089694 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/WrapperUtil.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/WrapperUtil.java @@ -16,6 +16,7 @@ package com.mybatisflex.core.query; +import com.mybatisflex.core.dialect.IDialect; import com.mybatisflex.core.util.ClassUtil; import com.mybatisflex.core.util.CollectionUtil; import com.mybatisflex.core.util.EnumWrapper; @@ -30,8 +31,8 @@ import java.util.List; class WrapperUtil { - static String buildAsAlias(String alias) { - return StringUtil.isBlank(alias) ? "" : " AS " + alias; + static String buildAsAlias(String alias, IDialect dialect) { + return StringUtil.isBlank(alias) ? "" : " AS " + dialect.wrap(alias); } static final Object[] NULL_PARA_ARRAY = new Object[0]; diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/Db.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/Db.java index c228ddd1..41fa7f58 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/Db.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/Db.java @@ -286,6 +286,7 @@ public class Db { })).sum(); } + /** * 根据主键来批量更新数据 * @@ -297,6 +298,11 @@ public class Db { } + public static int updateNumberAddByQuery(String tableName, String fieldName, Number value, QueryWrapper queryWrapper){ + return invoker().updateNumberAddByQuery(tableName, fieldName, value, queryWrapper); + } + + /** * 批量执行工具方法 * diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/Row.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/Row.java index 514bf14d..d1d8248e 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/Row.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/Row.java @@ -316,8 +316,29 @@ public class Row extends LinkedHashMap implements ModifyAttrsRec return ret; } + public void prepareAttrsByKeySet(){ + this.modifyAttrs.clear(); + this.modifyAttrs.addAll(keySet()); - void keepModifyAttrs(Collection attrs) { + if (this.primaryKeys != null){ + for (RowKey primaryKey : primaryKeys) { + this.modifyAttrs.removeIf(s -> s.equalsIgnoreCase(primaryKey.getKeyColumn())); + } + } + } + + + public void prepareAttrsByKeySet(RowKey ... primaryKeys){ + this.modifyAttrs.clear(); + this.modifyAttrs.addAll(keySet()); + this.primaryKeys = primaryKeys; + + for (RowKey primaryKey : primaryKeys) { + this.modifyAttrs.removeIf(s -> s.equalsIgnoreCase(primaryKey.getKeyColumn())); + } + } + + public void prepareAttrs(Collection attrs) { if (attrs == null) { throw new NullPointerException("attrs is null."); } @@ -325,6 +346,17 @@ public class Row extends LinkedHashMap implements ModifyAttrsRec modifyAttrs.addAll(attrs); } + public RowKey[] getPrimaryKeys() { + return primaryKeys; + } + + public void setPrimaryKeys(RowKey... primaryKeys) { + this.primaryKeys = primaryKeys; + for (RowKey primaryKey : primaryKeys) { + this.modifyAttrs.removeIf(s -> s.equalsIgnoreCase(primaryKey.getKeyColumn())); + } + } + /** * 获取修改的值,值需要保持顺序,返回的内容不包含主键的值 */ diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowCPI.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowCPI.java index 5001747c..5ab652d4 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowCPI.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowCPI.java @@ -15,17 +15,11 @@ */ package com.mybatisflex.core.row; -import java.util.Collection; - /** * cross package invoker */ public class RowCPI { - public static void keepModifyAttrs(Row row, Collection attrs) { - row.keepModifyAttrs(attrs); - } - public static Object[] obtainModifyValues(Row row) { return row.obtainModifyValues(); } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowKey.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowKey.java index 21b01fca..ad6b7f94 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowKey.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowKey.java @@ -16,6 +16,7 @@ package com.mybatisflex.core.row; import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.core.keygen.KeyGenerators; import com.mybatisflex.core.util.SqlUtil; /** @@ -26,12 +27,22 @@ public class RowKey { /** * 自增 ID */ - public static final RowKey ID_AUTO = RowKey.of("id", KeyType.Auto, null, false); + public static final RowKey AUTO = RowKey.of("id", KeyType.Auto, null, false); /** * UUID 的 ID */ - public static final RowKey ID_UUID = RowKey.of("id", KeyType.Generator, "uuid", true); + public static final RowKey UUID = RowKey.of("id", KeyType.Generator, KeyGenerators.uuid, true); + + /** + * flexId + */ + public static final RowKey FLEX_ID = RowKey.of("id", KeyType.Generator, KeyGenerators.flexId, true); + + /** + * snowFlakeId + */ + public static final RowKey SNOW_FLAKE_ID = RowKey.of("id", KeyType.Generator, KeyGenerators.snowFlakeId, true); public static RowKey of(String keyColumn) { diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowMapper.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowMapper.java index ea85985f..4f69b538 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowMapper.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowMapper.java @@ -198,6 +198,20 @@ public interface RowMapper { @UpdateProvider(value = RowSqlProvider.class, method = "updateEntity") int updateEntity(@Param(FlexConsts.ENTITY) Object entity); + + /** + * 执行类似 update table set field=field+1 where ... 的场景 + * + * @param fieldName 字段名 + * @param value 值( >=0 加,小于 0 减) + * @param queryWrapper 条件 + * @see RowSqlProvider#updateNumberAddByQuery(Map) + */ + @UpdateProvider(type = RowSqlProvider.class, method = "updateNumberAddByQuery") + int updateNumberAddByQuery(@Param(FlexConsts.TABLE_NAME) String tableName, @Param(FlexConsts.FIELD_NAME) String fieldName + , @Param(FlexConsts.VALUE) Number value, @Param(FlexConsts.QUERY) QueryWrapper queryWrapper); + + ///////select ///// /** diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowMapperInvoker.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowMapperInvoker.java index 982fb710..472d9a7d 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowMapperInvoker.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowMapperInvoker.java @@ -185,4 +185,7 @@ public class RowMapperInvoker { } + public int updateNumberAddByQuery(String tableName, String fieldName, Number value, QueryWrapper queryWrapper) { + return execute(mapper -> mapper.updateNumberAddByQuery(tableName, fieldName, value, queryWrapper)); + } } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowUtil.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowUtil.java index ec9a3bfb..0733acae 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowUtil.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/row/RowUtil.java @@ -133,6 +133,9 @@ public class RowUtil { public static void printPretty(Row row) { + if (row == null) { + return; + } printPretty(Collections.singletonList(row)); } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/TableInfo.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/TableInfo.java index 52ddf99d..65617acf 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/TableInfo.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/TableInfo.java @@ -266,6 +266,10 @@ public class TableInfo { return columnInfoList; } + public String getColumnByProperty(String property) { + return propertyColumnMapping.get(property); + } + void setColumnInfoList(List columnInfoList) { this.columnInfoList = columnInfoList; diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/ClassUtil.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/ClassUtil.java index 33c9619a..1c8ead73 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/ClassUtil.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/ClassUtil.java @@ -67,7 +67,7 @@ public class ClassUtil { } - public static Class wrap(Class clazz) { + public static Class getWrapType(Class clazz) { if (clazz == null || !clazz.isPrimitive()) { return clazz; } @@ -181,17 +181,23 @@ public class ClassUtil { public static List getAllFields(Class cl) { List fields = new ArrayList<>(); - doGetFields(cl, fields, null); + doGetFields(cl, fields, null, false); return fields; } public static List getAllFields(Class cl, Predicate predicate) { List fields = new ArrayList<>(); - doGetFields(cl, fields, predicate); + doGetFields(cl, fields, predicate, false); return fields; } - private static void doGetFields(Class cl, List fields, Predicate predicate) { + public static Field getFirstField(Class cl, Predicate predicate) { + List fields = new ArrayList<>(); + doGetFields(cl, fields, predicate, true); + return fields.isEmpty() ? null : fields.get(0); + } + + private static void doGetFields(Class cl, List fields, Predicate predicate, boolean firstOnly) { if (cl == null || cl == Object.class) { return; } @@ -200,26 +206,39 @@ public class ClassUtil { for (Field declaredField : declaredFields) { if (predicate == null || predicate.test(declaredField)) { fields.add(declaredField); + if (firstOnly) { + break; + } } } - doGetFields(cl.getSuperclass(), fields, predicate); + if (firstOnly && !fields.isEmpty()) { + return; + } + + doGetFields(cl.getSuperclass(), fields, predicate, firstOnly); } public static List getAllMethods(Class cl) { List methods = new ArrayList<>(); - doGetMethods(cl, methods, null); + doGetMethods(cl, methods, null, false); return methods; } public static List getAllMethods(Class cl, Predicate predicate) { List methods = new ArrayList<>(); - doGetMethods(cl, methods, predicate); + doGetMethods(cl, methods, predicate, false); return methods; } + public static Method getFirstMethod(Class cl, Predicate predicate) { + List methods = new ArrayList<>(); + doGetMethods(cl, methods, predicate, true); + return methods.isEmpty() ? null : methods.get(0); + } - private static void doGetMethods(Class cl, List methods, Predicate predicate) { + + private static void doGetMethods(Class cl, List methods, Predicate predicate, boolean firstOnly) { if (cl == null || cl == Object.class) { return; } @@ -228,10 +247,17 @@ public class ClassUtil { for (Method method : declaredMethods) { if (predicate == null || predicate.test(method)) { methods.add(method); + if (firstOnly) { + break; + } } } - doGetMethods(cl.getSuperclass(), methods, predicate); + if (firstOnly && !methods.isEmpty()) { + return; + } + + doGetMethods(cl.getSuperclass(), methods, predicate, firstOnly); } private static Class getJdkProxySuperClass(Class clazz) { diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/ConvertUtil.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/ConvertUtil.java index 61147aeb..1e0ecfa1 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/ConvertUtil.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/ConvertUtil.java @@ -94,7 +94,7 @@ public class ConvertUtil { } else if (targetClass.isEnum()) { EnumWrapper enumWrapper = EnumWrapper.of(targetClass); if (enumWrapper.hasEnumValueAnnotation()) { - return enumWrapper.toEnum(value); + return enumWrapper.getEnum(value); } else if (value instanceof String) { return Enum.valueOf(targetClass, value.toString()); } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/EnumWrapper.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/EnumWrapper.java index 75522b7e..58b0931e 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/EnumWrapper.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/EnumWrapper.java @@ -22,7 +22,6 @@ import org.apache.ibatis.util.MapUtil; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -30,13 +29,13 @@ public class EnumWrapper> { private static final Map cache = new ConcurrentHashMap<>(); - private Class enumClass; + private boolean hasEnumValueAnnotation = false; - private Class enumPropertyType; + private Class enumClass; private E[] enums; private Field property; - private Method getter; - private boolean hasEnumValueAnnotation = false; + private Class propertyType; + private Method getterMethod; public static > EnumWrapper of(Class enumClass) { return MapUtil.computeIfAbsent(cache, enumClass, EnumWrapper::new); @@ -44,32 +43,31 @@ public class EnumWrapper> { public EnumWrapper(Class enumClass) { this.enumClass = enumClass; + this.enums = enumClass.getEnumConstants(); - List allFields = ClassUtil.getAllFields(enumClass, field -> field.getAnnotation(EnumValue.class) != null); - if (!allFields.isEmpty()) { + Field enumValueField = ClassUtil.getFirstField(enumClass, field -> field.getAnnotation(EnumValue.class) != null); + if (enumValueField != null) { hasEnumValueAnnotation = true; } if (hasEnumValueAnnotation) { - Field field = allFields.get(0); + String getterMethodName = "get" + StringUtil.firstCharToUpperCase(enumValueField.getName()); - String fieldGetterName = "get" + StringUtil.firstCharToUpperCase(field.getName()); - List allMethods = ClassUtil.getAllMethods(enumClass, method -> { + Method getter = ClassUtil.getFirstMethod(enumClass, method -> { String methodName = method.getName(); - return methodName.equals(fieldGetterName); + return methodName.equals(getterMethodName) && Modifier.isPublic(method.getModifiers()); }); - enumPropertyType = ClassUtil.wrap(field.getType()); - enums = enumClass.getEnumConstants(); + propertyType = ClassUtil.getWrapType(enumValueField.getType()); - if (allMethods.isEmpty()) { - if (Modifier.isPublic(field.getModifiers())) { - property = field; + if (getter == null) { + if (Modifier.isPublic(enumValueField.getModifiers())) { + property = enumValueField; } else { - throw new IllegalStateException("Can not find \"" + fieldGetterName + "()\" method in enum: " + enumClass.getName()); + throw new IllegalStateException("Can not find method \"" + getterMethodName + "()\" in enum: " + enumClass.getName()); } } else { - getter = allMethods.get(0); + this.getterMethod = getter; } } } @@ -77,16 +75,14 @@ public class EnumWrapper> { public Object getEnumValue(E object) { try { - return getter != null - ? getter.invoke(object) - : property.get(object); + return getterMethod != null ? getterMethod.invoke(object) : property.get(object); } catch (Exception e) { throw FlexExceptions.wrap(e); } } - public E toEnum(Object value) { + public E getEnum(Object value) { for (E e : enums) { if (value.equals(getEnumValue(e))) { return e; @@ -95,12 +91,12 @@ public class EnumWrapper> { return null; } - public Class getEnumClass() { - return enumClass; + public boolean hasEnumValueAnnotation() { + return hasEnumValueAnnotation; } - public Class getEnumPropertyType() { - return enumPropertyType; + public Class getEnumClass() { + return enumClass; } public E[] getEnums() { @@ -111,11 +107,11 @@ public class EnumWrapper> { return property; } - public Method getGetter() { - return getter; + public Class getPropertyType() { + return propertyType; } - public boolean hasEnumValueAnnotation() { - return hasEnumValueAnnotation; + public Method getGetterMethod() { + return getterMethod; } } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/FieldWrapper.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/FieldWrapper.java new file mode 100644 index 00000000..59dfc80f --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/FieldWrapper.java @@ -0,0 +1,107 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.core.util; + +import java.lang.reflect.*; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class FieldWrapper { + + public static Map, Map> cache = new ConcurrentHashMap<>(); + + private Class fieldType; + private Class mappingType; + private Method setterMethod; + + public static FieldWrapper of(Class clazz, String fieldName) { + Map wrapperMap = cache.get(clazz); + if (wrapperMap == null) { + synchronized (clazz) { + if (wrapperMap == null) { + wrapperMap = new ConcurrentHashMap<>(); + cache.put(clazz, wrapperMap); + } + } + } + + FieldWrapper fieldWrapper = wrapperMap.get(fieldName); + if (fieldWrapper == null) { + synchronized (clazz) { + fieldWrapper = wrapperMap.get(fieldName); + if (fieldWrapper == null) { + Field findField = ClassUtil.getFirstField(clazz, field -> field.getName().equals(fieldName)); + if (findField == null) { + throw new IllegalStateException("Can not find field \"" + fieldName + "\" in class: " + clazz); + } + + Method setter = ClassUtil.getFirstMethod(clazz, method -> + method.getParameterCount() == 1 + && Modifier.isPublic(method.getModifiers()) + && method.getName().equals("set" + StringUtil.firstCharToUpperCase(fieldName))); + + if (setter == null) { + throw new IllegalStateException("Can not find method \"set" + StringUtil.firstCharToUpperCase(fieldName) + "\" in class: " + clazz); + } + + fieldWrapper = new FieldWrapper(); + fieldWrapper.fieldType = findField.getType(); + fieldWrapper.mappingType = parseMappingType(findField); + fieldWrapper.setterMethod = setter; + + wrapperMap.put(fieldName, fieldWrapper); + } + } + } + + return fieldWrapper; + } + + private static Class parseMappingType(Field field) { + Class fieldType = field.getType(); + if (Collection.class.isAssignableFrom(fieldType)) { + Type genericType = field.getGenericType(); + if (genericType instanceof ParameterizedType) { + Type actualTypeArgument = ((ParameterizedType) genericType).getActualTypeArguments()[0]; + return (Class) actualTypeArgument; + } + } + + if (fieldType.isArray()) { + return field.getType().getComponentType(); + } + + return fieldType; + } + + + public void set(Object value, Object to) { + try { + setterMethod.invoke(to, value); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public Class getFieldType() { + return fieldType; + } + + public Class getMappingType() { + return mappingType; + } +} diff --git a/mybatis-flex-core/src/test/java/com/mybatisflex/coretest/query/ArithmeticQueryColumnTest.java b/mybatis-flex-core/src/test/java/com/mybatisflex/coretest/query/ArithmeticQueryColumnTest.java new file mode 100644 index 00000000..57e31e5e --- /dev/null +++ b/mybatis-flex-core/src/test/java/com/mybatisflex/coretest/query/ArithmeticQueryColumnTest.java @@ -0,0 +1,148 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.coretest.query; + +import com.mybatisflex.core.dialect.IDialect; +import com.mybatisflex.core.dialect.impl.CommonsDialectImpl; +import com.mybatisflex.core.query.QueryWrapper; +import org.junit.Assert; +import org.junit.Test; + +import static com.mybatisflex.core.query.QueryMethods.sum; +import static com.mybatisflex.coretest.table.AccountTableDef.ACCOUNT; + +public class ArithmeticQueryColumnTest { + + private static String toSql(QueryWrapper queryWrapper){ + IDialect dialect = new CommonsDialectImpl(); + return dialect.forSelectByQuery(queryWrapper); + } + + + @Test + public void testAdd() { + QueryWrapper query = new QueryWrapper() + .select(ACCOUNT.ID.add(100).as("x100")) + .from(ACCOUNT); + + String sql = toSql(query); + System.out.println(sql); + + Assert.assertEquals(sql,"SELECT (`id` + 100) AS `x100` FROM `tb_account`"); + } + + @Test + public void testAdd1() { + QueryWrapper query = new QueryWrapper() + .select(ACCOUNT.ID.add(100).add(200).add(300).as("x100")) + .from(ACCOUNT); + + String sql = toSql(query); + System.out.println(sql); + + Assert.assertEquals(sql,"SELECT (`id` + 100 + 200 + 300) AS `x100` FROM `tb_account`"); + } + + @Test + public void testAdd2() { + QueryWrapper query = new QueryWrapper() + .select(ACCOUNT.ID.add(ACCOUNT.ID).as("x100")) + .from(ACCOUNT); + + String sql = toSql(query); + System.out.println(sql); + + Assert.assertEquals(sql,"SELECT (`id` + `id`) AS `x100` FROM `tb_account`"); + } + + @Test + public void testAdd3() { + QueryWrapper query = new QueryWrapper() + .select(ACCOUNT.ID.add(ACCOUNT.ID.add(100)).as("x100")) + .from(ACCOUNT); + + String sql = toSql(query); + System.out.println(sql); + + Assert.assertEquals(sql,"SELECT (`id` + (`id` + 100)) AS `x100` FROM `tb_account`"); + } + + @Test + public void testAdd4() { + QueryWrapper query = new QueryWrapper() + .select(ACCOUNT.ID.add(ACCOUNT.ID.add(100)).multiply(100).as("x100")) + .from(ACCOUNT); + + String sql = toSql(query); + System.out.println(sql); + + Assert.assertEquals(sql,"SELECT (`id` + (`id` + 100) * 100) AS `x100` FROM `tb_account`"); + } + + @Test + public void testAdd5() { + QueryWrapper query = new QueryWrapper() + .select(sum(ACCOUNT.ID.multiply(ACCOUNT.AGE)).as("total_x")) + .from(ACCOUNT); + + String sql = toSql(query); + System.out.println(sql); + + Assert.assertEquals(sql,"SELECT SUM(`id` * `age`) AS `total_x` FROM `tb_account`"); + } + + @Test + public void testSubtract() { + QueryWrapper query = new QueryWrapper() + .select(ACCOUNT.ID.subtract(100).as("x100")) + .from(ACCOUNT); + + String sql = toSql(query); + System.out.println(sql); + + Assert.assertEquals(sql,"SELECT (`id` - 100) AS `x100` FROM `tb_account`"); + } + + + @Test + public void testMultiply() { + QueryWrapper query = new QueryWrapper() + .select(ACCOUNT.ID.multiply(100).as("x100")) + .from(ACCOUNT); + + String sql = toSql(query); + System.out.println(sql); + + Assert.assertEquals(sql,"SELECT (`id` * 100) AS `x100` FROM `tb_account`"); + } + + + @Test + public void testDivide() { + QueryWrapper query = new QueryWrapper() + .select(ACCOUNT.ID.divide(100).as("x100")) + .from(ACCOUNT); + + String sql = toSql(query); + System.out.println(sql); + + Assert.assertEquals(sql,"SELECT (`id` / 100) AS `x100` FROM `tb_account`"); + } + + + + +} diff --git a/mybatis-flex-processor/pom.xml b/mybatis-flex-processor/pom.xml index 2687b22c..803ddf6e 100644 --- a/mybatis-flex-processor/pom.xml +++ b/mybatis-flex-processor/pom.xml @@ -5,7 +5,7 @@ parent com.mybatis-flex - 1.3.0 + 1.3.2 4.0.0 @@ -20,7 +20,7 @@ com.mybatis-flex mybatis-flex-annotation - 1.3.0 + 1.3.2 diff --git a/mybatis-flex-solon-plugin/pom.xml b/mybatis-flex-solon-plugin/pom.xml index 9b8dfa14..bc0d237b 100644 --- a/mybatis-flex-solon-plugin/pom.xml +++ b/mybatis-flex-solon-plugin/pom.xml @@ -5,7 +5,7 @@ parent com.mybatis-flex - 1.3.0 + 1.3.2 4.0.0 @@ -15,7 +15,7 @@ com.mybatis-flex mybatis-flex-core - 1.3.0 + 1.3.2 diff --git a/mybatis-flex-spring-boot-starter/pom.xml b/mybatis-flex-spring-boot-starter/pom.xml index f0e6b2e8..cb4f7680 100644 --- a/mybatis-flex-spring-boot-starter/pom.xml +++ b/mybatis-flex-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ parent com.mybatis-flex - 1.3.0 + 1.3.2 4.0.0 @@ -21,7 +21,7 @@ com.mybatis-flex mybatis-flex-spring - 1.3.0 + 1.3.2 diff --git a/mybatis-flex-spring/pom.xml b/mybatis-flex-spring/pom.xml index 4e7a1eef..f6ad65fa 100644 --- a/mybatis-flex-spring/pom.xml +++ b/mybatis-flex-spring/pom.xml @@ -5,7 +5,7 @@ parent com.mybatis-flex - 1.3.0 + 1.3.2 4.0.0 @@ -20,7 +20,7 @@ com.mybatis-flex mybatis-flex-core - 1.3.0 + 1.3.2 diff --git a/mybatis-flex-test/mybatis-flex-native-test/pom.xml b/mybatis-flex-test/mybatis-flex-native-test/pom.xml index 16d7ea84..d195fb13 100644 --- a/mybatis-flex-test/mybatis-flex-native-test/pom.xml +++ b/mybatis-flex-test/mybatis-flex-native-test/pom.xml @@ -5,7 +5,7 @@ mybatis-flex-test com.mybatis-flex - 1.3.0 + 1.3.2 4.0.0 @@ -20,7 +20,7 @@ com.mybatis-flex mybatis-flex-core - 1.3.0 + 1.3.2 diff --git a/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/DbTestStarter.java b/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/DbTestStarter.java index b38459bf..02366b9e 100644 --- a/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/DbTestStarter.java +++ b/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/DbTestStarter.java @@ -16,10 +16,7 @@ package com.mybatisflex.test; import com.mybatisflex.core.MybatisFlexBootstrap; -import com.mybatisflex.core.row.BatchArgsSetter; -import com.mybatisflex.core.row.Db; -import com.mybatisflex.core.row.Row; -import com.mybatisflex.core.row.RowKey; +import com.mybatisflex.core.row.*; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; @@ -33,7 +30,7 @@ public class DbTestStarter { DataSource dataSource = new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .addScript("schema.sql") - .addScript("data.sql") +// .addScript("data.sql") .build(); MybatisFlexBootstrap.getInstance() @@ -41,15 +38,18 @@ public class DbTestStarter { .start(); Row row1 = Db.selectOneById("tb_account", "id", 1); - System.out.println(row1); + RowUtil.printPretty(row1); //查询全部 List rows = Db.selectAll("tb_account"); - System.out.println(rows); + RowUtil.printPretty(rows); //插入 1 条数据 - Row row = Row.ofKey(RowKey.ID_AUTO); + + Row row = Row.ofKey(RowKey.AUTO); +// Row row = new Row(); +// row.set("id", 3); row.set("user_name", "michael yang"); row.set("age", 18); row.set("birthday", new Date()); @@ -80,6 +80,26 @@ public class DbTestStarter { //再次查询全部数据 rows = Db.selectAll("tb_account"); - System.out.println(rows); + RowUtil.printPretty(rows); + +// for (Row row2 : rows) { +//// for (String s : row2.keySet()) { +//// if (!s.equalsIgnoreCase("id")) { +//// row2.set(s, row2.get(s)); +//// } +//// } +// rows.remove("id"); +// } + +// rows.forEach(row2 -> row2.setPrimaryKeys(RowKey.AUTO)); + rows.forEach(r -> { + r.prepareAttrsByKeySet(); + r.setPrimaryKeys(RowKey.AUTO); + }); + Db.insertBatch("tb_account", rows, 100); + + //再次查询全部数据 + rows = Db.selectAll("tb_account"); + RowUtil.printPretty(rows); } } diff --git a/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/EntityTestStarter.java b/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/EntityTestStarter.java index 317c04e5..adae7e68 100644 --- a/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/EntityTestStarter.java +++ b/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/EntityTestStarter.java @@ -71,15 +71,22 @@ public class EntityTestStarter { RowUtil.printPretty(rowList); -// List accounts1 = accountMapper.selectListByQuery(QueryWrapper.create() -// , accountFieldQueryBuilder -> accountFieldQueryBuilder -// .field(Account::getArticles) -// .type(Article.class) -// .queryWrapper(entity -> -// select().from(ARTICLE).where(ARTICLE.ACCOUNT_ID.eq(entity.getId())) -// ) -// ); -// System.out.println(accounts1); + accountMapper.updateNumberAddByQuery("age", 100, QueryWrapper.create().where(ACCOUNT.ID.eq(1))); + accountMapper.updateNumberAddByQuery(Account::getAge, -50, QueryWrapper.create().where(ACCOUNT.ID.eq(1))); + + + Db.updateNumberAddByQuery("tb_account", "age", 30, QueryWrapper.create().where(ACCOUNT.ID.eq(1))); + Db.updateNumberAddByQuery("tb_account", "age", -20, QueryWrapper.create().where(ACCOUNT.ID.eq(1))); + + + List accounts1 = accountMapper.selectListByQuery(QueryWrapper.create() + , accountFieldQueryBuilder -> accountFieldQueryBuilder + .field(Account::getArticles) + .queryWrapper(entity -> + select().from(ARTICLE).where(ARTICLE.ACCOUNT_ID.eq(entity.getId())) + ) + ); + System.out.println(accounts1); // MyAccountMapper myAccountMapper = bootstrap.getMapper(MyAccountMapper.class); diff --git a/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/RowTestStarter.java b/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/RowTestStarter.java index c7ec5f77..f748af46 100644 --- a/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/RowTestStarter.java +++ b/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/RowTestStarter.java @@ -75,7 +75,7 @@ public class RowTestStarter { List rowList = new ArrayList<>(); for (int i = 0; i < 10; i++) { - Row row = Row.ofKey(RowKey.ID_AUTO); + Row row = Row.ofKey(RowKey.AUTO); row.set(ACCOUNT.USER_NAME,"zhang" + i); row.set(ACCOUNT.AGE,18); // row.set(ACCOUNT.BIRTHDAY,new Date()); diff --git a/mybatis-flex-test/mybatis-flex-spring-boot-test/pom.xml b/mybatis-flex-test/mybatis-flex-spring-boot-test/pom.xml index d4ea3a9a..2616acfc 100644 --- a/mybatis-flex-test/mybatis-flex-spring-boot-test/pom.xml +++ b/mybatis-flex-test/mybatis-flex-spring-boot-test/pom.xml @@ -5,7 +5,7 @@ mybatis-flex-test com.mybatis-flex - 1.3.0 + 1.3.2 4.0.0 @@ -21,7 +21,7 @@ com.mybatis-flex mybatis-flex-spring-boot-starter - 1.3.0 + 1.3.2 diff --git a/mybatis-flex-test/mybatis-flex-spring-test/pom.xml b/mybatis-flex-test/mybatis-flex-spring-test/pom.xml index 325f5b48..a26f9fe1 100644 --- a/mybatis-flex-test/mybatis-flex-spring-test/pom.xml +++ b/mybatis-flex-test/mybatis-flex-spring-test/pom.xml @@ -5,7 +5,7 @@ mybatis-flex-test com.mybatis-flex - 1.3.0 + 1.3.2 4.0.0 @@ -20,13 +20,13 @@ com.mybatis-flex mybatis-flex-core - 1.3.0 + 1.3.2 com.mybatis-flex mybatis-flex-spring - 1.3.0 + 1.3.2 diff --git a/mybatis-flex-test/pom.xml b/mybatis-flex-test/pom.xml index 378b7960..a2090d8a 100644 --- a/mybatis-flex-test/pom.xml +++ b/mybatis-flex-test/pom.xml @@ -5,7 +5,7 @@ parent com.mybatis-flex - 1.3.0 + 1.3.2 4.0.0 @@ -59,7 +59,7 @@ com.mybatis-flex mybatis-flex-processor - 1.3.0 + 1.3.2 diff --git a/pom.xml b/pom.xml index 78d6417d..992467f0 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.mybatis-flex parent pom - 1.3.0 + 1.3.2 mybatis-flex https://mybatis-flex.com