All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tech.ydb.jdbc.common.MappingSetters Maven / Gradle / Ivy

There is a newer version: 2.3.5
Show newest version
package tech.ydb.jdbc.common;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeParseException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import com.google.common.io.ByteStreams;
import com.google.common.io.CharStreams;

import tech.ydb.table.values.DecimalType;
import tech.ydb.table.values.DecimalValue;
import tech.ydb.table.values.ListType;
import tech.ydb.table.values.ListValue;
import tech.ydb.table.values.OptionalType;
import tech.ydb.table.values.PrimitiveType;
import tech.ydb.table.values.PrimitiveValue;
import tech.ydb.table.values.Type;
import tech.ydb.table.values.Value;

import static tech.ydb.jdbc.YdbConst.CANNOT_LOAD_DATA_FROM_IS;
import static tech.ydb.jdbc.YdbConst.CANNOT_LOAD_DATA_FROM_READER;
import static tech.ydb.jdbc.YdbConst.UNABLE_TO_CAST;

public class MappingSetters {
    private MappingSetters() { }

    static Setters buildSetters(Type type) {
        return buildToValueImpl(type);
    }

    private static Setters buildToValueImpl(Type type) {
        Type.Kind kind = type.getKind();
        // TODO: Separate setters for primitive values?
        if (kind == Type.Kind.PRIMITIVE) {
            PrimitiveType id = (PrimitiveType) type;
            switch (id) {
                case Bytes:
                    return x -> PrimitiveValue.newBytesOwn(castAsBytes(id, x));
                case Text:
                    return x -> PrimitiveValue.newText(castAsString(id, x));
                case Json:
                    return x -> PrimitiveValue.newJson(castAsJson(id, x));
                case JsonDocument:
                    return x -> PrimitiveValue.newJsonDocument(castAsJson(id, x));
                case Yson:
                    return x -> PrimitiveValue.newYsonOwn(castAsYson(id, x));
                case Uuid:
                    return x -> castAsUuid(id, x);
                case Bool:
                    return x -> PrimitiveValue.newBool(castAsBoolean(id, x));
                case Int8:
                    return x -> PrimitiveValue.newInt8(castAsByte(id, x));
                case Uint8:
                    return x -> PrimitiveValue.newUint8(castAsByte(id, x));
                case Int16:
                    return x -> PrimitiveValue.newInt16(castAsShort(id, x));
                case Uint16:
                    return x -> PrimitiveValue.newUint16(castAsShort(id, x));
                case Int32:
                    return x -> PrimitiveValue.newInt32(castAsInt(id, x));
                case Uint32:
                    return x -> PrimitiveValue.newUint32(castAsInt(id, x));
                case Int64:
                    return x -> PrimitiveValue.newInt64(castAsLong(id, x));
                case Uint64:
                    return x -> PrimitiveValue.newUint64(castAsLong(id, x));
                case Float:
                    return x -> PrimitiveValue.newFloat(castAsFloat(id, x));
                case Double:
                    return x -> PrimitiveValue.newDouble(castAsDouble(id, x));
                case Date:
                    return x -> castToDate(id, x);
                case Datetime:
                    return x -> castToDateTime(id, x);
                case Timestamp:
                    return x -> castToTimestamp(id, x);
                case Interval:
                    return x -> castToInterval(id, x);
                case TzDate:
                    return x -> PrimitiveValue.newTzDate(castAsZonedDateTime(id, x));
                case TzDatetime:
                    return x -> PrimitiveValue.newTzDatetime(castAsZonedDateTime(id, x));
                case TzTimestamp:
                    return x -> PrimitiveValue.newTzTimestamp(castAsZonedDateTime(id, x));
                default:
                    return x -> {
                        throw castNotSupported(id, x);
                    };
            }
        } else if (kind == Type.Kind.DECIMAL) {
            return x -> castToDecimalValue((DecimalType) type, x);
        } else if (kind == Type.Kind.LIST) {
            ListType listType = (ListType) type;
            Setters itemSetter = buildToValueImpl(listType.getItemType());
            return x -> castAsList(listType, itemSetter, x);
        } else if (kind == Type.Kind.OPTIONAL) {
            return buildToValueImpl(((OptionalType) type).getItemType());
        } else {
            return x -> {
                throw castNotSupported(kind, x);
            };
        }
    }

    private static String toString(Object x) {
        return x == null ? "null" : (x.getClass() + ": " + x);
    }

