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

dev.miku.r2dbc.mysql.codec.LocalDateCodec Maven / Gradle / Ivy

/*
 * Copyright 2018-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package dev.miku.r2dbc.mysql.codec;

import dev.miku.r2dbc.mysql.Parameter;
import dev.miku.r2dbc.mysql.ParameterWriter;
import dev.miku.r2dbc.mysql.constant.DataTypes;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import reactor.core.publisher.Mono;
import reactor.util.annotation.Nullable;

import java.time.LocalDate;

/**
 * Codec for {@link LocalDate}.
 */
final class LocalDateCodec extends AbstractClassedCodec {

    static final LocalDate ROUND = LocalDate.of(1, 1, 1);

    LocalDateCodec(ByteBufAllocator allocator) {
        super(allocator, LocalDate.class);
    }

    @Override
    public LocalDate decode(ByteBuf value, FieldInformation info, Class target, boolean binary, CodecContext context) {
        int bytes = value.readableBytes();
        LocalDate date = binary ? readDateBinary(value, bytes) : readDateText(value);

        if (date != null) {
            return date;
        }

        return DateTimes.zeroDate(context.getZeroDateOption(), binary, ROUND);
    }

    @Override
    public boolean canEncode(Object value) {
        return value instanceof LocalDate;
    }

    @Override
    public Parameter encode(Object value, CodecContext context) {
        return new LocalDateParameter(allocator, (LocalDate) value);
    }

    @Override
    public boolean doCanDecode(FieldInformation info) {
        return DataTypes.DATE == info.getType();
    }

    @Nullable
    static LocalDate readDateText(ByteBuf buf) {
        int year = DateTimes.readIntInDigits(buf);
        int month = DateTimes.readIntInDigits(buf);
        int day = DateTimes.readIntInDigits(buf);

        if (month == 0 || day == 0) {
            return null;
        }

        return LocalDate.of(year, month, day);
    }

    @Nullable
    static LocalDate readDateBinary(ByteBuf buf, int bytes) {
        if (bytes < DateTimes.DATE_SIZE) {
            return null;
        }

        short year = buf.readShortLE();
        byte month = buf.readByte();
        byte day = buf.readByte();

        if (month == 0 || day == 0) {
            return null;
        }

        return LocalDate.of(year, month, day);
    }

    static ByteBuf encodeDate(ByteBufAllocator alloc, LocalDate date) {
        ByteBuf buf = alloc.buffer(Byte.BYTES + DateTimes.DATE_SIZE);

        try {
            return buf.writeByte(DateTimes.DATE_SIZE)
                .writeShortLE(date.getYear())
                .writeByte(date.getMonthValue())
                .writeByte(date.getDayOfMonth());
        } catch (Throwable e) {
            buf.release();
            throw e;
        }
    }

    static void encodeDate(ParameterWriter writer, LocalDate date) {
        boolean isNegative;
        int year = date.getYear();

        if (year < 0) {
            year = -year;
            isNegative = true;
        } else {
            isNegative = false;
        }

        if (isNegative) {
            writer.append('-');
        } else {
            // Date start with number.
            writer.startString();
        }

        // Note: year is the abs value of origin year.
        if (year < 1000) {
            writer.append('0');
            if (year < 100) {
                writer.append('0');
                if (year < 10) {
                    writer.append('0');
                }
            }
        }

        writer.writeInt(year);
        writer.append('-');

        int month = date.getMonthValue();
        if (month < 10) {
            writer.append('0');
        }
        writer.writeInt(month);
        writer.append('-');

        int day = date.getDayOfMonth();
        if (day < 10) {
            writer.append('0');
        }
        writer.writeInt(day);
    }

    private static final class LocalDateParameter extends AbstractParameter {

        private final ByteBufAllocator allocator;

        private final LocalDate value;

        private LocalDateParameter(ByteBufAllocator allocator, LocalDate value) {
            this.allocator = allocator;
            this.value = value;
        }

        @Override
        public Mono publishBinary() {
            return Mono.fromSupplier(() -> encodeDate(allocator, value));
        }

        @Override
        public Mono publishText(ParameterWriter writer) {
            return Mono.fromRunnable(() -> encodeDate(writer, value));
        }

        @Override
        public short getType() {
            return DataTypes.DATE;
        }

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

            LocalDateParameter that = (LocalDateParameter) o;

            return value.equals(that.value);
        }

        @Override
        public int hashCode() {
            return value.hashCode();
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy