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