/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.facebook.presto.operator.scalar; import com.facebook.presto.Session; import com.facebook.presto.type.ArrayType; import com.facebook.presto.type.RowType; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import java.util.Optional; import static com.facebook.presto.operator.scalar.ApplyFunction.APPLY_FUNCTION; import static com.facebook.presto.operator.scalar.InvokeFunction.INVOKE_FUNCTION; import static com.facebook.presto.spi.StandardErrorCode.NOT_SUPPORTED; import static com.facebook.presto.spi.type.BigintType.BIGINT; import static com.facebook.presto.spi.type.BooleanType.BOOLEAN; import static com.facebook.presto.spi.type.DoubleType.DOUBLE; import static com.facebook.presto.spi.type.IntegerType.INTEGER; import static com.facebook.presto.spi.type.TimeZoneKey.getTimeZoneKey; import static com.facebook.presto.spi.type.VarcharType.VARCHAR; import static com.facebook.presto.spi.type.VarcharType.createUnboundedVarcharType; import static com.facebook.presto.spi.type.VarcharType.createVarcharType; import static com.facebook.presto.testing.TestingSession.testSessionBuilder; import static com.facebook.presto.util.StructuralTestUtil.mapType; public class TestLambdaExpression extends AbstractTestFunctions { public TestLambdaExpression() { this(testSessionBuilder().setTimeZoneKey(getTimeZoneKey("Pacific/Kiritimati")).build()); } private TestLambdaExpression(Session session) { super(session); } @BeforeClass public void setUp() { functionAssertions.getMetadata().addFunctions(ImmutableList.of(APPLY_FUNCTION, INVOKE_FUNCTION)); } @Test public void testBasic() throws Exception { assertFunction("apply(5, x -> x + 1)", INTEGER, 6); assertFunction("apply(5 + RANDOM(1), x -> x + 1)", INTEGER, 6); } @Test public void testNull() throws Exception { assertFunction("apply(3, x -> x + 1)", INTEGER, 4); assertFunction("apply(NULL, x -> x + 1)", INTEGER, null); assertFunction("apply(CAST (NULL AS INTEGER), x -> x + 1)", INTEGER, null); assertFunction("apply(3, x -> x IS NULL)", BOOLEAN, false); assertFunction("apply(NULL, x -> x IS NULL)", BOOLEAN, true); assertFunction("apply(CAST (NULL AS INTEGER), x -> x IS NULL)", BOOLEAN, true); } @Test public void testUnreferencedLambdaArgument() { assertFunction("apply(5, x -> 6)", INTEGER, 6); } @Test public void testSessionDependent() throws Exception { assertFunction("apply('timezone: ', x -> x || current_timezone())", VARCHAR, "timezone: Pacific/Kiritimati"); } @Test public void testInstanceFunction() { assertFunction("apply(ARRAY[2], x -> concat(ARRAY [1], x))", new ArrayType(INTEGER), ImmutableList.of(1, 2)); } @Test public void testWithTry() throws Exception { assertFunction("TRY(apply(5, x -> x + 1) / 0)", INTEGER, null); assertFunction("TRY(apply(5 + RANDOM(1), x -> x + 1) / 0)", INTEGER, null); assertInvalidFunction("apply(5 + RANDOM(1), x -> x + TRY(1 / 0))", NOT_SUPPORTED); } @Test public void testNestedLambda() throws Exception { assertFunction("apply(11, x -> apply(x + 7, y -> apply(y * 3, z -> z * 5) + 1) * 2)", INTEGER, 542); assertFunction("apply(11, x -> apply(x + 7, x -> apply(x * 3, x -> x * 5) + 1) * 2)", INTEGER, 542); } @Test public void testRowAccess() throws Exception { assertFunction("apply(CAST(ROW(1, 'a') AS ROW(x INTEGER, y VARCHAR)), r -> r.x)", INTEGER, 1); assertFunction("apply(CAST(ROW(1, 'a') AS ROW(x INTEGER, y VARCHAR)), r -> r.y)", VARCHAR, "a"); } @Test public void testBind() throws Exception { assertFunction("apply(90, \"$internal$bind\"(9, (x, y) -> x + y))", INTEGER, 99); assertFunction("invoke(\"$internal$bind\"(8, x -> x + 1))", INTEGER, 9); assertFunction("apply(900, \"$internal$bind\"(90, \"$internal$bind\"(9, (x, y, z) -> x + y + z)))", INTEGER, 999); assertFunction("invoke(\"$internal$bind\"(90, \"$internal$bind\"(9, (x, y) -> x + y)))", INTEGER, 99); } @Test public void testCoercion() throws Exception { assertFunction("apply(90, x -> x + 9.0)", DOUBLE, 99.0); assertFunction("apply(90, \"$internal$bind\"(9.0, (x, y) -> x + y))", DOUBLE, 99.0); assertFunction("invoke(\"$internal$bind\"(8, x -> x + 1.0))", DOUBLE, 9.0); } @Test public void testTypeCombinations() throws Exception { assertFunction("apply(25, x -> x + 1)", INTEGER, 26); assertFunction("apply(25, x -> x + 1.0)", DOUBLE, 26.0); assertFunction("apply(25, x -> x = 25)", BOOLEAN, true); assertFunction("apply(25, x -> to_base(x, 16))", createVarcharType(64), "19"); assertFunction("apply(25, x -> ARRAY[x + 1])", new ArrayType(INTEGER), ImmutableList.of(26)); assertFunction("apply(25.6, x -> CAST(x AS BIGINT))", BIGINT, 26L); assertFunction("apply(25.6, x -> x + 1.0)", DOUBLE, 26.6); assertFunction("apply(25.6, x -> x = 25.6)", BOOLEAN, true); assertFunction("apply(25.6, x -> CAST(x AS VARCHAR))", createUnboundedVarcharType(), "25.6"); assertFunction("apply(25.6, x -> MAP(ARRAY[x + 1], ARRAY[true]))", mapType(DOUBLE, BOOLEAN), ImmutableMap.of(26.6, true)); assertFunction("apply(true, x -> if(x, 25, 26))", INTEGER, 25); assertFunction("apply(false, x -> if(x, 25.6, 28.9))", DOUBLE, 28.9); assertFunction("apply(true, x -> not x)", BOOLEAN, false); assertFunction("apply(false, x -> CAST(x AS VARCHAR))", createUnboundedVarcharType(), "false"); assertFunction("apply(true, x -> ARRAY[x])", new ArrayType(BOOLEAN), ImmutableList.of(true)); assertFunction("apply('41', x -> from_base(x, 16))", BIGINT, 65L); assertFunction("apply('25.6', x -> CAST(x AS DOUBLE))", DOUBLE, 25.6); assertFunction("apply('abc', x -> 'abc' = x)", BOOLEAN, true); assertFunction("apply('abc', x -> x || x)", createUnboundedVarcharType(), "abcabc"); assertFunction( "apply('123', x -> ROW(x, CAST(x AS INTEGER), x > '0'))", new RowType(ImmutableList.of(createVarcharType(3), INTEGER, BOOLEAN), Optional.empty()), ImmutableList.of("123", 123, true)); assertFunction("apply(ARRAY['abc', NULL, '123'], x -> from_base(x[3], 10))", BIGINT, 123L); assertFunction("apply(ARRAY['abc', NULL, '123'], x -> CAST(x[3] AS DOUBLE))", DOUBLE, 123.0); assertFunction("apply(ARRAY['abc', NULL, '123'], x -> x[2] IS NULL)", BOOLEAN, true); assertFunction("apply(ARRAY['abc', NULL, '123'], x -> x[2])", createVarcharType(3), null); assertFunction("apply(MAP(ARRAY['abc', 'def'], ARRAY[123, 456]), x -> map_keys(x))", new ArrayType(createVarcharType(3)), ImmutableList.of("abc", "def")); } }