diff --git a/README.md b/README.md index ed00fcfbaa4734c4718b9f815841f795b355e0d6..b0e807e8d80136ab0e75a69c29f8d22f3ff13ae2 100644 --- a/README.md +++ b/README.md @@ -7,157 +7,49 @@ stars


-🔥🔥🔥轻量的领域驱动的ORM框架,帮助开发者通过建模,快速构建具有可维护性、可拓展性的应用程序。 -### 👍推荐理由 +### 📚简介 -- **模型驱动** -- **NoSQL** -- **面向对象** -- **事件模式** -- **代码生成** +​ dorive是一个轻量的领域驱动式业务框架,它提供了诸多开箱即用的功能,旨在帮助开发者快速、便捷地在项目中应用领域驱动,并从中受益。 -### 🤼‍♂️设计模式对比 +​ 这些功能涵盖了依赖注入校验、依赖即用配置、实体定义与映射、级联查询与操作、实体多态、实体事件通知、复杂推导查询、ref关键字、复杂计数统计、表结构生成、数据库逆向生成、接口代码生成等,覆盖了大部分开发场景。 -| | UI驱动 | 领域驱动 | -| -------- | --------- | -------------- | -| 编码风格 | 面向过程 | ✅面向对象 | -| 上手难度 | ✅简单 | 中等 | -| 开发速度 | ✅快 | 中等 | -| 设计依据 | 原型 | ✅核心业务 | -| 交付周期 | ✅小、精确 | 一般以整体交付 | -| 技术依赖 | 数据库 | ✅无 | -| 耦合度 | 极高 | ✅低 | -| 可维护性 | 差 | ✅高 | -| 可复用性 | 差 | ✅高 | -| 可拓展性 | 差 | ✅高 | +### 🎁名称由来 -### 🤸面临的挑战 +​ dorive = domain + driven 或 do + driven ,是原公司项目沉淀后的开源库。“do”表明了一种态度,只有付诸行动,才能有所收获。 -- 业务知识的提炼与抽象 -- 面向对象编程 + 数据持久化(框架发力点) +### 🍺设计理念 + +​ dorive提供统一的api,帮助开发者从繁复的增删改查中解脱出来,从而把精力集中到业务逻辑开发中。理想状态下,开发者无需再编写sql语句,也将无惧于快速迭代导致的频繁改动。 ### 📊架构设计 ![avatar](https://gitee.com/digital-engine/dorive/raw/master/doc/img/framework.png) -### 🏄快速开始 +### 🛠️模块说明 + +| 模块 | 说明 | +| -------------------------- | ---------------------------------------------------- | +| dorive-inject | 实现了依赖注入校验 | +| dorive-env | 实现了依赖即用配置 | +| dorive-web | 提供了web开发时会用到的工具类 | +| dorive-proxy | 动态代理工具包 | +| dorive-api | 包含领域驱动实体定义规范 | +| dorive-core | 核心实现(实体定义与映射、级联查询与操作、实体多态) | +| dorive-event | 实现了实体事件通知 | +| dorive-query | 实现了复杂推导查询 | +| dorive-ref | 实现了ref关键字 | +| dorive-sql | 实现了复杂计数统计 | +| dorive-mybatis-plus | 提供基于mybatis-plus的实现 | +| dorive-spring-boot-starter | 依赖管理启动器 | + +### 📦安装 ```xml com.gitee.digital-engine dorive-spring-boot-starter - 3.4.3.3 + 3.4.3.4 ``` -### 🧡代码示例 - -以Saas化场景为例,为租户建模。 - -#### 定义实体 - -```java -/** - * 租户聚合 - * name 实体名称 - * source 数据来源 - */ -@Data -@Entity(name = "tenant", source = SysTenantMapper.class) -public class Tenant { - - private Integer id; - private String tenantCode; - - /** - * 部门实体 - * field 字段名称 - * bindExp 绑定字段表达式 - */ - @Entity - @Binding(field = "tenantId", bindExp = "./id") - private List departments; - - /** - * 用户实体 - * property 绑定对象内部属性 - */ - @Entity - @Binding(field = "deptId", bindExp = "./departments", property = "id") - private List users; -} -``` - -#### 定义仓储 - -```java -@RootRepository -@QueryScan("xxx.xxx.xxx.xxx.xxx.query") -public class TenantRepository extends MybatisPlusRepository { -} -``` - -#### 定义查询对象 - -```java -package xxx.xxx.xxx.xxx.xxx.query; -@Data -@Example -public class TenantQuery { - @Criterion(belongTo = "user") - private String userCode; - private String sortBy; - private String order; - private Integer page; - private Integer limit; -} -``` - -#### 新增数据 - -```java -// 开发者无需设置实体之间的关联id -Tenant tenant = new Tenant(); -tenant.setTenantCode("tenant"); - -Department department = new Department(); -department.setDeptCode("dept"); -tenant.setDepartments(Collections.singletonList(department)); - -User user = new User(); -user.setUserCode("user"); -tenant.setUser(Collections.singletonList(user)); - -int count = tenantRepository.insert(Selector.ALL, tenant); -``` - -#### 查询数据 - -```java -// 开发者无需编写复杂的查询SQL -TenantQuery tenantQuery = new TenantQuery(); -tenantQuery.setUserCode("000001"); -tenantQuery.setSortBy("id"); -tenantQuery.setOrder("desc"); -tenantQuery.setPage(1); -tenantQuery.setLimit(10); - -List tenants = tenantRepository.selectByQuery(Selector.ALL, tenantQuery); -``` - -#### 更新数据 - -```java -Tenant tenant = tenantRepository.selectByPrimaryKey(Selector.ROOT, 1); -tenant.setTenantCode("tenant1"); - -int count = tenantRepository.update(Selector.ROOT, tenant); -``` - -#### 删除数据 - -```java -// 开发者通过聚合对象的id,即可删除所有数据 -int count = tenantRepository.deleteByPrimaryKey(Selector.ALL, 1); -``` diff --git a/doc/img/framework.png b/doc/img/framework.png index b8a0004ef5d4b4f78643cdae3bfecc3a7f8f0de8..66c6ed825c8788c12076c98b3e7b929d31cc8010 100644 Binary files a/doc/img/framework.png and b/doc/img/framework.png differ diff --git a/dorive-api/pom.xml b/dorive-api/pom.xml index ca9f7c8ae970fd51b8f405d975957780d82d2dc4..9755bd70284098d4721dd4304fbbc95645c6d5ac 100644 --- a/dorive-api/pom.xml +++ b/dorive-api/pom.xml @@ -6,7 +6,7 @@ com.gitee.digital-engine dorive - 3.4.3.3 + 3.4.3.4 dorive-api diff --git a/dorive-api/src/main/java/com/gitee/dorive/api/annotation/Aggregate.java b/dorive-api/src/main/java/com/gitee/dorive/api/annotation/Aggregate.java index f293f608d8c31493f299997dced7428371eab033..3e513f3ffeb4a5d87131cd72ad627ccd17a63c18 100644 --- a/dorive-api/src/main/java/com/gitee/dorive/api/annotation/Aggregate.java +++ b/dorive-api/src/main/java/com/gitee/dorive/api/annotation/Aggregate.java @@ -26,31 +26,81 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * 聚合注解
+ * 作用:声明字段的类型为聚合
+ * + *

+ * 解释:聚合一般指多个实体组装后的集合
+ *

+ * + *

+ * 使用说明:
+ * 1、在使用上,聚合注解基本等效于实体注解
+ * 2、在不指定仓储的情况下,框架会自动为实体匹配仓储
+ *

+ * + *

+ * 例如:
+ *

{@code
+ * @Aggregate
+ * private List users;
+ *
+ * 等效于:
+ *
+ * @Entity(repository = UserRepository.class)
+ * private List users;
+ * }
+ *

