From a2330e4d66c0a1832fb3b9e23a33c006c9345c28 Mon Sep 17 00:00:00 2001 From: shollyman Date: Fri, 14 May 2021 10:55:29 -0700 Subject: [PATCH] feat(bigquery): add support for parameterized types (#4103) * feat(bigquery): add support for parameterized types Exposes type parameterization constraints for STRING, BYTES, NUMERIC, BIGNUMERIC types. * Update bigquery/schema.go Co-authored-by: Cody Oss <6331106+codyoss@users.noreply.github.com> Co-authored-by: Cody Oss <6331106+codyoss@users.noreply.github.com> --- bigquery/integration_test.go | 30 ++++++++++++++++++++++++++ bigquery/schema.go | 41 ++++++++++++++++++++++++++++++++++++ bigquery/schema_test.go | 34 ++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+) diff --git a/bigquery/integration_test.go b/bigquery/integration_test.go index cedd4fafbbd..4206a44bc64 100644 --- a/bigquery/integration_test.go +++ b/bigquery/integration_test.go @@ -249,6 +249,36 @@ func TestIntegration_TableCreate(t *testing.T) { } } +func TestIntegration_TableCreateWithConstraints(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + table := dataset.Table("constraints") + schema := Schema{ + {Name: "str_col", Type: StringFieldType, MaxLength: 10}, + {Name: "bytes_col", Type: BytesFieldType, MaxLength: 150}, + {Name: "num_col", Type: NumericFieldType, Precision: 20}, + {Name: "bignumeric_col", Type: BigNumericFieldType, Precision: 30, Scale: 5}, + } + err := table.Create(context.Background(), &TableMetadata{ + Schema: schema, + ExpirationTime: testTableExpiration.Add(5 * time.Minute), + }) + if err != nil { + t.Fatalf("table create error: %v", err) + } + + meta, err := table.Metadata(context.Background()) + if err != nil { + t.Fatalf("couldn't get metadata: %v", err) + } + + if diff := testutil.Diff(meta.Schema, schema); diff != "" { + t.Fatalf("got=-, want=+:\n%s", diff) + } + +} + func TestIntegration_TableCreateView(t *testing.T) { if client == nil { t.Skip("Integration tests skipped") diff --git a/bigquery/schema.go b/bigquery/schema.go index 0bcd85a606c..9b117e40a72 100644 --- a/bigquery/schema.go +++ b/bigquery/schema.go @@ -70,6 +70,41 @@ type FieldSchema struct { // Describes the nested schema if Type is set to Record. Schema Schema + + // Maximum length of the field for STRING or BYTES type. + // + // It is invalid to set value for types other than STRING or BYTES. + // + // 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. + MaxLength int64 + + // 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. + Precision int64 + + // 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. + Scale int64 } func (fs *FieldSchema) toBQ() *bq.TableFieldSchema { @@ -78,6 +113,9 @@ func (fs *FieldSchema) toBQ() *bq.TableFieldSchema { Name: fs.Name, Type: string(fs.Type), PolicyTags: fs.PolicyTags.toBQ(), + MaxLength: fs.MaxLength, + Precision: fs.Precision, + Scale: fs.Scale, } if fs.Repeated { @@ -133,6 +171,9 @@ func bqToFieldSchema(tfs *bq.TableFieldSchema) *FieldSchema { Required: tfs.Mode == "REQUIRED", Type: FieldType(tfs.Type), PolicyTags: bqToPolicyTagList(tfs.PolicyTags), + MaxLength: tfs.MaxLength, + Precision: tfs.Precision, + Scale: tfs.Scale, } for _, f := range tfs.Fields { diff --git a/bigquery/schema_test.go b/bigquery/schema_test.go index 6bdbf13858d..f877e36766a 100644 --- a/bigquery/schema_test.go +++ b/bigquery/schema_test.go @@ -284,6 +284,40 @@ func TestSchemaConversion(t *testing.T) { fieldSchema("geo", "g", "GEOGRAPHY", false, false, nil), }, }, + { + // constrained + bqSchema: &bq.TableSchema{ + Fields: []*bq.TableFieldSchema{ + { + Name: "foo", + Type: "STRING", + MaxLength: 0, + Precision: 0, + Scale: 0, + }, + { + Name: "bar", + Type: "STRING", + MaxLength: 1, + Precision: 2, + Scale: 3, + }, + }}, + schema: Schema{ + {Name: "foo", + Type: StringFieldType, + MaxLength: 0, + Precision: 0, + Scale: 0, + }, + {Name: "bar", + Type: StringFieldType, + MaxLength: 1, + Precision: 2, + Scale: 3, + }, + }, + }, { // policy tags bqSchema: &bq.TableSchema{