/* * Copyright (C) 2012-2015 DataStax Inc. * * 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.datastax.driver.core; import com.datastax.driver.core.utils.CassandraVersion; import org.testng.annotations.Test; import static com.datastax.driver.core.Assertions.assertThat; import static com.datastax.driver.core.DataType.cint; import static com.datastax.driver.core.DataType.map; import static org.assertj.core.api.Assertions.entry; @CassandraVersion("2.2.0") @CCMConfig(config = "enable_user_defined_functions:true") public class FunctionMetadataTest extends CCMTestsSupport { @Test(groups = "short") public void should_parse_and_format_simple_function() { // given String cql = String.format("CREATE FUNCTION %s.plus(s int,v int) RETURNS NULL ON NULL INPUT RETURNS int LANGUAGE java AS 'return s+v;';", keyspace); // when session().execute(cql); // then KeyspaceMetadata keyspace = cluster().getMetadata().getKeyspace(this.keyspace); FunctionMetadata function = keyspace.getFunction("plus", cint(), cint()); assertThat(function).isNotNull(); assertThat(function.getKeyspace()).isEqualTo(keyspace); assertThat(function.getSignature()).isEqualTo("plus(int,int)"); assertThat(function.getSimpleName()).isEqualTo("plus"); assertThat(function.getReturnType()).isEqualTo(cint()); assertThat(function.getArguments()) .containsEntry("s", cint()) .containsEntry("v", cint()); assertThat(function.getLanguage()).isEqualTo("java"); assertThat(function.getBody()).isEqualTo("return s+v;"); assertThat(function.isCalledOnNullInput()).isFalse(); assertThat(function.toString()) .isEqualTo(cql); assertThat(function.exportAsString()) .isEqualTo(String.format("CREATE FUNCTION %s.plus(\n" + " s int,\n" + " v int)\n" + "RETURNS NULL ON NULL INPUT\n" + "RETURNS int\n" + "LANGUAGE java\n" + "AS 'return s+v;';", this.keyspace)); } @Test(groups = "short") public void should_parse_and_format_function_with_no_arguments() { // given String cql = String.format("CREATE FUNCTION %s.pi() CALLED ON NULL INPUT RETURNS double LANGUAGE java AS 'return Math.PI;';", keyspace); // when session().execute(cql); // then KeyspaceMetadata keyspace = cluster().getMetadata().getKeyspace(this.keyspace); FunctionMetadata function = keyspace.getFunction("pi"); assertThat(function).isNotNull(); assertThat(function.getKeyspace()).isEqualTo(keyspace); assertThat(function.getSignature()).isEqualTo("pi()"); assertThat(function.getSimpleName()).isEqualTo("pi"); assertThat(function.getReturnType()).isEqualTo(DataType.cdouble()); assertThat(function.getArguments()).isEmpty(); assertThat(function.getLanguage()).isEqualTo("java"); assertThat(function.getBody()).isEqualTo("return Math.PI;"); assertThat(function.isCalledOnNullInput()).isTrue(); assertThat(function.toString()) .isEqualTo(cql); assertThat(function.exportAsString()) .isEqualTo(String.format("CREATE FUNCTION %s.pi()\n" + "CALLED ON NULL INPUT\n" + "RETURNS double\n" + "LANGUAGE java\n" + "AS 'return Math.PI;';", this.keyspace)); } @Test(groups = "short") public void should_parse_and_format_function_with_udts() { // given String body = "//If \"called on null input\", handle nulls\n" + "if(ADDRESS == null) return previous_total + 0;\n" + "//User types are converted to com.datastax.driver.core.UDTValue types\n" + "java.util.Set phones = ADDRESS.getSet(\"phones\", com.datastax.driver.core.UDTValue.class);\n" + "return previous_total + phones.size();\n"; String cqlFunction = String.format( "CREATE FUNCTION %s.\"NUM_PHONES_ACCU\"(previous_total int,\"ADDRESS\" \"Address\") " + "CALLED ON NULL INPUT " + "RETURNS int " + "LANGUAGE java " + "AS " + "'" + body + "';", keyspace); // when session().execute(cqlFunction); // then KeyspaceMetadata keyspace = cluster().getMetadata().getKeyspace(this.keyspace); UserType addressType = keyspace.getUserType("\"Address\""); FunctionMetadata function = keyspace.getFunction("\"NUM_PHONES_ACCU\"", cint(), addressType); assertThat(function).isNotNull(); assertThat(function.getKeyspace()).isEqualTo(keyspace); assertThat(function.getSignature()).isEqualTo("\"NUM_PHONES_ACCU\"(int,\"Address\")"); assertThat(function.getSimpleName()).isEqualTo("NUM_PHONES_ACCU"); assertThat(function.getReturnType()).isEqualTo(cint()); assertThat(function.getArguments()).containsExactly(entry("previous_total", cint()), entry("ADDRESS", addressType)); assertThat(function.getLanguage()).isEqualTo("java"); assertThat(function.getBody()).isEqualTo(body); assertThat(function.isCalledOnNullInput()).isTrue(); assertThat(function.toString()).isEqualTo(cqlFunction); } /** * Ensures that functions whose arguments contain complex types such as * tuples and collections, and nested combinations thereof, are * correctly parsed. * * @jira_ticket JAVA-1137 */ @Test(groups = "short") public void should_parse_and_format_functions_with_complex_arguments() { // given String cql = String.format("CREATE FUNCTION %s.complex(x tuple<tuple<int>, map<int, int>>) RETURNS NULL ON NULL INPUT RETURNS int LANGUAGE java AS 'return 42;';", keyspace); // when session().execute(cql); // then KeyspaceMetadata keyspace = cluster().getMetadata().getKeyspace(this.keyspace); DataType argumentType = cluster().getMetadata().newTupleType(cluster().getMetadata().newTupleType(cint()), map(cint(), cint())); FunctionMetadata function = keyspace.getFunction("complex", argumentType); assertThat(function).isNotNull(); assertThat(function.getKeyspace()).isEqualTo(keyspace); assertThat(function.getSignature()).isEqualTo("complex(tuple<tuple<int>, map<int, int>>)"); assertThat(function.getSimpleName()).isEqualTo("complex"); assertThat(function.getReturnType()).isEqualTo(cint()); assertThat(function.getArguments()) .containsEntry("x", argumentType); assertThat(function.getLanguage()).isEqualTo("java"); assertThat(function.getBody()).isEqualTo("return 42;"); assertThat(function.isCalledOnNullInput()).isFalse(); assertThat(function.toString()) .isEqualTo(cql); assertThat(function.exportAsString()) .isEqualTo(String.format("CREATE FUNCTION %s.complex(\n" + " x tuple<tuple<int>, map<int, int>>)\n" + "RETURNS NULL ON NULL INPUT\n" + "RETURNS int\n" + "LANGUAGE java\n" + "AS 'return 42;';", this.keyspace)); } @Override public void onTestContextInitialized() { execute( String.format("CREATE TYPE IF NOT EXISTS %s.\"Phone\" (number text)", keyspace), String.format("CREATE TYPE IF NOT EXISTS %s.\"Address\" (" + " street text," + " city text," + " zip int," + " phones frozen<set<frozen<\"Phone\">>>," + " location frozen<tuple<float, float>>" + ")", keyspace) ); } }