package org.rakam.analysis; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.collect.Lists; import org.apache.avro.Schema; import org.rakam.collection.FieldType; import org.rakam.collection.SchemaField; import org.rakam.util.AvroUtil; import org.rakam.util.RakamException; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.function.Function; import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST; import static org.apache.avro.Schema.Type.NULL; public enum SchemaConverter { AVRO(schemaFields -> { Schema parse = new Schema.Parser().parse(schemaFields); if (parse.getType() != Schema.Type.RECORD) { throw new RakamException("Avro schema must be a RECORD", BAD_REQUEST); } Set<SchemaField> rakamFields = new HashSet<>(); for (Schema.Field field : parse.getFields()) { Schema avroSchema = field.schema(); if (avroSchema.getType() == Schema.Type.UNION) { List<Schema> types = field.schema().getTypes(); if (types.isEmpty()) { throw new IllegalStateException(); } if (types.size() == 1) { avroSchema = types.get(0); } if (types.size() == 2) { if (types.get(0).getType() == Schema.Type.NULL) { avroSchema = Schema.createUnion(Lists.newArrayList(Schema.create(NULL), types.get(1))); } else if (types.get(1).getType() == Schema.Type.NULL) { avroSchema = Schema.createUnion(Lists.newArrayList(Schema.create(NULL), types.get(0))); } else { throw new RakamException("UNION type is not supported: " + avroSchema, BAD_REQUEST); } } else { throw new RakamException("UNION type is not supported: " + avroSchema, BAD_REQUEST); } } final Schema finalAvroSchema = avroSchema; Optional<FieldType> fieldType = Arrays.stream(FieldType.values()).filter(e -> AvroUtil.generateAvroSchema(e).equals(finalAvroSchema)).findAny(); if (!fieldType.isPresent()) { new RakamException("Unsupported Avro type" + avroSchema, BAD_REQUEST); } rakamFields.add(new SchemaField(field.name(), fieldType.get(), null, avroSchema.getFullName(), avroSchema.getDoc(), null)); } return rakamFields; }); private final Function<String, Set<SchemaField>> mapper; SchemaConverter(Function<String, Set<SchemaField>> mapper) { this.mapper = mapper; } @JsonCreator public static SchemaConverter get(String name) { return valueOf(name.toUpperCase()); } @JsonProperty public String value() { return name(); } public Function<String, Set<SchemaField>> getMapper() { return mapper; } }