    private static SQLException castNotSupported(PrimitiveType type, Object x, Exception cause) {
        return new SQLException(String.format(UNABLE_TO_CAST, toString(x), type), cause);
    }

    private static SQLException castNotSupported(PrimitiveType type, Object x) {
        return new SQLException(String.format(UNABLE_TO_CAST, toString(x), type));
    }

    private static SQLException castNotSupported(Type.Kind kind, Object x) {
        return new SQLException(String.format(UNABLE_TO_CAST, toString(x), kind));
    }

    private static ListValue castAsList(ListType type, Setters itemSetter, Object x) throws SQLException {
        if (x instanceof Collection) {
            Collection values = (Collection) x;
            int len = values.size();
            Value[] result = new Value[len];
            int index = 0;
            for (Object value : values) {
                if (value != null) {
                    if (value instanceof Value) {
                        result[index++] = (Value) value;
                    } else {
                        result[index++] = itemSetter.toValue(value);
                    }
                }
            }
            if (index < result.length) {
                result = Arrays.copyOf(result, index); // Some values are null
            }
            return type.newValueOwn(result);
        } else {
            throw castNotSupported(type.getKind(), x);
        }
    }

    private static byte[] castAsBytes(PrimitiveType type, Object x) throws SQLException {
        if (x instanceof byte[]) {
            return (byte[]) x;
        } else if (x instanceof String) {
            return ((String) x).getBytes();
        } else if (x instanceof InputStream) {
            return ByteStream.fromInputStream((InputStream) x, -1).asByteArray();
        } else if (x instanceof Reader) {
            return CharStream.fromReader((Reader) x, -1).asString().getBytes();
        } else if (x instanceof ByteStream) {
            return ((ByteStream) x).asByteArray();
        } else if (x instanceof CharStream) {
            return ((CharStream) x).asString().getBytes();
        } else {
            return castAsString(type, x).getBytes();
        }
    }

    private static byte[] castAsYson(PrimitiveType type, Object x) throws SQLException {
        if (x instanceof byte[]) {
            return (byte[]) x;
        } else if (x instanceof String) {
            return ((String) x).getBytes();
        } else if (x instanceof InputStream) {
            return ByteStream.fromInputStream((InputStream) x, -1).asByteArray();
        } else if (x instanceof Reader) {
            return CharStream.fromReader((Reader) x, -1).asString().getBytes();
        } else if (x instanceof ByteStream) {
            return ((ByteStream) x).asByteArray();
        } else if (x instanceof CharStream) {
            return ((CharStream) x).asString().getBytes();
        }
        throw castNotSupported(type, x);
    }

    @SuppressWarnings("unused")
    private static String castAsString(PrimitiveType type, Object x) throws SQLException {
        if (x instanceof String) {
            return (String) x;
        } else if (x instanceof byte[]) {
            return new String((byte[]) x);
        } else if (x instanceof InputStream) {
            return new String(ByteStream.fromInputStream((InputStream) x, -1).asByteArray());
        } else if (x instanceof Reader) {
            return CharStream.fromReader((Reader) x, -1).asString();
        } else if (x instanceof ByteStream) {
            return new String(((ByteStream) x).asByteArray());
        } else if (x instanceof CharStream) {
            return ((CharStream) x).asString();
        } else {
            return String.valueOf(x);
        }
    }

    private static String castAsJson(PrimitiveType type, Object x) throws SQLException {
        if (x instanceof String) {
            return (String) x;
        } else if (x instanceof byte[]) {
            return new String((byte[]) x);
        } else if (x instanceof InputStream) {
            return new String(ByteStream.fromInputStream((InputStream) x, -1).asByteArray());
        } else if (x instanceof Reader) {
            return CharStream.fromReader((Reader) x, -1).asString();
        } else if (x instanceof ByteStream) {
            return new String(((ByteStream) x).asByteArray());
        } else if (x instanceof CharStream) {
            return ((CharStream) x).asString();
        }
        throw castNotSupported(type, x);
    }

    private static PrimitiveValue castAsUuid(PrimitiveType type, Object x) throws SQLException {
        if (x instanceof String) {
            return PrimitiveValue.newUuid((String) x);
        } else if (x instanceof byte[]) {
            return PrimitiveValue.newUuid(new String((byte[]) x));
        } else if (x instanceof UUID) {
            return PrimitiveValue.newUuid((UUID) x);
        }
        throw castNotSupported(type, x);
    }

