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 */
016package com.mybatisflex.core.util;
017
018import com.mybatisflex.core.BaseMapper;
019import com.mybatisflex.core.field.FieldQuery;
020import com.mybatisflex.core.field.FieldQueryBuilder;
021import com.mybatisflex.core.query.QueryWrapper;
022import org.apache.ibatis.exceptions.TooManyResultsException;
023import org.apache.ibatis.session.defaults.DefaultSqlSession;
024
025import java.util.*;
026import java.util.function.Consumer;
027
028public class MapperUtil {
029
030    private MapperUtil() {
031    }
032
033
034    public static <R> void queryFields(BaseMapper<?> mapper, List<R> list, Consumer<FieldQueryBuilder<R>>[] consumers) {
035        if (CollectionUtil.isEmpty(list) || ArrayUtil.isEmpty(consumers) || consumers[0] == null) {
036            return;
037        }
038        list.forEach(entity -> {
039            for (Consumer<FieldQueryBuilder<R>> consumer : consumers) {
040                FieldQueryBuilder<R> fieldQueryBuilder = new FieldQueryBuilder<>(entity);
041                consumer.accept(fieldQueryBuilder);
042                FieldQuery fieldQuery = fieldQueryBuilder.build();
043                QueryWrapper childQuery = fieldQuery.getQueryWrapper();
044
045                FieldWrapper fieldWrapper = FieldWrapper.of(entity.getClass(), fieldQuery.getField());
046
047                Class<?> fieldType = fieldWrapper.getFieldType();
048                Class<?> mappingType = fieldWrapper.getMappingType();
049
050                Object value;
051                if (Collection.class.isAssignableFrom(fieldType)) {
052                    value = mapper.selectListByQueryAs(childQuery, mappingType);
053                    if (!fieldType.isAssignableFrom(value.getClass())) {
054                        fieldType = getWrapType(fieldType);
055                        Collection newValue = (Collection) ClassUtil.newInstance(fieldType);
056                        newValue.addAll((Collection) value);
057                        value = newValue;
058                    }
059                } else if (fieldType.isArray()) {
060                    value = mapper.selectListByQueryAs(childQuery, mappingType);
061                    value = ((List<?>) value).toArray();
062                } else {
063                    value = mapper.selectOneByQueryAs(childQuery, mappingType);
064                }
065                fieldWrapper.set(value, entity);
066            }
067        });
068    }
069
070
071    private static Class<?> getWrapType(Class<?> type) {
072        if (List.class.isAssignableFrom(type)) {
073            return ArrayList.class;
074        }
075
076        if (Set.class.isAssignableFrom(type)) {
077            return HashSet.class;
078        }
079
080        throw new IllegalStateException("Field query can not support type: " + type.getName());
081    }
082
083
084    /**
085     * 搬运加改造 {@link DefaultSqlSession#selectOne(String, Object)}
086     */
087    public static <T> T getSelectOneResult(List<T> list) {
088        if (list == null || list.isEmpty()) {
089            return null;
090        }
091        int size = list.size();
092        if (size == 1) {
093            return list.get(0);
094        }
095        throw new TooManyResultsException(
096                "Expected one result (or null) to be returned by selectOne(), but found: " + size);
097    }
098}