package com.w11k.lsql; import com.google.common.base.Objects; import com.google.common.base.Optional; import com.google.common.collect.ForwardingMap; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.math.BigDecimal; import java.util.List; import java.util.Map; import java.util.Set; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Maps.newHashMap; /** * */ public class Row extends ForwardingMap<String, Object> { @Deprecated public static boolean LEGACY_CONVERT_VALUE_ON_GET = false; private final Logger logger = LoggerFactory.getLogger(getClass()); public static Row fromKeyVals(Object... keyVals) { Row r = new Row(); r.addKeyVals(keyVals); return r; } private Map<String, Object> data; public Row() { this(Maps.<String, Object>newHashMap()); } public Row(Map<String, Object> data) { this.data = newHashMap(data); } // public void setDelegate(Map<String, Object> data) { // this.data = data; // } public Row addKeyVals(Object... keyVals) { checkArgument( keyVals.length == 0 || keyVals.length % 2 == 0, "content must be a list of iterant key value pairs."); Iterable<List<Object>> partition = Iterables.partition(newArrayList(keyVals), 2); for (List<Object> objects : partition) { Object key = objects.get(0); checkArgument(key instanceof String, "argument " + key + " is not a String"); Object value = objects.get(1); put(key.toString(), value); } return this; } @Override public Object put(String key, Object value) { return super.put(key, value); } public <A> A getAs(Class<A> type, String key) { //noinspection deprecation if (!LEGACY_CONVERT_VALUE_ON_GET) { return getAs(type, key, false); } // legacy mode try { return getAs(type, key, false); } catch (WrongTypeException e) { String msg = "Row entry for " + "key: '" + key + "' " + "will be converted implicitly to type: " + "'" + type.getCanonicalName() + "'. " + "Please use .getAs(type, key, true);"; logger.warn(msg); return getAs(type, key, true); } } public <A> A getAs(Class<A> type, String key, boolean convert) { if (!containsKey(key)) { throw new IllegalArgumentException("No entry for key '" + key + "'."); } Object value = get(key); if (value == null) { return null; } if (type.isAssignableFrom(value.getClass())) { return type.cast(value); } else if (convert) { try { return LSql.OBJECT_MAPPER.convertValue(value, type); } catch (Exception e) { throw new IllegalArgumentException("Row entry for " + "key: '" + key + "', " + "value: '" + value + "', " + "type: '" + value.getClass().getCanonicalName() + "' " + "can not be converted to type '" + type.getCanonicalName() + "'", e); } } else { throw new WrongTypeException("Row entry for " + "key: '" + key + "', " + "value: '" + value + "', " + "type: '" + value.getClass().getCanonicalName() + "' " + "can not be converted to type '" + type.getCanonicalName() + "'"); } } public <A> A getAsOr(Class<A> type, String key, A defaultValue) { if (!containsKey(key)) { return defaultValue; } return getAs(type, key); } public Optional<Object> getOptional(String key) { return Optional.fromNullable(get(key)); } public Integer getInt(String key) { return getAs(Integer.class, key); } public Long getLong(String key) { return getAs(Long.class, key); } public Double getDouble(String key) { return getAs(Double.class, key); } public Float getFloat(String key) { return getAs(Float.class, key); } public Boolean getBoolean(String key) { return getAs(Boolean.class, key); } public BigDecimal getBigDecimal(String key) { return getAs(BigDecimal.class, key); } public DateTime getDateTime(String key) { Object val = get(key); return val == null ? null : new DateTime(get(key)); } public String getString(String key) { return getAs(String.class, key); } public Row getRow(String key) { return getAs(Row.class, key); } public Blob getBlob(String key) { return getAs(Blob.class, key); } public byte[] getByteArray(String key) { Blob blob = getBlob(key); return blob == null ? null : blob.getData(); } @SuppressWarnings("unchecked") public <A> List<A> getAsListOf(Class<A> clazz, String key) { return (List<A>) get(key); } @SuppressWarnings("unchecked") public <A> Set<A> getAsSetOf(Class<A> clazz, String key) { return (Set<A>) get(key); } public boolean hasNonNullValue(String key) { return get(key) != null; } public Row pick(String... keys) { Row extracted = new Row(); for (String key : keys) { if (containsKey(key)) { extracted.put(key, get(key)); } } return extracted; } public Row putAllIfAbsent(Map<String, Object> source) { Row copiedValues = new Row(); for (String key : source.keySet()) { if (!containsKey(key)) { Object value = source.get(key); put(key, value); copiedValues.put(key, value); } } return copiedValues; } public Row copy() { Row copy = new Row(); copy.putAll(this); return copy; } @Override public String toString() { return Objects.toStringHelper(this).addValue(delegate()).toString(); } @Override protected Map<String, Object> delegate() { return data; } }