Skip to content

Commit

Permalink
Update the interface.
Browse files Browse the repository at this point in the history
  • Loading branch information
aihuaxu committed Oct 29, 2024
1 parent 5e5a53e commit 1261bb7
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 78 deletions.
24 changes: 4 additions & 20 deletions api/src/main/java/org/apache/iceberg/VariantLike.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
*/
package org.apache.iceberg;

import java.math.BigDecimal;

/**
* Interface for accessing Variant fields.
*
Expand All @@ -28,25 +26,11 @@
public interface VariantLike {
int size();

VariantLike getFieldByKey(String key);

VariantLike getFieldAtIndex(int index);

boolean getBoolean();

int getInt();

long getLong();

float getFloat();

double getDouble();

BigDecimal getDecimal();

String getString();
// To access the value of the root element based on the type of provided javaClass.
<T> T get(Class<T> javaClass);

byte[] getBinary();
// To access the sub-element for the provided path.
VariantLike get(String[] path);

String toJson();
}
68 changes: 66 additions & 2 deletions api/src/test/java/org/apache/iceberg/TestAccessors.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@
import static org.apache.iceberg.types.Types.NestedField.required;
import static org.assertj.core.api.Assertions.assertThat;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.UUID;
import org.apache.iceberg.TestHelpers.JsonVariant;
import org.apache.iceberg.TestHelpers.Row;
Expand Down Expand Up @@ -250,8 +254,68 @@ public void testEmptySchema() {
}

@Test
public void testVariant() {
VariantLike variant = JsonVariant.of("{\"name\":\"John\",\"age\":30}");
public void testVariant() throws JsonProcessingException {
Base64.Encoder encoder = Base64.getEncoder();
boolean expectedTrue = true;
boolean expectedFalse = false;
int expectedInt = 2147483647;
long expectedLong = 2147483648L;
float expectedFloat = 1.2345f;
double expectedDouble = 1.23456;
BigDecimal expectedDecimal = new BigDecimal(123456);
String expectedString = "abc";
String expectedBytes =
new String(encoder.encode(expectedString.getBytes()), StandardCharsets.UTF_8);
int nestInt = 10;

String json =
"{\"false\":"
+ expectedFalse
+ ", \"true\":"
+ expectedTrue
+ ", \"string\": \""
+ expectedString
+ "\","
+ "\"int\":"
+ expectedInt
+ ","
+ "\"long\":"
+ expectedLong
+ ", \"float\":"
+ expectedFloat
+ ","
+ "\"double\":"
+ expectedDouble
+ ", \"bytes\":\""
+ expectedBytes
+ "\", \"decimal\":"
+ expectedDecimal
+ ","
+ "\"nest1\": {\"nest2\":"
+ nestInt
+ "}"
+ "}";

VariantLike variant = JsonVariant.of(json);
assertAccessorReturns(Types.VariantType.get(), variant);

assertThat(variant.get(new String[] {"true"}).get(Boolean.class)).isEqualTo(expectedTrue);
assertThat(variant.get(new String[] {"false"}).get(Boolean.class)).isEqualTo(expectedFalse);
assertThat(variant.get(new String[] {"string"}).get(String.class)).isEqualTo(expectedString);
assertThat(variant.get(new String[] {"int"}).get(Integer.class)).isEqualTo(expectedInt);
assertThat(variant.get(new String[] {"long"}).get(Long.class)).isEqualTo(expectedLong);
assertThat(variant.get(new String[] {"float"}).get(Float.class)).isEqualTo(expectedFloat);
assertThat(variant.get(new String[] {"double"}).get(Double.class)).isEqualTo(expectedDouble);
assertThat(variant.get(new String[] {"decimal"}).get(BigDecimal.class))
.isEqualTo(expectedDecimal);
assertThat(
StandardCharsets.UTF_8
.decode(variant.get(new String[] {"bytes"}).get(ByteBuffer.class))
.toString())
.isEqualTo(expectedString);
assertThat(variant.get(new String[] {"nest1", "nest2"}).get(Integer.class)).isEqualTo(nestInt);
assertThat(variant.get(new String[] {"nest1", "invalid"})).isNull();
assertThat(new ObjectMapper().readTree(variant.toJson()))
.isEqualTo(new ObjectMapper().readTree(json));
}
}
80 changes: 32 additions & 48 deletions api/src/test/java/org/apache/iceberg/TestHelpers.java
Original file line number Diff line number Diff line change
Expand Up @@ -433,59 +433,43 @@ public int size() {
}

@Override
public VariantLike getFieldByKey(String key) {
JsonNode childNode = node.get(key);
return new JsonVariant(childNode);
}

@Override
public VariantLike getFieldAtIndex(int index) {
JsonNode childNode = node.get(index);
return new JsonVariant(childNode);
}

@Override
public boolean getBoolean() {
return node.asBoolean();
}

@Override
public int getInt() {
return node.asInt();
}

@Override
public long getLong() {
return node.asLong();
}

@Override
public float getFloat() {
return (float) node.asDouble();
}

@Override
public double getDouble() {
return node.asDouble();
}

@Override
public BigDecimal getDecimal() {
return new BigDecimal(node.asText());
}
public <T> T get(Class<T> javaClass) {
if (javaClass.equals(Boolean.class)) {
return (T) (Boolean) node.asBoolean();
} else if (javaClass.equals(Integer.class)) {
return (T) (Integer) node.asInt();
} else if (javaClass.equals(Long.class)) {
return (T) (Long) node.asLong();
} else if (javaClass.equals(Float.class)) {
return (T) Float.valueOf((float) node.asDouble());
} else if (javaClass.equals(Double.class)) {
return (T) (Double) (node.asDouble());
} else if (CharSequence.class.isAssignableFrom(javaClass)) {
return (T) node.asText();
} else if (javaClass.equals(ByteBuffer.class)) {
try {
return (T) ByteBuffer.wrap(node.binaryValue());
} catch (IOException e) {
throw new RuntimeException(e);
}
} else if (javaClass.equals(BigDecimal.class)) {
return (T) node.decimalValue();
}

@Override
public String getString() {
return node.asText();
throw new IllegalArgumentException("Unsupported type: " + javaClass);
}

@Override
public byte[] getBinary() {
try {
return node.binaryValue();
} catch (IOException e) {
return null;
public VariantLike get(String[] path) {
JsonNode childNode = node;
for (String pathElement : path) {
childNode = childNode.get(pathElement);
if (childNode == null) {
return null;
}
}

return new JsonVariant(childNode);
}

@Override
Expand Down
8 changes: 0 additions & 8 deletions api/src/test/java/org/apache/iceberg/util/RandomUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Random;
import org.apache.iceberg.TestHelpers.JsonVariant;
import org.apache.iceberg.types.Type;
import org.apache.iceberg.types.Types;

Expand Down Expand Up @@ -145,9 +144,6 @@ public static Object generatePrimitive(Type.PrimitiveType primitive, Random rand
BigDecimal bigDecimal = new BigDecimal(unscaled, type.scale());
return negate(choice) ? bigDecimal.negate() : bigDecimal;

case VARIANT:
return randomVariant();

default:
throw new IllegalArgumentException(
"Cannot generate random value for unknown type: " + primitive);
Expand Down Expand Up @@ -229,8 +225,4 @@ private static BigInteger randomUnscaled(int precision, Random random) {

return new BigInteger(sb.toString());
}

private static JsonVariant randomVariant() {
return JsonVariant.of("{\"name\": \"John\"}");
}
}

0 comments on commit 1261bb7

Please sign in to comment.