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.relation;
017
018import com.mybatisflex.core.exception.FlexExceptions;
019import com.mybatisflex.core.query.QueryWrapper;
020import com.mybatisflex.core.row.Row;
021import com.mybatisflex.core.util.*;
022
023import java.lang.reflect.Field;
024import java.util.*;
025
026class ToManyRelation<SelfEntity> extends AbstractRelation<SelfEntity> {
027
028    protected String mapKeyField;
029    protected FieldWrapper mapKeyFieldWrapper;
030    protected String orderBy;
031    protected long limit = 0;
032    protected String selfValueSplitBy;
033
034
035    public ToManyRelation(String selfField, String targetSchema, String targetTable, String targetField, String valueField,
036                          String joinTable, String joinSelfColumn, String joinTargetColumn,
037                          String dataSource, Class<SelfEntity> selfEntityClass, Field relationField,
038                          String extraCondition, String[] selectColumns) {
039        super(selfField, targetSchema, targetTable, targetField, valueField,
040            joinTable, joinSelfColumn, joinTargetColumn,
041            dataSource, selfEntityClass, relationField,
042            extraCondition, selectColumns
043        );
044    }
045
046    /**
047     * 构建查询目标对象的 QueryWrapper
048     *
049     * @param targetValues 条件的值
050     * @return QueryWrapper
051     */
052    @Override
053    public QueryWrapper buildQueryWrapper(Set<Object> targetValues) {
054        if (StringUtil.isNotBlank(selfValueSplitBy) && CollectionUtil.isNotEmpty(targetValues)) {
055            Set<Object> newTargetValues = new HashSet<>();
056            for (Object targetValue : targetValues) {
057                if (targetValue == null) {
058                    continue;
059                }
060                if (!(targetValue instanceof String)) {
061                    throw FlexExceptions.wrap("split field only support String type, but current type is: \"" + targetValue.getClass().getName() + "\"");
062                }
063                String[] splitValues = ((String) targetValue).split(selfValueSplitBy);
064                for (String splitValue : splitValues) {
065                    //优化分割后的数据类型(防止在数据库查询时候出现隐式转换)
066                    newTargetValues.add(ConvertUtil.convert(splitValue, targetFieldWrapper.getFieldType()));
067                }
068            }
069            targetValues = newTargetValues;
070        }
071        return super.buildQueryWrapper(targetValues);
072    }
073
074
075    @Override
076    public void customizeQueryWrapper(QueryWrapper queryWrapper) {
077        if (StringUtil.isNotBlank(orderBy)) {
078            queryWrapper.orderBy(orderBy);
079        }
080
081        if (limit > 0) {
082            queryWrapper.limit(limit);
083        }
084    }
085
086    @SuppressWarnings("rawtypes")
087    @Override
088    public void join(List<SelfEntity> selfEntities, List<?> targetObjectList, List<Row> mappingRows) {
089        selfEntities.forEach(selfEntity -> {
090            Object selfValue = selfFieldWrapper.get(selfEntity);
091            if (selfValue != null) {
092                selfValue = selfValue.toString();
093                Set<String> targetMappingValues = new HashSet<>();
094                if (mappingRows != null) {
095                    for (Row mappingRow : mappingRows) {
096                        if (selfValue.equals(String.valueOf(mappingRow.getIgnoreCase(joinSelfColumn)))) {
097                            Object joinValue = mappingRow.getIgnoreCase(joinTargetColumn);
098                            if (joinValue != null) {
099                                targetMappingValues.add(joinValue.toString());
100                            }
101                        }
102                    }
103                } else {
104                    if (StringUtil.isNotBlank(selfValueSplitBy)) {
105                        String[] splitValues = ((String) selfValue).split(selfValueSplitBy);
106                        targetMappingValues.addAll(Arrays.asList(splitValues));
107                    } else {
108                        targetMappingValues.add((String) selfValue);
109                    }
110                }
111
112                if (targetMappingValues.isEmpty()) {
113                    return;
114                }
115
116                Class<?> fieldType = relationFieldWrapper.getFieldType();
117                //map
118                if (Map.class.isAssignableFrom(fieldType)) {
119                    Class<?> wrapType = getMapWrapType(fieldType);
120                    Map map = (Map) ClassUtil.newInstance(wrapType);
121                    for (Object targetObject : targetObjectList) {
122                        Object targetValue = targetFieldWrapper.get(targetObject);
123                        if (targetValue != null && targetMappingValues.contains(targetValue.toString())) {
124                            Object keyValue = mapKeyFieldWrapper.get(targetObject);
125                            Object needKeyValue = ConvertUtil.convert(keyValue, relationFieldWrapper.getKeyType());
126                            map.put(needKeyValue, targetObject);
127                        }
128                    }
129                    relationFieldWrapper.set(map, selfEntity);
130                }
131                //集合
132                else {
133                    Class<?> wrapType = MapperUtil.getCollectionWrapType(fieldType);
134                    Collection collection = (Collection) ClassUtil.newInstance(wrapType);
135                    for (Object targetObject : targetObjectList) {
136                        Object targetValue = targetFieldWrapper.get(targetObject);
137                        if (targetValue != null && targetMappingValues.contains(targetValue.toString())) {
138                            if (onlyQueryValueField) {
139                                //仅绑定某个字段
140                                collection.add(FieldWrapper.of(targetObject.getClass(), valueField).get(targetObject));
141                            } else {
142                                collection.add(targetObject);
143                            }
144                        }
145                    }
146                    relationFieldWrapper.set(collection, selfEntity);
147                }
148            }
149        });
150    }
151
152    public void setMapKeyField(String mapKeyField) {
153        this.mapKeyField = mapKeyField;
154        if (StringUtil.isNotBlank(mapKeyField)) {
155            this.mapKeyFieldWrapper = FieldWrapper.of(targetEntityClass, mapKeyField);
156        } else {
157            if (Map.class.isAssignableFrom(relationFieldWrapper.getFieldType())) {
158                throw FlexExceptions.wrap("Please config mapKeyField for map field: " + relationFieldWrapper.getField());
159            }
160        }
161    }
162
163    public static Class<? extends Map> getMapWrapType(Class<?> type) {
164        if (ClassUtil.canInstance(type.getModifiers())) {
165            return (Class<? extends Map>) type;
166        }
167
168        return HashMap.class;
169    }
170
171}