diff --git a/parquet-column/src/main/java/org/apache/parquet/schema/Types.java b/parquet-column/src/main/java/org/apache/parquet/schema/Types.java index b06c2bcb8f..65e1ef067f 100644 --- a/parquet-column/src/main/java/org/apache/parquet/schema/Types.java +++ b/parquet-column/src/main/java/org/apache/parquet/schema/Types.java @@ -19,6 +19,7 @@ package org.apache.parquet.schema; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.apache.parquet.Preconditions; @@ -89,6 +90,64 @@ * .named("User") * *
+ * Maps are built similarly, using {@code requiredMap()} (or the optionalMap() + * version) to return a map builder. Map builders provide {@code key} to add + * a primitive as key or a {@code groupKey} to add a group as key. {@code key()} + * returns a MapKey builder, which extends a primitive builder. On the other hand, + * {@code groupKey()} returns a MapGroupKey builder, which extends a group builder. + * A key in a map is always required. + *
+ * Once a key is built, a primitive map value can be built using {@code requiredValue()} + * (or the optionalValue() version) that returns MapValue builder. A group map value + * can be built using {@code requiredGroupValue()} (or the optionalGroupValue() + * version) that returns MapGroupValue builder. + * + * // required group zipMap (MAP) { + * // repeated group map (MAP_KEY_VALUE) { + * // required float key + * // optional int32 value + * // } + * // } + * Types.requiredMap() + * .key(FLOAT) + * .optionalValue(INT32) + * .named("zipMap") + * + * + * // required group zipMap (MAP) { + * // repeated group map (MAP_KEY_VALUE) { + * // required group key { + * // optional int64 first; + * // required group second { + * // required float inner_id_1; + * // optional int32 inner_id_2; + * // } + * // } + * // optional group value { + * // optional group localGeoInfo { + * // required float inner_value_1; + * // optional int32 inner_value_2; + * // } + * // optional int32 zipcode; + * // } + * // } + * // } + * Types.requiredMap() + * .groupKey() + * .optional(INT64).named("id") + * .requiredGroup() + * .required(FLOAT).named("inner_id_1") + * .required(FLOAT).named("inner_id_2") + * .named("second") + * .optionalGroup() + * .optionalGroup() + * .required(FLOAT).named("inner_value_1") + * .optional(INT32).named("inner_value_2") + * .named("localGeoInfo") + * .optional(INT32).named("zipcode") + * .named("zipMap") + * + *
* Message types are built using {@link #buildMessage()} and function just like * group builders. *
@@ -131,7 +190,7 @@ public class Types {
* @param The type that this builder will return from
* {@link #named(String)} when the type is built.
*/
- public abstract static class Builder {
+ public abstract static class Builder {
protected final P parent;
protected final Class extends P> returnClass;
@@ -148,7 +207,6 @@ public abstract static class Builder {
* @param parent a non-null object to return from {@link #named(String)}
*/
protected Builder(P parent) {
- Preconditions.checkNotNull(parent, "Parent cannot be null");
this.parent = parent;
this.returnClass = null;
}
@@ -167,9 +225,9 @@ protected Builder(Class returnClass) {
this.parent = null;
}
- protected abstract T self();
+ protected abstract THIS self();
- protected final T repetition(Type.Repetition repetition) {
+ protected final THIS repetition(Type.Repetition repetition) {
Preconditions.checkArgument(!repetitionAlreadySet,
"Repetition has already been set");
Preconditions.checkNotNull(repetition, "Repetition cannot be null");
@@ -190,7 +248,7 @@ protected final T repetition(Type.Repetition repetition) {
* @param type an {@code OriginalType}
* @return this builder for method chaining
*/
- public T as(OriginalType type) {
+ public THIS as(OriginalType type) {
this.originalType = type;
return self();
}
@@ -203,7 +261,7 @@ public T as(OriginalType type) {
* @param id the id of the field
* @return this builder for method chaining
*/
- public T id(int id) {
+ public THIS id(int id) {
this.id = new ID(id);
return self();
}
@@ -227,27 +285,26 @@ public P named(String name) {
Type type = build(name);
if (parent != null) {
- // if the parent is a GroupBuilder, add type to it
- if (GroupBuilder.class.isAssignableFrom(parent.getClass())) {
- GroupBuilder.class.cast(parent).addField(type);
+ // if the parent is a BaseGroupBuilder, add type to it
+ if (BaseGroupBuilder.class.isAssignableFrom(parent.getClass())) {
+ BaseGroupBuilder.class.cast(parent).addField(type);
}
return parent;
- } else {
+ } else if (returnClass != null) {
// no parent indicates that the Type object should be returned
// the constructor check guarantees that returnClass is a Type
return returnClass.cast(type);
+ } else {
+ throw new IllegalStateException(
+ "[BUG] Parent and return type are null: must override named");
}
}
}
- /**
- * A builder for {@link PrimitiveType} objects.
- *
- * @param
The type that this builder will return from
- * {@link #named(String)} when the type is built.
- */
- public static class PrimitiveBuilder
extends Builder, P> {
+ public abstract static class
+ BasePrimitiveBuilder>
+ extends Builder {
private static final long MAX_PRECISION_INT32 = maxPrecision(4);
private static final long MAX_PRECISION_INT64 = maxPrecision(8);
private final PrimitiveTypeName primitiveType;
@@ -255,20 +312,18 @@ public static class PrimitiveBuilder extends Builder, P>
private int precision = NOT_SET;
private int scale = NOT_SET;
- private PrimitiveBuilder(P parent, PrimitiveTypeName type) {
+ private BasePrimitiveBuilder(P parent, PrimitiveTypeName type) {
super(parent);
this.primitiveType = type;
}
- private PrimitiveBuilder(Class returnType, PrimitiveTypeName type) {
+ private BasePrimitiveBuilder(Class
returnType, PrimitiveTypeName type) {
super(returnType);
this.primitiveType = type;
}
@Override
- protected PrimitiveBuilder
self() {
- return this;
- }
+ protected abstract THIS self();
/**
* Adds the length for a FIXED_LEN_BYTE_ARRAY.
@@ -276,7 +331,7 @@ protected PrimitiveBuilder
self() {
* @param length an int length
* @return this builder for method chaining
*/
- public PrimitiveBuilder
length(int length) {
+ public BasePrimitiveBuilder
length(int length) {
this.length = length;
return this;
}
@@ -291,7 +346,7 @@ public PrimitiveBuilder
length(int length) {
* @param precision an int precision value for the DECIMAL
* @return this builder for method chaining
*/
- public PrimitiveBuilder
precision(int precision) {
+ public BasePrimitiveBuilder
precision(int precision) {
this.precision = precision;
return this;
}
@@ -309,7 +364,7 @@ public PrimitiveBuilder
precision(int precision) {
* @param scale an int scale value for the DECIMAL
* @return this builder for method chaining
*/
- public PrimitiveBuilder
scale(int scale) {
+ public BasePrimitiveBuilder
scale(int scale) {
this.scale = scale;
return this;
}
@@ -418,32 +473,47 @@ protected DecimalMetadata decimalMetadata() {
}
/**
- * A builder for {@link GroupType} objects.
+ * A builder for {@link PrimitiveType} objects.
*
* @param
The type that this builder will return from
* {@link #named(String)} when the type is built.
*/
- public static class GroupBuilder
extends Builder, P> {
+ public static class PrimitiveBuilder extends BasePrimitiveBuilder
> {
+
+ private PrimitiveBuilder(P parent, PrimitiveTypeName type) {
+ super(parent, type);
+ }
+
+ private PrimitiveBuilder(Class
returnType, PrimitiveTypeName type) {
+ super(returnType, type);
+ }
+
+ @Override
+ protected PrimitiveBuilder
self() {
+ return this;
+ }
+ }
+
+ public abstract static class BaseGroupBuilder
>
+ extends Builder {
protected final List fields;
- private GroupBuilder(P parent) {
+ private BaseGroupBuilder(P parent) {
super(parent);
this.fields = new ArrayList();
}
- private GroupBuilder(Class returnType) {
+ private BaseGroupBuilder(Class
returnType) {
super(returnType);
this.fields = new ArrayList();
}
@Override
- protected GroupBuilder self() {
- return this;
- }
+ protected abstract THIS self();
- public PrimitiveBuilder> primitive(
+ public PrimitiveBuilder primitive(
PrimitiveTypeName type, Type.Repetition repetition) {
- return new PrimitiveBuilder>(this, type)
+ return new PrimitiveBuilder (self(), type)
.repetition(repetition);
}
@@ -455,9 +525,9 @@ public PrimitiveBuilder> primitive(
* @return a primitive builder for {@code type} that will return this
* builder for additional fields.
*/
- public PrimitiveBuilder> required(
+ public PrimitiveBuilder required(
PrimitiveTypeName type) {
- return new PrimitiveBuilder>(this, type)
+ return new PrimitiveBuilder(self(), type)
.repetition(Type.Repetition.REQUIRED);
}
@@ -469,9 +539,9 @@ public PrimitiveBuilder> required(
* @return a primitive builder for {@code type} that will return this
* builder for additional fields.
*/
- public PrimitiveBuilder> optional(
+ public PrimitiveBuilder optional(
PrimitiveTypeName type) {
- return new PrimitiveBuilder>(this, type)
+ return new PrimitiveBuilder(self(), type)
.repetition(Type.Repetition.OPTIONAL);
}
@@ -483,14 +553,14 @@ public PrimitiveBuilder> optional(
* @return a primitive builder for {@code type} that will return this
* builder for additional fields.
*/
- public PrimitiveBuilder> repeated(
+ public PrimitiveBuilder repeated(
PrimitiveTypeName type) {
- return new PrimitiveBuilder>(this, type)
+ return new PrimitiveBuilder(self(), type)
.repetition(Type.Repetition.REPEATED);
}
- public GroupBuilder> group(Type.Repetition repetition) {
- return new GroupBuilder>(this)
+ public GroupBuilder group(Type.Repetition repetition) {
+ return new GroupBuilder(self())
.repetition(repetition);
}
@@ -500,8 +570,8 @@ public GroupBuilder> group(Type.Repetition repetition) {
* @return a group builder that will return this builder for additional
* fields.
*/
- public GroupBuilder> requiredGroup() {
- return new GroupBuilder>(this)
+ public GroupBuilder requiredGroup() {
+ return new GroupBuilder(self())
.repetition(Type.Repetition.REQUIRED);
}
@@ -511,8 +581,8 @@ public GroupBuilder> requiredGroup() {
* @return a group builder that will return this builder for additional
* fields.
*/
- public GroupBuilder> optionalGroup() {
- return new GroupBuilder>(this)
+ public GroupBuilder optionalGroup() {
+ return new GroupBuilder(self())
.repetition(Type.Repetition.OPTIONAL);
}
@@ -522,8 +592,8 @@ public GroupBuilder> optionalGroup() {
* @return a group builder that will return this builder for additional
* fields.
*/
- public GroupBuilder> repeatedGroup() {
- return new GroupBuilder>(this)
+ public GroupBuilder repeatedGroup() {
+ return new GroupBuilder(self())
.repetition(Type.Repetition.REPEATED);
}
@@ -532,9 +602,9 @@ public GroupBuilder> repeatedGroup() {
*
* @return this builder for additional fields.
*/
- public GroupBuilder addField(Type type) {
+ public THIS addField(Type type) {
fields.add(type);
- return this;
+ return self();
}
/**
@@ -542,11 +612,9 @@ public GroupBuilder
addField(Type type) {
*
* @return this builder for additional fields.
*/
- public GroupBuilder
addFields(Type... types) {
- for (Type type : types) {
- fields.add(type);
- }
- return this;
+ public THIS addFields(Type... types) {
+ Collections.addAll(fields, types);
+ return self();
}
@Override
@@ -555,6 +623,616 @@ protected GroupType build(String name) {
"Cannot build an empty group");
return new GroupType(repetition, name, originalType, fields, id);
}
+
+ public MapBuilder map(
+ Type.Repetition repetition) {
+ return new MapBuilder(self()).repetition(repetition);
+ }
+
+ public MapBuilder requiredMap() {
+ return new MapBuilder(self())
+ .repetition(Type.Repetition.REQUIRED);
+ }
+
+ public MapBuilder optionalMap() {
+ return new MapBuilder(self())
+ .repetition(Type.Repetition.OPTIONAL);
+ }
+
+ public ListBuilder list(Type.Repetition repetition) {
+ return new ListBuilder(self()).repetition(repetition);
+ }
+
+ public ListBuilder requiredList() {
+ return list(Type.Repetition.REQUIRED);
+ }
+
+ public ListBuilder optionalList() {
+ return list(Type.Repetition.OPTIONAL);
+ }
+ }
+
+ /**
+ * A builder for {@link GroupType} objects.
+ *
+ * @param The type that this builder will return from
+ * {@link #named(String)} when the type is built.
+ */
+ public static class GroupBuilder
extends BaseGroupBuilder
> {
+
+ private GroupBuilder(P parent) {
+ super(parent);
+ }
+
+ private GroupBuilder(Class
returnType) {
+ super(returnType);
+ }
+
+ @Override
+ protected GroupBuilder
self() {
+ return this;
+ }
+ }
+
+ public abstract static class BaseMapBuilder
>
+ extends Builder {
+ private static final Type STRING_KEY = Types
+ .required(PrimitiveTypeName.BINARY).as(OriginalType.UTF8).named("key");
+
+ public static class KeyBuilder> extends
+ BasePrimitiveBuilder> {
+ private final M mapBuilder;
+
+ public KeyBuilder(M mapBuilder, PrimitiveTypeName type) {
+ super(mapBuilder.parent, type);
+ this.mapBuilder = mapBuilder;
+ repetition(Type.Repetition.REQUIRED);
+ }
+
+ public ValueBuilder value(PrimitiveTypeName type,
+ Type.Repetition repetition) {
+ mapBuilder.setKeyType(build("key"));
+ return new ValueBuilder(mapBuilder, type).repetition(repetition);
+ }
+
+ public ValueBuilder requiredValue(PrimitiveTypeName type) {
+ return value(type, Type.Repetition.REQUIRED);
+ }
+
+ public ValueBuilder optionalValue(PrimitiveTypeName type) {
+ return value(type, Type.Repetition.OPTIONAL);
+ }
+
+ public GroupValueBuilder groupValue(Type.Repetition repetition) {
+ mapBuilder.setKeyType(build("key"));
+ return new GroupValueBuilder(mapBuilder).repetition(repetition);
+ }
+
+ public GroupValueBuilder requiredGroupValue() {
+ return groupValue(Type.Repetition.REQUIRED);
+ }
+
+ public GroupValueBuilder optionalGroupValue() {
+ return groupValue(Type.Repetition.OPTIONAL);
+ }
+
+ public MapValueBuilder mapValue(Type.Repetition repetition) {
+ mapBuilder.setKeyType(build("key"));
+ return new MapValueBuilder(mapBuilder).repetition(repetition);
+ }
+
+ public MapValueBuilder requiredMapValue() {
+ return mapValue(Type.Repetition.REQUIRED);
+ }
+
+ public MapValueBuilder optionalMapValue() {
+ return mapValue(Type.Repetition.OPTIONAL);
+ }
+
+ public ListValueBuilder listValue(Type.Repetition repetition) {
+ mapBuilder.setKeyType(build("key"));
+ return new ListValueBuilder(mapBuilder).repetition(repetition);
+ }
+
+ public ListValueBuilder requiredListValue() {
+ return listValue(Type.Repetition.REQUIRED);
+ }
+
+ public ListValueBuilder optionalListValue() {
+ return listValue(Type.Repetition.OPTIONAL);
+ }
+
+ public M value(Type type) {
+ mapBuilder.setKeyType(build("key"));
+ mapBuilder.setValueType(type);
+ return this.mapBuilder;
+ }
+
+ @Override
+ public MP named(String name) {
+ mapBuilder.setKeyType(build("key"));
+ return mapBuilder.named(name);
+ }
+
+ @Override
+ protected KeyBuilder self() {
+ return this;
+ }
+ }
+
+ public static class ValueBuilder>
+ extends BasePrimitiveBuilder> {
+ private final M mapBuilder;
+
+ public ValueBuilder(M mapBuilder, PrimitiveTypeName type) {
+ super(mapBuilder.parent, type);
+ this.mapBuilder = mapBuilder;
+ }
+
+ public MP named(String name) {
+ mapBuilder.setValueType(build("value"));
+ return mapBuilder.named(name);
+ }
+
+ @Override
+ protected ValueBuilder self() {
+ return this;
+ }
+ }
+
+ public static class GroupKeyBuilder>
+ extends BaseGroupBuilder> {
+ private final M mapBuilder;
+
+ public GroupKeyBuilder(M mapBuilder) {
+ super(mapBuilder.parent);
+ this.mapBuilder = mapBuilder;
+ repetition(Type.Repetition.REQUIRED);
+ }
+
+ @Override
+ protected GroupKeyBuilder self() {
+ return this;
+ }
+
+ public ValueBuilder value(PrimitiveTypeName type,
+ Type.Repetition repetition) {
+ mapBuilder.setKeyType(build("key"));
+ return new ValueBuilder(mapBuilder, type).repetition(repetition);
+ }
+
+ public ValueBuilder requiredValue(PrimitiveTypeName type) {
+ return value(type, Type.Repetition.REQUIRED);
+ }
+
+ public ValueBuilder optionalValue(PrimitiveTypeName type) {
+ return value(type, Type.Repetition.OPTIONAL);
+ }
+
+ public GroupValueBuilder groupValue(Type.Repetition repetition) {
+ mapBuilder.setKeyType(build("key"));
+ return new GroupValueBuilder(mapBuilder).repetition(repetition);
+ }
+
+ public GroupValueBuilder requiredGroupValue() {
+ return groupValue(Type.Repetition.REQUIRED);
+ }
+
+ public GroupValueBuilder optionalGroupValue() {
+ return groupValue(Type.Repetition.OPTIONAL);
+ }
+
+ public MapValueBuilder mapValue(Type.Repetition repetition) {
+ mapBuilder.setKeyType(build("key"));
+ return new MapValueBuilder(mapBuilder).repetition(repetition);
+ }
+
+ public MapValueBuilder requiredMapValue() {
+ return mapValue(Type.Repetition.REQUIRED);
+ }
+
+ public MapValueBuilder optionalMapValue() {
+ return mapValue(Type.Repetition.OPTIONAL);
+ }
+
+ public ListValueBuilder listValue(Type.Repetition repetition) {
+ mapBuilder.setKeyType(build("key"));
+ return new ListValueBuilder(mapBuilder).repetition(repetition);
+ }
+
+ public ListValueBuilder requiredListValue() {
+ return listValue(Type.Repetition.REQUIRED);
+ }
+
+ public ListValueBuilder optionalListValue() {
+ return listValue(Type.Repetition.OPTIONAL);
+ }
+
+ public M value(Type type) {
+ mapBuilder.setKeyType(build("key"));
+ mapBuilder.setValueType(type);
+ return this.mapBuilder;
+ }
+
+ @Override
+ public MP named(String name) {
+ mapBuilder.setKeyType(build("key"));
+ return mapBuilder.named(name);
+ }
+ }
+
+ public static class GroupValueBuilder>
+ extends BaseGroupBuilder> {
+ private final M mapBuilder;
+
+ public GroupValueBuilder(M mapBuilder) {
+ super(mapBuilder.parent);
+ this.mapBuilder = mapBuilder;
+ }
+
+ public MP named(String name) {
+ mapBuilder.setValueType(build("value"));
+ return mapBuilder.named(name);
+ }
+
+ @Override
+ protected GroupValueBuilder self() {
+ return this;
+ }
+ }
+
+ public static class MapValueBuilder>
+ extends BaseMapBuilder> {
+ private final M mapBuilder;
+
+ public MapValueBuilder(M mapBuilder) {
+ super(mapBuilder.parent);
+ this.mapBuilder = mapBuilder;
+ }
+
+ public MP named(String name) {
+ mapBuilder.setValueType(build("value"));
+ return mapBuilder.named(name);
+ }
+
+ @Override
+ protected MapValueBuilder self() {
+ return this;
+ }
+ }
+
+ public static class ListValueBuilder>
+ extends BaseListBuilder> {
+ private final M mapBuilder;
+
+ public ListValueBuilder(M mapBuilder) {
+ super(mapBuilder.parent);
+ this.mapBuilder = mapBuilder;
+ }
+
+ public MP named(String name) {
+ mapBuilder.setValueType(build("value"));
+ return mapBuilder.named(name);
+ }
+
+ @Override
+ protected ListValueBuilder self() {
+ return this;
+ }
+ }
+
+ protected void setKeyType(Type keyType) {
+ Preconditions.checkState(this.keyType == null,
+ "Only one key type can be built with a MapBuilder");
+ this.keyType = keyType;
+ }
+
+ protected void setValueType(Type valueType) {
+ Preconditions.checkState(this.valueType == null,
+ "Only one key type can be built with a ValueBuilder");
+ this.valueType = valueType;
+ }
+
+ private Type keyType = null;
+ private Type valueType = null;
+
+ public BaseMapBuilder(P parent) {
+ super(parent);
+ }
+
+ private BaseMapBuilder(Class returnType) {
+ super(returnType);
+ }
+
+ @Override
+ protected abstract THIS self();
+
+ public KeyBuilder
key(PrimitiveTypeName type) {
+ return new KeyBuilder
(self(), type);
+ }
+
+ public THIS key(Type type) {
+ setKeyType(type);
+ return self();
+ }
+
+ public GroupKeyBuilder
groupKey() {
+ return new GroupKeyBuilder
(self());
+ }
+
+ public ValueBuilder
value(PrimitiveTypeName type,
+ Type.Repetition repetition) {
+ return new ValueBuilder
(self(), type).repetition(repetition);
+ }
+
+ public ValueBuilder
requiredValue(PrimitiveTypeName type) {
+ return value(type, Type.Repetition.REQUIRED);
+ }
+
+ public ValueBuilder
optionalValue(PrimitiveTypeName type) {
+ return value(type, Type.Repetition.OPTIONAL);
+ }
+
+ public GroupValueBuilder
groupValue(Type.Repetition repetition) {
+ return new GroupValueBuilder
(self()).repetition(repetition);
+ }
+
+ public GroupValueBuilder
requiredGroupValue() {
+ return groupValue(Type.Repetition.REQUIRED);
+ }
+
+ public GroupValueBuilder
optionalGroupValue() {
+ return groupValue(Type.Repetition.OPTIONAL);
+ }
+
+ public MapValueBuilder
mapValue(Type.Repetition repetition) {
+ return new MapValueBuilder
(self()).repetition(repetition);
+ }
+
+ public MapValueBuilder
requiredMapValue() {
+ return mapValue(Type.Repetition.REQUIRED);
+ }
+
+ public MapValueBuilder
optionalMapValue() {
+ return mapValue(Type.Repetition.OPTIONAL);
+ }
+
+ public ListValueBuilder
listValue(Type.Repetition repetition) {
+ return new ListValueBuilder
(self()).repetition(repetition);
+ }
+
+ public ListValueBuilder
requiredListValue() {
+ return listValue(Type.Repetition.REQUIRED);
+ }
+
+ public ListValueBuilder
optionalListValue() {
+ return listValue(Type.Repetition.OPTIONAL);
+ }
+
+ public THIS value(Type type) {
+ setValueType(type);
+ return self();
+ }
+
+ @Override
+ protected Type build(String name) {
+ Preconditions.checkState(originalType == null,
+ "MAP is already a logical type and can't be changed.");
+ if (keyType == null) {
+ keyType = STRING_KEY;
+ }
+ if (valueType != null) {
+ return buildGroup(repetition).as(OriginalType.MAP)
+ .repeatedGroup().addFields(keyType, valueType).named("map")
+ .named(name);
+ } else {
+ return buildGroup(repetition).as(OriginalType.MAP)
+ .repeatedGroup().addFields(keyType).named("map")
+ .named(name);
+ }
+ }
+ }
+
+ public static class MapBuilder
extends BaseMapBuilder
> {
+ public MapBuilder(P parent) {
+ super(parent);
+ }
+
+ private MapBuilder(Class
returnType) {
+ super(returnType);
+ }
+
+ @Override
+ protected MapBuilder
self() {
+ return this;
+ }
+ }
+
+ public abstract static class BaseListBuilder
>
+ extends Builder {
+ private Type elementType = null;
+ private P parent;
+
+ public BaseListBuilder(P parent) {
+ super(parent);
+ this.parent = parent;
+ }
+
+ public BaseListBuilder(Class returnType) {
+ super(returnType);
+ }
+
+ public void setElementType(Type elementType) {
+ Preconditions.checkState(this.elementType == null,
+ "Only one element can be built with a ListBuilder");
+ this.elementType = elementType;
+ }
+
+ public static class ElementBuilder>
+ extends BasePrimitiveBuilder> {
+ private final BaseListBuilder listBuilder;
+
+ public ElementBuilder(L listBuilder, PrimitiveTypeName type) {
+ super(((BaseListBuilder) listBuilder).parent, type);
+ this.listBuilder = listBuilder;
+ }
+
+ public LP named(String name) {
+ listBuilder.setElementType(build("element"));
+ return listBuilder.named(name);
+ }
+
+ @Override
+ protected ElementBuilder self() {
+ return this;
+ }
+ }
+
+ public static class GroupElementBuilder>
+ extends BaseGroupBuilder> {
+ private final L listBuilder;
+
+ public GroupElementBuilder(L listBuilder) {
+ super(((BaseListBuilder) listBuilder).parent);
+ this.listBuilder = listBuilder;
+ }
+
+ public LP named(String name) {
+ listBuilder.setElementType(build("element"));
+ return listBuilder.named(name);
+ }
+
+ @Override
+ protected GroupElementBuilder self() {
+ return this;
+ }
+ }
+
+ public static class MapElementBuilder>
+ extends BaseMapBuilder> {
+
+ private final L listBuilder;
+
+ public MapElementBuilder(L listBuilder) {
+ super(((BaseListBuilder) listBuilder).parent);
+ this.listBuilder = listBuilder;
+ }
+
+ @Override
+ protected MapElementBuilder self() {
+ return this;
+ }
+
+ @Override
+ public LP named(String name) {
+ listBuilder.setElementType(build("element"));
+ return listBuilder.named(name);
+ }
+ }
+
+ public static class ListElementBuilder>
+ extends BaseListBuilder> {
+
+ private final L listBuilder;
+
+ public ListElementBuilder(L listBuilder) {
+ super(((BaseListBuilder) listBuilder).parent);
+ this.listBuilder = listBuilder;
+ }
+
+ @Override
+ protected ListElementBuilder self() {
+ return this;
+ }
+
+ @Override
+ public LP named(String name) {
+ listBuilder.setElementType(build("element"));
+ return listBuilder.named(name);
+ }
+ }
+
+ @Override
+ protected abstract THIS self();
+
+ @Override
+ protected Type build(String name) {
+ Preconditions.checkState(originalType == null,
+ "LIST is already the logical type and can't be changed");
+ Preconditions.checkNotNull(elementType, "List element type");
+ return buildGroup(repetition).as(OriginalType.LIST)
+ .repeatedGroup().addFields(elementType).named("list")
+ .named(name);
+ }
+
+ public ElementBuilder element(PrimitiveTypeName type,
+ Type.Repetition repetition) {
+ return new ElementBuilder
(self(), type).repetition(repetition);
+ }
+
+ public ElementBuilder
requiredElement(PrimitiveTypeName type) {
+ return element(type, Type.Repetition.REQUIRED);
+ }
+
+ public ElementBuilder
optionalElement(PrimitiveTypeName type) {
+ return element(type, Type.Repetition.OPTIONAL);
+ }
+
+ public GroupElementBuilder
groupElement(Type.Repetition repetition) {
+ return new GroupElementBuilder
(self()).repetition(repetition);
+ }
+
+ public GroupElementBuilder
requiredGroupElement() {
+ return groupElement(Type.Repetition.REQUIRED);
+ }
+
+ public GroupElementBuilder
optionalGroupElement() {
+ return groupElement(Type.Repetition.OPTIONAL);
+ }
+
+ public MapElementBuilder
mapElement(Type.Repetition repetition) {
+ return new MapElementBuilder
(self()).repetition(repetition);
+ }
+
+ public MapElementBuilder
requiredMapElement() {
+ return mapElement(Type.Repetition.REQUIRED);
+ }
+
+ public MapElementBuilder
optionalMapElement() {
+ return mapElement(Type.Repetition.OPTIONAL);
+ }
+
+ public ListElementBuilder
listElement(Type.Repetition repetition) {
+ return new ListElementBuilder
(self()).repetition(repetition);
+ }
+
+ public ListElementBuilder
requiredListElement() {
+ return listElement(Type.Repetition.REQUIRED);
+ }
+
+ public ListElementBuilder
optionalListElement() {
+ return listElement(Type.Repetition.OPTIONAL);
+ }
+
+ public BaseListBuilder
element(Type type) {
+ setElementType(type);
+ return self();
+ }
+ }
+
+ public static class ListBuilder
extends BaseListBuilder
> {
+ public ListBuilder(P parent) {
+ super(parent);
+ }
+
+ public ListBuilder(Class
returnType) {
+ super(returnType);
+ }
+
+ @Override
+ protected ListBuilder
self() {
+ return this;
+ }
}
public static class MessageTypeBuilder extends GroupBuilder {
@@ -588,6 +1266,45 @@ public static MessageTypeBuilder buildMessage() {
return new MessageTypeBuilder();
}
+ public static PrimitiveBuilder primitive(PrimitiveTypeName type,
+ Type.Repetition repetition) {
+ return new PrimitiveBuilder(PrimitiveType.class, type)
+ .repetition(repetition);
+ }
+
+ /**
+ * Returns a builder to construct a required {@link PrimitiveType}.
+ *
+ * @param type a {@link PrimitiveTypeName} for the constructed type
+ * @return a {@link PrimitiveBuilder}
+ */
+ public static PrimitiveBuilder required(PrimitiveTypeName type) {
+ return new PrimitiveBuilder(PrimitiveType.class, type)
+ .repetition(Type.Repetition.REQUIRED);
+ }
+
+ /**
+ * Returns a builder to construct an optional {@link PrimitiveType}.
+ *
+ * @param type a {@link PrimitiveTypeName} for the constructed type
+ * @return a {@link PrimitiveBuilder}
+ */
+ public static PrimitiveBuilder optional(PrimitiveTypeName type) {
+ return new PrimitiveBuilder(PrimitiveType.class, type)
+ .repetition(Type.Repetition.OPTIONAL);
+ }
+
+ /**
+ * Returns a builder to construct a repeated {@link PrimitiveType}.
+ *
+ * @param type a {@link PrimitiveTypeName} for the constructed type
+ * @return a {@link PrimitiveBuilder}
+ */
+ public static PrimitiveBuilder repeated(PrimitiveTypeName type) {
+ return new PrimitiveBuilder(PrimitiveType.class, type)
+ .repetition(Type.Repetition.REPEATED);
+ }
+
public static GroupBuilder buildGroup(
Type.Repetition repetition) {
return new GroupBuilder(GroupType.class).repetition(repetition);
@@ -623,46 +1340,29 @@ public static GroupBuilder repeatedGroup() {
.repetition(Type.Repetition.REPEATED);
}
- public static PrimitiveBuilder primitive(
- PrimitiveTypeName type, Type.Repetition repetition) {
- return new PrimitiveBuilder(PrimitiveType.class, type)
- .repetition(repetition);
+
+ public static MapBuilder map(Type.Repetition repetition) {
+ return new MapBuilder(GroupType.class).repetition(repetition);
}
- /**
- * Returns a builder to construct a required {@link PrimitiveType}.
- *
- * @param type a {@link PrimitiveTypeName} for the constructed type
- * @return a {@link PrimitiveBuilder}
- */
- public static PrimitiveBuilder required(
- PrimitiveTypeName type) {
- return new PrimitiveBuilder(PrimitiveType.class, type)
- .repetition(Type.Repetition.REQUIRED);
+ public static MapBuilder requiredMap() {
+ return map(Type.Repetition.REQUIRED);
}
- /**
- * Returns a builder to construct an optional {@link PrimitiveType}.
- *
- * @param type a {@link PrimitiveTypeName} for the constructed type
- * @return a {@link PrimitiveBuilder}
- */
- public static PrimitiveBuilder optional(
- PrimitiveTypeName type) {
- return new PrimitiveBuilder(PrimitiveType.class, type)
- .repetition(Type.Repetition.OPTIONAL);
+ public static MapBuilder optionalMap() {
+ return map(Type.Repetition.OPTIONAL);
}
- /**
- * Returns a builder to construct a repeated {@link PrimitiveType}.
- *
- * @param type a {@link PrimitiveTypeName} for the constructed type
- * @return a {@link PrimitiveBuilder}
- */
- public static PrimitiveBuilder repeated(
- PrimitiveTypeName type) {
- return new PrimitiveBuilder(PrimitiveType.class, type)
- .repetition(Type.Repetition.REPEATED);
+ public static ListBuilder list(Type.Repetition repetition) {
+ return new ListBuilder(GroupType.class).repetition(repetition);
+ }
+
+ public static ListBuilder requiredList() {
+ return list(Type.Repetition.REQUIRED);
+ }
+
+ public static ListBuilder optionalList() {
+ return list(Type.Repetition.OPTIONAL);
}
}
diff --git a/parquet-column/src/test/java/org/apache/parquet/schema/TestTypeBuilders.java b/parquet-column/src/test/java/org/apache/parquet/schema/TestTypeBuilders.java
index bdf7429e02..4230561e93 100644
--- a/parquet-column/src/test/java/org/apache/parquet/schema/TestTypeBuilders.java
+++ b/parquet-column/src/test/java/org/apache/parquet/schema/TestTypeBuilders.java
@@ -18,6 +18,8 @@
*/
package org.apache.parquet.schema;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.Callable;
import org.junit.Assert;
import org.junit.Ignore;
@@ -599,6 +601,773 @@ public Type call() throws Exception {
});
}
+ @Test
+ public void testRequiredMap() {
+ List typeList = new ArrayList();
+ typeList.add(new PrimitiveType(REQUIRED, INT64, "key"));
+ typeList.add(new PrimitiveType(REQUIRED, INT64, "value"));
+ GroupType expected = new GroupType(REQUIRED, "myMap", OriginalType.MAP, new GroupType(REPEATED,
+ "map",
+ typeList));
+ GroupType actual = Types.requiredMap()
+ .key(INT64)
+ .requiredValue(INT64)
+ .named("myMap");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testOptionalMap() {
+ List typeList = new ArrayList();
+ typeList.add(new PrimitiveType(REQUIRED, INT64, "key"));
+ typeList.add(new PrimitiveType(REQUIRED, INT64, "value"));
+ GroupType expected = new GroupType(OPTIONAL, "myMap", OriginalType.MAP, new GroupType(REPEATED,
+ "map",
+ typeList));
+ GroupType actual = Types.optionalMap()
+ .key(INT64)
+ .requiredValue(INT64)
+ .named("myMap");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testMapWithRequiredValue() {
+ List typeList = new ArrayList();
+ typeList.add(new PrimitiveType(REQUIRED, INT64, "key"));
+ typeList.add(new PrimitiveType(REQUIRED, INT64, "value"));
+ GroupType map = new GroupType(REQUIRED, "myMap", OriginalType.MAP, new GroupType(REPEATED, "map",
+ typeList));
+ MessageType expected = new MessageType("mapParent", map);
+ GroupType actual = Types.buildMessage().requiredMap()
+ .key(INT64)
+ .requiredValue(INT64)
+ .named("myMap").named("mapParent");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testMapWithOptionalValue() {
+ List typeList = new ArrayList();
+ typeList.add(new PrimitiveType(REQUIRED, INT64, "key"));
+ typeList.add(new PrimitiveType(OPTIONAL, INT64, "value"));
+ GroupType map = new GroupType(REQUIRED, "myMap", OriginalType.MAP, new GroupType(REPEATED, "map",
+ typeList));
+ MessageType expected = new MessageType("mapParent", map);
+ GroupType actual = Types.buildMessage().requiredMap()
+ .key(INT64)
+ .optionalValue(INT64)
+ .named("myMap").named("mapParent");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testMapWithGroupKeyAndOptionalGroupValue() {
+ List typeList = new ArrayList();
+
+ List keyFields = new ArrayList();
+ keyFields.add(new PrimitiveType(OPTIONAL, INT64, "first"));
+ keyFields.add(new PrimitiveType(OPTIONAL, DOUBLE, "second"));
+ typeList.add(new GroupType(REQUIRED, "key", keyFields));
+
+ List valueFields = new ArrayList();
+ valueFields.add(new PrimitiveType(OPTIONAL, DOUBLE, "one"));
+ valueFields.add(new PrimitiveType(OPTIONAL, INT32, "two"));
+ typeList.add(new GroupType(OPTIONAL, "value", valueFields));
+
+ GroupType map = new GroupType(OPTIONAL, "myMap", OriginalType.MAP, new GroupType(REPEATED, "map",
+ typeList));
+
+ GroupType actual = Types.optionalMap()
+ .groupKey()
+ .optional(INT64).named("first")
+ .optional(DOUBLE).named("second")
+ .optionalGroupValue()
+ .optional(DOUBLE).named("one")
+ .optional(INT32).named("two")
+ .named("myMap");
+ Assert.assertEquals(map, actual);
+ }
+
+ @Test
+ public void testMapWithGroupKeyAndRequiredGroupValue() {
+ List typeList = new ArrayList();
+
+ List keyFields = new ArrayList();
+ keyFields.add(new PrimitiveType(OPTIONAL, INT64, "first"));
+ keyFields.add(new PrimitiveType(OPTIONAL, DOUBLE, "second"));
+ typeList.add(new GroupType(REQUIRED, "key", keyFields));
+
+ List valueFields = new ArrayList();
+ valueFields.add(new PrimitiveType(OPTIONAL, DOUBLE, "one"));
+ valueFields.add(new PrimitiveType(OPTIONAL, INT32, "two"));
+ typeList.add(new GroupType(REQUIRED, "value", valueFields));
+
+ GroupType map = new GroupType(OPTIONAL, "myMap", OriginalType.MAP, new GroupType(REPEATED, "map",
+ typeList));
+
+ MessageType expected = new MessageType("mapParent", map);
+ GroupType actual =
+ Types.buildMessage()
+ .optionalMap()
+ .groupKey()
+ .optional(INT64).named("first")
+ .optional(DOUBLE).named("second")
+ .requiredGroupValue()
+ .optional(DOUBLE).named("one")
+ .optional(INT32).named("two")
+ .named("myMap")
+ .named("mapParent");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testMapWithGroupKeyAndOptionalValue() {
+ List typeList = new ArrayList();
+
+ List keyFields = new ArrayList();
+ keyFields.add(new PrimitiveType(OPTIONAL, INT64, "first"));
+ keyFields.add(new PrimitiveType(OPTIONAL, DOUBLE, "second"));
+ typeList.add(new GroupType(REQUIRED, "key", keyFields));
+
+ typeList.add(new PrimitiveType(OPTIONAL, DOUBLE, "value"));
+
+ GroupType map = new GroupType(OPTIONAL, "myMap", OriginalType.MAP, new GroupType(REPEATED, "map",
+ typeList));
+
+ MessageType expected = new MessageType("mapParent", map);
+ GroupType actual =
+ Types.buildMessage()
+ .optionalMap()
+ .groupKey()
+ .optional(INT64).named("first")
+ .optional(DOUBLE).named("second")
+ .optionalValue(DOUBLE).named("myMap")
+ .named("mapParent");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testMapWithGroupKeyAndRequiredValue() {
+ List typeList = new ArrayList();
+
+ List keyFields = new ArrayList();
+ keyFields.add(new PrimitiveType(OPTIONAL, INT64, "first"));
+ keyFields.add(new PrimitiveType(OPTIONAL, DOUBLE, "second"));
+ typeList.add(new GroupType(REQUIRED, "key", keyFields));
+
+ typeList.add(new PrimitiveType(REQUIRED, DOUBLE, "value"));
+
+ GroupType map = new GroupType(OPTIONAL, "myMap", OriginalType.MAP, new GroupType(REPEATED, "map",
+ typeList));
+
+ MessageType expected = new MessageType("mapParent", map);
+ GroupType actual =
+ Types.buildMessage()
+ .optionalMap()
+ .groupKey()
+ .optional(INT64).named("first")
+ .optional(DOUBLE).named("second")
+ .requiredValue(DOUBLE).named("myMap")
+ .named("mapParent");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testMapWithOptionalGroupValue() {
+ List typeList = new ArrayList();
+
+ List keyFields = new ArrayList();
+ keyFields.add(new PrimitiveType(OPTIONAL, INT64, "first"));
+ keyFields.add(new PrimitiveType(OPTIONAL, DOUBLE, "second"));
+ typeList.add(new PrimitiveType(REQUIRED, INT64, "key"));
+
+ List valueFields = new ArrayList();
+ valueFields.add(new PrimitiveType(OPTIONAL, DOUBLE, "one"));
+ valueFields.add(new PrimitiveType(OPTIONAL, INT32, "two"));
+ typeList.add(new GroupType(OPTIONAL, "value", valueFields));
+
+ GroupType map = new GroupType(OPTIONAL, "myMap", OriginalType.MAP, new GroupType(REPEATED, "map",
+ typeList));
+
+ MessageType expected = new MessageType("mapParent", map);
+ GroupType actual =
+ Types.buildMessage()
+ .optionalMap()
+ .key(INT64)
+ .optionalGroupValue()
+ .optional(DOUBLE).named("one")
+ .optional(INT32).named("two")
+ .named("myMap")
+ .named("mapParent");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testMapWithRequiredGroupValue() {
+ List typeList = new ArrayList();
+
+ typeList.add(new PrimitiveType(REQUIRED, INT64, "key"));
+
+ List valueFields = new ArrayList();
+ valueFields.add(new PrimitiveType(OPTIONAL, DOUBLE, "one"));
+ valueFields.add(new PrimitiveType(OPTIONAL, INT32, "two"));
+ typeList.add(new GroupType(REQUIRED, "value", valueFields));
+
+ GroupType map = new GroupType(OPTIONAL, "myMap", OriginalType.MAP, new GroupType(REPEATED, "map",
+ typeList));
+
+ MessageType expected = new MessageType("mapParent", map);
+ GroupType actual =
+ Types.buildMessage()
+ .optionalMap()
+ .key(INT64)
+ .requiredGroupValue()
+ .optional(DOUBLE).named("one")
+ .optional(INT32).named("two")
+ .named("myMap")
+ .named("mapParent");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testMapWithNestedGroupKeyAndNestedGroupValue() {
+ List typeList = new ArrayList();
+
+ List innerFields = new ArrayList();
+ innerFields.add(new PrimitiveType(REQUIRED, FLOAT, "inner_key_1"));
+ innerFields.add(new PrimitiveType(OPTIONAL, INT32, "inner_key_2"));
+
+ List keyFields = new ArrayList();
+ keyFields.add(new PrimitiveType(OPTIONAL, INT64, "first"));
+ keyFields.add(new GroupType(REQUIRED, "second", innerFields));
+ typeList.add(new GroupType(REQUIRED, "key", keyFields));
+
+ List valueFields = new ArrayList();
+ valueFields.add(new GroupType(OPTIONAL, "one", innerFields));
+ valueFields.add(new PrimitiveType(OPTIONAL, INT32, "two"));
+ typeList.add(new GroupType(OPTIONAL, "value", valueFields));
+
+ GroupType map = new GroupType(REQUIRED, "myMap", OriginalType.MAP, new GroupType(REPEATED, "map",
+ typeList));
+
+ MessageType expected = new MessageType("mapParent", map);
+ GroupType actual =
+ Types.buildMessage()
+ .requiredMap()
+ .groupKey()
+ .optional(INT64).named("first")
+ .requiredGroup()
+ .required(FLOAT).named("inner_key_1")
+ .optional(INT32).named("inner_key_2")
+ .named("second")
+ .optionalGroupValue()
+ .optionalGroup()
+ .required(FLOAT).named("inner_key_1")
+ .optional(INT32).named("inner_key_2")
+ .named("one")
+ .optional(INT32).named("two")
+ .named("myMap")
+ .named("mapParent");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testMapWithRequiredListValue() {
+ List typeList = new ArrayList();
+
+ typeList.add(new PrimitiveType(REQUIRED, INT64, "key"));
+ typeList.add(new GroupType(REQUIRED, "value", OriginalType.LIST,
+ new GroupType(REPEATED,
+ "list",
+ new PrimitiveType(OPTIONAL, INT64, "element"))));
+
+ GroupType map = new GroupType(OPTIONAL, "myMap", OriginalType.MAP, new GroupType(REPEATED, "map",
+ typeList));
+
+ MessageType expected = new MessageType("mapParent", map);
+ GroupType actual =
+ Types.buildMessage()
+ .optionalMap()
+ .key(INT64)
+ .requiredListValue()
+ .optionalElement(INT64)
+ .named("myMap")
+ .named("mapParent");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testMapWithOptionalListValue() {
+ List typeList = new ArrayList();
+
+ typeList.add(new PrimitiveType(REQUIRED, INT64, "key"));
+ typeList.add(new GroupType(OPTIONAL, "value", OriginalType.LIST,
+ new GroupType(REPEATED,
+ "list",
+ new PrimitiveType(OPTIONAL, INT64, "element"))));
+
+ GroupType map = new GroupType(OPTIONAL, "myMap", OriginalType.MAP, new GroupType(REPEATED, "map",
+ typeList));
+
+ MessageType expected = new MessageType("mapParent", map);
+ GroupType actual =
+ Types.buildMessage()
+ .optionalMap()
+ .key(INT64)
+ .optionalListValue()
+ .optionalElement(INT64)
+ .named("myMap")
+ .named("mapParent");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testMapWithRequiredMapValue() {
+ List typeList = new ArrayList();
+
+ List innerMapTypeList = new ArrayList();
+ innerMapTypeList.add(new PrimitiveType(REQUIRED, INT64, "key"));
+ innerMapTypeList.add(new PrimitiveType(REQUIRED, INT64, "value"));
+
+ typeList.add(new PrimitiveType(REQUIRED, INT64, "key"));
+ typeList.add(new GroupType(REQUIRED, "value", OriginalType.MAP,
+ new GroupType(REPEATED, "map", innerMapTypeList)));
+
+ GroupType map = new GroupType(OPTIONAL, "myMap", OriginalType.MAP, new GroupType(REPEATED, "map",
+ typeList));
+
+ MessageType expected = new MessageType("mapParent", map);
+ GroupType actual =
+ Types.buildMessage()
+ .optionalMap()
+ .key(INT64)
+ .requiredMapValue()
+ .key(INT64)
+ .requiredValue(INT64)
+ .named("myMap")
+ .named("mapParent");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testMapWithOptionalMapValue() {
+ List typeList = new ArrayList();
+
+ List innerMapTypeList = new ArrayList();
+ innerMapTypeList.add(new PrimitiveType(REQUIRED, INT64, "key"));
+ innerMapTypeList.add(new PrimitiveType(REQUIRED, INT64, "value"));
+
+ typeList.add(new PrimitiveType(REQUIRED, INT64, "key"));
+ typeList.add(new GroupType(OPTIONAL, "value", OriginalType.MAP,
+ new GroupType(REPEATED, "map", innerMapTypeList)));
+
+ GroupType map = new GroupType(OPTIONAL, "myMap", OriginalType.MAP, new GroupType(REPEATED, "map",
+ typeList));
+
+ MessageType expected = new MessageType("mapParent", map);
+ GroupType actual =
+ Types.buildMessage()
+ .optionalMap()
+ .key(INT64)
+ .optionalMapValue()
+ .key(INT64)
+ .requiredValue(INT64)
+ .named("myMap")
+ .named("mapParent");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testMapWithGroupKeyAndRequiredListValue() {
+ List typeList = new ArrayList();
+
+ typeList.add(new GroupType(REQUIRED, "key", new PrimitiveType(REQUIRED, INT64,
+ "first"
+ )));
+ typeList.add(new GroupType(REQUIRED, "value", OriginalType.LIST,
+ new GroupType(REPEATED,
+ "list",
+ new PrimitiveType(OPTIONAL, INT64, "element"))));
+
+ GroupType map = new GroupType(OPTIONAL, "myMap", OriginalType.MAP, new GroupType(REPEATED, "map",
+ typeList));
+
+ MessageType expected = new MessageType("mapParent", map);
+ GroupType actual =
+ Types.buildMessage()
+ .optionalMap()
+ .groupKey()
+ .required(INT64)
+ .named("first")
+ .requiredListValue()
+ .optionalElement(INT64)
+ .named("myMap")
+ .named("mapParent");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testMapWithGroupKeyAndOptionalListValue() {
+ List typeList = new ArrayList();
+
+ typeList.add(new GroupType(REQUIRED, "key", new PrimitiveType(REQUIRED, INT64,
+ "first"
+ )));
+ typeList.add(new GroupType(OPTIONAL, "value", OriginalType.LIST,
+ new GroupType(REPEATED,
+ "list",
+ new PrimitiveType(OPTIONAL, INT64, "element"))));
+
+ GroupType map = new GroupType(OPTIONAL, "myMap", OriginalType.MAP, new GroupType(REPEATED, "map",
+ typeList));
+
+ MessageType expected = new MessageType("mapParent", map);
+ GroupType actual =
+ Types.buildMessage()
+ .optionalMap()
+ .groupKey()
+ .required(INT64)
+ .named("first")
+ .optionalListValue()
+ .optionalElement(INT64)
+ .named("myMap")
+ .named("mapParent");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testMapWithGroupKeyAndRequiredMapValue() {
+ List typeList = new ArrayList();
+
+ List innerMapTypeList = new ArrayList();
+ innerMapTypeList.add(new PrimitiveType(REQUIRED, INT64, "key"));
+ innerMapTypeList.add(new PrimitiveType(REQUIRED, INT64, "value"));
+
+
+ typeList.add(new GroupType(REQUIRED, "key", new PrimitiveType(REQUIRED, INT64,
+ "first"
+ )));
+ typeList.add(new GroupType(REQUIRED, "value", OriginalType.MAP,
+ new GroupType(REPEATED, "map", innerMapTypeList)));
+
+ GroupType map = new GroupType(OPTIONAL, "myMap", OriginalType.MAP, new GroupType(REPEATED, "map",
+ typeList));
+
+ MessageType expected = new MessageType("mapParent", map);
+ GroupType actual =
+ Types.buildMessage()
+ .optionalMap()
+ .groupKey()
+ .required(INT64)
+ .named("first")
+ .requiredMapValue()
+ .key(INT64)
+ .requiredValue(INT64)
+ .named("myMap")
+ .named("mapParent");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testMapWithGroupKeyAndOptionalMapValue() {
+ List typeList = new ArrayList();
+
+ List innerMapTypeList = new ArrayList();
+ innerMapTypeList.add(new PrimitiveType(REQUIRED, INT64, "key"));
+ innerMapTypeList.add(new PrimitiveType(REQUIRED, INT64, "value"));
+
+
+ typeList.add(new GroupType(REQUIRED, "key", new PrimitiveType(REQUIRED, INT64,
+ "first"
+ )));
+ typeList.add(new GroupType(OPTIONAL, "value", OriginalType.MAP,
+ new GroupType(REPEATED, "map", innerMapTypeList)));
+
+ GroupType map = new GroupType(OPTIONAL, "myMap", OriginalType.MAP, new GroupType(REPEATED, "map",
+ typeList));
+
+ MessageType expected = new MessageType("mapParent", map);
+ GroupType actual =
+ Types.buildMessage()
+ .optionalMap()
+ .groupKey()
+ .required(INT64)
+ .named("first")
+ .optionalMapValue()
+ .key(INT64)
+ .requiredValue(INT64)
+ .named("myMap")
+ .named("mapParent");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testMapWithNullValue() {
+ List typeList = new ArrayList();
+
+ typeList.add(new PrimitiveType(REQUIRED, INT64, "key"));
+ GroupType map = new GroupType(OPTIONAL, "myMap", OriginalType.MAP, new GroupType(REPEATED, "map",
+ typeList));
+
+ MessageType expected = new MessageType("mapParent", map);
+ GroupType actual =
+ Types.buildMessage()
+ .optionalMap()
+ .key(INT64)
+ .named("myMap")
+ .named("mapParent");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testMapWithDefaultKeyAndNullValue() {
+ List typeList = new ArrayList();
+
+ typeList.add(new PrimitiveType(REQUIRED, BINARY, "key", OriginalType.UTF8));
+ GroupType map = new GroupType(OPTIONAL, "myMap", OriginalType.MAP, new GroupType(REPEATED, "map",
+ typeList));
+
+ MessageType expected = new MessageType("mapParent", map);
+ GroupType actual =
+ Types.buildMessage()
+ .optionalMap()
+ .named("myMap")
+ .named("mapParent");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testMapWithPreBuiltKeyAndValueTypes() {
+ Type keyType = Types.required(INT64).named("key");
+ Type valueType = Types.required(BOOLEAN).named("value");
+
+ GroupType map = new GroupType(REQUIRED, "myMap", OriginalType.MAP,
+ new GroupType(REPEATED, "map", new Type[] {
+ keyType,
+ valueType
+ }));
+ MessageType expected = new MessageType("mapParent", map);
+
+ GroupType actual = Types.buildMessage()
+ .requiredMap()
+ .key(keyType)
+ .value(valueType)
+ .named("myMap")
+ .named("mapParent");
+
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testListWithRequiredPreBuiltElement() {
+ GroupType expected = new GroupType(REQUIRED, "myList", OriginalType.LIST,
+ new GroupType(REPEATED,
+ "list",
+ new PrimitiveType(REQUIRED, INT64, "element")));
+ Type element = Types.primitive(INT64, REQUIRED).named("element");
+ Type actual = Types.requiredList()
+ .element(element)
+ .named("myList");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testRequiredList() {
+ GroupType expected = new GroupType(REQUIRED, "myList", OriginalType.LIST,
+ new GroupType(REPEATED,
+ "list",
+ new PrimitiveType(OPTIONAL, INT64, "element")));
+ Type actual = Types.requiredList()
+ .optionalElement(INT64)
+ .named("myList");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testOptionalList() {
+ GroupType expected = new GroupType(OPTIONAL, "myList", OriginalType.LIST,
+ new GroupType(REPEATED,
+ "list",
+ new PrimitiveType(OPTIONAL, INT64, "element")));
+ Type actual = Types.optionalList()
+ .optionalElement(INT64)
+ .named("myList");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testListOfReqGroup() {
+ List fields = new ArrayList();
+ fields.add(new PrimitiveType(OPTIONAL, BOOLEAN, "field"));
+ GroupType expected = new GroupType(REQUIRED, "myList", OriginalType.LIST,
+ new GroupType(REPEATED,
+ "list",
+ new GroupType(REQUIRED, "element", fields)));
+ Type actual = Types.requiredList()
+ .requiredGroupElement()
+ .optional(BOOLEAN)
+ .named("field")
+ .named("myList");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testListOfOptionalGroup() {
+ List fields = new ArrayList();
+ fields.add(new PrimitiveType(OPTIONAL, BOOLEAN, "field"));
+ GroupType expected = new GroupType(REQUIRED, "myList", OriginalType.LIST,
+ new GroupType(REPEATED,
+ "list",
+ new GroupType(OPTIONAL, "element", fields)));
+ Type actual = Types.requiredList()
+ .optionalGroupElement()
+ .optional(BOOLEAN)
+ .named("field")
+ .named("myList");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testRequiredNestedList() {
+ List fields = new ArrayList();
+ fields.add(new GroupType(REQUIRED, "element", OriginalType.LIST,
+ new GroupType(REPEATED,
+ "list",
+ new PrimitiveType(OPTIONAL, DOUBLE, "element"))));
+ GroupType expected = new GroupType(OPTIONAL, "myList", OriginalType.LIST,
+ new GroupType(REPEATED,
+ "list",
+ fields));
+
+ Type actual =
+ Types.optionalList()
+ .requiredListElement()
+ .optionalElement(DOUBLE)
+ .named("myList");
+
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testOptionalNestedList() {
+ List fields = new ArrayList();
+ fields.add(new GroupType(OPTIONAL, "element", OriginalType.LIST,
+ new GroupType(REPEATED,
+ "list",
+ new PrimitiveType(OPTIONAL, DOUBLE, "element"))));
+ GroupType expected = new GroupType(OPTIONAL, "myList", OriginalType.LIST,
+ new GroupType(REPEATED,
+ "list",
+ fields));
+
+ Type actual =
+ Types.optionalList()
+ .optionalListElement()
+ .optionalElement(DOUBLE)
+ .named("myList");
+
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testRequiredListWithinGroup() {
+ List fields = new ArrayList();
+ fields.add(new GroupType(REQUIRED, "element", OriginalType.LIST,
+ new GroupType(REPEATED,
+ "list",
+ new PrimitiveType(OPTIONAL, INT64, "element"))));
+ GroupType expected = new GroupType(REQUIRED, "topGroup", fields);
+ Type actual = Types.requiredGroup()
+ .requiredList()
+ .optionalElement(INT64).named("element")
+ .named("topGroup");
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testOptionalListWithinGroup() {
+ List