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.*;
025
026import java.math.BigDecimal;
027import java.math.BigInteger;
028import java.sql.Time;
029import java.sql.Timestamp;
030import java.time.LocalDateTime;
031import java.util.*;
032import java.util.function.BooleanSupplier;
033import java.util.function.Predicate;
034
035public class Row extends LinkedHashMap<String, Object> implements UpdateWrapper<Row> {
036
037    //主键,多个主键用英文逗号隔开
038    private Set<RowKey> primaryKeys;
039
040    public static Row of(String key, Object value) {
041        Row row = new Row();
042        return row.set(key, value);
043    }
044
045    @Override
046    public Map<String, Object> getUpdates() {
047        return this;
048    }
049
050    public static Row ofKey(String primaryKey, Object value) {
051        Row row = new Row();
052        String[] primaryKeyStrings = primaryKey.split(",");
053        row.primaryKeys = new HashSet<>(primaryKeyStrings.length);
054
055        for (String primaryKeyString : primaryKeyStrings) {
056            row.primaryKeys.add(RowKey.of(primaryKeyString.trim()));
057        }
058
059        if (primaryKeyStrings.length > 1 && !value.getClass().isArray()) {
060            throw new IllegalArgumentException("The type of \"" + value + "\" must be an array.");
061        }
062
063        if (primaryKeyStrings.length == 1) {
064            row.put(primaryKey.trim(), value);
065        } else {
066            Object[] values = (Object[]) value;
067            for (int i = 0; i < primaryKeyStrings.length; i++) {
068                row.put(primaryKeyStrings[i].trim(), values[i]);
069            }
070        }
071        return row;
072    }
073
074    public static Row ofKey(RowKey... rowKeys) {
075        Row row = new Row();
076        row.getPrimaryKeys().addAll(Arrays.asList(rowKeys));
077        return row;
078    }
079
080
081    public static Row ofKey(RowKey rowKey, Object value) {
082        Row row = new Row();
083        row.getPrimaryKeys().add(rowKey);
084        row.put(rowKey.keyColumn, value);
085        return row;
086    }
087
088
089    public static Row ofKey(RowKey[] rowKeys, Object[] value) {
090        Row row = new Row();
091        row.getPrimaryKeys().addAll(Arrays.asList(rowKeys));
092        for (int i = 0; i < rowKeys.length; i++) {
093            row.put(rowKeys[i].keyColumn, value[i]);
094        }
095        return row;
096    }
097
098    @Override
099    public Row set(String property, Object value, boolean isEffective) {
100        if (!isEffective) {
101            return this;
102        }
103
104        if (StringUtil.isBlank(property)) {
105            throw new IllegalArgumentException("key column not be null or empty.");
106        }
107
108        SqlUtil.keepColumnSafely(property);
109
110        if (value instanceof QueryWrapper || value instanceof QueryCondition || value instanceof QueryColumn) {
111            super.put(property, new RawValue(value));
112        } else {
113            super.put(property, value);
114        }
115
116        return this;
117    }
118
119    @Override
120    public Row set(QueryColumn property, Object value, boolean isEffective) {
121        if (!isEffective) {
122            return this;
123        }
124
125        if (value instanceof QueryWrapper || value instanceof QueryCondition || value instanceof QueryColumn) {
126            super.put(property.getName(), new RawValue(value));
127        } else {
128            super.put(property.getName(), value);
129        }
130
131        return this;
132    }
133
134    @Override
135    public <T> Row set(LambdaGetter<T> property, Object value, boolean isEffective) {
136        if (!isEffective) {
137            return this;
138        }
139
140        if (value instanceof QueryWrapper || value instanceof QueryCondition || value instanceof QueryColumn) {
141            super.put(LambdaUtil.getFieldName(property), new RawValue(value));
142        } else {
143            super.put(LambdaUtil.getFieldName(property), value);
144        }
145
146        return this;
147    }
148
149    @Override
150    public Row setRaw(String property, Object value, boolean isEffective) {
151        return (Row) UpdateWrapper.super.setRaw(property, value, isEffective);
152    }
153
154    @Override
155    public Row setRaw(QueryColumn property, Object value, boolean isEffective) {
156        return (Row) UpdateWrapper.super.setRaw(property, value, isEffective);
157    }
158
159    @Override
160    public <T> Row setRaw(LambdaGetter<T> property, Object value, boolean isEffective) {
161        return (Row) UpdateWrapper.super.setRaw(property, value, isEffective);
162    }
163
164
165    @Override
166    public Row set(String property, Object value) {
167        return set(property, value, true);
168    }
169
170    @Override
171    public Row set(String property, Object value, BooleanSupplier isEffective) {
172        return set(property, value, isEffective.getAsBoolean());
173    }
174
175    @Override
176    public <V> Row set(String property, V value, Predicate<V> isEffective) {
177        return set(property, value, isEffective.test(value));
178    }
179
180    @Override
181    public Row set(QueryColumn property, Object value) {
182        return set(property, value, true);
183    }
184
185    @Override
186    public Row set(QueryColumn property, Object value, BooleanSupplier isEffective) {
187        return set(property, value, isEffective.getAsBoolean());
188    }
189
190    @Override
191    public <V> Row set(QueryColumn property, V value, Predicate<V> isEffective) {
192        return set(property, value, isEffective.test(value));
193    }
194
195    @Override
196    public <T> Row set(LambdaGetter<T> property, Object value) {
197        return set(property, value, true);
198    }
199
200    @Override
201    public <T> Row set(LambdaGetter<T> property, Object value, BooleanSupplier isEffective) {
202        return set(property, value, isEffective.getAsBoolean());
203    }
204
205    @Override
206    public <T, V> Row set(LambdaGetter<T> property, V value, Predicate<V> isEffective) {
207        return set(property, value, isEffective.test(value));
208    }
209
210    @Override
211    public Row setRaw(String property, Object value) {
212        return setRaw(property, value, true);
213    }
214
215    @Override
216    public Row setRaw(String property, Object value, BooleanSupplier isEffective) {
217        return setRaw(property, value, isEffective.getAsBoolean());
218    }
219
220    @Override
221    public <V> Row setRaw(String property, V value, Predicate<V> isEffective) {
222        return setRaw(property, value, isEffective.test(value));
223    }
224
225    @Override
226    public Row setRaw(QueryColumn property, Object value) {
227        return setRaw(property, value, true);
228    }
229
230    @Override
231    public Row setRaw(QueryColumn property, Object value, BooleanSupplier isEffective) {
232        return setRaw(property, value, isEffective.getAsBoolean());
233    }
234
235    @Override
236    public <V> Row setRaw(QueryColumn property, V value, Predicate<V> isEffective) {
237        return setRaw(property, value, isEffective.test(value));
238    }
239
240    @Override
241    public <T> Row setRaw(LambdaGetter<T> property, Object value) {
242        return setRaw(property, value, true);
243    }
244
245    @Override
246    public <T> Row setRaw(LambdaGetter<T> property, Object value, BooleanSupplier isEffective) {
247        return setRaw(property, value, isEffective.getAsBoolean());
248    }
249
250    @Override
251    public <T, V> Row setRaw(LambdaGetter<T> property, V value, Predicate<V> isEffective) {
252        return setRaw(property, value, isEffective.test(value));
253    }
254
255    public Object get(String key, Object defaultValue) {
256        Object result = super.get(key);
257        return result != null ? result : defaultValue;
258    }
259
260    public Object getIgnoreCase(String key) {
261        String camelKey = null;
262        if (key.contains("_")) {
263            camelKey = StringUtil.deleteChar(key, '_');
264        }
265        for (String innerKey : keySet()) {
266            if (innerKey.equalsIgnoreCase(key) || (camelKey != null && camelKey.equalsIgnoreCase(innerKey))) {
267                return super.get(innerKey);
268            }
269        }
270        return null;
271    }
272
273
274    public Object getIgnoreCase(String key, Object defaultValue) {
275        Object result = getIgnoreCase(key);
276        return result != null ? result : defaultValue;
277    }
278
279
280    @Override
281    public Object put(String key, Object value) {
282        if (!containsKey(key)) {
283            return super.put(key, value);
284        } else {
285            for (int i = 1; i < 100; i++) {
286                String newKey = key + RowUtil.INDEX_SEPARATOR + 1;
287                if (!containsKey(newKey)) {
288                    return super.put(newKey, value);
289                }
290            }
291        }
292        return super.put(key, value);
293    }
294
295
296    public String getString(String key) {
297        Object s = super.get(key);
298        return s != null ? s.toString() : null;
299    }
300
301
302    public String getString(String key, String defaultValue) {
303        Object s = super.get(key);
304        if (s == null) {
305            return defaultValue;
306        }
307        String r = s.toString();
308        return r.trim().length() == 0 ? defaultValue : r;
309    }
310
311    public Integer getInt(String key) {
312        return ConvertUtil.toInt(super.get(key));
313    }
314
315    public Integer getInt(String key, Integer defaultValue) {
316        Integer r = ConvertUtil.toInt(super.get(key));
317        return r != null ? r : defaultValue;
318    }
319
320    public Long getLong(String key) {
321        return ConvertUtil.toLong(super.get(key));
322    }
323
324    public Long getLong(String key, Long defaultValue) {
325        Long r = ConvertUtil.toLong(super.get(key));
326        return r != null ? r : defaultValue;
327    }
328
329    public Double getDouble(String key) {
330        return ConvertUtil.toDouble(super.get(key));
331    }
332
333    public Double getDouble(String key, Double defaultValue) {
334        Double r = ConvertUtil.toDouble(super.get(key));
335        return r != null ? r : defaultValue;
336    }
337
338    public Float getFloat(String key, Float defaultValue) {
339        Float r = ConvertUtil.toFloat(super.get(key));
340        return r != null ? r : defaultValue;
341    }
342
343    public Float getFloat(String key) {
344        return ConvertUtil.toFloat(super.get(key));
345    }
346
347
348    public Short getShort(String key, Short defaultValue) {
349        Short r = ConvertUtil.toShort(super.get(key));
350        return r != null ? r : defaultValue;
351    }
352
353    public Short getShort(String key) {
354        return ConvertUtil.toShort(super.get(key));
355    }
356
357    public BigInteger getBigInteger(String key) {
358        return ConvertUtil.toBigInteger(super.get(key));
359    }
360
361    public BigInteger getBigInteger(String key, BigInteger defaultValue) {
362        BigInteger r = ConvertUtil.toBigInteger(super.get(key));
363        return r != null ? r : defaultValue;
364    }
365
366    public BigDecimal getBigDecimal(String key) {
367        return ConvertUtil.toBigDecimal(super.get(key));
368    }
369
370    public BigDecimal getBigDecimal(String key, BigDecimal defaultValue) {
371        BigDecimal r = ConvertUtil.toBigDecimal(super.get(key));
372        return r != null ? r : defaultValue;
373    }
374
375    public Boolean getBoolean(String key) {
376        return ConvertUtil.toBoolean(super.get(key));
377    }
378
379    public Boolean getBoolean(String key, Boolean defaultValue) {
380        Boolean r = ConvertUtil.toBoolean(super.get(key));
381        return r != null ? r : defaultValue;
382    }
383
384    public Date getDate(String key) {
385        return ConvertUtil.toDate(super.get(key));
386    }
387
388    public Date getDate(String key, Date defaultValue) {
389        Date r = ConvertUtil.toDate(super.get(key));
390        return r != null ? r : defaultValue;
391    }
392
393    public LocalDateTime getLocalDateTime(String key) {
394        return ConvertUtil.toLocalDateTime(super.get(key));
395    }
396
397    public LocalDateTime getLocalDateTime(String key, LocalDateTime defaultValue) {
398        LocalDateTime r = ConvertUtil.toLocalDateTime(super.get(key));
399        return r != null ? r : defaultValue;
400    }
401
402    public Time getTime(String key) {
403        return (Time) super.get(key);
404    }
405
406    public Time getTime(String key, Time defaultValue) {
407        Time r = (Time) super.get(key);
408        return r != null ? r : defaultValue;
409    }
410
411    public Timestamp getTimestamp(String key) {
412        return (Timestamp) super.get(key);
413    }
414
415    public Timestamp getTimestamp(String key, Timestamp defaultValue) {
416        Timestamp r = (Timestamp) super.get(key);
417        return r != null ? r : defaultValue;
418    }
419
420    public Byte getByte(String key) {
421        return ConvertUtil.toByte(super.get(key));
422    }
423
424    public byte[] getBytes(String key) {
425        return (byte[]) super.get(key);
426    }
427
428    @Override
429    public Object remove(Object key) {
430        for (String innerKey : keySet()) {
431            if (innerKey.equalsIgnoreCase((String) key)) {
432                return super.remove(innerKey);
433            }
434        }
435        return null;
436    }
437
438    public <T> T toEntity(Class<T> entityClass) {
439        return RowUtil.toEntity(this, entityClass);
440    }
441
442    public <T> T toObject(Class<T> objectClass) {
443        return RowUtil.toObject(this, objectClass);
444    }
445
446    public Map<String, Object> toCamelKeysMap() {
447        Map<String, Object> ret = new HashMap<>();
448        for (String key : keySet()) {
449            ret.put(StringUtil.underlineToCamel(key), get(key));
450        }
451        return ret;
452    }
453
454    public Map<String, Object> toUnderlineKeysMap() {
455        Map<String, Object> ret = new HashMap<>();
456        for (String key : keySet()) {
457            ret.put(StringUtil.camelToUnderline(key), get(key));
458        }
459        return ret;
460    }
461
462    public Set<RowKey> getPrimaryKeys() {
463        if (primaryKeys == null) {
464            primaryKeys = new HashSet<>();
465        }
466        return primaryKeys;
467    }
468
469    public void setPrimaryKeys(Set<RowKey> primaryKeys) {
470        this.primaryKeys = primaryKeys;
471    }
472
473    public void keep(String... columns) {
474        entrySet().removeIf(entry -> !ArrayUtil.contains(columns, entry.getKey()));
475    }
476
477
478    public void keep(Set<String> columns) {
479        entrySet().removeIf(entry -> !columns.contains(entry.getKey()));
480    }
481
482
483    Set<String> getModifyAttrs() {
484        int pkCount = primaryKeys != null ? primaryKeys.size() : 0;
485        if (pkCount == 0) {
486            return keySet();
487        }
488
489        Set<String> attrs = new LinkedHashSet<>(keySet());
490        attrs.removeIf(this::isPk);
491        return attrs;
492    }
493
494    Map<String, RawValue> getRawValueMap() {
495        Map<String, RawValue> map = new HashMap<>();
496        forEach((s, o) -> {
497            if (o instanceof RawValue) {
498                map.put(s, (RawValue) o);
499            }
500        });
501        return map;
502    }
503
504
505    /**
506     * 获取修改的值,值需要保持顺序,返回的内容不包含主键的值
507     */
508    Object[] obtainModifyValuesWithoutPk() {
509        List<Object> values = new ArrayList<>();
510        for (String key : keySet()) {
511            Object value = get(key);
512            if (!isPk(key) && !(value instanceof RawValue)) {
513                values.add(value);
514            }
515        }
516        return values.toArray();
517    }
518
519
520    String[] obtainsPrimaryKeyStrings() {
521        String[] returnKeys = new String[primaryKeys.size()];
522        int index = 0;
523        for (RowKey primaryKey : primaryKeys) {
524            returnKeys[index++] = primaryKey.keyColumn;
525        }
526        return returnKeys;
527    }
528
529
530    RowKey[] obtainsPrimaryKeys() {
531        return getPrimaryKeys().toArray(new RowKey[0]);
532    }
533
534
535    Object[] obtainsPrimaryValues() {
536        if (CollectionUtil.isEmpty(primaryKeys)) {
537            return FlexConsts.EMPTY_ARRAY;
538        }
539        Object[] values = new Object[primaryKeys.size()];
540
541        int index = 0;
542        for (RowKey primaryKey : primaryKeys) {
543            values[index++] = get(primaryKey.keyColumn);
544        }
545        return values;
546    }
547
548
549    Object[] obtainAllModifyValues() {
550        return ArrayUtil.concat(obtainModifyValuesWithoutPk(), obtainsPrimaryValues());
551    }
552
553
554    public Object[] obtainInsertValues() {
555        List<Object> values = new ArrayList<>();
556        if (primaryKeys != null && !primaryKeys.isEmpty()) {
557            for (RowKey primaryKey : primaryKeys) {
558                if (primaryKey.before) {
559                    values.add(get(primaryKey.keyColumn));
560                }
561            }
562        }
563
564        for (String key : keySet()) {
565            Object value = get(key);
566            if (!isPk(key) && !(value instanceof RawValue)) {
567                values.add(value);
568            }
569        }
570
571        return values.toArray();
572    }
573
574    public Set<String> getInsertAttrs() {
575        Set<String> attrs = new LinkedHashSet<>();
576        if (primaryKeys != null && !primaryKeys.isEmpty()) {
577            for (RowKey primaryKey : primaryKeys) {
578                if (primaryKey.before) {
579                    attrs.add(primaryKey.keyColumn);
580                }
581            }
582        }
583        attrs.addAll(keySet());
584        return attrs;
585    }
586
587    private boolean isPk(String attr) {
588        if (primaryKeys != null && !primaryKeys.isEmpty()) {
589            for (RowKey primaryKey : primaryKeys) {
590                if (primaryKey.keyColumn.equalsIgnoreCase(attr)) {
591                    return true;
592                }
593            }
594        }
595        return false;
596    }
597
598
599}