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

tech.ytsaurus.client.rows.UnversionedValue Maven / Gradle / Ivy

The newest version!
package tech.ytsaurus.client.rows;

import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Objects;

import tech.ytsaurus.client.SerializationResolver;
import tech.ytsaurus.core.tables.ColumnValueType;
import tech.ytsaurus.yson.YsonConsumer;
import tech.ytsaurus.ysontree.YTree;
import tech.ytsaurus.ysontree.YTreeBinarySerializer;
import tech.ytsaurus.ysontree.YTreeBooleanNode;
import tech.ytsaurus.ysontree.YTreeBuilder;
import tech.ytsaurus.ysontree.YTreeConvertible;
import tech.ytsaurus.ysontree.YTreeDoubleNode;
import tech.ytsaurus.ysontree.YTreeEntityNode;
import tech.ytsaurus.ysontree.YTreeIntegerNode;
import tech.ytsaurus.ysontree.YTreeNode;
import tech.ytsaurus.ysontree.YTreeStringNode;


/**
 * Соответствует TUnversionedValue в C++
 */
public class UnversionedValue implements YTreeConvertible {
    private final int id;
    private final ColumnValueType type;
    private final boolean aggregate;
    private final Object value;

    public UnversionedValue(int id, ColumnValueType type, boolean aggregate, Object value) {
        switch (Objects.requireNonNull(type)) {
            case INT64:
            case UINT64:
                if (!(value instanceof Long)) {
                    throw illegalValue(type, value);
                }
                break;
            case DOUBLE:
                if (!(value instanceof Double)) {
                    throw illegalValue(type, value);
                }
                break;
            case BOOLEAN:
                if (!(value instanceof Boolean)) {
                    throw illegalValue(type, value);
                }
                break;
            case STRING:
            case COMPOSITE:
            case ANY:
                if (!(value instanceof byte[])) {
                    throw illegalValue(type, value);
                }
                break;
            default:
                if (value != null) {
                    throw illegalValue(type, value);
                }
                break;
        }
        this.id = id;
        this.type = type;
        this.aggregate = aggregate;
        this.value = value;
    }

    private static IllegalArgumentException illegalValue(ColumnValueType type, Object value) {
        return new IllegalArgumentException(
                "Illegal value " + value + "(" + value.getClass() + ")" + " for type " + type
        );
    }

    /**
     * Конвертирует value в правильный для type тип данных
     */
    public static Object convertValueTo(
            Object value, ColumnValueType type, SerializationResolver serializationResolver) {
        switch (type) {
            case INT64:
                if (value == null || value instanceof Long) {
                    return value;
                } else if (value instanceof YTreeIntegerNode) {
                    return ((YTreeIntegerNode) value).longValue();
                } else if (value instanceof Integer || value instanceof Short || value instanceof Byte) {
                    return ((Number) value).longValue();
                } else if (value instanceof YTreeEntityNode) {
                    return null;
                }
                break;
            case UINT64:
                if (value == null || value instanceof Long) {
                    return value;
                } else if (value instanceof YTreeIntegerNode) {
                    return ((YTreeIntegerNode) value).longValue();
                } else if (value instanceof Integer) {
                    return Integer.toUnsignedLong((Integer) value);
                } else if (value instanceof Short) {
                    return Short.toUnsignedLong((Short) value);
                } else if (value instanceof Byte) {
                    return Byte.toUnsignedLong((Byte) value);
                } else if (value instanceof YTreeEntityNode) {
                    return null;
                }
                break;
            case DOUBLE:
                if (value == null || value instanceof Double) {
                    return value;
                } else if (value instanceof YTreeDoubleNode) {
                    return ((YTreeDoubleNode) value).doubleValue();
                } else if (value instanceof Float) {
                    return ((Float) value).doubleValue();
                } else if (value instanceof YTreeEntityNode) {
                    return null;
                }
                break;
            case BOOLEAN:
                if (value == null || value instanceof Boolean) {
                    return value;
                } else if (value instanceof YTreeBooleanNode) {
                    return ((YTreeNode) value).boolValue();
                } else if (value instanceof YTreeEntityNode) {
                    return null;
                }
                break;
            case STRING:
                if (value == null || value instanceof byte[]) {
                    return value;
                } else if (value instanceof YTreeStringNode) {
                    return ((YTreeStringNode) value).bytesValue();
                } else if (value instanceof String) {
                    return ((String) value).getBytes(StandardCharsets.UTF_8);
                } else if (value instanceof YTreeEntityNode) {
                    return null;
                }
                break;
            case ANY:
                if (value == null || value instanceof byte[]) {
                    return value;
                }

                return serializationResolver.toTree(value).toBinary();
            default:
                throw new IllegalArgumentException("Unexpected type " + type);
        }
        throw illegalValue(type, value);
    }

