diff --git a/dorive-api/src/main/java/com/gitee/dorive/api/constant/Operator.java b/dorive-api/src/main/java/com/gitee/dorive/api/constant/Operator.java index 17420285871a7fed22d2d57b86141d8dc4aa0f3b..797b7f1ddb1800aa71a42cc0307b259c16827c1f 100644 --- a/dorive-api/src/main/java/com/gitee/dorive/api/constant/Operator.java +++ b/dorive-api/src/main/java/com/gitee/dorive/api/constant/Operator.java @@ -31,4 +31,5 @@ public interface Operator { String IS_NULL = "IS NULL"; String IS_NOT_NULL = "IS NOT NULL"; String NULL_SWITCH = "NULL_SWITCH"; + String MULTI_IN = "MULTI_IN"; } diff --git a/dorive-api/src/main/java/com/gitee/dorive/api/entity/element/EntityEle.java b/dorive-api/src/main/java/com/gitee/dorive/api/entity/element/EntityEle.java index ffdb3ccf2edc30acb65e65ffe8d609dce92412af..2507279be820b921d82b41eabc5e43940e9f8de0 100644 --- a/dorive-api/src/main/java/com/gitee/dorive/api/entity/element/EntityEle.java +++ b/dorive-api/src/main/java/com/gitee/dorive/api/entity/element/EntityEle.java @@ -17,6 +17,7 @@ package com.gitee.dorive.api.entity.element; +import cn.hutool.core.util.StrUtil; import com.gitee.dorive.api.annotation.Aggregate; import com.gitee.dorive.api.api.PropProxy; import com.gitee.dorive.api.entity.def.BindingDef; @@ -25,7 +26,6 @@ import lombok.Data; import lombok.NoArgsConstructor; import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -42,16 +42,6 @@ public abstract class EntityEle { private PropProxy pkProxy; private Map aliasMap; - public static EntityEle fromElement(AnnotatedElement element) { - if (element instanceof Class) { - return EntityType.getInstance((Class) element); - - } else if (element instanceof Field) { - return new EntityField((Field) element); - } - throw new RuntimeException("Unsupported type!"); - } - public EntityEle(AnnotatedElement element) { this.element = element; this.entityDef = EntityDef.fromElement(element); @@ -74,17 +64,21 @@ public abstract class EntityEle { } public String toAlias(String property) { + if (property.contains(",")) { + List aliases = toAliases(StrUtil.splitTrim(property, ",")); + return StrUtil.join(",", aliases); + } return aliasMap.getOrDefault(property, property); } public List toAliases(List properties) { if (properties != null && !properties.isEmpty()) { - List columns = new ArrayList<>(properties.size()); + List aliases = new ArrayList<>(properties.size()); for (String property : properties) { String alias = toAlias(property); - columns.add(alias); + aliases.add(alias); } - return columns; + return aliases; } return properties; } diff --git a/dorive-api/src/main/java/com/gitee/dorive/api/entity/element/EntityField.java b/dorive-api/src/main/java/com/gitee/dorive/api/entity/element/EntityField.java index 592e69ee4ac512b016e0b4a672ab9225cca104fb..db9f7bf7935fa141756c847661ea062114eefa16 100644 --- a/dorive-api/src/main/java/com/gitee/dorive/api/entity/element/EntityField.java +++ b/dorive-api/src/main/java/com/gitee/dorive/api/entity/element/EntityField.java @@ -29,7 +29,7 @@ import java.lang.reflect.Type; import java.util.Collection; @Data -@EqualsAndHashCode(callSuper = true) +@EqualsAndHashCode(callSuper = false) public class EntityField extends EntityEle { private Field field; diff --git a/dorive-api/src/main/java/com/gitee/dorive/api/entity/element/EntityType.java b/dorive-api/src/main/java/com/gitee/dorive/api/entity/element/EntityType.java index 8c596aaaec58b250cd001985412ed5adfee5c6fa..b2cea697151e89bd38b23d0c718243fc3b0912de 100644 --- a/dorive-api/src/main/java/com/gitee/dorive/api/entity/element/EntityType.java +++ b/dorive-api/src/main/java/com/gitee/dorive/api/entity/element/EntityType.java @@ -39,7 +39,7 @@ import java.util.concurrent.ConcurrentHashMap; @Data @Slf4j -@EqualsAndHashCode(callSuper = true) +@EqualsAndHashCode(callSuper = false) public class EntityType extends EntityEle { private static final Map, EntityType> CACHE = new ConcurrentHashMap<>(); diff --git a/dorive-api/src/main/java/com/gitee/dorive/api/exception/CircularDependencyException.java b/dorive-api/src/main/java/com/gitee/dorive/api/exception/CircularDependencyException.java index 6d2d0a04f9bb21aea68aeaf4512ea8c66ab80812..21b0450915639bc649155cc261746017fb32ec83 100644 --- a/dorive-api/src/main/java/com/gitee/dorive/api/exception/CircularDependencyException.java +++ b/dorive-api/src/main/java/com/gitee/dorive/api/exception/CircularDependencyException.java @@ -1,10 +1,27 @@ +/* + * 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.api.exception; import lombok.Data; import lombok.EqualsAndHashCode; @Data -@EqualsAndHashCode(callSuper = true) +@EqualsAndHashCode(callSuper = false) public class CircularDependencyException extends RuntimeException { public CircularDependencyException(String message) { diff --git a/dorive-coating/src/main/java/com/gitee/dorive/coating/annotation/Property.java b/dorive-coating/src/main/java/com/gitee/dorive/coating/annotation/Property.java index 4fb5bfe1ed421f58c4cac1b6ce87e760ee38a59f..13bdaec6c5a90f4db0687d2f83718c9a35454eba 100644 --- a/dorive-coating/src/main/java/com/gitee/dorive/coating/annotation/Property.java +++ b/dorive-coating/src/main/java/com/gitee/dorive/coating/annotation/Property.java @@ -17,6 +17,8 @@ package com.gitee.dorive.coating.annotation; +import org.springframework.core.annotation.AliasFor; + import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; @@ -30,7 +32,11 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) public @interface Property { - String belongTo() default ""; + @AliasFor("belongTo") + String value() default "/"; + + @AliasFor("value") + String belongTo() default "/"; String field() default ""; diff --git a/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/CoatingRepositories.java b/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/CoatingCriteria.java similarity index 74% rename from dorive-coating/src/main/java/com/gitee/dorive/coating/entity/CoatingRepositories.java rename to dorive-coating/src/main/java/com/gitee/dorive/coating/entity/CoatingCriteria.java index cedfb04fc549101471482b0739bfd9dd9244bbff..7d573b18caa53100ef8a41eb3aa7ac02c9ce3274 100644 --- a/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/CoatingRepositories.java +++ b/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/CoatingCriteria.java @@ -17,17 +17,19 @@ package com.gitee.dorive.coating.entity; -import com.gitee.dorive.coating.entity.def.CoatingDef; +import com.gitee.dorive.core.entity.executor.Criterion; +import com.gitee.dorive.core.entity.executor.OrderBy; +import com.gitee.dorive.core.entity.executor.Page; import lombok.AllArgsConstructor; import lombok.Data; import java.util.List; +import java.util.Map; @Data @AllArgsConstructor -public class CoatingRepositories { - private CoatingDef coatingDef; - private List propertyRepositories; - private List reversedPropertyRepositories; - private SpecificProperties specificProperties; +public class CoatingCriteria { + private Map> criteriaMap; + private OrderBy orderBy; + private Page page; } diff --git a/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/Property.java b/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/CoatingField.java similarity index 85% rename from dorive-coating/src/main/java/com/gitee/dorive/coating/entity/Property.java rename to dorive-coating/src/main/java/com/gitee/dorive/coating/entity/CoatingField.java index 6c65c65a51da40663f1ca0fc440b387cc6819327..86f117095bfcaf50e53351a03fe821e0f9734e10 100644 --- a/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/Property.java +++ b/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/CoatingField.java @@ -29,7 +29,7 @@ import java.util.Collection; @Data @AllArgsConstructor -public class Property { +public class CoatingField { private Field field; private Class type; @@ -38,7 +38,7 @@ public class Property { private String name; private PropertyDef propertyDef; - public Property(Field field) { + public CoatingField(Field field) { this.field = field; this.type = field.getType(); this.collection = false; @@ -50,18 +50,11 @@ public class Property { Type actualTypeArgument = parameterizedType.getActualTypeArguments()[0]; this.genericType = (Class) actualTypeArgument; } - resolve(field); - } - - private void resolve(Field field) { propertyDef = PropertyDef.fromElement(field); - if (propertyDef != null) { - propertyDef.merge(name); - } } - public boolean isSameType(Property property) { - return type == property.getType() && genericType == property.getGenericType(); + public boolean isIgnore() { + return propertyDef.isIgnore(); } public Object getFieldValue(Object object) { diff --git a/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/PropertyRepository.java b/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/CoatingType.java similarity index 46% rename from dorive-coating/src/main/java/com/gitee/dorive/coating/entity/PropertyRepository.java rename to dorive-coating/src/main/java/com/gitee/dorive/coating/entity/CoatingType.java index d6c8299f5a5f2f2e7d77feb50ec44a09cb7efd7e..331542a6f775f566c48b85a58e01e048d17ab949 100644 --- a/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/PropertyRepository.java +++ b/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/CoatingType.java @@ -17,33 +17,50 @@ package com.gitee.dorive.coating.entity; +import com.gitee.dorive.coating.entity.def.CoatingDef; import com.gitee.dorive.coating.entity.def.PropertyDef; 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.core.entity.executor.Page; import lombok.AllArgsConstructor; import lombok.Data; +import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; @Data @AllArgsConstructor -public class PropertyRepository { +public class CoatingType { - private MergedRepository mergedRepository; - private List collectedProperties; + private CoatingDef coatingDef; + private List fields; + private SpecificFields specificFields; + private List mergedRepositories; + private List reversedMergedRepositories; - public Example newExampleByCoating(Object coating) { - Example example = new Example(); - for (Property property : collectedProperties) { - Object fieldValue = property.getFieldValue(coating); + public CoatingCriteria newCriteria(Object coating) { + Map> criteriaMap = newCriteriaMap(coating); + OrderBy orderBy = specificFields.newOrderBy(coating); + Page page = specificFields.newPage(coating); + return new CoatingCriteria(criteriaMap, orderBy, page); + } + + public Map> newCriteriaMap(Object coating) { + Map> criteriaMap = new LinkedHashMap<>(8); + for (CoatingField field : fields) { + Object fieldValue = field.getFieldValue(coating); if (fieldValue != null) { - PropertyDef propertyDef = property.getPropertyDef(); + PropertyDef propertyDef = field.getPropertyDef(); + String belongTo = propertyDef.getBelongTo(); String fieldName = propertyDef.getField(); String operator = propertyDef.getOperator(); - example.addCriterion(new Criterion(fieldName, operator, fieldValue)); + List criteria = criteriaMap.computeIfAbsent(belongTo, key -> new ArrayList<>(4)); + criteria.add(new Criterion(fieldName, operator, fieldValue)); } } - return example; + return criteriaMap; } } diff --git a/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/MergedRepository.java b/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/MergedRepository.java index 915baacaae26615d24a5885791a6ee95b53944a9..cb9eba4ac99c6fc9838405e21fe491e9ce789823 100644 --- a/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/MergedRepository.java +++ b/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/MergedRepository.java @@ -17,16 +17,29 @@ package com.gitee.dorive.coating.entity; +import com.gitee.dorive.core.impl.binder.PropertyBinder; import com.gitee.dorive.core.repository.CommonRepository; import lombok.AllArgsConstructor; import lombok.Data; +import java.util.List; +import java.util.Map; + @Data @AllArgsConstructor public class MergedRepository { + private String lastAccessPath; private String absoluteAccessPath; private boolean merged; + private String relativeAccessPath; private CommonRepository definedRepository; + private Map> mergedBindersMap; private CommonRepository executedRepository; + private Integer sequence; + + public String getName() { + return definedRepository.getEntityDef().getName(); + } + } diff --git a/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/SpecificProperties.java b/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/SpecificFields.java similarity index 74% rename from dorive-coating/src/main/java/com/gitee/dorive/coating/entity/SpecificProperties.java rename to dorive-coating/src/main/java/com/gitee/dorive/coating/entity/SpecificFields.java index ad948bbb69e9d8de011637f25593aaad43b119d5..421213c0f27dfd0c00dcf41d1bb39b7dc30f25ba 100644 --- a/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/SpecificProperties.java +++ b/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/SpecificFields.java @@ -27,37 +27,38 @@ import lombok.Data; import java.util.List; @Data -public class SpecificProperties { +public class SpecificFields { - private Property sortByProperty; - private Property orderProperty; - private Property pageProperty; - private Property limitProperty; + private CoatingField sortByField; + private CoatingField orderField; + private CoatingField pageField; + private CoatingField limitField; - public boolean addProperty(String fieldName, Property property) { + public boolean addProperty(CoatingField field) { + String fieldName = field.getName(); if ("sortBy".equals(fieldName)) { - sortByProperty = property; + sortByField = field; return true; } else if ("order".equals(fieldName)) { - orderProperty = property; + orderField = field; return true; } else if ("page".equals(fieldName)) { - pageProperty = property; + pageField = field; return true; } else if ("limit".equals(fieldName)) { - limitProperty = property; + limitField = field; return true; } return false; } public OrderBy newOrderBy(Object coating) { - if (sortByProperty != null && orderProperty != null) { - Object sortBy = sortByProperty.getFieldValue(coating); - Object order = orderProperty.getFieldValue(coating); + if (sortByField != null && orderField != null) { + Object sortBy = sortByField.getFieldValue(coating); + Object order = orderField.getFieldValue(coating); if (sortBy != null && order instanceof String) { List properties = StringUtils.toList(sortBy); if (properties != null && !properties.isEmpty()) { @@ -72,9 +73,9 @@ public class SpecificProperties { } public Page newPage(Object coating) { - if (pageProperty != null && limitProperty != null) { - Object page = pageProperty.getFieldValue(coating); - Object limit = limitProperty.getFieldValue(coating); + if (pageField != null && limitField != null) { + Object page = pageField.getFieldValue(coating); + Object limit = limitField.getFieldValue(coating); if (page != null && limit != null) { return new Page<>(Convert.convert(Long.class, page), Convert.convert(Long.class, limit)); } diff --git a/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/def/PropertyDef.java b/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/def/PropertyDef.java index 53c4004fcb08d7b891fb0d1542969cb313a32afe..c539613ed6e3c9e967d8b5bb64117459eaf8b256 100644 --- a/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/def/PropertyDef.java +++ b/dorive-coating/src/main/java/com/gitee/dorive/coating/entity/def/PropertyDef.java @@ -25,7 +25,7 @@ import lombok.NoArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.springframework.core.annotation.AnnotatedElementUtils; -import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Field; import java.util.Map; @Data @@ -38,18 +38,16 @@ public class PropertyDef { private String operator; private boolean ignore; - public static PropertyDef fromElement(AnnotatedElement element) { - if (element.isAnnotationPresent(Property.class)) { - Map attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(element, Property.class); - return BeanUtil.copyProperties(attributes, PropertyDef.class); - } - return new PropertyDef("", "", "=", false); - } - - public void merge(String fieldName) { - if (StringUtils.isBlank(field)) { - field = fieldName; + public static PropertyDef fromElement(Field field) { + if (field.isAnnotationPresent(Property.class)) { + Map attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(field, Property.class); + PropertyDef propertyDef = BeanUtil.copyProperties(attributes, PropertyDef.class); + if (StringUtils.isBlank(propertyDef.getField())) { + propertyDef.setField(field.getName()); + } + return propertyDef; } + return new PropertyDef("/", field.getName(), "=", false); } } diff --git a/dorive-coating/src/main/java/com/gitee/dorive/coating/impl/DefaultExampleBuilder.java b/dorive-coating/src/main/java/com/gitee/dorive/coating/impl/DefaultExampleBuilder.java index c137b1c801ace2b225180a5cede7db4a37e8ea85..e19f6ff46410e3d73cd2467a36d1697d80756f4f 100644 --- a/dorive-coating/src/main/java/com/gitee/dorive/coating/impl/DefaultExampleBuilder.java +++ b/dorive-coating/src/main/java/com/gitee/dorive/coating/impl/DefaultExampleBuilder.java @@ -18,15 +18,17 @@ package com.gitee.dorive.coating.impl; import cn.hutool.core.lang.Assert; -import com.gitee.dorive.api.entity.element.PropChain; import com.gitee.dorive.coating.api.ExampleBuilder; -import com.gitee.dorive.coating.entity.CoatingRepositories; +import com.gitee.dorive.coating.entity.CoatingCriteria; +import com.gitee.dorive.coating.entity.CoatingType; import com.gitee.dorive.coating.entity.MergedRepository; -import com.gitee.dorive.coating.entity.PropertyRepository; -import com.gitee.dorive.coating.impl.resolver.CoatingRepositoriesResolver; import com.gitee.dorive.coating.repository.AbstractCoatingRepository; import com.gitee.dorive.core.api.context.Context; +import com.gitee.dorive.core.entity.executor.Criterion; import com.gitee.dorive.core.entity.executor.Example; +import com.gitee.dorive.core.entity.executor.MultiInBuilder; +import com.gitee.dorive.core.entity.executor.OrderBy; +import com.gitee.dorive.core.entity.executor.Page; import com.gitee.dorive.core.impl.binder.PropertyBinder; import com.gitee.dorive.core.impl.resolver.BinderResolver; import com.gitee.dorive.core.repository.CommonRepository; @@ -38,6 +40,7 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; public class DefaultExampleBuilder implements ExampleBuilder { @@ -49,49 +52,49 @@ public class DefaultExampleBuilder implements ExampleBuilder { @Override public Example buildExample(Context context, Object coating) { - CoatingRepositoriesResolver coatingRepositoriesResolver = repository.getCoatingRepositoriesResolver(); - Map nameCoatingRepositoriesMap = coatingRepositoriesResolver.getNameCoatingRepositoriesMap(); - - CoatingRepositories coatingRepositories = nameCoatingRepositoriesMap.get(coating.getClass().getName()); - Assert.notNull(coatingRepositories, "No coating definition found!"); - - Map repoCriterionMap = new LinkedHashMap<>(); - for (PropertyRepository propertyRepository : coatingRepositories.getReversedPropertyRepositories()) { - Example example = propertyRepository.newExampleByCoating(coating); - RepoCriterion repoCriterion = new RepoCriterion(propertyRepository, example); - - MergedRepository mergedRepository = propertyRepository.getMergedRepository(); + CoatingType coatingType = repository.getCoatingType(coating); + CoatingCriteria coatingCriteria = coatingType.newCriteria(coating); + Map> criteriaMap = coatingCriteria.getCriteriaMap(); + OrderBy orderBy = coatingCriteria.getOrderBy(); + Page page = coatingCriteria.getPage(); + + Map repoExampleMap = new LinkedHashMap<>(); + for (MergedRepository mergedRepository : coatingType.getReversedMergedRepositories()) { String absoluteAccessPath = mergedRepository.getAbsoluteAccessPath(); - String relativeAccessPath = mergedRepository.isMerged() ? absoluteAccessPath + "/" : absoluteAccessPath; - repoCriterionMap.put(relativeAccessPath, repoCriterion); + String relativeAccessPath = mergedRepository.getRelativeAccessPath(); + List criteria = criteriaMap.computeIfAbsent(absoluteAccessPath, key -> new ArrayList<>(2)); + Example example = new Example(criteria); + repoExampleMap.put(relativeAccessPath, new RepoExample(mergedRepository, example)); } - executeChainQuery(context, repoCriterionMap); + executeQuery(context, repoExampleMap); - RepoCriterion repoCriterion = repoCriterionMap.get("/"); - Assert.notNull(repoCriterion, "The criterion cannot be null!"); - return repoCriterion.getExample(); + RepoExample repoExample = repoExampleMap.get("/"); + Assert.notNull(repoExample, "The criterion cannot be null!"); + + Example example = repoExample.getExample(); + example.setOrderBy(orderBy); + example.setPage(page); + return example; } - private void executeChainQuery(Context context, Map repoCriterionMap) { - repoCriterionMap.forEach((accessPath, repoCriterion) -> { + private void executeQuery(Context context, Map repoExampleMap) { + repoExampleMap.forEach((accessPath, repoExample) -> { if ("/".equals(accessPath)) return; - PropertyRepository propertyRepository = repoCriterion.getPropertyRepository(); - Example example = repoCriterion.getExample(); + MergedRepository mergedRepository = repoExample.getMergedRepository(); + Example example = repoExample.getExample(); - MergedRepository mergedRepository = propertyRepository.getMergedRepository(); - String lastAccessPath = mergedRepository.getLastAccessPath(); CommonRepository definedRepository = mergedRepository.getDefinedRepository(); + Map> mergedBindersMap = mergedRepository.getMergedBindersMap(); CommonRepository executedRepository = mergedRepository.getExecutedRepository(); BinderResolver binderResolver = definedRepository.getBinderResolver(); - for (PropertyBinder propertyBinder : binderResolver.getPropertyBinders()) { - String absoluteAccessPath = lastAccessPath + propertyBinder.getBelongAccessPath(); - RepoCriterion targetRepoCriterion = repoCriterionMap.get(absoluteAccessPath); - if (targetRepoCriterion != null) { - Example targetExample = targetRepoCriterion.getExample(); + for (String relativeAccessPath : mergedBindersMap.keySet()) { + RepoExample targetRepoExample = repoExampleMap.get(relativeAccessPath); + if (targetRepoExample != null) { + Example targetExample = targetRepoExample.getExample(); if (targetExample.isEmptyQuery()) { example.setEmptyQuery(true); break; @@ -105,51 +108,67 @@ public class DefaultExampleBuilder implements ExampleBuilder { List entities = Collections.emptyList(); if (!example.isEmptyQuery() && example.isDirtyQuery()) { - example.selectColumns(new ArrayList<>(binderResolver.getBoundFields())); + example.select(new ArrayList<>(binderResolver.getBoundFields())); entities = executedRepository.selectByExample(context, example); } - for (PropertyBinder propertyBinder : binderResolver.getPropertyBinders()) { - String absoluteAccessPath = lastAccessPath + propertyBinder.getBelongAccessPath(); - RepoCriterion targetRepoCriterion = repoCriterionMap.get(absoluteAccessPath); - if (targetRepoCriterion != null) { - Example targetExample = targetRepoCriterion.getExample(); - if (entities.isEmpty()) { + List finalEntities = entities; + mergedBindersMap.forEach((relativeAccessPath, binders) -> { + RepoExample targetRepoExample = repoExampleMap.get(relativeAccessPath); + if (targetRepoExample != null) { + Example targetExample = targetRepoExample.getExample(); + if (finalEntities.isEmpty()) { targetExample.setEmptyQuery(true); - continue; + return; } - - List fieldValues = collectFieldValues(context, entities, propertyBinder); - if (fieldValues.isEmpty()) { - targetExample.setEmptyQuery(true); - continue; + if (binders.size() == 1) { + PropertyBinder binder = binders.get(0); + List fieldValues = binder.collectFieldValues(context, finalEntities); + if (!fieldValues.isEmpty()) { + String boundName = binder.getBoundName(); + if (fieldValues.size() == 1) { + targetExample.eq(boundName, fieldValues.get(0)); + } else { + targetExample.in(boundName, fieldValues); + } + } else { + targetExample.setEmptyQuery(true); + } + + } else { + List properties = binders.stream().map(PropertyBinder::getBoundName).collect(Collectors.toList()); + MultiInBuilder builder = new MultiInBuilder(finalEntities.size(), properties); + collectFieldValues(context, finalEntities, binders, builder); + if (!builder.isEmpty()) { + targetExample.getCriteria().add(builder.build()); + } else { + targetExample.setEmptyQuery(true); + } } - - PropChain boundPropChain = propertyBinder.getBoundPropChain(); - String field = boundPropChain.getEntityField().getName(); - Object fieldValue = fieldValues.size() == 1 ? fieldValues.get(0) : fieldValues; - fieldValue = propertyBinder.output(context, fieldValue); - targetExample.eq(field, fieldValue); } - } + }); }); } - private List collectFieldValues(Context context, List entities, PropertyBinder propertyBinder) { - List fieldValues = new ArrayList<>(); + private void collectFieldValues(Context context, List entities, List binders, MultiInBuilder builder) { for (Object entity : entities) { - Object fieldValue = propertyBinder.getFieldValue(context, entity); - if (fieldValue != null) { - fieldValues.add(fieldValue); + for (PropertyBinder binder : binders) { + Object fieldValue = binder.getFieldValue(context, entity); + if (fieldValue != null) { + fieldValue = binder.output(context, fieldValue); + builder.append(fieldValue); + } else { + builder.clear(); + break; + } } } - return fieldValues; } @Data @AllArgsConstructor - public static class RepoCriterion { - private PropertyRepository propertyRepository; + public static class RepoExample { + private MergedRepository mergedRepository; private Example example; } diff --git a/dorive-coating/src/main/java/com/gitee/dorive/coating/impl/resolver/CoatingRepositoriesResolver.java b/dorive-coating/src/main/java/com/gitee/dorive/coating/impl/resolver/CoatingTypeResolver.java similarity index 45% rename from dorive-coating/src/main/java/com/gitee/dorive/coating/impl/resolver/CoatingRepositoriesResolver.java rename to dorive-coating/src/main/java/com/gitee/dorive/coating/impl/resolver/CoatingTypeResolver.java index a26b9defd9554960ee6ba52eef94abc5b11fb6c3..692897546dbeb7f2912bdc764f4bb88ccd93797b 100644 --- a/dorive-coating/src/main/java/com/gitee/dorive/coating/impl/resolver/CoatingRepositoriesResolver.java +++ b/dorive-coating/src/main/java/com/gitee/dorive/coating/impl/resolver/CoatingTypeResolver.java @@ -17,33 +17,42 @@ package com.gitee.dorive.coating.impl.resolver; +import cn.hutool.core.lang.Assert; +import com.gitee.dorive.api.entity.element.EntityEle; import com.gitee.dorive.coating.annotation.Coating; -import com.gitee.dorive.coating.entity.*; +import com.gitee.dorive.coating.entity.CoatingField; +import com.gitee.dorive.coating.entity.CoatingType; +import com.gitee.dorive.coating.entity.MergedRepository; +import com.gitee.dorive.coating.entity.SpecificFields; import com.gitee.dorive.coating.entity.def.CoatingDef; import com.gitee.dorive.coating.entity.def.PropertyDef; import com.gitee.dorive.coating.repository.AbstractCoatingRepository; import com.gitee.dorive.coating.util.ResourceUtils; -import com.gitee.dorive.api.entity.element.EntityEle; import com.gitee.dorive.core.repository.CommonRepository; import lombok.Data; -import org.apache.commons.lang3.StringUtils; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.util.ReflectionUtils; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Pattern; @Data -public class CoatingRepositoriesResolver { +public class CoatingTypeResolver { private static Map>> scannedClasses = new ConcurrentHashMap<>(); private AbstractCoatingRepository repository; - private Map, CoatingRepositories> classCoatingRepositoriesMap = new ConcurrentHashMap<>(); - private Map nameCoatingRepositoriesMap = new ConcurrentHashMap<>(); + private Map, CoatingType> classCoatingTypeMap = new ConcurrentHashMap<>(); + private Map nameCoatingTypeMap = new ConcurrentHashMap<>(); - public CoatingRepositoriesResolver(AbstractCoatingRepository repository) throws Exception { + public CoatingTypeResolver(AbstractCoatingRepository repository) throws Exception { this.repository = repository; resolve(); } @@ -65,101 +74,77 @@ public class CoatingRepositoriesResolver { if (coatingAnnotation == null) { continue; } - String simpleName = coatingClass.getSimpleName(); if (!pattern.matcher(simpleName).matches()) { continue; } - SpecificProperties specificProperties = new SpecificProperties(); - Set fieldNames = new LinkedHashSet<>(); - Map> belongToPropertyMap = new LinkedHashMap<>(); - Map fieldPropertyMap = new LinkedHashMap<>(); + CoatingDef coatingDef = CoatingDef.fromElement(coatingClass); + List fields = new ArrayList<>(); + SpecificFields specificFields = new SpecificFields(); ReflectionUtils.doWithLocalFields(coatingClass, declaredField -> { - Property property = new Property(declaredField); - - PropertyDef propertyDef = property.getPropertyDef(); - if (propertyDef.isIgnore()) { + CoatingField field = new CoatingField(declaredField); + if (field.isIgnore()) { return; } - - String fieldName = property.getName(); - if (specificProperties.addProperty(fieldName, property)) { + if (specificFields.addProperty(field)) { return; } - fieldNames.add(fieldName); - - String belongTo = propertyDef.getBelongTo(); - if (StringUtils.isNotBlank(belongTo) && belongTo.startsWith("/")) { - List existProperties = belongToPropertyMap.computeIfAbsent(belongTo, key -> new ArrayList<>()); - existProperties.add(property); - } else { - fieldPropertyMap.put(fieldName, property); - } + fields.add(field); }); - List propertyRepositories = collectRepositories(belongToPropertyMap, fieldPropertyMap); - checkFieldNames(coatingClass, fieldNames, propertyRepositories); + List mergedRepositories = collectRepositories(fields); + List reversedMergedRepositories = new ArrayList<>(mergedRepositories); + Collections.reverse(reversedMergedRepositories); - List reversedPropertyRepositories = new ArrayList<>(propertyRepositories); - Collections.reverse(reversedPropertyRepositories); - - CoatingDef coatingDef = CoatingDef.fromElement(coatingClass); - CoatingRepositories coatingRepositories = new CoatingRepositories(coatingDef, propertyRepositories, reversedPropertyRepositories, specificProperties); - classCoatingRepositoriesMap.put(coatingClass, coatingRepositories); - nameCoatingRepositoriesMap.put(coatingClass.getName(), coatingRepositories); + CoatingType coatingType = new CoatingType(coatingDef, fields, specificFields, mergedRepositories, reversedMergedRepositories); + classCoatingTypeMap.put(coatingClass, coatingType); + nameCoatingTypeMap.put(coatingClass.getName(), coatingType); } } } - private List collectRepositories(Map> belongToPropertyMap, Map fieldPropertyMap) { + private List collectRepositories(List fields) { MergedRepositoryResolver mergedRepositoryResolver = repository.getMergedRepositoryResolver(); Map mergedRepositoryMap = mergedRepositoryResolver.getMergedRepositoryMap(); + Map nameMergedRepositoryMap = mergedRepositoryResolver.getNameMergedRepositoryMap(); - List propertyRepositories = new ArrayList<>(); - - for (MergedRepository mergedRepository : mergedRepositoryMap.values()) { - String absoluteAccessPath = mergedRepository.getAbsoluteAccessPath(); - CommonRepository repository = mergedRepository.getExecutedRepository(); - EntityEle entityEle = repository.getEntityEle(); + Set mergedRepositorySet = new LinkedHashSet<>(); - List properties = new ArrayList<>(); + for (CoatingField field : fields) { + PropertyDef propertyDef = field.getPropertyDef(); + String belongTo = propertyDef.getBelongTo(); - List belongToProperties = belongToPropertyMap.get(absoluteAccessPath); - if (belongToProperties != null) { - properties.addAll(belongToProperties); + if (!belongTo.startsWith("/")) { + MergedRepository mergedRepository = nameMergedRepositoryMap.get(belongTo); + Assert.notNull(mergedRepository, "No merged repository found! belongTo: {}", belongTo); + belongTo = mergedRepository.getAbsoluteAccessPath(); } + MergedRepository mergedRepository = mergedRepositoryMap.get(belongTo); + Assert.notNull(mergedRepository, "No merged repository found! belongTo: {}", belongTo); + + String fieldName = propertyDef.getField(); + CommonRepository repository = mergedRepository.getExecutedRepository(); + EntityEle entityEle = repository.getEntityEle(); Map aliasMap = entityEle.getAliasMap(); - for (String fieldName : aliasMap.keySet()) { - Property property = fieldPropertyMap.get(fieldName); - if (property != null) { - properties.add(property); - } - } + Assert.isTrue(aliasMap.containsKey(fieldName), "The field does not exist within the entity! element: {}, field: {}", + entityEle.getElement(), fieldName); - if (!properties.isEmpty() || repository.isBoundEntity()) { - PropertyRepository propertyRepository = new PropertyRepository(mergedRepository, properties); - propertyRepositories.add(propertyRepository); - } + mergedRepositorySet.add(mergedRepository); } - return propertyRepositories; - } - - private void checkFieldNames(Class coatingClass, Set fieldNames, List propertyRepositories) { - Set remainFieldNames = new LinkedHashSet<>(fieldNames); - for (PropertyRepository propertyRepository : propertyRepositories) { - for (Property property : propertyRepository.getCollectedProperties()) { - remainFieldNames.remove(property.getName()); + for (MergedRepository mergedRepository : mergedRepositoryMap.values()) { + CommonRepository repository = mergedRepository.getExecutedRepository(); + if (repository.isBoundEntity()) { + mergedRepositorySet.add(mergedRepository); } } - if (!remainFieldNames.isEmpty()) { - String errorMessage = String.format("The field does not exist in the aggregate root! entity: %s, coating: %s, fieldNames: %s", - repository.getEntityClass(), coatingClass, remainFieldNames); - throw new RuntimeException(errorMessage); - } + + List mergedRepositories = new ArrayList<>(mergedRepositorySet); + mergedRepositories.sort(Comparator.comparing(MergedRepository::getSequence)); + return mergedRepositories; } } diff --git a/dorive-coating/src/main/java/com/gitee/dorive/coating/impl/resolver/MergedRepositoryResolver.java b/dorive-coating/src/main/java/com/gitee/dorive/coating/impl/resolver/MergedRepositoryResolver.java index a10d75e57fd318a6b110d094e4308d0b22043a9e..d1c411180bf276be39d5f919c6b9f52ceec32e31 100644 --- a/dorive-coating/src/main/java/com/gitee/dorive/coating/impl/resolver/MergedRepositoryResolver.java +++ b/dorive-coating/src/main/java/com/gitee/dorive/coating/impl/resolver/MergedRepositoryResolver.java @@ -19,10 +19,13 @@ package com.gitee.dorive.coating.impl.resolver; import cn.hutool.core.util.StrUtil; import com.gitee.dorive.coating.entity.MergedRepository; +import com.gitee.dorive.core.impl.binder.PropertyBinder; +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 lombok.Data; +import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -34,6 +37,7 @@ public class MergedRepositoryResolver { private AbstractContextRepository repository; private Map mergedRepositoryMap = new LinkedHashMap<>(); + private Map nameMergedRepositoryMap = new LinkedHashMap<>(); public MergedRepositoryResolver(AbstractContextRepository repository) { this.repository = repository; @@ -42,9 +46,22 @@ public class MergedRepositoryResolver { public void resolve() { CommonRepository rootRepository = repository.getRootRepository(); - - MergedRepository rootMergedRepository = new MergedRepository("", "/", false, rootRepository, rootRepository); - mergedRepositoryMap.put("/", rootMergedRepository); + MergedRepository mergedRepository = new MergedRepository( + "", + "/", + false, + "/", + rootRepository, + getMergedBindersMap("", rootRepository), + rootRepository, + 1); + + mergedRepositoryMap.put("/", mergedRepository); + + String name = mergedRepository.getName(); + if (StringUtils.isNotBlank(name)) { + nameMergedRepositoryMap.putIfAbsent(name, mergedRepository); + } resolve(new ArrayList<>(), repository); } @@ -65,10 +82,19 @@ public class MergedRepositoryResolver { lastAccessPath, absoluteAccessPath, true, + absoluteAccessPath + "/", repository, - rootRepository); + getMergedBindersMap(lastAccessPath, repository), + rootRepository, + mergedRepositoryMap.size() + 1); + mergedRepositoryMap.put(absoluteAccessPath, mergedRepository); + String name = mergedRepository.getName(); + if (StringUtils.isNotBlank(name)) { + nameMergedRepositoryMap.putIfAbsent(name, mergedRepository); + } + List newMultiAccessPath = new ArrayList<>(multiAccessPath); newMultiAccessPath.add(accessPath); resolve(newMultiAccessPath, abstractContextRepository); @@ -78,11 +104,32 @@ public class MergedRepositoryResolver { lastAccessPath, absoluteAccessPath, false, + absoluteAccessPath, + repository, + getMergedBindersMap(lastAccessPath, repository), repository, - repository); + mergedRepositoryMap.size() + 1); + mergedRepositoryMap.put(absoluteAccessPath, mergedRepository); + + String name = mergedRepository.getName(); + if (StringUtils.isNotBlank(name)) { + nameMergedRepositoryMap.putIfAbsent(name, mergedRepository); + } } } } + private Map> getMergedBindersMap(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<>()); + existPropertyBinders.add(propertyBinder); + } + return mergedBindersMap; + } + } diff --git a/dorive-coating/src/main/java/com/gitee/dorive/coating/repository/AbstractCoatingRepository.java b/dorive-coating/src/main/java/com/gitee/dorive/coating/repository/AbstractCoatingRepository.java index e4bd068828ff03a282878b598ea48bbd1ababf26..e99685e1ab18e805070bae6a468acb5f8990f01c 100644 --- a/dorive-coating/src/main/java/com/gitee/dorive/coating/repository/AbstractCoatingRepository.java +++ b/dorive-coating/src/main/java/com/gitee/dorive/coating/repository/AbstractCoatingRepository.java @@ -17,12 +17,14 @@ package com.gitee.dorive.coating.repository; +import cn.hutool.core.lang.Assert; import com.gitee.dorive.api.annotation.Repository; import com.gitee.dorive.coating.annotation.CoatingScan; import com.gitee.dorive.coating.api.CoatingRepository; import com.gitee.dorive.coating.api.ExampleBuilder; +import com.gitee.dorive.coating.entity.CoatingType; import com.gitee.dorive.coating.impl.DefaultExampleBuilder; -import com.gitee.dorive.coating.impl.resolver.CoatingRepositoriesResolver; +import com.gitee.dorive.coating.impl.resolver.CoatingTypeResolver; import com.gitee.dorive.coating.impl.resolver.MergedRepositoryResolver; import com.gitee.dorive.core.api.context.Context; import com.gitee.dorive.core.entity.executor.Example; @@ -34,6 +36,7 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.core.annotation.AnnotatedElementUtils; import java.util.List; +import java.util.Map; @Data @EqualsAndHashCode(callSuper = false) @@ -43,7 +46,7 @@ public abstract class AbstractCoatingRepository extends AbstractEventRepo private String[] scanPackages; private String regex; private MergedRepositoryResolver mergedRepositoryResolver; - private CoatingRepositoriesResolver coatingRepositoriesResolver; + private CoatingTypeResolver coatingTypeResolver; private ExampleBuilder exampleBuilder; @Override @@ -55,15 +58,21 @@ public abstract class AbstractCoatingRepository extends AbstractEventRepo this.querier = repository.querier(); this.scanPackages = coatingScan.value(); this.regex = StringUtils.isBlank(coatingScan.regex()) ? "^" + getEntityClass().getSimpleName() + ".*" : coatingScan.regex(); - this.mergedRepositoryResolver = new MergedRepositoryResolver(this); - this.coatingRepositoriesResolver = new CoatingRepositoriesResolver(this); + this.coatingTypeResolver = new CoatingTypeResolver(this); if ("default".equals(querier)) { this.exampleBuilder = new DefaultExampleBuilder(this); } } } + public CoatingType getCoatingType(Object coating) { + Map nameCoatingTypeMap = coatingTypeResolver.getNameCoatingTypeMap(); + CoatingType coatingType = nameCoatingTypeMap.get(coating.getClass().getName()); + Assert.notNull(coatingType, "No coating type found!"); + return coatingType; + } + @Override public Example buildExample(Context context, Object coating) { return exampleBuilder.buildExample(context, coating); diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/api/context/Selector.java b/dorive-core/src/main/java/com/gitee/dorive/core/api/context/Selector.java index c7c8d46450b5052c651ab396d2fa5152430ece29..0442bbc44b12dc832deaaf35ba5760878125ce8d 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/api/context/Selector.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/api/context/Selector.java @@ -25,6 +25,6 @@ public interface Selector extends Context { boolean matches(Context context, CommonRepository repository); - List selectColumns(Context context, CommonRepository repository); + List select(Context context, CommonRepository repository); } diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/Criterion.java b/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/Criterion.java index 23ba32c613d253a8d9ec703d8b1fe9854b0c8dcd..9cfde2435075ecfbb86cec3b63b756ccf39e169b 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/Criterion.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/Criterion.java @@ -17,21 +17,13 @@ package com.gitee.dorive.core.entity.executor; -import com.gitee.dorive.core.util.CriterionUtils; import lombok.AllArgsConstructor; import lombok.Data; @Data @AllArgsConstructor public class Criterion { - private String property; private String operator; private Object value; - - @Override - public String toString() { - return CriterionUtils.toString(this); - } - } diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/Example.java b/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/Example.java index 28b6814bea48d2fa23714464029fb22fdd93d84f..658952857b5b7eb2b2bfceab8efe41864a6c2a15 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/Example.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/Example.java @@ -17,7 +17,6 @@ package com.gitee.dorive.core.entity.executor; -import cn.hutool.core.util.StrUtil; import com.gitee.dorive.api.constant.Operator; import com.gitee.dorive.api.constant.Order; import com.gitee.dorive.core.util.StringUtils; @@ -34,12 +33,16 @@ public class Example { private boolean emptyQuery = false; private boolean countQueried = false; - private List selectColumns; - private List extraColumns; + private List selectProps; + private List extraProps; private List criteria = new ArrayList<>(4); private OrderBy orderBy; private Page page; + public Example(List criteria) { + this.criteria = criteria; + } + public boolean isDirtyQuery() { return !criteria.isEmpty(); } @@ -48,34 +51,26 @@ public class Example { return !emptyQuery && !isDirtyQuery(); } - public void selectColumns(String... columns) { - selectColumns(StringUtils.toList(columns)); + public void select(String... properties) { + select(StringUtils.toList(properties)); } - public void selectColumns(List columns) { - selectColumns = columns; + public void select(List properties) { + selectProps = properties; } - public void extraColumns(String... columns) { - extraColumns(StringUtils.toList(columns)); + public void selectExtra(String... properties) { + selectExtra(StringUtils.toList(properties)); } - public void extraColumns(List columns) { - if (extraColumns == null) { - extraColumns = columns; + public void selectExtra(List properties) { + if (extraProps == null) { + extraProps = properties; } else { - extraColumns.addAll(columns); + extraProps.addAll(properties); } } - public void addCriterion(Criterion criterion) { - criteria.add(criterion); - } - - public String buildCriteria() { - return StrUtil.join(" AND ", criteria); - } - public Example eq(String property, Object value) { criteria.add(new Criterion(property, Operator.EQ, value)); return this; @@ -136,13 +131,13 @@ public class Example { return this; } - public Example orderByAsc(String... columns) { - orderBy = new OrderBy(Arrays.asList(columns), Order.ASC); + public Example orderByAsc(String... properties) { + orderBy = new OrderBy(Arrays.asList(properties), Order.ASC); return this; } - public Example orderByDesc(String... columns) { - orderBy = new OrderBy(Arrays.asList(columns), Order.DESC); + public Example orderByDesc(String... properties) { + orderBy = new OrderBy(Arrays.asList(properties), Order.DESC); return this; } diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/MultiInBuilder.java b/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/MultiInBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..b335f818eb3e4f04e42e27b224b9eb5bdd8d7182 --- /dev/null +++ b/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/MultiInBuilder.java @@ -0,0 +1,76 @@ +/* + * 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.executor; + +import cn.hutool.core.util.StrUtil; +import com.gitee.dorive.api.constant.Operator; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.ArrayList; +import java.util.List; + +@Data +@EqualsAndHashCode(callSuper = false) +public class MultiInBuilder { + + private int size; + private List properties; + private int step; + private List values; + private int cursor; + + public MultiInBuilder(int size, List properties) { + this.size = size; + this.properties = properties; + this.step = properties.size(); + this.values = new ArrayList<>(size * step); + this.cursor = 0; + } + + public void append(Object value) { + if (values.size() - cursor >= step) { + cursor += step; + } + values.add(value); + } + + public void clear() { + values.subList(cursor, values.size()).clear(); + } + + public boolean isEmpty() { + return values.isEmpty(); + } + + public int page() { + return values.size() / step; + } + + public List get(int page) { + int fromIndex = (page - 1) * step; + int toIndex = fromIndex + step; + return values.subList(fromIndex, toIndex); + } + + public Criterion build() { + String propStr = StrUtil.join(",", properties); + return new Criterion(propStr, Operator.MULTI_IN, this); + } + +} diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/MultiResult.java b/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/MultiResult.java index 6d99256467ac3516ff4f31a9167fe4422f179ad7..4c7b2710f7eae8c2cb274df5277d88f2852462f1 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/MultiResult.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/MultiResult.java @@ -24,7 +24,7 @@ import java.util.List; import java.util.Map; @Data -@EqualsAndHashCode(callSuper = true) +@EqualsAndHashCode(callSuper = false) public class MultiResult extends Result { private List> resultMaps; diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/OrderBy.java b/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/OrderBy.java index 84b241667eee482790fde9d479ecf91a622d2d29..9c874e6dfea13198bf1b81864b74873a2813bedc 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/OrderBy.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/OrderBy.java @@ -27,12 +27,12 @@ import java.util.List; @AllArgsConstructor public class OrderBy { - private List columns; + private List properties; private String order; @Override public String toString() { - return "ORDER BY " + StrUtil.join(", ", columns) + " " + order.toUpperCase(); + return "ORDER BY " + StrUtil.join(",", properties) + " " + order.toUpperCase(); } } diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/Page.java b/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/Page.java index 1c614f1b0daddfb2d0d8d89159eda87c8d6c9259..e368926cb90906260f26a3128ff4e00dc1fab4ca 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/Page.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/Page.java @@ -41,7 +41,7 @@ public class Page { @Override public String toString() { - return "LIMIT " + (current - 1) * size + ", " + size; + return "LIMIT " + (current - 1) * size + "," + size; } } diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/UnionExample.java b/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/UnionExample.java index 6ab3168f4ef02ab94a70854466f26008fc6034f2..0cbd91975a4fabebffbda98061258c57b726ca7d 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/UnionExample.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/entity/executor/UnionExample.java @@ -37,10 +37,10 @@ public class UnionExample extends Example { } @Override - public void selectColumns(List selectColumns) { + public void select(List properties) { if (examples != null && !examples.isEmpty()) { for (Example example : examples) { - example.selectColumns(selectColumns); + example.select(properties); } } } diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/entity/operation/Query.java b/dorive-core/src/main/java/com/gitee/dorive/core/entity/operation/Query.java index 5001fec9549a68a9d872dda49666602c1a97cb2c..9eca5a48c3a84495b55d4938888222e20a767232 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/entity/operation/Query.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/entity/operation/Query.java @@ -33,6 +33,10 @@ public class Query extends Condition { super(OperationType.SELECT, entity); } + public boolean isEmpty() { + return getPrimaryKey() == null && getExample() == null; + } + public boolean withoutPage() { return getExample().getPage() == null; } 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/AbstractBinder.java index 50ce0e159eeccca561c8b2f4dd53b9891b785747..db9cd20046be20c1aca050fbff9d417172e96774 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/AbstractBinder.java @@ -17,14 +17,17 @@ package com.gitee.dorive.core.impl.binder; -import com.gitee.dorive.core.api.context.Context; import com.gitee.dorive.api.entity.def.BindingDef; +import com.gitee.dorive.api.entity.element.PropChain; import com.gitee.dorive.core.api.common.Binder; import com.gitee.dorive.core.api.common.Processor; -import com.gitee.dorive.api.entity.element.PropChain; +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 { @@ -34,6 +37,10 @@ public abstract class AbstractBinder implements Binder, Processor { private PropChain fieldPropChain; private Processor processor; + public String getFieldName() { + return fieldPropChain.getEntityField().getName(); + } + @Override public Object getFieldValue(Context context, Object entity) { return fieldPropChain.getValue(entity); @@ -54,4 +61,16 @@ public abstract class AbstractBinder implements Binder, Processor { return processor.output(context, value); } + 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; + } + } 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/PropertyBinder.java index 1a1dcb9f0266947143e59b18a76fab494f90cf3e..e3a19c193ec084b44c38c469d5c82dd9d2abc9d3 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/PropertyBinder.java @@ -17,10 +17,10 @@ package com.gitee.dorive.core.impl.binder; -import com.gitee.dorive.core.api.common.Processor; -import com.gitee.dorive.core.api.context.Context; import com.gitee.dorive.api.entity.def.BindingDef; import com.gitee.dorive.api.entity.element.PropChain; +import com.gitee.dorive.core.api.common.Processor; +import com.gitee.dorive.core.api.context.Context; import com.gitee.dorive.core.repository.CommonRepository; import lombok.Getter; import lombok.Setter; @@ -49,6 +49,10 @@ public class PropertyBinder extends AbstractBinder { this.bindAlias = bindAlias; } + public String getBoundName() { + return boundPropChain.getEntityField().getName(); + } + public boolean isSameType() { return getFieldPropChain().isSameType(boundPropChain); } diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/impl/executor/ChainExecutor.java b/dorive-core/src/main/java/com/gitee/dorive/core/impl/executor/ChainExecutor.java index 1180df2c1590d26fec2c6c728cf70d83da333a91..15ec0aeeb45abfff9149f4df104a0e75f1964ebb 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/impl/executor/ChainExecutor.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/impl/executor/ChainExecutor.java @@ -54,25 +54,18 @@ public class ChainExecutor extends AbstractExecutor implements EntityHandler { @Override public Result executeQuery(Context context, Query query) { - Assert.isTrue(query.getPrimaryKey() != null || query.getExample() != null, "The condition cannot be null!"); - - CommonRepository rootRepository = repository.getRootRepository(); + Assert.isTrue(!query.isEmpty(), "The query cannot be empty!"); Selector selector = context.getSelector(); boolean isIncludeRoot = (query.getType() & OperationType.INCLUDE_ROOT) == OperationType.INCLUDE_ROOT; - - if (selector.matches(context, rootRepository) || isIncludeRoot) { - int totalCount = 0; - - Result result = rootRepository.executeQuery(context, query); - totalCount += result.getCount(); - - List rootEntities = result.getRecords(); - if (!rootEntities.isEmpty()) { - totalCount += handle(context, rootEntities); + CommonRepository repository = this.repository.getRootRepository(); + + if (selector.matches(context, repository) || isIncludeRoot) { + Result result = repository.executeQuery(context, query); + List entities = result.getRecords(); + if (!entities.isEmpty()) { + handle(context, entities); } - - result.setCount(totalCount); return result; } 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 71b77d73818c1c3368cd28b98a46cfa264496e0c..2bb821aac3d9ccd3be7274d20bb35b836ee594f9 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 @@ -17,36 +17,24 @@ package com.gitee.dorive.core.impl.handler; -import com.gitee.dorive.api.api.PropProxy; -import com.gitee.dorive.api.constant.OperationType; -import com.gitee.dorive.api.entity.element.PropChain; import com.gitee.dorive.core.api.context.Context; import com.gitee.dorive.core.api.context.Selector; import com.gitee.dorive.core.api.executor.EntityHandler; -import com.gitee.dorive.core.entity.executor.Example; -import com.gitee.dorive.core.entity.executor.MultiResult; -import com.gitee.dorive.core.entity.executor.Result; -import com.gitee.dorive.core.entity.executor.UnionExample; -import com.gitee.dorive.core.entity.operation.Query; -import com.gitee.dorive.core.impl.factory.OperationFactory; +import com.gitee.dorive.core.impl.binder.PropertyBinder; +import com.gitee.dorive.core.impl.resolver.BinderResolver; import com.gitee.dorive.core.repository.AbstractContextRepository; import com.gitee.dorive.core.repository.CommonRepository; -import com.gitee.dorive.core.util.NumberUtils; +import lombok.AllArgsConstructor; +import lombok.Data; -import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Map; +@Data +@AllArgsConstructor public class BatchEntityHandler implements EntityHandler { private final AbstractContextRepository repository; - private final OperationFactory operationFactory; - - public BatchEntityHandler(AbstractContextRepository repository, OperationFactory operationFactory) { - this.repository = repository; - this.operationFactory = operationFactory; - } @Override public int handle(Context context, List entities) { @@ -54,79 +42,22 @@ public class BatchEntityHandler implements EntityHandler { int totalCount = 0; for (CommonRepository repository : this.repository.getSubRepositories()) { if (selector.matches(context, repository)) { - totalCount += executeQuery(repository, context, entities); - } - } - return totalCount; - } - - private long executeQuery(CommonRepository repository, Context context, List rootEntities) { - UnionExample unionExample = newUnionExample(repository, context, rootEntities); - if (unionExample.isDirtyQuery()) { - Query query = operationFactory.buildQuery(unionExample); - query.setType(query.getType() | OperationType.INCLUDE_ROOT); - Result result = repository.executeQuery(context, query); - if (result instanceof MultiResult) { - setValueForRootEntities(repository, rootEntities, (MultiResult) result); - } - return result.getCount(); - } - return 0; - } - - private UnionExample newUnionExample(CommonRepository repository, Context context, List rootEntities) { - PropChain anchorPoint = repository.getAnchorPoint(); - PropChain lastPropChain = anchorPoint.getLastPropChain(); - UnionExample unionExample = new UnionExample(); - for (int index = 0; index < rootEntities.size(); index++) { - Object rootEntity = rootEntities.get(index); - Object lastEntity = lastPropChain == null ? rootEntity : lastPropChain.getValue(rootEntity); - if (lastEntity != null) { - Example example = repository.newExampleByContext(context, rootEntity); - if (example.isDirtyQuery()) { - example.extraColumns((index + 1) + " as $row"); - unionExample.addExample(example); + if (isMultiQuery(repository)) { + EntityHandler entityHandler = new MultiEntityHandler(repository); + totalCount += entityHandler.handle(context, entities); + } else { + EntityHandler entityHandler = new UnionEntityHandler(repository); + totalCount += entityHandler.handle(context, entities); } } } - return unionExample; + return totalCount; } - private void setValueForRootEntities(CommonRepository repository, List rootEntities, MultiResult multiResult) { - boolean isCollection = repository.getEntityEle().isCollection(); - PropChain anchorPoint = repository.getAnchorPoint(); - PropProxy propProxy = anchorPoint.getPropProxy(); - - List> resultMaps = multiResult.getResultMaps(); - List entities = multiResult.getRecords(); - int averageSize = entities.size() / rootEntities.size() + 1; - int lastRowNum = -1; - Collection lastCollection = null; - - for (int index = 0; index < entities.size(); index++) { - Map resultMap = resultMaps.get(index); - Object entity = entities.get(index); - Integer rowNum = NumberUtils.intValue(resultMap.get("$row")); - - if (rowNum == lastRowNum) { - if (isCollection && lastCollection != null) { - lastCollection.add(entity); - } - - } else { - Object rootEntity = rootEntities.get(rowNum - 1); - if (isCollection) { - Collection collection = new ArrayList<>(averageSize); - propProxy.setValue(rootEntity, collection); - collection.add(entity); - lastCollection = collection; - } else { - propProxy.setValue(rootEntity, entity); - } - } - - lastRowNum = rowNum; - } + private boolean isMultiQuery(CommonRepository repository) { + BinderResolver binderResolver = repository.getBinderResolver(); + Map> mergedBindersMap = binderResolver.getMergedBindersMap(); + return mergedBindersMap.size() == 1 && mergedBindersMap.containsKey("/"); } } diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/impl/handler/MultiEntityHandler.java b/dorive-core/src/main/java/com/gitee/dorive/core/impl/handler/MultiEntityHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..79dcfaf26979121fc0ae21f923447aa0a5711089 --- /dev/null +++ b/dorive-core/src/main/java/com/gitee/dorive/core/impl/handler/MultiEntityHandler.java @@ -0,0 +1,240 @@ +/* + * 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.handler; + +import com.gitee.dorive.api.constant.OperationType; +import com.gitee.dorive.api.entity.element.PropChain; +import com.gitee.dorive.core.api.context.Context; +import com.gitee.dorive.core.api.executor.EntityHandler; +import com.gitee.dorive.core.entity.executor.Example; +import com.gitee.dorive.core.entity.executor.MultiInBuilder; +import com.gitee.dorive.core.entity.executor.MultiResult; +import com.gitee.dorive.core.entity.executor.Result; +import com.gitee.dorive.core.entity.operation.Query; +import com.gitee.dorive.core.impl.binder.AbstractBinder; +import com.gitee.dorive.core.impl.binder.ContextBinder; +import com.gitee.dorive.core.impl.binder.PropertyBinder; +import com.gitee.dorive.core.impl.factory.OperationFactory; +import com.gitee.dorive.core.impl.resolver.BinderResolver; +import com.gitee.dorive.core.repository.CommonRepository; +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Data +@AllArgsConstructor +public class MultiEntityHandler implements EntityHandler { + + private final CommonRepository repository; + + @Override + public int handle(Context context, List entities) { + Map entityIndex = new LinkedHashMap<>(entities.size() * 4 / 3 + 1); + Example example = newExample(context, entities, entityIndex); + if (example.isDirtyQuery()) { + OperationFactory operationFactory = repository.getOperationFactory(); + Query query = operationFactory.buildQuery(example); + query.setType(query.getType() | OperationType.INCLUDE_ROOT); + Result result = repository.executeQuery(context, query); + if (result instanceof MultiResult) { + setValueForRootEntities(context, entities, entityIndex, (MultiResult) result); + } + return (int) result.getCount(); + } + return 0; + } + + private Example newExample(Context context, List entities, Map entityIndex) { + BinderResolver binderResolver = repository.getBinderResolver(); + Map> mergedBindersMap = binderResolver.getMergedBindersMap(); + List binders = mergedBindersMap.get("/"); + + Example example = new Example(); + if (binders.size() == 1) { + PropertyBinder binder = binders.get(0); + List boundValues = collectBoundValues(context, entities, entityIndex, binder); + if (!boundValues.isEmpty()) { + String fieldName = binder.getFieldName(); + if (boundValues.size() == 1) { + example.eq(fieldName, boundValues.get(0)); + } else { + example.in(fieldName, boundValues); + } + } + + } else { + List properties = binders.stream().map(AbstractBinder::getFieldName).collect(Collectors.toList()); + MultiInBuilder builder = new MultiInBuilder(entities.size(), properties); + collectBoundValues(context, entities, entityIndex, binders, builder); + if (!builder.isEmpty()) { + example.getCriteria().add(builder.build()); + } + } + + if (example.isDirtyQuery()) { + for (ContextBinder binder : binderResolver.getContextBinders()) { + String fieldName = binder.getFieldName(); + Object boundValue = binder.getBoundValue(context, null); + if (boundValue != null) { + example.eq(fieldName, boundValue); + } + } + } + + return example; + } + + public List collectBoundValues(Context context, List entities, Map entityIndex, PropertyBinder binder) { + List boundValues = new ArrayList<>(entities.size()); + for (Object entity : entities) { + Object boundValue = binder.getBoundValue(context, entity); + if (boundValue != null) { + boundValue = binder.input(context, boundValue); + String key = String.valueOf(boundValue); + if (!entityIndex.containsKey(key)) { + boundValues.add(boundValue); + } + addToIndex(entityIndex, key, entity); + } + } + return boundValues; + } + + private void collectBoundValues(Context context, List entities, Map entityIndex, List binders, + MultiInBuilder multiInBuilder) { + for (Object entity : entities) { + StringBuilder strBuilder = new StringBuilder(); + for (PropertyBinder binder : binders) { + Object boundValue = binder.getBoundValue(context, entity); + if (boundValue != null) { + boundValue = binder.input(context, boundValue); + multiInBuilder.append(boundValue); + strBuilder.append(boundValue).append(","); + } else { + multiInBuilder.clear(); + strBuilder = null; + break; + } + } + if (strBuilder != null) { + if (strBuilder.length() > 0) { + strBuilder.deleteCharAt(strBuilder.length() - 1); + } + String key = strBuilder.toString(); + if (entityIndex.containsKey(key)) { + multiInBuilder.clear(); + } + addToIndex(entityIndex, key, entity); + } + } + } + + @SuppressWarnings("unchecked") + private void addToIndex(Map entityIndex, String key, Object entity) { + Object object = entityIndex.get(key); + if (object instanceof Collection) { + ((Collection) object).add(entity); + + } else if (object != null) { + List entities = new ArrayList<>(4); + entities.add(object); + entities.add(entity); + entityIndex.put(key, entities); + + } else { + entityIndex.put(key, entity); + } + } + + @SuppressWarnings("unchecked") + private void setValueForRootEntities(Context context, List rootEntities, Map entityIndex, MultiResult multiResult) { + boolean isCollection = repository.getEntityEle().isCollection(); + PropChain anchorPoint = repository.getAnchorPoint(); + + BinderResolver binderResolver = repository.getBinderResolver(); + List binders = binderResolver.getMergedBindersMap().get("/"); + + List entities = multiResult.getRecords(); + int averageSize = entities.size() / rootEntities.size() + 1; + + for (Object entity : entities) { + StringBuilder strBuilder = new StringBuilder(); + if (binders.size() == 1) { + PropertyBinder binder = binders.get(0); + Object fieldValue = binder.getFieldValue(context, entity); + if (fieldValue != null) { + strBuilder.append(fieldValue); + } else { + strBuilder = null; + } + } else { + for (PropertyBinder binder : binders) { + Object fieldValue = binder.getFieldValue(context, entity); + if (fieldValue != null) { + strBuilder.append(fieldValue).append(","); + } else { + strBuilder = null; + break; + } + } + if (strBuilder != null && strBuilder.length() > 0) { + strBuilder.deleteCharAt(strBuilder.length() - 1); + } + } + if (strBuilder != null) { + Object object = entityIndex.get(strBuilder.toString()); + if (object instanceof Collection) { + for (Object rootEntity : (Collection) object) { + setValueForRootEntity(isCollection, anchorPoint, averageSize, rootEntity, entity); + } + } else { + setValueForRootEntity(isCollection, anchorPoint, averageSize, object, entity); + } + } + } + } + + @SuppressWarnings("unchecked") + public void setValueForRootEntity(boolean isCollection, PropChain anchorPoint, int averageSize, Object rootEntity, Object entity) { + if (rootEntity != null) { + Object value = anchorPoint.getValue(rootEntity); + if (isCollection) { + Collection collection; + if (value == null) { + collection = new ArrayList<>(averageSize); + anchorPoint.setValue(rootEntity, collection); + } else { + collection = (Collection) value; + } + collection.add(entity); + + } else { + if (value == null) { + anchorPoint.setValue(rootEntity, entity); + } + } + } + } + +} diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/impl/handler/UnionEntityHandler.java b/dorive-core/src/main/java/com/gitee/dorive/core/impl/handler/UnionEntityHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..dd805969ae9ed1adf3aea162050144cb4e3ff9da --- /dev/null +++ b/dorive-core/src/main/java/com/gitee/dorive/core/impl/handler/UnionEntityHandler.java @@ -0,0 +1,146 @@ +/* + * 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.handler; + +import com.gitee.dorive.api.constant.OperationType; +import com.gitee.dorive.api.entity.element.PropChain; +import com.gitee.dorive.core.api.context.Context; +import com.gitee.dorive.core.api.executor.EntityHandler; +import com.gitee.dorive.core.entity.executor.Example; +import com.gitee.dorive.core.entity.executor.MultiResult; +import com.gitee.dorive.core.entity.executor.Result; +import com.gitee.dorive.core.entity.executor.UnionExample; +import com.gitee.dorive.core.entity.operation.Query; +import com.gitee.dorive.core.impl.binder.ContextBinder; +import com.gitee.dorive.core.impl.binder.PropertyBinder; +import com.gitee.dorive.core.impl.factory.OperationFactory; +import com.gitee.dorive.core.impl.resolver.BinderResolver; +import com.gitee.dorive.core.repository.CommonRepository; +import com.gitee.dorive.core.util.NumberUtils; +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +@Data +@AllArgsConstructor +public class UnionEntityHandler implements EntityHandler { + + private final CommonRepository repository; + + @Override + public int handle(Context context, List entities) { + Example example = newExample(context, entities); + if (example.isDirtyQuery()) { + OperationFactory operationFactory = repository.getOperationFactory(); + Query query = operationFactory.buildQuery(example); + query.setType(query.getType() | OperationType.INCLUDE_ROOT); + Result result = repository.executeQuery(context, query); + if (result instanceof MultiResult) { + setValueForRootEntities(entities, (MultiResult) result); + } + return (int) result.getCount(); + } + return 0; + } + + private Example newExample(Context context, List entities) { + PropChain anchorPoint = repository.getAnchorPoint(); + PropChain lastPropChain = anchorPoint.getLastPropChain(); + UnionExample unionExample = new UnionExample(); + for (int index = 0; index < entities.size(); index++) { + Object entity = entities.get(index); + Object lastEntity = lastPropChain == null ? entity : lastPropChain.getValue(entity); + if (lastEntity != null) { + Example example = newExample(context, entity); + if (example.isDirtyQuery()) { + example.selectExtra((index + 1) + " as $row"); + unionExample.addExample(example); + } + } + } + return unionExample; + } + + public Example newExample(Context context, Object entity) { + BinderResolver binderResolver = repository.getBinderResolver(); + Example example = new Example(); + for (PropertyBinder binder : binderResolver.getPropertyBinders()) { + String fieldName = binder.getFieldName(); + Object boundValue = binder.getBoundValue(context, entity); + if (boundValue instanceof Collection) { + boundValue = !((Collection) boundValue).isEmpty() ? boundValue : null; + } + if (boundValue != null) { + boundValue = binder.input(context, boundValue); + example.eq(fieldName, boundValue); + } else { + example.getCriteria().clear(); + break; + } + } + if (example.isDirtyQuery()) { + for (ContextBinder binder : binderResolver.getContextBinders()) { + String fieldName = binder.getFieldName(); + Object boundValue = binder.getBoundValue(context, entity); + if (boundValue != null) { + example.eq(fieldName, boundValue); + } + } + } + return example; + } + + private void setValueForRootEntities(List rootEntities, MultiResult multiResult) { + boolean isCollection = repository.getEntityEle().isCollection(); + PropChain anchorPoint = repository.getAnchorPoint(); + + List> resultMaps = multiResult.getResultMaps(); + int averageSize = resultMaps.size() / rootEntities.size() + 1; + int lastRowNum = -1; + Collection lastCollection = null; + + for (Map resultMap : resultMaps) { + Integer rowNum = NumberUtils.intValue(resultMap.get("$row")); + Object entity = resultMap.get("$entity"); + + if (rowNum == lastRowNum) { + if (isCollection && lastCollection != null) { + lastCollection.add(entity); + } + + } else { + Object rootEntity = rootEntities.get(rowNum - 1); + if (isCollection) { + Collection collection = new ArrayList<>(averageSize); + collection.add(entity); + lastCollection = collection; + anchorPoint.setValue(rootEntity, collection); + } else { + anchorPoint.setValue(rootEntity, entity); + } + } + + lastRowNum = rowNum; + } + } + +} 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 12c7e531a0f27c055a99a58984c59257080c3022..8704d03129084b68d59440cfe4ddbd5bec8bbb61 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 @@ -39,6 +39,7 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.context.ApplicationContext; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -50,6 +51,7 @@ public class BinderResolver { private List allBinders; private List propertyBinders; + private Map> mergedBindersMap; private List boundFields; private List contextBinders; private List boundValueBinders; @@ -66,6 +68,7 @@ public class BinderResolver { allBinders = new ArrayList<>(bindingDefs.size()); propertyBinders = new ArrayList<>(bindingDefs.size()); + mergedBindersMap = new LinkedHashMap<>(bindingDefs.size() * 4 / 3 + 1); boundFields = new ArrayList<>(bindingDefs.size()); contextBinders = new ArrayList<>(bindingDefs.size()); boundValueBinders = new ArrayList<>(bindingDefs.size()); @@ -87,6 +90,11 @@ public class BinderResolver { PropertyBinder propertyBinder = newPropertyBinder(bindingDef, alias, fieldPropChain, processor); allBinders.add(propertyBinder); propertyBinders.add(propertyBinder); + + String belongAccessPath = propertyBinder.getBelongAccessPath(); + List propertyBinders = mergedBindersMap.computeIfAbsent(belongAccessPath, key -> new ArrayList<>(2)); + propertyBinders.add(propertyBinder); + boundFields.add(bindingDef.getField()); if (propertyBinder.isSameType()) { diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/impl/selector/NameSelector.java b/dorive-core/src/main/java/com/gitee/dorive/core/impl/selector/NameSelector.java index 299bce88cc165a71a5cafe00fc046d72d9c1e40b..3848ee7424d770c4667a468f9039754af746e606 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/impl/selector/NameSelector.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/impl/selector/NameSelector.java @@ -72,7 +72,7 @@ public class NameSelector extends AbstractSelector { } @Override - public List selectColumns(Context context, CommonRepository repository) { + public List select(Context context, CommonRepository repository) { EntityDef entityDef = repository.getEntityDef(); String name = entityDef.getName(); NameDef nameDef = nameDefMap.get(name); diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/impl/selector/RootSelector.java b/dorive-core/src/main/java/com/gitee/dorive/core/impl/selector/RootSelector.java index 7252c2d3d8c2ef50ba187081255ac771cd3672dd..6fbeaa87da95aaab98f777d02414b91081bc9881 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/impl/selector/RootSelector.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/impl/selector/RootSelector.java @@ -34,7 +34,7 @@ public class RootSelector extends AbstractSelector { } @Override - public List selectColumns(Context context, CommonRepository repository) { + public List select(Context context, CommonRepository repository) { return null; } diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/repository/AbstractContextRepository.java b/dorive-core/src/main/java/com/gitee/dorive/core/repository/AbstractContextRepository.java index c7087258c1d81f5f11538ee8fd52c25f6468663a..3261c5163ff593db61d9eaae6d4a9be2d9ccf180 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/repository/AbstractContextRepository.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/repository/AbstractContextRepository.java @@ -99,7 +99,7 @@ public abstract class AbstractContextRepository extends AbstractRepositor setEntityDef(rootRepository.getEntityDef()); setEntityEle(rootRepository.getEntityEle()); setOperationFactory(rootRepository.getOperationFactory()); - setExecutor(newExecutor(rootRepository)); + setExecutor(newExecutor()); setAttachments(new ConcurrentHashMap<>(rootRepository.getAttachments())); } @@ -112,7 +112,7 @@ public abstract class AbstractContextRepository extends AbstractRepositor boolean isRoot = "/".equals(accessPath); boolean isAggregated = entityEle.isAggregated(); - OrderBy defaultOrderBy = newDefaultOrderBy(entityDef, entityEle); + OrderBy defaultOrderBy = newDefaultOrderBy(entityDef); Map propChainMap = propChainResolver.getPropChainMap(); PropChain anchorPoint = propChainMap.get(accessPath); @@ -172,21 +172,20 @@ public abstract class AbstractContextRepository extends AbstractRepositor return (AbstractRepository) repository; } - private OrderBy newDefaultOrderBy(EntityDef entityDef, EntityEle entityEle) { + private OrderBy newDefaultOrderBy(EntityDef entityDef) { String sortBy = entityDef.getSortBy(); String order = entityDef.getOrder().toUpperCase(); if (StringUtils.isNotBlank(sortBy) && (Order.ASC.equals(order) || Order.DESC.equals(order))) { List properties = StrUtil.splitTrim(sortBy, ","); - List columns = entityEle.toAliases(properties); - return new OrderBy(columns, order); + return new OrderBy(properties, order); } return null; } - private Executor newExecutor(CommonRepository rootRepository) { + private Executor newExecutor() { delegateResolver = new DelegateResolver(this); - EntityHandler entityHandler = new BatchEntityHandler(this, rootRepository.getOperationFactory()); + EntityHandler entityHandler = new BatchEntityHandler(this); processEntityClass(entityHandler); if (delegateResolver.isDelegated()) { 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 6d2ad88729164ed9b4edb0d3f2f5b0ff2f979d7a..77fa43a86faa4102223a186a3257436afc742c53 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 @@ -17,7 +17,6 @@ package com.gitee.dorive.core.repository; -import com.gitee.dorive.api.entity.def.BindingDef; import com.gitee.dorive.api.entity.element.PropChain; import com.gitee.dorive.core.api.context.Context; import com.gitee.dorive.core.api.context.Selector; @@ -26,13 +25,10 @@ import com.gitee.dorive.core.entity.executor.OrderBy; import com.gitee.dorive.core.entity.executor.Page; import com.gitee.dorive.core.entity.executor.Result; import com.gitee.dorive.core.entity.operation.Query; -import com.gitee.dorive.core.impl.binder.ContextBinder; -import com.gitee.dorive.core.impl.binder.PropertyBinder; import com.gitee.dorive.core.impl.resolver.BinderResolver; import lombok.Data; import lombok.EqualsAndHashCode; -import java.util.Collection; import java.util.List; @Data @@ -66,7 +62,7 @@ public class CommonRepository extends ProxyRepository { @Override public Result executeQuery(Context context, Query query) { Selector selector = context.getSelector(); - List properties = selector.selectColumns(context, this); + List properties = selector.select(context, this); if (properties != null && !properties.isEmpty()) { if (query.getPrimaryKey() != null) { Example example = new Example().eq("id", query.getPrimaryKey()); @@ -75,7 +71,7 @@ public class CommonRepository extends ProxyRepository { } Example example = query.getExample(); if (example != null) { - example.selectColumns(properties); + example.select(properties); } } Example example = query.getExample(); @@ -84,43 +80,14 @@ public class CommonRepository extends ProxyRepository { Page page = example.getPage(); return page != null ? new Result<>(page) : new Result<>(); } - if (example.getOrderBy() == null) { - example.setOrderBy(defaultOrderBy); + if (example.getOrderBy() == null && defaultOrderBy != null) { + OrderBy orderBy = new OrderBy(defaultOrderBy.getProperties(), defaultOrderBy.getOrder()); + example.setOrderBy(orderBy); } } return super.executeQuery(context, query); } - public Example newExampleByContext(Context context, Object rootEntity) { - Example example = new Example(); - for (PropertyBinder propertyBinder : binderResolver.getPropertyBinders()) { - BindingDef bindingDef = propertyBinder.getBindingDef(); - String field = bindingDef.getField(); - Object boundValue = propertyBinder.getBoundValue(context, rootEntity); - if (boundValue instanceof Collection) { - boundValue = !((Collection) boundValue).isEmpty() ? boundValue : null; - } - if (boundValue != null) { - boundValue = propertyBinder.input(context, boundValue); - example.eq(field, boundValue); - } else { - example.getCriteria().clear(); - break; - } - } - if (example.isDirtyQuery()) { - for (ContextBinder contextBinder : binderResolver.getContextBinders()) { - BindingDef bindingDef = contextBinder.getBindingDef(); - String field = bindingDef.getField(); - Object boundValue = contextBinder.getBoundValue(context, rootEntity); - if (boundValue != null) { - example.eq(field, boundValue); - } - } - } - return example; - } - public Object getPrimaryKey(Object entity) { return getEntityEle().getPkProxy().getValue(entity); } diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/repository/DefaultRepository.java b/dorive-core/src/main/java/com/gitee/dorive/core/repository/DefaultRepository.java index 7cc7b35686ada05715bbe5308434494fcaebda15..ec576f8ac08a16b34b1b8407ec667839cb6c030c 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/repository/DefaultRepository.java +++ b/dorive-core/src/main/java/com/gitee/dorive/core/repository/DefaultRepository.java @@ -23,6 +23,6 @@ import lombok.NoArgsConstructor; @Data @NoArgsConstructor -@EqualsAndHashCode(callSuper = true) +@EqualsAndHashCode(callSuper = false) public class DefaultRepository extends AbstractRepository { } diff --git a/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/entity/JoinSegment.java b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/entity/JoinSegment.java index 3f2cf810f05292123f71c2de4f39c531e657575e..023c3bd723f517c1bc94c68e61e64674eca09f0f 100644 --- a/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/entity/JoinSegment.java +++ b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/entity/JoinSegment.java @@ -23,7 +23,7 @@ import lombok.EqualsAndHashCode; import java.util.List; @Data -@EqualsAndHashCode(callSuper = true) +@EqualsAndHashCode(callSuper = false) public class JoinSegment extends Segment { private String tableName; private String tableAlias; diff --git a/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/entity/OnSegment.java b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/entity/OnSegment.java index 0f2996bb39c347d59a26ec9efa6ab3dec0bfa716..53ff3a252e5d04cdac3d47c5a7e69dd4a8f4ac2a 100644 --- a/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/entity/OnSegment.java +++ b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/entity/OnSegment.java @@ -21,7 +21,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; @Data -@EqualsAndHashCode(callSuper = true) +@EqualsAndHashCode(callSuper = false) public class OnSegment extends Segment { private String tableAlias; diff --git a/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/entity/SelectSegment.java b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/entity/SelectSegment.java index 70206e2340591c67083c09819e7a781f51ae580e..695847cf6296d9937bf77ea4cb6cda48ade46703 100644 --- a/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/entity/SelectSegment.java +++ b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/entity/SelectSegment.java @@ -26,7 +26,7 @@ import java.util.List; import java.util.stream.Collectors; @Data -@EqualsAndHashCode(callSuper = true) +@EqualsAndHashCode(callSuper = false) public class SelectSegment extends Segment { private boolean distinct; @@ -39,14 +39,18 @@ public class SelectSegment extends Segment { private String orderBy; private String limit; - public SqlBuilder createBuilder() { + public String selectSql() { SqlBuilder sqlBuilder = SqlBuilder.create(); sqlBuilder.select(distinct, columns); + return sqlBuilder.toString(); + } + + public String fromWhereSql() { + SqlBuilder sqlBuilder = SqlBuilder.create(); sqlBuilder.from(tableName + " " + tableAlias); for (JoinSegment joinSegment : joinSegments) { if (joinSegment.isAvailable()) { sqlBuilder.join(joinSegment.getTableName() + " " + joinSegment.getTableAlias(), SqlBuilder.Join.LEFT); - List onSegments = joinSegment.getOnSegments().stream() .filter(onSegment -> onSegment.getDirectedSegments().get(0).isAvailable()) .collect(Collectors.toList()); @@ -54,6 +58,11 @@ public class SelectSegment extends Segment { } } sqlBuilder.where(StrUtil.join(" AND ", argSegments)); + return sqlBuilder.toString(); + } + + public String lastSql() { + SqlBuilder sqlBuilder = SqlBuilder.create(); if (groupBy != null) { sqlBuilder.append(" ").append(groupBy); } @@ -63,12 +72,12 @@ public class SelectSegment extends Segment { if (limit != null) { sqlBuilder.append(" ").append(limit); } - return sqlBuilder; + return sqlBuilder.toString(); } @Override public String toString() { - return createBuilder().toString(); + return selectSql() + fromWhereSql() + lastSql(); } } diff --git a/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/AppenderContext.java b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/AppenderContext.java index c2a3e8ddf35fc0acd42c9648c4a55316c8d0c809..ec31c3f3da1805d33263ad4d77b688776951ad13 100644 --- a/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/AppenderContext.java +++ b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/AppenderContext.java @@ -18,13 +18,17 @@ package com.gitee.dorive.spring.boot.starter.impl; import com.baomidou.mybatisplus.core.conditions.interfaces.Compare; -import com.gitee.dorive.spring.boot.starter.api.CriterionAppender; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.gitee.dorive.api.constant.Operator; -import com.gitee.dorive.core.util.SqlUtils; +import com.gitee.dorive.core.entity.executor.MultiInBuilder; +import com.gitee.dorive.spring.boot.starter.api.CriterionAppender; +import com.gitee.dorive.spring.boot.starter.util.SqlUtils; import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; public class AppenderContext { @@ -57,14 +61,35 @@ public class AppenderContext { OPERATOR_CRITERION_APPENDER_MAP.put(Operator.IS_NOT_NULL, (abstractWrapper, property, value) -> abstractWrapper.isNotNull(property)); OPERATOR_CRITERION_APPENDER_MAP.put(Operator.NULL_SWITCH, (abstractWrapper, property, value) -> { if (value instanceof Boolean) { - Boolean flag = (Boolean) value; - if (flag) { + if ((Boolean) value) { abstractWrapper.isNull(property); } else { abstractWrapper.isNotNull(property); } } }); + OPERATOR_CRITERION_APPENDER_MAP.put(Operator.MULTI_IN, (abstractWrapper, property, value) -> { + if (value instanceof MultiInBuilder) { + MultiInBuilder builder = (MultiInBuilder) value; + StringBuilder valuesStr = new StringBuilder(); + for (int page = 1; page <= builder.page(); page++) { + List values = builder.get(page); + valuesStr.append(buildValuesStr(values)); + } + if (valuesStr.length() > 0) { + valuesStr.deleteCharAt(valuesStr.length() - 1); + } + if (abstractWrapper.isEmptyOfWhere()) { + abstractWrapper.last(" WHERE (" + property + ") IN (" + valuesStr + ")"); + } else { + abstractWrapper.last(" AND (" + property + ") IN (" + valuesStr + ")"); + } + } + }); + } + + public static String buildValuesStr(List values) { + return values.stream().map(StringUtils::sqlParam).collect(Collectors.joining(",", "(", "),")); } } diff --git a/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/SQLExampleBuilder.java b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/SQLExampleBuilder.java index c49bb0711c978b018aa5d4cbc43495245e08f7bb..e2fe7fca1ac49f33daf4c9deda5c8463cda2ac29 100644 --- a/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/SQLExampleBuilder.java +++ b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/SQLExampleBuilder.java @@ -18,7 +18,6 @@ package com.gitee.dorive.spring.boot.starter.impl; import cn.hutool.core.collection.CollUtil; -import cn.hutool.db.sql.SqlBuilder; import com.baomidou.mybatisplus.extension.toolkit.SqlRunner; import com.gitee.dorive.coating.api.ExampleBuilder; import com.gitee.dorive.coating.repository.AbstractCoatingRepository; @@ -30,7 +29,7 @@ import com.gitee.dorive.spring.boot.starter.entity.SegmentResult; import com.gitee.dorive.spring.boot.starter.entity.SelectSegment; import lombok.Data; -import java.util.Collections; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -67,13 +66,19 @@ public class SQLExampleBuilder implements ExampleBuilder { if (!selectSegment.isDirtyQuery()) { return example; } - + selectSegment.setDistinct(true); - selectSegment.setColumns(Collections.singletonList(selectSegment.getTableAlias() + ".id")); - SqlBuilder builder = selectSegment.createBuilder(); + + List selectColumns = new ArrayList<>(2); + String tableAlias = selectSegment.getTableAlias(); + selectColumns.add(tableAlias + ".id"); + selectSegment.setColumns(selectColumns); + + String fromWhereSql = selectSegment.fromWhereSql(); if (page != null) { - long count = SqlRunner.db().selectCount("SELECT COUNT(1) FROM (" + builder + ") " + letter, args.toArray()); + String countSql = selectSegment.selectSql() + fromWhereSql; + long count = SqlRunner.db().selectCount("SELECT COUNT(1) FROM (" + countSql + ") " + letter, args.toArray()); page.setTotal(count); example.setCountQueried(true); if (count == 0) { @@ -83,13 +88,19 @@ public class SQLExampleBuilder implements ExampleBuilder { } if (orderBy != null) { - builder.append(" ").append(orderBy.toString()); + for (String property : orderBy.getProperties()) { + if (!"id".equals(property)) { + selectColumns.add(tableAlias + "." + property); + } + } + selectSegment.setOrderBy(orderBy.toString()); } if (page != null) { - builder.append(" ").append(page.toString()); + selectSegment.setLimit(page.toString()); } - List> resultMaps = SqlRunner.db().selectList(builder.toString(), args.toArray()); + String selectSql = selectSegment.selectSql() + fromWhereSql + selectSegment.lastSql(); + List> resultMaps = SqlRunner.db().selectList(selectSql, args.toArray()); List primaryKeys = CollUtil.map(resultMaps, map -> map.get("id"), true); if (!primaryKeys.isEmpty()) { example.eq("id", primaryKeys); diff --git a/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/SegmentBuilder.java b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/SegmentBuilder.java index 44b3635693526fdd1b5348579fc0bd066502ec18..462f1649c1ae4c99e490e496d4a4720028e5f2e8 100644 --- a/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/SegmentBuilder.java +++ b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/SegmentBuilder.java @@ -17,40 +17,26 @@ package com.gitee.dorive.spring.boot.starter.impl; -import cn.hutool.core.lang.Assert; import com.baomidou.mybatisplus.core.metadata.TableInfo; import com.gitee.dorive.api.constant.Operator; -import com.gitee.dorive.coating.entity.CoatingRepositories; +import com.gitee.dorive.coating.entity.CoatingCriteria; +import com.gitee.dorive.coating.entity.CoatingType; import com.gitee.dorive.coating.entity.MergedRepository; -import com.gitee.dorive.coating.entity.PropertyRepository; -import com.gitee.dorive.coating.entity.SpecificProperties; -import com.gitee.dorive.coating.impl.resolver.CoatingRepositoriesResolver; import com.gitee.dorive.coating.repository.AbstractCoatingRepository; 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.core.entity.executor.Page; import com.gitee.dorive.core.impl.binder.PropertyBinder; import com.gitee.dorive.core.impl.resolver.BinderResolver; import com.gitee.dorive.core.repository.CommonRepository; -import com.gitee.dorive.core.util.CriterionUtils; -import com.gitee.dorive.core.util.SqlUtils; import com.gitee.dorive.spring.boot.starter.api.Keys; -import com.gitee.dorive.spring.boot.starter.entity.ArgSegment; -import com.gitee.dorive.spring.boot.starter.entity.JoinSegment; -import com.gitee.dorive.spring.boot.starter.entity.OnSegment; -import com.gitee.dorive.spring.boot.starter.entity.Segment; -import com.gitee.dorive.spring.boot.starter.entity.SegmentResult; -import com.gitee.dorive.spring.boot.starter.entity.SelectSegment; +import com.gitee.dorive.spring.boot.starter.entity.*; import com.gitee.dorive.spring.boot.starter.impl.executor.AliasExecutor; +import com.gitee.dorive.spring.boot.starter.util.CriterionUtils; 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.*; @Data @AllArgsConstructor @@ -59,26 +45,26 @@ public class SegmentBuilder { private final AbstractCoatingRepository repository; public SegmentResult buildSegment(Object coating) { - CoatingRepositoriesResolver resolver = repository.getCoatingRepositoriesResolver(); - Map coatingRepositoriesMap = resolver.getNameCoatingRepositoriesMap(); - CoatingRepositories coatingRepositories = coatingRepositoriesMap.get(coating.getClass().getName()); - Assert.notNull(coatingRepositories, "No coating definition found!"); - - List propertyRepositories = coatingRepositories.getPropertyRepositories(); - Map segmentMap = new LinkedHashMap<>(propertyRepositories.size() * 4 / 3 + 1); + CoatingType coatingType = repository.getCoatingType(coating); + CoatingCriteria coatingCriteria = coatingType.newCriteria(coating); + Map> criteriaMap = coatingCriteria.getCriteriaMap(); + OrderBy orderBy = coatingCriteria.getOrderBy(); + Page page = coatingCriteria.getPage(); + + List mergedRepositories = coatingType.getMergedRepositories(); + Map segmentMap = new LinkedHashMap<>(mergedRepositories.size() * 4 / 3 + 1); char letter = 'a'; SelectSegment selectSegment = null; List argSegments = new ArrayList<>(); List args = new ArrayList<>(); - for (PropertyRepository propertyRepository : propertyRepositories) { - MergedRepository mergedRepository = propertyRepository.getMergedRepository(); + for (MergedRepository mergedRepository : mergedRepositories) { String lastAccessPath = mergedRepository.getLastAccessPath(); String absoluteAccessPath = mergedRepository.getAbsoluteAccessPath(); + String relativeAccessPath = mergedRepository.getRelativeAccessPath(); CommonRepository definedRepository = mergedRepository.getDefinedRepository(); CommonRepository executedRepository = mergedRepository.getExecutedRepository(); - String relativeAccessPath = mergedRepository.isMerged() ? absoluteAccessPath + "/" : absoluteAccessPath; BinderResolver binderResolver = definedRepository.getBinderResolver(); Map attachments = executedRepository.getAttachments(); @@ -89,15 +75,14 @@ public class SegmentBuilder { String tableAlias = String.valueOf(letter); letter = (char) (letter + 1); - Example example = propertyRepository.newExampleByCoating(coating); - aliasExecutor.convert(example); - - appendArguments(argSegments, args, tableAlias, example); + List criteria = criteriaMap.computeIfAbsent(absoluteAccessPath, key -> Collections.emptyList()); + aliasExecutor.convertCriteria(criteria); + appendArguments(argSegments, args, tableAlias, criteria); if ("/".equals(relativeAccessPath)) { selectSegment = new SelectSegment(); selectSegment.setReachable(true); - selectSegment.setDirtyQuery(example.isDirtyQuery()); + selectSegment.setDirtyQuery(!criteria.isEmpty()); selectSegment.setDirectedSegments(new ArrayList<>(8)); selectSegment.setDistinct(false); selectSegment.setColumns(Collections.emptyList()); @@ -107,10 +92,12 @@ public class SegmentBuilder { selectSegment.setArgSegments(argSegments); segmentMap.put(relativeAccessPath, selectSegment); + aliasExecutor.convertOrderBy(orderBy); + } else { JoinSegment joinSegment = new JoinSegment(); joinSegment.setReachable(false); - joinSegment.setDirtyQuery(example.isDirtyQuery()); + joinSegment.setDirtyQuery(!criteria.isEmpty()); joinSegment.setDirectedSegments(new ArrayList<>(4)); joinSegment.setTableName(tableName); joinSegment.setTableAlias(tableAlias); @@ -131,38 +118,25 @@ public class SegmentBuilder { markReachableAndDirty(selectSegment); } - SpecificProperties properties = coatingRepositories.getSpecificProperties(); - OrderBy orderBy = properties.newOrderBy(coating); - Page page = properties.newPage(coating); - return new SegmentResult(letter, selectSegment, args, orderBy, page); } - private void appendArguments(List argSegments, List args, String tableAlias, Example example) { - List criteria = example.getCriteria(); + private void appendArguments(List argSegments, + List args, + String tableAlias, + List criteria) { for (Criterion criterion : criteria) { - String property = criterion.getProperty(); + String property = tableAlias + "." + criterion.getProperty(); String operator = CriterionUtils.getOperator(criterion); - Object value = criterion.getValue(); - if (operator.endsWith(Operator.LIKE)) { - value = SqlUtils.toLike(value); - } - ArgSegment argSegment = null; - if (Operator.NULL_SWITCH.equals(operator)) { - if (value instanceof Boolean) { - Boolean flag = (Boolean) value; - argSegment = new ArgSegment(tableAlias + "." + property, flag ? Operator.IS_NULL : Operator.IS_NOT_NULL, null); - } - - } else if (operator.startsWith("IS")) { - argSegment = new ArgSegment(tableAlias + "." + property, operator, null); + if (Operator.IS_NULL.equals(operator) || Operator.IS_NOT_NULL.equals(operator)) { + ArgSegment argSegment = new ArgSegment(property, operator, null); + argSegments.add(argSegment); } else { - args.add(value); + Object value = criterion.getValue(); + args.add(CriterionUtils.format(operator, value)); int index = args.size() - 1; - argSegment = new ArgSegment(tableAlias + "." + property, operator, "{" + index + "}"); - } - if (argSegment != null) { + ArgSegment argSegment = new ArgSegment(property, operator, "{" + index + "}"); argSegments.add(argSegment); } } @@ -177,10 +151,8 @@ public class SegmentBuilder { List onSegments = new ArrayList<>(propertyBinders.size()); for (PropertyBinder propertyBinder : propertyBinders) { - String belongAccessPath = propertyBinder.getBelongAccessPath(); - String targetAccessPath = lastAccessPath + belongAccessPath; - - Segment segment = segmentMap.get(targetAccessPath); + String relativeAccessPath = lastAccessPath + propertyBinder.getBelongAccessPath(); + Segment segment = segmentMap.get(relativeAccessPath); if (segment != null) { String alias = propertyBinder.getAlias(); String joinTableAlias = segment.getTableAlias(); diff --git a/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/executor/AliasExecutor.java b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/executor/AliasExecutor.java index 16aa4802f456988c51a8aa39c437058dafd6f0fc..552e2e6a6a81a9c6c4c7b27e1eb2eab5031757f4 100644 --- a/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/executor/AliasExecutor.java +++ b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/executor/AliasExecutor.java @@ -20,11 +20,7 @@ package com.gitee.dorive.spring.boot.starter.impl.executor; import com.gitee.dorive.api.entity.element.EntityEle; import com.gitee.dorive.core.api.context.Context; import com.gitee.dorive.core.api.executor.Executor; -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.core.entity.executor.Result; -import com.gitee.dorive.core.entity.executor.UnionExample; +import com.gitee.dorive.core.entity.executor.*; import com.gitee.dorive.core.entity.operation.Condition; import com.gitee.dorive.core.entity.operation.Operation; import com.gitee.dorive.core.entity.operation.Query; @@ -37,7 +33,7 @@ import java.util.List; @Data @AllArgsConstructor -@EqualsAndHashCode(callSuper = true) +@EqualsAndHashCode(callSuper = false) public class AliasExecutor extends AbstractExecutor { private EntityEle entityEle; @@ -85,13 +81,20 @@ public class AliasExecutor extends AbstractExecutor { } public void convert(Example example) { - List selectColumns = example.getSelectColumns(); - if (selectColumns != null && !selectColumns.isEmpty()) { - selectColumns = entityEle.toAliases(selectColumns); - example.selectColumns(selectColumns); + convertSelect(example); + convertCriteria(example.getCriteria()); + convertOrderBy(example.getOrderBy()); + } + + public void convertSelect(Example example) { + List properties = example.getSelectProps(); + if (properties != null && !properties.isEmpty()) { + properties = entityEle.toAliases(properties); + example.setSelectProps(properties); } + } - List criteria = example.getCriteria(); + public void convertCriteria(List criteria) { if (criteria != null && !criteria.isEmpty()) { for (Criterion criterion : criteria) { String property = criterion.getProperty(); @@ -99,12 +102,13 @@ public class AliasExecutor extends AbstractExecutor { criterion.setProperty(property); } } + } - OrderBy orderBy = example.getOrderBy(); + public void convertOrderBy(OrderBy orderBy) { if (orderBy != null) { - List orderByColumns = orderBy.getColumns(); - orderByColumns = entityEle.toAliases(orderByColumns); - orderBy.setColumns(orderByColumns); + List properties = orderBy.getProperties(); + properties = entityEle.toAliases(properties); + orderBy.setProperties(properties); } } diff --git a/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/executor/FactoryExecutor.java b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/executor/FactoryExecutor.java index 59d56ff9a7e6f0ee929d2f4211e903c5ce4b6f58..93d24a8dd31c707ef3342ba0da1ad4151bc2d119 100644 --- a/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/executor/FactoryExecutor.java +++ b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/executor/FactoryExecutor.java @@ -24,6 +24,7 @@ import com.gitee.dorive.core.api.common.EntityFactory; import com.gitee.dorive.core.api.context.Context; import com.gitee.dorive.core.api.executor.Executor; import com.gitee.dorive.core.entity.executor.Example; +import com.gitee.dorive.core.entity.executor.MultiResult; import com.gitee.dorive.core.entity.executor.Result; import com.gitee.dorive.core.entity.executor.UnionExample; import com.gitee.dorive.core.entity.operation.Insert; @@ -31,19 +32,19 @@ import com.gitee.dorive.core.entity.operation.Operation; import com.gitee.dorive.core.entity.operation.Query; import com.gitee.dorive.core.impl.executor.AbstractExecutor; import com.gitee.dorive.spring.boot.starter.entity.QueryResult; -import com.gitee.dorive.core.entity.executor.MultiResult; import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @Data @AllArgsConstructor -@EqualsAndHashCode(callSuper = true) +@EqualsAndHashCode(callSuper = false) public class FactoryExecutor extends AbstractExecutor { private EntityEle entityEle; @@ -58,12 +59,13 @@ public class FactoryExecutor extends AbstractExecutor { List> resultMaps = queryResult.getResultMaps(); if (resultMaps != null) { - List entities = reconstitute(context, resultMaps); + List entities; if (example instanceof UnionExample) { - return new MultiResult(resultMaps, entities); + entities = reconstituteWithoutDuplicate(context, resultMaps); } else { - return new Result<>(entities); + entities = reconstitute(context, resultMaps); } + return new MultiResult(resultMaps, entities); } Page> queryPage = queryResult.getPage(); @@ -78,6 +80,30 @@ public class FactoryExecutor extends AbstractExecutor { return new Result<>(Collections.emptyList()); } + private List reconstituteWithoutDuplicate(Context context, List> resultMaps) { + int size = resultMaps.size(); + List entities = new ArrayList<>(size); + Map existEntityMap = new LinkedHashMap<>(size * 4 / 3 + 1); + for (Map resultMap : resultMaps) { + Object id = resultMap.get("id"); + Object entity = null; + if (id != null) { + entity = existEntityMap.get(String.valueOf(id)); + } + if (entity == null) { + entity = entityFactory.reconstitute(context, resultMap); + if (id != null) { + existEntityMap.put(String.valueOf(id), entity); + } + entities.add(entity); + } + if (entity != null) { + resultMap.put("$entity", entity); + } + } + return entities; + } + private List reconstitute(Context context, List> resultMaps) { List entities = new ArrayList<>(resultMaps.size()); for (Map resultMap : resultMaps) { diff --git a/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/executor/MybatisPlusExecutor.java b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/executor/MybatisPlusExecutor.java index 7293b734cebb5dd024b65bdf9ebe60155b4713f9..830fd61a8473438647570c4ef289c1247e96401c 100644 --- a/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/executor/MybatisPlusExecutor.java +++ b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/impl/executor/MybatisPlusExecutor.java @@ -18,6 +18,7 @@ package com.gitee.dorive.spring.boot.starter.impl.executor; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; @@ -30,11 +31,21 @@ import com.gitee.dorive.api.constant.Order; import com.gitee.dorive.api.entity.def.EntityDef; import com.gitee.dorive.api.entity.element.EntityEle; import com.gitee.dorive.core.api.context.Context; -import com.gitee.dorive.core.entity.executor.*; -import com.gitee.dorive.core.entity.operation.*; +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.core.entity.executor.Result; +import com.gitee.dorive.core.entity.executor.UnionExample; +import com.gitee.dorive.core.entity.operation.Delete; +import com.gitee.dorive.core.entity.operation.Insert; +import com.gitee.dorive.core.entity.operation.NullableUpdate; +import com.gitee.dorive.core.entity.operation.Operation; +import com.gitee.dorive.core.entity.operation.Query; +import com.gitee.dorive.core.entity.operation.Update; import com.gitee.dorive.core.impl.executor.AbstractExecutor; import com.gitee.dorive.spring.boot.starter.api.CriterionAppender; import com.gitee.dorive.spring.boot.starter.entity.QueryResult; +import com.gitee.dorive.spring.boot.starter.util.CriterionUtils; import lombok.Getter; import lombok.Setter; import lombok.ToString; @@ -115,18 +126,18 @@ public class MybatisPlusExecutor extends AbstractExecutor { private QueryWrapper buildQueryWrapper(Example example) { QueryWrapper queryWrapper = new QueryWrapper<>(); - List selectColumns = example.getSelectColumns(); - if (selectColumns != null && !selectColumns.isEmpty()) { - queryWrapper.select(selectColumns); + List selectProps = example.getSelectProps(); + if (selectProps != null && !selectProps.isEmpty()) { + queryWrapper.select(selectProps); } - List extraColumns = example.getExtraColumns(); - if (extraColumns != null && !extraColumns.isEmpty()) { + List extraProps = example.getExtraProps(); + if (extraProps != null && !extraProps.isEmpty()) { String sqlSelect = queryWrapper.getSqlSelect(); if (StringUtils.isBlank(sqlSelect)) { sqlSelect = queryWrapper.select(pojoClass, i -> true).getSqlSelect(); } - sqlSelect = sqlSelect + StringPool.COMMA + queryWrapper.select(extraColumns).getSqlSelect(); + sqlSelect = sqlSelect + StringPool.COMMA + queryWrapper.select(extraProps).getSqlSelect(); queryWrapper.select(sqlSelect); } @@ -139,10 +150,10 @@ public class MybatisPlusExecutor extends AbstractExecutor { if (orderBy != null) { String order = orderBy.getOrder(); if (Order.ASC.equals(order)) { - queryWrapper.orderByAsc(orderBy.getColumns()); + queryWrapper.orderByAsc(orderBy.getProperties()); } else if (Order.DESC.equals(order)) { - queryWrapper.orderByDesc(orderBy.getColumns()); + queryWrapper.orderByDesc(orderBy.getProperties()); } } @@ -167,7 +178,7 @@ public class MybatisPlusExecutor extends AbstractExecutor { String sqlSelect = nextQueryWrapper.getSqlSelect(); String tableName = TableInfoHelper.getTableInfo(pojoClass).getTableName(); - String criteria = nextExample.buildCriteria(); + String criteria = CollUtil.join(nextExample.getCriteria(), " AND ", CriterionUtils::toString); String sql = ""; if (nextExample.getOrderBy() == null && nextExample.getPage() == null) { diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/util/CriterionUtils.java b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/util/CriterionUtils.java similarity index 49% rename from dorive-core/src/main/java/com/gitee/dorive/core/util/CriterionUtils.java rename to dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/util/CriterionUtils.java index ca4aaf21a1a4473d585e1c9932e77e03ab7eb88d..f3dba511e463b81b3b6674ea55ed5d3926624ded 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/util/CriterionUtils.java +++ b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/util/CriterionUtils.java @@ -15,22 +15,18 @@ * limitations under the License. */ -package com.gitee.dorive.core.util; +package com.gitee.dorive.spring.boot.starter.util; -import cn.hutool.core.util.StrUtil; +import cn.hutool.core.date.DateUtil; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.gitee.dorive.api.constant.Operator; import com.gitee.dorive.core.entity.executor.Criterion; -import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.Collection; import java.util.Date; -import java.util.List; public class CriterionUtils { - private static final SimpleDateFormat SQL_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - public static String getOperator(Criterion criterion) { String operator = criterion.getOperator(); Object value = criterion.getValue(); @@ -41,59 +37,47 @@ public class CriterionUtils { } else if (Operator.NE.equals(operator)) { operator = Operator.NOT_IN; } + } else { + if (Operator.IN.equals(operator)) { + operator = Operator.EQ; + + } else if (Operator.NOT_IN.equals(operator)) { + operator = Operator.NE; + + } else if (Operator.NULL_SWITCH.equals(operator) && value instanceof Boolean) { + return (Boolean) value ? Operator.IS_NULL : Operator.IS_NOT_NULL; + } } return operator; } public static Object getValue(Criterion criterion) { - return convertValue(criterion); - } - - private static String convertValue(Criterion criterion) { String operator = criterion.getOperator(); Object value = criterion.getValue(); - if (value instanceof Collection) { - Collection collection = (Collection) value; - List values = new ArrayList<>(collection.size()); - for (Object item : collection) { - values.add(doConvertValue(criterion, item)); - } - return "(" + StrUtil.join(", ", values) + ")"; - - } else if (operator.endsWith(Operator.IN)) { - return "(" + doConvertValue(criterion, value) + ")"; - } - return doConvertValue(criterion, value); + return StringUtils.sqlParam(format(operator, value)); } - private static String doConvertValue(Criterion criterion, Object value) { - String operator = criterion.getOperator(); - if (value instanceof Number) { - return String.valueOf(value); - - } else if (value instanceof String) { - if (operator.endsWith(Operator.LIKE)) { - value = SqlUtils.toLike(value); - } - return "'" + value + "'"; - - } else if (value instanceof Date) { - return "'" + SQL_DATE_FORMAT.format((Date) value) + "'"; - - } else if (value == null || operator.startsWith("IS")) { - return "NULL"; + public static Object format(String operator, Object value) { + if (value instanceof Collection) { + return value; + } + if (value instanceof Date) { + value = DateUtil.formatDateTime((Date) value); } - return value.toString(); + if (Operator.LIKE.equals(operator) || Operator.NOT_LIKE.equals(operator)) { + value = SqlUtils.toLike(value); + } + return value; } public static String toString(Criterion criterion) { - StringBuilder builder = new StringBuilder(); - builder.append(criterion.getProperty()).append(" ").append(getOperator(criterion)); - String operator = criterion.getOperator(); - if (!operator.startsWith("IS")) { - builder.append(" ").append(getValue(criterion)); + String property = criterion.getProperty(); + String operator = getOperator(criterion); + if (Operator.IS_NULL.equals(operator) || Operator.IS_NOT_NULL.equals(operator)) { + return property + " " + operator; + } else { + return property + " " + operator + " " + getValue(criterion); } - return builder.toString(); } } diff --git a/dorive-core/src/main/java/com/gitee/dorive/core/util/SqlUtils.java b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/util/SqlUtils.java similarity index 95% rename from dorive-core/src/main/java/com/gitee/dorive/core/util/SqlUtils.java rename to dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/util/SqlUtils.java index 7df1dc5c7d9575b69a27e5f165fa2ea501c20f76..e9f23486b30c0c64bed4db3bb8c222f9adece07b 100644 --- a/dorive-core/src/main/java/com/gitee/dorive/core/util/SqlUtils.java +++ b/dorive-spring-boot-starter/src/main/java/com/gitee/dorive/spring/boot/starter/util/SqlUtils.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package com.gitee.dorive.core.util; +package com.gitee.dorive.spring.boot.starter.util; public class SqlUtils {