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.row;
017
018import com.mybatisflex.core.FlexConsts;
019import com.mybatisflex.core.query.QueryColumn;
020import com.mybatisflex.core.query.QueryCondition;
021import com.mybatisflex.core.query.QueryWrapper;
022import com.mybatisflex.core.update.RawValue;
023import com.mybatisflex.core.update.UpdateWrapper;
024import com.mybatisflex.core.util.ArrayUtil;
025import com.mybatisflex.core.util.ConvertUtil;
026import com.mybatisflex.core.util.SqlUtil;
027import com.mybatisflex.core.util.StringUtil;
028
029import java.math.BigDecimal;
030import java.math.BigInteger;
031import java.sql.Time;
032import java.sql.Timestamp;
033import java.time.LocalDateTime;
034import java.util.*;
035
036public class Row extends LinkedHashMap<String, Object> implements UpdateWrapper {
037
038    //主键,多个主键用英文逗号隔开
039    private RowKey[] primaryKeys;
040
041    public static Row of(String key, Object value) {
042        Row row = new Row();
043        return row.set(key, value);
044    }
045
046    @Override
047    public Map<String, Object> getUpdates() {
048        return this;
049    }
050
051    public static Row ofKey(String primaryKey, Object value) {
052        Row row = new Row();
053        String[] primaryKeyStrings = primaryKey.split(",");
054        row.primaryKeys = new RowKey[primaryKeyStrings.length];
055
056        for (int i = 0; i < primaryKeyStrings.length; i++) {
057            row.primaryKeys[i] = RowKey.of(primaryKeyStrings[i].trim());
058        }
059
060        if (primaryKeyStrings.length > 1 && !value.getClass().isArray()) {
061            throw new IllegalArgumentException("The type of \"" + value + "\" must be an array.");
062        }
063
064        if (primaryKeyStrings.length == 1) {
065            row.put(primaryKey.trim(), value);
066        } else {
067            Object[] values = (Object[]) value;
068            for (int i = 0; i < primaryKeyStrings.length; i++) {
069                row.put(primaryKeyStrings[i].trim(), values[i]);
070            }
071        }
072        return row;
073    }
074
075    public static Row ofKey(RowKey... rowKeys) {
076        Row row = new Row();
077        row.primaryKeys = rowKeys;
078        return row;
079    }
080
081
082    public static Row ofKey(RowKey rowKey, Object value) {
083        Row row = new Row();
084        row.primaryKeys = new RowKey[]{rowKey};
085        row.put(rowKey.keyColumn, value);
086        return row;
087    }
088
089
090    public static Row ofKey(RowKey[] rowKeys, Object[] value) {
091        Row row = new Row();
092        row.primaryKeys = rowKeys;
093        for (int i = 0; i < rowKeys.length; i++) {
094            row.put(rowKeys[i].keyColumn, value[i]);
095        }
096        return row;
097    }
098
099
100    @Override
101    public Row set(String column, Object value) {
102        if (StringUtil.isBlank(column)) {
103            throw new IllegalArgumentException("key column not be null or empty.");
104        }
105
106        SqlUtil.keepColumnSafely(column);
107
108        if (value instanceof QueryWrapper || value instanceof QueryCondition || value instanceof QueryColumn) {
109            setRaw(column, value);
110        } else {
111            super.put(column, value);
112        }
113
114        return this;
115    }
116
117    @Override
118    public Row set(QueryColumn queryColumn, Object value) {
119        if (value instanceof QueryWrapper || value instanceof QueryCondition || value instanceof QueryColumn) {
120            setRaw(queryColumn, value);
121        } else {
122            super.put(queryColumn.getName(), value);
123        }
124        return this;
125    }
126
127
128    public Object get(String key, Object defaultValue) {
129        Object result = super.get(key);
130        return result != null ? result : defaultValue;
131    }
132
133    public Object getIgnoreCase(String key) {
134        for (String innerKey : keySet()) {
135            if (innerKey.equalsIgnoreCase(key)) {
136                return super.get(innerKey);
137            }
138        }
139        return null;
140    }
141
142
143    public Object getIgnoreCase(String key, Object defaultValue) {
144        Object result = getIgnoreCase(key);
145        return result != null ? result : defaultValue;
146    }
147
148
149    @Override
150    public Object put(String key, Object value) {
151        if (!containsKey(key)) {
152            return super.put(key, value);
153        } else {
154            for (int i = 1; i < 100; i++) {
155                String newKey = key + RowUtil.INDEX_SEPARATOR + 1;
156                if (!containsKey(newKey)) {
157                    return super.put(newKey, value);
158                }
159            }
160        }
161        return super.put(key, value);
162    }
163
164
165    public String getString(String key) {
166        Object s = super.get(key);
167        return s != null ? s.toString() : null;
168    }
169
170
171    public String getString(String key, String defaultValue) {
172        Object s = super.get(key);
173        if (s == null) {
174            return defaultValue;
175        }
176        String r = s.toString();
177        return r.trim().length() == 0 ? defaultValue : r;
178    }
179
180    public Integer getInt(String key) {
181        return ConvertUtil.toInt(super.get(key));
182    }
183
184    public Integer getInt(String key, Integer defaultValue) {
185        Integer r = ConvertUtil.toInt(super.get(key));
186        return r != null ? r : defaultValue;
187    }
188
189    public Long getLong(String key) {
190        return ConvertUtil.toLong(super.get(key));
191    }
192
193    public Long getLong(String key, Long defaultValue) {
194        Long r = ConvertUtil.toLong(super.get(key));
195        return r != null ? r : defaultValue;
196    }
197
198    public Double getDouble(String key) {
199        return ConvertUtil.toDouble(super.get(key));
200    }
201
202    public Double getDouble(String key, Double defaultValue) {
203        Double r = ConvertUtil.toDouble(super.get(key));
204        return r != null ? r : defaultValue;
205    }
206
207    public Float getFloat(String key, Float defaultValue) {
208        Float r = ConvertUtil.toFloat(super.get(key));
209        return r != null ? r : defaultValue;
210    }
211
212    public Float getFloat(String key) {
213        return ConvertUtil.toFloat(super.get(key));
214    }
215
216
217    public Short getShort(String key, Short defaultValue) {
218        Short r = ConvertUtil.toShort(super.get(key));
219        return r != null ? r : defaultValue;
220    }
221
222    public Short getShort(String key) {
223        return ConvertUtil.toShort(super.get(key));
224    }
225
226    public BigInteger getBigInteger(String key) {
227        return ConvertUtil.toBigInteger(super.get(key));
228    }
229
230    public BigInteger getBigInteger(String key, BigInteger defaultValue) {
231        BigInteger r = ConvertUtil.toBigInteger(super.get(key));
232        return r != null ? r : defaultValue;
233    }
234
235    public BigDecimal getBigDecimal(String key) {
236        return ConvertUtil.toBigDecimal(super.get(key));
237    }
238
239    public BigDecimal getBigDecimal(String key, BigDecimal defaultValue) {
240        BigDecimal r = ConvertUtil.toBigDecimal(super.get(key));
241        return r != null ? r : defaultValue;
242    }
243
244    public Boolean getBoolean(String key) {
245        return ConvertUtil.toBoolean(super.get(key));
246    }
247
248    public Boolean getBoolean(String key, Boolean defaultValue) {
249        Boolean r = ConvertUtil.toBoolean(super.get(key));
250        return r != null ? r : defaultValue;
251    }
252
253    public Date getDate(String key) {
254        return ConvertUtil.toDate(super.get(key));
255    }
256
257    public Date getDate(String key, Date defaultValue) {
258        Date r = ConvertUtil.toDate(super.get(key));
259        return r != null ? r : defaultValue;
260    }
261
262    public LocalDateTime getLocalDateTime(String key) {
263        return ConvertUtil.toLocalDateTime(super.get(key));
264    }
265
266    public LocalDateTime getLocalDateTime(String key, LocalDateTime defaultValue) {
267        LocalDateTime r = ConvertUtil.toLocalDateTime(super.get(key));
268        return r != null ? r : defaultValue;
269    }
270
271    public Time getTime(String key) {
272        return (Time) super.get(key);
273    }
274
275    public Time getTime(String key, Time defaultValue) {
276        Time r = (Time) super.get(key);
277        return r != null ? r : defaultValue;
278    }
279
280    public Timestamp getTimestamp(String key) {
281        return (Timestamp) super.get(key);
282    }
283
284    public Timestamp getTimestamp(String key, Timestamp defaultValue) {
285        Timestamp r = (Timestamp) super.get(key);
286        return r != null ? r : defaultValue;
287    }
288
289    public Byte getByte(String key) {
290        return ConvertUtil.toByte(super.get(key));
291    }
292
293    public byte[] getBytes(String key) {
294        return (byte[]) super.get(key);
295    }
296
297    @Override
298    public Object remove(Object key) {
299        for (String innerKey : keySet()) {
300            if (innerKey.equalsIgnoreCase((String) key)) {
301                return super.remove(innerKey);
302            }
303        }
304        return null;
305    }
306
307    public <T> T toEntity(Class<T> entityClass) {
308        return RowUtil.toEntity(this, entityClass);
309    }
310
311    public <T> T toObject(Class<T> objectClass) {
312        return RowUtil.toObject(this, objectClass);
313    }
314
315    public Map<String, Object> toCamelKeysMap() {
316        Map<String, Object> ret = new HashMap<>();
317        for (String key : keySet()) {
318            ret.put(StringUtil.underlineToCamel(key), get(key));
319        }
320        return ret;
321    }
322
323    public Map<String, Object> toUnderlineKeysMap() {
324        Map<String, Object> ret = new HashMap<>();
325        for (String key : keySet()) {
326            ret.put(StringUtil.camelToUnderline(key), get(key));
327        }
328        return ret;
329    }
330
331    public RowKey[] getPrimaryKeys() {
332        return primaryKeys;
333    }
334
335    public void setPrimaryKeys(RowKey... primaryKeys) {
336        this.primaryKeys = primaryKeys;
337    }
338
339    public void keep(String... columns) {
340        entrySet().removeIf(entry -> !ArrayUtil.contains(columns, entry.getKey()));
341    }
342
343
344    public void keep(Set<String> columns) {
345        entrySet().removeIf(entry -> !columns.contains(entry.getKey()));
346    }
347
348
349    Set<String> getModifyAttrs() {
350        int pkCount = primaryKeys != null ? primaryKeys.length : 0;
351        if (pkCount == 0) {
352            return keySet();
353        }
354
355        Set<String> attrs = new LinkedHashSet<>(keySet());
356        attrs.removeIf(this::isPk);
357        return attrs;
358    }
359
360    Map<String, RawValue> getRawValueMap() {
361        Map<String, RawValue> map = new HashMap<>();
362        forEach((s, o) -> {
363            if (o instanceof RawValue) {
364                map.put(s, (RawValue) o);
365            }
366        });
367        return map;
368    }
369
370
371    /**
372     * 获取修改的值,值需要保持顺序,返回的内容不包含主键的值
373     */
374    Object[] obtainModifyValuesWithoutPk() {
375        List<Object> values = new ArrayList<>();
376        for (String key : keySet()) {
377            Object value = get(key);
378            if (!isPk(key) && !(value instanceof RawValue)) {
379                values.add(value);
380            }
381        }
382        return values.toArray();
383    }
384
385
386    String[] obtainsPrimaryKeyStrings() {
387        String[] returnKeys = new String[primaryKeys.length];
388        for (int i = 0; i < primaryKeys.length; i++) {
389            returnKeys[i] = primaryKeys[i].keyColumn;
390        }
391        return returnKeys;
392    }
393
394
395    RowKey[] obtainsPrimaryKeys() {
396        return this.primaryKeys;
397    }
398
399
400    Object[] obtainsPrimaryValues() {
401        if (ArrayUtil.isEmpty(primaryKeys)) {
402            return FlexConsts.EMPTY_ARRAY;
403        }
404        Object[] values = new Object[primaryKeys.length];
405        for (int i = 0; i < primaryKeys.length; i++) {
406            values[i] = get(primaryKeys[i].keyColumn);
407        }
408        return values;
409    }
410
411
412    Object[] obtainAllModifyValues() {
413        return ArrayUtil.concat(obtainModifyValuesWithoutPk(), obtainsPrimaryValues());
414    }
415
416
417    private boolean isPk(String attr) {
418        if (primaryKeys != null && primaryKeys.length > 0) {
419            for (RowKey primaryKey : primaryKeys) {
420                if (primaryKey.keyColumn.equalsIgnoreCase(attr)) {
421                    return true;
422                }
423            }
424        }
425        return false;
426    }
427
428
429}