    private static byte castAsByte(PrimitiveType type, Object x) throws SQLException {
        if (x instanceof Byte) {
            return (Byte) x;
        } else if (x instanceof Boolean) {
            return (byte) (((Boolean) x) ? 1 : 0);
        }
        throw castNotSupported(type, x);
    }

    private static short castAsShort(PrimitiveType type, Object x) throws SQLException {
        if (x instanceof Short) {
            return (Short) x;
        } else if (x instanceof Byte) {
            return (Byte) x;
        } else if (x instanceof Boolean) {
            return (short) (((Boolean) x) ? 1 : 0);
        }
        throw castNotSupported(type, x);
    }

    private static int castAsInt(PrimitiveType type, Object x) throws SQLException {
        if (x instanceof Integer) {
            return (Integer) x;
        } else if (x instanceof Short) {
            return (Short) x;
        } else if (x instanceof Byte) {
            return (Byte) x;
        } else if (x instanceof Boolean) {
            return ((Boolean) x) ? 1 : 0;
        }
        throw castNotSupported(type, x);
    }

    private static long castAsLong(PrimitiveType type, Object x) throws SQLException {
        if (x instanceof Long) {
            return (Long) x;
        } else if (x instanceof Integer) {
            return (Integer) x;
        } else if (x instanceof Short) {
            return (Short) x;
        } else if (x instanceof Byte) {
            return (Byte) x;
        } else if (x instanceof Boolean) {
            return ((Boolean) x) ? 1L : 0L;
        } else if (x instanceof BigInteger) {
            return ((BigInteger) x).longValue();
        }
        throw castNotSupported(type, x);
    }

    private static float castAsFloat(PrimitiveType type, Object x) throws SQLException {
        if (x instanceof Float) {
            return (Float) x;
        } else if (x instanceof Integer) {
            return (Integer) x;
        } else if (x instanceof Short) {
            return (Short) x;
        } else if (x instanceof Byte) {
            return (Byte) x;
        } else if (x instanceof Boolean) {
            return ((Boolean) x) ? 1f : 0f;
        }
        throw castNotSupported(type, x);
    }

    private static double castAsDouble(PrimitiveType type, Object x) throws SQLException {
        if (x instanceof Double) {
            return (Double) x;
        } else if (x instanceof Float) {
            return (Float) x;
        } else if (x instanceof Long) {
            return (Long) x;
        } else if (x instanceof Integer) {
            return (Integer) x;
        } else if (x instanceof Short) {
            return (Short) x;
        } else if (x instanceof Byte) {
            return (Byte) x;
        } else if (x instanceof Boolean) {
            return ((Boolean) x) ? 1d : 0d;
        }
        throw castNotSupported(type, x);
    }

    private static boolean castAsBoolean(PrimitiveType type, Object x) throws SQLException {
        if (x instanceof Boolean) {
            return (boolean) x;
        } else if (x instanceof Number) {
            long lValue = ((Number) x).longValue();
            return lValue > 0;
        }
        throw castNotSupported(type, x);
    }

    private static ZonedDateTime castAsZonedDateTime(PrimitiveType type, Object x) throws SQLException {
        if (x instanceof ZonedDateTime) {
            return (ZonedDateTime) x;
        }
        throw castNotSupported(type, x);
    }

    private static PrimitiveValue castToInterval(PrimitiveType type, Object x) throws SQLException {
        if (x instanceof Duration) {
            return PrimitiveValue.newInterval((Duration) x);
        } else if (x instanceof Long) {
            return PrimitiveValue.newInterval((Long) x);
        } else if (x instanceof String) {
            Duration parsed;
            try {
                parsed = Duration.parse((String) x);
            } catch (DateTimeParseException e) {
                throw castNotSupported(type, x, e);
            }
            return PrimitiveValue.newInterval(parsed);
        }
        throw castNotSupported(type, x);
    }

    private static PrimitiveValue castToDate(PrimitiveType type, Object x) throws SQLException {
        if (x instanceof Instant) {
            return PrimitiveValue.newDate((Instant) x);
        } else if (x instanceof LocalDate) {
            return PrimitiveValue.newDate((LocalDate) x);
        } else if (x instanceof Long) {
            return PrimitiveValue.newDate(TimeUnit.MILLISECONDS.toDays((Long) x));
        } else if (x instanceof Date) {
            return PrimitiveValue.newDate(TimeUnit.MILLISECONDS.toDays(((Date) x).getTime()));
        } else if (x instanceof Timestamp) {
            return PrimitiveValue.newDate(TimeUnit.MILLISECONDS.toDays(((Timestamp) x).getTime()));
        } else if (x instanceof String) {
            Instant parsed;
            try {
                parsed = Instant.parse((String) x);
            } catch (DateTimeParseException e) {
                throw castNotSupported(type, x, e);
            }
            return PrimitiveValue.newDate(parsed);
        }
        throw castNotSupported(type, x);
    }

