blob: e62012d701132d5cf6a6d18ad38a5564f32b0b45 [file] [log] [blame]
/*
* 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.iceberg;
import java.util.List;
import java.util.Map;
import org.apache.iceberg.relocated.com.google.common.collect.Maps;
import org.apache.iceberg.types.Type;
import org.apache.iceberg.types.TypeUtil;
import org.apache.iceberg.types.Types;
public class Accessors {
private Accessors() {
}
public static Integer toPosition(Accessor<StructLike> accessor) {
if (accessor instanceof PositionAccessor) {
return ((PositionAccessor) accessor).position();
}
throw new IllegalArgumentException("Cannot convert nested accessor to position");
}
static Map<Integer, Accessor<StructLike>> forSchema(Schema schema) {
return TypeUtil.visit(schema, new BuildPositionAccessors());
}
private static class PositionAccessor implements Accessor<StructLike> {
private int position;
private final Type type;
private final Class<?> javaClass;
PositionAccessor(int pos, Type type) {
this.position = pos;
this.type = type;
this.javaClass = type.typeId().javaClass();
}
@Override
public Object get(StructLike row) {
return row.get(position, javaClass);
}
@Override
public Type type() {
return type;
}
public int position() {
return position;
}
public Class<?> javaClass() {
return javaClass;
}
@Override
public String toString() {
return "Accessor(positions=[" + position + "], type=" + type + ")";
}
}
private static class Position2Accessor implements Accessor<StructLike> {
private final int p0;
private final int p1;
private final Type type;
private final Class<?> javaClass;
Position2Accessor(int pos, PositionAccessor wrapped) {
this.p0 = pos;
this.p1 = wrapped.position();
this.type = wrapped.type();
this.javaClass = wrapped.javaClass();
}
@Override
public Object get(StructLike row) {
return row.get(p0, StructLike.class).get(p1, javaClass);
}
@Override
public Type type() {
return type;
}
public Class<?> javaClass() {
return javaClass;
}
@Override
public String toString() {
return "Accessor(positions=[" + p0 + ", " + p1 + "], type=" + type + ")";
}
}
private static class Position3Accessor implements Accessor<StructLike> {
private final int p0;
private final int p1;
private final int p2;
private final Type type;
private final Class<?> javaClass;
Position3Accessor(int pos, Position2Accessor wrapped) {
this.p0 = pos;
this.p1 = wrapped.p0;
this.p2 = wrapped.p1;
this.type = wrapped.type();
this.javaClass = wrapped.javaClass();
}
@Override
public Object get(StructLike row) {
return row.get(p0, StructLike.class).get(p1, StructLike.class).get(p2, javaClass);
}
@Override
public Type type() {
return type;
}
@Override
public String toString() {
return "Accessor(positions=[" + p0 + ", " + p1 + ", " + p2 + "], type=" + type + ")";
}
}
private static class WrappedPositionAccessor implements Accessor<StructLike> {
private final int position;
private final Accessor<StructLike> accessor;
WrappedPositionAccessor(int pos, Accessor<StructLike> accessor) {
this.position = pos;
this.accessor = accessor;
}
@Override
public Object get(StructLike row) {
StructLike inner = row.get(position, StructLike.class);
if (inner != null) {
return accessor.get(inner);
}
return null;
}
@Override
public Type type() {
return accessor.type();
}
@Override
public String toString() {
return "WrappedAccessor(position=" + position + ", wrapped=" + accessor + ")";
}
}
private static Accessor<StructLike> newAccessor(int pos, Type type) {
return new PositionAccessor(pos, type);
}
private static Accessor<StructLike> newAccessor(int pos, boolean isOptional,
Accessor<StructLike> accessor) {
if (isOptional) {
// the wrapped position handles null layers
return new WrappedPositionAccessor(pos, accessor);
} else if (accessor.getClass() == PositionAccessor.class) {
return new Position2Accessor(pos, (PositionAccessor) accessor);
} else if (accessor instanceof Position2Accessor) {
return new Position3Accessor(pos, (Position2Accessor) accessor);
} else {
return new WrappedPositionAccessor(pos, accessor);
}
}
private static class BuildPositionAccessors extends TypeUtil.SchemaVisitor<Map<Integer, Accessor<StructLike>>> {
@Override
public Map<Integer, Accessor<StructLike>> schema(
Schema schema, Map<Integer, Accessor<StructLike>> structResult) {
return structResult;
}
@Override
public Map<Integer, Accessor<StructLike>> struct(
Types.StructType struct, List<Map<Integer, Accessor<StructLike>>> fieldResults) {
Map<Integer, Accessor<StructLike>> accessors = Maps.newHashMap();
List<Types.NestedField> fields = struct.fields();
for (int i = 0; i < fieldResults.size(); i += 1) {
Types.NestedField field = fields.get(i);
Map<Integer, Accessor<StructLike>> result = fieldResults.get(i);
if (result != null) {
for (Map.Entry<Integer, Accessor<StructLike>> entry : result.entrySet()) {
accessors.put(entry.getKey(), newAccessor(i, field.isOptional(), entry.getValue()));
}
} else {
accessors.put(field.fieldId(), newAccessor(i, field.type()));
}
}
return accessors;
}
@Override
public Map<Integer, Accessor<StructLike>> field(
Types.NestedField field, Map<Integer, Accessor<StructLike>> fieldResult) {
return fieldResult;
}
}
}