Skip to content

Commit

Permalink
feat: add support for parameterized type (#1390)
Browse files Browse the repository at this point in the history
Fixes #1309
  • Loading branch information
stephaniewang526 committed Jun 25, 2021
1 parent 95f1a6c commit b1fb57c
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 0 deletions.
Expand Up @@ -59,6 +59,9 @@ public TableFieldSchema apply(Field field) {
private final String mode;
private final String description;
private final PolicyTags policyTags;
private final Long maxLength;
private final Long scale;
private final Long precision;

/**
* Mode for a BigQuery Table field. {@link Mode#NULLABLE} fields can be set to {@code null},
Expand All @@ -79,6 +82,9 @@ public static final class Builder {
private String mode;
private String description;
private PolicyTags policyTags;
private Long maxLength;
private Long scale;
private Long precision;

private Builder() {}

Expand All @@ -89,6 +95,9 @@ private Builder(Field field) {
this.mode = field.mode;
this.description = field.description;
this.policyTags = field.policyTags;
this.maxLength = field.maxLength;
this.scale = field.scale;
this.precision = field.precision;
}

/**
Expand Down Expand Up @@ -199,6 +208,43 @@ public Builder setPolicyTags(PolicyTags policyTags) {
return this;
}

/**
* Sets the maximum length of the field for STRING or BYTES type.
*
* <p>It is invalid to set value for types other than STRING or BYTES.
*
* <p>For STRING type, this represents the maximum UTF-8 length of strings allowed in the field.
* For BYTES type, this represents the maximum number of bytes in the field.
*/
public Builder setMaxLength(Long maxLength) {
this.maxLength = maxLength;
return this;
}

/**
* Scale can be used to constrain the maximum number of digits in the fractional part of a
* NUMERIC or BIGNUMERIC type. If the Scale value is set, the Precision value must be set as
* well. It is invalid to set values for Scale for types other than NUMERIC or BIGNUMERIC. See
* the Precision field for additional guidance about valid values.
*/
public Builder setScale(Long scale) {
this.scale = scale;
return this;
}

/**
* Precision can be used to constrain the maximum number of total digits allowed for NUMERIC or
* BIGNUMERIC types. It is invalid to set values for Precision for types other than // NUMERIC
* or BIGNUMERIC. For NUMERIC type, acceptable values for Precision must be: 1 ≤ (Precision -
* Scale) ≤ 29. Values for Scale must be: 0 ≤ Scale ≤ 9. For BIGNUMERIC type, acceptable values
* for Precision must be: 1 ≤ (Precision - Scale) ≤ 38. Values for Scale must be: 0 ≤ Scale ≤
* 38.
*/
public Builder setPrecision(Long precision) {
this.precision = precision;
return this;
}

/** Creates a {@code Field} object. */
public Field build() {
return new Field(this);
Expand All @@ -212,6 +258,9 @@ private Field(Builder builder) {
this.mode = builder.mode;
this.description = builder.description;
this.policyTags = builder.policyTags;
this.maxLength = builder.maxLength;
this.scale = builder.scale;
this.precision = builder.precision;
}

/** Returns the field name. */
Expand Down Expand Up @@ -244,6 +293,24 @@ public PolicyTags getPolicyTags() {
return policyTags;
}

/** Returns the maximum length of the field for STRING or BYTES type. */
public Long getMaxLength() {
return maxLength;
}

/**
* Returns the maximum number of digits set in the fractional part of a NUMERIC or BIGNUMERIC
* type.
*/
public Long getScale() {
return scale;
}

/** Returns the maximum number of total digits allowed for NUMERIC or BIGNUMERIC types. */
public Long getPrecision() {
return precision;
}

/**
* Returns the list of sub-fields if {@link #getType()} is a {@link LegacySQLTypeName#RECORD}.
* Returns {@code null} otherwise.
Expand All @@ -265,6 +332,9 @@ public String toString() {
.add("mode", mode)
.add("description", description)
.add("policyTags", policyTags)
.add("maxLength", maxLength)
.add("scale", scale)
.add("precision", precision)
.toString();
}

Expand Down Expand Up @@ -335,6 +405,15 @@ TableFieldSchema toPb() {
if (policyTags != null) {
fieldSchemaPb.setPolicyTags(policyTags.toPb());
}
if (maxLength != null) {
fieldSchemaPb.setMaxLength(maxLength);
}
if (scale != null) {
fieldSchemaPb.setScale(scale);
}
if (precision != null) {
fieldSchemaPb.setPrecision(precision);
}
if (getSubFields() != null) {
List<TableFieldSchema> fieldsPb = Lists.transform(getSubFields(), TO_PB_FUNCTION);
fieldSchemaPb.setFields(fieldsPb);
Expand All @@ -354,6 +433,15 @@ static Field fromPb(TableFieldSchema fieldSchemaPb) {
if (fieldSchemaPb.getPolicyTags() != null) {
fieldBuilder.setPolicyTags(PolicyTags.fromPb(fieldSchemaPb.getPolicyTags()));
}
if (fieldSchemaPb.getMaxLength() != null) {
fieldBuilder.setMaxLength(fieldSchemaPb.getMaxLength());
}
if (fieldSchemaPb.getScale() != null) {
fieldBuilder.setScale(fieldSchemaPb.getScale());
}
if (fieldSchemaPb.getPrecision() != null) {
fieldBuilder.setPrecision(fieldSchemaPb.getPrecision());
}
FieldList subFields =
fieldSchemaPb.getFields() != null
? FieldList.of(Lists.transform(fieldSchemaPb.getFields(), FROM_PB_FUNCTION))
Expand Down
Expand Up @@ -32,6 +32,9 @@ public class SchemaTest {
Field.newBuilder("StringField", LegacySQLTypeName.STRING)
.setMode(Field.Mode.NULLABLE)
.setDescription("FieldDescription1")
.setPrecision(20L)
.setScale(20L)
.setMaxLength(10L)
.build();
private static final Field FIELD_SCHEMA2 =
Field.newBuilder("IntegerField", LegacySQLTypeName.INTEGER)
Expand Down
Expand Up @@ -90,6 +90,7 @@
import com.google.cloud.bigquery.StandardSQLDataType;
import com.google.cloud.bigquery.StandardSQLField;
import com.google.cloud.bigquery.StandardSQLTableType;
import com.google.cloud.bigquery.StandardSQLTypeName;
import com.google.cloud.bigquery.StandardTableDefinition;
import com.google.cloud.bigquery.Table;
import com.google.cloud.bigquery.TableDataWriteChannel;
Expand Down Expand Up @@ -703,6 +704,50 @@ public void testCreateTableWithRangePartitioning() {
}
}

@Test
public void testCreateTableWithConstraints() {
String tableName = "test_create_table_with_constraints";
TableId tableId = TableId.of(DATASET, tableName);
Field stringFieldWithConstraint =
Field.newBuilder("stringFieldWithConstraint", StandardSQLTypeName.STRING)
.setMode(Field.Mode.NULLABLE)
.setDescription("field has a constraint")
.setMaxLength(10L)
.build();
Field byteFieldWithConstraint =
Field.newBuilder("byteFieldWithConstraint", StandardSQLTypeName.BYTES)
.setMode(Field.Mode.NULLABLE)
.setDescription("field has a constraint")
.setMaxLength(150L)
.build();
Field numericFieldWithConstraint =
Field.newBuilder("numericFieldWithConstraint", StandardSQLTypeName.NUMERIC)
.setMode(Field.Mode.NULLABLE)
.setDescription("field has a constraint")
.setPrecision(20L)
.build();
Field bigNumericFieldWithConstraint =
Field.newBuilder("bigNumericFieldWithConstraint", StandardSQLTypeName.BIGNUMERIC)
.setMode(Field.Mode.NULLABLE)
.setDescription("field has a constraint")
.setPrecision(30L)
.setScale(5L)
.build();
Schema schema =
Schema.of(
stringFieldWithConstraint,
byteFieldWithConstraint,
numericFieldWithConstraint,
bigNumericFieldWithConstraint);
StandardTableDefinition tableDefinition =
StandardTableDefinition.newBuilder().setSchema(schema).build();
Table createdTable = bigquery.create(TableInfo.of(tableId, tableDefinition));
assertNotNull(createdTable);
Table remoteTable = bigquery.getTable(DATASET, tableName);
assertEquals(schema, remoteTable.<StandardTableDefinition>getDefinition().getSchema());
bigquery.delete(tableId);
}

@Test
public void testCreateAndUpdateTableWithPolicyTags() throws IOException {
// Set up policy tags in the datacatalog service
Expand Down

0 comments on commit b1fb57c

Please sign in to comment.