    public int getId() {
        return id;
    }

    public ColumnValueType getType() {
        return type;
    }

    public boolean isAggregate() {
        return aggregate;
    }

    public Object getValue() {
        return value;
    }

    public int getLength() {
        switch (type) {
            case STRING:
            case COMPOSITE:
            case ANY:
                return ((byte[]) value).length;
            default:
                return 0;
        }
    }

    public long longValue() {
        switch (type) {
            case INT64:
            case UINT64:
                return (Long) value;
            default:
                throw new IllegalArgumentException(type + " is not an integer value");
        }
    }

    public double doubleValue() {
        if (type != ColumnValueType.DOUBLE) {
            throw new IllegalArgumentException(type + " is not a double value");
        }
        return (Double) value;
    }

    public boolean booleanValue() {
        if (type != ColumnValueType.BOOLEAN) {
            throw new IllegalArgumentException(type + " is not a boolean value");
        }
        return (Boolean) value;
    }

    public byte[] bytesValue() {
        switch (type) {
            case STRING:
            case COMPOSITE:
            case ANY:
                return (byte[]) value;
            default:
                throw new IllegalArgumentException(type + " is not a string-like value");
        }
    }

    public String stringValue() {
        return new String(bytesValue(), StandardCharsets.UTF_8);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof UnversionedValue)) {
            return false;
        }

        UnversionedValue other = (UnversionedValue) o;

        if (id != other.id) {
            return false;
        }
        if (aggregate != other.aggregate) {
            return false;
        }
        if (type != other.type) {
            return false;
        }
        switch (type) {
            case INT64:
            case UINT64:
            case DOUBLE:
            case BOOLEAN:
                return value.equals(other.value);
            case STRING:
            case ANY:
                return Arrays.equals((byte[]) value, (byte[]) other.value);
            default:
                return true;
        }
    }

    private static int valueHashCode(Object value) {
        if (value != null) {
            if (value instanceof byte[]) {
                return Arrays.hashCode((byte[]) value);
            }
            return value.hashCode();
        }
        return 0;
    }

    @Override
    public int hashCode() {
        int result = id;
        result = 31 * result + type.hashCode();
        result = 31 * result + (aggregate ? 1 : 0);
        result = 31 * result + valueHashCode(value);
        return result;
    }

    private static String valueString(Object value) {
        if (value instanceof byte[]) {
            return Arrays.toString((byte[]) value);
        }
        return String.valueOf(value);
    }

    @Override
    public String toString() {
        return "UnversionedValue{" +
                "id=" + id +
                ", type=" + type +
                ", aggregate=" + aggregate +
                ", value=" + valueString(value) +
                '}';
    }

    /**
     * Пишет значение в consumer
     */
    public void writeTo(YsonConsumer consumer) {
        switch (type) {
            case NULL:
                consumer.onEntity();
                break;
            case INT64:
                consumer.onInteger(longValue());
                break;
            case UINT64:
                consumer.onUnsignedInteger(longValue());
                break;
            case DOUBLE:
                consumer.onDouble(doubleValue());
                break;
            case BOOLEAN:
                consumer.onBoolean(booleanValue());
                break;
            case STRING: {
                byte[] bytes = bytesValue();
                consumer.onString(bytes, 0, bytes.length);
                break;
            }
            case COMPOSITE:
            case ANY: {
                YTreeBinarySerializer.deserialize(new ByteArrayInputStream(bytesValue()), consumer);
                break;
            }
            default:
                throw new IllegalArgumentException("Cannot convert " + type + " to YTree");
        }
    }

    /**
     * Конвертирует значение в соответствующий YTreeNode
     */
    @Override
    public YTreeNode toYTree() {
        YTreeBuilder builder = YTree.builder();
        writeTo(builder);
        return builder.build();
    }

    /**
     * Конвертирует значение в сырое 64-х битное число для сериализации
     */
    public long toRawBits() {
        switch (type) {
            case INT64:
            case UINT64:
                return (Long) value;
            case DOUBLE:
                return Double.doubleToRawLongBits((Double) value);
            case BOOLEAN:
                return ((Boolean) value) ? 1L : 0L;
            default:
                throw new IllegalArgumentException(type + " cannot be represented as raw bits");
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy