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