    private static PrimitiveValue castToDateTime(PrimitiveType type, Object x) throws SQLException {
        if (x instanceof Instant) {
            return PrimitiveValue.newDatetime((Instant) x);
        } else if (x instanceof LocalDateTime) {
            return PrimitiveValue.newDatetime((LocalDateTime) x);
        } else if (x instanceof Long) {
            return PrimitiveValue.newDatetime(TimeUnit.MILLISECONDS.toSeconds((Long) x));
        } else if (x instanceof Date) {
            return PrimitiveValue.newDatetime(TimeUnit.MILLISECONDS.toSeconds(((Date) x).getTime()));
        } else if (x instanceof Timestamp) {
            return PrimitiveValue.newDatetime(TimeUnit.MILLISECONDS.toSeconds(((Timestamp) x).getTime()));
        } else if (x instanceof String) {
            Instant parsed;
            try {
                parsed = Instant.parse((String) x);
            } catch (DateTimeParseException e) {
                throw castNotSupported(type, x, e);
            }
            return PrimitiveValue.newDatetime(parsed);
        }
        throw castNotSupported(type, x);
    }

    private static PrimitiveValue castToTimestamp(PrimitiveType type, Object x) throws SQLException {
        if (x instanceof Instant) {
            return PrimitiveValue.newTimestamp((Instant) x);
        } else if (x instanceof Long) {
            return PrimitiveValue.newTimestamp(TimeUnit.MILLISECONDS.toMicros((Long) x));
        } else if (x instanceof Date) {
            return PrimitiveValue.newTimestamp(TimeUnit.MILLISECONDS.toMicros(((Date) x).getTime()));
        } else if (x instanceof Timestamp) {
            return PrimitiveValue.newTimestamp(TimeUnit.MILLISECONDS.toMicros(((Timestamp) x).getTime()));
        } else if (x instanceof String) {
            Instant parsed;
            try {
                parsed = Instant.parse((String) x);
            } catch (DateTimeParseException e) {
                throw castNotSupported(type, x, e);
            }
            return PrimitiveValue.newTimestamp(parsed);
        }
        throw castNotSupported(type, x);
    }

    private static DecimalValue castToDecimalValue(DecimalType type, Object x) throws SQLException {
        if (x instanceof DecimalValue) {
            return (DecimalValue) x;
        } else if (x instanceof BigDecimal) {
            return type.newValue((BigDecimal) x);
        } else if (x instanceof BigInteger) {
            return type.newValue((BigInteger) x);
        } else if (x instanceof Long) {
            return type.newValue((Long) x);
        } else if (x instanceof Integer) {
            return type.newValue((Integer) x);
        } else if (x instanceof Short) {
            return type.newValue((Short) x);
        } else if (x instanceof Byte) {
            return type.newValue((Byte) x);
        } else if (x instanceof String) {
            return type.newValue((String) x);
        }
        throw castNotSupported(type.getKind(), x);
    }

    public interface Setters {
        Value toValue(Object value) throws SQLException;
    }

    public interface CharStream {
        String asString() throws SQLException;

        static CharStream fromReader(Reader reader, long length) {
            return () -> {
                try {
                    if (length >= 0) {
                        return CharStreams.toString(new LimitedReader(reader, length));
                    } else {
                        return CharStreams.toString(reader);
                    }
                } catch (IOException e) {
                    throw new RuntimeException(CANNOT_LOAD_DATA_FROM_READER + e.getMessage(), e);
                }
            };
        }
    }

    public interface ByteStream {
        byte[] asByteArray() throws SQLException;

        @SuppressWarnings("UnstableApiUsage")
        static ByteStream fromInputStream(InputStream stream, long length) {
            return () -> {
                try {
                    if (length >= 0) {
                        return ByteStreams.toByteArray(ByteStreams.limit(stream, length));
                    } else {
                        return ByteStreams.toByteArray(stream);
                    }
                } catch (IOException e) {
                    throw new RuntimeException(CANNOT_LOAD_DATA_FROM_IS + e.getMessage(), e);
                }
            };
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy