All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.iceberg.util.StructProjection Maven / Gradle / Ivy

The newest version!
/*
 * 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.util;

import java.util.List;
import java.util.Set;
import org.apache.iceberg.Schema;
import org.apache.iceberg.StructLike;
import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
import org.apache.iceberg.types.TypeUtil;
import org.apache.iceberg.types.Types;
import org.apache.iceberg.types.Types.ListType;
import org.apache.iceberg.types.Types.MapType;
import org.apache.iceberg.types.Types.StructType;

public class StructProjection implements StructLike {
  /**
   * Creates a projecting wrapper for {@link StructLike} rows.
   * 

* This projection does not work with repeated types like lists and maps. * * @param schema schema of rows wrapped by this projection * @param ids field ids from the row schema to project * @return a wrapper to project rows */ public static StructProjection create(Schema schema, Set ids) { StructType structType = schema.asStruct(); return new StructProjection(structType, TypeUtil.project(structType, ids)); } /** * Creates a projecting wrapper for {@link StructLike} rows. *

* This projection does not work with repeated types like lists and maps. * * @param dataSchema schema of rows wrapped by this projection * @param projectedSchema result schema of the projected rows * @return a wrapper to project rows */ public static StructProjection create(Schema dataSchema, Schema projectedSchema) { return new StructProjection(dataSchema.asStruct(), projectedSchema.asStruct()); } /** * Creates a projecting wrapper for {@link StructLike} rows. *

* This projection does not work with repeated types like lists and maps. * * @param structType type of rows wrapped by this projection * @param projectedStructType result type of the projected rows * @return a wrapper to project rows */ public static StructProjection create(StructType structType, StructType projectedStructType) { return new StructProjection(structType, projectedStructType); } /** * Creates a projecting wrapper for {@link StructLike} rows. *

* This projection allows missing fields and does not work with repeated types like lists and maps. * * @param structType type of rows wrapped by this projection * @param projectedStructType result type of the projected rows * @return a wrapper to project rows */ public static StructProjection createAllowMissing(StructType structType, StructType projectedStructType) { return new StructProjection(structType, projectedStructType, true); } private final StructType type; private final int[] positionMap; private final StructProjection[] nestedProjections; private StructLike struct; private StructProjection(StructType structType, StructType projection) { this(structType, projection, false); } @SuppressWarnings("checkstyle:CyclomaticComplexity") private StructProjection(StructType structType, StructType projection, boolean allowMissing) { this.type = projection; this.positionMap = new int[projection.fields().size()]; this.nestedProjections = new StructProjection[projection.fields().size()]; // set up the projection positions and any nested projections that are needed List dataFields = structType.fields(); for (int pos = 0; pos < positionMap.length; pos += 1) { Types.NestedField projectedField = projection.fields().get(pos); boolean found = false; for (int i = 0; !found && i < dataFields.size(); i += 1) { Types.NestedField dataField = dataFields.get(i); if (projectedField.fieldId() == dataField.fieldId()) { found = true; positionMap[pos] = i; switch (projectedField.type().typeId()) { case STRUCT: nestedProjections[pos] = new StructProjection( dataField.type().asStructType(), projectedField.type().asStructType()); break; case MAP: MapType projectedMap = projectedField.type().asMapType(); MapType originalMap = dataField.type().asMapType(); boolean keyProjectable = !projectedMap.keyType().isNestedType() || projectedMap.keyType().equals(originalMap.keyType()); boolean valueProjectable = !projectedMap.valueType().isNestedType() || projectedMap.valueType().equals(originalMap.valueType()); Preconditions.checkArgument(keyProjectable && valueProjectable, "Cannot project a partial map key or value struct. Trying to project %s out of %s", projectedField, dataField); nestedProjections[pos] = null; break; case LIST: ListType projectedList = projectedField.type().asListType(); ListType originalList = dataField.type().asListType(); boolean elementProjectable = !projectedList.elementType().isNestedType() || projectedList.elementType().equals(originalList.elementType()); Preconditions.checkArgument(elementProjectable, "Cannot project a partial list element struct. Trying to project %s out of %s", projectedField, dataField); nestedProjections[pos] = null; break; default: nestedProjections[pos] = null; } } } if (!found && projectedField.isOptional() && allowMissing) { positionMap[pos] = -1; nestedProjections[pos] = null; } else if (!found) { throw new IllegalArgumentException(String.format("Cannot find field %s in %s", projectedField, structType)); } } } public StructProjection wrap(StructLike newStruct) { this.struct = newStruct; return this; } @Override public int size() { return type.fields().size(); } @Override public T get(int pos, Class javaClass) { if (struct == null) { // Return a null struct when projecting a nested required field from an optional struct. // See more details in issue #2738. return null; } int structPos = positionMap[pos]; if (nestedProjections[pos] != null) { return javaClass.cast(nestedProjections[pos].wrap(struct.get(structPos, StructLike.class))); } if (structPos != -1) { return struct.get(structPos, javaClass); } else { return null; } } @Override public void set(int pos, T value) { throw new UnsupportedOperationException("Cannot set fields in a TypeProjection"); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy