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
029import static com.mybatisflex.core.table.TableInfoFactory.defaultSupportColumnTypes;
030
031/**
032 * 属性查询管理。
033 *
034 * @author 王帅
035 * @since 2023-07-15
036 */
037public class FieldQueryManager {
038
039    private FieldQueryManager() {
040    }
041
042    public static void queryFields(BaseMapper<?> mapper, Collection<?> entities, Map<String, FieldQuery> fieldQueryMap) {
043        for (Object entity : entities) {
044
045            if (entity == null) {
046                continue;
047            }
048
049            String className = ClassUtil.getUsefulClass(entity.getClass()).getName();
050
051            fieldQueryMap.forEach((key, fieldQuery) -> {
052                // 不是当前类的内容
053                if (!key.startsWith(className + "#")) {
054                    return;
055                }
056
057                @SuppressWarnings("unchecked")
058                QueryWrapper queryWrapper = fieldQuery.getQueryBuilder().build(entity);
059
060                // QueryWrapper 为 null 值时,不进行属性查询
061                if (queryWrapper == null) {
062                    return;
063                }
064
065                Class<?> filedType = fieldQuery.getFieldWrapper().getFieldType();
066                Object value;
067
068                if (Collection.class.isAssignableFrom(filedType)) {
069                    Class<?> mappingType = fieldQuery.getFieldWrapper().getMappingType();
070                    List<?> list = mapper.selectListByQueryAs(queryWrapper, mappingType);
071                    // 转换成 Collection 子类,或者空 Collection 对象,避免 NPE
072                    value = getCollectionValue(filedType, list);
073                    // 循环查询泛型实体类
074                    if ((!Number.class.isAssignableFrom(mappingType)
075                        || !String.class.isAssignableFrom(mappingType)
076                        || !Map.class.isAssignableFrom(mappingType))
077                        && !fieldQuery.isPrevent()) {
078                        queryFields(mapper, (Collection<?>) value, fieldQueryMap);
079                    }
080                } else if (Map.class.isAssignableFrom(filedType)) {
081                    List<Row> rows = mapper.selectRowsByQuery(queryWrapper);
082                    // 转换成 Map 子类,或者空 Map 对象,避免 NPE
083                    if (rows != null && !rows.isEmpty() && rows.get(0) != null) {
084                        value = getMapValue(filedType, rows.get(0));
085                    } else {
086                        value = new HashMap<>();
087                    }
088                } else if (filedType.isArray()) {
089                    Class<?> componentType = filedType.getComponentType();
090                    List<?> objects = mapper.selectListByQueryAs(queryWrapper, componentType);
091                    value = getArrayValue(componentType, objects);
092                } else if (defaultSupportColumnTypes.contains(filedType)) {
093                    value = mapper.selectObjectByQueryAs(queryWrapper, filedType);
094                } else {
095                    value = mapper.selectOneByQueryAs(queryWrapper, filedType);
096                    // 循环查询嵌套类
097                    if (!fieldQuery.isPrevent()) {
098                        queryFields(mapper, Collections.singletonList(value), fieldQueryMap);
099                    }
100                }
101                // 属性查询出来的值不为 null 时,为属性设置值
102                if (value != null) {
103                    fieldQuery.getFieldWrapper().set(value, entity);
104                }
105            });
106        }
107    }
108
109
110    @SuppressWarnings({"rawtypes", "unchecked"})
111    private static Object getCollectionValue(Class<?> fieldType, Collection value) {
112        if (value == null) {
113            if (fieldType == List.class) {
114                return Collections.emptyList();
115            } else if (fieldType == Set.class) {
116                return Collections.emptySet();
117            }
118            // avoid NPE
119            return ClassUtil.newInstance(fieldType);
120        }
121
122        if (ClassUtil.canInstance(fieldType.getModifiers())) {
123            Collection collection = (Collection) ClassUtil.newInstance(fieldType);
124            collection.addAll(value);
125            return collection;
126        }
127
128        if (List.class.isAssignableFrom(fieldType)) {
129            return value;
130        }
131
132        if (Set.class.isAssignableFrom(fieldType)) {
133            return new HashSet<>(value);
134        }
135
136        throw FlexExceptions.wrap("Unsupported collection type: " + fieldType);
137    }
138
139    @SuppressWarnings({"rawtypes", "unchecked"})
140    private static Object getMapValue(Class<?> fieldType, Map value) {
141        if (ClassUtil.canInstance(fieldType.getModifiers())) {
142            Map map = (Map) ClassUtil.newInstance(fieldType);
143            map.putAll(value);
144            return map;
145        }
146
147        return new HashMap<>(value);
148    }
149
150    @SuppressWarnings("unchecked")
151    private static <T> Object getArrayValue(Class<?> componentType, List<T> list) {
152        if (CollectionUtil.isEmpty(list)) {
153            return Array.newInstance(componentType, 0);
154        }
155
156        T[] array = (T[]) Array.newInstance(componentType, list.size());
157
158        for (int rows = 0; rows < list.size(); rows++) {
159            array[rows] = list.get(rows);
160        }
161
162        return array;
163    }
164
165}