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