Skip to content

Commit

Permalink
Introduce Neo4jValue abstraction
Browse files Browse the repository at this point in the history
  • Loading branch information
pontusmelke committed Jul 12, 2016
1 parent ee54249 commit 48af905
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 18 deletions.
Expand Up @@ -50,7 +50,7 @@ case class ProcedureCallExecutionPlan(signature: ProcedureSignature,
extends ExecutionPlan {

private val argExprCommands: Seq[expressions.Expression] = argExprs.map(toCommandExpression) ++
signature.inputSignature.drop(argExprs.size).flatMap(_.default).map(Literal(_))
signature.inputSignature.drop(argExprs.size).flatMap(_.default).map(o => Literal(o.value))

override def run(ctx: QueryContext, planType: ExecutionMode, params: Map[String, Any]): InternalExecutionResult = {
val input = evaluateArguments(ctx, params)
Expand Down
Expand Up @@ -314,7 +314,7 @@ case class ActualPipeBuilder(monitors: Monitors, recurse: LogicalPlan => Pipe, r

case ProcedureCall(_, call@ResolvedCall(signature, callArguments, callResults, _, _)) =>
val callMode = ProcedureCallMode.fromAccessMode(signature.accessMode)
val callArgumentCommands = callArguments.map(Some(_)).zipAll(signature.inputSignature.map(_.default), None, None).map {
val callArgumentCommands = callArguments.map(Some(_)).zipAll(signature.inputSignature.map(_.default.map(_.value)), None, None).map {
case (given, default) => given.map(toCommandExpression).getOrElse(Literal(default.get))
}
val rowProcessing = ProcedureCallRowProcessing(signature)
Expand Down
Expand Up @@ -41,7 +41,8 @@ case class QualifiedProcedureName(namespace: Seq[String], name: String) {
override def toString = s"""${namespace.mkString(".")}.$name"""
}

case class FieldSignature(name: String, typ: CypherType, default: Option[AnyRef] = None)
case class CypherValue(value: AnyRef, cypherType: CypherType)
case class FieldSignature(name: String, typ: CypherType, default: Option[CypherValue] = None)

sealed trait ProcedureAccessMode

Expand Down
Expand Up @@ -36,6 +36,7 @@ import org.neo4j.kernel.api.exceptions.schema.SchemaKernelException
import org.neo4j.kernel.api.index.{IndexDescriptor, InternalIndexState}
import org.neo4j.kernel.api.proc.Neo4jTypes.AnyType
import org.neo4j.kernel.api.proc.{Neo4jTypes, ProcedureSignature => KernelProcedureSignature}
import org.neo4j.kernel.impl.proc.Neo4jValue

import scala.collection.JavaConverters._

Expand Down Expand Up @@ -132,7 +133,7 @@ class TransactionBoundPlanContext(tc: TransactionalContextWrapperv3_1)
override def procedureSignature(name: QualifiedProcedureName) = {
val kn = new KernelProcedureSignature.ProcedureName(name.namespace.asJava, name.name)
val ks = tc.statement.readOperations().procedureGet(kn)
val input = ks.inputSignature().asScala.map(s => FieldSignature(s.name(), asCypherType(s.neo4jType()), asOption(s.defaultValue()))).toIndexedSeq
val input = ks.inputSignature().asScala.map(s => FieldSignature(s.name(), asCypherType(s.neo4jType()), asOption(s.defaultValue()).map(asCypherValue))).toIndexedSeq
val output = if (ks.isVoid) None else Some(ks.outputSignature().asScala.map(s => FieldSignature(s.name(), asCypherType(s.neo4jType()))).toIndexedSeq)
val mode = asCypherProcMode(ks.mode())

Expand All @@ -150,6 +151,8 @@ class TransactionBoundPlanContext(tc: TransactionalContextWrapperv3_1)
"Unable to execute procedure, because it requires an unrecognized execution mode: " + mode.name(), null )
}

private def asCypherValue(neo4jValue: Neo4jValue) = CypherValue(neo4jValue.value, asCypherType(neo4jValue.neo4jType()))

private def asCypherType(neoType: AnyType): CypherType = neoType match {
case Neo4jTypes.NTString => symbols.CTString
case Neo4jTypes.NTInteger => symbols.CTInteger
Expand Down
Expand Up @@ -28,6 +28,7 @@

import org.neo4j.helpers.collection.Iterables;
import org.neo4j.kernel.api.proc.Neo4jTypes.AnyType;
import org.neo4j.kernel.impl.proc.Neo4jValue;

import static java.util.Arrays.asList;
import static java.util.Collections.unmodifiableList;
Expand Down Expand Up @@ -97,14 +98,14 @@ public static class FieldSignature
{
private final String name;
private final AnyType type;
private final Optional<Object> defaultValue;
private final Optional<Neo4jValue> defaultValue;

public FieldSignature( String name, AnyType type)
{
this(name, type, Optional.empty());
}

public FieldSignature( String name, AnyType type, Optional<Object> defaultValue )
public FieldSignature( String name, AnyType type, Optional<Neo4jValue> defaultValue )
{
this.name = name;
this.type = type;
Expand All @@ -121,7 +122,7 @@ public AnyType neo4jType()
return type;
}

public Optional<Object> defaultValue()
public Optional<Neo4jValue> defaultValue()
{
return defaultValue;
}
Expand Down
Expand Up @@ -77,7 +77,7 @@ public List<FieldSignature> signatureFor( Method method ) throws ProcedureExcept
try
{
NeoValueConverter valueConverter = typeMappers.converterFor( type );
Optional<Object> defaultValue = valueConverter.defaultValue( parameter );
Optional<Neo4jValue> defaultValue = valueConverter.defaultValue( parameter );
//it is not allowed to have holes in default values
if (seenDefault && !defaultValue.isPresent())
{
Expand Down
@@ -0,0 +1,64 @@
/*
* Copyright (c) 2002-2016 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.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.kernel.impl.proc;

import org.neo4j.kernel.api.proc.Neo4jTypes;

public class Neo4jValue
{
private final Object value;
private final Neo4jTypes.AnyType type;

public Neo4jValue( Object value, Neo4jTypes.AnyType type )
{
this.value = value;
this.type = type;
}

public Object value()
{
return value;
}

public Neo4jTypes.AnyType neo4jType()
{
return type;
}

public static Neo4jValue ntString(String value)
{
return new Neo4jValue( value, Neo4jTypes.NTString );
}

public static Neo4jValue ntInteger(long value)
{
return new Neo4jValue( value, Neo4jTypes.NTInteger );
}

public static Neo4jValue ntFloat(double value)
{
return new Neo4jValue( value, Neo4jTypes.NTFloat );
}

public static Neo4jValue ntBoolean(boolean value)
{
return new Neo4jValue( value, Neo4jTypes.NTBoolean );
}
}
Expand Up @@ -33,6 +33,9 @@
import org.neo4j.kernel.api.proc.Neo4jTypes.AnyType;
import org.neo4j.procedure.Name;

import static java.lang.Boolean.parseBoolean;
import static java.lang.Double.parseDouble;
import static java.lang.Long.parseLong;
import static org.neo4j.kernel.api.proc.Neo4jTypes.NTAny;
import static org.neo4j.kernel.api.proc.Neo4jTypes.NTBoolean;
import static org.neo4j.kernel.api.proc.Neo4jTypes.NTFloat;
Expand All @@ -41,6 +44,9 @@
import static org.neo4j.kernel.api.proc.Neo4jTypes.NTMap;
import static org.neo4j.kernel.api.proc.Neo4jTypes.NTNumber;
import static org.neo4j.kernel.api.proc.Neo4jTypes.NTString;
import static org.neo4j.kernel.impl.proc.Neo4jValue.ntBoolean;
import static org.neo4j.kernel.impl.proc.Neo4jValue.ntFloat;
import static org.neo4j.kernel.impl.proc.Neo4jValue.ntInteger;

public class TypeMappers
{
Expand All @@ -53,7 +59,7 @@ interface NeoValueConverter
{
AnyType type();
Object toNeoValue( Object javaValue ) throws ProcedureException;
Optional<Object> defaultValue(Name parameter) throws ProcedureException;
Optional<Neo4jValue> defaultValue(Name parameter) throws ProcedureException;
}

private final Map<Type,NeoValueConverter> javaToNeo = new HashMap<>();
Expand Down Expand Up @@ -129,11 +135,20 @@ public void registerType( Class<?> javaClass, NeoValueConverter toNeo )
}

private final NeoValueConverter TO_ANY = new SimpleConverter( NTAny, Object.class );
private final NeoValueConverter TO_STRING = new SimpleConverter( NTString, String.class, s -> s);
private final NeoValueConverter TO_INTEGER = new SimpleConverter( NTInteger, Long.class, Long::parseLong );
private final NeoValueConverter TO_FLOAT = new SimpleConverter( NTFloat, Double.class, Double::parseDouble);
private final NeoValueConverter TO_NUMBER = new SimpleConverter( NTNumber, Number.class, Boolean::parseBoolean);
private final NeoValueConverter TO_BOOLEAN = new SimpleConverter( NTBoolean, Boolean.class, Boolean::parseBoolean);
private final NeoValueConverter TO_STRING = new SimpleConverter( NTString, String.class, Neo4jValue::ntString );
private final NeoValueConverter TO_INTEGER = new SimpleConverter( NTInteger, Long.class, s -> ntInteger( parseLong(s) ) );
private final NeoValueConverter TO_FLOAT = new SimpleConverter( NTFloat, Double.class, s -> ntFloat( parseDouble(s) ));
private final NeoValueConverter TO_NUMBER = new SimpleConverter( NTNumber, Number.class, s -> {
try
{
return ntInteger( parseLong(s) );
}
catch ( NumberFormatException e )
{
return ntFloat( parseDouble( s ) );
}
});
private final NeoValueConverter TO_BOOLEAN = new SimpleConverter( NTBoolean, Boolean.class, s -> ntBoolean( parseBoolean(s) ));
private final NeoValueConverter TO_MAP = new SimpleConverter( NTMap, Map.class);
private final NeoValueConverter TO_LIST = toList( TO_ANY );

Expand All @@ -159,23 +174,24 @@ public static class SimpleConverter implements NeoValueConverter
{
private final AnyType type;
private final Class<?> javaClass;
private final Function<String,Object> defaultConverter;
private final Function<String,Neo4jValue> defaultConverter;

public SimpleConverter( AnyType type, Class<?> javaClass)
{
this( type, javaClass, s -> {
throw new UnsupportedOperationException( String.format("Default values for type %s is not supported", javaClass.getSimpleName() ));
throw new UnsupportedOperationException(
String.format("Default values for type %s is not supported", javaClass.getSimpleName() ));
} );
}

public SimpleConverter( AnyType type, Class<?> javaClass, Function<String,Object> defaultConverter )
public SimpleConverter( AnyType type, Class<?> javaClass, Function<String,Neo4jValue> defaultConverter )
{
this.type = type;
this.javaClass = javaClass;
this.defaultConverter = defaultConverter;
}

public Optional<Object> defaultValue(Name parameter) throws ProcedureException
public Optional<Neo4jValue> defaultValue(Name parameter) throws ProcedureException
{
String defaultValue = parameter.defaultValue();
if ( defaultValue.equals( Name.DEFAULT_VALUE ) )
Expand Down

0 comments on commit 48af905

Please sign in to comment.