use of org.neo4j.kernel.api.procedure.CallableUserFunction in project neo4j by neo4j.
the class ProcedureCompilationTest method shouldHandleNulls.
@Test
void shouldHandleNulls() throws ProcedureException {
// Given
UserFunctionSignature signature = functionSignature("test", "foo").in("b", NTBoolean).out(NTFloat).build();
// When
CallableUserFunction nullyMethod = compileFunction(signature, emptyList(), method("nullyMethod", Boolean.class));
// Then
assertEquals(Values.NO_VALUE, nullyMethod.apply(ctx, new AnyValue[] { TRUE }));
assertEquals(PI, nullyMethod.apply(ctx, new AnyValue[] { Values.NO_VALUE }));
}
use of org.neo4j.kernel.api.procedure.CallableUserFunction in project neo4j by neo4j.
the class ProcedureCompilationTest method shouldHandleNumberOutput.
@Test
void shouldHandleNumberOutput() throws ProcedureException {
// Given
UserFunctionSignature signature = functionSignature("test", "foo").in("numbers", NTList(NTNumber)).out(NTNumber).build();
// When
CallableUserFunction sumMethod = compileFunction(signature, emptyList(), method("sum", List.class));
// Then
assertEquals(longValue(3), sumMethod.apply(ctx, new AnyValue[] { list(longValue(1), longValue(2)) }));
}
use of org.neo4j.kernel.api.procedure.CallableUserFunction in project neo4j by neo4j.
the class ProcedureCompilationTest method shouldExposeUserFunctionSignature.
@Test
void shouldExposeUserFunctionSignature() throws ProcedureException {
// Given
UserFunctionSignature signature = functionSignature("test", "foo").out(NTInteger).build();
// When
CallableUserFunction function = compileFunction(signature, emptyList(), method("longMethod"));
// Then
assertEquals(function.signature(), signature);
}
use of org.neo4j.kernel.api.procedure.CallableUserFunction in project neo4j by neo4j.
the class ProcedureCompilation method compileFunction.
/**
* Generates code for a user-defined function.
* <p>
* Given a user-defined function defined by
*
* <pre>
* class MyClass {
* {@literal @}Context
* public Log log;
*
* {@literal @}UserFunction
* public double addPi(long value) {
* return value + Math.PI;
* }
* }
* </pre>
* <p>
* we will generate something like
*
* <pre>
* class GeneratedAddPi implements CallableUserFunction {
* public static UserFunctionSignature SIGNATURE;
* public static FieldSetter SETTER_0;
*
* public AnyValue apply(Context ctx, AnyValue[] input) {
* try {
* MyClass userClass = new MyClass();
* userClass.log = (Log) SETTER_0.get(ctx);
* return Values.doubleValue(userClass.addPi( ((NumberValue) input[0]).longValue() );
* } catch (Throwable T) {
* throw new ProcedureException([appropriate error msg], T);
* }
* }
*
* public UserFunctionSignature signature() {return SIGNATURE;}
* }
* </pre>
* <p>
* where the static fields are set once during loading via reflection.
*
* @param signature the signature of the user-defined function
* @param fieldSetters the fields to set before each call.
* @param methodToCall the method to call
* @return a CallableUserFunction delegating to the underlying user-defined function.
* @throws ProcedureException if something went wrong when compiling the user-defined function.
*/
static CallableUserFunction compileFunction(UserFunctionSignature signature, List<FieldSetter> fieldSetters, Method methodToCall) throws ProcedureException {
ClassHandle handle;
try {
CodeGenerator codeGenerator = codeGenerator();
try (ClassGenerator generator = codeGenerator.generateClass(PACKAGE, className(signature), CallableUserFunction.class)) {
// static fields
FieldReference signatureField = generator.publicStaticField(typeReference(UserFunctionSignature.class), SIGNATURE_NAME);
List<FieldReference> fieldsToSet = createContextSetters(fieldSetters, generator);
// CallableUserFunction::apply
try (CodeBlock method = generator.generate(USER_FUNCTION)) {
method.tryCatch(body -> functionBody(body, fieldSetters, fieldsToSet, methodToCall), onError -> onError(onError, format("function `%s`", signature.name())), param(Throwable.class, "T"));
}
// CallableUserFunction::signature
try (CodeBlock method = generator.generateMethod(UserFunctionSignature.class, "signature")) {
method.returns(getStatic(signatureField));
}
handle = generator.handle();
}
Class<?> clazz = handle.loadClass();
// set all static fields
setAllStaticFields(signature, fieldSetters, methodToCall, clazz);
return (CallableUserFunction) clazz.getConstructor().newInstance();
} catch (Throwable e) {
throw new ProcedureException(Status.Procedure.ProcedureRegistrationFailed, e, "Failed to compile function defined in `%s`: %s", methodToCall.getDeclaringClass().getSimpleName(), e.getMessage());
}
}
use of org.neo4j.kernel.api.procedure.CallableUserFunction in project neo4j by neo4j.
the class GlobalProceduresRegistry method start.
@Override
public void start() throws Exception {
ProcedureJarLoader loader = new ProcedureJarLoader(compiler, log);
ProcedureJarLoader.Callables callables = loader.loadProceduresFromDir(proceduresDirectory);
for (CallableProcedure procedure : callables.procedures()) {
register(procedure);
}
for (CallableUserFunction function : callables.functions()) {
register(function);
}
for (CallableUserAggregationFunction function : callables.aggregationFunctions()) {
register(function);
}
// And register built-in procedures
builtin.accept(this);
}
Aggregations