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

org.neo4j.driver.internal.messaging.common.CommonValuePacker Maven / Gradle / Ivy

/*
 * Copyright (c) "Neo4j"
 * Neo4j Sweden AB [http://neo4j.com]
 *
 * This file is part of Neo4j.
 *
 * 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 org.neo4j.driver.internal.messaging.common;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Map;

import org.neo4j.driver.Value;
import org.neo4j.driver.internal.InternalPoint2D;
import org.neo4j.driver.internal.InternalPoint3D;
import org.neo4j.driver.internal.messaging.ValuePacker;
import org.neo4j.driver.internal.packstream.PackOutput;
import org.neo4j.driver.internal.packstream.PackStream;
import org.neo4j.driver.internal.value.InternalValue;
import org.neo4j.driver.types.IsoDuration;
import org.neo4j.driver.types.Point;

import static java.time.ZoneOffset.UTC;

public class CommonValuePacker implements ValuePacker
{

    public static final byte DATE = 'D';
    public static final int DATE_STRUCT_SIZE = 1;

    public static final byte TIME = 'T';
    public static final int TIME_STRUCT_SIZE = 2;

    public static final byte LOCAL_TIME = 't';
    public static final int LOCAL_TIME_STRUCT_SIZE = 1;

    public static final byte LOCAL_DATE_TIME = 'd';
    public static final int LOCAL_DATE_TIME_STRUCT_SIZE = 2;

    public static final byte DATE_TIME_WITH_ZONE_OFFSET = 'F';
    public static final byte DATE_TIME_WITH_ZONE_ID = 'f';
    public static final int DATE_TIME_STRUCT_SIZE = 3;

    public static final byte DURATION = 'E';
    public static final int DURATION_TIME_STRUCT_SIZE = 4;

    public static final byte POINT_2D_STRUCT_TYPE = 'X';
    public static final int POINT_2D_STRUCT_SIZE = 3;

    public static final byte POINT_3D_STRUCT_TYPE = 'Y';
    public static final int POINT_3D_STRUCT_SIZE = 4;

    protected final PackStream.Packer packer;

    public CommonValuePacker( PackOutput output )
    {
        this.packer = new PackStream.Packer( output );
    }

    @Override
    public final void packStructHeader( int size, byte signature ) throws IOException
    {
        packer.packStructHeader( size, signature );
    }

    @Override
    public final void pack( String string ) throws IOException
    {
        packer.pack( string );
    }

    @Override
    public final void pack( Value value ) throws IOException
    {
        if ( value instanceof InternalValue )
        {
            packInternalValue( ((InternalValue) value) );
        }
        else
        {
            throw new IllegalArgumentException( "Unable to pack: " + value );
        }
    }

    @Override
    public final void pack( Map map ) throws IOException
    {
        if ( map == null || map.size() == 0 )
        {
            packer.packMapHeader( 0 );
            return;
        }
        packer.packMapHeader( map.size() );
        for ( Map.Entry entry : map.entrySet() )
        {
            packer.pack( entry.getKey() );
            pack( entry.getValue() );
        }
    }

    protected void packInternalValue( InternalValue value ) throws IOException
    {
        switch ( value.typeConstructor() )
        {
        case DATE:
            packDate( value.asLocalDate() );
            break;
        case TIME:
            packTime( value.asOffsetTime() );
            break;
        case LOCAL_TIME:
            packLocalTime( value.asLocalTime() );
            break;
        case LOCAL_DATE_TIME:
            packLocalDateTime( value.asLocalDateTime() );
            break;
        case DATE_TIME:
            packZonedDateTime( value.asZonedDateTime() );
            break;
        case DURATION:
            packDuration( value.asIsoDuration() );
            break;
        case POINT:
            packPoint( value.asPoint() );
            break;
        case NULL:
            packer.packNull();
            break;

        case BYTES:
            packer.pack( value.asByteArray() );
            break;

        case STRING:
            packer.pack( value.asString() );
            break;

        case BOOLEAN:
            packer.pack( value.asBoolean() );
            break;

        case INTEGER:
            packer.pack( value.asLong() );
            break;

        case FLOAT:
            packer.pack( value.asDouble() );
            break;

        case MAP:
            packer.packMapHeader( value.size() );
            for ( String s : value.keys() )
            {
                packer.pack( s );
                pack( value.get( s ) );
            }
            break;

        case LIST:
            packer.packListHeader( value.size() );
            for ( Value item : value.values() )
            {
                pack( item );
            }
            break;

        default:
            throw new IOException( "Unknown type: " + value.type().name() );
        }
    }

    private void packDate( LocalDate localDate ) throws IOException
    {
        packer.packStructHeader( DATE_STRUCT_SIZE, DATE );
        packer.pack( localDate.toEpochDay() );
    }

    private void packTime( OffsetTime offsetTime ) throws IOException
    {
        long nanoOfDayLocal = offsetTime.toLocalTime().toNanoOfDay();
        int offsetSeconds = offsetTime.getOffset().getTotalSeconds();

        packer.packStructHeader( TIME_STRUCT_SIZE, TIME );
        packer.pack( nanoOfDayLocal );
        packer.pack( offsetSeconds );
    }

    private void packLocalTime( LocalTime localTime ) throws IOException
    {
        packer.packStructHeader( LOCAL_TIME_STRUCT_SIZE, LOCAL_TIME );
        packer.pack( localTime.toNanoOfDay() );
    }

    private void packLocalDateTime( LocalDateTime localDateTime ) throws IOException
    {
        long epochSecondUtc = localDateTime.toEpochSecond( UTC );
        int nano = localDateTime.getNano();

        packer.packStructHeader( LOCAL_DATE_TIME_STRUCT_SIZE, LOCAL_DATE_TIME );
        packer.pack( epochSecondUtc );
        packer.pack( nano );
    }

    private void packZonedDateTime( ZonedDateTime zonedDateTime ) throws IOException
    {
        long epochSecondLocal = zonedDateTime.toLocalDateTime().toEpochSecond( UTC );
        int nano = zonedDateTime.getNano();

        ZoneId zone = zonedDateTime.getZone();
        if ( zone instanceof ZoneOffset )
        {
            int offsetSeconds = ((ZoneOffset) zone).getTotalSeconds();

            packer.packStructHeader( DATE_TIME_STRUCT_SIZE, DATE_TIME_WITH_ZONE_OFFSET );
            packer.pack( epochSecondLocal );
            packer.pack( nano );
            packer.pack( offsetSeconds );
        }
        else
        {
            String zoneId = zone.getId();

            packer.packStructHeader( DATE_TIME_STRUCT_SIZE, DATE_TIME_WITH_ZONE_ID );
            packer.pack( epochSecondLocal );
            packer.pack( nano );
            packer.pack( zoneId );
        }
    }

    private void packDuration( IsoDuration duration ) throws IOException
    {
        packer.packStructHeader( DURATION_TIME_STRUCT_SIZE, DURATION );
        packer.pack( duration.months() );
        packer.pack( duration.days() );
        packer.pack( duration.seconds() );
        packer.pack( duration.nanoseconds() );
    }

    private void packPoint( Point point ) throws IOException
    {
        if ( point instanceof InternalPoint2D )
        {
            packPoint2D( point );
        }
        else if ( point instanceof InternalPoint3D )
        {
            packPoint3D( point );
        }
        else
        {
            throw new IOException( String.format( "Unknown type: type: %s, value: %s", point.getClass(), point.toString() ) );
        }
    }

    private void packPoint2D( Point point ) throws IOException
    {
        packer.packStructHeader( POINT_2D_STRUCT_SIZE, POINT_2D_STRUCT_TYPE );
        packer.pack( point.srid() );
        packer.pack( point.x() );
        packer.pack( point.y() );
    }

    private void packPoint3D( Point point ) throws IOException
    {
        packer.packStructHeader( POINT_3D_STRUCT_SIZE, POINT_3D_STRUCT_TYPE );
        packer.pack( point.srid() );
        packer.pack( point.x() );
        packer.pack( point.y() );
        packer.pack( point.z() );
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy