| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 org.apache.cassandra.cql3.functions.types; |
| |
| import java.util.Arrays; |
| import java.util.List; |
| |
| import com.google.common.collect.ImmutableList; |
| |
| import org.apache.cassandra.transport.ProtocolVersion; |
| import org.apache.cassandra.cql3.functions.types.exceptions.InvalidTypeException; |
| |
| /** |
| * A tuple type. |
| * |
| * <p>A tuple type is a essentially a list of types. |
| */ |
| public class TupleType extends DataType |
| { |
| |
| private final List<DataType> types; |
| private final ProtocolVersion protocolVersion; |
| private final CodecRegistry codecRegistry; |
| |
| TupleType(List<DataType> types, ProtocolVersion protocolVersion, CodecRegistry codecRegistry) |
| { |
| super(DataType.Name.TUPLE); |
| this.types = ImmutableList.copyOf(types); |
| this.protocolVersion = protocolVersion; |
| this.codecRegistry = codecRegistry; |
| } |
| |
| /** |
| * Creates a "disconnected" tuple type (<b>you should prefer {@code |
| * Metadata#newTupleType(DataType...) cluster.getMetadata().newTupleType(...)} whenever |
| * possible</b>). |
| * |
| * <p>This method is only exposed for situations where you don't have a {@code Cluster} instance |
| * available. If you create a type with this method and use it with a {@code Cluster} later, you |
| * won't be able to set tuple fields with custom codecs registered against the cluster, or you |
| * might get errors if the protocol versions don't match. |
| * |
| * @param protocolVersion the protocol version to use. |
| * @param codecRegistry the codec registry to use. |
| * @param types the types for the tuple type. |
| * @return the newly created tuple type. |
| */ |
| public static TupleType of( |
| ProtocolVersion protocolVersion, CodecRegistry codecRegistry, DataType... types) |
| { |
| return new TupleType(Arrays.asList(types), protocolVersion, codecRegistry); |
| } |
| |
| /** |
| * The (immutable) list of types composing this tuple type. |
| * |
| * @return the (immutable) list of types composing this tuple type. |
| */ |
| List<DataType> getComponentTypes() |
| { |
| return types; |
| } |
| |
| /** |
| * Returns a new empty value for this tuple type. |
| * |
| * @return an empty (with all component to {@code null}) value for this user type definition. |
| */ |
| public TupleValue newValue() |
| { |
| return new TupleValue(this); |
| } |
| |
| /** |
| * Returns a new value for this tuple type that uses the provided values for the components. |
| * |
| * <p>The numbers of values passed to this method must correspond to the number of components in |
| * this tuple type. The {@code i}th parameter value will then be assigned to the {@code i}th |
| * component of the resulting tuple value. |
| * |
| * @param values the values to use for the component of the resulting tuple. |
| * @return a new tuple values based on the provided values. |
| * @throws IllegalArgumentException if the number of {@code values} provided does not correspond |
| * to the number of components in this tuple type. |
| * @throws InvalidTypeException if any of the provided value is not of the correct type for the |
| * component. |
| */ |
| public TupleValue newValue(Object... values) |
| { |
| if (values.length != types.size()) |
| throw new IllegalArgumentException( |
| String.format( |
| "Invalid number of values. Expecting %d but got %d", types.size(), values.length)); |
| |
| TupleValue t = newValue(); |
| for (int i = 0; i < values.length; i++) |
| { |
| DataType dataType = types.get(i); |
| if (values[i] == null) t.setValue(i, null); |
| else |
| t.setValue( |
| i, codecRegistry.codecFor(dataType, values[i]).serialize(values[i], protocolVersion)); |
| } |
| return t; |
| } |
| |
| @Override |
| public boolean isFrozen() |
| { |
| return true; |
| } |
| |
| /** |
| * Return the protocol version that has been used to deserialize this tuple type, or that will be |
| * used to serialize it. In most cases this should be the version currently in use by the cluster |
| * instance that this tuple type belongs to, as reported by {@code |
| * ProtocolOptions#getProtocolVersion()}. |
| * |
| * @return the protocol version that has been used to deserialize this tuple type, or that will be |
| * used to serialize it. |
| */ |
| ProtocolVersion getProtocolVersion() |
| { |
| return protocolVersion; |
| } |
| |
| CodecRegistry getCodecRegistry() |
| { |
| return codecRegistry; |
| } |
| |
| @Override |
| public int hashCode() |
| { |
| return Arrays.hashCode(new Object[]{ name, types }); |
| } |
| |
| @Override |
| public boolean equals(Object o) |
| { |
| if (!(o instanceof TupleType)) return false; |
| |
| TupleType d = (TupleType) o; |
| return name == d.name && types.equals(d.types); |
| } |
| |
| /** |
| * Return {@code true} if this tuple type contains the given tuple type, and {@code false} |
| * otherwise. |
| * |
| * <p>A tuple type is said to contain another one if the latter has fewer components than the |
| * former, but all of them are of the same type. E.g. the type {@code tuple<int, text>} is |
| * contained by the type {@code tuple<int, text, double>}. |
| * |
| * <p>A contained type can be seen as a "partial" view of a containing type, where the missing |
| * components are supposed to be {@code null}. |
| * |
| * @param other the tuple type to compare against the current one |
| * @return {@code true} if this tuple type contains the given tuple type, and {@code false} |
| * otherwise. |
| */ |
| public boolean contains(TupleType other) |
| { |
| if (this.equals(other)) return true; |
| if (other.types.size() > this.types.size()) return false; |
| return types.subList(0, other.types.size()).equals(other.types); |
| } |
| |
| @Override |
| public String toString() |
| { |
| return "frozen<" + asFunctionParameterString() + '>'; |
| } |
| |
| @Override |
| public String asFunctionParameterString() |
| { |
| StringBuilder sb = new StringBuilder(); |
| for (DataType type : types) |
| { |
| sb.append(sb.length() == 0 ? "tuple<" : ", "); |
| sb.append(type.asFunctionParameterString()); |
| } |
| return sb.append('>').toString(); |
| } |
| } |