Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for parameterized type #1390

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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