+ * + * @author tao.chen + */ @Entity @Inherited @Documented +@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.TYPE, ElementType.FIELD}) public @interface Aggregate { + /** + * @see Entity + */ @AliasFor(annotation = Entity.class) String name() default ""; + /** + * @see Entity + */ @AliasFor(annotation = Entity.class) Class source() default Object.class; + /** + * @see Entity + */ @AliasFor(annotation = Entity.class) Class factory() default Object.class; + /** + * @see Entity + */ @AliasFor(annotation = Entity.class) Class repository() default Object.class; + /** + * @see Entity + */ @AliasFor(annotation = Entity.class) int priority() default 0; + /** + * @see Entity + */ @AliasFor(annotation = Entity.class) String sortBy() default ""; + /** + * @see Entity + */ @AliasFor(annotation = Entity.class) String order() default ""; diff --git a/dorive-api/src/main/java/com/gitee/dorive/api/annotation/Binding.java b/dorive-api/src/main/java/com/gitee/dorive/api/annotation/Binding.java index 1af274bea2755cbc1c5f04bd0e54832fa555eb04..ecf6f07b2bd4f0da8c7ce9575e4c2d0ca6e9f501 100644 --- a/dorive-api/src/main/java/com/gitee/dorive/api/annotation/Binding.java +++ b/dorive-api/src/main/java/com/gitee/dorive/api/annotation/Binding.java @@ -19,19 +19,83 @@ package com.gitee.dorive.api.annotation; import java.lang.annotation.*; +/** + * 绑定注解
+ * 作用:声明实体字段之间的绑定关系
+ * + *

+ * 绑定类型有三种,分别是:
+ * 1、强绑定(两个字段强相关时使用)
+ *

{@code
+ * @Binding(field = "field", bindExp = "./field")
+ * }
+ * 2、弱绑定(字段与上下文相关时使用)
+ *
{@code
+ * @Binding(field = "field", processExp = "#ctx['field']")
+ * }
+ * 3、值绑定(字段与字面值相关时使用)
+ *
{@code
+ * @Binding(value = "0", bindExp = "./field")
+ * }
+ *

+ * + *

+ * 当绑定的字段,还需要再进行深度解析时,请使用以下配置方式:
+ *

{@code
+ * @Binding(field = "field", bindExp = "./list", processExp = "#val.![field]", bindField = "field")
+ * }
+ *

+ * + * @author tao.chen + */ @Inherited @Documented +@Target(ElementType.FIELD) @Repeatable(Bindings.class) @Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.TYPE, ElementType.FIELD}) public @interface Binding { - String field(); + /** + * 字段名称
+ * 作用:声明当前实体绑定的字段
+ */ + String field() default ""; + + /** + * 字面值
+ * 作用:值绑定时使用
+ */ + String value() default ""; - String bindExp(); + /** + * 绑定表达式
+ * 作用:声明上下文绑定的字段
+ * 说明:
+ * 1、./field是以当前实体为参考系的相对路径
+ * 2、/field是以聚合根为参考系的绝对路径
+ */ + String bindExp() default ""; - String property() default ""; + /** + * 加工表达式
+ * 作用:从上下文中获取信息,或加工绑定的字段
+ * 说明:表达式书写请参考SpEL
+ * + * @see org.springframework.expression + */ + String processExp() default ""; + /** + * 指定加工器
+ * 作用:声明字段加工的具体实现
+ * 说明:如果加工表达式不为空,默认实现为SpELProcessor
+ */ Class processor() default Object.class; + /** + * 绑定的字段名称
+ * 作用:显式声明绑定的字段名称
+ */ + String bindField() default ""; + } diff --git a/dorive-api/src/main/java/com/gitee/dorive/api/annotation/Bindings.java b/dorive-api/src/main/java/com/gitee/dorive/api/annotation/Bindings.java index 8e7d9394ed8668236117924b9d7100bfb33765a6..77f285447f8da1376beec5a23827e9a8e2f29463 100644 --- a/dorive-api/src/main/java/com/gitee/dorive/api/annotation/Bindings.java +++ b/dorive-api/src/main/java/com/gitee/dorive/api/annotation/Bindings.java @@ -21,10 +21,8 @@ import java.lang.annotation.*; @Inherited @Documented +@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.TYPE, ElementType.FIELD}) public @interface Bindings { - Binding[] value(); - } diff --git a/dorive-api/src/main/java/com/gitee/dorive/api/annotation/Entity.java b/dorive-api/src/main/java/com/gitee/dorive/api/annotation/Entity.java index 64073c48afe1afa08fce03aa94752b58034128f2..411f5ea068ca7cf1896ffaa2099cc5bb05d59341 100644 --- a/dorive-api/src/main/java/com/gitee/dorive/api/annotation/Entity.java +++ b/dorive-api/src/main/java/com/gitee/dorive/api/annotation/Entity.java @@ -19,24 +19,142 @@ package com.gitee.dorive.api.annotation; import java.lang.annotation.*; +/** + * 实体注解
+ * 作用:声明一个类或字段的类型为实体
+ * + *

+ * 解释:实体是一种数据结构的具体表现形式,具有以下特征:
+ * 1、描述了实体和其他实体之间的关系。(一对一、一对多、多对多)
+ * 2、描述了实体字段和持久化数据的映射关系。
+ * 3、包含方法,可通过方法重写进行拓展。
+ *

+ * + *

+ * 使用说明:
+ * 1、在类上声明的实体注解,代表该实体的默认配置
+ *

{@code
+ * @Entity(name = "user", source = UserMapper.class)
+ * public class User {
+ *     ......
+ * }
+ * }
+ * 2、在字段上声明的实体注解,代表在当前实体内的配置
+ *
{@code
+ * public class Dept {
+ *     @Entity(name = "user1", source = UserMapper1.class)
+ *     private List users;
+ * }
+ * }
+ * 3、一般情况下,使用默认配置即可
+ *
{@code
+ * public class Dept {
+ *     @Entity
+ *     private List users;
+ * }
+ * }
+ *

+ * + *

+ * 补充说明:如果想要在关联查询时,查询实体内部的其他实体,请指定仓储
+ *

{@code
+ * @Entity(name = "user", source = UserMapper.class)
+ * public class User {
+ *     @Entity
+ *     private List roles;
+ * }
+ *
+ * @Entity(name = "dept", source = DeptMapper.class)
+ * public class Dept {
+ *     @Entity(repository = UserRepository.class)
+ *     private List users;
+ * }
+ * }
+ *

+ * + * @author tao.chen + */ @Inherited @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.FIELD}) public @interface Entity { + /** + * 实体名称
+ * 作用:可作为选取器的匹配条件
+ */ String name() default ""; + /** + * 数据来源
+ * 作用:声明持久化数据操作的具体实现
+ * 注意:目前仅支持mybatis-plus框架中BaseMapper的子类
+ */ Class source() default Object.class; + /** + * 实体工厂
+ * 作用:声明实体构造的具体实现
+ * 解释:实体工厂通过映射关系,实现了实体与持久化数据之间的相互转换
+ * 多态的实现方式:
+ * 1、假设实体为User,子类分别为User1、User2
+ * 2、新建UserFactory继承于DefaultEntityFactory,并重写reconstitute方法
+ *
{@code
+     * @Override
+     * public Object reconstitute(Context context, Object persistent) {
+     *     User user = (User) super.reconstitute(context, persistent);
+     *     if (user.getType() == 1) {
+     *         return BeanUtil.copyProperties(user, User1.class);
+     *
+     *     } else if (user.getType() == 2) {
+     *         return BeanUtil.copyProperties(user, User2.class);
+     *     }
+     *     return user;
+     * }
+     * }
+ * 3、修改User的@Entity注解,指定实体工厂为UserFactory
+ *
{@code
+     * @Entity(......, factory = UserFactory.class)
+     * public class User {
+     *     ......
+     * }
+     * }
+ * 4、在UserRepository中引入子类的仓储
+ *
{@code
+     * public class UserRepository extends MybatisPlusRepository {
+     *     private final User1Repository user1Repository;
+     *     private final User2Repository user2Repository;
+     * }
+     * }
+ */ Class factory() default Object.class; + /** + * 指定仓储
+ * 作用:指定一个特定的仓储,代替source操作数据
+ * 注意:不能和source与factory同时使用,优先级更高
+ */ Class repository() default Object.class; + /** + * 操作优先级
+ * 作用:可以改变插入、更新、删除的操作顺序
+ */ int priority() default 0; + /** + * 默认排序字段
+ * 作用:关联查询时,默认的排序字段
+ */ String sortBy() default ""; + /** + * 默认排序方式
+ * 作用:关联查询时,默认的排序方式
+ * + * @see com.gitee.dorive.api.constant.Order + */ String order() default ""; } diff --git a/dorive-api/src/main/java/com/gitee/dorive/api/annotation/Field.java b/dorive-api/src/main/java/com/gitee/dorive/api/annotation/Field.java index 1cf133973d39448fb8541751c98f80e5908d8f39..6de4af0c45c166f8160a1391feae3ebcf7bd2629 100644 --- a/dorive-api/src/main/java/com/gitee/dorive/api/annotation/Field.java +++ b/dorive-api/src/main/java/com/gitee/dorive/api/annotation/Field.java @@ -35,8 +35,8 @@ public @interface Field { @AliasFor("value") String alias() default ""; - Class converter() default Object.class; - String mapExp() default ""; + Class converter() default Object.class; + } diff --git a/dorive-api/src/main/java/com/gitee/dorive/api/entity/def/BindingDef.java b/dorive-api/src/main/java/com/gitee/dorive/api/entity/def/BindingDef.java index 4d8070efa9f8d90edfc79c03fed119b931a840ef..6538b8f856ce91581fc4041fc125ec962bf9ce84 100644 --- a/dorive-api/src/main/java/com/gitee/dorive/api/entity/def/BindingDef.java +++ b/dorive-api/src/main/java/com/gitee/dorive/api/entity/def/BindingDef.java @@ -37,9 +37,11 @@ import java.util.Set; public class BindingDef { private String field; + private String value; private String bindExp; - private String property; + private String processExp; private Class processor; + private String bindField; public static List fromElement(AnnotatedElement element) { Set bindingAnnotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(element, Binding.class); diff --git a/dorive-api/src/main/java/com/gitee/dorive/api/entity/def/FieldDef.java b/dorive-api/src/main/java/com/gitee/dorive/api/entity/def/FieldDef.java index b4b90f8ad5584297ccee86af74c670de8a2a8428..b7f22b4430f649c3de0e04e65c73ca73886439e8 100644 --- a/dorive-api/src/main/java/com/gitee/dorive/api/entity/def/FieldDef.java +++ b/dorive-api/src/main/java/com/gitee/dorive/api/entity/def/FieldDef.java @@ -34,8 +34,8 @@ public class FieldDef { private boolean isId; private String alias; - private Class converter; private String mapExp; + private Class converter; public static FieldDef fromElement(AnnotatedElement element) { Map attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(element, Field.class); diff --git a/dorive-core/pom.xml b/dorive-core/pom.xml index 23a98eb08aea157168fcfbb8d7eee9a43bc8c09f..83b2940026bed4f9ec665be29c9d4d5ee6be4a33 100644 --- a/dorive-core/pom.xml +++ b/dorive-core/pom.xml @@ -6,7 +6,7 @@ com.gitee.digital-engine dorive - 3.4.3.3 + 3.4.3.4 dorive-core diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/api/binder/Binder.java b/dorive-core/src/main/java/com/gitee/dorive/core/api/binder/Binder.java index 116e6fcd0968d94e0651932f79e14b436b5e8e36..02ac3f006065d10757ff97b53a82059ef23b6b61 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/api/binder/Binder.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/api/binder/Binder.java @@ -17,17 +17,18 @@ package com.gitee.dorive.core.api.binder; -import com.gitee.dorive.api.entity.def.BindingDef; import com.gitee.dorive.core.api.context.Context; -public interface Binder { +public interface Binder extends Processor { - BindingDef getBindingDef(); + String getFieldName(); Object getFieldValue(Context context, Object entity); void setFieldValue(Context context, Object entity, Object property); + String getBoundName(); + Object getBoundValue(Context context, Object rootEntity); void setBoundValue(Context context, Object rootEntity, Object property); diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/api/context/Matcher.java b/dorive-core/src/main/java/com/gitee/dorive/core/api/context/Matcher.java index d71bd7c43bad0ac5aa74ec8802ca1635697aa4d9..c76dcdf8315dc19a3fdaee50660ad5387b9530ca 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/api/context/Matcher.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/api/context/Matcher.java @@ -19,6 +19,6 @@ package com.gitee.dorive.core.api.context; public interface Matcher { - boolean matches(Context context); + boolean matches(Options options); } diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/entity/context/AbstractContext.java b/dorive-core/src/main/java/com/gitee/dorive/core/entity/context/AbstractContext.java index d011dcab34e5fe0ba813c4e079f4d2d1eee15cfd..82f782a48ebb0c019070d5a25a132284cfe22a5a 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/entity/context/AbstractContext.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/entity/context/AbstractContext.java @@ -20,7 +20,6 @@ package com.gitee.dorive.core.entity.context; import com.gitee.dorive.core.api.context.Context; import com.gitee.dorive.core.api.context.Options; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import java.util.LinkedHashMap; @@ -28,19 +27,23 @@ import java.util.Map; @Getter @Setter -@NoArgsConstructor -public abstract class AbstractContext implements Context { +public abstract class AbstractContext extends LinkedHashMap implements Context { protected Map, Object> options = new LinkedHashMap<>(4); - protected Map attachments = new LinkedHashMap<>(8); + + public AbstractContext() { + super(8); + } public AbstractContext(Options options) { + this(); this.options.putAll(options.getOptions()); } public AbstractContext(Context anotherContext) { + this(); this.options.putAll(anotherContext.getOptions()); - this.attachments.putAll(anotherContext.getAttachments()); + putAll(anotherContext.getAttachments()); } @Override @@ -58,19 +61,24 @@ public abstract class AbstractContext implements Context { options.remove(type); } + @Override + public Map getAttachments() { + return this; + } + @Override public void setAttachment(String name, Object value) { - attachments.put(name, value); + put(name, value); } @Override public Object getAttachment(String name) { - return attachments.get(name); + return get(name); } @Override public void removeAttachment(String name) { - attachments.remove(name); + remove(name); } } diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/Result.java b/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/Result.java index c92bbb2db43c0f12218ae68f52d4d9d926bb131b..1b35bcd8e892023a4deb8b9e5ed93396c4304f68 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/Result.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/Result.java @@ -17,6 +17,7 @@ package com.gitee.dorive.core.entity.executor; +import com.gitee.dorive.core.entity.operation.Query; import lombok.Data; import lombok.NoArgsConstructor; @@ -34,6 +35,17 @@ public class Result { private E record; private long count = 0L; + public static Result emptyResult(Query query) { + Example example = query.getExample(); + if (example != null) { + Page page = example.getPage(); + if (page != null) { + return new Result<>(page); + } + } + return new Result<>(); + } + public Result(Page page, List> recordMaps) { this.page = page; this.recordMaps = recordMaps; diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/entity/operation/Operation.java b/dorive-core/src/main/java/com/gitee/dorive/core/entity/operation/Operation.java index 350d824c42adb08eb9c4cd274b8a525ce11b4794..f7bb315faac9ad6618f1939056798c122f52ad3a 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/entity/operation/Operation.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/entity/operation/Operation.java @@ -22,7 +22,7 @@ import lombok.Data; @Data public class Operation { - public enum RootControl {NONE, INCLUDE_ROOT, IGNORE_ROOT,} + public enum RootControl {NONE, INCLUDE_ROOT, IGNORE_ROOT} private RootControl rootControl = RootControl.NONE; private Object entity; diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/entity/option/BindingType.java b/dorive-core/src/main/java/com/gitee/dorive/core/entity/option/BindingType.java new file mode 100644 index 0000000000000000000000000000000000000000..89ea6fc6f1f46a8d969b62913c7f3a50d30726a7 --- /dev/null +++ b/dorive-core/src/main/java/com/gitee/dorive/core/entity/option/BindingType.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.gitee.dorive.core.entity.option; + +public enum BindingType { + STRONG, + WEAK, + VALUE +} diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/BoundBinder.java b/dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/BoundBinder.java new file mode 100644 index 0000000000000000000000000000000000000000..23743447b8fbe45fcdb5849653cbe4c56c64b09d --- /dev/null +++ b/dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/BoundBinder.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.gitee.dorive.core.impl.binder; + +import com.gitee.dorive.api.entity.def.BindingDef; +import com.gitee.dorive.api.entity.element.PropChain; +import com.gitee.dorive.core.api.binder.Binder; +import com.gitee.dorive.core.api.binder.Processor; +import com.gitee.dorive.core.api.context.Context; +import com.gitee.dorive.core.repository.CommonRepository; +import lombok.AllArgsConstructor; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +@Data +@AllArgsConstructor +public class BoundBinder implements Binder { + + protected BindingDef bindingDef; + protected Processor processor; + protected String belongAccessPath; + protected CommonRepository belongRepository; + protected PropChain boundPropChain; + protected String bindAlias; + + public BoundBinder(BindingDef bindingDef, Processor processor) { + this.bindingDef = bindingDef; + this.processor = processor; + } + + @Override + public String getFieldName() { + return null; + } + + @Override + public Object getFieldValue(Context context, Object entity) { + return null; + } + + @Override + public void setFieldValue(Context context, Object entity, Object property) { + // ignore + } + + @Override + public String getBoundName() { + String bindField = bindingDef.getBindField(); + if (StringUtils.isNotBlank(bindField)) { + return bindField; + } + return boundPropChain.getEntityField().getName(); + } + + @Override + public Object getBoundValue(Context context, Object rootEntity) { + return boundPropChain.getValue(rootEntity); + } + + @Override + public void setBoundValue(Context context, Object rootEntity, Object property) { + boundPropChain.setValue(rootEntity, property); + } + + @Override + public Object input(Context context, Object value) { + return value == null || processor == null ? value : processor.input(context, value); + } + + @Override + public Object output(Context context, Object value) { + return value == null || processor == null ? value : processor.output(context, value); + } + +} diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/AbstractBinder.java b/dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/FieldBinder.java similarity index 68% rename from dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/AbstractBinder.java rename to dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/FieldBinder.java index 38c1c43ab4cc582abb1626bf2e44d3e7cafc7745..60df494f50fb1af50722e6924312b33ef7087e32 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/AbstractBinder.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/FieldBinder.java @@ -25,18 +25,16 @@ import com.gitee.dorive.core.api.context.Context; import lombok.AllArgsConstructor; import lombok.Data; -import java.util.ArrayList; -import java.util.List; - @Data @AllArgsConstructor -public abstract class AbstractBinder implements Binder, Processor { +public class FieldBinder implements Binder { - private BindingDef bindingDef; - private String alias; - private PropChain fieldPropChain; - private Processor processor; + protected BindingDef bindingDef; + protected Processor processor; + protected PropChain fieldPropChain; + protected String alias; + @Override public String getFieldName() { return fieldPropChain.getEntityField().getName(); } @@ -52,25 +50,28 @@ public abstract class AbstractBinder implements Binder, Processor { } @Override - public Object input(Context context, Object value) { - return processor.input(context, value); + public String getBoundName() { + return null; } @Override - public Object output(Context context, Object value) { - return processor.output(context, value); + public Object getBoundValue(Context context, Object rootEntity) { + return null; + } + + @Override + public void setBoundValue(Context context, Object rootEntity, Object property) { + // ignore } - public List collectFieldValues(Context context, List entities) { - List fieldValues = new ArrayList<>(entities.size()); - for (Object entity : entities) { - Object fieldValue = getFieldValue(context, entity); - if (fieldValue != null) { - fieldValue = output(context, fieldValue); - fieldValues.add(fieldValue); - } - } - return fieldValues; + @Override + public Object input(Context context, Object value) { + return value == null || processor == null ? value : processor.input(context, value); + } + + @Override + public Object output(Context context, Object value) { + return value == null || processor == null ? value : processor.output(context, value); } } diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/PropertyBinder.java b/dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/StrongBinder.java similarity index 54% rename from dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/PropertyBinder.java rename to dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/StrongBinder.java index 3bb6dce54fbe410b3828fc26b8c225fbfa5afc18..f9a6d5928406975cbd8e5f67b1769e29861d552d 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/PropertyBinder.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/StrongBinder.java @@ -21,54 +21,41 @@ import com.gitee.dorive.api.entity.def.BindingDef; import com.gitee.dorive.api.entity.element.PropChain; import com.gitee.dorive.core.api.binder.Processor; import com.gitee.dorive.core.api.context.Context; -import com.gitee.dorive.core.repository.CommonRepository; import lombok.Getter; import lombok.Setter; @Getter @Setter -public class PropertyBinder extends AbstractBinder { +public class StrongBinder extends FieldBinder { - private String belongAccessPath; - private CommonRepository belongRepository; - private PropChain boundPropChain; - private String bindAlias; + private BoundBinder boundBinder; - public PropertyBinder(BindingDef bindingDef, - String alias, - PropChain fieldPropChain, - Processor processor, - String belongAccessPath, - CommonRepository belongRepository, - PropChain boundPropChain, - String bindAlias) { - super(bindingDef, alias, fieldPropChain, processor); - this.belongAccessPath = belongAccessPath; - this.belongRepository = belongRepository; - this.boundPropChain = boundPropChain; - this.bindAlias = bindAlias; + public StrongBinder(BindingDef bindingDef, Processor processor, PropChain fieldPropChain, String alias) { + super(bindingDef, processor, fieldPropChain, alias); + this.boundBinder = new BoundBinder(bindingDef, processor); } + @Override public String getBoundName() { - return boundPropChain.getEntityField().getName(); - } - - public boolean isSameType() { - return getFieldPropChain().isSameType(boundPropChain); - } - - public boolean isCollection() { - return boundPropChain.getEntityField().isCollection(); + return boundBinder.getBoundName(); } @Override public Object getBoundValue(Context context, Object rootEntity) { - return boundPropChain.getValue(rootEntity); + return boundBinder.getBoundValue(context, rootEntity); } @Override public void setBoundValue(Context context, Object rootEntity, Object property) { - boundPropChain.setValue(rootEntity, property); + boundBinder.setBoundValue(context, rootEntity, property); + } + + public boolean isSameType() { + return getFieldPropChain().isSameType(boundBinder.getBoundPropChain()); + } + + public boolean isCollection() { + return boundBinder.getBoundPropChain().getEntityField().isCollection(); } } diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/ContextBinder.java b/dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/ValueBinder.java similarity index 63% rename from dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/ContextBinder.java rename to dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/ValueBinder.java index 30882a1f58989ba528fdc37bf80060421954a927..3325517d396b571260ff902c8eac1716ec8ded45 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/ContextBinder.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/ValueBinder.java @@ -17,25 +17,34 @@ package com.gitee.dorive.core.impl.binder; +import cn.hutool.core.convert.Convert; import com.gitee.dorive.api.entity.def.BindingDef; import com.gitee.dorive.api.entity.element.PropChain; import com.gitee.dorive.core.api.binder.Processor; import com.gitee.dorive.core.api.context.Context; +import lombok.Getter; +import lombok.Setter; -public class ContextBinder extends AbstractBinder { +@Getter +@Setter +public class ValueBinder extends BoundBinder { - public ContextBinder(BindingDef bindingDef, String alias, PropChain fieldPropChain, Processor processor) { - super(bindingDef, alias, fieldPropChain, processor); + private Object value; + + public ValueBinder(BindingDef bindingDef, Processor processor) { + super(bindingDef, processor); } @Override - public Object getBoundValue(Context context, Object rootEntity) { - return context.getAttachment(getBindingDef().getBindExp()); + public void setBoundPropChain(PropChain boundPropChain) { + super.setBoundPropChain(boundPropChain); + Class genericType = boundPropChain.getEntityField().getGenericType(); + this.value = Convert.convert(genericType, bindingDef.getValue()); } @Override - public void setBoundValue(Context context, Object rootEntity, Object property) { - // ignore + public Object getFieldValue(Context context, Object entity) { + return value; } } diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/impl/processor/DefaultProcessor.java b/dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/WeakBinder.java similarity index 72% rename from dorive-core/src/main/java/com/gitee/dorive/core/impl/processor/DefaultProcessor.java rename to dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/WeakBinder.java index 69d1381ad826a6d09550955489af7a90cf87c63b..e228a1581d58cc3f56cdcf3355dd75817fb478df 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/impl/processor/DefaultProcessor.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/impl/binder/WeakBinder.java @@ -15,28 +15,27 @@ * limitations under the License. */ -package com.gitee.dorive.core.impl.processor; +package com.gitee.dorive.core.impl.binder; import com.gitee.dorive.api.entity.def.BindingDef; +import com.gitee.dorive.api.entity.element.PropChain; import com.gitee.dorive.core.api.binder.Processor; import com.gitee.dorive.core.api.context.Context; -import lombok.Data; -import lombok.NoArgsConstructor; -@Data -@NoArgsConstructor -public class DefaultProcessor implements Processor { +public class WeakBinder extends FieldBinder { - private BindingDef bindingDef; + public WeakBinder(BindingDef bindingDef, Processor processor, PropChain fieldPropChain, String alias) { + super(bindingDef, processor, fieldPropChain, alias); + } @Override public Object input(Context context, Object value) { - return value; + return processor.input(context, value); } @Override public Object output(Context context, Object value) { - return value; + return processor.output(context, value); } } diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/impl/context/SelectTypeMatcher.java b/dorive-core/src/main/java/com/gitee/dorive/core/impl/context/SelectTypeMatcher.java index d9f3048ee9ac4aa7853ebaba3385936d8f56ee3a..965dda7d841547bbf4d6ce24d382c42a9bb05d96 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/impl/context/SelectTypeMatcher.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/impl/context/SelectTypeMatcher.java @@ -17,8 +17,8 @@ package com.gitee.dorive.core.impl.context; -import com.gitee.dorive.core.api.context.Context; import com.gitee.dorive.core.api.context.Matcher; +import com.gitee.dorive.core.api.context.Options; import com.gitee.dorive.core.api.context.Selector; import com.gitee.dorive.core.entity.option.SelectType; import com.gitee.dorive.core.repository.CommonRepository; @@ -41,19 +41,19 @@ public class SelectTypeMatcher implements Matcher { public SelectTypeMatcher(CommonRepository repository) { this.repository = repository; - this.matcherMap.put(SelectType.NONE, context -> false); - this.matcherMap.put(SelectType.ROOT, context -> repository.isRoot()); - this.matcherMap.put(SelectType.ALL, context -> true); + this.matcherMap.put(SelectType.NONE, options -> false); + this.matcherMap.put(SelectType.ROOT, options -> repository.isRoot()); + this.matcherMap.put(SelectType.ALL, options -> true); this.matcherMap.put(SelectType.SELECTOR, new SelectorMatcher()); } @Override - public boolean matches(Context context) { - SelectType selectType = (SelectType) context.getOption(SelectType.class); + public boolean matches(Options options) { + SelectType selectType = (SelectType) options.getOption(SelectType.class); if (selectType != null) { Matcher matcher = matcherMap.get(selectType); if (matcher != null) { - return matcher.matches(context); + return matcher.matches(options); } } return false; @@ -61,8 +61,8 @@ public class SelectTypeMatcher implements Matcher { private class SelectorMatcher implements Matcher { @Override - public boolean matches(Context context) { - Selector selector = (Selector) context.getOption(Selector.class); + public boolean matches(Options options) { + Selector selector = (Selector) options.getOption(Selector.class); if (selector != null) { Set names = selector.getNames(); String name = repository.getName(); diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/impl/executor/ContextExecutor.java b/dorive-core/src/main/java/com/gitee/dorive/core/impl/executor/ContextExecutor.java index c1d8d7015efa96be7658fcd04ebeb579a5dcdec4..858e282c4ad28f19a153e0c1b0eca3d5caf988a2 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/impl/executor/ContextExecutor.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/impl/executor/ContextExecutor.java @@ -66,7 +66,7 @@ public class ContextExecutor extends AbstractExecutor { } return result; } - return new Result<>(); + return Result.emptyResult(query); } public void populate(Context context, List entities) { @@ -254,7 +254,7 @@ public class ContextExecutor extends AbstractExecutor { } private void getBoundValue(Context context, Object rootEntity, CommonRepository repository, Object entity) { - for (Binder binder : repository.getBinderResolver().getBoundValueBinders()) { + for (Binder binder : repository.getBinderResolver().getStrongBinders()) { Object fieldValue = binder.getFieldValue(context, entity); if (fieldValue == null) { Object boundValue = binder.getBoundValue(context, rootEntity); diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/impl/handler/BatchEntityHandler.java b/dorive-core/src/main/java/com/gitee/dorive/core/impl/handler/BatchEntityHandler.java index 1c196901af30f6cc380e4d75777710ef37a69e63..4a690ef8ade480157378b320de139e50f957d463 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/impl/handler/BatchEntityHandler.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/impl/handler/BatchEntityHandler.java @@ -24,15 +24,18 @@ import com.gitee.dorive.core.entity.executor.Example; import com.gitee.dorive.core.entity.executor.Result; import com.gitee.dorive.core.entity.operation.Query; import com.gitee.dorive.core.entity.option.JoinType; +import com.gitee.dorive.core.impl.binder.ValueBinder; import com.gitee.dorive.core.impl.factory.OperationFactory; import com.gitee.dorive.core.impl.joiner.MultiEntityJoiner; import com.gitee.dorive.core.impl.joiner.SingleEntityJoiner; import com.gitee.dorive.core.impl.joiner.UnionEntityJoiner; +import com.gitee.dorive.core.impl.resolver.BinderResolver; import com.gitee.dorive.core.repository.AbstractContextRepository; import com.gitee.dorive.core.repository.CommonRepository; import lombok.AllArgsConstructor; import lombok.Data; +import java.util.ArrayList; import java.util.List; @Data @@ -46,11 +49,15 @@ public class BatchEntityHandler implements EntityHandler { long totalCount = 0L; for (CommonRepository repository : this.repository.getSubRepositories()) { if (repository.matches(context)) { - EntityJoiner entityJoiner = newEntityJoiner(repository, entities.size()); + List newEntities = filterByValueBinders(context, entities, repository); + if (newEntities.isEmpty()) { + continue; + } + EntityJoiner entityJoiner = newEntityJoiner(repository, newEntities.size()); if (entityJoiner == null) { continue; } - Example example = entityJoiner.newExample(context, entities); + Example example = entityJoiner.newExample(context, newEntities); if (example.isEmpty()) { continue; } @@ -58,13 +65,38 @@ public class BatchEntityHandler implements EntityHandler { Query query = operationFactory.buildQueryByExample(example); query.includeRoot(); Result result = repository.executeQuery(context, query); - entityJoiner.join(context, entities, result); + entityJoiner.join(context, newEntities, result); totalCount += result.getCount(); } } return totalCount; } + private List filterByValueBinders(Context context, List entities, CommonRepository repository) { + BinderResolver binderResolver = repository.getBinderResolver(); + List valueBinders = binderResolver.getValueBinders(); + if (valueBinders.isEmpty()) { + return entities; + } + List newEntities = new ArrayList<>(entities.size()); + for (Object entity : entities) { + boolean isValueEqual = true; + for (ValueBinder valueBinder : valueBinders) { + Object fieldValue = valueBinder.getFieldValue(context, null); + Object boundValue = valueBinder.getBoundValue(context, entity); + boundValue = valueBinder.input(context, boundValue); + if (!fieldValue.equals(boundValue)) { + isValueEqual = false; + break; + } + } + if (isValueEqual) { + newEntities.add(entity); + } + } + return newEntities; + } + protected EntityJoiner newEntityJoiner(CommonRepository repository, int entitiesSize) { JoinType joinType = repository.getJoinType(); if (joinType == JoinType.SINGLE) { diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/impl/joiner/AbstractEntityJoiner.java b/dorive-core/src/main/java/com/gitee/dorive/core/impl/joiner/AbstractEntityJoiner.java index bbe7b8f995ec76a5d7f5f35af19dc06e87a32c18..5bf1930837e27b46920b577d0f1507f616d82964 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/impl/joiner/AbstractEntityJoiner.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/impl/joiner/AbstractEntityJoiner.java @@ -22,7 +22,7 @@ import com.gitee.dorive.core.api.context.Context; import com.gitee.dorive.core.api.executor.EntityJoiner; import com.gitee.dorive.core.entity.executor.Example; import com.gitee.dorive.core.entity.executor.Result; -import com.gitee.dorive.core.impl.binder.ContextBinder; +import com.gitee.dorive.core.impl.binder.WeakBinder; import com.gitee.dorive.core.impl.resolver.BinderResolver; import com.gitee.dorive.core.repository.CommonRepository; import org.apache.commons.lang3.StringUtils; @@ -51,16 +51,16 @@ public abstract class AbstractEntityJoiner implements EntityJoiner { this.recordIndex = new LinkedHashMap<>(size); } - protected void appendContext(Context context, Example example) { + protected void appendFilterCriteria(Context context, Example example) { if (example == null || example.isEmpty()) { return; } BinderResolver binderResolver = repository.getBinderResolver(); - List contextBinders = binderResolver.getContextBinders(); - for (ContextBinder contextBinder : contextBinders) { - Object boundValue = contextBinder.getBoundValue(context, null); + List weakBinders = binderResolver.getWeakBinders(); + for (WeakBinder weakBinder : weakBinders) { + Object boundValue = weakBinder.input(context, null); if (boundValue != null) { - String fieldName = contextBinder.getFieldName(); + String fieldName = weakBinder.getFieldName(); example.eq(fieldName, boundValue); } } diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/impl/joiner/MultiEntityJoiner.java b/dorive-core/src/main/java/com/gitee/dorive/core/impl/joiner/MultiEntityJoiner.java index 5f2d66fa933b98e6757ee4e414e52a32c4ed6695..039a5a5851adc59a1dac6d4aa57613edad125e45 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/impl/joiner/MultiEntityJoiner.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/impl/joiner/MultiEntityJoiner.java @@ -21,8 +21,8 @@ import com.gitee.dorive.core.api.context.Context; import com.gitee.dorive.core.entity.executor.Example; import com.gitee.dorive.core.entity.executor.InnerExample; import com.gitee.dorive.core.entity.executor.Result; -import com.gitee.dorive.core.impl.binder.AbstractBinder; -import com.gitee.dorive.core.impl.binder.PropertyBinder; +import com.gitee.dorive.core.impl.binder.FieldBinder; +import com.gitee.dorive.core.impl.binder.StrongBinder; import com.gitee.dorive.core.repository.CommonRepository; import com.gitee.dorive.core.util.MultiInBuilder; import lombok.Getter; @@ -35,7 +35,7 @@ import java.util.stream.Collectors; @Setter public class MultiEntityJoiner extends AbstractEntityJoiner { - private List binders; + private List binders; public MultiEntityJoiner(CommonRepository repository, int entitiesSize) { super(repository, entitiesSize); @@ -49,21 +49,19 @@ public class MultiEntityJoiner extends AbstractEntityJoiner { if (!builder.isEmpty()) { example.getCriteria().add(builder.toCriterion()); } - appendContext(context, example); + appendFilterCriteria(context, example); return example; } private MultiInBuilder newMultiInBuilder(Context context, List entities) { - List aliases = binders.stream().map(AbstractBinder::getAlias).collect(Collectors.toList()); + List aliases = binders.stream().map(FieldBinder::getAlias).collect(Collectors.toList()); MultiInBuilder multiInBuilder = new MultiInBuilder(aliases, entities.size()); for (Object entity : entities) { StringBuilder keyBuilder = new StringBuilder(); - for (PropertyBinder binder : binders) { + for (StrongBinder binder : binders) { Object boundValue = binder.getBoundValue(context, entity); - if (boundValue != null) { - boundValue = binder.input(context, boundValue); - } + boundValue = binder.input(context, boundValue); if (boundValue != null) { multiInBuilder.append(boundValue); String key = boundValue.toString(); @@ -92,7 +90,7 @@ public class MultiEntityJoiner extends AbstractEntityJoiner { List records = result.getRecords(); for (Object entity : records) { StringBuilder keyBuilder = new StringBuilder(); - for (PropertyBinder binder : binders) { + for (StrongBinder binder : binders) { Object fieldValue = binder.getFieldValue(context, entity); if (fieldValue != null) { String key = fieldValue.toString(); diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/impl/joiner/SingleEntityJoiner.java b/dorive-core/src/main/java/com/gitee/dorive/core/impl/joiner/SingleEntityJoiner.java index 166f981eb43553eec313c5183c50ca84584a58ca..aa119a2b024170c32a4cc7141fe4b725b17c8fad 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/impl/joiner/SingleEntityJoiner.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/impl/joiner/SingleEntityJoiner.java @@ -21,7 +21,7 @@ import com.gitee.dorive.core.api.context.Context; import com.gitee.dorive.core.entity.executor.Example; import com.gitee.dorive.core.entity.executor.InnerExample; import com.gitee.dorive.core.entity.executor.Result; -import com.gitee.dorive.core.impl.binder.PropertyBinder; +import com.gitee.dorive.core.impl.binder.StrongBinder; import com.gitee.dorive.core.repository.CommonRepository; import lombok.Getter; import lombok.Setter; @@ -33,7 +33,7 @@ import java.util.List; @Setter public class SingleEntityJoiner extends AbstractEntityJoiner { - private PropertyBinder binder; + private StrongBinder binder; public SingleEntityJoiner(CommonRepository repository, int entitiesSize) { super(repository, entitiesSize); @@ -52,7 +52,7 @@ public class SingleEntityJoiner extends AbstractEntityJoiner { example.in(fieldName, boundValues); } } - appendContext(context, example); + appendFilterCriteria(context, example); return example; } @@ -60,9 +60,7 @@ public class SingleEntityJoiner extends AbstractEntityJoiner { List boundValues = new ArrayList<>(entities.size()); for (Object entity : entities) { Object boundValue = binder.getBoundValue(context, entity); - if (boundValue != null) { - boundValue = binder.input(context, boundValue); - } + boundValue = binder.input(context, boundValue); if (boundValue != null) { String key = boundValue.toString(); if (!keys.contains(key)) { diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/impl/joiner/UnionEntityJoiner.java b/dorive-core/src/main/java/com/gitee/dorive/core/impl/joiner/UnionEntityJoiner.java index 9a46330febd931b2e3293da0a1df8afb6d4d6461..2af9695612d9574065423812f003be6081a8a526 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/impl/joiner/UnionEntityJoiner.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/impl/joiner/UnionEntityJoiner.java @@ -23,7 +23,7 @@ import com.gitee.dorive.core.entity.executor.Example; import com.gitee.dorive.core.entity.executor.InnerExample; import com.gitee.dorive.core.entity.executor.Result; import com.gitee.dorive.core.entity.executor.UnionExample; -import com.gitee.dorive.core.impl.binder.PropertyBinder; +import com.gitee.dorive.core.impl.binder.StrongBinder; import com.gitee.dorive.core.repository.CommonRepository; import lombok.Getter; import lombok.Setter; @@ -65,17 +65,15 @@ public class UnionEntityJoiner extends AbstractEntityJoiner { private Example newExample(Context context, Object entity) { Example example = new InnerExample(); - List binders = repository.getBinderResolver().getPropertyBinders(); - for (PropertyBinder binder : binders) { + List binders = repository.getBinderResolver().getStrongBinders(); + for (StrongBinder binder : binders) { Object boundValue = binder.getBoundValue(context, entity); + boundValue = binder.input(context, boundValue); if (boundValue instanceof Collection) { if (((Collection) boundValue).isEmpty()) { boundValue = null; } } - if (boundValue != null) { - boundValue = binder.input(context, boundValue); - } if (boundValue != null) { String fieldName = binder.getFieldName(); example.eq(fieldName, boundValue); @@ -84,7 +82,7 @@ public class UnionEntityJoiner extends AbstractEntityJoiner { break; } } - appendContext(context, example); + appendFilterCriteria(context, example); return example; } diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/impl/processor/SpELProcessor.java b/dorive-core/src/main/java/com/gitee/dorive/core/impl/processor/SpELProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..b9723d729ed21e259463881ac1323d680031af60 --- /dev/null +++ b/dorive-core/src/main/java/com/gitee/dorive/core/impl/processor/SpELProcessor.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.gitee.dorive.core.impl.processor; + +import com.gitee.dorive.api.entity.def.BindingDef; +import com.gitee.dorive.core.api.binder.Processor; +import com.gitee.dorive.core.api.context.Context; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; + +public class SpELProcessor implements Processor { + + private final Expression expression; + + public SpELProcessor(BindingDef bindingDef) { + ExpressionParser parser = new SpelExpressionParser(); + this.expression = parser.parseExpression(bindingDef.getProcessExp()); + } + + @Override + public Object input(Context context, Object value) { + EvaluationContext evaluationContext = new StandardEvaluationContext(); + evaluationContext.setVariable("ctx", context); + evaluationContext.setVariable("val", value); + return expression.getValue(evaluationContext); + } + + @Override + public Object output(Context context, Object value) { + return value; + } + +} diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/impl/resolver/BinderResolver.java b/dorive-core/src/main/java/com/gitee/dorive/core/impl/resolver/BinderResolver.java index 4298bf01ff166ac141b5ff8c1d1bc91304e2c313..30c1b6a3496818323b05203870c08cb93e38a107 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/impl/resolver/BinderResolver.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/impl/resolver/BinderResolver.java @@ -20,7 +20,9 @@ package com.gitee.dorive.core.impl.resolver; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; import com.gitee.dorive.api.entity.def.BindingDef; import com.gitee.dorive.api.entity.def.EntityDef; import com.gitee.dorive.api.entity.element.EntityEle; @@ -28,11 +30,13 @@ import com.gitee.dorive.api.entity.element.PropChain; import com.gitee.dorive.api.impl.resolver.PropChainResolver; import com.gitee.dorive.core.api.binder.Binder; import com.gitee.dorive.core.api.binder.Processor; +import com.gitee.dorive.core.entity.option.BindingType; import com.gitee.dorive.core.entity.option.JoinType; -import com.gitee.dorive.core.impl.binder.ContextBinder; -import com.gitee.dorive.core.impl.binder.PropertyBinder; -import com.gitee.dorive.core.impl.processor.DefaultProcessor; -import com.gitee.dorive.core.impl.processor.PropertyProcessor; +import com.gitee.dorive.core.impl.binder.BoundBinder; +import com.gitee.dorive.core.impl.binder.StrongBinder; +import com.gitee.dorive.core.impl.binder.ValueBinder; +import com.gitee.dorive.core.impl.binder.WeakBinder; +import com.gitee.dorive.core.impl.processor.SpELProcessor; import com.gitee.dorive.core.repository.AbstractContextRepository; import com.gitee.dorive.core.repository.CommonRepository; import com.gitee.dorive.core.util.PathUtils; @@ -53,13 +57,14 @@ public class BinderResolver { private PropChainResolver propChainResolver; private List allBinders; - private List propertyBinders; - private Map> mergedBindersMap; - private JoinType joinType; + private List valueBinders; + private List strongBinders; + // 决定了关联查询具体使用哪种实现 + private Map> mergedBindersMap; + private StrongBinder boundIdBinder; private List selfFields; - private List contextBinders; - private List boundValueBinders; - private PropertyBinder boundIdBinder; + private JoinType joinType; + private List weakBinders; public BinderResolver(AbstractContextRepository repository, EntityEle entityEle) { this.repository = repository; @@ -73,115 +78,144 @@ public class BinderResolver { String idName = entityEle.getIdName(); List bindingDefs = entityEle.getBindingDefs(); - allBinders = new ArrayList<>(bindingDefs.size()); - propertyBinders = new ArrayList<>(bindingDefs.size()); - mergedBindersMap = new LinkedHashMap<>(bindingDefs.size() * 4 / 3 + 1); - joinType = JoinType.UNKNOWN; - selfFields = new ArrayList<>(bindingDefs.size()); - contextBinders = new ArrayList<>(bindingDefs.size()); - boundValueBinders = new ArrayList<>(bindingDefs.size()); - boundIdBinder = null; + this.allBinders = new ArrayList<>(bindingDefs.size()); + this.valueBinders = new ArrayList<>(bindingDefs.size()); + this.strongBinders = new ArrayList<>(bindingDefs.size()); + this.mergedBindersMap = new LinkedHashMap<>(bindingDefs.size() * 4 / 3 + 1); + this.boundIdBinder = null; + this.selfFields = new ArrayList<>(bindingDefs.size()); + this.joinType = JoinType.UNION; + this.weakBinders = new ArrayList<>(bindingDefs.size()); + String fieldErrorMsg = "The field configured for @Binding does not exist within the entity! type: {}, field: {}"; for (BindingDef bindingDef : bindingDefs) { + BindingType bindingType = determineBindingType(bindingDef); bindingDef = renewBindingDef(accessPath, bindingDef); - String field = bindingDef.getField(); - String bindExp = bindingDef.getBindExp(); + Processor processor = newProcessor(bindingDef); + if (bindingType == BindingType.VALUE) { + ValueBinder valueBinder = new ValueBinder(bindingDef, processor); + initBoundBinder(bindingDef, valueBinder); + allBinders.add(valueBinder); + valueBinders.add(valueBinder); + continue; + } + + String field = bindingDef.getField(); String alias = entityEle.toAlias(field); PropChain fieldPropChain = propChainMap.get("/" + field); - Assert.notNull(fieldPropChain, "The field configured for @Binding does not exist within the entity! type: {}, field: {}", - genericType.getName(), field); + Assert.notNull(fieldPropChain, fieldErrorMsg, genericType.getName(), field); fieldPropChain.newPropProxy(); - Processor processor = newProcessor(bindingDef); - - if (bindExp.startsWith("/")) { - PropertyBinder propertyBinder = newPropertyBinder(bindingDef, alias, fieldPropChain, processor); - allBinders.add(propertyBinder); - propertyBinders.add(propertyBinder); + if (bindingType == BindingType.STRONG) { + StrongBinder strongBinder = new StrongBinder(bindingDef, processor, fieldPropChain, alias); + BoundBinder boundBinder = strongBinder.getBoundBinder(); + initBoundBinder(bindingDef, boundBinder); + allBinders.add(strongBinder); + strongBinders.add(strongBinder); - String belongAccessPath = propertyBinder.getBelongAccessPath(); - List propertyBinders = mergedBindersMap.computeIfAbsent(belongAccessPath, key -> new ArrayList<>(2)); - propertyBinders.add(propertyBinder); + String belongAccessPath = boundBinder.getBelongAccessPath(); + List strongBinders = mergedBindersMap.computeIfAbsent(belongAccessPath, key -> new ArrayList<>(2)); + strongBinders.add(strongBinder); - selfFields.add(field); - - if (propertyBinder.isSameType()) { - if (!idName.equals(field)) { - boundValueBinders.add(propertyBinder); - } else { - if (entityDef.getPriority() == 0) { - entityDef.setPriority(-1); - } - boundIdBinder = propertyBinder; + if (strongBinder.isSameType() && idName.equals(field)) { + if (entityDef.getPriority() == 0) { + entityDef.setPriority(-1); } + boundIdBinder = strongBinder; } + selfFields.add(field); - } else { - ContextBinder contextBinder = new ContextBinder(bindingDef, alias, fieldPropChain, processor); - allBinders.add(contextBinder); - contextBinders.add(contextBinder); - boundValueBinders.add(contextBinder); + } else if (bindingType == BindingType.WEAK) { + WeakBinder weakBinder = new WeakBinder(bindingDef, processor, fieldPropChain, alias); + allBinders.add(weakBinder); + weakBinders.add(weakBinder); } } + selfFields = Collections.unmodifiableList(selfFields); + if (mergedBindersMap.size() == 1 && mergedBindersMap.containsKey("/")) { - List binders = mergedBindersMap.get("/"); - boolean hasCollection = CollUtil.findOne(binders, PropertyBinder::isCollection) != null; + List binders = mergedBindersMap.get("/"); + boolean hasCollection = CollUtil.findOne(binders, StrongBinder::isCollection) != null; if (!hasCollection) { joinType = binders.size() == 1 ? JoinType.SINGLE : JoinType.MULTI; } } - if (joinType == JoinType.UNKNOWN) { - joinType = JoinType.UNION; + } + + private BindingType determineBindingType(BindingDef bindingDef) { + String field = StrUtil.trim(bindingDef.getField()); + String value = StrUtil.trim(bindingDef.getValue()); + String bindExp = StrUtil.trim(bindingDef.getBindExp()); + String processExp = StrUtil.trim(bindingDef.getProcessExp()); + if (ObjectUtil.isAllNotEmpty(field, bindExp)) { + return BindingType.STRONG; + + } else if (ObjectUtil.isAllNotEmpty(field, processExp)) { + return BindingType.WEAK; + + } else if (ObjectUtil.isAllNotEmpty(value, bindExp)) { + return BindingType.VALUE; } - selfFields = Collections.unmodifiableList(selfFields); + throw new RuntimeException("Unknown binding type!"); } private BindingDef renewBindingDef(String accessPath, BindingDef bindingDef) { bindingDef = BeanUtil.copyProperties(bindingDef, BindingDef.class); - String bindExp = bindingDef.getBindExp(); + String field = StrUtil.trim(bindingDef.getField()); + String value = StrUtil.trim(bindingDef.getValue()); + String bindExp = StrUtil.trim(bindingDef.getBindExp()); + String processExp = StrUtil.trim(bindingDef.getProcessExp()); + Class processor = bindingDef.getProcessor(); + String bindField = StrUtil.trim(bindingDef.getBindField()); + if (bindExp.startsWith(".")) { bindExp = PathUtils.getAbsolutePath(accessPath, bindExp); - bindingDef.setBindExp(bindExp); } + if (StringUtils.isNotBlank(bindExp)) { + if (StringUtils.isBlank(processExp) && StringUtils.isBlank(bindField)) { + bindField = PathUtils.getLastName(bindExp); + } + Assert.notEmpty(bindField, "The bindField of @Binding cannot be empty!"); + } + if (StringUtils.isNotBlank(processExp) && processor == Object.class) { + processor = SpELProcessor.class; + } + + bindingDef.setField(field); + bindingDef.setValue(value); + bindingDef.setBindExp(bindExp); + bindingDef.setProcessExp(processExp); + bindingDef.setProcessor(processor); + bindingDef.setBindField(bindField); return bindingDef; } private Processor newProcessor(BindingDef bindingDef) { Assert.notNull(bindingDef, "The bindingDef cannot be null!"); Class processorClass = bindingDef.getProcessor(); - Processor processor = null; if (processorClass == Object.class) { - if (StringUtils.isBlank(bindingDef.getProperty())) { - processor = new DefaultProcessor(); - } else { - processor = new PropertyProcessor(); - } + return null; + + } else if (processorClass == SpELProcessor.class) { + return new SpELProcessor(bindingDef); + } else { ApplicationContext applicationContext = repository.getApplicationContext(); String[] beanNamesForType = applicationContext.getBeanNamesForType(processorClass); if (beanNamesForType.length > 0) { - processor = (Processor) applicationContext.getBean(beanNamesForType[0]); - } - if (processor == null) { - processor = (Processor) ReflectUtil.newInstance(processorClass); + return (Processor) applicationContext.getBean(beanNamesForType[0]); + } else { + return (Processor) ReflectUtil.newInstance(processorClass); } } - if (processor instanceof DefaultProcessor) { - DefaultProcessor defaultProcessor = (DefaultProcessor) processor; - defaultProcessor.setBindingDef(bindingDef); - } - if (processor instanceof PropertyProcessor) { - Assert.notBlank(bindingDef.getProperty(), "The property of PropertyProcessor cannot be blank!"); - } - return processor; } - private PropertyBinder newPropertyBinder(BindingDef bindingDef, String alias, PropChain fieldPropChain, Processor processor) { + private void initBoundBinder(BindingDef bindingDef, BoundBinder boundBinder) { String bindExp = bindingDef.getBindExp(); - String property = bindingDef.getProperty(); + String bindField = bindingDef.getBindField(); Map repositoryMap = repository.getRepositoryMap(); String belongAccessPath = PathUtils.getBelongPath(repositoryMap.keySet(), bindExp); @@ -196,11 +230,12 @@ public class BinderResolver { boundPropChain.newPropProxy(); EntityEle entityEle = belongRepository.getEntityEle(); - String boundName = StringUtils.isBlank(property) ? PathUtils.getLastName(bindExp) : property; - String bindAlias = entityEle.toAlias(boundName); + String bindAlias = entityEle.toAlias(bindField); - return new PropertyBinder(bindingDef, alias, fieldPropChain, processor, - belongAccessPath, belongRepository, boundPropChain, bindAlias); + boundBinder.setBelongAccessPath(belongAccessPath); + boundBinder.setBelongRepository(belongRepository); + boundBinder.setBoundPropChain(boundPropChain); + boundBinder.setBindAlias(bindAlias); } } diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/repository/AbstractGenericRepository.java b/dorive-core/src/main/java/com/gitee/dorive/core/repository/AbstractGenericRepository.java index a8480cb4903dc5866df978350b0542085f7ad943..dc12acfcb8ec1c4b9db2cb80e41e75471ffa468b 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/repository/AbstractGenericRepository.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/repository/AbstractGenericRepository.java @@ -43,7 +43,7 @@ public abstract class AbstractGenericRepository extends AbstractContextRe Assert.notNull(example, "The example cannot be null!"); int totalCount = 0; for (CommonRepository repository : getOrderedRepositories()) { - if (repository.matches((Context) options)) { + if (repository.matches(options)) { totalCount += repository.updateByExample(options, entity, ExampleUtils.clone(example)); } } @@ -69,7 +69,7 @@ public abstract class AbstractGenericRepository extends AbstractContextRe Assert.notNull(example, "The example cannot be null!"); int totalCount = 0; for (CommonRepository repository : getOrderedRepositories()) { - if (repository.matches((Context) options)) { + if (repository.matches(options)) { totalCount += repository.deleteByExample(options, ExampleUtils.clone(example)); } } diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/repository/CommonRepository.java b/dorive-core/src/main/java/com/gitee/dorive/core/repository/CommonRepository.java index 458272a04d493cafdd911705891ab8d55999dc31..4289705baa2ef17166b58951bbe552f569b322f8 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/repository/CommonRepository.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/repository/CommonRepository.java @@ -20,6 +20,7 @@ package com.gitee.dorive.core.repository; import com.gitee.dorive.api.entity.element.PropChain; import com.gitee.dorive.core.api.context.Context; import com.gitee.dorive.core.api.context.Matcher; +import com.gitee.dorive.core.api.context.Options; import com.gitee.dorive.core.api.context.Selector; import com.gitee.dorive.core.entity.executor.Example; import com.gitee.dorive.core.entity.executor.InnerExample; @@ -27,7 +28,7 @@ import com.gitee.dorive.core.entity.executor.OrderBy; import com.gitee.dorive.core.entity.executor.Result; import com.gitee.dorive.core.entity.operation.Query; import com.gitee.dorive.core.entity.option.JoinType; -import com.gitee.dorive.core.impl.binder.PropertyBinder; +import com.gitee.dorive.core.impl.binder.StrongBinder; import com.gitee.dorive.core.impl.resolver.BinderResolver; import com.gitee.dorive.core.util.ExampleUtils; import lombok.Getter; @@ -68,13 +69,13 @@ public class CommonRepository extends AbstractProxyRepository implements Matcher return binderResolver.getJoinType(); } - public List getRootBinders() { + public List getRootBinders() { return binderResolver.getMergedBindersMap().get("/"); } @Override - public boolean matches(Context context) { - return matcher.matches(context); + public boolean matches(Options options) { + return matcher.matches(options); } @Override diff --git a/dorive-env/pom.xml b/dorive-env/pom.xml index 16060c10b7e9cd67e8c2c1f9f6a35015c43cbac9..64f097ee16dc0590afeb67bada52090e65356d9b 100644 --- a/dorive-env/pom.xml +++ b/dorive-env/pom.xml @@ -6,7 +6,7 @@ com.gitee.digital-engine dorive - 3.4.3.3 + 3.4.3.4 dorive-env diff --git a/dorive-event/pom.xml b/dorive-event/pom.xml index 42a09b4c3a0544584d07b5b5941514c7c8418e7e..297735c67547ba7a5f1e2fa525f96b0c4e0c8349 100644 --- a/dorive-event/pom.xml +++ b/dorive-event/pom.xml @@ -6,7 +6,7 @@ com.gitee.digital-engine dorive - 3.4.3.3 + 3.4.3.4 dorive-event diff --git a/dorive-inject/pom.xml b/dorive-inject/pom.xml index 756bed41cf2ca1f9803040cd45bfe44e47aa6af3..b46ff43d9fea04b08db202645724f9660bde3720 100644 --- a/dorive-inject/pom.xml +++ b/dorive-inject/pom.xml @@ -6,7 +6,7 @@ com.gitee.digital-engine dorive - 3.4.3.3 + 3.4.3.4 dorive-inject diff --git a/dorive-mybatis-plus/pom.xml b/dorive-mybatis-plus/pom.xml index 03be052251ad48afa462bbbe5964c1e6cf962c7d..49c9b84a95790e630a47b038eaa02fd62082777c 100644 --- a/dorive-mybatis-plus/pom.xml +++ b/dorive-mybatis-plus/pom.xml @@ -6,7 +6,7 @@ com.gitee.digital-engine dorive - 3.4.3.3 + 3.4.3.4 dorive-mybatis-plus diff --git a/dorive-mybatis-plus/src/main/java/com/gitee/dorive/mybatis/plus/api/CriterionAppender.java b/dorive-mybatis-plus/src/main/java/com/gitee/dorive/mybatis/plus/api/CriterionAppender.java index 13e90e54d174c65a0a9c19b9f7910aba334560cc..81ed3bd9eff47294863be281edfa15246ed20398 100644 --- a/dorive-mybatis-plus/src/main/java/com/gitee/dorive/mybatis/plus/api/CriterionAppender.java +++ b/dorive-mybatis-plus/src/main/java/com/gitee/dorive/mybatis/plus/api/CriterionAppender.java @@ -18,9 +18,10 @@ package com.gitee.dorive.mybatis.plus.api; import com.baomidou.mybatisplus.core.conditions.AbstractWrapper; +import com.gitee.dorive.core.entity.executor.Example; public interface CriterionAppender { - void appendCriterion(AbstractWrapper abstractWrapper, String property, Object value); + void appendCriterion(AbstractWrapper wrapper, Example example, String property, Object value); } diff --git a/dorive-mybatis-plus/src/main/java/com/gitee/dorive/mybatis/plus/impl/AppenderContext.java b/dorive-mybatis-plus/src/main/java/com/gitee/dorive/mybatis/plus/impl/AppenderContext.java index 93e8566268aba3dd778a70d6f9535e5116f6ffbc..178afcc8cbe32a24606e331a346cf729b6850213 100644 --- a/dorive-mybatis-plus/src/main/java/com/gitee/dorive/mybatis/plus/impl/AppenderContext.java +++ b/dorive-mybatis-plus/src/main/java/com/gitee/dorive/mybatis/plus/impl/AppenderContext.java @@ -18,13 +18,15 @@ package com.gitee.dorive.mybatis.plus.impl; import com.baomidou.mybatisplus.core.conditions.AbstractWrapper; -import com.baomidou.mybatisplus.core.conditions.interfaces.Compare; +import com.baomidou.mybatisplus.core.toolkit.StringPool; import com.gitee.dorive.api.constant.Operator; import com.gitee.dorive.core.entity.executor.Criterion; import com.gitee.dorive.core.entity.executor.Example; +import com.gitee.dorive.core.entity.executor.OrderBy; import com.gitee.dorive.mybatis.plus.api.CriterionAppender; import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -33,54 +35,69 @@ public class AppenderContext { public final static Map OPERATOR_CRITERION_APPENDER_MAP = new ConcurrentHashMap<>(); static { - OPERATOR_CRITERION_APPENDER_MAP.put(Operator.EQ, (abstractWrapper, property, value) -> { + OPERATOR_CRITERION_APPENDER_MAP.put(Operator.EQ, (wrapper, example, property, value) -> { if (value instanceof Collection) { - abstractWrapper.in(property, (Collection) value); + wrapper.in(property, (Collection) value); } else { - abstractWrapper.eq(property, value); + wrapper.eq(property, value); } }); - OPERATOR_CRITERION_APPENDER_MAP.put(Operator.NE, (abstractWrapper, property, value) -> { + OPERATOR_CRITERION_APPENDER_MAP.put(Operator.NE, (wrapper, example, property, value) -> { if (value instanceof Collection) { - abstractWrapper.notIn(property, (Collection) value); + wrapper.notIn(property, (Collection) value); } else { - abstractWrapper.ne(property, value); + wrapper.ne(property, value); } }); - OPERATOR_CRITERION_APPENDER_MAP.put(Operator.GT, Compare::gt); - OPERATOR_CRITERION_APPENDER_MAP.put(Operator.GE, Compare::ge); - OPERATOR_CRITERION_APPENDER_MAP.put(Operator.LT, Compare::lt); - OPERATOR_CRITERION_APPENDER_MAP.put(Operator.LE, Compare::le); - OPERATOR_CRITERION_APPENDER_MAP.put(Operator.IN, (abstractWrapper, property, value) -> abstractWrapper.in(property, (Collection) value)); - OPERATOR_CRITERION_APPENDER_MAP.put(Operator.NOT_IN, (abstractWrapper, property, value) -> abstractWrapper.notIn(property, (Collection) value)); - OPERATOR_CRITERION_APPENDER_MAP.put(Operator.LIKE, Compare::like); - OPERATOR_CRITERION_APPENDER_MAP.put(Operator.NOT_LIKE, Compare::notLike); - OPERATOR_CRITERION_APPENDER_MAP.put(Operator.IS_NULL, (abstractWrapper, property, value) -> abstractWrapper.isNull(property)); - OPERATOR_CRITERION_APPENDER_MAP.put(Operator.IS_NOT_NULL, (abstractWrapper, property, value) -> abstractWrapper.isNotNull(property)); - OPERATOR_CRITERION_APPENDER_MAP.put(Operator.MULTI_IN, (abstractWrapper, property, value) -> { - String prefix = abstractWrapper.isEmptyOfWhere() ? " WHERE " : " AND "; - abstractWrapper.last(prefix + "(" + property + ") IN (" + value + ")"); + OPERATOR_CRITERION_APPENDER_MAP.put(Operator.GT, (wrapper, example, property, value) -> wrapper.gt(property, value)); + OPERATOR_CRITERION_APPENDER_MAP.put(Operator.GE, (wrapper, example, property, value) -> wrapper.ge(property, value)); + OPERATOR_CRITERION_APPENDER_MAP.put(Operator.LT, (wrapper, example, property, value) -> wrapper.lt(property, value)); + OPERATOR_CRITERION_APPENDER_MAP.put(Operator.LE, (wrapper, example, property, value) -> wrapper.le(property, value)); + OPERATOR_CRITERION_APPENDER_MAP.put(Operator.IN, (wrapper, example, property, value) -> wrapper.in(property, (Collection) value)); + OPERATOR_CRITERION_APPENDER_MAP.put(Operator.NOT_IN, (wrapper, example, property, value) -> wrapper.notIn(property, (Collection) value)); + OPERATOR_CRITERION_APPENDER_MAP.put(Operator.LIKE, (wrapper, example, property, value) -> wrapper.like(property, value)); + OPERATOR_CRITERION_APPENDER_MAP.put(Operator.NOT_LIKE, (wrapper, example, property, value) -> wrapper.notLike(property, value)); + OPERATOR_CRITERION_APPENDER_MAP.put(Operator.IS_NULL, (wrapper, example, property, value) -> wrapper.isNull(property)); + OPERATOR_CRITERION_APPENDER_MAP.put(Operator.IS_NOT_NULL, (wrapper, example, property, value) -> wrapper.isNotNull(property)); + OPERATOR_CRITERION_APPENDER_MAP.put(Operator.MULTI_IN, (wrapper, example, property, value) -> { + List criteria = example.getCriteria(); + OrderBy orderBy = example.getOrderBy(); + String prefix = criteria.size() == 1 ? " WHERE " : " AND "; + String lastSql = prefix + "(" + property + ") IN (" + value + ")"; + if (orderBy != null) { + lastSql = lastSql + StringPool.SPACE + orderBy; + example.setOrderBy(null); + } + wrapper.last(lastSql); }); - OPERATOR_CRITERION_APPENDER_MAP.put(Operator.MULTI_NOT_IN, (abstractWrapper, property, value) -> { - String prefix = abstractWrapper.isEmptyOfWhere() ? " WHERE " : " AND "; - abstractWrapper.last(prefix + "(" + property + ") NOT IN (" + value + ")"); + OPERATOR_CRITERION_APPENDER_MAP.put(Operator.MULTI_NOT_IN, (wrapper, example, property, value) -> { + List criteria = example.getCriteria(); + OrderBy orderBy = example.getOrderBy(); + String prefix = criteria.size() == 1 ? " WHERE " : " AND "; + String lastSql = prefix + "(" + property + ") NOT IN (" + value + ")"; + if (orderBy != null) { + lastSql = lastSql + StringPool.SPACE + orderBy; + example.setOrderBy(null); + } + wrapper.last(lastSql); }); - OPERATOR_CRITERION_APPENDER_MAP.put(Operator.AND, (abstractWrapper, property, value) -> { + OPERATOR_CRITERION_APPENDER_MAP.put(Operator.AND, (wrapper, example, property, value) -> { if (value instanceof Example) { - abstractWrapper.and(q -> appendCriterion(q, (Example) value)); + wrapper.and(q -> appendCriterion(q, (Example) value)); } }); - OPERATOR_CRITERION_APPENDER_MAP.put(Operator.OR, (abstractWrapper, property, value) -> { + OPERATOR_CRITERION_APPENDER_MAP.put(Operator.OR, (wrapper, example, property, value) -> { if (value instanceof Example) { - abstractWrapper.or(q -> appendCriterion(q, (Example) value)); + wrapper.or(q -> appendCriterion(q, (Example) value)); } }); } - public static void appendCriterion(AbstractWrapper abstractWrapper, Example example) { - for (Criterion criterion : example.getCriteria()) { + public static void appendCriterion(AbstractWrapper wrapper, Example example) { + List criteria = example.getCriteria(); + for (Criterion criterion : criteria) { CriterionAppender criterionAppender = OPERATOR_CRITERION_APPENDER_MAP.get(criterion.getOperator()); - criterionAppender.appendCriterion(abstractWrapper, criterion.getProperty(), criterion.getValue()); + criterionAppender.appendCriterion(wrapper, example, criterion.getProperty(), criterion.getValue()); } } diff --git a/dorive-mybatis-plus/src/main/java/com/gitee/dorive/mybatis/plus/repository/MybatisPlusRepository.java b/dorive-mybatis-plus/src/main/java/com/gitee/dorive/mybatis/plus/repository/MybatisPlusRepository.java index de7641a7e48520f68e3aef93b2ec7b2669f50b49..b4d9f5d520945c6bf9a4b5728d760e21b5bd93af 100644 --- a/dorive-mybatis-plus/src/main/java/com/gitee/dorive/mybatis/plus/repository/MybatisPlusRepository.java +++ b/dorive-mybatis-plus/src/main/java/com/gitee/dorive/mybatis/plus/repository/MybatisPlusRepository.java @@ -34,11 +34,12 @@ import com.gitee.dorive.query.api.QueryExecutor; import com.gitee.dorive.query.entity.QueryContext; import com.gitee.dorive.query.entity.QueryWrapper; import com.gitee.dorive.ref.repository.AbstractRefRepository; +import com.gitee.dorive.sql.api.CountQuerier; import com.gitee.dorive.sql.api.SqlRunner; -import com.gitee.dorive.sql.impl.CountQuerier; -import com.gitee.dorive.sql.impl.SegmentBuilder; -import com.gitee.dorive.sql.impl.SqlQueryExecutor; -import com.gitee.dorive.sql.impl.UnionExecutor; +import com.gitee.dorive.sql.entity.common.CountQuery; +import com.gitee.dorive.sql.impl.count.DefaultCountQuerier; +import com.gitee.dorive.sql.impl.executor.SqlQueryExecutor; +import com.gitee.dorive.sql.impl.executor.UnionExecutor; import lombok.Data; import lombok.EqualsAndHashCode; import org.apache.commons.lang3.StringUtils; @@ -52,19 +53,18 @@ import java.util.Map; @Data @EqualsAndHashCode(callSuper = false) -public class MybatisPlusRepository extends AbstractRefRepository { +public class MybatisPlusRepository extends AbstractRefRepository implements CountQuerier { private SqlRunner sqlRunner; private QueryExecutor sqlQueryExecutor; - private CountQuerier countQuerier; + private CountQuerier defaultCountQuerier; @Override public void afterPropertiesSet() throws Exception { ImplFactory implFactory = getApplicationContext().getBean(ImplFactory.class); this.sqlRunner = implFactory.getInstance(SqlRunner.class); - SegmentBuilder segmentBuilder = new SegmentBuilder(); - this.sqlQueryExecutor = new SqlQueryExecutor(this, segmentBuilder, this.sqlRunner); - this.countQuerier = new CountQuerier(this, segmentBuilder, this.sqlRunner); + this.sqlQueryExecutor = new SqlQueryExecutor(this, this.sqlRunner); + this.defaultCountQuerier = new DefaultCountQuerier(this, this.sqlRunner); super.afterPropertiesSet(); } @@ -135,4 +135,9 @@ public class MybatisPlusRepository extends AbstractRefRepository { return super.adaptiveQueryExecutor(queryContext, queryWrapper); } + @Override + public Map selectCountMap(Context context, CountQuery countQuery) { + return defaultCountQuerier.selectCountMap(context, countQuery); + } + } diff --git a/dorive-proxy/pom.xml b/dorive-proxy/pom.xml index 162bdd4ce846f60beb42290e95b42fc8028dcbfb..52aebc36577608547f38828f1f745090cebac8ff 100644 --- a/dorive-proxy/pom.xml +++ b/dorive-proxy/pom.xml @@ -6,7 +6,7 @@ com.gitee.digital-engine dorive - 3.4.3.3 + 3.4.3.4 dorive-proxy diff --git a/dorive-query/pom.xml b/dorive-query/pom.xml index 032a77afcebae3332e2035e2b683b34c4f20fb36..9da0aa6dad696d3fd9e8f2ec89c133b2231d31fa 100644 --- a/dorive-query/pom.xml +++ b/dorive-query/pom.xml @@ -6,7 +6,7 @@ com.gitee.digital-engine dorive - 3.4.3.3 + 3.4.3.4 dorive-query diff --git a/dorive-query/src/main/java/com/gitee/dorive/query/entity/MergedRepository.java b/dorive-query/src/main/java/com/gitee/dorive/query/entity/MergedRepository.java index a4c107f80662ffa3bbdf5ea3dd442912e421b0b5..b957a4efb2210b9136e486c18aca4fe654564534 100644 --- a/dorive-query/src/main/java/com/gitee/dorive/query/entity/MergedRepository.java +++ b/dorive-query/src/main/java/com/gitee/dorive/query/entity/MergedRepository.java @@ -17,7 +17,8 @@ package com.gitee.dorive.query.entity; -import com.gitee.dorive.core.impl.binder.PropertyBinder; +import com.gitee.dorive.core.impl.binder.StrongBinder; +import com.gitee.dorive.core.impl.binder.ValueBinder; import com.gitee.dorive.core.repository.CommonRepository; import lombok.AllArgsConstructor; import lombok.Data; @@ -34,7 +35,8 @@ public class MergedRepository { private String relativeAccessPath; private boolean merged; private CommonRepository definedRepository; - private Map> mergedBindersMap; + private Map> relativeValueBindersMap; + private Map> relativeStrongBindersMap; private CommonRepository executedRepository; private Integer order; diff --git a/dorive-query/src/main/java/com/gitee/dorive/query/impl/executor/StepwiseQueryExecutor.java b/dorive-query/src/main/java/com/gitee/dorive/query/impl/executor/StepwiseQueryExecutor.java index 7654af28bd364dde1d5e3ec8aa213c264c9a5973..624e84c6fbd73ebd1650c07acf6d850049cdb912 100644 --- a/dorive-query/src/main/java/com/gitee/dorive/query/impl/executor/StepwiseQueryExecutor.java +++ b/dorive-query/src/main/java/com/gitee/dorive/query/impl/executor/StepwiseQueryExecutor.java @@ -21,7 +21,8 @@ import com.gitee.dorive.core.api.context.Context; import com.gitee.dorive.core.entity.executor.Example; import com.gitee.dorive.core.entity.executor.InnerExample; import com.gitee.dorive.core.entity.executor.Result; -import com.gitee.dorive.core.impl.binder.PropertyBinder; +import com.gitee.dorive.core.impl.binder.StrongBinder; +import com.gitee.dorive.core.impl.binder.ValueBinder; import com.gitee.dorive.core.impl.resolver.BinderResolver; import com.gitee.dorive.core.repository.CommonRepository; import com.gitee.dorive.core.util.MultiInBuilder; @@ -33,10 +34,12 @@ import com.gitee.dorive.query.repository.AbstractQueryRepository; import lombok.AllArgsConstructor; import lombok.Data; +import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; public class StepwiseQueryExecutor extends AbstractQueryExecutor { @@ -81,19 +84,17 @@ public class StepwiseQueryExecutor extends AbstractQueryExecutor { boolean abandoned = exampleWrapper.isAbandoned(); CommonRepository definedRepository = mergedRepository.getDefinedRepository(); - Map> mergedBindersMap = mergedRepository.getMergedBindersMap(); + Map> relativeValueBindersMap = mergedRepository.getRelativeValueBindersMap(); + Map> relativeStrongBindersMap = mergedRepository.getRelativeStrongBindersMap(); CommonRepository executedRepository = mergedRepository.getExecutedRepository(); BinderResolver binderResolver = definedRepository.getBinderResolver(); - for (String relativeAccessPath : mergedBindersMap.keySet()) { - ExampleWrapper targetExampleWrapper = exampleWrapperMap.get(relativeAccessPath); - if (targetExampleWrapper != null) { - if (targetExampleWrapper.isAbandoned()) { - abandoned = true; - break; - } - } + if (!abandoned) { + abandoned = determineAbandon(exampleWrapperMap, relativeValueBindersMap.keySet()); + } + if (!abandoned) { + abandoned = determineAbandon(exampleWrapperMap, relativeStrongBindersMap.keySet()); } List entities; @@ -108,9 +109,21 @@ public class StepwiseQueryExecutor extends AbstractQueryExecutor { return; } - for (Map.Entry> entry : mergedBindersMap.entrySet()) { - String relativeAccessPath = entry.getKey(); - List binders = entry.getValue(); + relativeValueBindersMap.forEach((relativeAccessPath, valueBinders) -> { + ExampleWrapper targetExampleWrapper = exampleWrapperMap.get(relativeAccessPath); + if (targetExampleWrapper != null) { + Example targetExample = targetExampleWrapper.getExample(); + for (ValueBinder valueBinder : valueBinders) { + Object fieldValue = valueBinder.getFieldValue(context, null); + if (fieldValue != null) { + String boundName = valueBinder.getBoundName(); + targetExample.eq(boundName, fieldValue); + } + } + } + }); + + relativeStrongBindersMap.forEach((relativeAccessPath, strongBinders) -> { ExampleWrapper targetExampleWrapper = exampleWrapperMap.get(relativeAccessPath); if (targetExampleWrapper != null) { if (entities.isEmpty()) { @@ -118,11 +131,11 @@ public class StepwiseQueryExecutor extends AbstractQueryExecutor { return; } Example targetExample = targetExampleWrapper.getExample(); - if (binders.size() == 1) { - PropertyBinder binder = binders.get(0); - List fieldValues = binder.collectFieldValues(context, entities); + if (strongBinders.size() == 1) { + StrongBinder strongBinder = strongBinders.get(0); + List fieldValues = collectFieldValues(context, entities, strongBinder); if (!fieldValues.isEmpty()) { - String boundName = binder.getBoundName(); + String boundName = strongBinder.getBoundName(); if (fieldValues.size() == 1) { targetExample.eq(boundName, fieldValues.get(0)); } else { @@ -133,9 +146,11 @@ public class StepwiseQueryExecutor extends AbstractQueryExecutor { } } else { - List aliases = binders.stream().map(PropertyBinder::getBindAlias).collect(Collectors.toList()); + List aliases = strongBinders.stream() + .map(binder -> binder.getBoundBinder().getBindAlias()) + .collect(Collectors.toList()); MultiInBuilder builder = new MultiInBuilder(aliases, entities.size()); - collectFieldValues(context, entities, binders, builder); + collectFieldValues(context, entities, strongBinders, builder); if (!builder.isEmpty()) { targetExample.getCriteria().add(builder.toCriterion()); } else { @@ -143,16 +158,40 @@ public class StepwiseQueryExecutor extends AbstractQueryExecutor { } } } - } + }); }); } - private void collectFieldValues(Context context, List entities, List binders, MultiInBuilder builder) { + private boolean determineAbandon(Map exampleWrapperMap, Set relativeAccessPaths) { + for (String relativeAccessPath : relativeAccessPaths) { + ExampleWrapper targetExampleWrapper = exampleWrapperMap.get(relativeAccessPath); + if (targetExampleWrapper != null) { + if (targetExampleWrapper.isAbandoned()) { + return true; + } + } + } + return false; + } + + private List collectFieldValues(Context context, List entities, StrongBinder strongBinder) { + List fieldValues = new ArrayList<>(entities.size()); + for (Object entity : entities) { + Object fieldValue = strongBinder.getFieldValue(context, entity); + if (fieldValue != null) { + fieldValue = strongBinder.output(context, fieldValue); + fieldValues.add(fieldValue); + } + } + return fieldValues; + } + + private void collectFieldValues(Context context, List entities, List strongBinders, MultiInBuilder builder) { for (Object entity : entities) { - for (PropertyBinder binder : binders) { - Object fieldValue = binder.getFieldValue(context, entity); + for (StrongBinder strongBinder : strongBinders) { + Object fieldValue = strongBinder.getFieldValue(context, entity); if (fieldValue != null) { - fieldValue = binder.output(context, fieldValue); + fieldValue = strongBinder.output(context, fieldValue); builder.append(fieldValue); } else { builder.clearRemainder(); diff --git a/dorive-query/src/main/java/com/gitee/dorive/query/impl/resolver/MergedRepositoryResolver.java b/dorive-query/src/main/java/com/gitee/dorive/query/impl/resolver/MergedRepositoryResolver.java index bcbef8da4778c38bf012af5e3fce713daf0d8d7e..7cd5aab9b3629f8e5e042f604626c7b2bc2fba05 100644 --- a/dorive-query/src/main/java/com/gitee/dorive/query/impl/resolver/MergedRepositoryResolver.java +++ b/dorive-query/src/main/java/com/gitee/dorive/query/impl/resolver/MergedRepositoryResolver.java @@ -18,12 +18,14 @@ package com.gitee.dorive.query.impl.resolver; import cn.hutool.core.util.StrUtil; -import com.gitee.dorive.query.entity.MergedRepository; -import com.gitee.dorive.core.impl.binder.PropertyBinder; +import com.gitee.dorive.core.impl.binder.BoundBinder; +import com.gitee.dorive.core.impl.binder.StrongBinder; +import com.gitee.dorive.core.impl.binder.ValueBinder; import com.gitee.dorive.core.impl.resolver.BinderResolver; import com.gitee.dorive.core.repository.AbstractContextRepository; import com.gitee.dorive.core.repository.AbstractRepository; import com.gitee.dorive.core.repository.CommonRepository; +import com.gitee.dorive.query.entity.MergedRepository; import lombok.Data; import org.apache.commons.lang3.StringUtils; @@ -76,7 +78,8 @@ public class MergedRepositoryResolver { relativeAccessPath, abstractContextRepository != null, repository, - getMergedBindersMap(lastAccessPath, repository), + getRelativeValueBindersMap(lastAccessPath, repository), + getRelativeStrongBindersMap(lastAccessPath, repository), executedRepository, mergedRepositoryMap.size() + 1); addMergedRepository(mergedRepository); @@ -89,16 +92,29 @@ public class MergedRepositoryResolver { } } - private Map> getMergedBindersMap(String lastAccessPath, CommonRepository repository) { + private Map> getRelativeValueBindersMap(String lastAccessPath, CommonRepository repository) { + BinderResolver binderResolver = repository.getBinderResolver(); + List valueBinders = binderResolver.getValueBinders(); + Map> relativeValueBindersMap = new LinkedHashMap<>(); + for (ValueBinder valueBinder : valueBinders) { + String relativeAccessPath = lastAccessPath + valueBinder.getBelongAccessPath(); + List existBinders = relativeValueBindersMap.computeIfAbsent(relativeAccessPath, key -> new ArrayList<>(4)); + existBinders.add(valueBinder); + } + return relativeValueBindersMap; + } + + private Map> getRelativeStrongBindersMap(String lastAccessPath, CommonRepository repository) { BinderResolver binderResolver = repository.getBinderResolver(); - List propertyBinders = binderResolver.getPropertyBinders(); - Map> mergedBindersMap = new LinkedHashMap<>(); - for (PropertyBinder propertyBinder : propertyBinders) { - String relativeAccessPath = lastAccessPath + propertyBinder.getBelongAccessPath(); - List existPropertyBinders = mergedBindersMap.computeIfAbsent(relativeAccessPath, key -> new ArrayList<>(4)); - existPropertyBinders.add(propertyBinder); + List strongBinders = binderResolver.getStrongBinders(); + Map> relativeStrongBindersMap = new LinkedHashMap<>(); + for (StrongBinder strongBinder : strongBinders) { + BoundBinder boundBinder = strongBinder.getBoundBinder(); + String relativeAccessPath = lastAccessPath + boundBinder.getBelongAccessPath(); + List existBinders = relativeStrongBindersMap.computeIfAbsent(relativeAccessPath, key -> new ArrayList<>(4)); + existBinders.add(strongBinder); } - return mergedBindersMap; + return relativeStrongBindersMap; } private void addMergedRepository(MergedRepository mergedRepository) { diff --git a/dorive-query/src/main/java/com/gitee/dorive/query/repository/AbstractQueryRepository.java b/dorive-query/src/main/java/com/gitee/dorive/query/repository/AbstractQueryRepository.java index ad943bed02b479d8940e96d0726cda4235e9ef23..ea1784a893efca4b42f75a39e7cfba35bc0b66de 100644 --- a/dorive-query/src/main/java/com/gitee/dorive/query/repository/AbstractQueryRepository.java +++ b/dorive-query/src/main/java/com/gitee/dorive/query/repository/AbstractQueryRepository.java @@ -20,6 +20,7 @@ package com.gitee.dorive.query.repository; import cn.hutool.core.lang.Assert; import com.gitee.dorive.api.annotation.Repository; import com.gitee.dorive.core.api.context.Context; +import com.gitee.dorive.core.api.context.Matcher; import com.gitee.dorive.core.api.context.Options; import com.gitee.dorive.core.entity.executor.Page; import com.gitee.dorive.core.entity.executor.Result; @@ -37,6 +38,7 @@ import com.gitee.dorive.query.impl.resolver.QueryResolver; import com.gitee.dorive.query.impl.resolver.QueryTypeResolver; import lombok.Data; import lombok.EqualsAndHashCode; +import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.core.annotation.AnnotatedElementUtils; @@ -58,10 +60,8 @@ public abstract class AbstractQueryRepository extends AbstractEventReposi super.afterPropertiesSet(); Repository repository = AnnotatedElementUtils.getMergedAnnotation(this.getClass(), Repository.class); this.queryScanDef = QueryScanDef.fromElement(this.getClass()); - if (repository != null && this.queryScanDef != null) { - if (StringUtils.isBlank(this.queryScanDef.getRegex())) { - this.queryScanDef.setRegex("^" + getEntityClass().getSimpleName() + ".*"); - } + if (repository != null && queryScanDef != null) { + renewQueryScanDef(); this.mergedRepositoryResolver = new MergedRepositoryResolver(this); this.queryTypeResolver = new QueryTypeResolver(this); this.simpleQueryExecutor = new SimpleQueryExecutor(this); @@ -69,6 +69,20 @@ public abstract class AbstractQueryRepository extends AbstractEventReposi } } + private void renewQueryScanDef() { + String[] value = queryScanDef.getValue(); + String regex = queryScanDef.getRegex(); + Class[] queries = queryScanDef.getQueries(); + if (ArrayUtils.isEmpty(value) && ArrayUtils.isEmpty(queries)) { + String packageName = this.getClass().getPackage().getName(); + String parentPackageName = packageName.substring(0, packageName.lastIndexOf(".")); + queryScanDef.setValue(new String[]{parentPackageName + ".query"}); + } + if (StringUtils.isBlank(regex)) { + queryScanDef.setRegex("^" + getEntityClass().getSimpleName() + ".*"); + } + } + @Override @SuppressWarnings("unchecked") public List selectByQuery(Options options, Object query) { @@ -98,6 +112,10 @@ public abstract class AbstractQueryRepository extends AbstractEventReposi @Override public Result executeQuery(QueryContext queryContext, QueryWrapper queryWrapper) { resolveQuery(queryContext, queryWrapper); + Matcher matcher = getRootRepository(); + if (!matcher.matches(queryContext.getContext())) { + return queryContext.newEmptyResult(); + } if (queryContext.isSimpleQuery()) { return simpleQueryExecutor.executeQuery(queryContext, queryWrapper); } else { diff --git a/dorive-ref/pom.xml b/dorive-ref/pom.xml index 28b8008121254f440d7467b1555c19ee7da073b5..8281b7ddeebde7e3652c299ab5d7b23b6c473a2a 100644 --- a/dorive-ref/pom.xml +++ b/dorive-ref/pom.xml @@ -6,7 +6,7 @@ com.gitee.digital-engine dorive - 3.4.3.3 + 3.4.3.4 dorive-ref diff --git a/dorive-spring-boot-starter/pom.xml b/dorive-spring-boot-starter/pom.xml index d43c948a51414c5fd3d963f74c054ca8f0908d13..6605196a9016378f349b5b91801fc2e920f1dc98 100644 --- a/dorive-spring-boot-starter/pom.xml +++ b/dorive-spring-boot-starter/pom.xml @@ -6,7 +6,7 @@ com.gitee.digital-engine dorive - 3.4.3.3 + 3.4.3.4 dorive-spring-boot-starter diff --git a/dorive-sql/pom.xml b/dorive-sql/pom.xml index bc1a34710b44c72d319d8ac0b5d25292ee5370d1..739265873dfa74d6d3d617003236eb00f98bbb87 100644 --- a/dorive-sql/pom.xml +++ b/dorive-sql/pom.xml @@ -6,7 +6,7 @@ com.gitee.digital-engine dorive - 3.4.3.3 + 3.4.3.4 dorive-sql diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/impl/processor/PropertyProcessor.java b/dorive-sql/src/main/java/com/gitee/dorive/sql/api/CountQuerier.java similarity index 55% rename from dorive-core/src/main/java/com/gitee/dorive/core/impl/processor/PropertyProcessor.java rename to dorive-sql/src/main/java/com/gitee/dorive/sql/api/CountQuerier.java index 0bdb69e0f9dab56f25f2ef1627b42d8cea54cfc7..9317f540a84e195f78f8b6c2ca7f6b0f63c6c9e8 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/impl/processor/PropertyProcessor.java +++ b/dorive-sql/src/main/java/com/gitee/dorive/sql/api/CountQuerier.java @@ -15,28 +15,15 @@ * limitations under the License. */ -package com.gitee.dorive.core.impl.processor; +package com.gitee.dorive.sql.api; -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.collection.CollUtil; import com.gitee.dorive.core.api.context.Context; -import lombok.Data; -import lombok.EqualsAndHashCode; +import com.gitee.dorive.sql.entity.common.CountQuery; -import java.util.Collection; +import java.util.Map; -@Data -@EqualsAndHashCode(callSuper = false) -public class PropertyProcessor extends DefaultProcessor { +public interface CountQuerier { - @Override - public Object input(Context context, Object value) { - String property = getBindingDef().getProperty(); - if (value instanceof Collection) { - return CollUtil.map((Collection) value, item -> BeanUtil.getFieldValue(item, property), true); - } else { - return BeanUtil.getFieldValue(value, property); - } - } + Map selectCountMap(Context context, CountQuery countQuery); } diff --git a/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/common/CountQuery.java b/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/common/CountQuery.java new file mode 100644 index 0000000000000000000000000000000000000000..20a5c468d23b44b64d630945a0bb8ac991cd0204 --- /dev/null +++ b/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/common/CountQuery.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.gitee.dorive.sql.entity.common; + +import com.gitee.dorive.core.api.context.Selector; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Collections; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CountQuery { + + private Object query; + private boolean distinct = true; + private Selector selector; + private List countBy; + private List groupBy; + + public CountQuery(Object query, String countBy, String groupBy) { + this.query = query; + this.countBy = Collections.singletonList(countBy); + this.groupBy = Collections.singletonList(groupBy); + } + +} diff --git a/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/OnSegment.java b/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/common/SegmentInfo.java similarity index 75% rename from dorive-sql/src/main/java/com/gitee/dorive/sql/entity/OnSegment.java rename to dorive-sql/src/main/java/com/gitee/dorive/sql/entity/common/SegmentInfo.java index 9773da95ead6dbf8f311696f699f874b7865a2ac..93638db389eb7ad144bc175b304a8eb53c99e544 100644 --- a/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/OnSegment.java +++ b/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/common/SegmentInfo.java @@ -15,23 +15,15 @@ * limitations under the License. */ -package com.gitee.dorive.sql.entity; +package com.gitee.dorive.sql.entity.common; +import com.gitee.dorive.api.entity.element.EntityEle; import lombok.AllArgsConstructor; import lombok.Data; @Data @AllArgsConstructor -public class OnSegment { - +public class SegmentInfo { private String tableAlias; - private String column; - private String joinTableAlias; - private String joinColumn; - - @Override - public String toString() { - return tableAlias + "." + column + " = " + joinTableAlias + "." + joinColumn; - } - + private EntityEle entityEle; } diff --git a/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/ArgSegment.java b/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/segment/ArgSegment.java similarity index 96% rename from dorive-sql/src/main/java/com/gitee/dorive/sql/entity/ArgSegment.java rename to dorive-sql/src/main/java/com/gitee/dorive/sql/entity/segment/ArgSegment.java index c56c2079ca41c57fb841fd075733485da791872b..5c6e73563d10aa373ebe8fa571bf47ecde1804e6 100644 --- a/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/ArgSegment.java +++ b/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/segment/ArgSegment.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package com.gitee.dorive.sql.entity; +package com.gitee.dorive.sql.entity.segment; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/JoinSegment.java b/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/segment/JoinSegment.java similarity index 95% rename from dorive-sql/src/main/java/com/gitee/dorive/sql/entity/JoinSegment.java rename to dorive-sql/src/main/java/com/gitee/dorive/sql/entity/segment/JoinSegment.java index f2b9fe25d4d67a9ad832a3d56f9025222dbd6906..26aafc9bd7d83c54fd4d132a4f8fe52ea087dcb8 100644 --- a/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/JoinSegment.java +++ b/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/segment/JoinSegment.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package com.gitee.dorive.sql.entity; +package com.gitee.dorive.sql.entity.segment; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/segment/OnSegment.java b/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/segment/OnSegment.java new file mode 100644 index 0000000000000000000000000000000000000000..7d0b6749c0a5ded8d23432eb7f4680dc265ee9ce --- /dev/null +++ b/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/segment/OnSegment.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.gitee.dorive.sql.entity.segment; + +import lombok.AllArgsConstructor; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +@Data +@AllArgsConstructor +public class OnSegment { + + private String tableAlias; + private String column; + private String joinTableAlias; + private String joinColumn; + private String literal; + + public OnSegment(String tableAlias, String column, String joinTableAlias, String joinColumn) { + this.tableAlias = tableAlias; + this.column = column; + this.joinTableAlias = joinTableAlias; + this.joinColumn = joinColumn; + } + + public OnSegment(String joinTableAlias, String joinColumn, String literal) { + this.joinTableAlias = joinTableAlias; + this.joinColumn = joinColumn; + this.literal = literal; + } + + @Override + public String toString() { + if (StringUtils.isNotBlank(tableAlias) && StringUtils.isNotBlank(column)) { + return tableAlias + "." + column + " = " + joinTableAlias + "." + joinColumn; + + } else if (StringUtils.isNotBlank(literal)) { + return joinTableAlias + "." + joinColumn + " = " + literal; + } + return tableAlias + "." + column + " = " + joinTableAlias + "." + joinColumn; + } + +} diff --git a/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/SelectSegment.java b/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/segment/SelectSegment.java similarity index 98% rename from dorive-sql/src/main/java/com/gitee/dorive/sql/entity/SelectSegment.java rename to dorive-sql/src/main/java/com/gitee/dorive/sql/entity/segment/SelectSegment.java index f01c1393bd5e4bd47a90b3fce51e05f327cbfe88..06d51b188a3cbd71dc43ab345a9f556a6189d01f 100644 --- a/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/SelectSegment.java +++ b/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/segment/SelectSegment.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package com.gitee.dorive.sql.entity; +package com.gitee.dorive.sql.entity.segment; import cn.hutool.core.util.StrUtil; import cn.hutool.db.sql.SqlBuilder; diff --git a/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/TableSegment.java b/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/segment/TableSegment.java similarity index 96% rename from dorive-sql/src/main/java/com/gitee/dorive/sql/entity/TableSegment.java rename to dorive-sql/src/main/java/com/gitee/dorive/sql/entity/segment/TableSegment.java index 5d563ff78174bc8dca9725f49dc9d2ef2c67e243..b51db1021d4f289727a57f90294f0d1fced955b1 100644 --- a/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/TableSegment.java +++ b/dorive-sql/src/main/java/com/gitee/dorive/sql/entity/segment/TableSegment.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package com.gitee.dorive.sql.entity; +package com.gitee.dorive.sql.entity.segment; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/dorive-sql/src/main/java/com/gitee/dorive/sql/impl/CountQuerier.java b/dorive-sql/src/main/java/com/gitee/dorive/sql/impl/count/DefaultCountQuerier.java similarity index 44% rename from dorive-sql/src/main/java/com/gitee/dorive/sql/impl/CountQuerier.java rename to dorive-sql/src/main/java/com/gitee/dorive/sql/impl/count/DefaultCountQuerier.java index 39bbd8f4b6781e833e0ff316e402572740bdce21..545b0284bf408538ca3ec91079a32752ac2d091a 100644 --- a/dorive-sql/src/main/java/com/gitee/dorive/sql/impl/CountQuerier.java +++ b/dorive-sql/src/main/java/com/gitee/dorive/sql/impl/count/DefaultCountQuerier.java @@ -15,21 +15,24 @@ * limitations under the License. */ -package com.gitee.dorive.sql.impl; +package com.gitee.dorive.sql.impl.count; +import cn.hutool.core.collection.CollUtil; import com.gitee.dorive.api.entity.element.EntityEle; import com.gitee.dorive.core.api.context.Context; import com.gitee.dorive.query.entity.QueryContext; -import com.gitee.dorive.query.entity.enums.ResultType; import com.gitee.dorive.query.entity.QueryWrapper; +import com.gitee.dorive.query.entity.enums.ResultType; import com.gitee.dorive.query.repository.AbstractQueryRepository; +import com.gitee.dorive.sql.api.CountQuerier; import com.gitee.dorive.sql.api.SqlRunner; -import com.gitee.dorive.sql.entity.SelectSegment; -import com.gitee.dorive.sql.entity.TableSegment; +import com.gitee.dorive.sql.entity.common.SegmentInfo; +import com.gitee.dorive.sql.entity.common.CountQuery; +import com.gitee.dorive.sql.entity.segment.SelectSegment; +import com.gitee.dorive.sql.entity.segment.TableSegment; +import com.gitee.dorive.sql.impl.segment.SegmentBuilder; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; -import lombok.NoArgsConstructor; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -38,51 +41,77 @@ import java.util.Map; @Data @AllArgsConstructor -public class CountQuerier { +public class DefaultCountQuerier implements CountQuerier { private AbstractQueryRepository repository; - private SegmentBuilder segmentBuilder; private SqlRunner sqlRunner; + @Override public Map selectCountMap(Context context, CountQuery countQuery) { QueryContext queryContext = new QueryContext(context, ResultType.COUNT); QueryWrapper queryWrapper = new QueryWrapper(countQuery.getQuery()); repository.resolveQuery(queryContext, queryWrapper); - SelectSegment selectSegment = segmentBuilder.buildSegment(queryContext); + SegmentBuilder segmentBuilder = new SegmentBuilder(queryContext); + SelectSegment selectSegment = segmentBuilder.buildSegment(context, countQuery.getSelector()); TableSegment tableSegment = selectSegment.getTableSegment(); List args = selectSegment.getArgs(); - String tableAlias = tableSegment.getTableAlias(); + String tableAlias = tableSegment.getTableAlias(); EntityEle entityEle = repository.getEntityEle(); - String countByColumn = tableAlias + "." + entityEle.toAlias(countQuery.getCountBy()); - String groupByColumn = tableAlias + "." + entityEle.toAlias(countQuery.getGroupBy()); - - List columns = new ArrayList<>(2); - columns.add(groupByColumn + " AS groupId"); + String countByExp = buildCountByExp(countQuery, segmentBuilder, tableAlias, entityEle); - String format = "COUNT(%s) AS total"; - String countByColumnStr = String.format(format, countQuery.isDistinct() ? "DISTINCT " + countByColumn : countByColumn); - columns.add(countByColumnStr); + String groupByPrefix = tableAlias + "."; + List groupBy = entityEle.toAliases(countQuery.getGroupBy()); + String groupByColumns = CollUtil.join(groupBy, ",", groupByPrefix, null); - selectSegment.setSelectColumns(columns); - selectSegment.setGroupBy("GROUP BY " + groupByColumn); + List selectColumns = new ArrayList<>(2); + selectColumns.add(groupByColumns); + selectColumns.add(String.format("COUNT(%s) AS total", countByExp)); + selectSegment.setSelectColumns(selectColumns); + selectSegment.setGroupBy("GROUP BY " + groupByColumns); List> resultMaps = sqlRunner.selectList(selectSegment.toString(), args.toArray()); Map countMap = new LinkedHashMap<>(resultMaps.size() * 4 / 3 + 1); - resultMaps.forEach(resultMap -> countMap.put(resultMap.get("groupId").toString(), (Long) resultMap.get("total"))); + resultMaps.forEach(resultMap -> countMap.put(buildKey(resultMap, groupBy), (Long) resultMap.get("total"))); return countMap; } - @Data - @Builder - @NoArgsConstructor - @AllArgsConstructor - public static class CountQuery { - private Object query; - private boolean distinct = true; - private String countBy; - private String groupBy; + private String buildCountByExp(CountQuery countQuery, SegmentBuilder segmentBuilder, String tableAlias, EntityEle entityEle) { + List segmentInfos = segmentBuilder.getMatchedSegmentInfos(); + if (segmentInfos != null && !segmentInfos.isEmpty()) { + SegmentInfo segmentInfo = segmentInfos.get(0); + tableAlias = segmentInfo.getTableAlias(); + entityEle = segmentInfo.getEntityEle(); + } + String countByPrefix = tableAlias + "."; + List countBy = entityEle.toAliases(countQuery.getCountBy()); + String countByStr = CollUtil.join(countBy, ",',',", countByPrefix, null); + + StringBuilder countByExp = new StringBuilder(); + if (countQuery.isDistinct()) { + countByExp.append("DISTINCT "); + } + if (countBy.size() == 1) { + countByExp.append(countByStr); + + } else if (countBy.size() > 1) { + countByExp.append("CONCAT(").append(countByStr).append(")"); + } + return countByExp.toString(); + } + + private String buildKey(Map resultMap, List groupBy) { + StringBuilder keyBuilder = new StringBuilder(); + for (String column : groupBy) { + String valueStr = String.valueOf(resultMap.get(column)).trim(); + keyBuilder.append(valueStr).append(", "); + } + int length = keyBuilder.length(); + if (length > 0) { + keyBuilder.delete(length - 2, length); + } + return keyBuilder.toString(); } } diff --git a/dorive-sql/src/main/java/com/gitee/dorive/sql/impl/SqlQueryExecutor.java b/dorive-sql/src/main/java/com/gitee/dorive/sql/impl/executor/SqlQueryExecutor.java similarity index 93% rename from dorive-sql/src/main/java/com/gitee/dorive/sql/impl/SqlQueryExecutor.java rename to dorive-sql/src/main/java/com/gitee/dorive/sql/impl/executor/SqlQueryExecutor.java index 98271b65761039459396fda662ffa713f1ee0459..de61be101ee178935afed30f7d3838137f2bf6ad 100644 --- a/dorive-sql/src/main/java/com/gitee/dorive/sql/impl/SqlQueryExecutor.java +++ b/dorive-sql/src/main/java/com/gitee/dorive/sql/impl/executor/SqlQueryExecutor.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package com.gitee.dorive.sql.impl; +package com.gitee.dorive.sql.impl.executor; import cn.hutool.core.collection.CollUtil; import com.gitee.dorive.api.entity.element.EntityEle; @@ -33,9 +33,10 @@ import com.gitee.dorive.query.entity.enums.ResultType; import com.gitee.dorive.query.impl.executor.AbstractQueryExecutor; import com.gitee.dorive.query.repository.AbstractQueryRepository; import com.gitee.dorive.sql.api.SqlRunner; -import com.gitee.dorive.sql.entity.ArgSegment; -import com.gitee.dorive.sql.entity.SelectSegment; -import com.gitee.dorive.sql.entity.TableSegment; +import com.gitee.dorive.sql.entity.segment.ArgSegment; +import com.gitee.dorive.sql.entity.segment.SelectSegment; +import com.gitee.dorive.sql.entity.segment.TableSegment; +import com.gitee.dorive.sql.impl.segment.SegmentBuilder; import lombok.Getter; import lombok.Setter; @@ -47,12 +48,10 @@ import java.util.Map; @Setter public class SqlQueryExecutor extends AbstractQueryExecutor { - private SegmentBuilder segmentBuilder; private SqlRunner sqlRunner; - public SqlQueryExecutor(AbstractQueryRepository repository, SegmentBuilder segmentBuilder, SqlRunner sqlRunner) { + public SqlQueryExecutor(AbstractQueryRepository repository, SqlRunner sqlRunner) { super(repository); - this.segmentBuilder = segmentBuilder; this.sqlRunner = sqlRunner; } @@ -73,7 +72,8 @@ public class SqlQueryExecutor extends AbstractQueryExecutor { boolean needCount = queryContext.isNeedCount(); Result emptyResult = queryContext.newEmptyResult(); - SelectSegment selectSegment = segmentBuilder.buildSegment(queryContext); + SegmentBuilder segmentBuilder = new SegmentBuilder(queryContext); + SelectSegment selectSegment = segmentBuilder.buildSegment(context, null); char letter = selectSegment.getLetter(); TableSegment tableSegment = selectSegment.getTableSegment(); List argSegments = selectSegment.getArgSegments(); diff --git a/dorive-sql/src/main/java/com/gitee/dorive/sql/impl/UnionExecutor.java b/dorive-sql/src/main/java/com/gitee/dorive/sql/impl/executor/UnionExecutor.java similarity index 99% rename from dorive-sql/src/main/java/com/gitee/dorive/sql/impl/UnionExecutor.java rename to dorive-sql/src/main/java/com/gitee/dorive/sql/impl/executor/UnionExecutor.java index f9db3dba5b05f5510045593ca6f0a4b40dcf4a11..a6122243e2411acfc4f436390e4d2aa65f1c7a47 100644 --- a/dorive-sql/src/main/java/com/gitee/dorive/sql/impl/UnionExecutor.java +++ b/dorive-sql/src/main/java/com/gitee/dorive/sql/impl/executor/UnionExecutor.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package com.gitee.dorive.sql.impl; +package com.gitee.dorive.sql.impl.executor; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; diff --git a/dorive-sql/src/main/java/com/gitee/dorive/sql/impl/SegmentBuilder.java b/dorive-sql/src/main/java/com/gitee/dorive/sql/impl/segment/SegmentBuilder.java similarity index 67% rename from dorive-sql/src/main/java/com/gitee/dorive/sql/impl/SegmentBuilder.java rename to dorive-sql/src/main/java/com/gitee/dorive/sql/impl/segment/SegmentBuilder.java index e34673e084cfcf4e20882246be70b8b8ab2a6d19..04d8ae6349498fd4b0fc5a2299627b728dc83972 100644 --- a/dorive-sql/src/main/java/com/gitee/dorive/sql/impl/SegmentBuilder.java +++ b/dorive-sql/src/main/java/com/gitee/dorive/sql/impl/segment/SegmentBuilder.java @@ -15,16 +15,19 @@ * limitations under the License. */ -package com.gitee.dorive.sql.impl; +package com.gitee.dorive.sql.impl.segment; import com.gitee.dorive.api.constant.Operator; import com.gitee.dorive.api.entity.element.EntityEle; import com.gitee.dorive.core.api.context.Context; +import com.gitee.dorive.core.api.context.Selector; import com.gitee.dorive.core.entity.common.EntityStoreInfo; import com.gitee.dorive.core.entity.executor.Criterion; import com.gitee.dorive.core.entity.executor.Example; import com.gitee.dorive.core.entity.executor.InnerExample; -import com.gitee.dorive.core.impl.binder.PropertyBinder; +import com.gitee.dorive.core.impl.binder.BoundBinder; +import com.gitee.dorive.core.impl.binder.StrongBinder; +import com.gitee.dorive.core.impl.binder.ValueBinder; import com.gitee.dorive.core.impl.executor.ExampleExecutor; import com.gitee.dorive.core.impl.resolver.BinderResolver; import com.gitee.dorive.core.repository.AbstractContextRepository; @@ -33,7 +36,8 @@ import com.gitee.dorive.core.util.CriterionUtils; import com.gitee.dorive.query.entity.MergedRepository; import com.gitee.dorive.query.entity.QueryContext; import com.gitee.dorive.query.impl.resolver.QueryResolver; -import com.gitee.dorive.sql.entity.*; +import com.gitee.dorive.sql.entity.common.SegmentInfo; +import com.gitee.dorive.sql.entity.segment.*; import lombok.AllArgsConstructor; import lombok.Data; @@ -42,11 +46,19 @@ import java.util.*; @Data public class SegmentBuilder { - public SelectSegment buildSegment(QueryContext queryContext) { - Context context = queryContext.getContext(); - QueryResolver queryResolver = queryContext.getQueryResolver(); - Map exampleMap = queryContext.getExampleMap(); + private QueryResolver queryResolver; + private Map exampleMap; + private List matchedSegmentInfos; + public SegmentBuilder(QueryContext queryContext) { + this.queryResolver = queryContext.getQueryResolver(); + this.exampleMap = queryContext.getExampleMap(); + } + + public SelectSegment buildSegment(Context context, Selector selector) { + if (selector != null) { + this.matchedSegmentInfos = new ArrayList<>(8); + } List mergedRepositories = queryResolver.getMergedRepositories(); Map nodeMap = new LinkedHashMap<>(mergedRepositories.size() * 4 / 3 + 1); SelectSegment selectSegment = new SelectSegment(); @@ -55,6 +67,7 @@ public class SegmentBuilder { for (MergedRepository mergedRepository : mergedRepositories) { String absoluteAccessPath = mergedRepository.getAbsoluteAccessPath(); String relativeAccessPath = mergedRepository.getRelativeAccessPath(); + CommonRepository definedRepository = mergedRepository.getDefinedRepository(); CommonRepository executedRepository = mergedRepository.getExecutedRepository(); EntityEle entityEle = executedRepository.getEntityEle(); @@ -63,10 +76,17 @@ public class SegmentBuilder { String tableName = entityStoreInfo.getTableName(); String tableAlias = selectSegment.generateTableAlias(); + + SegmentInfo segmentInfo = new SegmentInfo(tableAlias, entityEle); + boolean isMatch = selector != null && definedRepository.matches(selector); + if (isMatch) { + matchedSegmentInfos.add(segmentInfo); + } + Example example = exampleMap.computeIfAbsent(absoluteAccessPath, key -> new InnerExample(Collections.emptyList())); exampleExecutor.convert(context, example); - TableSegment tableSegment = new TableSegment(tableName, tableAlias, example.isNotEmpty(), new ArrayList<>(example.getCriteria().size())); + TableSegment tableSegment = new TableSegment(tableName, tableAlias, example.isNotEmpty() || isMatch, new ArrayList<>(example.getCriteria().size())); Node node = new Node(tableSegment, new ArrayList<>(4)); nodeMap.put(relativeAccessPath, node); @@ -74,7 +94,7 @@ public class SegmentBuilder { selectSegment.setTableSegment(tableSegment); } else { - List onSegments = newOnSegments(nodeMap, mergedRepository, node); + List onSegments = newOnSegments(context, nodeMap, mergedRepository, node); if (onSegments.isEmpty()) { nodeMap.remove(relativeAccessPath); continue; @@ -91,16 +111,33 @@ public class SegmentBuilder { return selectSegment; } - private List newOnSegments(Map nodeMap, MergedRepository mergedRepository, Node node) { + private List newOnSegments(Context context, Map nodeMap, MergedRepository mergedRepository, Node node) { String lastAccessPath = mergedRepository.getLastAccessPath(); CommonRepository definedRepository = mergedRepository.getDefinedRepository(); BinderResolver binderResolver = definedRepository.getBinderResolver(); - List propertyBinders = binderResolver.getPropertyBinders(); + List valueBinders = binderResolver.getValueBinders(); + List strongBinders = binderResolver.getStrongBinders(); TableSegment tableSegment = node.getTableSegment(); - List onSegments = new ArrayList<>(propertyBinders.size()); - for (PropertyBinder propertyBinder : propertyBinders) { - String relativeAccessPath = lastAccessPath + propertyBinder.getBelongAccessPath(); + List onSegments = new ArrayList<>(strongBinders.size()); + for (ValueBinder valueBinder : valueBinders) { + String relativeAccessPath = lastAccessPath + valueBinder.getBelongAccessPath(); + Node targetNode = nodeMap.get(relativeAccessPath); + if (targetNode != null) { + TableSegment targetTableSegment = targetNode.getTableSegment(); + List children = targetNode.getChildren(); + if (!children.contains(node)) { + children.add(node); + } + OnSegment onSegment = new OnSegment( + targetTableSegment.getTableAlias(), valueBinder.getBindAlias(), + CriterionUtils.sqlParam(valueBinder.getFieldValue(context, null))); + onSegments.add(onSegment); + } + } + for (StrongBinder strongBinder : strongBinders) { + BoundBinder boundBinder = strongBinder.getBoundBinder(); + String relativeAccessPath = lastAccessPath + boundBinder.getBelongAccessPath(); Node targetNode = nodeMap.get(relativeAccessPath); if (targetNode != null) { TableSegment targetTableSegment = targetNode.getTableSegment(); @@ -108,8 +145,9 @@ public class SegmentBuilder { if (!children.contains(node)) { children.add(node); } - OnSegment onSegment = new OnSegment(tableSegment.getTableAlias(), propertyBinder.getAlias(), - targetTableSegment.getTableAlias(), propertyBinder.getBindAlias()); + OnSegment onSegment = new OnSegment( + tableSegment.getTableAlias(), strongBinder.getAlias(), + targetTableSegment.getTableAlias(), boundBinder.getBindAlias()); onSegments.add(onSegment); } } diff --git a/dorive-web/pom.xml b/dorive-web/pom.xml index d0151dc17fe433bcecf7ee4c8026d0b71823f00a..e0ee277b656d2707a7c6f4b677944bb1238fdbb2 100644 --- a/dorive-web/pom.xml +++ b/dorive-web/pom.xml @@ -6,7 +6,7 @@ com.gitee.digital-engine dorive - 3.4.3.3 + 3.4.3.4 dorive-web diff --git a/dorive-web/src/main/java/com/gitee/dorive/web/advice/ParameterControllerAdvice.java b/dorive-web/src/main/java/com/gitee/dorive/web/advice/ParameterControllerAdvice.java index db8e69e95af4b77565773a44639440136e0e6bee..4720d25569520708686edea94c22d7780a6b97c1 100644 --- a/dorive-web/src/main/java/com/gitee/dorive/web/advice/ParameterControllerAdvice.java +++ b/dorive-web/src/main/java/com/gitee/dorive/web/advice/ParameterControllerAdvice.java @@ -1,3 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.gitee.dorive.web.advice; import cn.hutool.core.date.DateUtil; diff --git a/pom.xml b/pom.xml index c223ef9a896d2934145dd078d8af57fdd7605cf0..0ab8cb4cf08326dfa2055a191a4549d39cd732e6 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.gitee.digital-engine dorive - 3.4.3.3 + 3.4.3.4 pom