001/*
002 *  Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
003 *  <p>
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *  <p>
008 *  http://www.apache.org/licenses/LICENSE-2.0
009 *  <p>
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016
017package com.mybatisflex.core.field;
018
019import com.mybatisflex.core.BaseMapper;
020import com.mybatisflex.core.exception.FlexExceptions;
021import com.mybatisflex.core.query.QueryWrapper;
022import com.mybatisflex.core.row.Row;
023import com.mybatisflex.core.util.ClassUtil;
024import com.mybatisflex.core.util.CollectionUtil;
025
026import java.lang.reflect.Array;
027import java.util.*;
028
029/**
030 * 属性查询管理。
031 *
032 * @author 王帅
033 * @since 2023-07-15
034 */
035public class FieldQueryManager {
036
037    private FieldQueryManager() {
038    }
039
040    public static void queryFields(BaseMapper<?> mapper, Collection<?> entities, Map<String, FieldQuery> fieldQueryMap) {
041        for (Object entity : entities) {
042            fieldQueryMap.forEach((key, fieldQuery) -> {
043                //不是当前类的内容
044                if (!key.startsWith(entity.getClass().getName() + "#")) {
045                    return;
046                }
047
048                QueryWrapper queryWrapper = fieldQuery.getQueryBuilder().build(entity);
049                Class<?> filedType = fieldQuery.getFieldWrapper().getFieldType();
050                Object value;
051
052                if (Collection.class.isAssignableFrom(filedType)) {
053                    Class<?> mappingType = fieldQuery.getFieldWrapper().getMappingType();
054                    List<?> list = mapper.selectListByQueryAs(queryWrapper, mappingType);
055                    // 转换成 Collection 子类,或者空 Collection 对象,避免 NPE
056                    value = getCollectionValue(filedType, list);
057                    // 循环查询泛型实体类
058                    if ((!Number.class.isAssignableFrom(mappingType)
059                        || !String.class.isAssignableFrom(mappingType)
060                        || !Map.class.isAssignableFrom(mappingType))
061                        && !fieldQuery.isPrevent()) {
062                        queryFields(mapper, (Collection<?>) value, fieldQueryMap);
063                    }
064                } else if (Map.class.isAssignableFrom(filedType)) {
065                    List<Row> rows = mapper.selectRowsByQuery(queryWrapper);
066                    // 转换成 Map 子类,或者空 Map 对象,避免 NPE
067                    if (rows != null && !rows.isEmpty() && rows.get(0) != null) {
068                        value = getMapValue(filedType, rows.get(0));
069                    } else {
070                        value = new HashMap<>();
071                    }
072                } else if (filedType.isArray()) {
073                    Class<?> componentType = filedType.getComponentType();
074                    List<?> objects = mapper.selectListByQueryAs(queryWrapper, componentType);
075                    value = getArrayValue(componentType, objects);
076                }
077                // 实体类
078                else {
079                    value = mapper.selectOneByQueryAs(queryWrapper, filedType);
080                    // 循环查询嵌套类
081                    if (!fieldQuery.isPrevent()) {
082                        queryFields(mapper, Collections.singletonList(value), fieldQueryMap);
083                    }
084                }
085                // 属性查询出来的值不为 null 时,为属性设置值
086                if (value != null) {
087                    fieldQuery.getFieldWrapper().set(value, entity);
088                }
089            });
090        }
091    }
092
093
094    @SuppressWarnings({"rawtypes", "unchecked"})
095    private static Object getCollectionValue(Class<?> fieldType, Collection value) {
096        if (value == null) {
097            if (fieldType == List.class) {
098                return Collections.emptyList();
099            } else if (fieldType == Set.class) {
100                return Collections.emptySet();
101            }
102        }
103
104        if (ClassUtil.canInstance(fieldType.getModifiers())) {
105            Collection collection = (Collection) ClassUtil.newInstance(fieldType);
106            collection.addAll(value);
107            return collection;
108        }
109
110        if (List.class.isAssignableFrom(fieldType)) {
111            return value;
112        }
113
114        if (Set.class.isAssignableFrom(fieldType)) {
115            return new HashSet<>(value);
116        }
117
118        throw FlexExceptions.wrap("Unsupported collection type: " + fieldType);
119    }
120
121    @SuppressWarnings({"rawtypes", "unchecked"})
122    private static Object getMapValue(Class<?> fieldType, Map value) {
123        if (ClassUtil.canInstance(fieldType.getModifiers())) {
124            Map map = (Map) ClassUtil.newInstance(fieldType);
125            map.putAll(value);
126            return map;
127        }
128
129        return new HashMap<>(value);
130    }
131
132    @SuppressWarnings("unchecked")
133    private static <T> Object getArrayValue(Class<?> componentType, List<T> list) {
134        if (CollectionUtil.isEmpty(list)) {
135            return Array.newInstance(componentType, 0);
136        }
137
138        T[] array = (T[]) Array.newInstance(componentType, list.size());
139
140        for (int rows = 0; rows < list.size(); rows++) {
141            array[rows] = list.get(rows);
142        }
143
144        return array;
145    }
146
147}