Skip to content

Commit

Permalink
feat: Add base64 encode/decode scalar functions
Browse files Browse the repository at this point in the history
  • Loading branch information
kuseman committed Jul 3, 2024
1 parent 9a441b3 commit 3e7a6a2
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
public class ResolvedType
{
private static final EnumMap<Type, ResolvedType> CONSTANTS;

static
{
CONSTANTS = new EnumMap<>(Type.class);
Expand All @@ -25,6 +24,8 @@ public class ResolvedType
}
}
}
public static ResolvedType STRING = ResolvedType.of(Type.String);
public static ResolvedType ANY = ResolvedType.of(Type.Any);

private final Type type;
/** Type used do specify the contained type if {@link #type} is {@link Type#Array} */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,9 +336,14 @@ public static UTF8String from(Object object)
return ((Boolean) object).booleanValue() ? TRUE
: FALSE;
}
else if (object instanceof UTF8String)
else if (object instanceof UTF8String utf8s)
{
return (UTF8String) object;
return utf8s;
}
else if (object instanceof byte[] bytes)
{
// Assume utf8 bytes
return new UTF8String(bytes, 0, bytes.length);
}
return from(String.valueOf(object));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package se.kuseman.payloadbuilder.core.catalog.system;

import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;
import java.util.List;

import se.kuseman.payloadbuilder.api.catalog.ResolvedType;
import se.kuseman.payloadbuilder.api.catalog.ScalarFunctionInfo;
import se.kuseman.payloadbuilder.api.execution.IExecutionContext;
import se.kuseman.payloadbuilder.api.execution.TupleVector;
import se.kuseman.payloadbuilder.api.execution.UTF8String;
import se.kuseman.payloadbuilder.api.execution.ValueVector;
import se.kuseman.payloadbuilder.api.execution.vector.MutableValueVector;
import se.kuseman.payloadbuilder.api.expression.IExpression;

/** Scalar function that encodes/decodes base64 strings. */
class Base64Function extends ScalarFunctionInfo
{
private static final Decoder DECODER = Base64.getDecoder();
private static final Encoder ENCODER = Base64.getEncoder();

private final boolean decode;

Base64Function(boolean decode)
{
super("base64_" + (decode ? "decode"
: "encode"), FunctionType.SCALAR);
this.decode = decode;
}

@Override
public Arity arity()
{
return Arity.ONE;
}

@Override
public ResolvedType getType(List<IExpression> arguments)
{
return decode ? ResolvedType.ANY
: ResolvedType.STRING;
}

@Override
public ValueVector evalScalar(IExecutionContext context, TupleVector input, String catalogAlias, List<IExpression> arguments)
{
return evalScalar(context, input, ValueVector.range(0, input.getRowCount()), catalogAlias, arguments);
}

@Override
public ValueVector evalScalar(IExecutionContext context, TupleVector input, ValueVector selection, String catalogAlias, List<IExpression> arguments)
{
ValueVector value = arguments.get(0)
.eval(input, selection, context);

int size = selection.size();
MutableValueVector result = context.getVectorFactory()
.getMutableVector(getType(arguments), size);

for (int i = 0; i < size; i++)
{
if (value.isNull(i))
{
result.setNull(i);
}
else
{
String str = value.getString(i)
.toString();

if (decode)
{
byte[] bytes = DECODER.decode(str);
result.setAny(i, bytes);
}
else
{
String val = ENCODER.encodeToString(str.getBytes());
result.setString(i, UTF8String.from(val));
}
}
}
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ public static Catalog get()
catalog.registerFunction(new ReverseFunction());
catalog.registerFunction(new CharIndexFunction());
catalog.registerFunction(new StringAggFunction());
catalog.registerFunction(new Base64Function(true));
catalog.registerFunction(new Base64Function(false));

// Date functions
catalog.registerFunction(new GetDateFunction(true));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ public void test_function_hash() throws Exception
assertExpression(23433, null, "hash(1,123)");
}

@Test
public void test_base64() throws Exception
{
assertExpression(null, null, "base64_decode(null)");
assertExpression(null, null, "base64_encode(null)");
assertExpression("aGVsbG8gd29ybGQ=", null, "base64_encode('hello world')");
assertExpression(new byte[] { 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100 }, null, "base64_decode('aGVsbG8gd29ybGQ=')");
assertExpression("hello world", null, "cast(base64_decode('aGVsbG8gd29ybGQ=') as string)");
assertExpression("hello world", null, "cast(base64_decode(base64_encode('hello world')) as string)");
}

@Test
public void test_reverse() throws Exception
{
Expand Down Expand Up @@ -114,7 +125,6 @@ public void test_ceiling() throws Exception
@Test
public void test_floor() throws Exception
{

assertExpression(null, null, "floor(null)");
assertExpression(1, null, "floor(1)");
assertExpression(1L, null, "floor(1L)");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,14 @@ else if (actual instanceof ValueVector
actual = list;
}

assertEquals("Eval: " + expression, expected, actual);
if (actual instanceof byte[] bytes)
{
assertArrayEquals("Eval: " + expression, (byte[]) expected, (byte[]) actual);
}
else
{
assertEquals("Eval: " + expression, expected, actual);
}
}
catch (Exception e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ public void test_get_bytes()

byte[] slice = str.getBytes();
assertEquals("hello", new String(slice, StandardCharsets.UTF_8));

assertEquals("hello", UTF8String.from(slice)
.toString());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1424,6 +1424,8 @@
[{"key":"name","value": "abs"}, {"key":"type","value": "SCALAR"}, {"key":"description","value": "###IGNORE###"}],
[{"key":"name","value": "all"}, {"key":"type","value": "SCALAR"}, {"key":"description","value": "###IGNORE###"}],
[{"key":"name","value": "any"}, {"key":"type","value": "SCALAR"}, {"key":"description","value": "###IGNORE###"}],
[{"key":"name","value": "base64_decode"}, {"key":"type","value": "SCALAR"}, {"key":"description","value": "###IGNORE###"}],
[{"key":"name","value": "base64_encode"}, {"key":"type","value": "SCALAR"}, {"key":"description","value": "###IGNORE###"}],
[{"key":"name","value": "ceiling"}, {"key":"type","value": "SCALAR"}, {"key":"description","value": "###IGNORE###"}],
[{"key":"name","value": "char"}, {"key":"type","value": "SCALAR"}, {"key":"description","value": "###IGNORE###"}],
[{"key":"name","value": "charindex"}, {"key":"type","value": "SCALAR"}, {"key":"description","value": "###IGNORE###"}],
Expand Down

0 comments on commit 3e7a6a2

Please sign in to comment.