Skip to content

Commit

Permalink
Add java API for using with external types
Browse files Browse the repository at this point in the history
  • Loading branch information
pontusmelke authored and fickludd committed Mar 27, 2019
1 parent 6f9df20 commit e511172
Show file tree
Hide file tree
Showing 8 changed files with 265 additions and 3 deletions.
Expand Up @@ -17,9 +17,9 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.cypher.evaluator;
package org.neo4j.cypher.internal.evaluator;

public class EvaluationException extends RuntimeException
public class EvaluationException extends Exception
{
public EvaluationException( String message )
{
Expand Down
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2002-2019 "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 <http://www.gnu.org/licenses/>.
*/
package org.neo4j.cypher.internal.evaluator;

class EvaluationRuntimeException extends RuntimeException
{
EvaluationRuntimeException( String message )
{
super( message );
}
}
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2002-2019 "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 <http://www.gnu.org/licenses/>.
*/
package org.neo4j.cypher.internal.evaluator;

@SuppressWarnings( "WeakerAccess" )
public final class Evaluator
{
private Evaluator()
{
throw new UnsupportedOperationException( "Do not instantiate" );
}

public static ExpressionEvaluator expressionEvaluator()
{
return new SimpleExpressionEvaluator();
}
}
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2002-2019 "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 <http://www.gnu.org/licenses/>.
*/
package org.neo4j.cypher.internal.evaluator;

/**
* An ExpressionEvaluator takes an arbitrary Cypher expression and evaluates it to a java value.
*/
public interface ExpressionEvaluator
{
/**
* Evaluates a Cypher expression
*
* @param expression The expression to evaluate.
* @param type The type that we expect the returned value to have
* @return The evaluated Cypher expression.
* @throws EvaluationException if the evaluation fails.
*/
<T> T evaluate( String expression, Class<T> type ) throws EvaluationException;
}
@@ -0,0 +1,93 @@
/*
* Copyright (c) 2002-2019 "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 <http://www.gnu.org/licenses/>.
*/
package org.neo4j.cypher.internal.evaluator;

import org.neo4j.values.AnyValue;
import org.neo4j.values.ValueMapper;
import org.neo4j.values.virtual.PathValue;
import org.neo4j.values.virtual.VirtualNodeValue;
import org.neo4j.values.virtual.VirtualRelationshipValue;

class SimpleExpressionEvaluator implements ExpressionEvaluator
{
private InternalExpressionEvaluator evaluator = new SimpleInternalExpressionEvaluator();

@Override
public <T> T evaluate( String expression, Class<T> type ) throws EvaluationException
{
if ( expression == null )
{
throw new EvaluationException( "Cannot evaluate null as an expression " );
}
if ( type == null )
{
throw new EvaluationException( "Cannot evaluate to type null" );
}

return cast( map( evaluator.evaluate( expression ) ), type );
}

private <T> T cast( Object value, Class<T> type ) throws EvaluationException
{
try
{
return type.cast( value );
}
catch ( ClassCastException e )
{
throw new EvaluationException( String.format( "Expected expression of be of type `%s` but it was `%s`",
type.getCanonicalName(),
value.getClass().getCanonicalName() ), e );
}
}

private Object map( AnyValue value ) throws EvaluationException
{
try
{
return value.map( MAPPER );
}
catch ( EvaluationRuntimeException e )
{
throw new EvaluationException( e.getMessage(), e );
}
}

private static ValueMapper<Object> MAPPER = new ValueMapper.JavaMapper()
{
@Override
public Object mapPath( PathValue value )
{
throw new EvaluationRuntimeException( "Unable to evaluate paths" );
}

@Override
public Object mapNode( VirtualNodeValue value )
{
throw new EvaluationRuntimeException( "Unable to evaluate nodes" );
}

@Override
public Object mapRelationship( VirtualRelationshipValue value )
{
throw new EvaluationRuntimeException( "Unable to evaluate relationships" );
}
};
}
Expand Up @@ -28,9 +28,12 @@ trait InternalExpressionEvaluator {

/**
* Evaluates a Cypher expression provided as a String to an instance of [[AnyValue]]
*
* @param expression The cypher expression string
* @return An instance of [[AnyValue]] corresponding to the provided expression string
* @throws EvaluationException if evaluation fails
*/
@throws(classOf[EvaluationException])
def evaluate(expression: String): AnyValue
}

Expand Down
Expand Up @@ -19,7 +19,6 @@
*/
package org.neo4j.cypher.internal.evaluator

import org.neo4j.cypher.evaluator.EvaluationException
import org.neo4j.cypher.internal.planner.v3_5.spi.TokenContext
import org.neo4j.cypher.internal.runtime.interpreted.ExecutionContext
import org.neo4j.cypher.internal.runtime.interpreted.commands.convert.{CommunityExpressionConverter, ExpressionConverters}
Expand Down
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2002-2019 "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 <http://www.gnu.org/licenses/>.
*/
package org.neo4j.cypher.internal.evaluator;

import org.junit.jupiter.api.Test;

import java.util.List;

import org.neo4j.helpers.collection.MapUtil;

import static java.util.Arrays.asList;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

class SimpleExpressionEvaluatorTest
{
@Test
void shouldConvertToSpecificType() throws EvaluationException
{
// Given
ExpressionEvaluator evaluator = Evaluator.expressionEvaluator();

// When
List<?> list = evaluator.evaluate( "[1, 2, 3]", List.class );

// Then
assertEquals( asList( 1L, 2L, 3L ), list );
}

@Test
void shouldConvertToObject() throws EvaluationException
{
// Given
ExpressionEvaluator evaluator = Evaluator.expressionEvaluator();

// When
Object object = evaluator.evaluate( "{prop: 42}", Object.class );

// Then
assertEquals( MapUtil.map( "prop", 42L ), object );
}

@Test
void shouldThrowIfWrongType()
{
// Given
ExpressionEvaluator evaluator = Evaluator.expressionEvaluator();

// Expect
assertThrows( EvaluationException.class, () -> evaluator.evaluate( "{prop: 42}", List.class ) );
}
}

0 comments on commit e511172

Please sign in to comment.