| /** |
| * Copyright 2012 Twitter, 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 parquet.schema; |
| |
| import java.util.Arrays; |
| import java.util.List; |
| |
| import parquet.column.ColumnReader; |
| import parquet.io.InvalidRecordException; |
| import parquet.io.api.Binary; |
| import parquet.io.api.PrimitiveConverter; |
| import parquet.io.api.RecordConsumer; |
| |
| |
| /** |
| * |
| * Representation of a Primitive type |
| * |
| * @author Julien Le Dem |
| * |
| */ |
| public final class PrimitiveType extends Type { |
| |
| public static interface PrimitiveTypeNameConverter<T> { |
| |
| T convertFLOAT(PrimitiveTypeName primitiveTypeName); |
| |
| T convertDOUBLE(PrimitiveTypeName primitiveTypeName); |
| |
| T convertINT32(PrimitiveTypeName primitiveTypeName); |
| |
| T convertINT64(PrimitiveTypeName primitiveTypeName); |
| |
| T convertINT96(PrimitiveTypeName primitiveTypeName); |
| |
| T convertFIXED_LEN_BYTE_ARRAY(PrimitiveTypeName primitiveTypeName); |
| |
| T convertBOOLEAN(PrimitiveTypeName primitiveTypeName); |
| |
| T convertBINARY(PrimitiveTypeName primitiveTypeName); |
| |
| } |
| |
| /** |
| * Supported Primitive types |
| * |
| * @author Julien Le Dem |
| */ |
| public static enum PrimitiveTypeName { |
| |
| INT64("Long", Long.TYPE) { |
| @Override |
| public String toString(ColumnReader columnReader) { |
| return String.valueOf(columnReader.getLong()); |
| } |
| |
| @Override |
| public void addValueToRecordConsumer(RecordConsumer recordConsumer, |
| ColumnReader columnReader) { |
| recordConsumer.addLong(columnReader.getLong()); |
| } |
| |
| @Override |
| public void addValueToPrimitiveConverter( |
| PrimitiveConverter primitiveConverter, ColumnReader columnReader) { |
| primitiveConverter.addLong(columnReader.getLong()); |
| } |
| |
| @Override |
| public <T> T convert(PrimitiveTypeNameConverter<T> converter) { |
| return converter.convertINT64(this); |
| } |
| }, |
| INT32("Integer", Integer.TYPE) { |
| @Override |
| public String toString(ColumnReader columnReader) { |
| return String.valueOf(columnReader.getInteger()); |
| } |
| |
| @Override |
| public void addValueToRecordConsumer(RecordConsumer recordConsumer, |
| ColumnReader columnReader) { |
| recordConsumer.addInteger(columnReader.getInteger()); |
| } |
| |
| @Override |
| public void addValueToPrimitiveConverter( |
| PrimitiveConverter primitiveConverter, ColumnReader columnReader) { |
| primitiveConverter.addInt(columnReader.getInteger()); |
| } |
| |
| @Override |
| public <T> T convert(PrimitiveTypeNameConverter<T> converter) { |
| return converter.convertINT32(this); |
| } |
| }, |
| BOOLEAN("Boolean", Boolean.TYPE) { |
| @Override |
| public String toString(ColumnReader columnReader) { |
| return String.valueOf(columnReader.getBoolean()); |
| } |
| |
| @Override |
| public void addValueToRecordConsumer(RecordConsumer recordConsumer, |
| ColumnReader columnReader) { |
| recordConsumer.addBoolean(columnReader.getBoolean()); |
| } |
| |
| @Override |
| public void addValueToPrimitiveConverter( |
| PrimitiveConverter primitiveConverter, ColumnReader columnReader) { |
| primitiveConverter.addBoolean(columnReader.getBoolean()); |
| } |
| |
| @Override |
| public <T> T convert(PrimitiveTypeNameConverter<T> converter) { |
| return converter.convertBOOLEAN(this); |
| } |
| }, |
| BINARY("Binary", Binary.class) { |
| @Override |
| public String toString(ColumnReader columnReader) { |
| return String.valueOf(columnReader.getBinary()); |
| } |
| |
| @Override |
| public void addValueToRecordConsumer(RecordConsumer recordConsumer, |
| ColumnReader columnReader) { |
| recordConsumer.addBinary(columnReader.getBinary()); |
| } |
| |
| @Override |
| public void addValueToPrimitiveConverter( |
| PrimitiveConverter primitiveConverter, ColumnReader columnReader) { |
| primitiveConverter.addBinary(columnReader.getBinary()); |
| } |
| |
| @Override |
| public <T> T convert(PrimitiveTypeNameConverter<T> converter) { |
| return converter.convertBINARY(this); |
| } |
| }, |
| FLOAT("Float", Float.TYPE) { |
| @Override |
| public String toString(ColumnReader columnReader) { |
| return String.valueOf(columnReader.getFloat()); |
| } |
| |
| @Override |
| public void addValueToRecordConsumer(RecordConsumer recordConsumer, |
| ColumnReader columnReader) { |
| recordConsumer.addFloat(columnReader.getFloat()); |
| } |
| |
| @Override |
| public void addValueToPrimitiveConverter( |
| PrimitiveConverter primitiveConverter, ColumnReader columnReader) { |
| primitiveConverter.addFloat(columnReader.getFloat()); |
| } |
| |
| @Override |
| public <T> T convert(PrimitiveTypeNameConverter<T> converter) { |
| return converter.convertFLOAT(this); |
| } |
| }, |
| DOUBLE("Double", Double.TYPE) { |
| @Override |
| public String toString(ColumnReader columnReader) { |
| return String.valueOf(columnReader.getDouble()); |
| } |
| |
| @Override |
| public void addValueToRecordConsumer(RecordConsumer recordConsumer, |
| ColumnReader columnReader) { |
| recordConsumer.addDouble(columnReader.getDouble()); |
| } |
| |
| @Override |
| public void addValueToPrimitiveConverter( |
| PrimitiveConverter primitiveConverter, ColumnReader columnReader) { |
| primitiveConverter.addDouble(columnReader.getDouble()); |
| } |
| |
| @Override |
| public <T> T convert(PrimitiveTypeNameConverter<T> converter) { |
| return converter.convertDOUBLE(this); |
| } |
| }, |
| INT96(null, null) { // TODO: support for INT96 |
| @Override |
| public String toString(ColumnReader columnReader) { |
| throw new UnsupportedOperationException("NYI"); |
| } |
| @Override |
| public void addValueToRecordConsumer(RecordConsumer recordConsumer, |
| ColumnReader columnReader) { |
| throw new UnsupportedOperationException("NYI"); |
| } |
| @Override |
| public void addValueToPrimitiveConverter( |
| PrimitiveConverter primitiveConverter, ColumnReader columnReader) { |
| throw new UnsupportedOperationException("NYI"); |
| } |
| |
| @Override |
| public <T> T convert(PrimitiveTypeNameConverter<T> converter) { |
| return converter.convertINT96(this); |
| } |
| }, |
| FIXED_LEN_BYTE_ARRAY(null, null) { // TODO: support for FIXED_LEN_BYTE_ARRAY |
| |
| @Override |
| public String toString(ColumnReader columnReader) { |
| throw new UnsupportedOperationException("NYI"); |
| } |
| |
| @Override |
| public void addValueToRecordConsumer(RecordConsumer recordConsumer, |
| ColumnReader columnReader) { |
| throw new UnsupportedOperationException("NYI"); |
| } |
| |
| @Override |
| public void addValueToPrimitiveConverter( |
| PrimitiveConverter primitiveConverter, ColumnReader columnReader) { |
| throw new UnsupportedOperationException("NYI"); |
| } |
| |
| @Override |
| public <T> T convert(PrimitiveTypeNameConverter<T> converter) { |
| return converter.convertFIXED_LEN_BYTE_ARRAY(this); |
| } |
| }; |
| |
| private final String internalName; |
| public final Class<?> javaType; |
| |
| private PrimitiveTypeName(String internalName, Class<?> javaType) { |
| this.internalName = internalName; |
| this.javaType = javaType; |
| } |
| |
| public String getMethod() { |
| return "get" + internalName; |
| } |
| |
| public String addMethod() { |
| return "add" + internalName; |
| } |
| |
| |
| /** |
| * reads the value from the columnReader with the appropriate accessor and returns a String representation |
| * @param columnReader |
| * @return a string |
| */ |
| abstract public String toString(ColumnReader columnReader); |
| |
| /** |
| * reads the value from the columnReader with the appropriate accessor and writes it to the recordConsumer |
| * @param recordConsumer where to write |
| * @param columnReader where to read from |
| */ |
| abstract public void addValueToRecordConsumer(RecordConsumer recordConsumer, |
| ColumnReader columnReader); |
| |
| abstract public void addValueToPrimitiveConverter( |
| PrimitiveConverter primitiveConverter, ColumnReader columnReader); |
| |
| abstract public <T> T convert(PrimitiveTypeNameConverter<T> converter); |
| |
| } |
| |
| private final PrimitiveTypeName primitive; |
| |
| /** |
| * |
| * @param repetition the OPTIONAL, REPEATED, REQUIRED |
| * @param primitive STRING, INT64, ... |
| * @param name the name of the type |
| */ |
| public PrimitiveType(Repetition repetition, PrimitiveTypeName primitive, String name) { |
| this(repetition, primitive, name, null); |
| } |
| |
| public PrimitiveType(Repetition repetition, PrimitiveTypeName primitive, String name, OriginalType originalType) { |
| super(name, repetition, originalType); |
| this.primitive = primitive; |
| } |
| |
| /** |
| * @return the primitive type |
| */ |
| public PrimitiveTypeName getPrimitiveTypeName() { |
| return primitive; |
| } |
| |
| /** |
| * @return true |
| */ |
| @Override |
| public boolean isPrimitive() { |
| return true; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void accept(TypeVisitor visitor) { |
| visitor.visit(this); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void writeToStringBuilder(StringBuilder sb, String indent) { |
| sb.append(indent) |
| .append(getRepetition().name().toLowerCase()) |
| .append(" ") |
| .append(primitive.name().toLowerCase()) |
| .append(" ") |
| .append(getName()); |
| if (getOriginalType() != null) { |
| sb.append(" (").append(getOriginalType()).append(")"); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| protected boolean typeEquals(Type other) { |
| if (other.isPrimitive()) { |
| PrimitiveType primitiveType = other.asPrimitiveType(); |
| return getRepetition() == primitiveType.getRepetition() && |
| getPrimitiveTypeName().equals(primitiveType.getPrimitiveTypeName()) && |
| getName().equals(primitiveType.getName()); |
| } else { |
| return false; |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| protected int typeHashCode() { |
| int hash = 17; |
| hash += 31 * getRepetition().hashCode(); |
| hash += 31 * getPrimitiveTypeName().hashCode(); |
| hash += 31 * getName().hashCode(); |
| return hash; |
| } |
| |
| @Override |
| public int getMaxRepetitionLevel(String[] path, int i) { |
| if (path.length != i) { |
| throw new InvalidRecordException("Arrived at primitive node, path invalid"); |
| } |
| return getRepetition() == Repetition.REPEATED ? 1 : 0; |
| } |
| |
| @Override |
| public int getMaxDefinitionLevel(String[] path, int i) { |
| if (path.length != i) { |
| throw new InvalidRecordException("Arrived at primitive node, path invalid"); |
| } |
| return getRepetition() == Repetition.REQUIRED ? 0 : 1; |
| } |
| |
| @Override |
| public Type getType(String[] path, int i) { |
| if (path.length != i) { |
| throw new InvalidRecordException("Arrived at primitive node at index " + i + " , path invalid: " + Arrays.toString(path)); |
| } |
| return this; |
| } |
| |
| @Override |
| protected List<String[]> getPaths(int depth) { |
| return Arrays.<String[]>asList(new String[depth]); |
| } |
| |
| @Override |
| void checkContains(Type subType) { |
| super.checkContains(subType); |
| if (!subType.isPrimitive()) { |
| throw new InvalidRecordException(subType + " found: expected " + this); |
| } |
| PrimitiveType primitiveType = subType.asPrimitiveType(); |
| if (this.primitive != primitiveType.primitive) { |
| throw new InvalidRecordException(subType + " found: expected " + this); |
| } |
| |
| } |
| |
| @Override |
| public <T> T convert(List<GroupType> path, TypeConverter<T> converter) { |
| return converter.convertPrimitiveType(path, this); |
| } |
| |
| @Override |
| protected boolean containsPath(String[] path, int depth) { |
| return path.length == depth; |
| } |
| } |