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

org.neo4j.kernel.impl.util.ValueUtils Maven / Gradle / Ivy

Go to download

Neo4j kernel is a lightweight, embedded Java database designed to store data structured as graphs rather than tables. For more information, see http://neo4j.org.

There is a newer version: 5.25.1
Show newest version
/*
 * Copyright (c) "Neo4j"
 * Neo4j Sweden AB [http://neo4j.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.neo4j.kernel.impl.util;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import org.neo4j.graphdb.Entity;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.spatial.Geometry;
import org.neo4j.graphdb.spatial.Point;
import org.neo4j.util.CalledFromGeneratedCode;
import org.neo4j.values.AnyValue;
import org.neo4j.values.storable.BooleanValue;
import org.neo4j.values.storable.CoordinateReferenceSystem;
import org.neo4j.values.storable.DoubleValue;
import org.neo4j.values.storable.IntValue;
import org.neo4j.values.storable.LongValue;
import org.neo4j.values.storable.PointValue;
import org.neo4j.values.storable.TextValue;
import org.neo4j.values.storable.Value;
import org.neo4j.values.storable.Values;
import org.neo4j.values.virtual.ListValue;
import org.neo4j.values.virtual.ListValueBuilder;
import org.neo4j.values.virtual.MapValue;
import org.neo4j.values.virtual.MapValueBuilder;
import org.neo4j.values.virtual.VirtualNodeValue;
import org.neo4j.values.virtual.VirtualPathValue;
import org.neo4j.values.virtual.VirtualRelationshipValue;
import org.neo4j.values.virtual.VirtualValues;

public final class ValueUtils
{
    private ValueUtils()
    {
        throw new UnsupportedOperationException( "do not instantiate" );
    }

    public static AnyValue of( Object object )
    {
        return of( object, false );
    }

    /**
     * Creates an AnyValue by doing type inspection. Do not use in production code where performance is important.
     *
     * @param object the object to turned into a AnyValue
     * @return the AnyValue corresponding to object.
     */
    @SuppressWarnings( "unchecked" )
    public static AnyValue of( Object object, boolean wrapEntities )
    {
        if ( object instanceof AnyValue )
        {
            return (AnyValue) object;
        }
        Value value = Values.unsafeOf( object, true );
        if ( value != null )
        {
            return value;
        }
        else
        {
            if ( object instanceof Entity )
            {
                if ( object instanceof Node )
                {
                    if ( wrapEntities )
                    {
                        return wrapNodeEntity( (Node) object );
                    }
                    else
                    {
                        return fromNodeEntity( (Node) object );
                    }
                }
                else if ( object instanceof Relationship )
                {
                    if ( wrapEntities )
                    {
                        return wrapRelationshipEntity( (Relationship) object );
                    }
                    else
                    {
                        return fromRelationshipEntity( (Relationship) object );
                    }
                }
                else
                {
                    throw new IllegalArgumentException( "Unknown entity + " + object.getClass().getName() );
                }
            }
            else if ( object instanceof Iterable )
            {
                if ( object instanceof Path )
                {
                    if ( wrapEntities )
                    {
                        return wrapPath( (Path) object );
                    }
                    else
                    {
                        return pathReferenceFromPath( (Path) object );
                    }
                }
                else if ( object instanceof List )
                {
                    return asListValue( (List) object, wrapEntities );
                }
                else
                {
                    return asListValue( (Iterable) object, wrapEntities );
                }
            }
            else if ( object instanceof Map )
            {
                return asMapValue( (Map) object, wrapEntities );
            }
            else if ( object instanceof Iterator )
            {
                ListValueBuilder builder = ListValueBuilder.newListBuilder();
                Iterator iterator = (Iterator) object;
                while ( iterator.hasNext() )
                {
                    builder.add( ValueUtils.of( iterator.next(), wrapEntities ) );
                }
                return builder.build();
            }
            else if ( object instanceof Object[] )
            {
                Object[] array = (Object[]) object;
                if ( array.length == 0 )
                {
                    return VirtualValues.EMPTY_LIST;
                }

                ListValueBuilder builder = ListValueBuilder.newListBuilder( array.length );
                for ( Object o : array )
                {
                    builder.add( ValueUtils.of( o, wrapEntities ) );
                }
                return builder.build();
            }
            else if ( object instanceof Stream )
            {
                return asListValue( ((Stream) object).collect( Collectors.toList() ) );
            }
            else if ( object instanceof Geometry )
            {
                return asGeometryValue( (Geometry) object );
            }
            else
            {
                ClassLoader classLoader = object.getClass().getClassLoader();
                throw new IllegalArgumentException(
                        String.format( "Cannot convert %s of type %s to AnyValue, classloader=%s, classloader-name=%s",
                                object,
                                object.getClass().getName(),
                                classLoader != null ? classLoader.toString() : "null",
                                classLoader != null ? classLoader.getName() : "null" )
                );
            }
        }
    }

    public static PointValue asPointValue( Point point )
    {
        return toPoint( point );
    }

    public static PointValue asGeometryValue( Geometry geometry )
    {
        if ( !geometry.getGeometryType().equals( "Point" ) )
        {
            throw new IllegalArgumentException( "Cannot handle geometry type: " + geometry.getCRS().getType() );
        }
        return toPoint( geometry );
    }

    private static PointValue toPoint( Geometry geometry )
    {
        List coordinate = geometry.getCoordinates().get( 0 ).getCoordinate();
        double[] primitiveCoordinate = new double[coordinate.size()];
        for ( int i = 0; i < coordinate.size(); i++ )
        {
            primitiveCoordinate[i] = coordinate.get( i );
        }

        return Values.pointValue( CoordinateReferenceSystem.get( geometry.getCRS() ), primitiveCoordinate );
    }

    public static ListValue asListValue( List collection )
    {
        return asListValue( collection, false );
    }

    public static ListValue asListValue( List collection, boolean wrapEntities )
    {
        int size = collection.size();
        if ( size == 0 )
        {
            return VirtualValues.EMPTY_LIST;
        }

        ListValueBuilder values = ListValueBuilder.newListBuilder( size );
        for ( Object o : collection )
        {
            values.add( ValueUtils.of( o, wrapEntities ) );
        }
        return values.build();
    }

    public static ListValue asListValue( Iterable collection )
    {
        return asListValue( collection, false );
    }

    public static ListValue asListValue( Iterable collection, boolean wrapEntities )
    {
        ListValueBuilder values = ListValueBuilder.newListBuilder();
        for ( Object o : collection )
        {
            values.add( ValueUtils.of( o, wrapEntities ) );
        }
        return values.build();
    }

    public static AnyValue asNodeOrEdgeValue( Entity container )
    {
        if ( container instanceof Node )
        {
            return fromNodeEntity( (Node) container );
        }
        else if ( container instanceof Relationship )
        {
            return fromRelationshipEntity( (Relationship) container );
        }
        else
        {
            throw new IllegalArgumentException(
                    "Cannot produce a node or edge from " + container.getClass().getName() );
        }
    }

    public static ListValue asListOfEdges( Iterable rels )
    {
        return VirtualValues.list( StreamSupport.stream( rels.spliterator(), false )
                .map( ValueUtils::fromRelationshipEntity ).toArray( VirtualRelationshipValue[]::new ) );
    }

    public static ListValue asListOfEdges( Relationship[] rels )
    {
        if ( rels.length == 0 )
        {
            return VirtualValues.EMPTY_LIST;
        }

        ListValueBuilder relValues = ListValueBuilder.newListBuilder( rels.length );
        for ( Relationship rel : rels )
        {
            relValues.add( fromRelationshipEntity( rel ) );
        }
        return relValues.build();
    }
    public static MapValue asMapValue( Map map )
    {
        return asMapValue( map, false );
    }

    public static MapValue asMapValue( Map map, boolean wrapEntities )
    {
        int size = map.size();
        if ( size == 0 )
        {
            return VirtualValues.EMPTY_MAP;
        }

        MapValueBuilder builder = new MapValueBuilder( size );
        for ( Map.Entry entry : map.entrySet() )
        {
            builder.add( entry.getKey(), ValueUtils.of( entry.getValue(), wrapEntities ) );
        }
        return builder.build();
    }

    public static MapValue asParameterMapValue( Map map )
    {
        int size = map.size();
        if ( size == 0 )
        {
            return VirtualValues.EMPTY_MAP;
        }

        MapValueBuilder builder = new MapValueBuilder( size );
        for ( Map.Entry entry : map.entrySet() )
        {
            try
            {
                builder.add( entry.getKey(), ValueUtils.of( entry.getValue(), true ) );
            }
            catch ( IllegalArgumentException e )
            {
                builder.add( entry.getKey(), VirtualValues.error( e ) );
            }
        }

        return builder.build();
    }

    public static VirtualNodeValue fromNodeEntity( Node node )
    {
        //sigh: negative ids are used as a mechanism for transferring "fake" entities from and to procedures.
        //We use it ourselves in some internal procedures, see VirtualNodeHack, and it is also used extensively
        //in apoc.
        if ( node.getId() < 0 )
        {
            return wrapNodeEntity( node );
        }
        else
        {
            return VirtualValues.node( node.getId() );
        }
    }

    //sigh: For procedures we must support "fake" entities from and to procedures.
    //We use it ourselves in some internal procedures, see VirtualNodeHack, and it is also used extensively
    // in apoc.
    @Deprecated
    public static VirtualNodeValue wrapNodeEntity( Node node )
    {
        return new NodeEntityWrappingNodeValue( node );
    }

    public static VirtualRelationshipValue fromRelationshipEntity( Relationship relationship )
    {
        //sigh: negative ids are used as a mechanism for transferring "fake" entities from and to procedures.
        //We use it ourselves in some internal procedures, see VirtualNodeHack, and it is also used extensively
        //in apoc.
        if ( relationship.getId() < 0 )
        {
            return wrapRelationshipEntity( relationship );
        }
        else
        {
            return VirtualValues.relationship( relationship.getId() );
        }
    }

    //sigh: For procedures we must support "fake" entities from and to procedures.
    //We use it ourselves in some internal procedures, see VirtualNodeHack, and it is also used extensively
    // in apoc.
    @Deprecated
    public static VirtualRelationshipValue wrapRelationshipEntity( Relationship relationship )
    {
        return RelationshipEntityWrappingValue.wrapLazy( relationship );
    }

    public static VirtualPathValue fromPath( Path path )
    {
        return VirtualValues.pathReference(
                StreamSupport.stream(path.nodes().spliterator(), false )
                             .map( ValueUtils::fromNodeEntity ).toArray( VirtualNodeValue[]::new ) ,
                StreamSupport.stream(path.relationships().spliterator(), false )
                             .map( ValueUtils::fromRelationshipEntity )
                             .toArray( VirtualRelationshipValue[]::new )
        );
    }

    //sigh: For procedures we must support "fake" entities from and to procedures.
    //We use it ourselves in some internal procedures, see VirtualNodeHack, and it is also used extensively
    // in apoc.
    @Deprecated
    public static VirtualPathValue wrapPath( Path path )
    {
        return new PathWrappingPathValue( path );
    }

    public static VirtualPathValue pathReferenceFromPath( Path path )
    {
        if ( path instanceof DefaultValueMapper.CoreAPIPath )
        {
            return ((DefaultValueMapper.CoreAPIPath) path).pathValue();
        }
        else
        {
            int len = path.length();
            long[] nodes = new long[len + 1];
            long[] rels = new long[len];
            Iterator nodeIterator = path.nodes().iterator();
            Iterator relIterator = path.relationships().iterator();
            int i = 0;
            for ( ; i < len; i++ )
            {
                nodes[i] = nodeIterator.next().getId();
                rels[i] = relIterator.next().getId();
            }
            nodes[i] = nodeIterator.next().getId();
            return VirtualValues.pathReference( nodes, rels );
        }
    }

    /**
     * Creates a {@link Value} from the given object, or if it is already a Value it is returned as it is.
     * 

* This is different from {@link Values#of} which often explicitly fails or creates a new copy * if given a Value. */ public static Value asValue( Object value ) { if ( value instanceof Value ) { return (Value) value; } return Values.of( value ); } /** * Creates an {@link AnyValue} from the given object, or if it is already an AnyValue it is returned as it is. *

* This is different from {@link ValueUtils#of} which often explicitly fails or creates a new copy * if given an AnyValue. */ public static AnyValue asAnyValue( Object value ) { if ( value instanceof AnyValue ) { return (AnyValue) value; } return ValueUtils.of( value ); } @CalledFromGeneratedCode public static VirtualNodeValue asNodeValue( Object object ) { if ( object instanceof VirtualNodeValue ) { return (VirtualNodeValue) object; } if ( object instanceof Node ) { return fromNodeEntity( (Node) object ); } throw new IllegalArgumentException( "Cannot produce a node from " + object.getClass().getName() ); } @CalledFromGeneratedCode public static VirtualRelationshipValue asRelationshipValue( Object object ) { if ( object instanceof VirtualRelationshipValue ) { return (VirtualRelationshipValue) object; } else if ( object instanceof Relationship ) { return fromRelationshipEntity( (Relationship) object ); } else { throw new IllegalArgumentException( "Cannot produce a relationship from " + object.getClass().getName() ); } } @CalledFromGeneratedCode public static LongValue asLongValue( Object object ) { if ( object instanceof LongValue ) { return (LongValue) object; } if ( object instanceof Long ) { return Values.longValue( (long) object ); } if ( object instanceof IntValue ) { return Values.longValue(((IntValue) object).longValue()); } if ( object instanceof Integer ) { return Values.longValue( (int) object ); } throw new IllegalArgumentException( "Cannot produce a long from " + object.getClass().getName() ); } @CalledFromGeneratedCode public static DoubleValue asDoubleValue( Object object ) { if ( object instanceof DoubleValue ) { return (DoubleValue) object; } if ( object instanceof Double ) { return Values.doubleValue( (double) object ); } throw new IllegalArgumentException( "Cannot produce a double from " + object.getClass().getName() ); } @CalledFromGeneratedCode public static BooleanValue asBooleanValue( Object object ) { if ( object instanceof BooleanValue ) { return (BooleanValue) object; } if ( object instanceof Boolean ) { return Values.booleanValue( (boolean) object ); } throw new IllegalArgumentException( "Cannot produce a boolean from " + object.getClass().getName() ); } @CalledFromGeneratedCode public static TextValue asTextValue( Object object ) { if ( object instanceof TextValue ) { return (TextValue) object; } if ( object instanceof String ) { return Values.utf8Value( (String) object ); } throw new IllegalArgumentException( "Cannot produce a string from " + object.getClass().getName() ); } }