feat: update runtime classes for CESQL

Signed-off-by: Calum Murray <cmurray@redhat.com>
This commit is contained in:
Calum Murray 2024-06-19 09:31:52 -04:00
parent 588648110f
commit 48fd18e31c
No known key found for this signature in database
GPG Key ID: D9837BD1D90C1512
6 changed files with 46 additions and 70 deletions

View File

@ -2,19 +2,20 @@ package io.cloudevents.sql.impl.runtime;
import io.cloudevents.sql.EvaluationContext;
import io.cloudevents.sql.EvaluationException;
import io.cloudevents.sql.impl.ExceptionThrower;
import io.cloudevents.sql.ExceptionFactory;
import io.cloudevents.sql.impl.ExceptionFactoryImpl;
import org.antlr.v4.runtime.misc.Interval;
public class EvaluationContextImpl implements EvaluationContext {
private final Interval expressionInterval;
private final String expressionText;
private final ExceptionThrower exceptionThrower;
private final ExceptionFactory exceptionFactory;
public EvaluationContextImpl(Interval expressionInterval, String expressionText, ExceptionThrower exceptionThrower) {
public EvaluationContextImpl(Interval expressionInterval, String expressionText, ExceptionFactory exceptionFactory) {
this.expressionInterval = expressionInterval;
this.expressionText = expressionText;
this.exceptionThrower = exceptionThrower;
this.exceptionFactory = exceptionFactory;
}
@Override
@ -28,12 +29,7 @@ public class EvaluationContextImpl implements EvaluationContext {
}
@Override
public void appendException(EvaluationException exception) {
this.exceptionThrower.throwException(exception);
}
@Override
public void appendException(EvaluationException.EvaluationExceptionFactory exceptionFactory) {
this.exceptionThrower.throwException(exceptionFactory.create(expressionInterval(), expressionText()));
public ExceptionFactory exceptionFactory() {
return this.exceptionFactory;
}
}

View File

@ -18,7 +18,6 @@ public class EvaluationRuntimeBuilder {
public EvaluationRuntime build() {
return new EvaluationRuntimeImpl(
new TypeCastingProvider(),
functionTable
);
}

View File

@ -5,7 +5,7 @@ import io.cloudevents.sql.*;
public class EvaluationRuntimeImpl implements EvaluationRuntime {
private static class SingletonContainer {
private final static EvaluationRuntimeImpl INSTANCE = new EvaluationRuntimeImpl(new TypeCastingProvider(), FunctionTable.getDefaultInstance());
private final static EvaluationRuntimeImpl INSTANCE = new EvaluationRuntimeImpl(FunctionTable.getDefaultInstance());
}
/**
@ -15,29 +15,12 @@ public class EvaluationRuntimeImpl implements EvaluationRuntime {
return EvaluationRuntimeImpl.SingletonContainer.INSTANCE;
}
private final TypeCastingProvider typeCastingProvider;
private final FunctionTable functionTable;
public EvaluationRuntimeImpl(TypeCastingProvider typeCastingProvider, FunctionTable functionTable) {
this.typeCastingProvider = typeCastingProvider;
public EvaluationRuntimeImpl(FunctionTable functionTable) {
this.functionTable = functionTable;
}
@Override
public boolean canCast(Object value, Type target) {
return this.typeCastingProvider.canCast(value, target);
}
@Override
public Object cast(EvaluationContext ctx, Object value, Type target) {
return this.typeCastingProvider.cast(ctx, value, target);
}
@Override
public Object cast(Object value, Type target) throws EvaluationException {
return this.typeCastingProvider.cast(FailFastExceptionThrower.getInstance(), value, target);
}
@Override
public Function resolveFunction(String name, int args) throws IllegalStateException {
return functionTable.resolve(name, args);

View File

@ -5,6 +5,7 @@ import io.cloudevents.sql.EvaluationException;
import io.cloudevents.sql.EvaluationRuntime;
import io.cloudevents.sql.Expression;
import io.cloudevents.sql.Result;
import io.cloudevents.sql.impl.ExceptionFactoryImpl;
import io.cloudevents.sql.impl.ExpressionInternal;
public class ExpressionImpl implements Expression {
@ -17,14 +18,15 @@ public class ExpressionImpl implements Expression {
@Override
public Result evaluate(EvaluationRuntime evaluationRuntime, CloudEvent event) {
ExceptionStore exceptions = new ExceptionStore();
Object value = this.expressionInternal.evaluate(evaluationRuntime, event, exceptions);
return new EvaluationResult(value, exceptions.getExceptions());
ExceptionFactoryImpl exceptionFactory = new ExceptionFactoryImpl(false);
return this.expressionInternal.evaluate(evaluationRuntime, event, exceptionFactory);
}
@Override
public Object tryEvaluate(EvaluationRuntime evaluationRuntime, CloudEvent event) throws EvaluationException {
return this.expressionInternal.evaluate(evaluationRuntime, event, FailFastExceptionThrower.getInstance());
ExceptionFactoryImpl exceptionFactory = new ExceptionFactoryImpl(true);
return this.expressionInternal.evaluate(evaluationRuntime, event, exceptionFactory).value();
}
public ExpressionInternal getExpressionInternal() {

View File

@ -12,18 +12,18 @@ public class FunctionTable {
private static class SingletonContainer {
private final static FunctionTable INSTANCE = new FunctionTable(
Stream.of(
new InfallibleOneArgumentFunction<>("ABS", Integer.class, Math::abs),
new AbsFunction(),
new IntFunction(),
new BoolFunction(),
new StringFunction(),
new IsBoolFunction(),
new IsIntFunction(),
new InfallibleOneArgumentFunction<>("LENGTH", String.class, String::length),
new InfallibleOneArgumentFunction<>("LENGTH", String.class, Integer.class, String::length),
new ConcatFunction(),
new ConcatWSFunction(),
new InfallibleOneArgumentFunction<>("LOWER", String.class, String::toLowerCase),
new InfallibleOneArgumentFunction<>("UPPER", String.class, String::toUpperCase),
new InfallibleOneArgumentFunction<>("TRIM", String.class, String::trim),
new InfallibleOneArgumentFunction<>("LOWER", String.class, String.class, String::toLowerCase),
new InfallibleOneArgumentFunction<>("UPPER", String.class, String.class, String::toUpperCase),
new InfallibleOneArgumentFunction<>("TRIM", String.class, String.class, String::trim),
new LeftFunction(),
new RightFunction(),
new SubstringFunction(),

View File

@ -2,13 +2,12 @@ package io.cloudevents.sql.impl.runtime;
import io.cloudevents.sql.EvaluationContext;
import io.cloudevents.sql.Type;
import io.cloudevents.sql.impl.ExceptionFactory;
import java.util.Objects;
public class TypeCastingProvider {
boolean canCast(Object value, Type target) {
public static boolean canCast(Object value, Type target) {
if (target.valueClass().equals(value.getClass())) {
return true;
}
@ -22,7 +21,7 @@ public class TypeCastingProvider {
return false;
}
}
return false;
return value instanceof Boolean;
case BOOLEAN:
if (value instanceof String) {
try {
@ -31,58 +30,55 @@ public class TypeCastingProvider {
} catch (IllegalArgumentException e) {
return false;
}
}
return false;
} else return value instanceof Integer;
}
return true;
}
Object cast(EvaluationContext ctx, Object value, Type target) {
Objects.requireNonNull(value);
if (target.valueClass().equals(value.getClass())) {
return value;
public static EvaluationResult cast(EvaluationContext ctx, EvaluationResult result, Type target) {
Objects.requireNonNull(result);
Objects.requireNonNull(result.value());
if (target.valueClass().equals(result.value().getClass())) {
return result;
}
switch (target) {
case ANY:
return value;
return result;
case STRING:
return Objects.toString(value);
return result.copyWithValue(Objects.toString(result.value()));
case INTEGER:
if (value instanceof String) {
if (result.value() instanceof String) {
try {
return Integer.parseInt((String) value);
return result.copyWithValue(Integer.parseInt((String) result.value()));
} catch (NumberFormatException e) {
ctx.appendException(
ExceptionFactory.castError(String.class, Integer.class, e)
);
return new EvaluationResult(0, ctx.exceptionFactory().castError(String.class, Integer.class, e).create(ctx.expressionInterval(), ctx.expressionText()));
}
} else if (result.value() instanceof Boolean) {
if ((Boolean) result.value()) {
return result.copyWithValue(1);
}
return result.copyWithValue(0);
} else {
ctx.appendException(
ExceptionFactory.invalidCastTarget(value.getClass(), target.valueClass())
);
return new EvaluationResult(0, ctx.exceptionFactory().invalidCastTarget(result.getClass(), target.valueClass()).create(ctx.expressionInterval(), ctx.expressionText()));
}
return 0;
case BOOLEAN:
if (value instanceof String) {
if (result.value() instanceof String) {
try {
return parseBool((String) value);
return result.copyWithValue(parseBool((String) result.value()));
} catch (IllegalArgumentException e) {
ctx.appendException(
ExceptionFactory.castError(String.class, Boolean.class, e)
);
return new EvaluationResult(false, ctx.exceptionFactory().castError(String.class, Boolean.class, e).create(ctx.expressionInterval(), ctx.expressionText()));
}
} else if (result.value() instanceof Integer) {
return result.copyWithValue(((Integer) result.value()) != 0);
} else {
ctx.appendException(
ExceptionFactory.invalidCastTarget(value.getClass(), target.valueClass())
);
return new EvaluationResult(false, ctx.exceptionFactory().invalidCastTarget(result.getClass(), target.getClass()).create(ctx.expressionInterval(), ctx.expressionText()));
}
return false;
}
// This should never happen
throw new IllegalArgumentException("target type doesn't correspond to a known type");
}
private boolean parseBool(String val) {
private static boolean parseBool(String val) {
switch (val.toLowerCase()) {
case "true":
return true;